1
2
3
4
5
6
7
8
9
10
11#include <common.h>
12#include <log.h>
13#include <physmem.h>
14#include <asm/cpu.h>
15#include <linux/compiler.h>
16
17DECLARE_GLOBAL_DATA_PTR;
18
19
20#define LARGE_PAGE_SIZE ((1 << 20) * 2)
21
22
23
24
25
26struct pdpe {
27 uint64_t p:1;
28 uint64_t mbz_0:2;
29 uint64_t pwt:1;
30 uint64_t pcd:1;
31 uint64_t mbz_1:4;
32 uint64_t avl:3;
33 uint64_t base:40;
34 uint64_t mbz_2:12;
35};
36
37typedef struct pdpe pdpt_t[512];
38
39struct pde {
40 uint64_t p:1;
41 uint64_t rw:1;
42 uint64_t us:1;
43 uint64_t pwt:1;
44 uint64_t pcd:1;
45 uint64_t a:1;
46 uint64_t d:1;
47 uint64_t ps:1;
48 uint64_t g:1;
49 uint64_t avl:3;
50 uint64_t pat:1;
51 uint64_t mbz_0:8;
52 uint64_t base:31;
53};
54
55typedef struct pde pdt_t[512];
56
57static pdpt_t pdpt __aligned(4096);
58static pdt_t pdts[4] __aligned(4096);
59
60
61
62
63
64
65
66
67
68static void x86_phys_map_page(uintptr_t virt, phys_addr_t phys, int invlpg)
69{
70
71 uintptr_t pdpt_idx = (virt >> 30) & 0x3;
72 uintptr_t pdt_idx = (virt >> 21) & 0x1ff;
73
74
75 struct pde *pde = &(pdts[pdpt_idx][pdt_idx]);
76
77 memset(pde, 0, sizeof(struct pde));
78 pde->p = 1;
79 pde->rw = 1;
80 pde->us = 1;
81 pde->ps = 1;
82 pde->base = phys >> 21;
83
84 if (invlpg) {
85
86 __asm__ __volatile__(
87 "invlpg %0\n\t"
88 :
89 : "m" (*(uint8_t *)virt)
90 );
91 }
92}
93
94
95static void x86_phys_enter_paging(void)
96{
97 phys_addr_t page_addr;
98 unsigned i;
99
100
101 memset(pdpt, 0, sizeof(pdpt));
102 memset(pdts, 0, sizeof(pdts));
103
104
105 for (i = 0; i < ARRAY_SIZE(pdts); i++) {
106 pdpt[i].p = 1;
107 pdpt[i].base = ((uintptr_t)&pdts[i]) >> 12;
108 }
109
110
111 for (page_addr = 0; page_addr < (1ULL << 32);
112 page_addr += LARGE_PAGE_SIZE) {
113
114 x86_phys_map_page(page_addr, page_addr, 0);
115 }
116
117 cpu_enable_paging_pae((ulong)pdpt);
118}
119
120
121static void x86_phys_exit_paging(void)
122{
123 cpu_disable_paging_pae();
124}
125
126
127
128
129
130
131
132
133
134
135static void x86_phys_memset_page(phys_addr_t map_addr, uintptr_t offset, int c,
136 unsigned size)
137{
138
139
140
141
142 const uintptr_t window = LARGE_PAGE_SIZE;
143
144
145 assert(window + LARGE_PAGE_SIZE <
146 gd->relocaddr - CONFIG_SYS_MALLOC_LEN - CONFIG_SYS_STACK_SIZE);
147
148 x86_phys_map_page(window, map_addr, 1);
149 memset((void *)(window + offset), c, size);
150}
151
152
153
154
155
156phys_addr_t arch_phys_memset(phys_addr_t start, int c, phys_size_t size)
157{
158 const phys_addr_t max_addr = (phys_addr_t)~(uintptr_t)0;
159 const phys_addr_t orig_start = start;
160
161 if (!size)
162 return orig_start;
163
164
165 if (start <= max_addr) {
166 phys_size_t low_size = min(max_addr + 1 - start, size);
167 void *start_ptr = (void *)(uintptr_t)start;
168
169 assert(((phys_addr_t)(uintptr_t)start) == start);
170 memset(start_ptr, c, low_size);
171 start += low_size;
172 size -= low_size;
173 }
174
175
176 if (size) {
177 phys_addr_t map_addr = start & ~(LARGE_PAGE_SIZE - 1);
178 phys_addr_t offset = start - map_addr;
179
180 x86_phys_enter_paging();
181
182
183 if (offset) {
184 phys_addr_t end =
185 min(map_addr + LARGE_PAGE_SIZE, start + size);
186 phys_size_t cur_size = end - start;
187 x86_phys_memset_page(map_addr, offset, c, cur_size);
188 size -= cur_size;
189 map_addr += LARGE_PAGE_SIZE;
190 }
191
192 while (size > LARGE_PAGE_SIZE) {
193 x86_phys_memset_page(map_addr, 0, c, LARGE_PAGE_SIZE);
194 size -= LARGE_PAGE_SIZE;
195 map_addr += LARGE_PAGE_SIZE;
196 }
197
198 if (size)
199 x86_phys_memset_page(map_addr, 0, c, size);
200
201 x86_phys_exit_paging();
202 }
203 return orig_start;
204}
205