x86: use a flat segmentation model
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 27 May 2013 22:39:04 +0000 (15:39 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 27 May 2013 22:39:04 +0000 (15:39 -0700)
This no longer uses the -KERNBASE segmentation model to fake the mapping
of KERNBASE -> 0.  Instead, we construct a single page directory with
jumbo entries to use as the KERNBASE mapping (and one for the identity
mapping of 0 -> 0).  Previously, we were using this segmentation through
the early stages of kern/src/init.c.

We also link the bootstrap code for its original location in unpaged
memory, getting rid of the confusing RELOC business.

Finally, this assumes the ability to support jumbo pages.  Previously,
the kernel would just panic during start up.  Now, those ancient x86
machines will probably just reboot.  (page fault on the second level
page table with no idt).

kern/arch/i686/entry.S
kern/arch/i686/kernel.ld

index 62e9996..ab1afdf 100644 (file)
@@ -1,4 +1,6 @@
-/* See COPYRIGHT for copyright information. */
+/* Copyright (c) 2009-13 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details. */
 
 #include <arch/mmu.h>
 #include <arch/trap.h>
@@ -7,22 +9,6 @@
 # Shift Right Logical 
 #define SRL(val, shamt)                (((val) >> (shamt)) & ~(-1 << (32 - (shamt))))
 
-
-###################################################################
-# The kernel (this code) is linked at address (KERNBASE + 0x00100000 (1MB)), 
-# but we tell the bootloader to load it at physical address 
-# 0x00100000 (1MB), which is the start of extended memory.
-# (See kernel.ld)
-###################################################################
-
-
-###################################################################
-# RELOC(x) maps a symbol x from its link address to its actual
-# location in physical memory (its load address).       
-###################################################################
-#define        RELOC(x) ((x) - KERNBASE)
-
-
 .set CODE_SEL,0x8              # index of code seg within mygdt
 .set DATA_SEL,0x10             # index of data seg within mygdt
 
 #define MULTIBOOT_HEADER_FLAGS (MULTIBOOT_MEMORY_INFO | MULTIBOOT_PAGE_ALIGN)
 #define CHECKSUM (-(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS))
 
-###################################################################
-# entry point
-###################################################################
+.section .text
+# The kernel bootstrap (this code) is linked and loaded at physical address
+# 0x00100000 (1MB), which is the start of extended memory.  (See kernel.ld)
 
-# The Multiboot header
-.section .multiboot
+.code32
 .align 4
+multiboot_header:
 .long MULTIBOOT_HEADER_MAGIC
 .long MULTIBOOT_HEADER_FLAGS
 .long CHECKSUM
 
-.section .text
 .globl         _start
 _start:
        movw    $0x1234,0x472                   # warm boot
-
-       # Establish our own GDT in place of the boot loader's temporary GDT.
-       lgdt    RELOC(mygdtdesc)                # load descriptor table
-
-       # Immediately reload all segment registers (including CS!)
-       # with segment selectors from the new GDT.
-       movl    $DATA_SEL, %eax                 # Data segment selector
-       movw    %ax,%ds                         # -> DS: Data Segment
-       movw    %ax,%es                         # -> ES: Extra Segment
-       movw    %ax,%ss                         # -> SS: Stack Segment
-       ljmp    $CODE_SEL,$relocated            # reload CS by jumping
-relocated:
+       # Reload all segment registers (including CS!) with flag segment selectors
+       # from our boot GDT.
+       lgdt    mygdtdesc
+       movl    $DATA_SEL, %eax
+       movw    %ax,%ds
+       movw    %ax,%es
+       movw    %ax,%ss
+       ljmp    $CODE_SEL,$newcs                # reload CS by jumping
+newcs:
+       # build page table.  need a mapping for current code at 0x00100000 and a
+       # basic kernbase mapping.  we're using the 32 bit second PT (aka, pg_dir),
+       # which covers 4MB per entry
+       movl    $boot_pdt, %edx
+       # identity map the first jumbo PTE from 0x0 -> 0x0
+       movl    $(PTE_P | PTE_W | PTE_PS), (%edx)
+       # map KERNBASE -> 0 for 200 MB
+       movl    $50, %ecx
+       # init loop, eax at paddr 0, and edx is advanced by KERNBASE mapping slots
+       # (with 4 bytes per PTE).
+       addl    $((KERNBASE >> PTSHIFT) << 2), %edx
+       movl    $(PTE_P | PTE_W | PTE_PS), %eax
+loop:
+       movl    %eax, (%edx)
+       addl    $PTSIZE, %eax
+       addl    $4, %edx
+       decl    %ecx
+       jnz             loop
+       # load cr3 and turn on paging.  note we assume PSE support.  if we didn't
+       # have it, then our jumbo page mappings are going to fail.
+       movl    $boot_pdt, %eax
+       movl    %eax, %cr3
+       movl    %cr4, %eax
+       orl             $(CR4_PSE | CR4_PGE), %eax
+       movl    %eax, %cr4
+       movl    %cr0, %eax
+       orl             $(CR0_PE | CR0_PG | CR0_AM | CR0_WP | CR0_NE | CR0_MP), %eax  
+       andl    $(~(CR0_TS | CR0_EM | CR0_CD | CR0_NW)), %eax  
+       movl    %eax, %cr0
+       # paging is on, and our code is still running at 0x00100000 do some
+       # miscellaneous OS setup.  the coreid stuff is so we can call core_id()
+       # before smp_boot.  this is the only arch-dependent code called before then.
        movl    $0x0, os_coreid_lookup
        movl    $0x0, hw_coreid_lookup
-
        # Clear the frame pointer register (EBP)
        # so that once we get into debugging C code,
        # stack backtraces will be terminated properly.
-       movl    $0x0,%ebp                       # nuke frame pointer
-
-    # Set the stack pointer
+       movl    $0x0,%ebp
        movl    $(bootstacktop),%esp
-
        # Save multiboot info
        push    %ebx
-
-       # now to C code
        movl    $0x1,num_cpus           # init global var, for now
        call    kernel_init
-
        # Should never get here, but in case we do, just spin.
 spin:  jmp     spin
 
+.section .bootdata
+       .p2align        2               # force 4 byte alignment
+mygdt:
+       SEG_NULL                        # null seg
+       SEG(STA_X|STA_R, 0, 0xffffffff) # code seg
+       SEG(STA_W, 0, 0xffffffff)       # data seg
+mygdtdesc:
+       .word   0x17            # sizeof(mygdt) - 1
+       .long   mygdt           # address mygdt
+# boot page directory.  going to use jumbo page entries
+       .align PGSIZE
+boot_pdt:
+       .space  PGSIZE
+
+
+# From here down is linked for KERNBASE
+
 ###################################################################    
 # See <inc/memlayout.h> for a complete description of these two symbols.
 ###################################################################
@@ -89,7 +113,6 @@ spin:        jmp     spin
        .globl  vpd
        .set    vpd, (VPT + SRL(VPT, 10))
 
-
 ###################################################################
 # boot stack
 ###################################################################
@@ -100,15 +123,3 @@ bootstack:
        .globl          bootstacktop   
 bootstacktop:
 
-###################################################################
-# setup the GDT        
-###################################################################
-       .p2align        2               # force 4 byte alignment
-mygdt:
-       SEG_NULL                                # null seg
-       SEG(STA_X|STA_R, -KERNBASE, 0xffffffff) # code seg
-       SEG(STA_W, -KERNBASE, 0xffffffff)       # data seg
-mygdtdesc:
-       .word   0x17                    # sizeof(mygdt) - 1
-       .long   RELOC(mygdt)            # address mygdt
-
index 139c266..d09807c 100644 (file)
@@ -4,13 +4,24 @@
 OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
 OUTPUT_ARCH(i386)
 ENTRY(_start)
+KERNBASE = 0xc0000000;
 
 SECTIONS
 {
-       /* Link the kernel for 0xC01000C0, but load it at 0x001000C0) */
+       /* Entry Linked and loaded at 0x00100000 (includes multiboot) */
+       . = 0x00100000;
 
-       .text 0xC01000C0 : AT(0x001000C0) {
-               *(.multiboot .text .stub .text.* .gnu.linkonce.t.*)
+       .bootstrap : {
+               obj/kern/arch/i686/entry.o (.text .bootdata)
+       }
+
+       /* Link the main kernel for the space after entry + KERNBASE.  We'll still
+        * load it adjacent in physical memory */
+       . += KERNBASE;
+
+       .text : AT(ADDR(.text) - KERNBASE) {
+               *(.text .stub .text.* .gnu.linkonce.t.*)
+               *(EXCLUDE_FILE(*obj/kern/arch/i686/entry.o) .text)
        }
 
        PROVIDE(etext = .);     /* Define the 'etext' symbol to this value */