strace: Qstrace controls whether tracing is on
[akaros.git] / kern / arch / x86 / pmap.c
1 /* Copyright (c) 2009 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Physical memory managment, common to 32 and 64 bit */
6
7 #include <arch/x86.h>
8 #include <arch/arch.h>
9 #include <arch/mmu.h>
10 #include <arch/apic.h>
11
12 #include <error.h>
13 #include <sys/queue.h>
14
15 #include <atomic.h>
16 #include <string.h>
17 #include <assert.h>
18 #include <pmap.h>
19 #include <kclock.h>
20 #include <env.h>
21 #include <stdio.h>
22 #include <kmalloc.h>
23 #include <page_alloc.h>
24
25 static int nvram_read(int r)
26 {
27         return mc146818_read(r) | (mc146818_read(r + 1) << 8);
28 }
29
30 bool enable_pse(void)
31 {
32         uint32_t edx, cr4;
33         cpuid(0x1, 0x0, 0, 0, 0, &edx);
34         if (edx & CPUID_PSE_SUPPORT) {
35                 cr4 = rcr4();
36                 cr4 |= CR4_PSE;
37                 lcr4(cr4);
38                 return 1;
39         } else
40                 return 0;
41 }
42
43 #define PAT_UC                                  0x00
44 #define PAT_WC                                  0x01
45 #define PAT_WT                                  0x04
46 #define PAT_WP                                  0x05
47 #define PAT_WB                                  0x06
48 #define PAT_UCm                                 0x07
49
50 static inline uint64_t mk_pat(int pat_idx, int type)
51 {
52         return (uint64_t)type << (8 * pat_idx);
53 }
54
55 static void pat_init(void)
56 {
57         uint64_t pat = 0;
58
59         /* Default PAT at boot:
60          *   0: WB, 1: WT, 2: UC-, 3: UC, 4: WB, 5: WT, 6: UC-, 7: UC
61          *
62          * We won't use PATs 4-7, but we'll at least enforce that they are set up
63          * the way we think they are.  I'd like to avoid using the PAT flag, since
64          * that is also the PTE_PS (jumbo) flag.  That means we can't use __PTE_PAT
65          * on jumbo pages, and we'd need to be careful whenever using any unorthodox
66          * types.  We're better off just not using it.
67          *
68          * We want WB, WT, WC, and either UC or UC- for our memory types.  (WT is
69          * actually optional at this point).  We'll use UC- instead of UC, since
70          * Linux uses that for their pgprot_noncached.  The UC- type is UC with the
71          * ability to override to WC via MTRR.  We don't use the MTRRs much yet, and
72          * hopefully won't.  The UC- will only matter if we do.
73          *
74          * No one should be using the __PTE_{PAT,PCD,PWT} bits directly, and
75          * everyone should use things like PTE_NOCACHE. */
76         pat |= mk_pat(0, PAT_WB);       /*           |           |           */
77         pat |= mk_pat(1, PAT_WT);       /*           |           | __PTE_PWT */
78         pat |= mk_pat(2, PAT_WC);       /*           | __PTE_PCD |           */
79         pat |= mk_pat(3, PAT_UCm);      /*           | __PTE_PCD | __PTE_PWT */
80         pat |= mk_pat(4, PAT_WB);       /* __PTE_PAT |           |           */
81         pat |= mk_pat(5, PAT_WT);       /* __PTE_PAT |           | __PTE_PWT */
82         pat |= mk_pat(6, PAT_UCm);      /* __PTE_PAT | __PTE_PCD |           */
83         pat |= mk_pat(7, PAT_UC);       /* __PTE_PAT | __PTE_PCD | __PTE_PWT */
84         write_msr(MSR_IA32_CR_PAT, pat);
85 }
86
87 // could consider having an API to allow these to dynamically change
88 // MTRRs are for physical, static ranges.  PAT are linear, more granular, and
89 // more dynamic
90 void setup_default_mtrrs(barrier_t* smp_barrier)
91 {
92         // disable interrupts
93         int8_t state = 0;
94         disable_irqsave(&state);
95         // barrier - if we're meant to do this for all cores, we'll be
96         // passed a pointer to an initialized barrier
97         if (smp_barrier)
98                 waiton_barrier(smp_barrier);
99
100         // disable caching      cr0: set CD and clear NW
101         lcr0((rcr0() | CR0_CD) & ~CR0_NW);
102         // flush caches
103         cache_flush();
104         // flush tlb
105         tlb_flush_global();
106         // disable MTRRs, and sets default type to WB (06)
107 #ifndef CONFIG_NOMTRRS
108         write_msr(IA32_MTRR_DEF_TYPE, 0x00000006);
109
110         // Now we can actually safely adjust the MTRRs
111         // MTRR for IO Holes (note these are 64 bit values we are writing)
112         // 0x000a0000 - 0x000c0000 : VGA - WC 0x01
113         write_msr(IA32_MTRR_PHYSBASE0, PTE_ADDR(VGAPHYSMEM) | 0x01);
114         // if we need to have a full 64bit val, use the UINT64 macro
115         write_msr(IA32_MTRR_PHYSMASK0, 0x0000000ffffe0800);
116         // 0x000c0000 - 0x00100000 : IO devices (and ROM BIOS) - UC 0x00
117         write_msr(IA32_MTRR_PHYSBASE1, PTE_ADDR(DEVPHYSMEM) | 0x00);
118         write_msr(IA32_MTRR_PHYSMASK1, 0x0000000ffffc0800);
119         // APIC/IOAPIC holes
120         /* Going to skip them, since we set their mode using PAT when we
121          * map them in
122          */
123         // make sure all other MTRR ranges are disabled (should be unnecessary)
124         write_msr(IA32_MTRR_PHYSMASK2, 0);
125         write_msr(IA32_MTRR_PHYSMASK3, 0);
126         write_msr(IA32_MTRR_PHYSMASK4, 0);
127         write_msr(IA32_MTRR_PHYSMASK5, 0);
128         write_msr(IA32_MTRR_PHYSMASK6, 0);
129         write_msr(IA32_MTRR_PHYSMASK7, 0);
130
131         // keeps default type to WB (06), turns MTRRs on, and turns off fixed ranges
132         write_msr(IA32_MTRR_DEF_TYPE, 0x00000806);
133 #endif
134         pat_init();
135         // reflush caches and TLB
136         cache_flush();
137         tlb_flush_global();
138         // turn on caching
139         lcr0(rcr0() & ~(CR0_CD | CR0_NW));
140         // barrier
141         if (smp_barrier)
142                 waiton_barrier(smp_barrier);
143         // enable interrupts
144         enable_irqsave(&state);
145 }
146
147 void invlpg(void *addr)
148 {
149         asm volatile("invlpg (%0)" : : "r" (addr) : "memory");
150         if (per_cpu_info[core_id()].vmx_enabled)
151                 ept_inval_addr((uintptr_t)addr);
152 }
153
154 void tlbflush(void)
155 {
156         unsigned long cr3;
157         asm volatile("mov %%cr3,%0" : "=r" (cr3));
158         asm volatile("mov %0,%%cr3" : : "r" (cr3));
159         if (per_cpu_info[core_id()].vmx_enabled)
160                 ept_inval_context();
161 }
162
163 /* Flushes a TLB, including global pages.  We should always have the CR4_PGE
164  * flag set, but just in case, we'll check.  Toggling this bit flushes the TLB.
165  */
166 void tlb_flush_global(void)
167 {
168         uint32_t cr4 = rcr4();
169         if (cr4 & CR4_PGE) {
170                 lcr4(cr4 & ~CR4_PGE);
171                 lcr4(cr4);
172         } else {
173                 lcr3(rcr3());
174         }
175         if (per_cpu_info[core_id_early()].vmx_enabled)
176                 ept_inval_global();
177 }