; -*- fundamental -*- ; GeekOS setup code ; Copyright (c) 2001,2004 David H. Hovemeyer ; (c) 2008, Peter Dinda ; (c) 2008, Jack Lange ; (c) 2008, The V3VEE Project ; $Revision: 1.8 $ ; This is free software. You are permitted to use, ; redistribute, and modify it as specified in the file "COPYING". ; A lot 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 %define __BIG_KERNEL__ %include "defs.asm" [BITS 16] [ORG 0x0] start: db 0xEB db 46 ;trampoline ; This is the setup header, and it must start at %cs:2 (old 0x9020:2) db 'H' ; header signature db 'd' db 'r' db 'S' dw 0x0203 ; header version number (>= 0x0105) ; or else old loadlin-1.5 will fail) realmode_swtch: dw 0, 0 ; default_switch, SETUPSEG start_sys_seg: dw SYSSEG dw kernel_version ; pointing to kernel version string ; above section of header is compatible ; with loadlin-1.5 (header v1.5). Don't ; change it. type_of_loader: db 0 ; = 0, old one (LILO, Loadlin, ; Bootlin, SYSLX, bootsect...) ; See Documentation/i386/boot.txt for ; assigned ids ; flags, unused bits must be zero (RFU) bit within loadflags loadflags: db 1 ;LOADED_HIGH equ 1 ; If set, the kernel is loaded high ;CAN_USE_HEAP equ 0x80 ; If set, the loader also has set ; heap_end_ptr to tell how much ; space behind setup.S can be used for ; heap purposes. ; Only the loader knows what is free ;%ifndef __BIG_KERNEL__ ; db 1 ;%else ; db 1 ;%endif setup_move_size: dw 0x8000 ; size to move, when setup is not ; loaded at 0x90000. We will move setup ; to 0x90000 then just before jumping ; into the kernel. However, only the ; loader knows how much data behind ; us also needs to be loaded. code32_start: dd 0x100000 ; here loaders can put a different ; start address for 32-bit code. ;%ifndef __BIG_KERNEL__ ; dd 0x100000 ; 0x1000 = default for zImage ;%else ; dd 0x100000 ; 0x100000 = default for big kernel ;%endif ramdisk_image: dd 0 ; address of loaded ramdisk image ; Here the loader puts the 32-bit ; address where it loaded the image. ; This only will be read by the kernel. ramdisk_size: dd 0 ; its size in bytes bootsect_kludge: dd 0 ; obsolete heap_end_ptr: dw modelist+1024 ; (Header version 0x0201 or later) ; space from here (exclusive) down to ; end of setup code can be used by setup ; for local heap purposes. pad1: dw 0 cmd_line_ptr: dd 0 ; (Header version 0x0202 or later) ; If nonzero, a 32-bit pointer ; to the kernel command line. ; The command line should be ; located between the start of ; setup and the end of low ; memory (0xa0000), or it may ; get overwritten before it ; gets read. If this field is ; used, there is no longer ; anything magical about the ; 0x90000 segment; the setup ; can be located anywhere in ; low memory 0x10000 or higher. ramdisk_max: dd 0xffffffff ;kernel_alignment: dd 0x200000 ; physical addr alignment required for ; protected mode relocatable kernel ;%ifdef CONFIG_RELOCATABLE ;relocatable_kernel: db 1 ;%else ;relocatable_kernel: db 0 ;%endif ;pad2: db 0 ;pad3: dw 0 ;cmdline_size: dd COMMAND_LINE_SIZE-1 ;length of the command line, ;added with boot protocol ;version 2.06 trampoline: call start_setup ; ALIGN 16 space: %rep 1024 db 0 %endrep ; The offset at this point is 0x240 ; End of setup header ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; start_setup: ; Redefine the data segment so we can access variables ; declared in this file. mov ax, SETUPSEG mov ds, ax ; Use int 15h to find out size of extended memory in KB. ; Extended memory is the memory above 1MB. So by ; adding 1MB to this amount, we get the total amount ; of system memory. We can only detect 64MB this way, ; but that's OK for now. ;mov ah, 0x88 ;int 0x15 ;add ax, 1024 ; 1024 KB == 1 MB mov ax, 0xe801 int 0x15 add ax, 1024 ; 1024 KB == 1 MB mov [mem_size_kbytes], ax mov [mem_size_eblocks], bx ; Kill the floppy motor. call Kill_Motor ; Block interrupts, since we can't meaningfully handle them yet ; and we no longer need BIOS services. cli ; Set up IDT and GDT registers lidt [IDT_Pointer] lgdt [GDT_Pointer] ; Initialize the interrupt controllers, and enable the ; A20 address line call Init_PIC call Enable_A20 ; Switch to protected mode! mov ax, 0x01 lmsw ax ; Jump to 32 bit code. jmp dword KERNEL_CS:(SETUPSEG << 4) + setup_32 [BITS 32] setup_32: ; set up data segment registers mov ax, KERNEL_DS mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax ; Create the stack for the initial kernel thread. mov esp, KERN_STACK + 4096 ; Build Boot_Info struct on stack. ; Note that we push the fields on in reverse order, ; since the stack grows downwards. ;Zheng 08/02/2008 xor eax, eax mov eax, [(SETUPSEG<<4)+ramdisk_size] push eax xor eax, eax mov eax, [(SETUPSEG<<4)+ramdisk_image] push eax xor eax, eax mov ax, [(SETUPSEG<<4)+mem_size_kbytes] xor ebx, ebx mov bx, [(SETUPSEG<<4)+mem_size_eblocks] shl ebx, 6 add eax, ebx push eax ; memSizeKB mov eax, VMM_SIZE shl eax, 9 ; Multiply the vmm size by 512 to get byte size push ebx ; size of the VMM push dword 8 ; bootInfoSize ; Pass pointer to Boot_Info struct as argument to kernel ; entry point. push esp ; Push return address to make this look like a call ; XXX - untested push dword (SETUPSEG<<4)+.returnAddr ; Far jump into kernel jmp KERNEL_CS:ENTRY_POINT .returnAddr: ; We shouldn't return here. .here: jmp .here [BITS 16] ; Kill the floppy motor. ; This code was shamelessly stolen from Linux. Kill_Motor: mov dx, 0x3f2 xor al, al out dx, al ret Init_PIC: ; Initialize master and slave PIC! mov al, ICW1 out 0x20, al ; ICW1 to master call Delay out 0xA0, al ; ICW1 to slave call Delay mov al, ICW2_MASTER out 0x21, al ; ICW2 to master call Delay mov al, ICW2_SLAVE out 0xA1, al ; ICW2 to slave call Delay mov al, ICW3_MASTER out 0x21, al ; ICW3 to master call Delay mov al, ICW3_SLAVE out 0xA1, al ; ICW3 to slave call Delay mov al, ICW4 out 0x21, al ; ICW4 to master call Delay out 0xA1, al ; ICW4 to slave call Delay mov al, 0xff ; mask all ints in slave out 0xA1, al ; OCW1 to slave call Delay mov al, 0xfb ; mask all ints but 2 in master out 0x21, al ; OCW1 to master call Delay ret ; Linux uses this code. ; The idea is that some systems issue port I/O instructions ; faster than the device hardware can deal with them. Delay: jmp .done .done: ret ; Enable the A20 address line, so we can correctly address ; memory above 1MB. Enable_A20: mov al, 0xD1 out 0x64, al call Delay mov al, 0xDF out 0x60, al call Delay ret ; ---------------------------------------------------------------------- ; Setup data ; ---------------------------------------------------------------------- mem_size_kbytes: dw 0 mem_size_eblocks: dw 0 ; ---------------------------------------------------------------------- ; The GDT. Creates flat 32-bit address space for the kernel ; code, data, and stack. Note that this GDT is just used ; to create an environment where we can start running 32 bit ; code. The kernel will create and manage its own GDT. ; ---------------------------------------------------------------------- ; GDT initialization stuff NUM_GDT_ENTRIES equ 3 ; number of entries in GDT GDT_ENTRY_SZ equ 8 ; size of a single GDT entry align 8, db 0 GDT: ; Descriptor 0 is not used dw 0 dw 0 dw 0 dw 0 ; Descriptor 1: kernel code segment dw 0xFFFF ; bytes 0 and 1 of segment size dw 0x0000 ; bytes 0 and 1 of segment base address db 0x00 ; byte 2 of segment base address db 0x9A ; present, DPL=0, non-system, code, non-conforming, ; readable, not accessed db 0xCF ; granularity=page, 32 bit code, upper nibble of size db 0x00 ; byte 3 of segment base address ; Descriptor 2: kernel data and stack segment ; NOTE: what Intel calls an "expand-up" segment ; actually means that the stack will grow DOWN, ; towards lower memory. So, we can use this descriptor ; for both data and stack references. dw 0xFFFF ; bytes 0 and 1 of segment size dw 0x0000 ; bytes 0 and 1 of segment base address db 0x00 ; byte 2 of segment base address db 0x92 ; present, DPL=0, non-system, data, expand-up, ; writable, not accessed db 0xCF ; granularity=page, big, upper nibble of size db 0x00 ; byte 3 of segment base address GDT_Pointer: dw NUM_GDT_ENTRIES*GDT_ENTRY_SZ ; limit dd (SETUPSEG<<4) + GDT ; base address IDT_Pointer: dw 0 dd 00 ; Here's a bunch of information about your current kernel.. kernel_version: db "1.0.0VMMHack" db " (" db "copyright" db "@" db "2008" db ") " db "" db 0 modelist: