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.

861 lines
28 KiB

  1. ;++
  2. ;
  3. ;Copyright (c) 1995 Compaq Computer Corporation
  4. ;
  5. ;Module Name:
  6. ;
  7. ; etfsboot.asm
  8. ;
  9. ;Abstract:
  10. ;
  11. ; The ROM in the IBM PC starts the boot process by performing a hardware
  12. ; initialization and a verification of all external devices. If an El
  13. ; Torito CD-ROM with no-emulation support is detected, it will then load
  14. ; the "image" pointed to in the Boot Catalog. This "image" is placed at
  15. ; the physical address specified in the Boot Catalog (which should be 07C00h).
  16. ;
  17. ; The code in this "image" is responsible for locating NTLDR, loading the
  18. ; first sector of NTLDR into memory at 2000:0000, and branching to it.
  19. ;
  20. ; There are only two errors possible during execution of this code.
  21. ; 1 - NTLDR does not exist
  22. ; 2 - BIOS read error
  23. ;
  24. ; In both cases, a short message is printed, and the user is prompted to
  25. ; reboot the system.
  26. ;
  27. ;
  28. ;Author:
  29. ;
  30. ; Steve Collins (stevec) 25-Oct-1995
  31. ;
  32. ;Environment:
  33. ;
  34. ; Image has been loaded at 7C0:0000 by BIOS. (or 0000:7C00 to support some broken BIOSes)
  35. ; Real mode
  36. ; ISO 9660 El Torito no-emulation CD-ROM Boot support
  37. ; DL = El Torito drive number we booted from
  38. ;
  39. ;Revision History:
  40. ;
  41. ; Calin Negreanu (calinn) 25-May-1998 - added safety check at the beginning of the code
  42. ; - added code for loading and executing BOOTFIX.BIN
  43. ; - modified error path
  44. ;--
  45. page ,132
  46. title boot - NTLDR ETFS loader
  47. name etfsboot
  48. EtfsCodeSize EQU 2048
  49. BootSeg segment at 07c0h
  50. BootSeg ends
  51. DirSeg segment at 1000h
  52. DirSeg ends
  53. LoadSeg segment at 2000h
  54. LoadSeg ends
  55. BootCode segment ;would like to use BootSeg here, but LINK flips its lid
  56. ASSUME CS:BootCode,DS:NOTHING,ES:NOTHING,SS:NOTHING
  57. public ETFSBOOT
  58. ETFSBOOT proc far
  59. cli
  60. ;WARNING!!! DO NOT CHANGE THE STACK SETUP. BOOTFIX NEEDS THIS TO BE HERE.
  61. xor ax,ax ; Setup the stack to a known good spot
  62. mov ss,ax ; Stack is set to 0000:7c00, which is just below this code
  63. mov sp,7c00h
  64. sti
  65. mov ax,cs ; Set DS to our code segment (should be 07C0h)
  66. mov ds,ax
  67. assume DS:BootCode
  68. ;
  69. ; Save the Drive Number for later use
  70. ;
  71. push dx
  72. ;
  73. ; Let's do some safety checks here. We are going to check for three things:
  74. ; 1. We are loaded at 07c0:0000 or 0000:7C00
  75. ; 2. Boot Drive Number looks good (80h-FFh)
  76. ; 3. Our code was completely loaded by the BIOS
  77. ;
  78. call NextInstr
  79. NextInstr:
  80. pop si ; Get IP from the stack
  81. sub si,OFFSET NextInstr ; See if we run with ORIGIN 0
  82. jz NormalCase ; Yes
  83. cmp si,7C00h ; See if, at least we run with ORIGIN 7C00H
  84. jne BootErr$wof1 ; If not, try to display some message
  85. mov ax,cs ; If offset is 7C00H, segment should be 0
  86. cmp ax,0000h
  87. jne BootErr$wof2 ; If not, try to display some message
  88. ; We are loaded at 0000:7C00 instead of 07C0:0000. This could mess up
  89. ; some stuff so we are going to fix it.
  90. ; hack to execute JMP 07c0:BootOK
  91. db 0eah
  92. dw OFFSET BootOK
  93. dw BootSeg
  94. NormalCase:
  95. mov MSG_BAD_BIOS_CODE, '3'
  96. mov ax,cs ; See if segment is 07C0H
  97. cmp ax,07c0h
  98. jne BootErr$wnb ; If not, try to display some message
  99. BootOK:
  100. ;
  101. ; Reset ds in case we needed to change code segment
  102. ;
  103. mov ax,cs
  104. mov ds,ax
  105. ;
  106. ; OK so far. Let's try to see if drive letter looks good (80h-FFh)
  107. ;
  108. mov MSG_BAD_BIOS_CODE, '4'
  109. cmp dl,80h
  110. jb BootErr$wnb
  111. ;
  112. ; OK so far. Let's try to see if all our code was loaded.
  113. ; We look for our signature at the end of the code.
  114. ;
  115. mov MSG_BAD_BIOS_CODE, '5'
  116. mov bx, EtfsCodeSize - 2
  117. mov ax, WORD PTR DS:[bx]
  118. cmp ax, 0AA55h
  119. jne BootErr$wnb
  120. ;
  121. ; Finally, everything looks good.
  122. ;
  123. ;
  124. ; Save the Drive Number for later use - right now drive number is pushed on the stack
  125. ;
  126. pop dx
  127. mov DriveNum,dl
  128. ;
  129. ; Let's try to load and run BOOTFIX.BIN
  130. ;
  131. .386
  132. push OFFSET BOOTFIXNAME
  133. push 11
  134. push LoadSeg
  135. call LoadFile
  136. jc FindSetupLdr
  137. ;
  138. ; We have BOOTFIX.BIN loaded. We call that code to see if we should boot from CD. If we shouldn't
  139. ; we'll not come back here.
  140. ;
  141. .286
  142. pusha
  143. push ds
  144. push es
  145. ;
  146. ; BOOTFIX requires:
  147. ; DL = INT 13 drive number we booted from
  148. ;
  149. mov dl, DriveNum ; DL = CD drive number
  150. ;hack to execute CALL LoadSeg:0000
  151. db 9Ah
  152. dw 0000h
  153. dw LoadSeg
  154. pop es
  155. pop ds
  156. popa
  157. .8086
  158. FindSetupldr:
  159. ;
  160. ; Scan for the presence of SETUPLDR.BIN
  161. ;
  162. .386
  163. push OFFSET LOADERNAME
  164. push 12
  165. push LoadSeg
  166. call LoadFile
  167. jc BootErr$bnf
  168. ;
  169. ; SETUPLDR requires:
  170. ; DL = INT 13 drive number we booted from
  171. ;
  172. mov dl, DriveNum ; DL = CD drive number
  173. xor ax,ax
  174. .386
  175. push LoadSeg
  176. push ax
  177. retf ; "return" to NTLDR (LoadSeg:0000h). Will not come back here.
  178. ETFSBOOT endp
  179. ;
  180. ; BootErr - print error message and hang the system.
  181. ;
  182. BootErr proc
  183. BootErr$wof1: ; we were loaded at a wrong address - Code 1
  184. PUSH SI
  185. MOV BX, SI
  186. ADD BX, OFFSET MSG_BAD_BIOS_CODE
  187. MOV BYTE PTR DS:[BX], '1'
  188. ADD SI, OFFSET MSG_BAD_BIOS
  189. JMP BootErr2
  190. BootErr$wof2: ; we were loaded at a wrong address - Code 2
  191. PUSH SI
  192. MOV BX, SI
  193. ADD BX, OFFSET MSG_BAD_BIOS_CODE
  194. MOV BYTE PTR DS:[BX], '2'
  195. ADD SI, OFFSET MSG_BAD_BIOS
  196. JMP BootErr2
  197. BootErr$wnb: ; some other BIOS problem
  198. PUSH 0
  199. MOV SI, OFFSET MSG_BAD_BIOS
  200. JMP BootErr2
  201. BootErr$bnf: ; NTLDR not found
  202. PUSH 0
  203. MOV SI, OFFSET MSG_NO_NTLDR
  204. JMP BootErr2
  205. BootErr$mof: ; memory overflow
  206. PUSH 0
  207. MOV SI, OFFSET MSG_MEM_OVERFLOW
  208. JMP BootErr2
  209. BootErr2:
  210. CALL BootErrPrint
  211. POP SI
  212. JMP BootFromHD
  213. BootErrPrint:
  214. LODSB ; Get next character
  215. OR AL, AL
  216. JZ BEdone
  217. MOV AH, 14 ; Write teletype
  218. MOV BX, 7 ; Attribute
  219. INT 10H ; Print it
  220. JMP BootErrPrint
  221. BEdone:
  222. RET
  223. BootErr endp
  224. ;
  225. ; we are trying to boot from HD. We need to move ourself out of
  226. ; this area because we are going to load MBR here
  227. ;
  228. BootFromHD:
  229. ;
  230. ; let's wait here for two seconds, so the user gets a chance to see the message
  231. ;
  232. ;
  233. ; hook INT08
  234. ;
  235. MOV [SI+TicksCount], 24H ; two seconds delay
  236. CLI
  237. PUSH ES
  238. XOR AX, AX
  239. MOV ES, AX
  240. MOV BX, 0020H
  241. MOV AX, ES:[BX]
  242. MOV WORD PTR [SI+OldInt08], AX
  243. MOV AX, ES:[BX+2]
  244. MOV WORD PTR [SI+OldInt08+2], AX
  245. MOV ES:[BX], SI
  246. ADD ES:[BX], OFFSET NewInt08
  247. MOV ES:[BX+2], CS
  248. POP ES
  249. STI
  250. ;
  251. ; now let's actively wait for TicksCount to become zero
  252. ;
  253. Delay:
  254. CMP [SI+TicksCount], 0
  255. JNE Delay
  256. ;
  257. ; unhook INT08
  258. ;
  259. cli
  260. push es
  261. xor ax,ax
  262. mov es,ax
  263. mov bx,08h * 4
  264. mov ax,WORD PTR [SI+OldInt08]
  265. mov es:[bx],ax
  266. mov ax,WORD PTR [SI+OldInt08+2]
  267. mov es:[bx+2],ax
  268. pop es
  269. sti
  270. ;
  271. ; now let's move ourselves away from here because we are going to load MBR here
  272. ;
  273. MoveCode:
  274. push ds
  275. push es
  276. mov ax, LoadSeg
  277. mov es, ax
  278. mov ax, cs
  279. mov ds, ax
  280. ;si is already set
  281. xor di, di
  282. mov cx, EtfsCodeSize
  283. rep movsb
  284. pop es
  285. pop ds
  286. ;hack to execute JMP LoadSeg:AfterMoveLabel
  287. db 0eah
  288. dw OFFSET AfterMoveLabel
  289. dw LoadSeg
  290. AfterMoveLabel:
  291. ;
  292. ; finally load MBR
  293. ;
  294. push es
  295. mov ax, BootSeg
  296. mov es, ax
  297. mov bx, 0000h
  298. mov ax, 0201h ;read function, one sector
  299. mov cx, 0001h
  300. mov dx, 0080h
  301. int 13h
  302. jnc MbrOk
  303. ;
  304. ; there was an error, nothing else to do
  305. ;
  306. jmp $
  307. MbrOk:
  308. pop es
  309. ;
  310. ; now let's return into MBR code
  311. ;
  312. mov dl,80h
  313. ;hack to execute JMP 0000:7C00
  314. db 0eah
  315. dw 7c00h
  316. dw 0000h
  317. ;
  318. ; We rely on the fact that SI is not changed when this INT occurs
  319. ; This is a pretty good assumption since this code is active only
  320. ; within the tight loop near Delay label. The odds are that some
  321. ; other IRQ occures, enables interrupts, changes SI and then INT08
  322. ; occures. This should not happen.
  323. ;
  324. NewInt08:
  325. PUSHF
  326. CLI
  327. CMP CS:[SI+TicksCount], 0
  328. JE Default08
  329. DEC WORD PTR CS:[SI+TicksCount]
  330. Default08:
  331. POPF
  332. PUSH WORD PTR CS:[SI+OldInt08+2]
  333. PUSH WORD PTR CS:[SI+OldInt08]
  334. RETF
  335. include etfsboot.inc ; message text
  336. ;
  337. ; ScanForEntry - Scan for an entry in a directory
  338. ;
  339. ; Entry:
  340. ; ES:0 points to the beginning of the directory to search
  341. ; Directory length in bytes is in ExtentLen1 and Extend_Len_0
  342. ;
  343. ; Exit:
  344. ; CF set on error, clear on success.
  345. ; ES:BX points to record containing entry if match is found
  346. ;
  347. ScanForEntry proc near
  348. mov ScanIncCount, 0
  349. mov cx,ExtentLen0 ; CX = length of root directory in bytes (low word only)
  350. cld ; Work up for string compares
  351. xor bx,bx
  352. xor dx,dx
  353. ScanLoop:
  354. mov si, EntryToFind
  355. mov dl,byte ptr es:[bx] ; directory record length -> DL
  356. cmp dl,0
  357. jz Skip00 ; if the "record length" assume it is "system use" and skip it
  358. mov ax,bx
  359. add ax,021h ; file identifier is at offset 21h in directory record
  360. mov di,ax ; ES:DI now points to file identifier
  361. push cx
  362. xor cx,cx
  363. mov cl,EntryLen ; compare bytes
  364. repe cmpsb
  365. pop cx
  366. jz ScanEnd ; do we have a match?
  367. CheckCountUnderFlow:
  368. ; If CX is about to underflow or be 0 we need to reset CX, ES and BX if ExtentLen1 is non-0
  369. cmp dx,cx
  370. jae ResetCount0
  371. sub cx,dx ; update CX to contain number of bytes left in directory
  372. cmp ScanIncCount, 1
  373. je ScanAdd1ToCount
  374. AdjustScanPtr: ; Adjust ES:BX to point to next record
  375. add dx,bx
  376. mov bx,dx
  377. and bx,0fh
  378. push cx
  379. mov cl,4
  380. shr dx,cl
  381. pop cx
  382. mov ax,es
  383. add ax,dx
  384. mov es,ax
  385. jmp ScanLoop
  386. Skip00:
  387. mov dx,1 ; Skip past this byte
  388. jmp CheckCountUnderFlow
  389. ScanAdd1ToCount:
  390. inc cx
  391. mov ScanIncCount,0
  392. jmp AdjustScanPtr
  393. S0:
  394. mov ScanIncCount,1 ; We'll need to increment Count next time we get a chance
  395. jmp SetNewCount
  396. ResetCount0:
  397. cmp ExtentLen1,0 ; Do we still have at least 64K bytes left to scan?
  398. jne ResetContinue
  399. stc ; We overran the end of the directory - corrupt/invalid directory
  400. ret
  401. ResetContinue:
  402. sub ExtentLen1,1
  403. add bx,dx ; Adjust ES:BX to point to next record - we cross seg boundary here
  404. push bx
  405. push cx
  406. mov cl,4
  407. shr bx,cl
  408. pop cx
  409. mov ax,es
  410. add ax,bx
  411. mov es,ax
  412. pop bx
  413. and bx,0fh
  414. sub dx,cx ; Get overflow amount
  415. je S0 ; If we ended right on the boundary we need to make special adjustments
  416. dec dx
  417. SetNewCount:
  418. mov ax,0ffffh
  419. sub ax,dx ; and subtract it from 10000h
  420. mov cx,ax ; - this is the new count
  421. jmp ScanLoop
  422. ScanEnd:
  423. cmp IsDir,1
  424. je CheckDir
  425. test byte ptr es:[bx][25],2 ; Is this a file?
  426. jnz CheckCountUnderFlow ; No - go to next record
  427. jmp CheckLen
  428. CheckDir:
  429. test byte ptr es:[bx][25],2 ; Is this a directory?
  430. jz CheckCountUnderFlow ; No - go to next record
  431. CheckLen:
  432. mov al,EntryLen
  433. cmp byte ptr es:[bx][32],al ; Is the identifier length correct?
  434. jnz CheckCountUnderFlow ; No - go to next record
  435. clc
  436. ret
  437. ScanForEntry endp
  438. ;
  439. ; ExtRead - Do an INT 13h extended read
  440. ; NOTE: I force the offset of the Transfer buffer address to be 0
  441. ; I force the high 2 words of the Starting absolute block number to be 0
  442. ; - This allows for a max 4 GB medium - a safe assumption for now
  443. ;
  444. ; Entry:
  445. ; Arg1 - word 0 (low word) of Number of 2048-byte blocks to transfer
  446. ; Arg2 - word 1 (high word) of Number of 2048-byte blocks to transfer
  447. ; Arg3 - segment of Transfer buffer address
  448. ; Arg4 - word 0 (low word) of Starting absolute block number
  449. ; Arg5 - word 1 of Starting absolute block number
  450. ;
  451. ; Exit
  452. ; The following are modified:
  453. ; Count0
  454. ; Count1
  455. ; Dest
  456. ; Source0
  457. ; Source1
  458. ; PartialRead
  459. ; NumBlocks
  460. ; Disk Address Packet [DiskAddPack]
  461. ;
  462. ExtRead proc near
  463. push bp ; set up stack frame so we can get args
  464. mov bp,sp
  465. push bx ; Save registers used during this routine
  466. push si
  467. push dx
  468. push ax
  469. mov bx,offset DiskAddPack ; Use BX as base to index into Disk Address Packet
  470. ; Set up constant fields
  471. mov [bx][0],byte ptr 010h ; Offset 0: Packet size = 16 bytes
  472. mov [bx][1],byte ptr 0h ; Offset 1: Reserved (must be 0)
  473. mov [bx][3],byte ptr 0h ; Offset 3: Reserved (must be 0)
  474. mov [bx][4],word ptr 0h ; Offset 4: Offset of Transfer buffer address (force 0)
  475. mov [bx][12],word ptr 0h ; Offset 12: Word 2 of Starting absolute block number (force 0)
  476. mov [bx][14],word ptr 0h ; Offset 14: Word 3 (high word) of Starting absolute block number (force 0)
  477. ;
  478. ; Initialize loop variables
  479. ;
  480. mov ax,[bp][12] ; set COUNT to number of blocks to transfer
  481. mov Count0,ax
  482. mov ax,[bp][10]
  483. mov Count1,ax
  484. mov ax,[bp][8] ; set DEST to destination segment
  485. mov Dest,ax
  486. mov ax,[bp][6] ; set SOURCE to source lbn
  487. mov Source0,ax
  488. mov ax,[bp][4]
  489. mov Source1,ax
  490. ExtReadLoop:
  491. ;
  492. ; First check if COUNT <= 32
  493. ;
  494. cmp Count1,word ptr 0h ; Is upper word 0?
  495. jne SetupPartialRead ; No - we're trying to read at least 64K blocks (128 MB)
  496. cmp Count0,word ptr 20h ; Is lower word greater than 32?
  497. jg SetupPartialRead ; Yes - only read in 32-block increments
  498. mov PartialRead,0 ; Clear flag to indicate we are doing a full read
  499. mov ax,Count0 ; NUMBLOCKS = COUNT
  500. mov NumBlocks,al ; Since Count0 < 32 we're OK just using low byte
  501. jmp DoExtRead ; Do read
  502. SetupPartialRead:
  503. ;
  504. ; Since COUNT > 32,
  505. ; Set flag indicating we are only doing a partial read
  506. ;
  507. mov PartialRead,1
  508. mov NumBlocks,20h ; NUMBYTES = 32
  509. DoExtRead:
  510. ;
  511. ; Perform Extended Read
  512. ;
  513. mov al,NumBlocks ; Offset 2: Number of 2048-byte blocks to transfer
  514. mov [bx][2],al
  515. mov ax,Dest ; Offset 6: Segment of Transfer buffer address
  516. mov [bx][6],ax
  517. mov ax,Source0 ; Offset 8: Word 0 (low word) of Starting absolute block number
  518. mov [bx][8],ax
  519. mov ax,Source1 ; Offset 10: Word 1 of Starting absolute block number
  520. mov [bx][10],ax
  521. mov si,offset DiskAddPack ; Disk Address Packet in DS:SI
  522. mov ah,042h ; Function = Extended Read
  523. mov dl,DriveNum ; CD-ROM drive number
  524. int 13h
  525. ;
  526. ; Determine if we are done reading
  527. ;
  528. cmp PartialRead,1 ; Did we just do a partial read?
  529. jne ExtReadDone ; No - we're done
  530. ReadjustValues:
  531. ;
  532. ; We're not done reading yet, so
  533. ; COUNT = COUNT - 32
  534. ;
  535. sub Count0,020h ; Subtract low-order words
  536. sbb Count1,0h ; Subtract high-order words
  537. ;
  538. ; Just read 32 blocks and have more to read
  539. ; Increment DEST to next 64K segment (this equates to adding 1000h to the segment)
  540. ;
  541. add Dest,1000h
  542. jc BootErr$mof ; Error if we overflowed
  543. ;
  544. ; SOURCE = SOURCE + 32 blocks
  545. ;
  546. add Source0,word ptr 020h ; Add low order words
  547. adc Source1,word ptr 0h ; Add high order words
  548. ; NOTE - I don't account for overflow - probably OK now since we already account for 4 GB medium
  549. ;
  550. ; jump back to top of loop to do another read
  551. ;
  552. jmp ExtReadLoop
  553. ExtReadDone:
  554. pop ax ; Restore registers used during this routine
  555. pop dx
  556. pop si
  557. pop bx
  558. mov sp,bp ; restore BP and SP
  559. pop bp
  560. ret
  561. ExtRead endp
  562. ;
  563. ; ReadExtent - Read in an extent
  564. ;
  565. ; Arg1 - segment to transfer extent to
  566. ;
  567. ; Entry:
  568. ; ExtentLen0 = word 0 (low word) of extent length in bytes
  569. ; ExtentLen1 = word 1 (high word) of extent length in bytes
  570. ; ExtentLoc0 = word 0 (low word) of starting absolute block number of extent
  571. ; ExtentLoc1 = word 1 of starting absolute block number of extent
  572. ;
  573. ; Exit:
  574. ; ExtRead exit mods
  575. ;
  576. ReadExtent proc near
  577. push bp ; set up stack frame so we can get args
  578. mov bp,sp
  579. push cx ; Save registers used during this routine
  580. push bx
  581. push ax
  582. mov cl,11 ; Convert length in bytes to 2048-byte blocks
  583. mov bx,ExtentLen1 ; Directory length = BX:AX
  584. mov ax,ExtentLen0
  585. .386
  586. shrd ax,bx,cl ; Shift AX, filling with BX
  587. .8086
  588. shr bx,cl ; BX:AX = number of blocks (rounded down)
  589. test ExtentLen0,07ffh ; If any of the low-order 11 bits are set we need to round up
  590. jz ReadExtentNoRoundUp
  591. add ax,1 ; We need to round up by incrementing AX, and
  592. adc bx,0 ; adding the carry to BX
  593. ReadExtentNoRoundUp:
  594. push ax ; Word 0 (low word) of Transfer size = AX
  595. push bx ; Word 1 (high word) of Transfer size = BX
  596. .286
  597. push [bp][4] ; Segment used to transfer extent
  598. .8086
  599. push ExtentLoc0 ; Word 0 (low word) of Starting absolute block number
  600. push ExtentLoc1 ; Word 1 of Starting absolute block number
  601. call ExtRead
  602. add sp,10 ; Clean 5 arguments off the stack
  603. pop ax ; Restore registers used during this routine
  604. pop bx
  605. pop cx
  606. mov sp,bp ; restore BP and SP
  607. pop bp
  608. ret
  609. ReadExtent endp
  610. ;
  611. ; GetExtentInfo - Get extent location
  612. ;
  613. ; Entry:
  614. ; ES:BX points to record
  615. ; Exit:
  616. ; Location -> ExtentLoc1 and ExtentLoc0
  617. ; Length -> ExtentLen1 and ExtentLen0
  618. ;
  619. GetExtentInfo proc near
  620. push ax ; Save registers used during this routine
  621. mov ax,es:[bx][2] ; 32-bit LBN of extent
  622. mov ExtentLoc0,ax ; store low word
  623. mov ax,es:[bx][4]
  624. mov ExtentLoc1,ax ; store high word
  625. mov ax,es:[bx][10] ; 32-bit file length in bytes
  626. mov ExtentLen0,ax ; store low word
  627. mov ax,es:[bx][12]
  628. mov ExtentLen1,ax ; store high word
  629. pop ax ; Restore registers used during this routine
  630. ret
  631. GetExtentInfo endp
  632. LoadFile proc near
  633. push bp
  634. mov bp, sp
  635. ;
  636. ; First thing, we need to read in the Primary Volume Descriptor so we can locate the root directory
  637. ;
  638. .286
  639. push 01h ; Word 0 (low word) of Transfer size = 1 block (2048 bytes)
  640. push 0h ; Word 1 (high word) of Transfer size = 0
  641. push DirSeg ; Segment of Transfer buffer = DirSeg
  642. push 010h ; Word 0 (low word) of Starting absolute block number = 10h
  643. push 0h ; Word 1 of Starting absolute block number = 0
  644. .8086
  645. call ExtRead
  646. add sp,10 ; Clean 5 arguments off the stack
  647. ;
  648. ; Determine the root directory location LBN -> ExtentLoc1:ExtentLoc0
  649. ; determine the root directory data length in bytes -> ExtentLen1:ExtentLen0
  650. ;
  651. mov ax,DirSeg ; ES is set to segment used for storing PVD and directories
  652. mov es,ax
  653. ASSUME ES:DirSeg
  654. mov ax,es:[09eh] ; 32-bit LBN of extent at offset 158 in Primary Volume Descriptor
  655. mov ExtentLoc0,ax ; store low word
  656. mov ax,es:[0a0h]
  657. mov ExtentLoc1,ax ; store high word
  658. mov ax,es:[0a6h] ; 32-bit Root directory data length in bytes at offset 166 in Primary Volume Descriptor
  659. mov ExtentLen0,ax ; store low word
  660. mov ax,es:[0a8h]
  661. mov ExtentLen1,ax ; store high word
  662. ;
  663. ; Now read in the root directory
  664. ;
  665. .286
  666. push DirSeg ; Segment used for transfer = DirSeg
  667. .8086
  668. call ReadExtent
  669. add sp,2 ; Clean 1 argument off the stack
  670. ;
  671. ; Scan for the presence of the I386 directory
  672. ; ES points to directory segment
  673. ;
  674. mov EntryToFind, offset I386DIRNAME
  675. mov EntryLen,4
  676. mov IsDir,1
  677. call ScanForEntry
  678. jc EntryNotFound
  679. ;
  680. ; We found the I386 directory entry, so now get its extent location (offset -31 from filename ID)
  681. ; ES:[BX] still points to the directory record for the I386 directory
  682. ;
  683. call GetExtentInfo
  684. ;
  685. ; Now read in the I386 directory
  686. ;
  687. .286
  688. push DirSeg ; Segment used for transfer = DirSeg
  689. .8086
  690. call ReadExtent
  691. add sp,2 ; Clean 1 argument off the stack
  692. ;
  693. ; Scan for the presence of the file that we need
  694. ; ES points to directory segment
  695. ;
  696. mov ax, DirSeg
  697. mov es, ax
  698. mov ax, [bp][8]
  699. mov EntryToFind, ax
  700. mov al, [bp][6]
  701. mov EntryLen, al
  702. mov IsDir,0
  703. call ScanForEntry
  704. jc EntryNotFound
  705. ;
  706. ; We found the needed file, so now get its extent location (offset -31 from filename ID)
  707. ; ES:[BX] still points to the directory record for that code
  708. ;
  709. call GetExtentInfo
  710. ;
  711. ; Now, go read the file
  712. ;
  713. .286
  714. push [bp][4] ; Segment used for transfer
  715. .8086
  716. call ReadExtent
  717. add sp,2 ; Clean 1 argument off the stack
  718. EntryNotFound:
  719. pop bp
  720. ret
  721. LoadFile endp
  722. OldInt08 DD ? ; Default Int08 vector
  723. TicksCount dw 24H ; two seconds
  724. DiskAddPack db 16 dup (?) ; Disk Address Packet
  725. PartialRead db 0 ; Boolean indicating whether or not we are doing a partial read
  726. LOADERNAME db "SETUPLDR.BIN"
  727. BOOTFIXNAME db "BOOTFIX.BIN"
  728. I386DIRNAME db "I386"
  729. DriveNum db ? ; Drive number used for INT 13h extended reads
  730. ExtentLoc0 dw ? ; Loader LBN - low word
  731. ExtentLoc1 dw ? ; Loader LBN - high word
  732. ExtentLen0 dw ? ; Loader Length - low word
  733. ExtentLen1 dw ? ; Loader Length - high word
  734. Count0 dw ? ; Read Count - low word
  735. Count1 dw ? ; Read Count - high word
  736. Dest dw ? ; Read Destination segment
  737. Source0 dw ? ; Read Source - word 0 (low word)
  738. Source1 dw ? ; Read Source - word 1
  739. NumBlocks db ? ; Number of blocks to Read
  740. EntryToFind dw ? ; Offset of string trying to match in ScanForEntry
  741. EntryLen db ? ; Length in bytes of entry to match in ScanForEntry
  742. IsDir db ? ; Boolean indicating whether or not entry to match in ScanForEntry is a directory
  743. ScanIncCount db ? ; Boolean indicating if we need to add 1 to Count after adjustment in ScanForEntry
  744. .errnz ($-ETFSBOOT) GT (EtfsCodeSize - 2) ; FATAL PROBLEM: boot sector is too large
  745. org (EtfsCodeSize - 2)
  746. db 55h,0aah
  747. BootSectorEnd label dword
  748. BootCode ends
  749. END ETFSBOOT