make the linux-ppc packags be in synch with other platforms
[tangerine.git] / arch / x86_64-pc / kernel / mmu.c
blobd87f8b0629dafb9a9899a52095ff1564a7818dfe
1 #include <asm/cpu.h>
3 #include "kernel_intern.h"
5 /*
6 The MMU pages and directories. They are stored at fixed location and may be either reused in the
7 64-bit kernel, or replaced by it. Four PDE directories (PDE2M structures) are enough to map whole
8 4GB address space.
9 */
10 static struct PML4E PML4[512] __attribute__((used,aligned(4096)));
11 static struct PDPE PDP[512] __attribute__((used,aligned(4096)));
12 static struct PDE2M PDE[4][512] __attribute__((used,aligned(4096)));
14 extern IPTR _Kern_APICTrampolineBase;
16 void core_SetupMMU()
18 int i;
19 struct PDE2M *pdes[] = { &PDE[0], &PDE[1], &PDE[2], &PDE[3] };
21 rkprintf("[Kernel] Re-creating the MMU pages for first 4GB area\n");
23 /* PML4 Entry - we need only the first out of 16 entries */
24 PML4[0].p = 1; /* present */
25 PML4[0].rw = 1; /* read/write */
26 PML4[0].us = 1; /* accessible for user */
27 PML4[0].pwt= 0; /* write-through cache */
28 PML4[0].pcd= 0; /* cache enabled */
29 PML4[0].a = 0; /* not yet accessed */
30 PML4[0].mbz= 0; /* must be zero */
31 PML4[0].base_low = (unsigned int)PDP >> 12;
32 PML4[0].avl= 0;
33 PML4[0].nx = 0;
34 PML4[0].avail = 0;
35 PML4[0].base_high = 0;
38 PDP Entries. There are four of them used in order to define 2048 pages of 2MB each.
40 for (i=0; i < 4; i++)
42 int j;
44 /* Set the PDP entry up and point to the PDE table */
45 PDP[i].p = 1;
46 PDP[i].rw = 1;
47 PDP[i].us = 1;
48 PDP[i].pwt= 0;
49 PDP[i].pcd= 0;
50 PDP[i].a = 0;
51 PDP[i].mbz= 0;
52 PDP[i].base_low = (unsigned int)pdes[i] >> 12;
54 PDP[i].nx = 0;
55 PDP[i].avail = 0;
56 PDP[i].base_high = 0;
58 for (j=0; j < 512; j++)
60 /* Set PDE entries - use 2MB memory pages, with full supervisor and user access */
62 struct PDE2M *PDE = pdes[i];
63 PDE[j].p = 1;
64 PDE[j].rw = 1;
65 PDE[j].us = 1;
66 PDE[j].pwt= 0; // 1
67 PDE[j].pcd= 0; // 1
68 PDE[j].a = 0;
69 PDE[j].d = 0;
70 PDE[j].g = 0;
71 PDE[j].pat= 0;
72 PDE[j].ps = 1;
73 PDE[j].base_low = ((i << 30) + (j << 21)) >> 13;
75 PDE[j].avail = 0;
76 PDE[j].nx = 0;
77 PDE[j].base_high = 0;
81 wrcr(cr3, &PML4);
83 /* HACK! Store the PML4 address in smp trampoline area */
84 *(ULONG *)(_Kern_APICTrampolineBase + 0x0014) = (ULONG)&PML4;
86 rkprintf("[Kernel] PML4 @ %012p\n", &PML4);
89 static struct PTE Pages4K[32][512] __attribute__((used,aligned(4096)));
90 static int used_page;
92 void core_ProtPage(intptr_t addr, char p, char rw, char us)
94 struct PML4E *pml4 = rdcr(cr3);
95 struct PDPE *pdpe = pml4[(addr >> 39) & 0x1ff].base_low << 12;
96 struct PDE4K *pde = pdpe[(addr >> 30) & 0x1ff].base_low << 12;
98 rkprintf("[Kernel] Marking page %012p as read-only\n",addr);
100 if (pde[(addr >> 21) & 0x1ff].ps)
102 struct PTE *pte = Pages4K[used_page++];
103 struct PDE2M *pde2 = (struct PDE2M *)pde;
105 /* work on local copy of the affected PDE */
106 struct PDE4K tmp_pde = pde[(addr >> 21) & 0x1ff];
108 intptr_t base = pde2[(addr >> 21) & 0x1ff].base_low << 13;
109 int i;
111 rkprintf("[Kernel] The page for address %012p was a big one. Splitting it into 4K pages\n",
112 addr);
113 rkprintf("[Kernel] Base=%012p, pte=%012p\n", base, pte);
115 for (i = 0; i < 512; i++)
117 pte[i].p = 1;
118 pte[i].rw = pde2[(addr >> 21) & 0x1ff].rw;
119 pte[i].us = pde2[(addr >> 21) & 0x1ff].us;
120 pte[i].pwt = pde2[(addr >> 21) & 0x1ff].pwt;
121 pte[i].pcd = pde2[(addr >> 21) & 0x1ff].pcd;
122 pte[i].base_low = base >> 12;
123 base += 4096;
126 tmp_pde.ps = 0;
127 tmp_pde.base_low = ((intptr_t)pte) >> 12;
129 pde[(addr >> 21) & 0x1ff] = tmp_pde;
132 struct PTE *pte = pde[(addr >> 21) & 0x1ff].base_low << 12;
133 pte[(addr >> 12) & 0x1ff].rw = rw ? 1:0;
134 pte[(addr >> 12) & 0x1ff].us = us ? 1:0;
135 pte[(addr >> 12) & 0x1ff].p = p ? 1:0;
136 asm volatile ("invlpg (%0)"::"r"(addr));
139 void core_ProtKernelArea(intptr_t addr, intptr_t length, char p, char rw, char us)
141 rkprintf("[Kernel] Protecting area %012p-%012p\n", addr, addr + length - 1);
143 while (length > 0)
145 core_ProtPage(addr, p, rw, us);
146 addr += 4096;
147 length -= 4096;