Basic MTRRs
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 13 Apr 2009 21:30:13 +0000 (14:30 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 13 Apr 2009 21:30:13 +0000 (14:30 -0700)
Set up for Core0 to enable its MTRRs.  Will later do all cores at once
in SMP boot.

inc/memlayout.h
inc/mmu.h
inc/x86.h
kern/init.c
kern/pmap.c
kern/pmap.h

index ffd9e36..a2248b9 100644 (file)
@@ -85,6 +85,9 @@
 // IOPHYSMEM can be addressed at KERNBASE + IOPHYSMEM.  The hole ends
 // at physical address EXTPHYSMEM.
 #define IOPHYSMEM      0x0A0000
+#define VGAPHYSMEM     0x0A0000
+#define DEVPHYSMEM     0x0C0000
+#define BIOSPHYSMEM    0x0F0000
 #define EXTPHYSMEM     0x100000
 
 // Virtual page table.  Entry PDX(VPT) in the PD contains a pointer to
index 0ce68cf..adf8122 100644 (file)
--- a/inc/mmu.h
+++ b/inc/mmu.h
@@ -68,8 +68,9 @@
 #define PTE_PCD                0x010   // Cache-Disable
 #define PTE_A          0x020   // Accessed
 #define PTE_D          0x040   // Dirty
-#define PTE_PS         0x080   // Page Size
-#define PTE_MBZ                0x180   // Bits must be zero
+#define PTE_PS         0x080   // Page Size (only applies to PDEs)
+#define PTE_PAT                0x080   // PAT (only applies to second layer PTEs)
+#define PTE_G          0x100   // Global Page
 
 // The PTE_AVAIL bits aren't used by the kernel or interpreted by the
 // hardware, so user processes are allowed to set them arbitrarily.
 #define CR0_EM         0x00000004      // Emulation
 #define CR0_TS         0x00000008      // Task Switched
 #define CR0_ET         0x00000010      // Extension Type
-#define CR0_NE         0x00000020      // Numeric Errror
+#define CR0_NE         0x00000020      // Numeric Error
 #define CR0_WP         0x00010000      // Write Protect
 #define CR0_AM         0x00040000      // Alignment Mask
-#define CR0_NW         0x20000000      // Not Writethrough
+#define CR0_NW         0x20000000      // Not Writethrough - more tricky than it sounds
 #define CR0_CD         0x40000000      // Cache Disable
 #define CR0_PG         0x80000000      // Paging
 
-#define CR4_PCE                0x00000100      // Performance counter enable
-#define CR4_MCE                0x00000040      // Machine Check Enable
-#define CR4_PSE                0x00000010      // Page Size Extensions
-#define CR4_DE         0x00000008      // Debugging Extensions
-#define CR4_TSD                0x00000004      // Time Stamp Disable
-#define CR4_PVI                0x00000002      // Protected-Mode Virtual Interrupts
+// These two relate to the cacheability (L1, etc) of the page directory
+#define CR3_PWT                0x00000008      // Page directory caching write through
+#define CR3_PCD                0x00000010      // Page directory caching disabled
+
 #define CR4_VME                0x00000001      // V86 Mode Extensions
+#define CR4_PVI                0x00000002      // Protected-Mode Virtual Interrupts
+#define CR4_TSD                0x00000004      // Time Stamp Disable
+#define CR4_DE         0x00000008      // Debugging Extensions
+#define CR4_PSE                0x00000010      // Page Size Extensions
+#define CR4_PAE                0x00000020      // Physical Address Extensions
+#define CR4_MCE                0x00000040      // Machine Check Enable
+#define CR4_PGE                0x00000080      // Global Pages Enabled
+#define CR4_PCE                0x00000100      // Performance counter enable
+#define CR4_OSFXSR     0x00000200      // OS support for FXSAVE/FXRSTOR
+#define CR4_OSXMME     0x00000400      // OS support for unmasked SIMD FP exceptions
+#define CR4_VMXE       0x00002000      // VMX enable
+#define CR4_SMXE       0x00004000      // SMX enable
+#define CR4_OSXSAVE    0x00040000      // XSAVE and processor extended states-enabled
 
 // Eflags register
 #define FL_CF          0x00000001      // Carry Flag
index 36cc6b0..90f4cd3 100644 (file)
--- a/inc/x86.h
+++ b/inc/x86.h
@@ -7,6 +7,22 @@
 /* Model Specific Registers */
 #define IA32_APIC_BASE                         0x1b
 #define IA32_MTRR_DEF_TYPE                     0x2ff
+#define IA32_MTRR_PHYSBASE0                    0x200
+#define IA32_MTRR_PHYSMASK0                    0x201
+#define IA32_MTRR_PHYSBASE1                    0x202
+#define IA32_MTRR_PHYSMASK1                    0x203
+#define IA32_MTRR_PHYSBASE2                    0x204
+#define IA32_MTRR_PHYSMASK2                    0x205
+#define IA32_MTRR_PHYSBASE3                    0x206
+#define IA32_MTRR_PHYSMASK3                    0x207
+#define IA32_MTRR_PHYSBASE4                    0x208
+#define IA32_MTRR_PHYSMASK4                    0x209
+#define IA32_MTRR_PHYSBASE5                    0x20a
+#define IA32_MTRR_PHYSMASK5                    0x20b
+#define IA32_MTRR_PHYSBASE6                    0x20c
+#define IA32_MTRR_PHYSMASK6                    0x20d
+#define IA32_MTRR_PHYSBASE7                    0x20e
+#define IA32_MTRR_PHYSMASK7                    0x20f
 
 #define MSR_APIC_ENABLE                                0x00000800
 #define MSR_APIC_BASE_ADDRESS          0x0000000FFFFFF000
@@ -57,6 +73,8 @@ static __inline void disable_irq(void) __attribute__((always_inline));
 static __inline bool enable_irqsave(void) __attribute__((always_inline));
 static __inline void disable_irqsave(bool state) __attribute__((always_inline));
 static __inline void cpu_relax(void) __attribute__((always_inline));
+static __inline void wbinvd(void) __attribute__((always_inline));
+static __inline void clflush(uintptr_t* addr) __attribute__((always_inline));
 
 static __inline void
 breakpoint(void)
@@ -364,4 +382,16 @@ cpu_relax(void)
 {
        asm volatile("pause");
 }
+
+static __inline void
+wbinvd(void) __attribute__((always_inline))
+{
+       asm volatile("wbinvd");
+}
+
+static __inline void
+clflush(uintptr_t* addr) __attribute__((always_inline))
+{
+       asm volatile("clflush %0" : : "m"(*addr));
+}
 #endif /* !JOS_INC_X86_H */
index e563a43..50ff35d 100644 (file)
@@ -51,8 +51,8 @@ void kernel_init(multiboot_info_t *mboot_info)
        // this returns when all other cores are done and ready to receive IPIs
        smp_boot();
 
-       test_barrier();
        panic("Don't Panic");
+       test_barrier();
        test_print_info();
        test_ipi_sending();
 
@@ -141,17 +141,22 @@ static void print_cpuinfo(void) {
        // eventually can fill this out with SDM Vol3B App B info, or 
        // better yet with stepping info.  or cpuid 8000_000{2,3,4}
        switch ( family << 8 | model ) {
+               case(0x061a):
+                       cprintf("Processor: Core i7\n");
+                       break;
                case(0x060f):
                        cprintf("Processor: Core 2 Duo or Similar\n");
                        break;
                default:
                        cprintf("Unknown or non-Intel CPU\n");
        }
-       if (!(edx & 0x00000010))
+       if (!(edx & 0x00000020))
                panic("MSRs not supported!");
        if (!(edx & 0x00001000))
                panic("MTRRs not supported!");
-       if (!(edx & 0x00000100))
+       if (!(edx & 0x00002000))
+               panic("Global Pages not supported!");
+       if (!(edx & 0x00000200))
                panic("Local APIC Not Detected!");
        if (ecx & 0x00200000)
                cprintf("x2APIC Detected\n");
index 7c9f977..0638618 100644 (file)
@@ -239,6 +239,56 @@ boot_map_segment(pde_t *pgdir, uintptr_t la, size_t size, physaddr_t pa, int per
        }
 }
 
+// could consider having an API to allow these to dynamically change
+// MTRRs are for physical, static ranges.  PAT are linear, more granular, and 
+// more dynamic
+void setup_default_mtrrs(void)
+{
+       // disable interrupts
+       //uint32_t state = enable_irqsave();    
+       // barrier
+       // disable caching      cr0: set CD and clear NW
+       lcr0((rcr0() | CR0_CD) & ~CR0_NW);
+       // flush caches
+       cache_flush();
+       // flush tlb
+       tlb_flush_global();
+       // disable MTRRs, and sets default type to WB (06)
+       write_msr(IA32_MTRR_DEF_TYPE, 0x00000006);
+
+       // Now we can actually safely adjust the MTRRs
+       // MTRR for IO Holes (note these are 64 bit values we are writing)
+       // 0x000a0000 - 0x000c0000 : VGA - WC 0x01
+       write_msr(IA32_MTRR_PHYSBASE0, PTE_ADDR(VGAPHYSMEM) | 0x01);
+       write_msr(IA32_MTRR_PHYSMASK0, 0x0000000ffffe0800);
+       // 0x000c0000 - 0x00100000 : IO devices (and ROM BIOS) - UC 0x00
+       write_msr(IA32_MTRR_PHYSBASE1, PTE_ADDR(DEVPHYSMEM) | 0x00);
+       write_msr(IA32_MTRR_PHYSMASK1, 0x0000000ffffc0800);
+       // APIC/IOAPIC holes
+       /* Going to skip them, since we set their mode using PAT when we 
+        * map them in 
+        */
+       // make sure all other MTRR ranges are disabled (should be unnecessary)
+       write_msr(IA32_MTRR_PHYSMASK2, 0);
+       write_msr(IA32_MTRR_PHYSMASK3, 0);
+       write_msr(IA32_MTRR_PHYSMASK4, 0);
+       write_msr(IA32_MTRR_PHYSMASK5, 0);
+       write_msr(IA32_MTRR_PHYSMASK6, 0);
+       write_msr(IA32_MTRR_PHYSMASK7, 0);
+
+       // keeps default type to WB (06), turns MTRRs on, and turns off fixed ranges
+       write_msr(IA32_MTRR_DEF_TYPE, 0x00000806);
+       // reflush caches and TLB
+       cache_flush();
+       tlb_flush_global();
+       // turn on caching
+       lcr0(rcr0() & ~(CR0_CD | CR0_NW));
+       // barrier
+       // enable interrupts
+
+}
+
+
 // Set up a two-level page table:
 //    boot_pgdir is its linear (virtual) address of the root
 //    boot_cr3 is the physical adresss of the root
@@ -259,17 +309,13 @@ i386_vm_init(void)
        size_t n;
        bool pse;
 
-       // set up MTRRs
-       // default type is normally 06 (WB), but once we have regions
-       // set up, we can set it to 00 (UC)
-       //write_msr(IA32_MTRR_DEF_TYPE, 0x00000c00);
-       write_msr(IA32_MTRR_DEF_TYPE, 0x00000c06);
-       // might need to set up MTRRS for the IO holes
-
        pse = enable_pse();
        if (pse)
                cprintf("PSE capability detected.\n");
 
+       // set up mtrr's for core0.  other cores will do the same later
+       setup_default_mtrrs();
+
        /*
         * PSE status: 
         * - can walk and set up boot_map_segments with jumbos but can't
@@ -338,9 +384,12 @@ i386_vm_init(void)
        // but this only maps what is available, and saves memory.  every 4MB of
        // mapped memory requires a 2nd level page: 2^10 entries, each covering 2^12
        // need to modify tests below to account for this
-       if (pse)
-               boot_map_segment(pgdir, KERNBASE, maxpa, 0, PTE_W | PTE_PS);
-       else
+       if (pse) {
+               // map the first 4MB as regular entries, to support different MTRRs
+               boot_map_segment(pgdir, KERNBASE, JPGSIZE, 0, PTE_W);
+               boot_map_segment(pgdir, KERNBASE + JPGSIZE, maxpa - JPGSIZE, JPGSIZE,
+                                PTE_W | PTE_PS);
+       } else
                boot_map_segment(pgdir, KERNBASE, maxpa, 0, PTE_W );
 
        // APIC mapping, in lieu of MTRRs for now.  TODO: remove when MTRRs are up
@@ -840,6 +889,7 @@ page_remove(pde_t *pgdir, void *va)
 // Invalidate a TLB entry, but only if the page tables being
 // edited are the ones currently in use by the processor.
 //
+// Need to sort this for cross core lovin'  TODO
 void
 tlb_invalidate(pde_t *pgdir, void *va)
 {
@@ -848,6 +898,19 @@ tlb_invalidate(pde_t *pgdir, void *va)
        invlpg(va);
 }
 
+/* Flushes a TLB, including global pages.  We should always have the CR4_PGE
+ * flag set, but just in case, we'll check.  Toggling this bit flushes the TLB.
+ */
+void tlb_flush_global(void)
+{
+       uint32_t cr4 = rcr4();
+       if (cr4 & CR4_PGE) {
+               lcr4(cr4 & ~CR4_PGE);
+               lcr4(cr4);
+       } else 
+               lcr3(rcr3());
+}
+
 static void *DANGEROUS user_mem_check_addr;
 
 //
index fa741bd..faab71b 100644 (file)
@@ -62,6 +62,7 @@ struct Page *page_lookup(pde_t *pgdir, void *va, pte_t **pte_store);
 void   page_decref(struct Page *pp);
 
 void   tlb_invalidate(pde_t *pgdir, void *va);
+void tlb_flush_global(void);
 
 void *COUNT(len)
 user_mem_check(struct Env *env, const void *DANGEROUS va, size_t len, int perm);
@@ -69,6 +70,16 @@ user_mem_check(struct Env *env, const void *DANGEROUS va, size_t len, int perm);
 void *COUNT(len)
 user_mem_assert(struct Env *env, const void *DANGEROUS va, size_t len, int perm);
 
+static inline void cache_flush(void)
+{
+       wbinvd();
+}
+
+static inline void cacheline_flush(void* addr)
+{
+       clflush((uintptr_t*)addr);
+}
+
 static inline ppn_t
 page2ppn(struct Page *pp)
 {