95c2ad726cb076e2f894250e43de1eff7f232abc
[coreboot.git] / src / cpu / x86 / pae / pgtbl.c
1 /*
2         2005.12 yhlu add coreboot_ram cross the vga font buffer handling
3 */
4
5 #include <console/console.h>
6 #include <cpu/cpu.h>
7 #include <cpu/x86/pae.h>
8 #include <string.h>
9
10 static void paging_off(void)
11 {
12         __asm__ __volatile__ (
13                 /* Disable paging */
14                 "movl   %%cr0, %%eax\n\t"
15                 "andl   $0x7FFFFFFF, %%eax\n\t"
16                 "movl   %%eax, %%cr0\n\t"
17                 /* Disable pae */
18                 "movl   %%cr4, %%eax\n\t"
19                 "andl   $0xFFFFFFDF, %%eax\n\t"
20                 "movl   %%eax, %%cr4\n\t"
21                 :
22                 :
23                 : "eax"
24                 );
25 }
26
27 static void paging_on(void *pdp)
28 {
29         __asm__ __volatile__(
30                 /* Load the page table address */
31                 "movl   %0, %%cr3\n\t"
32                 /* Enable pae */
33                 "movl   %%cr4, %%eax\n\t"
34                 "orl    $0x00000020, %%eax\n\t"
35                 "movl   %%eax, %%cr4\n\t"
36                 /* Enable paging */
37                 "movl   %%cr0, %%eax\n\t"
38                 "orl    $0x80000000, %%eax\n\t"
39                 "movl   %%eax, %%cr0\n\t"
40                 :
41                 : "r" (pdp)
42                 : "eax"
43                 );
44 }
45
46 void *map_2M_page(unsigned long page) 
47 {
48         struct pde {
49                 uint32_t addr_lo;
50                 uint32_t addr_hi;
51         } __attribute__ ((packed));
52         struct pg_table {
53                 struct pde pd[2048];
54                 struct pde pdp[512];
55         } __attribute__ ((packed));
56
57 #if (CONFIG_LB_MEM_TOPK>1024) && (CONFIG_RAMBASE<0x100000) && ((CONFIG_CONSOLE_VGA==1) || (CONFIG_PCI_ROM_RUN == 1))
58         /*
59          pgtbl is too big, so use last one 1M before CONFIG_LB_MEM_TOP, otherwise for 8 way dual core with vga support will push stack and heap cross 0xa0000, 
60          and that region need to be used as vga font buffer. Please make sure set CONFIG_LB_MEM_TOPK=2048 in MB Config
61         */
62         struct pg_table *pgtbl = (struct pg_table*)0x100000; //1M
63
64         unsigned x_end = 0x100000 + sizeof(struct pg_table) * CONFIG_MAX_CPUS;
65 #if (0x100000+20480*CONFIG_MAX_CPUS) > (CONFIG_LB_MEM_TOPK<<10)
66                 #warning "We may need to increase CONFIG_LB_MEM_TOPK, it need to be more than (0x100000+20480*CONFIG_MAX_CPUS)\n"
67 #endif
68         if(x_end > (CONFIG_LB_MEM_TOPK<<10)) {
69                         printk_debug("map_2M_page: Please increase the CONFIG_LB_MEM_TOPK more than %dK\n", x_end>>10);
70                         die("Can not go on");
71         }
72 #else
73         static struct pg_table pgtbl[CONFIG_MAX_CPUS] __attribute__ ((aligned(4096)));
74 #endif
75         static unsigned long mapped_window[CONFIG_MAX_CPUS];
76         unsigned long index;
77         unsigned long window;
78         void *result;
79         int i;
80         index = cpu_index();
81         if ((index < 0) || (index >= CONFIG_MAX_CPUS)) {
82                 return MAPPING_ERROR;
83         }
84         window = page >> 10;
85         if (window != mapped_window[index]) {
86                 paging_off();
87                 if (window > 1) {
88                         struct pde *pd, *pdp;
89                         /* Point the page directory pointers at the page directories */
90                         memset(&pgtbl[index].pdp, 0, sizeof(pgtbl[index].pdp));
91                         pd = pgtbl[index].pd;
92                         pdp = pgtbl[index].pdp;
93                         pdp[0].addr_lo = ((uint32_t)&pd[512*0])|1;
94                         pdp[1].addr_lo = ((uint32_t)&pd[512*1])|1;
95                         pdp[2].addr_lo = ((uint32_t)&pd[512*2])|1;
96                         pdp[3].addr_lo = ((uint32_t)&pd[512*3])|1;
97                         /* The first half of the page table is identity mapped */
98                         for(i = 0; i < 1024; i++) {
99                                 pd[i].addr_lo = ((i & 0x3ff) << 21)| 0xE3;
100                                 pd[i].addr_hi = 0;
101                         }
102                         /* The second half of the page table holds the mapped page */
103                         for(i = 1024; i < 2048; i++) {
104                                 pd[i].addr_lo = ((window & 1) << 31) | ((i & 0x3ff) << 21) | 0xE3;
105                                 pd[i].addr_hi = (window >> 1);
106                         }
107                         paging_on(pdp);
108                 }
109                 mapped_window[index] = window;
110         }
111         if (window == 0) {
112                 result = (void *)(page << 21);
113         } else {
114                 result = (void *)(0x80000000 | ((page & 0x3ff) << 21));
115         }
116         return result;
117 }