singrdk/base/boot/BootSectors/Etfs_BS.asm

305 lines
9.2 KiB
NASM

;;
;; Copyright (c) Microsoft Corporation. All rights reserved.
;;
;;;;;;;;;;;;;;;;;;;;
; Concerns
; 1 - there is no error checking on the int13 calls
; 2 - we assume that the block size is 2048 bytes
; 3 - this cannot handle large root directories (>64KB)
;;;;;;;;;;;;;;;;;;;;
; Constants
BootSecOrigin EQU 07c00h ; the BIOS puts the boot sector at 07c0h:0000 == 0000:7c00h
StackOffset EQU -12 ; we will put the stack a small bit below it (we hardly use the stack, so it is safe...)
;;;;;;;;;;;;;;;;;;;;
; Macros
JMPF16 MACRO SEG:REQ,OFF:REQ
db 0eah
dw OFF
dw SEG
ENDM
;;;;;;;;;;;;;;;;;;;;
; Directives
.model tiny
.686p
;;;;;;;;;;;;;;;;;;;;
; Begin Code segment
_TEXT SEGMENT use16 ; 16-bit code segment
.code
ORG 0h ; ETFS puts us at 07c0h:0000
start:
JMPF16 07c0h,OFFSET Step1
Step1: ; set stack and data segments
mov cx, cs
mov ss, cx
mov sp, BootSecOrigin + StackOffset
mov es, cx
mov ds, cx
mov bp, sp
Step2: ; Save the boot drive (dl holds it on boot)
mov [CDDrive], dl
Step3: ; Clear the Screen
mov ax, 02h
int 010h
;; Configure GS to point to the text-mode video console.
mov ax, 0b800h
mov gs, ax
;; Write 'A' to position 0.
mov ax, 04f41h
mov gs:[0], ax
;; Write 'B' to position 1.
mov ax, 04f42h
mov gs:[2], ax
Step4: ; Load the PVD to get the Logical Block Size
mov eax, 10h ; the PVD is in the 16th block
mov bx, 2000h
mov es, bx ; transfer address = 2000:0000
mov cx, 1
call ReadDisk
mov ax, es:128 ; block size is at offset 128
mov [BlockSize], ax
;; Write 'C' to position 2.
mov ax, 04f43h
mov gs:[4], ax
Step5: ; Find the Joliet SVD, and then find the Root Directory Information
mov eax, 10h ; start with the PVD, even though it will fail
GetNextVD:
push eax
mov cx, 1
call ReadDisk
mov si, OFFSET SVDesc ; [ds:si] points to the desired first 6 bytes of this VD
xor di, di ; [es:di] points to the start of what we just read
mov cx, 6
repe cmpsb
je FoundSVD
mov al, es:0000h
cmp al, 0FFh ; is this the last Volume Descriptor?
je SVDError
pop eax
inc eax
jmp GetNextVD ; try another VD
FoundSVD: ; need to make sure this is a Joliet SVD - we need 025h, 02Fh, 045h in [88,89,90]
mov si, OFFSET JolietSig ; [ds:si] points to the Joliet Signature
mov di, 88 ; [es:di] points to the escape sequence field of the current SVD
mov cx, 3
repe cmpsb
je FoundJoliet
pop eax
inc eax
jmp GetNextVD
FoundJoliet:
;; Write 'D' to position 3.
mov ax, 04f44h
mov gs:[6], ax
mov eax, es:158 ; now get the rootstart and rootsize fields
mov [RootStart], eax
mov eax, es:166
mov [RootSize], eax
Step6: ; Load the Root Directory (SVD), and search it for SINGLDR
movzx ebx, [BlockSize]
div ebx ; eax has # blocks in root directory. Round up if necessary:
cmp edx, 0
je ReadyToLoad
add eax, 1
ReadyToLoad: ; we're going to assume that the root directory will not be bigger than 64K
mov ecx, eax
mov eax, [RootStart]
call ReadDisk
xor ebx, ebx ; bx will hold the start of the current entry
CheckEntry:
mov di, bx
add di, 25 ; let's check the file flags - should be 00
mov al, es:[di]
cmp al, 0
jne PrepNextEntry
; file flags are good. now check the file identifier:
mov si, OFFSET Stage2FileSize
xor cx, cx
mov cl, ds:[si] ; first byte is file name length
add cx, 2 ; add two because we check the length byte of the directory entry and the padding byte, too
add di, 7 ; now es:di points to the file length/name field, and ds:si has our desired content
repe cmpsb
je FoundEntry
PrepNextEntry:
xor cx, cx ; increment bx by adding the byte value in es:[bx]
mov cl, es:[bx] ; if es:[bx]==0 and ebx!= [RootSize], then we are in a padding zone
cmp cx, 0 ; designed to prevent a directory entry from spilling over a block.
jne LoadNext ; Should this be the case, we will increment bx until es:[bx] is not null
inc bx
jmp PrepNextEntry
LoadNext:
add bx, cx
cmp ebx, [RootSize]
jl CheckEntry
jmp FileNotFoundError
FoundEntry:
;; Write 'E' to position 5.
mov ax, 04f45h
mov gs:[8], ax
mov eax, es:[bx+2]
mov [FileStart], eax
mov eax, es:[bx+10]
mov [FileSize], eax
Step7: ; Load the file to 57c0:0000
mov cx, 057c0h
mov es, cx
movzx ebx, [BlockSize]
div ebx ; eax has # blocks in root directory
cmp edx, 0 ; on carry, there will be one more block
je ReadyToLoadFile
add eax, 1
ReadyToLoadFile:
mov ecx, eax
mov eax, [FileStart]
call ReadDisk
;; Write 'F' to position 6.
mov ax, 04f46h
mov gs:[10], ax
Step8: ; Now we need to set up the stack for SINGLDR and do a jump
xor cx, cx ; Always point the stack to 0000:7c00h - 12
mov ss, cx
mov sp, BootSecOrigin + StackOffset
movzx edx, [CDDrive]
push edx ; SINGLDR will need to know the boot drive #
pushd 04344h ; CD boot signature
pushw offset infloop ; return address = "infloop", which is the infinite loop
push cs
;; Write 'G' to position 7.
mov ax, 04f47h
mov gs:[12], ax
db 0EAh ; emit a long jump to 5000:7c00
dd 50007c00h
;;;;;;;;;;;;;;;;;;;;
; ReadDisk
;
; Inputs: eax = Block Number
; cx = number of blocks to read (warning: cx > 32 will cause overflow)
; es = destination segment
; Assumptions: 1 - assumes request will not cause overflow of es:00 (limit on # sectors)
; 2 - assumes int13 extensions available
ReadDisk PROC NEAR
pushad
mov dl, [CDDrive] ; set the drive
pushd 00
push eax ; push 64-bit block number (top half always null)
push es
pushw 00h ; push transfer address
push cx ; # sectors
pushw 0010h ; this request packet is 16 bytes
mov ah,42h ; extended read
mov si,sp ; ds:si = address of params
int 13h ; perform the read
add sp, 10h ; clean the stack and return
popad
ret
ReadDisk ENDP
;;;;;;;;;;;;;;;;;;;;
; Error Routines (these are jump points that never return)
SVDError:
mov si, offset SvdFailMsg
call PrintString
@@:
jmp @b
FileNotFoundError:
mov si, offset FileNotFoundMsg
call PrintString
@@:
jmp @b
PrintString:
psnext:
lodsb
or al, al
jz done
;;; Write directly to memory.
mov ah, 047h
mov bx, [Cursor]
mov gs:[bx], ax
add bx, 2
mov [Cursor], bx
mov bx, 07h ; normal attribute
mov ah, 0eh ; default print 1 char
int 10h
jmp psnext
done:
ret
infloop:
jmp infloop
;;;;;;;;;;;;;;;;;;;;
; Global Vars
RootStart DD 0
RootSize DD 0
CDDrive DB 0
BlockSize DW 0
FileStart DD 0
FileSize DD 0
Cursor DW 640
;;;;;;;;;;;;;;;;;;;;
; String Constants
SVDesc DB 02h, "CD001"
JolietSig DB 25h, 2fh, 45h ; this is the value of the escape sequence for a Joliet CD
; we'll use it as the signature...
Stage2FileSize DB OFFSET Stage2FilePad - OFFSET Stage2File
Stage2File DB 0,"S",0,"i",0,"n",0,"g",0,"l",0,"d",0,"r" ; in unicode, this is how our filename will appear
Stage2FilePad DB 0
SvdFailMsg DB 10,13,"SVD Failed",0
FileNotFoundMsg DB 10,13,"File not found",0
;;;;;;;;;;;;;;;;;;;;
; Boot Sector Signature
ORG 510
DW 0AA55h
end start