forked from KolibriOS/kolibrios
418e448f59
git-svn-id: svn://kolibrios.org@4299 a494cfbc-eb01-0410-851d-a64ba20cac60
454 lines
8.1 KiB
NASM
454 lines
8.1 KiB
NASM
; KolibriOS bootloader
|
|
; this code has been written by diamond in 2005,2006,2007 specially for KolibriOS
|
|
|
|
; this code is loaded by our bootsector to 0000:8000
|
|
format binary
|
|
use16
|
|
|
|
out_string = 0x7DAB
|
|
read_cluster = 0x7D15
|
|
relative_read = 0x7D22
|
|
next_cluster = 0x7D65
|
|
|
|
org 0x8000
|
|
start:
|
|
; cs=ds=0, es undefined, ss=0, sp=7C00
|
|
movzx esp, sp
|
|
push 1000h
|
|
pop es
|
|
; say hi to user
|
|
mov si, start_msg
|
|
call out_string
|
|
; parse image name
|
|
mov eax, [7C2Ch] ; root_cluster
|
|
and eax, 0xFFFFFFF
|
|
mov [cur_obj], root_string
|
|
.parsedir:
|
|
push ax
|
|
mov si, [imgnameofs]
|
|
push si
|
|
@@:
|
|
lodsb
|
|
cmp al, 0
|
|
jz @f
|
|
cmp al, '\'
|
|
jnz @b
|
|
dec si
|
|
mov [missing_slash], si
|
|
inc si
|
|
@@:
|
|
xchg ax, [esp+2]
|
|
mov byte [si-1], 0
|
|
mov [imgnameofs], si
|
|
call fat32_parse_dir
|
|
call restore_slash
|
|
pop cx
|
|
test cl, cl
|
|
jz .end
|
|
test byte [es:di+0Bh], 10h
|
|
mov si, notdir_string
|
|
jz find_error_si
|
|
jmp .parsedir
|
|
.end:
|
|
test byte [es:di+0Bh], 10h
|
|
mov si, directory_string
|
|
jnz find_error_si
|
|
; parse FAT chunk
|
|
; runlist at 5000:0000
|
|
mov di, 4
|
|
push 5000h
|
|
pop es
|
|
mov dword [es:di-4], 1
|
|
stosd
|
|
.parsefat:
|
|
call next_cluster
|
|
jnc .done
|
|
mov ecx, [es:di-8]
|
|
add ecx, [es:di-4]
|
|
cmp eax, ecx
|
|
jz .contc
|
|
mov dword [es:di], 1
|
|
scasd
|
|
stosd
|
|
jmp .parsefat
|
|
.contc:
|
|
inc dword [es:di-8]
|
|
jmp .parsefat
|
|
.done:
|
|
xor eax, eax
|
|
stosd
|
|
read_img_file:
|
|
xor si, si
|
|
push es
|
|
pop fs
|
|
; yes! Now read file to 0x100000
|
|
xor edi, edi
|
|
; read buffer to 1000:0000 and move it to extended memory
|
|
push 1000h
|
|
pop es
|
|
xor bx, bx
|
|
.img_read_block:
|
|
lods dword [fs:si] ; eax=length
|
|
xchg eax, ecx
|
|
jecxz .img_read_done
|
|
lods dword [fs:si] ; eax=disk cluster
|
|
.img_read_cluster:
|
|
pushad
|
|
; read part of file
|
|
movzx esi, byte [7C0Dh]
|
|
mul esi
|
|
add eax, [7A04h]
|
|
push ax
|
|
mov ax, 0x200
|
|
div si
|
|
cmp cx, ax
|
|
jb @f
|
|
mov cx, ax
|
|
@@:
|
|
pop ax
|
|
add [esp+1Ch], ecx
|
|
sub [esp+18h], cx
|
|
imul cx, si
|
|
push cx
|
|
call relative_read
|
|
pop cx
|
|
; move it to extended memory
|
|
mov byte [sou_addr+2], 1
|
|
.move_loop:
|
|
push cx
|
|
cmp cx, 80h
|
|
jbe @f
|
|
mov cx, 80h
|
|
@@:
|
|
mov ah, 87h
|
|
xchg cl, ch
|
|
mov si, movedesc
|
|
push cx es
|
|
push ds
|
|
pop es
|
|
int 15h
|
|
pop es cx
|
|
test ah, ah
|
|
mov si, exmem_string
|
|
jnz find_error_si
|
|
add [dest_addr], ecx
|
|
add [dest_addr], ecx
|
|
inc byte [sou_addr+2]
|
|
mov al, ch
|
|
mov ah, cl
|
|
pop cx
|
|
sub cx, ax
|
|
jnz .move_loop
|
|
popad
|
|
test cx, cx
|
|
jnz .img_read_cluster
|
|
jmp .img_read_block
|
|
.img_read_done:
|
|
; kolibri.img loaded; now load kernel.mnt
|
|
load_kernel:
|
|
push ds
|
|
pop es
|
|
mov [cur_obj], kernel_mnt_name
|
|
; read boot sector
|
|
xor eax, eax
|
|
mov bx, 500h
|
|
mov cx, 1
|
|
call read_img
|
|
; init vars
|
|
mov ax, [50Eh] ; reserved_sect
|
|
add ax, [51Ch] ; hidden
|
|
mov word [fat_start], ax
|
|
xchg ax, bx
|
|
movzx ax, byte [510h] ; num_fats
|
|
mul word [516h] ; fat_length
|
|
add ax, bx
|
|
; read root dir
|
|
mov bx, 700h
|
|
mov cx, [511h] ; dir_entries
|
|
add cx, 0Fh
|
|
shr cx, 4
|
|
call read_img
|
|
add ax, cx
|
|
mov [img_data_start], ax
|
|
shl cx, 9
|
|
mov di, bx
|
|
add bx, cx
|
|
mov byte [bx], 0
|
|
.scan_loop:
|
|
cmp byte [di], 0
|
|
mov si, notfound_string
|
|
jz find_error_si
|
|
mov si, kernel_mnt_name
|
|
call fat_compare_name
|
|
jz .found
|
|
and di, not 1Fh
|
|
add di, 20h
|
|
jmp .scan_loop
|
|
.found:
|
|
and di, not 1Fh
|
|
mov si, directory_string
|
|
test byte [di+0Bh], 10h
|
|
jnz find_error_si
|
|
; found, now load it to 1000h:0000h
|
|
mov ax, [di+1Ah]
|
|
; first cluster of kernel.mnt in ax
|
|
; translate it to sector on disk in kolibri.img
|
|
push ax
|
|
dec ax
|
|
dec ax
|
|
movzx cx, byte [50Dh]
|
|
mul cx
|
|
add ax, [img_data_start]
|
|
; now ax is sector in kolibri.img
|
|
mov [kernel_mnt_in_img], ax
|
|
movzx cx, byte [7C0Dh]
|
|
div cx
|
|
; now ax is cluster in kolibri.img and
|
|
; dx is offset from the beginning of cluster
|
|
movzx eax, ax
|
|
push 5000h
|
|
pop ds
|
|
xor si, si
|
|
mov si, 1
|
|
.scani:
|
|
sub eax, [si]
|
|
jb .scanidone
|
|
; sanity check
|
|
cmp dword [si], 0
|
|
push data_error_msg
|
|
jz find_error_sp
|
|
pop cx
|
|
; next chunk
|
|
add si, 8
|
|
jmp .scani
|
|
.scanidone:
|
|
add eax, [si] ; undo last subtract
|
|
add eax, [si+4] ; get cluster
|
|
push 0
|
|
pop ds
|
|
movzx ecx, byte [7C0Dh]
|
|
push dx
|
|
mul ecx ; get sector
|
|
pop dx
|
|
movzx edx, dx
|
|
add eax, edx
|
|
add eax, [7A04h]
|
|
mov [kernel_mnt_1st], eax
|
|
pop ax
|
|
push 1000h
|
|
pop es
|
|
.read_loop:
|
|
push ax
|
|
xor bx, bx
|
|
call img_read_cluster
|
|
shl cx, 9-4
|
|
mov ax, es
|
|
add ax, cx
|
|
mov es, ax
|
|
pop ax
|
|
call img_next_cluster
|
|
jc .read_loop
|
|
mov ax, 'KL'
|
|
mov si, loader_block
|
|
jmp 1000h:0000h
|
|
|
|
img_next_cluster:
|
|
mov bx, 700h
|
|
push ax
|
|
shr ax, 1
|
|
add ax, [esp]
|
|
mov dx, ax
|
|
shr ax, 9
|
|
add ax, word [fat_start]
|
|
mov cx, 2
|
|
push es
|
|
push ds
|
|
pop es
|
|
call read_img
|
|
pop es
|
|
and dx, 1FFh
|
|
add bx, dx
|
|
mov ax, [bx]
|
|
pop cx
|
|
test cx, 1
|
|
jz .1
|
|
shr ax, 4
|
|
.1:
|
|
and ax, 0FFFh
|
|
mov si, bad_cluster_string
|
|
cmp ax, 0FF7h
|
|
jz find_error_si
|
|
ret
|
|
img_read_cluster:
|
|
dec ax
|
|
dec ax
|
|
movzx cx, byte [50Dh] ; sects_per_clust
|
|
mul cx
|
|
add ax, [img_data_start]
|
|
movzx eax, ax
|
|
; call read_img
|
|
; ret
|
|
read_img:
|
|
; in: ax = sector, es:bx->buffer, cx=length in sectors
|
|
pushad
|
|
movzx ebx, bx
|
|
mov si, movedesc
|
|
shl eax, 9
|
|
add eax, 93100000h
|
|
mov dword [si+sou_addr-movedesc], eax
|
|
mov eax, 9300000h
|
|
mov ax, es
|
|
shl eax, 4
|
|
add eax, ebx
|
|
mov [si+dest_addr-movedesc], eax
|
|
mov ah, 87h
|
|
shl cx, 8 ; mul 200h/2
|
|
push es
|
|
push 0
|
|
pop es
|
|
int 15h
|
|
pop es
|
|
cmp ah, 0
|
|
mov si, exmem_string
|
|
jnz find_error_si
|
|
popad
|
|
ret
|
|
|
|
movedesc:
|
|
times 16 db 0
|
|
; source
|
|
dw 0xFFFF ; segment length
|
|
sou_addr dw 0000h ; linear address
|
|
db 1 ; linear address
|
|
db 93h ; access rights
|
|
dw 0
|
|
; destination
|
|
dw 0xFFFF ; segment length
|
|
dest_addr dd 93100000h ; high byte contains access rights
|
|
; three low bytes contains linear address (updated when reading)
|
|
dw 0
|
|
times 32 db 0
|
|
|
|
find_error_si:
|
|
push si
|
|
find_error_sp:
|
|
mov si, error_msg
|
|
call out_string
|
|
mov si, [cur_obj]
|
|
call out_string
|
|
mov si, colon
|
|
call out_string
|
|
pop si
|
|
call out_string
|
|
mov si, newline
|
|
call out_string
|
|
jmp $
|
|
|
|
file_not_found:
|
|
mov si, [esp+2]
|
|
mov [cur_obj], si
|
|
push notfound_string
|
|
jmp find_error_sp
|
|
|
|
restore_slash:
|
|
mov si, [missing_slash]
|
|
test si, si
|
|
jz @f
|
|
and [missing_slash], 0
|
|
mov byte [si], '\'
|
|
@@: ret
|
|
|
|
include 'fat32.inc'
|
|
|
|
if 0
|
|
write1st:
|
|
; callback from kernel.mnt
|
|
; write first sector of kernel.mnt from 1000:0000 back to disk
|
|
push cs
|
|
pop ds
|
|
push cs
|
|
pop es
|
|
; sanity check
|
|
mov bx, 500h
|
|
mov si, bx
|
|
mov cx, 1
|
|
push cx
|
|
mov eax, [kernel_mnt_1st]
|
|
push eax
|
|
call relative_read
|
|
push 1000h
|
|
pop es
|
|
xor di, di
|
|
mov cx, 8
|
|
repz cmpsw
|
|
mov si, data_error_msg
|
|
jnz find_error_si
|
|
; ok, now write back to disk
|
|
or byte [read.patch1+2], 1
|
|
or byte [read.patch2+2], 1
|
|
xor bx, bx
|
|
pop eax
|
|
pop cx
|
|
call relative_read
|
|
and byte [read.patch1+1], not 1
|
|
and byte [read.patch2+2], not 2
|
|
; and to image in memory (probably this may be done by kernel.mnt itself?)
|
|
mov dword [sou_addr], 93010000h
|
|
movzx eax, [kernel_mnt_in_img]
|
|
shl eax, 9
|
|
add eax, 93100000h
|
|
mov dword [dest_addr], eax
|
|
mov si, movedesc
|
|
push ds
|
|
pop es
|
|
mov ah, 87h
|
|
mov cx, 100h
|
|
int 15h
|
|
cmp ah, 0
|
|
mov si, exmem_string
|
|
jnz find_error_si
|
|
retf
|
|
else
|
|
write1st = 0
|
|
end if
|
|
|
|
loader_block:
|
|
db 1 ; version
|
|
dw 1 ; flags - image is loaded
|
|
dw write1st ; offset
|
|
dw 0 ; segment
|
|
|
|
imgnameofs dw kolibri_img_name
|
|
|
|
; -----------------------------------------------
|
|
; ------------------ Settings -------------------
|
|
; -----------------------------------------------
|
|
|
|
; must be in lowercase, see ntfs_parse_dir.scan, fat32_parse_dir.scan
|
|
kernel_mnt_name db 'kernel.mnt',0
|
|
kolibri_img_name db 'kolibri.img',0
|
|
|
|
missing_slash dw 0
|
|
|
|
start_msg db 2,' KolibriOS bootloader, FAT32 flash version'
|
|
newline db 13,10,0
|
|
error_msg db 'Error'
|
|
colon db ': ',0
|
|
root_string db '\',0
|
|
nodata_string db '$DATA '
|
|
notfound_string db 'not found',0
|
|
directory_string db 'is a directory',0
|
|
notdir_string db 'not a directory',0
|
|
exmem_string db 'extended memory error',0
|
|
bad_cluster_string db 'bad cluster',0
|
|
data_error_msg db 'data error',0
|
|
|
|
align 2
|
|
|
|
; uninitialized data follows
|
|
cur_obj dw ?
|
|
img_data_start dw ?
|
|
kernel_mnt_in_img dw ?
|
|
fat_start dw ?
|
|
kernel_mnt_1st dd ?
|