forked from KolibriOS/kolibrios
e4362a1edc
git-svn-id: svn://kolibrios.org@9942 a494cfbc-eb01-0410-851d-a64ba20cac60
307 lines
10 KiB
NASM
307 lines
10 KiB
NASM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; ;;
|
|
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
|
;; Distributed under terms of the GNU General Public License ;;
|
|
;; ;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
; 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
|
|
|
|
include "lang.inc"
|
|
|
|
lf = 0ah
|
|
cr = 0dh
|
|
|
|
pos_read_tmp = 0700h ;position for temporary read
|
|
boot_program = 07c00h ;position for boot code
|
|
seg_read_kernel = 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:
|
|
; <Efremenkov S.V.>
|
|
cld ;clear direction flag for Phoenix BIOS, see next "lodsb"
|
|
xor ax, ax
|
|
cli
|
|
mov ss, ax
|
|
mov sp, boot_program
|
|
sti
|
|
; <\Efremenkov S.V.>
|
|
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
|
|
mov [cluster1st+boot_program], bp ; starting cluster of kernel file
|
|
|
|
; 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:
|
|
mov ax, 'KL'
|
|
push 0
|
|
pop ds
|
|
mov si, loader_block+boot_program
|
|
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
|
|
pop bx
|
|
|
|
writesec:
|
|
; convert cluster number to sector number
|
|
mov ax, bp ; data cluster to read
|
|
sub ax, 2
|
|
xor dx, dx
|
|
mov dl, byte [BPB_SecPerClus+boot_program]
|
|
mul dx
|
|
add ax, word [data_start+boot_program]
|
|
|
|
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
|
|
jnz .next
|
|
cmp ah, 02h ; if read sectors
|
|
jz file_error_message
|
|
mov byte[write_err+boot_program], 1 ; if write sectors
|
|
jmp .ret
|
|
.next:
|
|
push ax bx cx dx
|
|
int 13h
|
|
pop dx cx bx ax
|
|
jc newread
|
|
.ret:
|
|
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
|
|
;------------------------------------------
|
|
|
|
if lang eq sp
|
|
loading db cr,lf,'Iniciando el sistema ',00h
|
|
else
|
|
loading db cr,lf,'Starting system ',00h
|
|
end if
|
|
error_message db 13,10
|
|
kernel_name db 'KERNEL MNT ?',cr,lf,00h
|
|
FirstRootDirSecNum dw ?
|
|
RootDirSecs dw ?
|
|
data_start dw ?
|
|
|
|
write1st:
|
|
push cs
|
|
pop ds
|
|
mov byte [patchhere+1+boot_program], 3 ; change ah=2 to ah=3
|
|
mov bp, [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 ; +0
|
|
dw 0 ; +1
|
|
dw write1st+boot_program ; +3
|
|
dw 0 ; +5
|
|
write_err: db 0 ; +7
|
|
|
|
times 0x1fe-$ db 00h
|
|
|
|
db 55h,0aah ;boot signature
|