1
0

arch/i386: Boot to kernel main() with proper initial segmentation/paging setup

This commit is contained in:
2012-12-17 00:35:23 -05:00
parent cee0ac7dda
commit c51062ce87
5 changed files with 153 additions and 60 deletions

View File

@ -18,39 +18,128 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
.global start /* making entry point visible to linker */
#include <arch/segmentation.h>
/* setting up the Multiboot header - see GRUB docs for details */
.set ALIGN, 1<<0 /* align loaded modules on page boundaries */
.set MEMINFO, 1<<1 /* provide memory map */
.set FLAGS, ALIGN | MEMINFO /* this is the Multiboot 'flag' field */
.set MAGIC, 0x1BADB002 /* 'magic number' lets bootloader find the header */
.set CHECKSUM, -(MAGIC + FLAGS) /* checksum required */
#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
/* reserve initial kernel stack space */
.set STACKSIZE, 0x4000 /* that is, 16k. */
.align 32
.lcomm stack, STACKSIZE /* reserve 16k stack on a doubleword boundary */
.comm mbd, 4 /* we will use this in i386_main */
.comm magic, 4 /* we will use this in i386_main */
/*
* 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 $(stack + STACKSIZE), %esp /* set up the stack */
movl %eax, magic /* Multiboot magic number */
movl %ebx, mbd /* Multiboot data structure */
movl %eax, virt_to_phys(magic) /* Save off multiboot magic number */
movl %ebx, virt_to_phys(mbd) /* Save off multiboot data structure */
call i386_main /* call kernel proper */
movl $virt_to_phys(init_page_dir), %eax /* load page directory base register */
movl %eax, %cr3
cli
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
hlt /* halt machine should kernel return */
jmp hang
.globl atags_ptr
.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:
.word 0
.long 0