x86: Initialize the PAT MSR
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 11 Mar 2016 19:33:14 +0000 (14:33 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 11 Mar 2016 21:40:48 +0000 (16:40 -0500)
This sets up PAT so we can have WB, WC, WT, and UC- memory types via the
__PTE flags.  The PCD and PWT bits don't necessarily disable caching or set
write-through anymore; they are indexes into the PAT table.  (This was
always happening btw, since anything we run on has PAT support).

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/x86/cpuinfo.c
kern/arch/x86/pmap.c

index 1fed072..b857ee2 100644 (file)
@@ -82,6 +82,8 @@ void print_cpuinfo(void)
                panic("MSRs not supported!");
        if (!(edx & 0x00001000))
                panic("MTRRs not supported!");
+       if (!(edx & (1 << 16)))
+               panic("PAT not supported!");
        if (!(edx & 0x00002000))
                panic("Global Pages not supported!");
        if (!(edx & 0x00000200))
index 8ca6fb4..54c58a1 100644 (file)
@@ -40,6 +40,50 @@ bool enable_pse(void)
                return 0;
 }
 
+#define PAT_UC                                 0x00
+#define PAT_WC                                 0x01
+#define PAT_WT                                 0x04
+#define PAT_WP                                 0x05
+#define PAT_WB                                 0x06
+#define PAT_UCm                                        0x07
+
+static inline uint64_t mk_pat(int pat_idx, int type)
+{
+       return (uint64_t)type << (8 * pat_idx);
+}
+
+static void pat_init(void)
+{
+       uint64_t pat = 0;
+
+       /* Default PAT at boot:
+        *   0: WB, 1: WT, 2: UC-, 3: UC, 4: WB, 5: WT, 6: UC-, 7: UC
+        *
+        * We won't use PATs 4-7, but we'll at least enforce that they are set up
+        * the way we think they are.  I'd like to avoid using the PAT flag, since
+        * that is also the PTE_PS (jumbo) flag.  That means we can't use __PTE_PAT
+        * on jumbo pages, and we'd need to be careful whenever using any unorthodox
+        * types.  We're better off just not using it.
+        *
+        * We want WB, WT, WC, and either UC or UC- for our memory types.  (WT is
+        * actually optional at this point).  We'll use UC- instead of UC, since
+        * Linux uses that for their pgprot_noncached.  The UC- type is UC with the
+        * ability to override to WC via MTRR.  We don't use the MTRRs much yet, and
+        * hopefully won't.  The UC- will only matter if we do.
+        *
+        * No one should be using the __PTE_{PAT,PCD,PWT} bits directly, and
+        * everyone should use things like PTE_NOCACHE. */
+       pat |= mk_pat(0, PAT_WB);       /*           |           |           */
+       pat |= mk_pat(1, PAT_WT);       /*           |           | __PTE_PWT */
+       pat |= mk_pat(2, PAT_WC);       /*           | __PTE_PCD |           */
+       pat |= mk_pat(3, PAT_UCm);      /*           | __PTE_PCD | __PTE_PWT */
+       pat |= mk_pat(4, PAT_WB);       /* __PTE_PAT |           |           */
+       pat |= mk_pat(5, PAT_WT);       /* __PTE_PAT |           | __PTE_PWT */
+       pat |= mk_pat(6, PAT_UCm);      /* __PTE_PAT | __PTE_PCD |           */
+       pat |= mk_pat(7, PAT_UC);       /* __PTE_PAT | __PTE_PCD | __PTE_PWT */
+       write_msr(MSR_IA32_CR_PAT, pat);
+}
+
 // 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
@@ -87,6 +131,7 @@ void setup_default_mtrrs(barrier_t* smp_barrier)
        // keeps default type to WB (06), turns MTRRs on, and turns off fixed ranges
        write_msr(IA32_MTRR_DEF_TYPE, 0x00000806);
 #endif 
+       pat_init();
        // reflush caches and TLB
        cache_flush();
        tlb_flush_global();