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
 | 
					SECTIONS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	. = 0x00100000;
 | 
						. = 0xc0100000;
 | 
				
			||||||
	.text ALIGN (0x1000) : { *(.text*) *(.rodata*) }
 | 
						kernel_start = .;
 | 
				
			||||||
	.init : {
 | 
						.text ALIGN(0x1000) : AT(ADDR(.text) - 0xc0000000) {
 | 
				
			||||||
 | 
							*(.text*) *(.rodata*)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						.init : AT(ADDR(.init) - 0xc0000000) {
 | 
				
			||||||
		early_initcalls_start = .;
 | 
							early_initcalls_start = .;
 | 
				
			||||||
		*(.earlyinitcalls*)
 | 
							*(.earlyinitcalls*)
 | 
				
			||||||
		early_initcalls_end = .;
 | 
							early_initcalls_end = .;
 | 
				
			||||||
@@ -12,7 +15,13 @@ SECTIONS
 | 
				
			|||||||
		*(.driversubsysinitcalls*)
 | 
							*(.driversubsysinitcalls*)
 | 
				
			||||||
		*(.deviceinitcalls*)
 | 
							*(.deviceinitcalls*)
 | 
				
			||||||
		initcalls_end = .;
 | 
							initcalls_end = .;
 | 
				
			||||||
 | 
							*(.init*)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	.data ALIGN (0x1000) : { *(.data*) }
 | 
						.data ALIGN(0x1000) : AT(ADDR(.data) - 0xc0000000) {
 | 
				
			||||||
	.bss : { *(.bss*) *(COMMON*) }
 | 
							*(.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 "$@" aedrix-kernel.elf ::kernel.bin
 | 
				
			||||||
	$(V)mcopy -i "$@" arch/i386/syslinux.cfg ::syslinux.cfg
 | 
						$(V)mcopy -i "$@" arch/i386/syslinux.cfg ::syslinux.cfg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OBJS_$(d) := $(d)/start.o \
 | 
					OBJS_$(d) := $(d)/start.o
 | 
				
			||||||
	$(d)/i386_main.o
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
KOBJS += $(OBJS_$(d))
 | 
					KOBJS += $(OBJS_$(d))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,39 +18,128 @@
 | 
				
			|||||||
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
					    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 */
 | 
					#define KERNEL_START_VIRTUAL 0xc0000000
 | 
				
			||||||
.set ALIGN,    1<<0                     /* align loaded modules on page boundaries */
 | 
					#define KERNEL_START_PAGE (KERNEL_START_VIRTUAL >> 22)
 | 
				
			||||||
.set MEMINFO,  1<<1                     /* provide memory map */
 | 
					#define virt_to_phys(addr) (addr - KERNEL_START_VIRTUAL)
 | 
				
			||||||
.set FLAGS,    ALIGN | MEMINFO          /* this is the Multiboot 'flag' field */
 | 
					
 | 
				
			||||||
.set MAGIC,    0x1BADB002               /* 'magic number' lets bootloader find the header */
 | 
					#define STACK_SIZE 0x4000 /* 16k */
 | 
				
			||||||
.set CHECKSUM, -(MAGIC + FLAGS)         /* checksum required */
 | 
					
 | 
				
			||||||
 | 
					/* 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
 | 
					.align 4
 | 
				
			||||||
.long MAGIC
 | 
					.long MAGIC
 | 
				
			||||||
.long FLAGS
 | 
					.long FLAGS
 | 
				
			||||||
.long CHECKSUM
 | 
					.long CHECKSUM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* reserve initial kernel stack space */
 | 
					/*
 | 
				
			||||||
.set STACKSIZE, 0x4000                  /* that is, 16k. */
 | 
					 * Kernel entry in assembly for i386 architecture. This handles saving off
 | 
				
			||||||
.align 32
 | 
					 * multiboot information, setting up initial page tables to map the kernel to
 | 
				
			||||||
.lcomm stack, STACKSIZE                 /* reserve 16k stack on a doubleword boundary */
 | 
					 * where it is linked against, ensures segmentation is setup right (large segments
 | 
				
			||||||
.comm  mbd, 4                           /* we will use this in i386_main */
 | 
					 * over entire address range), and finally jumps to the kernel's main() function
 | 
				
			||||||
.comm  magic, 4                         /* we will use this in i386_main */
 | 
					 * in C.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					.global start
 | 
				
			||||||
start:
 | 
					start:
 | 
				
			||||||
    movl  $(stack + STACKSIZE), %esp    /* set up the stack */
 | 
						movl  %eax, virt_to_phys(magic)		/* Save off multiboot magic number */
 | 
				
			||||||
    movl  %eax, magic                   /* Multiboot magic number */
 | 
						movl  %ebx, virt_to_phys(mbd)		/* Save off multiboot data structure */
 | 
				
			||||||
    movl  %ebx, mbd                     /* 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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
 | 
						cli
 | 
				
			||||||
hang:
 | 
					hang:
 | 
				
			||||||
	hlt                                 /* halt machine should kernel return */
 | 
						hlt                                 /* halt machine should kernel return */
 | 
				
			||||||
	jmp   hang
 | 
						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:
 | 
					atags_ptr:
 | 
				
			||||||
	.word 0
 | 
						.long 0
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user