; 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 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 ''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 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