X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=blobdiff_plain;f=misc%2Ftest_vm%2Fsrc%2Fgeekos%2Ffd_boot.asm;fp=misc%2Ftest_vm%2Fsrc%2Fgeekos%2Ffd_boot.asm;h=d5fa1204751c739626bc177a9f9d9f6cdbc19859;hp=0000000000000000000000000000000000000000;hb=ddc16b0737cf58f7aa90a69c6652cdf4090aec51;hpb=626595465a2c6987606a6bc697df65130ad8c2d3 diff --git a/misc/test_vm/src/geekos/fd_boot.asm b/misc/test_vm/src/geekos/fd_boot.asm new file mode 100644 index 0000000..d5fa120 --- /dev/null +++ b/misc/test_vm/src/geekos/fd_boot.asm @@ -0,0 +1,425 @@ +; -*- fundamental -*- +; Boot sector for GeekOS +; Copyright (c) 2001,2004 David H. Hovemeyer +; Copyright (c) 2003, Jeffrey K. Hollingsworth +; $Revision: 1.1 $ + +; This is free software. You are permitted to use, +; redistribute, and modify it as specified in the file "COPYING". + +; Loads setup code and a program image from sectors 1..n of a floppy +; and executes the setup code (which will in turn execute +; the program image). + +; Some of this code is adapted from Kernel Toolkit 0.2 +; and Linux version 2.2.x, so the following copyrights apply: + +; Copyright (C) 1991, 1992 Linus Torvalds +; modified by Drew Eckhardt +; modified by Bruce Evans (bde) +; adapted for Kernel Toolkit by Luigi Sgro + +%include "defs.asm" + + +; Pad to desired offset from start symbol. +; Usage: Pad_From_Symbol offset, symbol +%macro Pad_From_Symbol 2 + times (%1 - ($ - %2)) db 0 +%endmacro + +; ---------------------------------------------------------------------- +; The actual code +; ---------------------------------------------------------------------- + +[BITS 16] +[ORG 0x0] + +BeginText: ; needed to calculate padding bytes to fill the sector + + ; Copy the boot sector into INITSEG. + mov ax, BOOTSEG + mov ds, ax ; source segment for string copy + xor si, si ; source index for string copy + mov ax, INITSEG + mov es, ax ; destination segment for string copy + xor di, di ; destination index for string copy + cld ; clear direction flag + mov cx, 256 ; number of words to copy + rep movsw ; copy 512 bytes + + jmp INITSEG:after_move + +after_move: + ; Now we're executing in INITSEG + + + ; We want the data segment to refer to INITSEG + ; (since we've defined variables in the same place as the code) + mov ds, ax ; ax still contains INITSEG + + ; Put the stack in the place where we were originally loaded. + ; By definition, there is nothing important there now. + mov ax, 0 + mov ss, ax + mov sp, (BOOTSEG << 4) + 512 - 2 + + +load_setup: + ; Load the setup code. + mov ax, word [setupStart] + mov word [sec_count], ax + add ax, [setupSize] + mov word [max_sector], ax +.again: + mov ax, [sec_count] + push ax ; 1st param to ReadSector (log sec num) + push word SETUPSEG ; 2nd param to ReadSector (seg base) + sub ax, [setupStart] ; convert to 0-indexed + shl ax, 9 ; multiply by 512 + push ax ; ...to get 3rd param (byte offset) + + ; read the sector from the floppy + call ReadSector + add sp, 6 ; clear 3 word params + + ; on to next sector + inc word [sec_count] + + ; are we done? + mov bx, word [max_sector] + cmp word [sec_count], bx + jl .again + + +load_kernel: + ; Load the kernel image from sectors KERN_START_SEC..n of the + ; floppy into memory at KERNSEG. Note that there are 128 sectors + ; per 64K segment. So, when figuring out which segment to + ; load the sector into, we shift right by 7 bits (which is + ; equivalent to dividing by 128). + + ; Figure out start sector and max sector + + mov ax, word [kernelStart] + mov word [sec_count], ax + add ax, word [kernelSize] + mov word [max_sector], ax +.again: + + + mov ax, [sec_count] ; logical sector on the floppy +; mov dx, ax +; call PrintHex +; call PrintNL + push ax ; 1st param to ReadSector (log sec num) + sub ax, [kernelStart] ; convert to 0-indexed + mov cx, ax ; save in cx + shr ax, 7 ; divide by 128 + shl ax, 12 ; ...and multiply by 0x1000 + add ax, KERNSEG ; ...to get base relative to KERNSEG +; mov dx, ax +; call PrintHex +; call PrintNL + push ax ; 2nd param to ReadSector (seg base) + and cx, 0x7f ; mod sector by 128 + shl cx, 9 ; ...and multiply by 512 + push cx ; to get offset in segment (3rd parm) +; mov dx, cx +; call PrintHex +; call PrintNL + + + ; read the sector from the floppy + call ReadSector + add sp, 6 ; clear 3 word params + + + ; on to next sector + inc word [sec_count] + + ; have we loaded all of the sectors? + mov bx, word [max_sector] + cmp word [sec_count], bx + jl .again + + +; execute bios call + + push cx + push si + push bx + push es ; + + mov dx, cs + call PrintHex + call PrintNL + + push cs + pop es + + mov si, bootsect_gdt + mov ah, 87h + + ;; determine the actual kernel size + mov cx, word [kernelSize] ; number of 512 byte sectors + shl cx, 8 ; multiply by 9-1 to get number of bytes / 2 (words) + + ;; Print out the size of the kernel + mov dx, cx + call PrintHex + call PrintNL + + int 0x15 + + adc ax, 0 + + ;; Print out the return code to the screen + mov dx, ax + call PrintHex + call PrintNL + + mov dx, KERNSEG + call PrintHex + call PrintNL + + mov dx, SETUPSEG + call PrintHex + call PrintNL + + + + mov dx, 0x4a4a + call PrintHex + call PrintNL + + pop es ; + pop bx + pop si + pop cx + + +;.loop: jmp .loop + + +.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 0x00,0x00,0x01 ; ! base = 0x010000 + 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