Leaked source code of windows server 2003
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.

723 lines
26 KiB

  1. NEC_98=1
  2. Page ,132
  3. TITLE BOOT SECTOR 1 OF TRACK 0 - BOOT LOADER
  4. ;++
  5. ;
  6. ;Module Name:
  7. ;
  8. ; fat32nec.asm
  9. ;
  10. ;Abstract:
  11. ;
  12. ; The ROM in NEC PC-9800 starts the boot process by performing a hardware
  13. ; initialization and a verification of all external devices. If all goes
  14. ; well, it will then load from the boot drive the sector from track 0, head 0,
  15. ; sector 1. This sector is placed at physical address 1FE00h.
  16. ;
  17. ; We need to load NTLDR at 2000:0. But the bootcode of FAT32 is 600h bytes.
  18. ; If we start at physical address 1FE0:0, the bootcode is broken by loaded NTLDR.
  19. ; At first, we move the bootcode to 0:7C00 from 1FE0:0 by oneself.
  20. ; The next, we jump to new Segment:Offset and start real bootcode procedure.
  21. ;
  22. ; The code is responsible for locating NTLDR and for placing the directory sector
  23. ; with this information.
  24. ;
  25. ; If WINBOOT.SYS is not found, an error message is displayed and the user is
  26. ; prompted to insert another disk. If there is a disk error during the
  27. ; process, a message is displayed and things are halted.
  28. ;
  29. ; At the beginning of the boot sector, there is a table which describes the
  30. ; structure of the media. This is equivalent to the BPB with some
  31. ; additional information describing the physical layout of the driver (heads,
  32. ; tracks, sectors)
  33. ;
  34. ;Author:
  35. ;
  36. ;
  37. ;Environment:
  38. ;
  39. ; Real mode
  40. ; FAT32 file system
  41. ;
  42. ;Revision History:
  43. ;
  44. ; 7/01/97 Tochizawa(NEC) support FAT32
  45. ;
  46. ;--
  47. .xlist
  48. include bpb.inc
  49. include bootsec.inc
  50. include dirent.inc
  51. ;include version.inc
  52. .list
  53. ; ==========================================================================
  54. ORIGIN EQU 7C00H ; Origin of bootstrap LOADER
  55. BIO_SEG EQU 2000H ; Destination segment of BIOS
  56. BIO_OFFSET EQU 0000H ; Offset of bios
  57. SECTOR_SIZE EQU 512 ; Sector size in bytes
  58. DIR_ENTRY_SIZE EQU SIZE DIR_ENTRY ; Size of directory entry in bytes
  59. ROM_DISKRD EQU 2
  60. SIZEBIGBOOTINSEC EQU 3
  61. ifdef NEC_98
  62. BOOTCODE_SEG EQU 0000H ; Destination segment of BOOTCODE
  63. DAUA EQU 584h
  64. endif
  65. ; ==========================================================================
  66. SEGBIOS SEGMENT AT BIO_SEG
  67. ; Define the destination segment of the BIOS, including the
  68. ; initialization label
  69. ORG BIO_OFFSET
  70. WINLOAD LABEL BYTE
  71. SEGBIOS ENDS
  72. ; ==========================================================================
  73. ; Local (on stack) Data storage between temp stack and start of
  74. ; boot sector
  75. CurrBuffFatSecL EQU -12
  76. CurrBuffFatSecH EQU -10
  77. Int13Sectors EQU -8
  78. DataSecL EQU -4
  79. DataSecH EQU -2
  80. ; ==========================================================================
  81. CODE SEGMENT
  82. ASSUME CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING
  83. ORG ORIGIN
  84. Public $START
  85. $START Label byte
  86. jmp short Main
  87. GotXint13:
  88. nop ; used to store xint13 flag
  89. GotXint13Offset = (offset GotXint13 - offset $START)
  90. ; ==========================================================================
  91. ; Start of BPB area of the boot record
  92. OsName DB "MSWIN"
  93. OsVersion DB "4.1" ; Windows version number
  94. BytesPerSector DW SECTOR_SIZE ; Size of a physical sector
  95. SecsPerClust DB 2 ; Sectors per allocation unit
  96. ReservedSecs DW 8 ; Number of reserved sectors
  97. NumFats DB 1 ; Number of fats
  98. NumDirEntries DW 1024 ; Number of direc entries
  99. TotalSectors DW 0 ; Number of sectors - number of hidden
  100. ; sectors (0 when 32 bit sector number)
  101. MediaByte DB 0F8H ; MediaByte byte
  102. NumFatSecs DW 0 ; Number of fat sectors (0 when 32 bit)
  103. SecPerTrack DW 17 ; Sectors per track
  104. NumHeads DW 4 ; Number of drive heads
  105. HiddenSecs DD 1 ; Number of hidden sectors
  106. BigTotalSecs DD 00200000h ; 32 bit version of number of sectors
  107. BigNumFatSecs DD 00001FE0h ; 32 bit version of number of FAT sectors
  108. ExtFlags DW 0
  109. BPBReserved1 DW 0
  110. RootStrtClus DD 0
  111. FSInfoSec dw ((FSInfoSecSig - $START) / SECTOR_SIZE)
  112. BkUpBootSec dw MBR_BOOTFAILBACKUP
  113. BPBReserved2 DD 3 DUP (0)
  114. .errnz ($-BytesPerSector) NE SIZE BIGFATBPB
  115. BootDrv DB 80h
  116. CurrentHead DB 0h ; Current Head
  117. ExtBootSig DB 41
  118. SerialNum DD 0
  119. VolumeLabel DB 'NO NAME '
  120. FatId DB 'FAT32 '
  121. .errnz ($-$START) NE SIZE BIGFATBOOTSEC
  122. ; =========================================================================
  123. ;
  124. ; First thing is to reset the stack to a better and more known
  125. ; place. The ROM may change, but we'd like to get the stack
  126. ; in the correct place.
  127. ;
  128. Main:
  129. ifdef NEC_98
  130. push si ; Save Partition Information
  131. ;
  132. ; We moved bootcode to 0:ORIGIN from 1fe0:0.
  133. ;
  134. push di
  135. mov ax, cs
  136. mov ds, ax ; DS = CS
  137. mov si, 0 ; DS:SI = 1fe0:0
  138. cld
  139. mov cx, 256
  140. xor ax, ax
  141. mov es, ax
  142. mov di, ORIGIN ; ES:DI = 0:7c00
  143. rep movsw
  144. pop di
  145. pop si ; Restore Partition Information
  146. ;
  147. ; We jump to 0:ORIGIN+RealBootStart
  148. ;
  149. mov ax, BOOTCODE_SEG
  150. push ax
  151. mov ax, ORIGIN
  152. add ax, RealBootStart
  153. push ax
  154. retf
  155. RealBootStart = (offset $ - offset $START)
  156. endif
  157. xor CX,CX
  158. mov SS,CX ;Work in stack just below this routine
  159. mov SP,ORIGIN+CurrBuffFatSecL
  160. mov es,cx
  161. mov ds,cx ; DS = ES = SS = 0
  162. ASSUME DS:CODE,ES:CODE,SS:CODE
  163. mov BP,ORIGIN
  164. IFDEF NEC_98
  165. .386
  166. push si ; Save Partition Information
  167. mov al, ds:[DAUA] ;
  168. mov [BP].bgbsDriveNumber, al ; Save DriveNumber
  169. else
  170. ;
  171. ; Determine the number of sectors addressable via
  172. ; conventional int13. If we can't get drive params for some reason
  173. ; then something is very wrong -- we'll try to force the caller
  174. ; to use conventional int13 by maxing out the sector count.
  175. ;
  176. mov [bp].GotXint13Offset,cl ; no xint13 yet
  177. mov dl,[bp].bgbsDriveNumber ; int13 unit number
  178. mov ah,8 ; get drive params
  179. int 13h ; call BIOS
  180. jnc @f ; no error, procede
  181. mov cx,-1 ; strange case, fake registers to force
  182. mov dh,cl ; use of standard int13 (set all vals to max)
  183. @@:
  184. .386
  185. movzx eax,dh ; eax = max head # (0-255)
  186. inc ax ; eax = heads (1-256)
  187. movzx edx,cl ; edx = sectors per track + cyl bits
  188. and dl,3fh ; edx = sectors per track (1-63)
  189. mul dx ; eax = sectors per cylinder, edx = 0
  190. xchg cl,ch
  191. shr ch,6 ; cx = max cylinder # (0-1023)
  192. inc cx ; cx = cylinders (1-1024)
  193. movzx ecx,cx ; ecx = cylinders (1-1024)
  194. mul ecx ; eax = sectors visible via int13, edx = 0
  195. mov [bp].Int13Sectors,eax ; save # sectors addressable via int13
  196. ENDIF
  197. .8086
  198. ;
  199. ; The MBR (or boot ROM) only reads one boot sector. Thus the first order
  200. ; of business is to read the rest of ourself in by reading the second
  201. ; boot sector of the 2-sector boot record.
  202. ;
  203. ; The second sector in the NT case is at sector 12. This preserves
  204. ; the bootsect.dos logic and eliminates a special case for fat32.
  205. ;
  206. ReadBoot:
  207. cmp [BP].bgbsBPB.oldBPB.BPB_SectorsPerFAT,0 ; FAT32 BPB?
  208. jne short NoSysMsg ; No, invalid, messed up
  209. cmp [BP].bgbsBPB.BGBPB_FS_Version,FAT32_Curr_FS_Version
  210. ja short NoSysMsg ; boot code too old for this volume
  211. .386
  212. mov eax,dword ptr [BP].bgbsBPB.oldBPB.BPB_HiddenSectors
  213. add eax,12 ; read in the second boot sector
  214. .8086
  215. mov BX,ORIGIN + (SECTOR_SIZE * 2)
  216. mov cx,1
  217. call DoRead ; doesn't return if err
  218. jmp DirRead ; no error, continue boot in sector 2
  219. DiskError:
  220. mov al,byte ptr [MSGOFF_IOERROR]
  221. ;
  222. ; Al is the offset - 256 of the message within the boot sector.
  223. ; So we first calculate the real segment-based offset to the message
  224. ; and stick it in si so lodsb will work later.
  225. ;
  226. DisplayError:
  227. .ERRNZ ORIGIN MOD 256
  228. mov ah,(ORIGIN / 256) + 1
  229. ifdef NEC_98
  230. add ax, 2
  231. mov di, 0
  232. endif
  233. mov si,ax
  234. DisplayError1:
  235. ifdef NEC_98
  236. mov ax, 0a000h ; set V-RAM
  237. mov es, ax
  238. xor ah, ah
  239. lodsb ; Get next character
  240. cmp AL,0Dh ; end of message?
  241. jz WaitForKey ; yes
  242. cmp AL,0FFh ; end of sub-message?
  243. je DisplayWait ; yes, switch to final message now
  244. stosw ; move to vram
  245. jmp short DisplayError1
  246. else
  247. lodsb ; get next character
  248. test AL,AL ; end of message?
  249. jz WaitForKey ; yes
  250. cmp AL,0FFh ; end of sub-message?
  251. je DisplayWait ; yes, switch to final message now
  252. mov AH,14 ; write character & attribute
  253. mov BX,7 ; attribute (white char on black)
  254. int 10h ; print the character
  255. jmp short DisplayError1
  256. endif
  257. DisplayWait:
  258. mov al,byte ptr [MSGOFF_COMMON]
  259. ifdef NEC_98
  260. mov ah,(ORIGIN / 256) + 1
  261. add ax, 2
  262. mov si,ax
  263. mov di, 160
  264. jmp short DisplayError1
  265. else
  266. jmp short DisplayError
  267. endif
  268. NoSysMsg:
  269. mov al,byte ptr [MSGOFF_NOSYS] ; point to no system file message
  270. jmp short DisplayError
  271. WaitForKey:
  272. ifdef NEC_98
  273. mov ax, 0h
  274. int 18h
  275. mov al, 0h
  276. out 0f0h, al
  277. else
  278. cbw ;warning assumes al is zero!
  279. int 16h ; get character from keyboard
  280. int 19h ; Continue in loop till good disk
  281. endif
  282. ; =========================================================================
  283. ;
  284. ; Read disk sector(s). This routine cannot transfer more than 64K!
  285. ;
  286. ; Inputs: EAX == physical sector #
  287. ; CL == # sectors (CH == 0)
  288. ; ES:BX == transfer address
  289. ;
  290. ; Outputs: EAX next physical sector #
  291. ; CX == 0
  292. ; ES:BX -> byte after last byte of read
  293. ; Does not return if error
  294. ;
  295. ; Reads sectors, switching to extended int13 if necessary and
  296. ; available. The note below is for the conventional int13 case.
  297. ;
  298. ; Notes: Reads sectors one at a time in case they straddle a
  299. ; track boundary. Performs full 32-bit division on the
  300. ; first decomposition (of logical sector into track+sector)
  301. ; but not on the second (of track into cylinder+head),
  302. ; since (A) we don't have room for it, and (B) the results
  303. ; of that division must yield a quotient < 1024 anyway, because
  304. ; the CHS-style INT 13h interface can't deal with cylinders
  305. ; larger than that.
  306. ;
  307. ; =========================================================================
  308. DoRead:
  309. .386
  310. pushad
  311. IFDEF NEC_98
  312. shld edx,eax,16 ; EAX -> DX:AX
  313. mov CX,AX ; We've gotten Phy.Sector# in DX:CX
  314. mov bp,bx ; Buffer addr -> bp
  315. mov bx,SECTOR_SIZE ; Sector size -> bx
  316. push ds
  317. xor ax,ax
  318. mov ds,ax ; DS = 0
  319. mov al,ds:[DAUA] ; set booting da/ua
  320. pop ds ; Restore DS
  321. and al,7fh ; strip high 1 bit
  322. ; SCSI HD
  323. mov ah,06h ; set read command
  324. int 1bh
  325. else
  326. ;
  327. ; Determine if the sector we're about to read is available via
  328. ; conventional int13.
  329. ;
  330. cmp eax,[bp].Int13Sectors ; determine if standard int13 is ok
  331. jb stdint13
  332. ;
  333. ; Need extended int13. First set up parameter packet on stack.
  334. ; Then, if we don't know whether xint13 is available for the drive yet,
  335. ; find out. If not, error out since we know we can't read the sector
  336. ; we need.
  337. ;
  338. db 66h ; hand-coded 32-bit push of 8-bit immediate
  339. push 0 ; high 32 bits of sector #
  340. push eax ; low 32 bits of sector #
  341. push es
  342. push bx ; transfer address
  343. push dword ptr 10010h ; transfer 1 sector, packet size = 16
  344. cmp byte ptr [bp].GotXint13Offset,0 ; have xint13?
  345. jnz xint13ok ; yes, do the read
  346. mov ah,41h
  347. mov bx,055aah
  348. mov dl,[bp].bgbsDriveNumber
  349. int 13h ; check availability
  350. jc xint13err ; error from int13 means no xint13
  351. cmp bx,0aa55h ; absence of sig means no xint13
  352. jne xint13err
  353. test cl,1 ; bit 0 off means no xint13
  354. jz xint13err
  355. inc byte ptr [bp].GotXint13Offset ; have xint13, remember for next time
  356. xint13ok:
  357. mov ah,42h ; extended read
  358. mov dl,[bp].bgbsDriveNumber ; dl = int13 unit #
  359. mov si,sp ; ds:si -> param packet
  360. int 13h ; perform the read
  361. db 0b0h ; HACK: avoid stc by making next
  362. ; byte part of mov al,xx instruction
  363. xint13err:
  364. stc ; this instruction MUST follow previous byte!
  365. pop eax ; throw away param packet without
  366. pop eax ; clobbering carry flag
  367. pop eax
  368. pop eax
  369. jmp short did_read
  370. stdint13:
  371. ;
  372. ; Read via conventional int13
  373. ;
  374. xor edx,edx ; edx:eax = absolute sector number
  375. movzx ecx,[bp].bgbsBPB.oldBPB.BPB_SectorsPerTrack ; ecx = sectors per track
  376. div ecx ; eax = track, edx = sector within track (0-62)
  377. inc dl ; dl = sector within track (1-63)
  378. mov cl,dl ; cl = sector within track
  379. mov edx,eax
  380. shr edx,16 ; dx:ax = track
  381. div [bp].bgbsBPB.oldBPB.BPB_Heads ; ax = cylinder (0-1023), dx = head (0-255)
  382. xchg dl,dh ; dh = head
  383. mov dl,[bp].bgbsDriveNumber ; dl = int13 unit #
  384. mov ch,al ; ch = bits 0-7 of cylinder
  385. shl ah,6
  386. or cl,ah ; bits 6-7 of cl = bits 8-9 of cylinder
  387. mov ax,201h ; read 1 sector
  388. int 13h
  389. did_read:
  390. ENDIF
  391. popad
  392. jc DiskError
  393. add bx,SECTOR_SIZE ; advance transfer address
  394. inc eax ; next sector number
  395. dec cx ; loop instruction is out of range,
  396. jnz DoRead ; have to do it manually
  397. ret
  398. .8086
  399. Public WinBoot ; System boot file (11 bytes)
  400. WinBoot DB "NTLDR "
  401. ;
  402. ; Message table.
  403. ;
  404. ; We put English messages here as a placeholder only, so that in case
  405. ; anyone uses bootf32.h without patching new messages in, things will
  406. ; still be correct (in English, but at least functional).
  407. ;
  408. .errnz ($-$START) GT 1ACH
  409. ORG ORIGIN + 01ACH ; shift message to coincide with that in FAT
  410. ; this will help driver to think the MBR
  411. ; is empty when dealing with FAT32 superfloppy
  412. include msgstub.inc
  413. ;
  414. ; Now build a table with the low byte of the offset to each message.
  415. ; Code that patches the boot sector messages updates this table.
  416. ;
  417. .errnz ($-$START) GT (SECTOR_SIZE-7)
  418. ORG ORIGIN + SECTOR_SIZE - 7
  419. MSGOFF_NOSYS:
  420. db OFFSET (MSG_NOSYS - ORIGIN) - 256
  421. MSGOFF_IOERROR:
  422. db OFFSET (MSG_IOERROR - ORIGIN) - 256
  423. MSGOFF_COMMON:
  424. db OFFSET (MSG_COMMON - ORIGIN) - 256
  425. ORG ORIGIN + (SECTOR_SIZE - 4)
  426. DD BOOTSECTRAILSIG ; Boot sector signature (4 bytes)
  427. .errnz ($-$START) NE SECTOR_SIZE
  428. SecndSecStart label byte
  429. ;
  430. ; The second boot sector contains nothing but data. This sector is re-written
  431. ; by MS-DOS with a fairly high frequency due to changes made to the fsinfo
  432. ; structure. We don't want the actual boot code to get accidentally corrupted.
  433. ;
  434. FSInfoSecSig label byte
  435. .errnz ($-SecndSecStart) NE 0
  436. DD SECONDBOOTSECSIG
  437. db (SECTOR_SIZE - ($-FSInfoSecSig) - 4 - (SIZE BIGFATBOOTFSINFO)) DUP (0)
  438. .errnz ($-SecndSecStart) NE (OFFSETFSINFOFRMSECSTRT)
  439. fsinfo BIGFATBOOTFSINFO <FSINFOSIG,0FFFFFFFFh,000000002h>
  440. .errnz ($-FSInfoSecSig) NE OFFSETTRLSIG
  441. DD BOOTSECTRAILSIG ; Boot sector signature (4 bytes)
  442. .errnz ($-$START) NE (SECTOR_SIZE * 2)
  443. StrtThirdBootSector LABEL BYTE
  444. DirRead:
  445. .386
  446. movzx eax,[BP].bgbsBPB.oldBPB.BPB_NumberOfFATs ; Determine sector dir starts on (NumFats)
  447. mov ecx,dword ptr [BP].bgbsBPB.BGBPB_BigSectorsPerFat
  448. mul ecx ; EAX = (NumFatSecs)
  449. add EAX,dword ptr [BP].bgbsBPB.oldBPB.BPB_HiddenSectors ; (HiddenSecs)
  450. movzx edx,[BP].bgbsBPB.oldBPB.BPB_ReservedSectors ;(ReservedSecs)
  451. add EAX,EDX
  452. ;
  453. ; EAX = NumFats * NumFatSecs + ReservedSecs + cSecHid
  454. ; (first physical sector of cluster area)
  455. ;
  456. mov dword ptr [BP].DataSecL,EAX
  457. mov dword ptr [BP].CurrBuffFatSecL,0FFFFFFFFh
  458. DirReRead:
  459. mov eax,dword ptr [BP].bgbsBPB.BGBPB_RootDirStrtClus
  460. cmp eax,2
  461. jb NoSysMsg
  462. cmp eax,00FFFFFF8h
  463. jae NoSysMsg
  464. ; EAX is starting cluster of root directory
  465. DirCluster:
  466. push eax ; save starting cluster number
  467. sub eax,2 ; Convert to 0 based cluster #
  468. movzx EBX,[BP].bgbsBPB.oldBPB.BPB_SectorsPerCluster
  469. mov si,bx ; Sector count to SI for sector loop
  470. mul EBX ; compute logical sector in EAX
  471. add EAX,dword ptr [BP].DataSecL ; Add data start bias
  472. DirSector:
  473. mov BX,ORIGIN+(SIZEBIGBOOTINSEC*SECTOR_SIZE)
  474. mov DI,BX ; save address in DI for comparisons
  475. mov CX,1
  476. call DoRead ; doesn't return if error
  477. ; relies on return cx=0
  478. DirEntry:
  479. cmp byte ptr [di],ch ; empty, NUL directory entry?
  480. je short MissingFile ; yes, that's the end
  481. mov CL,11
  482. push SI
  483. mov si,offset WinBoot
  484. repz cmpsb ; see if the same
  485. pop SI
  486. jz short DoLoad ; if so, continue booting
  487. add DI,CX ; Finish advance to end of name field
  488. add DI,DIR_ENTRY_SIZE-11 ; Next dir entry
  489. cmp DI,BX ; exhausted this root dir sector yet?
  490. jb DirEntry ; no, check next entry
  491. dec SI ; decrement # dir sectors
  492. jnz DirSector ; More dir sectors in this cluster
  493. pop eax ; recover current root dir cluster
  494. call GetNextFatEntry
  495. jc DirCluster ; Do next Root dir cluster
  496. MissingFile:
  497. add sp,4 ; Discard EAX saved on stack
  498. jmp NoSysMsg
  499. CurrentSegment dw BIO_SEG
  500. ;
  501. ; We now load NTLDR
  502. ;
  503. ; All we have to do is multiply the file's starting cluster
  504. ; (whose directory entry is at DS:DI-11) by sectors per cluster and
  505. ; add that to the disk's starting data sector. We read ntldr into
  506. ; 2000:0, and begin execution there.
  507. ;
  508. DoLoad:
  509. add sp,4 ; Discard DX:AX saved on stack above
  510. mov si,[DI-11].DIR_FIRSTHIGH
  511. mov di,[DI-11].DIR_FIRST ; SI:DI = NTLDR starting cluster
  512. mov ax,si
  513. shl eax,16
  514. mov ax,di ; EAX = NTLDR starting cluster
  515. cmp eax,2 ; valid cluster #?
  516. jb NoSysMsg ; NO!
  517. cmp eax,00FFFFFF8h
  518. jae NoSysMsg ; NO!
  519. ReadAcluster:
  520. push eax ; save cluster number
  521. sub eax,2 ; Subtract first 2 reserved clusters
  522. movzx ecx,[BP].bgbsBPB.oldBPB.BPB_SectorsPerCluster ; ECX = Sectors per cluster (SecsPerClust)
  523. mul ecx ; EAX = logical sector #
  524. add eax,dword ptr [BP].DataSecL ; EAX = physical sector #
  525. mov bx,BIO_OFFSET
  526. push es
  527. mov es,CurrentSegment ; ES:BX = destination for read
  528. call DoRead ; read all sectors in cluster, doesn't return if error
  529. pop es
  530. pop eax ; recover current 0-based cluster#
  531. shr bx,4 ; updated offset -> paragraphs
  532. add CurrentSegment,bx ; update segment for next read
  533. call GetNextFatEntry ; get 2-based successor cluster in EAX
  534. jnc StartItUp ; if end of cluster chain reached
  535. jc ReadACluster ; keep sucking up clusters
  536. .8086
  537. ;
  538. ; NTLDR requires the following input conditions:
  539. ;
  540. ; DL = boot drive #
  541. ;
  542. StartItUp:
  543. mov DL,[BP].bgbsDriveNumber
  544. ifdef NEC_98
  545. lea si,[BP].bgbsBPB
  546. pop bp ; Restore Partition Information
  547. endif
  548. jmp FAR PTR WINLOAD ; CRANK UP THE WINDOWS NT BOOT LOADER
  549. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  550. ;
  551. ; GetNextFatEntry
  552. ;
  553. ; Given the last cluster found, this will return the next cluster
  554. ; of a chain of clusters. If the last cluster is (ffff)(f)ff8 - (ffff)(f)fff,
  555. ; then the final cluster has been loaded.
  556. ;
  557. ; INPUTS:
  558. ; EAX = CurrentCluster (0 based cluster #)
  559. ;
  560. ; OUTPUTS:
  561. ; EAX = Next cluster (2 based cluster #)
  562. ; Carry CLEAR if all done, SET if not
  563. ;
  564. ; USES:
  565. ; EAX,EBX,ECX,EDX,ESI,DI es
  566. ;
  567. GetNextFatEntry PROC NEAR
  568. ; NOTE For following... FAT32 cluster numbers are 28 bits not 32,
  569. ; so we know the following multiply (shl DX:AX by 2) will never
  570. ; overflow into carry.
  571. .386
  572. shl eax,2
  573. call GetFatSector
  574. mov EAX,dword ptr ES:[DI+BX]
  575. and EAX,0FFFFFFFh ; Mask to valid FAT32 cluster # bits
  576. cmp EAX,00FFFFFF8h ; carry CLEAR if all done, SET if not
  577. .8086
  578. ret
  579. GetNextFatEntry ENDP
  580. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  581. ;
  582. ; GetFatSector
  583. ;
  584. ; Read the corresponding FAT sector into the second boot sector
  585. ;
  586. ; INPUTS:
  587. ; EAX == offset (from FAT entry 0) of entry to find
  588. ;
  589. ; OUTPUTS:
  590. ; ES:DI+BX -> corresponding FAT entry in the FAT sector
  591. ;
  592. ; USES:
  593. ; BX,EAX,ECX,EDX,DI
  594. ;
  595. GetFatSector PROC NEAR
  596. .386
  597. mov DI,ORIGIN + SECTOR_SIZE
  598. movzx ECX,[BP].bgbsBPB.oldBPB.BPB_BytesPerSector
  599. xor edx,edx
  600. div ECX ; EAX = Sector number, (E)DX = Offset
  601. cmp EAX,dword ptr [BP].CurrBuffFatSecL ; The same fat sector?
  602. je short SetRet ; Don't need to read it again
  603. mov dword ptr [BP].CurrBuffFatSecL,EAX
  604. add EAX,dword ptr [BP].bgbsBPB.oldBPB.BPB_HiddenSectors
  605. movzx ecx,[BP].bgbsBPB.oldBPB.BPB_ReservedSectors
  606. add eax,ecx ; Point at 1st (0th) FAT
  607. movzx ebx,[BP].bgbsBPB.BGBPB_ExtFlags
  608. and bx,BGBPB_F_ACTIVEFATMSK
  609. jz short GotFatSec
  610. cmp bl,[BP].bgbsBPB.oldBPB.BPB_NumberOfFATs
  611. jae NoSysMsg
  612. push dx ; Save offset of cluster in the FAT sec
  613. mov ecx,eax ; Save FAT sector # in 0th FAT
  614. mov eax,dword ptr [BP].bgbsBPB.BGBPB_BigSectorsPerFat
  615. mul ebx ; EAX = Sector offset to active FAT
  616. ; from 0th FAT
  617. add eax,ecx
  618. pop dx
  619. GotFatSec:
  620. push dx ; Save offset of cluster in the FAT sec
  621. mov BX,DI
  622. mov CX,1
  623. call DoRead ; do the disk read, doesn't return if error
  624. pop dx
  625. SetRet:
  626. mov BX,DX ; set BX to the offset of the cluster
  627. .8086
  628. ret
  629. GetFatSector ENDP
  630. db ((SECTOR_SIZE - ($-StrtThirdBootSector)) - 4) DUP (0)
  631. .errnz ($-StrtThirdBootSector) NE OFFSETTRLSIG
  632. DD BOOTSECTRAILSIG ; Boot sector signature (4 bytes)
  633. .errnz ($-$START) NE (SECTOR_SIZE * 3)
  634. .errnz SIZEBIGBOOTINSEC NE 3
  635. $BigEnd label byte
  636. CODE ENDS
  637. END