Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

717 lines
18 KiB

  1. ;++
  2. ;
  3. ;Copyright (c) 1995 Microsoft Corporation
  4. ;
  5. ;Module Name:
  6. ;
  7. ; bioschk.asm
  8. ;
  9. ;Abstract:
  10. ;
  11. ; The code in this "image" is responsible for checking if is appropriate
  12. ; for us to start setupldr.bin. We consider this appropriate when we pass
  13. ; BIOS checkings. Setupldr.bin is binary appended at the end of this image.
  14. ;
  15. ;Author:
  16. ;
  17. ; Windows 2000 OPK Development Team 16-Dec-1999
  18. ; Alan M. Brown (Compaq Datacenter) 18-Oct-2000
  19. ; Scott Wilmot (CTO Tools) 25-Jan-2001
  20. ; Windows 2000 OPK Development Team 02-Apr-2001
  21. ;
  22. ;Environment:
  23. ;
  24. ; Real mode
  25. ;
  26. ; Case 1:
  27. ; Complete image has been loaded at 2000:0000 by the boot code
  28. ; DL = INT 13h drive number we've booted from
  29. ;
  30. ; Case 2:
  31. ; First 512 bytes of this image has been loaded at 2000:000 by the boot code
  32. ; BX = Starting Cluster Number of this image
  33. ; DL = INT 13h drive number we've booted from
  34. ; DS:SI -> boot media's BPB
  35. ; DS:DI -> argument structure
  36. ;
  37. ;Revision History:
  38. ;
  39. ;--
  40. page ,132
  41. title boot - BIOS check
  42. name bioschk
  43. .8086
  44. CODE SEGMENT
  45. ASSUME CS:CODE,DS:CODE,SS:NOTHING,ES:NOTHING
  46. ORG 0000H
  47. _BiosChk label byte
  48. BiosChkDestSeg EQU 1000h
  49. SetupLdrDestSeg EQU 2000h
  50. MaxCodeSize EQU 0800h ;number of paragraphs (32k)
  51. MaxSetupLdrSize EQU 4000h ;number of paragraphs (256k)
  52. StackSeg EQU 1000h ;stack goes from here
  53. MAXREAD EQU 10000h
  54. MAXSECTORS EQU MAXREAD/0200h
  55. DoubleWord struc
  56. lsw dw ?
  57. msw dw ?
  58. DoubleWord ends
  59. SHARED struc
  60. ReadClusters dd ? ; function pointer
  61. ReadSectors dd ? ; function pointer
  62. SectorBase dd ? ; starting sector for
  63. ; ReadSectors callback
  64. SHARED ends
  65. BPB struc
  66. BytesPerSector dw ?
  67. SectorsPerCluster db ?
  68. ReservedSectors dw ?
  69. Fats db ?
  70. DirectoryEntries dw ?
  71. Sectors dw ?
  72. Media db ?
  73. FatSectors dw ?
  74. SectorsPerTrack dw ?
  75. Heads dw ?
  76. HiddenSectors dd ?
  77. SectorsLong dd ?
  78. BootDriveNumber db ?
  79. BPB ends
  80. JMPFAR MACRO DestOfs,DestSeg
  81. db 0eah
  82. dw OFFSET DestOfs
  83. dw DestSeg
  84. endm
  85. START:
  86. ;
  87. ; The FAT boot sector only reads in the first 512 bytes of NTLDR. This is
  88. ; the module that contains those 512 bytes, so we are now responsible for
  89. ; loading the rest of the file. Other filesystems will load the whole file,
  90. ; so the default entrypoint branches around the FAT-specific code.
  91. ;
  92. jmp RealStart
  93. FatBegin:
  94. .386
  95. ;
  96. ; If we're here, we've booted off a FAT system and we must load the rest
  97. ; of the binary image at 2000:0200 (right behind this sector). The boot
  98. ; sector passes us the following:
  99. ; BX = Starting Cluster Number of this image
  100. ; DL = INT 13h drive number we've booted from
  101. ; DS:SI -> boot media's BPB
  102. ; DS:DI -> argument structure
  103. ;
  104. ;
  105. ; Save away the boot drive and the starting cluster number
  106. ;
  107. push dx
  108. push bx
  109. ;
  110. ; Blast the FAT into memory at 6000:0000 - 8000:0000
  111. ;
  112. .386
  113. push 06000h
  114. .8086
  115. pop es
  116. xor bx,bx ; (es:bx) = 6000:0000
  117. mov cx,ds:[si].ReservedSectors
  118. mov ds:[di].SectorBase.msw,0
  119. mov ds:[di].SectorBase.lsw,cx ; set up Sector Base
  120. mov ax,ds:[si].FatSectors ; (al) = # Sectors to read
  121. cmp ax,080h
  122. jbe FatLt64k
  123. ; The FAT is > 64k, so we read the first 64k chunk, then the rest.
  124. ; (A 16-bit FAT can't be bigger than 128k)
  125. push cx
  126. mov ax,080h ; (al) = # of sectors to read
  127. call ds:[di].ReadSectors
  128. pop cx ; (cx) = previous SectorBase
  129. .386
  130. push 07000h
  131. .8086
  132. pop es
  133. xor bx,bx ; (es:bx) = 7000:0000
  134. mov ax,ds:[si].FatSectors
  135. sub ax,080h ; (ax) = # Sectors left to read
  136. add cx,080h ; (cx) = SectorBase for next read
  137. mov ds:[di].SectorBase.lsw,cx
  138. adc ds:[di].SectorBase.msw,0 ; set up SectorBase
  139. ;
  140. ; (al) = # of sectors to read
  141. ;
  142. FatLt64k:
  143. call ds:[di].ReadSectors
  144. ;
  145. ; FAT is in memory, now we restore our starting cluster number
  146. ;
  147. pop dx ; (dx) = starting cluster number
  148. xor bx,bx
  149. ;
  150. ; set up FS and GS for reading the FAT
  151. ;
  152. .386
  153. mov ax,6000h
  154. mov fs,ax
  155. mov ax,7000h
  156. mov gs,ax
  157. .8086
  158. ;
  159. ; set up ES for reading in the rest of us
  160. ;
  161. push cs
  162. pop es
  163. mov ah,MAXSECTORS ; (ah) = number of sectors we can read
  164. FatLoop:
  165. ;
  166. ; (dx) = next cluster to load
  167. ;
  168. push dx
  169. mov al,ds:[si].SectorsPerCluster ; (al) = number of contiguous sectors
  170. ; found
  171. sub ah,ds:[si].SectorsPerCluster ; can read before 64k
  172. ;
  173. ; Check to see if we've reached the end of the file
  174. ;
  175. cmp dx,0ffffh
  176. jne Fat10
  177. ;
  178. ; The entire file has been loaded. Throw away the saved next cluster,
  179. ; restore the boot drive, and let NTLDR do its thing.
  180. ;
  181. pop dx
  182. pop dx
  183. jmp RealStart
  184. Fat10:
  185. mov cx,dx
  186. ;
  187. ; (dx) = (cx) = last contiguous cluster
  188. ; (al) = # of contiguous clusters found
  189. ;
  190. call NextFatEntry
  191. ;
  192. ; (dx) = cluster following last contiguous cluster
  193. ;
  194. ; Check to see if the next cluster is contiguous. If not, go load the
  195. ; contiguous block we've found.
  196. ;
  197. inc cx
  198. cmp dx,cx
  199. jne LncLoad
  200. ;
  201. ; Check to see if we've reached the 64k boundary. If so, go load the
  202. ; contiguous block so far. If not, increment the number of contiguous
  203. ; sectors and loop again.
  204. ;
  205. cmp ah,0
  206. jne Lnc20
  207. mov ah,MAXSECTORS ; (ah) = number of sectors until
  208. jmp short LncLoad
  209. Lnc20:
  210. add al,ds:[si].SectorsPerCluster
  211. sub ah,ds:[si].SectorsPerCluster
  212. jmp short Fat10
  213. LncLoad:
  214. ;
  215. ; (TOS) = first cluster to load
  216. ; (dx) = first cluster of next group to load
  217. ; (al) = number of contiguous sectors
  218. ;
  219. pop cx
  220. push dx
  221. mov dx,cx
  222. mov cx,10 ; (cx) = retry count
  223. ;
  224. ; N.B.
  225. ; This assumes that we will never have more than 255 contiguous clusters.
  226. ; Since that would get broken up into chunks that don't cross the 64k
  227. ; boundary, this is ok.
  228. ;
  229. ; (dx) = first cluster to load
  230. ; (al) = number of contiguous sectors
  231. ; (TOS) = first cluster of next group to load
  232. ; (es:bx) = address where clusters should be loaded
  233. ;
  234. FatRetry:
  235. push bx
  236. push ax
  237. push dx
  238. push cx
  239. call [di].ReadClusters
  240. jnc ReadOk
  241. ;
  242. ; error in the read, reset the drive and try again
  243. ;
  244. mov ax,01h
  245. mov al,ds:[si].BootDriveNumber
  246. int 13h
  247. xor ax,ax
  248. mov al,ds:[si].BootDriveNumber
  249. int 13h
  250. ;
  251. ; pause for a while
  252. ;
  253. xor ax,ax
  254. FatPause:
  255. dec ax
  256. jnz FatPause
  257. pop cx
  258. pop dx
  259. pop ax
  260. pop bx
  261. dec cx
  262. jnz FatRetry
  263. ;
  264. ; we have re-tried ten times, it still doesn't work, so punt.
  265. ;
  266. push cs
  267. pop ds
  268. mov si,offset FAT_ERROR
  269. FatErrPrint:
  270. lodsb
  271. or al,al
  272. jz FatErrDone
  273. mov ah,14 ; write teletype
  274. mov bx,7 ; attribute
  275. int 10h ; print it
  276. jmp FatErrPrint
  277. FatErrDone:
  278. jmp $
  279. ; BUGBUG this should be replaced by a mechanism to get a pointer
  280. ; passed to us in the param block. since the boot sector msg itself
  281. ; is properly localized but this one isn't.
  282. FAT_ERROR db 13,10,"Disk I/O error",0dh,0ah,0
  283. ReadOk:
  284. pop cx
  285. pop dx
  286. pop ax
  287. pop bx
  288. pop dx ; (dx) = first cluster of next group
  289. ; to load.
  290. .386
  291. ;
  292. ; Convert # of sectors into # of bytes.
  293. ;
  294. mov cl,al
  295. xor ch,ch
  296. shl cx,9
  297. .8086
  298. add bx,cx
  299. jz FatLoopDone
  300. jmp FatLoop
  301. FatLoopDone:
  302. ;
  303. ; (bx) = 0
  304. ; This means we've just ended on a 64k boundary, so we have to
  305. ; increment ES to continue reading the file. We are guaranteed to
  306. ; always end on a 64k boundary and never cross it, because we
  307. ; will reduce the number of contiguous clusters to read
  308. ; to ensure that the last cluster read will end on the 64k boundary.
  309. ; Since we start reading at 0, and ClusterSize will always be a power
  310. ; of two, a cluster will never cross a 64k boundary.
  311. ;
  312. mov ax,es
  313. add ax,01000h
  314. mov es,ax
  315. mov ah,MAXSECTORS
  316. jmp FatLoop
  317. ;++
  318. ;
  319. ; NextFatEntry - This procedure returns the next cluster in the FAT chain.
  320. ; It will deal with both 12-bit and 16-bit FATs. It assumes
  321. ; that the entire FAT has been loaded into memory.
  322. ;
  323. ; Arguments:
  324. ; (dx) = current cluster number
  325. ; (fs:0) = start of FAT in memory
  326. ; (gs:0) = start of second 64k of FAT in memory
  327. ;
  328. ; Returns:
  329. ; (dx) = next cluster number in FAT chain
  330. ; (dx) = 0ffffh if there are no more clusters in the chain
  331. ;
  332. ;--
  333. NextFatEntry proc near
  334. push bx
  335. ;
  336. ; Check to see if this is a 12-bit or 16-bit FAT. The biggest FAT we can
  337. ; have for a 12-bit FAT is 4080 clusters. This is 6120 bytes, or just under
  338. ; 12 sectors.
  339. ;
  340. ; A 16-bit FAT that's 12 sectors long would only hold 3072 clusters. Thus,
  341. ; we compare the number of FAT sectors to 12. If it's greater than 12, we
  342. ; have a 16-bit FAT. If it's less than or equal to 12, we have a 12-bit FAT.
  343. ;
  344. call IsFat12
  345. jnc Next16Fat
  346. Next12Fat:
  347. mov bx,dx ; (fs:bx) => temporary index
  348. shr dx,1 ; (dx) = offset/2
  349. ; (CY) = 1 need to shift
  350. pushf ; = 0 don't need to shift
  351. add bx,dx ; (fs:bx) => next cluster number
  352. .386
  353. mov dx,fs:[bx] ; (dx) = next cluster number
  354. .8086
  355. popf
  356. jc shift ; carry flag tells us whether to
  357. and dx,0fffh ; mask
  358. jmp short N12Tail
  359. shift:
  360. .386
  361. shr dx,4 ; or shift
  362. .8086
  363. N12Tail:
  364. ;
  365. ; Check for end of file
  366. ;
  367. cmp dx,0ff8h ; If we're at the end of the file,
  368. jb NfeDone ; convert to canonical EOF.
  369. mov dx,0ffffh
  370. jmp short NfeDone
  371. Next16Fat:
  372. add dx,dx ; (dx) = offset
  373. jc N16high
  374. mov bx,dx ; (fs:bx) => next cluster number
  375. .386
  376. mov dx,fs:[bx] ; (dx) = next cluster number
  377. .8086
  378. jmp short N16Tail
  379. N16high:
  380. mov bx,dx
  381. .386
  382. mov dx,gs:[bx]
  383. .8086
  384. N16Tail:
  385. cmp dx,0fff8h
  386. jb NfeDone
  387. mov dx,0ffffh ; If we're at the end of the file
  388. ; convert to canonical EOF.
  389. NfeDone:
  390. pop bx
  391. ret
  392. NextFatEntry endp
  393. ;++
  394. ;
  395. ; IsFat12 - This function determines whether the BPB describes a 12-bit
  396. ; or 16-bit FAT.
  397. ;
  398. ; Arguments - ds:si supplies pointer to BPB
  399. ;
  400. ; Returns
  401. ; CY set - 12-bit FAT
  402. ; CY clear - 16-bit FAT
  403. ;
  404. ;--
  405. IsFat12 proc near
  406. .386
  407. push eax
  408. push ebx
  409. push ecx
  410. push edx
  411. movzx ecx, ds:[si].Sectors
  412. or cx,cx
  413. jnz if10
  414. mov ecx, ds:[si].SectorsLong
  415. if10:
  416. ;
  417. ; (ecx) = number of sectors
  418. ;
  419. movzx ebx, byte ptr ds:[si].Fats
  420. movzx eax, word ptr ds:[si].FatSectors
  421. mul ebx
  422. sub ecx,eax
  423. ;
  424. ; (ecx) = (#sectors)-(sectors in FATs)
  425. ;
  426. movzx eax, word ptr ds:[si].DirectoryEntries
  427. shl eax, 5
  428. ;
  429. ; (eax) = #bytes in root dir
  430. ;
  431. mov edx,eax
  432. and edx,0ffff0000h
  433. div word ptr ds:[si].BytesPerSector
  434. sub ecx,eax
  435. ;
  436. ; (ecx) = (#sectors) - (sectors in fat) - (sectors in root dir)
  437. ;
  438. movzx eax, word ptr ds:[si].ReservedSectors
  439. sub ecx, eax
  440. mov eax, ecx
  441. movzx ecx, byte ptr ds:[si].SectorsPerCluster
  442. xor edx,edx
  443. div ecx
  444. cmp eax, 4087
  445. jae if20
  446. stc
  447. jmp short if30
  448. if20:
  449. clc
  450. if30:
  451. pop edx
  452. pop ecx
  453. pop ebx
  454. pop eax
  455. ret
  456. .8086
  457. IsFat12 endp
  458. Free EQU 512-($-Start)
  459. if Free lt 0
  460. %out FATAL PROBLEM: FAT-specific startup code is greater than
  461. %out 512 bytes. Fix it!
  462. .err
  463. endif
  464. RealStart:
  465. ;
  466. ; we are completely done with the boot sector, we can party on it's memory as we like.
  467. ; set up the stack
  468. ;
  469. mov ax,StackSeg
  470. mov ss,ax
  471. xor sp,sp
  472. mov ax,cs
  473. mov ds,ax
  474. mov es,ax
  475. ;
  476. ; save setupldr data
  477. ;
  478. mov Preserve, dl
  479. ; move ourselves from 2000:0000 to 1000:0000, one paragraph at a time.
  480. mov ax, BiosChkDestSeg
  481. mov es, ax
  482. mov dx, MaxCodeSize
  483. cld
  484. Again1:
  485. xor di, di
  486. xor si, si
  487. mov cx, 10h
  488. rep movsb
  489. mov ax, ds
  490. inc ax
  491. mov ds, ax
  492. mov ax, es
  493. inc ax
  494. mov es, ax
  495. dec dx
  496. jnz Again1
  497. mov ax, BiosChkDestSeg
  498. mov ds, ax
  499. mov es, ax
  500. JMPFAR Continue1, BiosChkDestSeg
  501. Continue1:
  502. ; Go to System specific check
  503. jmp short IDCheck1
  504. IdString1 db 'COMPAQ'
  505. SYSID1 EQU 'C '
  506. SYSID2 EQU '3L'
  507. SYSID3 EQU '08'
  508. NoMatchUS db "This system is not a supported platform.",13,10,"$"
  509. TestString db 7 dup (0)
  510. IDCheck1:
  511. push ds
  512. push si
  513. mov ax,0f000h
  514. push ax
  515. pop ds
  516. mov ax,0ffeah
  517. push ax
  518. pop si
  519. mov di,OFFSET TestString
  520. mov cx,6
  521. rep movsb
  522. pop si
  523. pop ds
  524. mov si,OFFSET IdString1
  525. mov di,OFFSET TestString
  526. mov cx,6
  527. repe cmpsb
  528. jne IDCheckFailed
  529. IDCheck2:
  530. ;
  531. push es
  532. ;
  533. mov ax, 0f000h ; look in the ROM area for our system name id string search
  534. mov es, ax ; load segment into ROM area
  535. xor di, di ; begin indexing ROM area at 0
  536. mov dx, 8000h ; total area to search
  537. Loop2:
  538. cmp di, dx ; Q: have we exhausted our search?
  539. je short IDCheckFailed ; Y: unable to find string
  540. mov si, di ; save off the data
  541. inc di ; increment 1-byte for next loop
  542. mov ax, word ptr es:[si] ; read 2-bytes
  543. cmp ax, offset SYSID1 ; Q: match?
  544. jne short Loop2 ; N: start again
  545. mov ax, word ptr es:[si+2] ; read next 2-bytes
  546. cmp ax, offset SYSID2 ; Q: match?
  547. jne short Loop2 ; N: start again
  548. mov ax, word ptr es:[si+4] ; read next 2-bytes
  549. cmp ax, offset SYSID3 ; Q: match?
  550. jne short Loop2 ; N: start again
  551. ;
  552. pop es
  553. ;
  554. jmp short MoveSetupLdr ; Y: Join the party...
  555. ;
  556. ; The System specific check failed...this system is not supported.
  557. ;
  558. IDCheckFailed:
  559. ;
  560. pop es
  561. ;
  562. push dx
  563. push cx
  564. push bx
  565. push ax
  566. push bp
  567. mov ax,1301h
  568. mov bx,0007h
  569. mov cx,42
  570. mov dx,0A00h
  571. mov bp, OFFSET NoMatchUS
  572. int 10h
  573. pop bp
  574. pop ax
  575. pop bx
  576. pop cx
  577. pop dx
  578. jmp Continue2
  579. MoveSetupLdr:
  580. ; move Setupldr code from 2000+MaxCodeSize:0000 to 2000:0000, one paragraph at a time.
  581. push ds
  582. push es
  583. mov ax, SetupLdrDestSeg
  584. mov es, ax
  585. add ax, MaxCodeSize
  586. mov ds, ax
  587. mov dx, MaxSetupLdrSize
  588. cld
  589. Again2:
  590. xor di, di
  591. xor si, si
  592. mov cx, 10h
  593. rep movsb
  594. mov ax, ds
  595. inc ax
  596. mov ds, ax
  597. mov ax, es
  598. inc ax
  599. mov es, ax
  600. dec dx
  601. jnz Again2
  602. pop es
  603. pop ds
  604. Continue2:
  605. mov dl, Preserve
  606. JMPFAR 0,SetupLdrDestSeg
  607. ;
  608. ;EXPECTS DS:SI - MESSAGE ADDR
  609. ;
  610. PrintMsg proc near
  611. push ax
  612. push bx
  613. PrintMsgLoop:
  614. lodsb
  615. cmp al,0
  616. je PrintMsgEnd
  617. mov ah,0eh
  618. mov bx,0007h
  619. int 10h
  620. jmp PrintMsgLoop
  621. PrintMsgEnd:
  622. pop bx
  623. pop ax
  624. ret
  625. PrintMsg endp
  626. Preserve db ?
  627. MsgPressKey db 0dh, 0ah, "Press any key to continue..."
  628. db 0
  629. .errnz ($-_BiosChk) GT (MaxCodeSize*16 - 2) ;FATAL: BiosChk code is too large
  630. org MaxCodeSize*16 - 2
  631. db 55h,0aah
  632. CODE ENDS
  633. END START