summaryrefslogtreecommitdiffstats
path: root/private/ntos/boot/bootcode/etfs/i386/etfsboot.asm
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/boot/bootcode/etfs/i386/etfsboot.asm')
-rw-r--r--private/ntos/boot/bootcode/etfs/i386/etfsboot.asm584
1 files changed, 584 insertions, 0 deletions
diff --git a/private/ntos/boot/bootcode/etfs/i386/etfsboot.asm b/private/ntos/boot/bootcode/etfs/i386/etfsboot.asm
new file mode 100644
index 000000000..15d2d4a85
--- /dev/null
+++ b/private/ntos/boot/bootcode/etfs/i386/etfsboot.asm
@@ -0,0 +1,584 @@
+;++
+;
+;Copyright (c) 1995 Compaq Computer Corporation
+;
+;Module Name:
+;
+; etfsboot.asm
+;
+;Abstract:
+;
+; The ROM in the IBM PC starts the boot process by performing a hardware
+; initialization and a verification of all external devices. If an El
+; Torito CD-ROM with no-emulation support is detected, it will then load
+; the "image" pointed to in the Boot Catalog. This "image" is placed at
+; the physical address specified in the Boot Catalog (which should be 07C00h).
+;
+; The code in this "image" is responsible for locating NTLDR, loading the
+; first sector of NTLDR into memory at 2000:0000, and branching to it.
+;
+; There are only two errors possible during execution of this code.
+; 1 - NTLDR does not exist
+; 2 - BIOS read error
+;
+; In both cases, a short message is printed, and the user is prompted to
+; reboot the system.
+;
+;
+;Author:
+;
+; Steve Collins (stevec) 25-Oct-1995
+;
+;Environment:
+;
+; Image has been loaded at 7C0:0000 by BIOS.
+; Real mode
+; ISO 9660 El Torito no-emulation CD-ROM Boot support
+; DL = El Torito drive number we booted from
+;
+;Revision History:
+;
+;--
+ page ,132
+ title boot - NTLDR ETFS loader
+ name etfsboot
+
+
+BootSeg segment at 07c0h
+BootSeg ends
+
+DirSeg segment at 1000h
+DirSeg ends
+
+NtLdrSeg segment at 2000h
+NtLdrSeg ends
+
+BootCode segment ;would like to use BootSeg here, but LINK flips its lid
+ ASSUME CS:BootCode,DS:NOTHING,ES:NOTHING,SS:NOTHING
+
+ public ETFSBOOT
+ETFSBOOT proc far
+
+ xor ax,ax ; Setup the stack to a known good spot
+ mov ss,ax ; Stack is set to 0000:7c00, which is just below this code
+ mov sp,7c00h
+
+ mov ax,BootSeg ; Set DS to our code/data segment (07C0h)
+ mov ds,ax
+assume DS:BootCode
+
+;
+; Save the Drive Number for later use
+ mov DriveNum,dl
+
+;
+; The system is now prepared for us to begin reading. First, we need to
+; read in the Primary Volume Descriptor so we can locate the root directory
+;
+.286
+ push 01h ; Word 0 (low word) of Transfer size = 1 block (2048 bytes)
+ push 0h ; Word 1 (high word) of Transfer size = 0
+ push DirSeg ; Segment of Transfer buffer = DirSeg
+ push 010h ; Word 0 (low word) of Starting absolute block number = 10h
+ push 0h ; Word 1 of Starting absolute block number = 0
+.8086
+ call ExtRead
+ add sp,10 ; Clean 5 arguments off the stack
+
+;
+; Determine the root directory location LBN -> ExtentLoc1:ExtentLoc0
+; determine the root directory data length in bytes -> ExtentLen1:ExtentLen0
+;
+ mov ax,DirSeg ; ES is set to segment used for storing PVD and directories
+ mov es,ax
+ASSUME ES:DirSeg
+ mov ax,es:[09eh] ; 32-bit LBN of extent at offset 158 in Primary Volume Descriptor
+ mov ExtentLoc0,ax ; store low word
+ mov ax,es:[0a0h]
+ mov ExtentLoc1,ax ; store high word
+ mov ax,es:[0a6h] ; 32-bit Root directory data length in bytes at offset 166 in Primary Volume Descriptor
+ mov ExtentLen0,ax ; store low word
+ mov ax,es:[0a8h]
+ mov ExtentLen1,ax ; store high word
+
+;
+; Now read in the root directory
+;
+.286
+ push DirSeg ; Segment used for transfer = DirSeg
+.8086
+ call ReadExtent
+ add sp,2 ; Clean 1 argument off the stack
+
+;
+; Scan for the presence of the I386 directory
+; ES points to directory segment
+;
+ mov EntryToFind, offset I386DIRNAME
+ mov EntryLen,4
+ mov IsDir,1
+ call ScanForEntry
+
+;
+; We found the I386 directory entry, so now get its extent location (offset -31 from filename ID)
+; ES:[BX] still points to the directory record for the I386 directory
+;
+ call GetExtentInfo
+
+;
+; Now read in the I386 directory
+;
+.286
+ push DirSeg ; Segment used for transfer = DirSeg
+.8086
+ call ReadExtent
+ add sp,2 ; Clean 1 argument off the stack
+
+;
+; Scan for the presence of SETUPLDR.BIN
+; ES points to directory segment
+;
+ mov ax,DirSeg
+ mov es,ax
+ mov EntryToFind, offset LOADERNAME
+ mov EntryLen,12
+ mov IsDir,0
+ call ScanForEntry
+
+;
+; We found the loader entry, so now get its extent location (offset -31 from filename ID)
+; ES:[BX] still points to the directory record for the LOADER
+;
+ call GetExtentInfo
+
+;
+; Now, go read the file
+;
+.286
+ push NtLdrSeg ; Segment used for transfer = NtLdrSeg
+.8086
+ call ReadExtent
+ add sp,2 ; Clean 1 argument off the stack
+
+;
+; NTLDR requires:
+; DL = INT 13 drive number we booted from
+;
+ mov dl, DriveNum ; DL = CD drive number - this isn't really necessary since DirveNum is already in dl
+ xor ax,ax
+.386
+ push NtLdrSeg
+ push ax
+ retf ; "return" to NTLDR.
+
+ETFSBOOT endp
+
+
+;
+; ScanForEntry - Scan for an entry in a directory
+;
+; Entry:
+; ES:0 points to the beginning of the directory to search
+; Directory length in bytes is in ExtentLen1 and Extend_Len_0
+;
+; Exit:
+; ES:BX points to record containing entry if match is found
+; Otherwise, we jump to error routine
+;
+ScanForEntry proc near
+ mov cx,ExtentLen0 ; CX = length of root directory in bytes (low word only)
+ cld ; Work up for string compares
+ xor bx,bx
+ xor dx,dx
+ScanLoop:
+ mov si, EntryToFind
+ mov dl,byte ptr es:[bx] ; directory record length -> DL
+ cmp dl,0
+ jz Skip00 ; if the "record length" assume it is "system use" and skip it
+ mov ax,bx
+ add ax,021h ; file identifier is at offset 21h in directory record
+ mov di,ax ; ES:DI now points to file identifier
+ push cx
+ xor cx,cx
+ mov cl,EntryLen ; compare bytes
+ repe cmpsb
+ pop cx
+ jz ScanEnd ; do we have a match?
+
+CheckCountUnderFlow:
+ ; If CX is about to underflow or be 0 we need to reset CX, ES and BX if ExtentLen1 is non-0
+ cmp dx,cx
+ jae ResetCount0
+
+ sub cx,dx ; update CX to contain number of bytes left in directory
+ cmp ScanIncCount, 1
+ je ScanAdd1ToCount
+
+AdjustScanPtr: ; Adjust ES:BX to point to next record
+ add dx,bx
+ mov bx,dx
+ and bx,0fh
+ push cx
+ mov cl,4
+ shr dx,cl
+ pop cx
+ mov ax,es
+ add ax,dx
+ mov es,ax
+ jmp ScanLoop
+
+Skip00:
+ mov dx,1 ; Skip past this byte
+ jmp CheckCountUnderFlow
+
+ScanAdd1ToCount:
+ inc cx
+ mov ScanIncCount,0
+ jmp AdjustScanPtr
+
+S0:
+ mov ScanIncCount,1 ; We'll need to increment Count next time we get a chance
+ jmp SetNewCount
+
+ResetCount0:
+ cmp ExtentLen1,0 ; Do we still have at least 64K bytes left to scan?
+ je BootErr$bnf ; We overran the end of the directory - corrupt/invalid directory
+ sub ExtentLen1,1
+
+ add bx,dx ; Adjust ES:BX to point to next record - we cross seg boundary here
+ push bx
+ push cx
+ mov cl,4
+ shr bx,cl
+ pop cx
+ mov ax,es
+ add ax,bx
+ mov es,ax
+ pop bx
+ and bx,0fh
+
+ sub dx,cx ; Get overflow amount
+ je S0 ; If we ended right on the boundary we need to make special adjustments
+ dec dx
+SetNewCount:
+ mov ax,0ffffh
+ sub ax,dx ; and subtract it from 10000h
+ mov cx,ax ; - this is the new count
+ jmp ScanLoop
+
+ScanEnd:
+ cmp IsDir,1
+ je CheckDir
+
+ test byte ptr es:[bx][25],2 ; Is this a file?
+ jnz CheckCountUnderFlow ; No - go to next record
+ jmp CheckLen
+
+CheckDir:
+ test byte ptr es:[bx][25],2 ; Is this a directory?
+ jz CheckCountUnderFlow ; No - go to next record
+
+CheckLen:
+ mov al,EntryLen
+ cmp byte ptr es:[bx][32],al ; Is the identifier length correct?
+ jnz CheckCountUnderFlow ; No - go to next record
+
+ ret
+ScanForEntry endp
+
+;
+; BootErr - print error message and hang the system.
+;
+BootErr proc
+BootErr$bnf:
+ MOV SI,OFFSET MSG_NO_NTLDR
+ jmp short BootErr2
+BootErr$mof:
+ MOV SI,OFFSET MSG_MEM_OVERFLOW
+ jmp short BootErr2
+BootErr2:
+ call BootErrPrint
+ MOV SI,OFFSET MSG_REBOOT_ERROR
+ call BootErrPrint
+ sti
+ jmp $ ;Wait forever
+
+BootErrPrint:
+ LODSB ; Get next character
+ or al,al
+ jz BEdone
+
+ MOV AH,14 ; Write teletype
+ MOV BX,7 ; Attribute
+ INT 10H ; Print it
+ jmp BootErrPrint
+BEdone:
+
+ ret
+BootErr endp
+
+;
+; ExtRead - Do an INT 13h extended read
+; NOTE: I force the offset of the Transfer buffer address to be 0
+; I force the high 2 words of the Starting absolute block number to be 0
+; - This allows for a max 4 GB medium - a safe assumption for now
+;
+; Entry:
+; Arg1 - word 0 (low word) of Number of 2048-byte blocks to transfer
+; Arg2 - word 1 (high word) of Number of 2048-byte blocks to transfer
+; Arg3 - segment of Transfer buffer address
+; Arg4 - word 0 (low word) of Starting absolute block number
+; Arg5 - word 1 of Starting absolute block number
+;
+; Exit
+; The following are modified:
+; Count0
+; Count1
+; Dest
+; Source0
+; Source1
+; PartialRead
+; NumBlocks
+; Disk Address Packet [DiskAddPack]
+;
+ExtRead proc near
+ push bp ; set up stack frame so we can get args
+ mov bp,sp
+
+ push bx ; Save registers used during this routine
+ push si
+ push dx
+ push ax
+
+ mov bx,offset DiskAddPack ; Use BX as base to index into Disk Address Packet
+
+ ; Set up constant fields
+ mov [bx][0],byte ptr 010h ; Offset 0: Packet size = 16 bytes
+ mov [bx][1],byte ptr 0h ; Offset 1: Reserved (must be 0)
+ mov [bx][3],byte ptr 0h ; Offset 3: Reserved (must be 0)
+ mov [bx][4],word ptr 0h ; Offset 4: Offset of Transfer buffer address (force 0)
+ mov [bx][12],word ptr 0h ; Offset 12: Word 2 of Starting absolute block number (force 0)
+ mov [bx][14],word ptr 0h ; Offset 14: Word 3 (high word) of Starting absolute block number (force 0)
+
+;
+; Initialize loop variables
+;
+ mov ax,[bp][12] ; set COUNT to number of blocks to transfer
+ mov Count0,ax
+ mov ax,[bp][10]
+ mov Count1,ax
+
+ mov ax,[bp][8] ; set DEST to destination segment
+ mov Dest,ax
+
+ mov ax,[bp][6] ; set SOURCE to source lbn
+ mov Source0,ax
+ mov ax,[bp][4]
+ mov Source1,ax
+
+ExtReadLoop:
+;
+; First check if COUNT <= 32
+;
+ cmp Count1,word ptr 0h ; Is upper word 0?
+ jne SetupPartialRead ; No - we're trying to read at least 64K blocks (128 MB)
+ cmp Count0,word ptr 20h ; Is lower word greater than 32?
+ jg SetupPartialRead ; Yes - only read in 32-block increments
+
+ mov PartialRead,0 ; Clear flag to indicate we are doing a full read
+
+ mov ax,Count0 ; NUMBLOCKS = COUNT
+ mov NumBlocks,al ; Since Count0 < 32 we're OK just using low byte
+
+ jmp DoExtRead ; Do read
+
+SetupPartialRead:
+;
+; Since COUNT > 32,
+; Set flag indicating we are only doing a partial read
+;
+ mov PartialRead,1
+
+ mov NumBlocks,20h ; NUMBYTES = 32
+
+DoExtRead:
+;
+; Perform Extended Read
+;
+ mov al,NumBlocks ; Offset 2: Number of 2048-byte blocks to transfer
+ mov [bx][2],al
+ mov ax,Dest ; Offset 6: Segment of Transfer buffer address
+ mov [bx][6],ax
+ mov ax,Source0 ; Offset 8: Word 0 (low word) of Starting absolute block number
+ mov [bx][8],ax
+ mov ax,Source1 ; Offset 10: Word 1 of Starting absolute block number
+ mov [bx][10],ax
+
+ mov si,offset DiskAddPack ; Disk Address Packet in DS:SI
+ mov ah,042h ; Function = Extended Read
+ mov dl,DriveNum ; CD-ROM drive number
+ int 13h
+
+;
+; Determine if we are done reading
+;
+ cmp PartialRead,1 ; Did we just do a partial read?
+ jne ExtReadDone ; No - we're done
+
+ReadjustValues:
+;
+; We're not done reading yet, so
+; COUNT = COUNT - 32
+;
+ sub Count0,020h ; Subtract low-order words
+ sbb Count1,0h ; Subtract high-order words
+
+;
+; Just read 32 blocks and have more to read
+; Increment DEST to next 64K segment (this equates to adding 1000h to the segment)
+;
+ add Dest,1000h
+ jc BootErr$mof ; Error if we overflowed
+
+;
+; SOURCE = SOURCE + 32 blocks
+;
+ add Source0,word ptr 020h ; Add low order words
+ adc Source1,word ptr 0h ; Add high order words
+ ; NOTE - I don't account for overflow - probably OK now since we already account for 4 GB medium
+
+;
+; jump back to top of loop to do another read
+;
+ jmp ExtReadLoop
+
+ExtReadDone:
+
+ pop ax ; Restore registers used during this routine
+ pop dx
+ pop si
+ pop bx
+
+ mov sp,bp ; restore BP and SP
+ pop bp
+
+ ret
+ExtRead endp
+
+;
+; ReadExtent - Read in an extent
+;
+; Arg1 - segment to transfer extent to
+;
+; Entry:
+; ExtentLen0 = word 0 (low word) of extent length in bytes
+; ExtentLen1 = word 1 (high word) of extent length in bytes
+; ExtentLoc0 = word 0 (low word) of starting absolute block number of extent
+; ExtentLoc1 = word 1 of starting absolute block number of extent
+;
+; Exit:
+; ExtRead exit mods
+;
+ReadExtent proc near
+ push bp ; set up stack frame so we can get args
+ mov bp,sp
+
+ push cx ; Save registers used during this routine
+ push bx
+ push ax
+
+ mov cl,11 ; Convert length in bytes to 2048-byte blocks
+ mov bx,ExtentLen1 ; Directory length = BX:AX
+ mov ax,ExtentLen0
+
+.386
+ shrd ax,bx,cl ; Shift AX, filling with BX
+.8086
+ shr bx,cl ; BX:AX = number of blocks (rounded down)
+ test ExtentLen0,07ffh ; If any of the low-order 11 bits are set we need to round up
+ jz ReadExtentNoRoundUp
+ add ax,1 ; We need to round up by incrementing AX, and
+ adc bx,0 ; adding the carry to BX
+ReadExtentNoRoundUp:
+
+ push ax ; Word 0 (low word) of Transfer size = AX
+ push bx ; Word 1 (high word) of Transfer size = BX
+.286
+ push [bp][4] ; Segment used to transfer extent
+.8086
+ push ExtentLoc0 ; Word 0 (low word) of Starting absolute block number
+ push ExtentLoc1 ; Word 1 of Starting absolute block number
+ call ExtRead
+ add sp,10 ; Clean 5 arguments off the stack
+
+ pop ax ; Restore registers used during this routine
+ pop bx
+ pop cx
+
+ mov sp,bp ; restore BP and SP
+ pop bp
+
+ ret
+ReadExtent endp
+
+;
+; GetExtentInfo - Get extent location
+;
+; Entry:
+; ES:BX points to record
+; Exit:
+; Location -> ExtentLoc1 and ExtentLoc0
+; Length -> ExtentLen1 and ExtentLen0
+;
+GetExtentInfo proc near
+ push ax ; Save registers used during this routine
+
+ mov ax,es:[bx][2] ; 32-bit LBN of extent
+ mov ExtentLoc0,ax ; store low word
+ mov ax,es:[bx][4]
+ mov ExtentLoc1,ax ; store high word
+ mov ax,es:[bx][10] ; 32-bit file length in bytes
+ mov ExtentLen0,ax ; store low word
+ mov ax,es:[bx][12]
+ mov ExtentLen1,ax ; store high word
+
+ pop ax ; Restore registers used during this routine
+
+ ret
+GetExtentInfo endp
+
+
+include etfsboot.inc ; message text
+
+DiskAddPack db 16 dup (?) ; Disk Address Packet
+PartialRead db 0 ; Boolean indicating whether or not we are doing a partial read
+LOADERNAME db "SETUPLDR.BIN"
+I386DIRNAME db "I386"
+DriveNum db (?) ; Drive number used for INT 13h extended reads
+ExtentLoc0 dw (?) ; Loader LBN - low word
+ExtentLoc1 dw (?) ; Loader LBN - high word
+ExtentLen0 dw (?) ; Loader Length - low word
+ExtentLen1 dw (?) ; Loader Length - high word
+Count0 dw (?) ; Read Count - low word
+Count1 dw (?) ; Read Count - high word
+Dest dw (?) ; Read Destination segment
+Source0 dw (?) ; Read Source - word 0 (low word)
+Source1 dw (?) ; Read Source - word 1
+NumBlocks db (?) ; Number of blocks to Read
+EntryToFind dw (?) ; Offset of string trying to match in ScanForEntry
+EntryLen db (?) ; Length in bytes of entry to match in ScanForEntry
+IsDir db (?) ; Boolean indicating whether or not entry to match in ScanForEntry is a directory
+ScanIncCount db 0 ; Boolean indicating if we need to add 1 to Count after adjustment in ScanForEntry
+
+ .errnz ($-ETFSBOOT) GT 2046 ; FATAL PROBLEM: boot sector is too large
+
+ org 2046
+ db 55h,0aah
+
+BootSectorEnd label dword
+
+BootCode ends
+
+
+ END ETFSBOOT
+