; Boot sector for GeekOS ; Copyright (c) 2001,2004 David H. Hovemeyer ; Copyright (c) 2003, Jeffrey K. Hollingsworth ; Copyright (c) 2008, Jack Lange high copy table for the bios ; mov ax, word [bootsect_src_base] ; ; add ax, 512 ; mov dx,ax; ; call PrintHex ; adc byte [bootsect_src_base+2], 0 ; mov word [bootsect_src_base],ax mov ax, word [bootsect_dst_base] ; add ax, 512 adc byte [bootsect_dst_base+2], 0 mov word [bootsect_dst_base],ax ; have we loaded all of the sectors? mov bx, word [max_sector] cmp word [sec_count], bx .stall ; jmp .skip jl .again2 .skip ; Now we've loaded the setup code and the kernel image. ; Jump to setup code. jmp SETUPSEG:0 ; Read a sector from the floppy drive. ; This code (and the rest of this boot sector) will have to ; be re-written at some point so it reads more than one ; sector at a time. ; ; Parameters: ; - "logical" sector number [bp+8] ; - destination segment [bp+6] ; - destination offset [bp+4] ReadSector: push bp ; set up stack frame mov bp, sp ; " pusha ; save all registers %if 0 ; debug params mov dx, [bp+8] call PrintHex call PrintNL mov dx, [bp+6] call PrintHex call PrintNL mov dx, [bp+4] call PrintHex call PrintNL %endif ; Sector = log_sec % SECTORS_PER_TRACK ; Head = (log_sec / SECTORS_PER_TRACK) % HEADS mov ax, [bp+8] ; get logical sector number from stack xor dx, dx ; dx is high part of dividend (== 0) mov bx, SECTORS_PER_TRACK ; divisor div bx ; do the division mov [sec], dx ; sector is the remainder and ax, 1 ; same as mod by HEADS==2 (slight hack) mov [head], ax ; Track = log_sec / (SECTORS_PER_TRACK*HEADS) mov ax, [bp+8] ; get logical sector number again xor dx, dx ; dx is high part of dividend mov bx, SECTORS_PER_TRACK*2 ; divisor div bx ; do the division mov [track], ax ; track is quotient %if 0 ; debugging code mov dx, [sec] call PrintHex call PrintNL mov dx, [head] call PrintHex call PrintNL mov dx, [track] call PrintHex call PrintNL %endif ; Now, try to actually read the sector from the floppy, ; retrying up to 3 times. mov [num_retries], byte 0 .again: mov ax, [bp+6] ; dest segment... mov es, ax ; goes in es mov ax, (0x02 << 8) | 1 ; function = 02h in ah, ; # secs = 1 in al mov bx, [track] ; track number... mov ch, bl ; goes in ch mov bx, [sec] ; sector number... mov cl, bl ; goes in cl... inc cl ; but it must be 1-based, not 0-based mov bx, [head] ; head number... mov dh, bl ; goes in dh xor dl, dl ; hard code drive=0 mov bx, [bp+4] ; offset goes in bx ; (es:bx points to buffer) ; Call the BIOS Read Diskette Sectors service int 0x13 ; If the carry flag is NOT set, then there was no error ; and we're done. jnc .done ; Error - code stored in ah mov dx, ax call PrintHex inc byte [num_retries] cmp byte [num_retries], 3 jne .again ; If we got here, we failed thrice, so we give up mov dx, 0xdead call PrintHex .here: jmp .here .done: popa ; restore all regisiters pop bp ; leave stack frame ret ; Include utility routines: ;%include "util.asm" ; REPLACED WITH FOLLOWING WHICH MUST BE COMPILED 16 FOR USE IN THIS CODE PrintHex: pusha mov cx, 4 ; 4 hex digits .PrintDigit: rol dx, 4 ; rotate so that lowest 4 bits are used mov ax, 0E0Fh ; ah = request, al = mask for nybble and al, dl add al, 90h ; convert al to ascii hex (four instructions) daa ; I've spent 1 hour to understand how it works.. adc al, 40h daa int 10h loop .PrintDigit popa ret ; Print a newline. PrintNL: ; print CR and NL push ax mov ax, 0E0Dh ; CR int 10h mov al, 0Ah ; LF int 10h pop ax ret ; ---------------------------------------------------------------------- ; Variables ; ---------------------------------------------------------------------- ; These are used by ReadSector head: dw 0 track: dw 0 sec: dw 0 num_retries: db 0 ; Used for loops reading sectors from floppy sec_count: dw 0 max_sector: dw 0 bootsect_gdt: dw 0,0,0,0 dw 0,0,0,0 bootsect_src: dw 0xffff bootsect_src_base: db 0,0x20,0x08 ; ! base = 0x082000 db 0x93 ; ! typbyte dw 0 ; ! limit16,base24 =0 bootsect_dst: dw 0xffff bootsect_dst_base: db 0,0,0x10 ; ! base = 0x100000 db 0x93 ; ! typbyte dw 0 ; ! limit16,base24 =0 dw 0,0,0,0 ; ! BIOS CS dw 0,0,0,0 ; ! BIOS DS ; Padding to make the PFAT Boot Record sit just before the BIOS signature. ;Pad_From_Symbol PFAT_BOOT_RECORD_OFFSET, BeginText ; PFAT boot record ; Describes how to load the setup program and kernel. ; The default values are appropriate for creating a boot ; floppy by concatenating the boot sector, setup program, ; and kernel image. The buildFat program will change ; these values if the boot floppy is formatted as a PFAT ; filesystem. dw 0 dw 0 dw 0 dw 0 dw 0 dw 0 dw 0 dw 0 dw 0 dw 0 ;; part of pfat boot record setupStart: dw 1 ; by default, setup is at first sector ;; part of pfat boot record setupSize: dw NUM_SETUP_SECTORS ; number of sectors in setup ;; part of pfat boot record kernelStart: dw 1+NUM_SETUP_SECTORS ; default start sector for kernel ;; part of pfat boot record kernelSize: dw NUM_KERN_SECTORS ; Finish by writing the BIOS signature to mark this as ; a valid boot sector. Pad_From_Symbol BIOS_SIGNATURE_OFFSET, BeginText Signature dw 0xAA55 ; BIOS controls this to ensure this is a boot sector