.386p
code segment use16 'BOOT'
assume ds:code

jmp near ptr BSMain
db "MSWIN4.1"
dw 512
db 1
dw 1
db 2
dw 0
dw 0b40h
db 240
dw 9,18,2
dd 0,0
db 0,0
; Volume serial number not supported

ErrorHandler:
mov si,offset errmsg
printlp:
lodsb
test al,al
jz reset
mov ah,14
int 10h
jmp printlp
reset:
xor ax,ax
int 16h
int 19h

sys_notfound:
mov si,offset notfounderr
jmp printlp

ReadMultipleSectors:
push ax
push cx
cwd
div word ptr [bp+24] ; Sectors per track
mov cl,dl
inc cx               ; Sector number
shr al,1             ; Cylinder number
rcl dh,1             ; Head number
mov dl,[bp-2]        ; Drive number
mov ch,al
mov ax,201h
mov bx,di
int 13h
pop cx
pop ax
jb ErrorHandler
inc ax
mov dx,es
add dx,[bp+11]       ; Advance pointer
mov es,dx
loop ReadMultipleSectors
ret

BSMain:
jmp far ptr BSMainFar
BSMainFar:
xor ax,ax
mov ds,ax
mov bp,7c00h
mov ss,ax
mov sp,bp
push dx                   ; 7BFE: Boot drive number
shr word ptr [bp+11],4    ; Convert sector size to paragraphs
mov ax,[bp+14]            ; FAT start
push 800h
pop es
xor di,di
mov cx,[bp+22]            ; FAT size
call ReadMultipleSectors  ; Load FAT to 8000h
mov ax,[bp+22]
movzx cx,byte ptr [bp+16] ; FAT count
mul cx
add ax,[bp+14]
xchg cx,ax                ; Root directory start in CX
mov ax,[bp+17]            ; Root entry count
shl ax,1
xor dx,dx
div word ptr [bp+11]      ; Get root directory sector count
mov dx,cx
add dx,ax
push dx                   ; 7BFC: Data area start
xchg cx,ax
push es
call ReadMultipleSectors  ; Load root directory
mov al,0
stosb                     ; Mark end of directory
mov ax,es
add ax,[bp+11]            ; Skip end marker
pop es
push es
push ax
mov si,offset SystemImageName
mov bx,offset BuiltinCharHandlers
call FAT12B_GetNamedObjectInfo
jnz sys_notfound
pop es
push es
sysreadlp:
call FAT12B_GetObjectData
jb sysreadlp              ; Repeat if end of file not reached
pop ax
pop dx
push word ptr [bp-2]      ; Parameter 3: Boot drive number
push dx                   ; Parameter 2: File system root handle
push offset ServiceTable  ; Parameter 1: Service table pointer
push ax                   ; System file segment
push 0                    ; Entry point (0 for now)
retf

FAT12B_GetObjectData:
push cx
push ax
dec ax
dec ax
movzx cx,byte ptr [bp+13] ; Sectors per cluster
mul cx
add ax,[bp-4]             ; Starting sector
call ReadMultipleSectors
pop ax
pop cx
imul si,ax,3
shr si,1
mov ax,[si+8000h]         ; Get next cluster number
jae notshr4
shr ax,4
notshr4:
and ax,0fffh
cmp ax,0ff0h              ; End of chain reached?
ret

FAT12B_GetNamedObjectInfo:
mov di,502h
mov cx,11
mov dx,50ah
mov [di-2],si        ; Save name
push es
push cs
pop es
push di
cvtname_lp:          ; Check if short name
call word ptr [bx+2] ; Read character
jb cvtname_fail      ; Fail if not ASCII
test al,al
jz cvtname_end
call word ptr [bx]   ; Convert to uppercase
cmp al,'.'
jnz cvtname_notdot
cmp dl,13
jz cvtname_fail      ; Fail on multiple dots
sub cl,3
mov al,0
rep stosb            ; Pad until extension
mov cl,3
mov dl,13
cvtname_notdot:
cmp di,dx            ; Fail if too long
jae cvtname_fail
stosb
dec cx
jmp cvtname_lp
cvtname_fail:
mov byte ptr ds:[502h],0
inc di
cvtname_end:
rep stosb            ; Pad filename
pop si
pop es
xor di,di
find_loop:
cmp byte ptr es:[di],1
jb find_fail         ; Fail if end of directory reached
mov cl,11            ; Check if short name matches
pusha
repz cmpsb
popa
jz find_ok
pusha
mov si,[si-2]        ; Retrieve original name
find_longlp:
sub di,32
jb find_notlong
push di
inc di
mov cl,5
call CompareStrings
mov ax,es:[di]
and al,63
cmp al,15
jnz find_notlong1    ; Is long name entry?
add di,3
mov cl,6
call CompareStrings
inc di
inc di
mov cl,2
call CompareStrings
pop di
test byte ptr es:[di],64 ; Not last part?
jz find_longlp
push di
call word ptr [bx+2]
test ax,ax
jz find_longmatch    ; Succeed if end of name reached
find_notlong1:
pop di
find_notlong:
popa
add di,32            ; Check next entry
jmp find_loop
cmpstr_match:
pop ax               ; Skip return address
find_longmatch:
pop di
popa
find_ok:
mov ax,es:[di+26]    ; Reference number (for FAT, starting cluster)
mov ecx,es:[di+28]   ; Size, if entry describes file
mov dl,es:[di+11]    ; DL bit 5 indicates a directory, same as entry attribute bit 5
find_fail:
ret

CompareStrings:
call word ptr [bx+2] ; Read character from filename
call word ptr [bx]   ; Make uppercase
xchg dx,ax
mov ax,es:[di]       ; Read character from entry
inc di
inc di
call word ptr [bx]   ; Make uppercase
cmp ax,dx
jnz cmpstr_fail
test ax,ax
jz cmpstr_match      ; Succeed if end of name reached
loop CompareStrings
ret
cmpstr_fail:
pop ax               ; Skip return address
jmp find_notlong1

; Default character service implementation (ASCII only)

ReadChar:
lodsb
xor ah,ah
ret

UppercaseChar:
cmp al,61h
jb ucc_no
cmp al,7bh
jae ucc_no
and al,0dfh
ucc_no:
ret

BuiltinCharHandlers dw UppercaseChar,ReadChar
ServiceTable dw FAT12B_GetNamedObjectInfo,FAT12B_GetObjectData,ErrorHandler
errmsg db "Disk error",13,10,0
notfounderr db "No system file",13,10,0
SystemImageName db "gigaos.sys",0
db 0,0
dw 0aa55h
code ends
end