0,0 → 1,287 |
; FAT12 boot sector for Kolibri OS |
; |
; Copyright (C) Alex Nogueira Teixeira |
; Copyright (C) Diamond |
; Copyright (C) Dmitry Kartashov aka shurf |
; |
; Distributed under GPL, see file COPYING for details |
; |
; Version 1.0 |
|
lf equ 0ah |
cr equ 0dh |
|
pos_read_tmp equ 0700h ;position for temporary read |
boot_program equ 07c00h ;position for boot code |
seg_read_kernel equ 01000h ;segment to kernel read |
|
jmp start_program |
nop |
|
; Boot Sector and BPB Structure |
include 'floppy1440.inc' |
;include 'floppy2880.inc' |
;include 'floppy1680.inc' |
;include 'floppy1743.inc' |
|
start_program: |
|
xor ax,ax |
mov ss,ax |
mov sp,boot_program |
push ss |
pop ds |
|
; print loading string |
mov si,loading+boot_program |
loop_loading: |
lodsb |
or al,al |
jz read_root_directory |
mov ah,0eh |
mov bx,7 |
int 10h |
jmp loop_loading |
|
read_root_directory: |
push ss |
pop es |
|
; calculate some disk parameters |
; - beginning sector of RootDir |
mov ax,word [BPB_FATSz16+boot_program] |
xor cx,cx |
mov cl,byte [BPB_NumFATs+boot_program] |
mul cx |
add ax,word [BPB_RsvdSecCnt+boot_program] |
mov word [FirstRootDirSecNum+boot_program],ax ; 19 |
mov si,ax |
|
; - count of sectors in RootDir |
mov bx,word [BPB_BytsPerSec+boot_program] |
mov cl,5 ; divide ax by 32 |
shr bx,cl ; bx = directory entries per sector |
mov ax,word [BPB_RootEntCnt+boot_program] |
xor dx,dx |
div bx |
mov word [RootDirSecs+boot_program],ax ; 14 |
|
; - data start |
add si,ax ; add beginning sector of RootDir and count sectors in RootDir |
mov word [data_start+boot_program],si ; 33 |
; reading root directory |
; al=count root dir sectrors !!!! TODO: al, max 255 sectors !!!! |
mov ah,2 ; read |
push ax |
|
mov ax,word [FirstRootDirSecNum+boot_program] |
call conv_abs_to_THS ; convert abs sector (AX) to BIOS T:H:S (track:head:sector) |
pop ax |
mov bx,pos_read_tmp ; es:bx read buffer |
call read_sector |
|
mov si,bx ; read buffer address: es:si |
mov ax,[RootDirSecs+boot_program] |
mul word [BPB_BytsPerSec+boot_program] |
add ax,si ; AX = end of root dir. in buffer pos_read_tmp |
|
; find kernel file in root directory |
loop_find_dir_entry: |
push si |
mov cx,11 |
mov di,kernel_name+boot_program |
rep cmpsb ; compare es:si and es:di, cx bytes long |
pop si |
je found_kernel_file |
add si,32 ; next dir. entry |
cmp si,ax ; end of directory |
jb loop_find_dir_entry |
|
file_error_message: |
mov si,error_message+boot_program |
|
loop_error_message: |
lodsb |
or al,al |
jz freeze_pc |
mov ah,0eh |
mov bx,7 |
int 10h |
jmp loop_error_message |
|
freeze_pc: |
jmp $ ; endless loop |
|
; === KERNEL FOUND. LOADING... === |
|
found_kernel_file: |
mov bp,[si+01ah] ; first cluster of kernel file |
; <diamond> |
mov [cluster1st+boot_program],bp ; starting cluster of kernel file |
; <\diamond> |
|
; reading first FAT table |
mov ax,word [BPB_RsvdSecCnt+boot_program] ; begin first FAT abs sector number |
call conv_abs_to_THS ; convert abs sector (AX) to BIOS T:H:S (track:head:sector) |
mov bx,pos_read_tmp ; es:bx read position |
mov ah,2 ; ah=2 (read) |
mov al, byte [BPB_FATSz16+boot_program] ; FAT size in sectors (TODO: max 255 sectors) |
call read_sector |
jc file_error_message ; read error |
|
mov ax,seg_read_kernel |
mov es,ax |
xor bx,bx ; es:bx = 1000h:0000h |
|
|
; reading kernel file |
loop_obtains_kernel_data: |
; read one cluster of file |
call obtain_cluster |
jc file_error_message ; read error |
|
; add one cluster length to segment:offset |
push bx |
mov bx,es |
mov ax,word [BPB_BytsPerSec+boot_program] ;\ |
movsx cx,byte [BPB_SecPerClus+boot_program] ; | !!! TODO: !!! |
mul cx ; | out this from loop !!! |
shr ax,4 ;/ |
add bx,ax |
mov es,bx |
pop bx |
|
mov di,bp |
shr di,1 |
pushf |
add di,bp ; di = bp * 1.5 |
add di,pos_read_tmp |
mov ax,[di] ; read next entry from FAT-chain |
popf |
jc move_4_right |
and ax,0fffh |
jmp verify_end_sector |
move_4_right: |
mov cl,4 |
shr ax,cl |
verify_end_sector: |
cmp ax,0ff8h ; last cluster |
jae execute_kernel |
mov bp,ax |
jmp loop_obtains_kernel_data |
|
execute_kernel: |
; <diamond> |
mov ax,'KL' |
push 0 |
pop ds |
mov si,loader_block+boot_program |
; </diamond> |
push word seg_read_kernel |
push word 0 |
retf ; jmp far 1000:0000 |
|
|
;------------------------------------------ |
; loading cluster from file to es:bx |
obtain_cluster: |
; bp - cluster number to read |
; carry = 0 -> read OK |
; carry = 1 -> read ERROR |
|
; print one dot |
push bx |
mov ax,0e2eh ; ah=0eh (teletype), al='.' |
xor bh,bh |
int 10h |
|
; convert cluster number to sector number |
mov ax,bp ; data cluster to read |
sub ax,2 |
xor bx,bx |
mov bl,byte [BPB_SecPerClus+boot_program] |
mul bx |
add ax,word [data_start+boot_program] |
pop bx |
|
writesec: |
call conv_abs_to_THS ; convert abs sector (AX) to BIOS T:H:S (track:head:sector) |
patchhere: |
mov ah,2 ; ah=2 (read) |
mov al,byte [BPB_SecPerClus+boot_program] ; al=(one cluster) |
call read_sector |
retn |
;------------------------------------------ |
|
;------------------------------------------ |
; read sector from disk |
read_sector: |
push bp |
mov bp,20 ; try 20 times |
newread: |
dec bp |
jz file_error_message |
push ax bx cx dx |
int 13h |
pop dx cx bx ax |
jc newread |
pop bp |
retn |
;------------------------------------------ |
; convert abs. sector number (AX) to BIOS T:H:S |
; sector number = (abs.sector%BPB_SecPerTrk)+1 |
; pre.track number = (abs.sector/BPB_SecPerTrk) |
; head number = pre.track number%BPB_NumHeads |
; track number = pre.track number/BPB_NumHeads |
; Return: cl - sector number |
; ch - track number |
; dl - drive number (0 = a:) |
; dh - head number |
conv_abs_to_THS: |
push bx |
mov bx,word [BPB_SecPerTrk+boot_program] |
xor dx,dx |
div bx |
inc dx |
mov cl, dl ; cl = sector number |
mov bx,word [BPB_NumHeads+boot_program] |
xor dx,dx |
div bx |
; !!!!!!! ax = track number, dx = head number |
mov ch,al ; ch=track number |
xchg dh,dl ; dh=head number |
mov dl,0 ; dl=0 (drive 0 (a:)) |
pop bx |
retn |
;------------------------------------------ |
|
loading db cr,lf,'Starting system ',00h |
error_message db 13,10 |
kernel_name db 'KERNEL MNT ?',cr,lf,00h |
FirstRootDirSecNum dw ? |
RootDirSecs dw ? |
data_start dw ? |
|
; <diamond> |
write1st: |
push cs |
pop ds |
mov byte [patchhere+1+boot_program], 3 ; change ah=2 to ah=3 |
mov ax,[cluster1st+boot_program] |
push 1000h |
pop es |
xor bx,bx |
call writesec |
mov byte [patchhere+1+boot_program], 2 ; change back ah=3 to ah=2 |
retf |
cluster1st dw ? |
loader_block: |
db 1 |
dw 0 |
dw write1st+boot_program |
dw 0 |
; <\diamond> |
|
times 0x1fe-$ db 00h |
|
db 55h,0aah ;boot signature |