forked from KolibriOS/kolibrios
037099f50d
git-svn-id: svn://kolibrios.org@2288 a494cfbc-eb01-0410-851d-a64ba20cac60
393 lines
11 KiB
NASM
393 lines
11 KiB
NASM
; Copyright (c) 2008-2009, diamond
|
|
; All rights reserved.
|
|
;
|
|
; Redistribution and use in source and binary forms, with or without
|
|
; modification, are permitted provided that the following conditions are met:
|
|
; * Redistributions of source code must retain the above copyright
|
|
; notice, this list of conditions and the following disclaimer.
|
|
; * Redistributions in binary form must reproduce the above copyright
|
|
; notice, this list of conditions and the following disclaimer in the
|
|
; documentation and/or other materials provided with the distribution.
|
|
; * Neither the name of the <organization> nor the
|
|
; names of its contributors may be used to endorse or promote products
|
|
; derived from this software without specific prior written permission.
|
|
;
|
|
; THIS SOFTWARE IS PROVIDED BY Alexey Teplov aka <Lrz> ''AS IS'' AND ANY
|
|
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
; DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
|
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
;*****************************************************************************
|
|
|
|
use_lba = 0
|
|
org 0x7C00
|
|
jmp start
|
|
nop
|
|
; FAT parameters, BPB
|
|
; note: they can be changed at install, replaced with real values
|
|
; these settings are for most typical 1.44M floppies
|
|
db 'KOLIBRI ' ; BS_OEMName, ignored
|
|
dw 200h ; BPB_BytsPerSec
|
|
BPB_SecsPerClus db 1
|
|
BPB_RsvdSecCnt dw 1
|
|
BPB_NumFATs db 2
|
|
BPB_RootEntCnt dw 0xE0
|
|
dw 2880 ; BPB_TotSec16
|
|
db 0xF0 ; BPB_Media
|
|
BPB_FATSz16 dw 9
|
|
BPB_SecPerTrk dw 18
|
|
BPB_NumHeads dw 2
|
|
BPB_HiddSec dd 0
|
|
dd 0 ; BPB_TotSec32
|
|
BS_DrvNum db 0
|
|
db 0 ; BS_Reserved1
|
|
db ')' ; BS_BootSig
|
|
dd 12344321h ; BS_VolID
|
|
filename:
|
|
db 'KORD.OS ' ; BS_VolLab
|
|
db 'FAT12 ' ; BS_FilSysType
|
|
; Used memory map:
|
|
; 8000:0000 - current directory
|
|
; 9000:0000 - root directory data [cached]
|
|
start:
|
|
xor ax, ax
|
|
mov ss, ax
|
|
mov sp, 0x7C00
|
|
mov ds, ax
|
|
mov bp, sp
|
|
cld
|
|
sti
|
|
mov [bp+BS_DrvNum-0x7C00], dl
|
|
if use_lba
|
|
mov ah, 41h
|
|
mov bx, 55AAh
|
|
int 13h
|
|
mov si, aNoLBA
|
|
jc err_
|
|
cmp bx, 0AA55h
|
|
jnz err_
|
|
test cx, 1
|
|
jz err_
|
|
else
|
|
mov ah, 8
|
|
int 13h
|
|
jc @f ; on error, assume that BPB geometry is valid
|
|
mov al, dh
|
|
mov ah, 0
|
|
inc ax
|
|
mov [bp+BPB_NumHeads-0x7C00], ax
|
|
and cx, 3Fh
|
|
mov [bp+BPB_SecPerTrk-0x7C00], cx
|
|
@@:
|
|
end if
|
|
; get FAT parameters
|
|
xor bx, bx
|
|
mov al, [bp+BPB_NumFATs-0x7C00]
|
|
mov ah, 0
|
|
mul [bp+BPB_FATSz16-0x7C00]
|
|
add ax, [bp+BPB_RsvdSecCnt-0x7C00]
|
|
adc dx, bx
|
|
push dx
|
|
push ax ; root directory start = dword [bp-4]
|
|
mov cx, [bp+BPB_RootEntCnt-0x7C00]
|
|
add cx, 0xF
|
|
rcr cx, 1
|
|
shr cx, 3 ; cx = size of root directory in sectors
|
|
add ax, cx
|
|
adc dx, bx
|
|
push dx
|
|
push ax ; data start = dword [bp-8]
|
|
; load start of root directory (no more than 0x2000 bytes = 0x10 sectors)
|
|
cmp cx, 0x10
|
|
jb @f
|
|
mov cx, 0x10
|
|
@@:
|
|
mov ax, [bp-4]
|
|
mov dx, [bp-2]
|
|
push 0x9000
|
|
pop es
|
|
call read_sectors
|
|
add word [bp-4], cx ; dword [bp-4] = start of non-cached root data
|
|
adc word [bp-2], bx
|
|
; load kordldr.f12
|
|
mov si, main_loader
|
|
call lookup_in_root_dir
|
|
jc noloader
|
|
test byte [es:di+11], 10h ; directory?
|
|
jz kordldr_ok
|
|
noloader:
|
|
mov si, aLoaderNotFound
|
|
err_:
|
|
call out_string
|
|
mov si, aPressAnyKey
|
|
call out_string
|
|
xor ax, ax
|
|
int 16h
|
|
int 18h
|
|
jmp $
|
|
kordldr_ok:
|
|
mov ax, [es:di+26] ; get file cluster
|
|
mov bx, 0x7E00
|
|
xor cx, cx
|
|
mov es, cx
|
|
sub ax, 2
|
|
jc noloader
|
|
push bx ; save return address: bx = 7E00
|
|
mov cl, [bp+BPB_SecsPerClus-0x7C00]
|
|
mul cx
|
|
; fall through - 'ret' in read_sectors will return to 7E00
|
|
|
|
read_sectors2:
|
|
; same as read_sectors, but dx:ax is relative to start of data
|
|
add ax, [bp-8]
|
|
adc dx, [bp-6]
|
|
read_sectors:
|
|
; ss:bp = 0:7C00
|
|
; es:bx = pointer to data
|
|
; dx:ax = first sector
|
|
; cx = number of sectors
|
|
pusha
|
|
add ax, word [bp+BPB_HiddSec-0x7C00]
|
|
adc dx, word [bp+BPB_HiddSec+2-0x7C00]
|
|
if use_lba
|
|
push ds
|
|
do_read_sectors:
|
|
push ax
|
|
push cx
|
|
push dx
|
|
cmp cx, 0x7F
|
|
jbe @f
|
|
mov cx, 0x7F
|
|
@@:
|
|
; create disk address packet on the stack
|
|
; dq starting LBA
|
|
push 0
|
|
push 0
|
|
push dx
|
|
push ax
|
|
; dd buffer
|
|
push es
|
|
push bx
|
|
; dw number of blocks to transfer (no more than 0x7F)
|
|
push cx
|
|
; dw packet size in bytes
|
|
push 10h
|
|
; issue BIOS call
|
|
push ss
|
|
pop ds
|
|
mov si, sp
|
|
mov dl, [bp+BS_DrvNum-0x7C00]
|
|
mov ah, 42h
|
|
int 13h
|
|
mov si, aReadError
|
|
jc err_
|
|
; restore stack
|
|
add sp, 10h
|
|
; increase current sector & buffer; decrease number of sectors
|
|
mov si, cx
|
|
mov ax, es
|
|
shl cx, 5
|
|
add ax, cx
|
|
mov es, ax
|
|
pop dx
|
|
pop cx
|
|
pop ax
|
|
add ax, si
|
|
adc dx, 0
|
|
sub cx, si
|
|
jnz do_read_sectors
|
|
pop ds
|
|
popa
|
|
ret
|
|
else
|
|
do_read_sectors:
|
|
pusha
|
|
pop di
|
|
push bx
|
|
|
|
; (dword in dx:ax) / (SectorsPerTrack) -> (dword in dx:ax), remainder bx
|
|
mov si, ax
|
|
xchg ax, dx
|
|
xor dx, dx
|
|
div [bp+BPB_SecPerTrk-0x7C00]
|
|
push ax
|
|
mov ax, si
|
|
div [bp+BPB_SecPerTrk-0x7C00]
|
|
mov bx, dx ; bx=sector-1
|
|
pop dx
|
|
|
|
; (dword in dx:ax) / (NumHeads) -> (word in ax), remainder dx
|
|
div [bp+BPB_NumHeads-0x7C00]
|
|
|
|
; number of sectors: read no more than to end of track
|
|
push bx
|
|
sub bx, [bp+BPB_SecPerTrk-0x7C00]
|
|
neg bx
|
|
cmp cx, bx
|
|
jbe @f
|
|
mov cx, bx
|
|
@@:
|
|
pop bx
|
|
|
|
inc bx
|
|
; now ax=track, dl=head, dh=0, cl=number of sectors, ch=0, bl=sector; convert to int13 format
|
|
mov di, cx
|
|
mov dh, dl
|
|
mov dl, [bp+BS_DrvNum-0x7C00]
|
|
shl ah, 6
|
|
mov ch, al
|
|
mov al, cl
|
|
mov cl, bl
|
|
or cl, ah
|
|
pop bx
|
|
mov si, 3
|
|
mov ah, 2
|
|
@@:
|
|
push ax
|
|
int 13h
|
|
jnc @f
|
|
xor ax, ax
|
|
int 13h ; reset drive
|
|
pop ax
|
|
dec si
|
|
jnz @b
|
|
mov si, aReadError
|
|
jmp err_
|
|
@@:
|
|
pop ax
|
|
mov ax, es
|
|
mov cx, di
|
|
shl cx, 5
|
|
add ax, cx
|
|
mov es, ax
|
|
push di
|
|
popa
|
|
add ax, di
|
|
adc dx, 0
|
|
sub cx, di
|
|
jnz do_read_sectors
|
|
popa
|
|
ret
|
|
end if
|
|
|
|
scan_for_filename:
|
|
; in: ds:si -> 11-bytes FAT name
|
|
; in: es:0 -> part of directory data
|
|
; in: cx = number of entries
|
|
; out: if found: CF=0, ZF=1, es:di -> directory entry
|
|
; out: if not found, but continue required: CF=1 and ZF=0
|
|
; out: if not found and zero item reached: CF=1 and ZF=1
|
|
xor di, di
|
|
push cx
|
|
sloop:
|
|
cmp byte [es:di], 0
|
|
jz snotfound
|
|
test byte [es:di+11], 8 ; volume label?
|
|
jnz scont ; ignore volume labels
|
|
pusha
|
|
mov cx, 11
|
|
repz cmpsb
|
|
popa
|
|
jz sdone
|
|
scont:
|
|
add di, 0x20
|
|
loop sloop
|
|
inc cx ; clear ZF flag
|
|
snotfound:
|
|
stc
|
|
sdone:
|
|
pop cx
|
|
lrdret:
|
|
ret
|
|
|
|
lookup_in_root_dir:
|
|
; ss:bp = 0:7C00
|
|
; in: ds:si -> 11-bytes FAT name
|
|
; out: if found: CF=0, es:di -> directory entry
|
|
; out: if not found: CF=1
|
|
mov cx, [bp+BPB_RootEntCnt-0x7C00]
|
|
push cx
|
|
; first, look in root directory cache
|
|
push 0x9000
|
|
pop es
|
|
test ch, ch
|
|
jz @f
|
|
mov cx, 0x100
|
|
@@:
|
|
mov ax, [bp-4]
|
|
mov dx, [bp-2] ; dx:ax = starting sector of not cached data of root directory
|
|
lrdloop:
|
|
call scan_for_filename
|
|
pop bx
|
|
jz lrdret
|
|
sub bx, cx
|
|
mov cx, bx
|
|
stc
|
|
jz lrdret
|
|
; read no more than 0x10000 bytes, or 0x10000/0x20 = 0x800 entries
|
|
push cx
|
|
cmp ch, 0x8
|
|
jb @f
|
|
mov cx, 0x800
|
|
@@:
|
|
push 0x8000
|
|
pop es
|
|
push cx
|
|
push es
|
|
xor bx, bx
|
|
add cx, 0xF
|
|
shr cx, 4
|
|
call read_sectors
|
|
pop es
|
|
add ax, cx
|
|
adc dx, bx
|
|
pop cx
|
|
jmp lrdloop
|
|
|
|
out_string:
|
|
; in: ds:si -> ASCIIZ string
|
|
lodsb
|
|
test al, al
|
|
jz lrdret
|
|
mov ah, 0Eh
|
|
mov bx, 7
|
|
int 10h
|
|
jmp out_string
|
|
|
|
aReadError db 'Read error',0
|
|
if use_lba
|
|
aNoLBA db 'The drive does not support LBA!',0
|
|
end if
|
|
aLoaderNotFound db 'Loader not found',0
|
|
aPressAnyKey db 13,10,'Press any key...',13,10,0
|
|
main_loader db 'KORDLDR F1X'
|
|
|
|
if use_lba
|
|
db 0 ; make bootsector 512 bytes in length
|
|
end if
|
|
|
|
; bootsector signature
|
|
dw 0xAA55
|
|
|
|
; display offsets of all procedures used by kordldr.f12.asm
|
|
macro show [procedure]
|
|
{
|
|
bits = 16
|
|
display `procedure,' = '
|
|
repeat bits/4
|
|
d = '0' + procedure shr (bits - %*4) and 0Fh
|
|
if d > '9'
|
|
d = d + 'A'-'9'-1
|
|
end if
|
|
display d
|
|
end repeat
|
|
display 13,10
|
|
}
|
|
|
|
show read_sectors, read_sectors2, lookup_in_root_dir, scan_for_filename, err_, noloader
|