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.

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