arch/i386: Boot to kernel main() with proper initial segmentation/paging setup
This commit is contained in:
		| @@ -1,30 +0,0 @@ | ||||
| #include <stdint.h> | ||||
|  | ||||
| void main(); | ||||
|   | ||||
| void i386_main(void) | ||||
| { | ||||
|    extern uint32_t magic; | ||||
|   | ||||
|    /* Uncomment the following if you want to be able to access the multiboot header */ | ||||
|    /* extern void *mbd; */ | ||||
|   | ||||
|    if ( magic != 0x2BADB002 ) | ||||
|    { | ||||
|       /* Something went not according to specs. Print an error */ | ||||
|       /* message and halt, but do *not* rely on the multiboot */ | ||||
|       /* data structure. */ | ||||
|    } | ||||
|   | ||||
|    /* You could either use multiboot.h */ | ||||
|    /* (http://www.gnu.org/software/grub/manual/multiboot/multiboot.html#multiboot_002eh) */ | ||||
|    /* or do your offsets yourself. The following is merely an example. */  | ||||
|    //char * boot_loader_name =(char*) ((long*)mbd)[16]; | ||||
|   | ||||
|    /* Print a letter to screen to see everything is working: */ | ||||
|    unsigned char *videoram = (unsigned char *)0xB8000; | ||||
|    videoram[0] = 65; /* character 'A' */ | ||||
|    videoram[1] = 0x07; /* light grey (7) on black (0). */ | ||||
|  | ||||
|    main(); | ||||
| } | ||||
							
								
								
									
										26
									
								
								arch/i386/include/arch/segmentation.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								arch/i386/include/arch/segmentation.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| /* | ||||
|     Copyright (C) 2012, Aaron Lindsay <aaron@aclindsay.com> | ||||
|  | ||||
|     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. | ||||
|  */ | ||||
|  | ||||
| #define SEGMENT_SELECTOR_KERNEL_PRIVILEGE  0x0 | ||||
| #define SEGMENT_SELECTOR_KERNEL_CS         (0x10 | SEGMENT_SELECTOR_KERNEL_PRIVILEGE) | ||||
| #define SEGMENT_SELECTOR_KERNEL_DS         (0x18 | SEGMENT_SELECTOR_KERNEL_PRIVILEGE) | ||||
| #define SEGMENT_SELECTOR_USER_PRIVILEGE    0x3 | ||||
| #define SEGMENT_SELECTOR_USER_CS           (0x20 | SEGMENT_SELECTOR_USER_PRIVILEGE) | ||||
| #define SEGMENT_SELECTOR_USER_DS           (0x28 | SEGMENT_SELECTOR_USER_PRIVILEGE) | ||||
| @@ -2,9 +2,12 @@ ENTRY (start) | ||||
|  | ||||
| SECTIONS | ||||
| { | ||||
| 	. = 0x00100000; | ||||
| 	.text ALIGN (0x1000) : { *(.text*) *(.rodata*) } | ||||
| 	.init : { | ||||
| 	. = 0xc0100000; | ||||
| 	kernel_start = .; | ||||
| 	.text ALIGN(0x1000) : AT(ADDR(.text) - 0xc0000000) { | ||||
| 		*(.text*) *(.rodata*) | ||||
| 	} | ||||
| 	.init : AT(ADDR(.init) - 0xc0000000) { | ||||
| 		early_initcalls_start = .; | ||||
| 		*(.earlyinitcalls*) | ||||
| 		early_initcalls_end = .; | ||||
| @@ -12,7 +15,13 @@ SECTIONS | ||||
| 		*(.driversubsysinitcalls*) | ||||
| 		*(.deviceinitcalls*) | ||||
| 		initcalls_end = .; | ||||
| 		*(.init*) | ||||
| 	} | ||||
| 	.data ALIGN (0x1000) : { *(.data*) } | ||||
| 	.bss : { *(.bss*) *(COMMON*) } | ||||
| 	.data ALIGN(0x1000) : AT(ADDR(.data) - 0xc0000000) { | ||||
| 		*(.data*) | ||||
| 	} | ||||
| 	.bss : AT(ADDR(.bss) - 0xc0000000) { | ||||
| 		*(.bss*) *(COMMON*) | ||||
| 	} | ||||
| 	kernel_end = .; | ||||
| } | ||||
|   | ||||
| @@ -22,8 +22,7 @@ aedrix-boot.img: aedrix-kernel.elf | ||||
| 	$(V)mcopy -i "$@" aedrix-kernel.elf ::kernel.bin | ||||
| 	$(V)mcopy -i "$@" arch/i386/syslinux.cfg ::syslinux.cfg | ||||
|  | ||||
| OBJS_$(d) := $(d)/start.o \ | ||||
| 	$(d)/i386_main.o | ||||
| OBJS_$(d) := $(d)/start.o | ||||
|  | ||||
| KOBJS += $(OBJS_$(d)) | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user