/* Copyright (C) 2012, Aaron Lindsay This file is part of Aedrix. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #define KERNEL_START_VIRTUAL 0xc0000000 #define KERNEL_START_PAGE (KERNEL_START_VIRTUAL >> 22) #define virt_to_phys(addr) (addr - KERNEL_START_VIRTUAL) #define STACK_SIZE 0x4000 /* 16k */ /* setup multiboot header */ #define ALIGN (1<<0) /* align loaded modules on page boundaries */ #define MEMINFO (1<<1) /* provide memory map */ #define FLAGS (ALIGN | MEMINFO) /* this is the Multiboot 'flag' field */ #define MAGIC 0x1BADB002 /* 'magic number' lets bootloader find the header */ #define CHECKSUM (-(MAGIC + FLAGS)) /* checksum required */ .align 4 .long MAGIC .long FLAGS .long CHECKSUM /* * Kernel entry in assembly for i386 architecture. This handles saving off * multiboot information, setting up initial page tables to map the kernel to * where it is linked against, ensures segmentation is setup right (large segments * over entire address range), and finally jumps to the kernel's main() function * in C. */ .global start start: movl %eax, virt_to_phys(magic) /* Save off multiboot magic number */ movl %ebx, virt_to_phys(mbd) /* Save off multiboot data structure */ movl $virt_to_phys(init_page_dir), %eax /* load page directory base register */ movl %eax, %cr3 movl %cr4, %eax orl $0x00000010, %eax /* set PSE bit for 4mb pages */ movl %eax, %cr4 movl %cr0, %eax orl $0x80000000, %eax /* set PG bit to enable paging */ movl %eax, %cr0 lea paging_enabled, %eax jmp *%eax paging_enabled: movl $0, init_page_dir /* unmap identity mapping and invalidate */ invlpg 0 movl $(stack + STACK_SIZE), %esp /* set up the stack */ /* setup two large kernel segments over entire 4gb address range */ pushl $initial_gdt /* setup the pointer to the GDT */ pushw $(INITIAL_GDT_SIZE-1) lgdt (%esp) addl $6, %esp ljmp $SEGMENT_SELECTOR_KERNEL_CS, $gdt_reload /* long jump to set %cs */ gdt_reload: /* reset remaining segment registers */ movl $SEGMENT_SELECTOR_KERNEL_DS, %eax movl %eax, %ds movl %eax, %es movl %eax, %fs movl %eax, %gs movl %eax, %ss call main /* call kernel proper */ cli hang: hlt /* halt machine should kernel return */ jmp hang .section .init /* Note: if the offsets into the GDT change, they must be updated in arch/segmentation.h */ .set INITIAL_GDT_SIZE, 8*6 initial_gdt: .long 0x00000000 /* 0x00 intentionally empty */ .long 0x00000000 .long 0x00000000 /* 0x08 TODO TSS */ .long 0x00000000 .long 0x0000ffff /* 0x10 kernel code segment (%cs) */ .long 0x00cf9a00 .long 0x0000ffff /* 0x18 kernel data segment (%ds) */ .long 0x00cf9200 .long 0x0000ffff /* 0x20 userspace code segment (%cs) */ .long 0x00cffa00 .long 0x0000ffff /* 0x28 userspace data segment (%ds) */ .long 0x00cff200 .align 0x1000 init_page_dir: /* This page directory entry identity-maps the first 4MB of the 32-bit physical address space. All bits are clear except the following: bit 7: PS The kernel page is 4MB. bit 1: RW The kernel page is read/write. bit 0: P The kernel page is present. This entry must be here -- otherwise the kernel will crash immediately after paging is enabled because it can't fetch the next instruction! It's ok to unmap this page later. */ .long 0x00000083 .rept (KERNEL_START_PAGE - 1) .long 0 /* Pages before kernel space. */ .endr /* This page directory entry defines a 4MB page containing the kernel. */ .long 0x00000083 .rept (1024 - KERNEL_START_PAGE - 1) .long 0 /* Pages after the kernel image. */ .endr /* reserve initial kernel stack space */ .align 32 .lcomm stack, STACK_SIZE /* reserve stack space on a doubleword boundary */ /* place to store multiboot header information */ .global mbd .comm mbd, 4 /* we will use this in i386_main */ .global magic .comm magic, 4 /* we will use this in i386_main */ /* TODO FIXME remove this - needs fix to dependencies first */ .global atags_ptr atags_ptr: .long 0