forked from KolibriOS/kolibrios
359 lines
9.9 KiB
NASM
359 lines
9.9 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 = 1
|
||
|
org 0x7C00
|
||
|
jmp start
|
||
|
nop
|
||
|
; FAT parameters, BPB
|
||
|
; they must be changed at install, replaced with real values
|
||
|
rb 8 ; BS_OEMName, ignored
|
||
|
dw 200h ; BPB_BytsPerSec
|
||
|
BPB_SecsPerClus db ?
|
||
|
BPB_RsvdSecCnt dw ?
|
||
|
BPB_NumFATs db ?
|
||
|
BPB_RootEntCnt dw ?
|
||
|
dw ? ; BPB_TotSec16
|
||
|
db ? ; BPB_Media
|
||
|
dw ? ; BPB_FATSz16 = 0 for FAT32
|
||
|
BPB_SecPerTrk dw ?
|
||
|
BPB_NumHeads dw ?
|
||
|
BPB_HiddSec dd ?
|
||
|
dd ? ; BPB_TotSec32
|
||
|
BPB_FATSz32 dd ?
|
||
|
BPB_ExtFlags dw ?
|
||
|
dw ? ; BPB_FSVer
|
||
|
BPB_RootClus dd ?
|
||
|
dw ? ; BPB_FSInfo
|
||
|
BPB_BkBootSec dw ?
|
||
|
rb 12 ; BPB_Reserved
|
||
|
BS_DrvNum db ?
|
||
|
db ? ; BS_Reserved1
|
||
|
db ? ; BS_BootSig
|
||
|
dd ? ; BS_VolID
|
||
|
rb 11 ; BS_VolLab
|
||
|
rb 8 ;
|
||
|
|
||
|
curseg dw 0x8000
|
||
|
|
||
|
start:
|
||
|
xor ax, ax
|
||
|
mov ss, ax
|
||
|
mov sp, 0x7C00
|
||
|
mov ds, ax
|
||
|
mov bp, sp
|
||
|
cld
|
||
|
sti
|
||
|
push dx ; byte [bp-2] = boot drive
|
||
|
if use_lba
|
||
|
mov ah, 41h
|
||
|
mov bx, 55AAh
|
||
|
int 13h
|
||
|
mov si, aNoLBA
|
||
|
jc err_
|
||
|
cmp bx, 0AA55h
|
||
|
jnz err_
|
||
|
test cl, 1
|
||
|
jz err_
|
||
|
else
|
||
|
mov ah, 8
|
||
|
int 13h
|
||
|
jc @f
|
||
|
movzx ax, dh
|
||
|
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
|
||
|
movzx eax, [bp+BPB_NumFATs-0x7C00]
|
||
|
mul [bp+BPB_FATSz32-0x7C00]
|
||
|
movzx ecx, [bp+BPB_RsvdSecCnt-0x7C00]
|
||
|
push ecx ; FAT start = dword [bp-6]
|
||
|
add eax, ecx
|
||
|
push eax ; data start = dword [bp-10]
|
||
|
;push dword -1 ; dword [bp-14] = current sector for FAT cache
|
||
|
db 66h
|
||
|
push -1 ; dword [bp-14] = current sector for FAT cache
|
||
|
mov eax, [bp+BPB_RootClus-0x7C00]
|
||
|
mov si, main_loader
|
||
|
call lookup_in_dir
|
||
|
jnc 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 eax, [es:di+20-2] ; hiword(eax) = hiword(cluster)
|
||
|
mov ax, [es:di+26] ; loword(eax) = loword(cluster)
|
||
|
mov es, bx ; es = 0
|
||
|
mov bx, 0x7E00
|
||
|
push bx ; save return address: bx = 7E00
|
||
|
; fall through - 'ret' in read_cluster will return to 7E00
|
||
|
|
||
|
read_cluster:
|
||
|
; ss:bp = 0:7C00
|
||
|
; es:bx = pointer to data
|
||
|
; eax = cluster
|
||
|
sub eax, 2
|
||
|
movzx ecx, [bp+BPB_SecsPerClus-0x7C00]
|
||
|
mul ecx
|
||
|
|
||
|
read_sectors2:
|
||
|
; same as read_sectors32, but eax is relative to start of data
|
||
|
add eax, [bp-10]
|
||
|
read_sectors32:
|
||
|
; ss:bp = 0:7C00
|
||
|
; es:bx = pointer to data
|
||
|
; eax = first sector
|
||
|
; cx = number of sectors
|
||
|
; some high words of 32-bit registers are destroyed!
|
||
|
pusha
|
||
|
add eax, [bp+BPB_HiddSec-0x7C00]
|
||
|
if use_lba
|
||
|
push ds
|
||
|
do_read_sectors:
|
||
|
push ax
|
||
|
push cx
|
||
|
cmp cx, 0x7F
|
||
|
jbe @f
|
||
|
mov cx, 0x7F
|
||
|
@@:
|
||
|
; create disk address packet on the stack
|
||
|
; dq starting LBA
|
||
|
push 0
|
||
|
push 0
|
||
|
push eax
|
||
|
; 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-2]
|
||
|
mov ah, 42h
|
||
|
int 13h
|
||
|
mov si, aReadError
|
||
|
jc err_
|
||
|
; restore stack
|
||
|
add sp, 10h
|
||
|
; increase current sector & buffer; decrease number of sectors
|
||
|
movzx esi, cx
|
||
|
mov ax, es
|
||
|
shl cx, 5
|
||
|
add ax, cx
|
||
|
mov es, ax
|
||
|
pop cx
|
||
|
pop ax
|
||
|
add eax, esi
|
||
|
sub cx, si
|
||
|
jnz do_read_sectors
|
||
|
pop ds
|
||
|
popa
|
||
|
ret
|
||
|
else
|
||
|
do_read_sectors:
|
||
|
pusha
|
||
|
pop edi ; loword(edi) = di, hiword(edi) = si
|
||
|
push bx
|
||
|
|
||
|
; eax / (SectorsPerTrack) -> eax, remainder bx
|
||
|
movzx esi, [bp+BPB_SecPerTrk-0x7C00]
|
||
|
xor edx, edx
|
||
|
div esi
|
||
|
mov bx, dx ; bx=sector-1
|
||
|
|
||
|
; eax -> dx:ax
|
||
|
push eax
|
||
|
pop ax
|
||
|
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
|
||
|
sub si, bx
|
||
|
cmp cx, si
|
||
|
jbe @f
|
||
|
mov cx, si
|
||
|
@@:
|
||
|
|
||
|
inc bx
|
||
|
; now ax=track, dl=head, dh=0, cl=number of sectors, ch=0, bl=sector; convert to int13 format
|
||
|
movzx edi, cx
|
||
|
mov dh, dl
|
||
|
mov dl, [bp-2]
|
||
|
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 edi
|
||
|
popa
|
||
|
add eax, edi
|
||
|
sub cx, di
|
||
|
jnz do_read_sectors
|
||
|
popa
|
||
|
ret
|
||
|
end if
|
||
|
|
||
|
lookup_in_dir:
|
||
|
; in: ds:si -> 11-bytes FAT name
|
||
|
; in: eax = cluster
|
||
|
; in: bx = 0
|
||
|
; out: if found: CF=0, es:di -> directory entry
|
||
|
; out: if not found: CF=1
|
||
|
; push 0x8000
|
||
|
; pop es
|
||
|
; read current cluster: first cluster goes to 8000:0000, others - to 8200:0000
|
||
|
mov es, [bp-7C00h + curseg]
|
||
|
push es
|
||
|
push eax
|
||
|
call read_cluster
|
||
|
mov ax, es
|
||
|
cmp ah, 82h
|
||
|
jb @f
|
||
|
mov ax, 8200h
|
||
|
@@:
|
||
|
mov [bp-7C00h + curseg], ax
|
||
|
pop eax
|
||
|
pop es
|
||
|
; scan for filename
|
||
|
shl cx, 4
|
||
|
xor di, di
|
||
|
sloop:
|
||
|
cmp byte [es:di], bl
|
||
|
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
|
||
|
; next cluster
|
||
|
push 0x6000
|
||
|
pop es
|
||
|
push es ax
|
||
|
shr eax, 7
|
||
|
cmp eax, [bp-14]
|
||
|
mov [bp-14], eax
|
||
|
jz @f
|
||
|
add eax, [bp-6]
|
||
|
mov cx, 1
|
||
|
call read_sectors32
|
||
|
@@:
|
||
|
pop di es
|
||
|
and di, 0x7F
|
||
|
shl di, 2
|
||
|
and byte [es:di+3], 0x0F
|
||
|
mov eax, [es:di]
|
||
|
;and eax, 0x0FFFFFFF
|
||
|
cmp eax, 0x0FFFFFF7
|
||
|
jb lookup_in_dir
|
||
|
snotfound:
|
||
|
stc
|
||
|
sdone:
|
||
|
ret
|
||
|
|
||
|
out_string:
|
||
|
; in: ds:si -> ASCIIZ string
|
||
|
lodsb
|
||
|
test al, al
|
||
|
jz sdone
|
||
|
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 F32'
|
||
|
|
||
|
db 56h
|
||
|
; just to make file 512 bytes long :)
|
||
|
db 'd' xor 'i' xor 'a' xor 'm' xor 'o' xor 'n' xor 'd'
|
||
|
|
||
|
; 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_sectors32, read_sectors2, err_, noloader
|