- Fix bug with > 4GB of memory where PAE was left enabled.
[coreboot.git] / src / cpu / x86 / pae / pgtbl.c
1 #include <console/console.h>
2 #include <cpu/cpu.h>
3 #include <cpu/x86/pae.h>
4 #include <string.h>
5
6 static void paging_off(void)
7 {
8         __asm__ __volatile__ (
9                 /* Disable paging */
10                 "movl   %%cr0, %%eax\n\t"
11                 "andl   $0x7FFFFFFF, %%eax\n\t"
12                 "movl   %%eax, %%cr0\n\t"
13                 /* Disable pae */
14                 "movl   %%cr4, %%eax\n\t"
15                 "andl   $0xFFFFFFDF, %%eax\n\t"
16                 "movl   %%eax, %%cr4\n\t"
17                 :
18                 :
19                 : "eax"
20                 );
21 }
22
23 static void paging_on(void *pdp)
24 {
25         __asm__ __volatile__(
26                 /* Load the page table address */
27                 "movl   %0, %%cr3\n\t"
28                 /* Enable pae */
29                 "movl   %%cr4, %%eax\n\t"
30                 "orl    $0x00000020, %%eax\n\t"
31                 "movl   %%eax, %%cr4\n\t"
32                 /* Enable paging */
33                 "movl   %%cr0, %%eax\n\t"
34                 "orl    $0x80000000, %%eax\n\t"
35                 "movl   %%eax, %%cr0\n\t"
36                 :
37                 : "r" (pdp)
38                 : "eax"
39                 );
40 }
41
42 void *map_2M_page(unsigned long page) 
43 {
44         struct pde {
45                 uint32_t addr_lo;
46                 uint32_t addr_hi;
47         } __attribute__ ((packed));
48         struct pg_table {
49                 struct pde pd[2048];
50                 struct pde pdp[512];
51         } __attribute__ ((packed));
52         static struct pg_table pgtbl[CONFIG_MAX_CPUS] __attribute__ ((aligned(4096)));
53         static unsigned long mapped_window[CONFIG_MAX_CPUS];
54         unsigned long index;
55         unsigned long window;
56         void *result;
57         int i;
58         index = cpu_index();
59         if ((index < 0) || (index >= CONFIG_MAX_CPUS)) {
60                 return MAPPING_ERROR;
61         }
62         window = page >> 10;
63         if (window != mapped_window[index]) {
64                 paging_off();
65                 if (window > 1) {
66                         struct pde *pd, *pdp;
67                         /* Point the page directory pointers at the page directories */
68                         memset(&pgtbl[index].pdp, 0, sizeof(pgtbl[index].pdp));
69                         pd = pgtbl[index].pd;
70                         pdp = pgtbl[index].pdp;
71                         pdp[0].addr_lo = ((uint32_t)&pd[512*0])|1;
72                         pdp[1].addr_lo = ((uint32_t)&pd[512*1])|1;
73                         pdp[2].addr_lo = ((uint32_t)&pd[512*2])|1;
74                         pdp[3].addr_lo = ((uint32_t)&pd[512*3])|1;
75                         /* The first half of the page table is identity mapped */
76                         for(i = 0; i < 1024; i++) {
77                                 pd[i].addr_lo = ((i & 0x3ff) << 21)| 0xE3;
78                                 pd[i].addr_hi = 0;
79                         }
80                         /* The second half of the page table holds the mapped page */
81                         for(i = 1024; i < 2048; i++) {
82                                 pd[i].addr_lo = ((window & 1) << 31) | ((i & 0x3ff) << 21) | 0xE3;
83                                 pd[i].addr_hi = (window >> 1);
84                         }
85                         paging_on(pdp);
86                 }
87                 mapped_window[index] = window;
88         }
89         if (window == 0) {
90                 result = (void *)(page << 21);
91         } else {
92                 result = (void *)(0x80000000 | ((page & 0x3ff) << 21));
93         }
94         return result;
95 }