mm.c revision 1.20.2.2 1 1.20.2.2 jdolecek /* $NetBSD: mm.c,v 1.20.2.2 2017/12/03 11:35:48 jdolecek Exp $ */
2 1.20.2.2 jdolecek
3 1.20.2.2 jdolecek /*
4 1.20.2.2 jdolecek * Copyright (c) 2017 The NetBSD Foundation, Inc. All rights reserved.
5 1.20.2.2 jdolecek *
6 1.20.2.2 jdolecek * This code is derived from software contributed to The NetBSD Foundation
7 1.20.2.2 jdolecek * by Maxime Villard.
8 1.20.2.2 jdolecek *
9 1.20.2.2 jdolecek * Redistribution and use in source and binary forms, with or without
10 1.20.2.2 jdolecek * modification, are permitted provided that the following conditions
11 1.20.2.2 jdolecek * are met:
12 1.20.2.2 jdolecek * 1. Redistributions of source code must retain the above copyright
13 1.20.2.2 jdolecek * notice, this list of conditions and the following disclaimer.
14 1.20.2.2 jdolecek * 2. Redistributions in binary form must reproduce the above copyright
15 1.20.2.2 jdolecek * notice, this list of conditions and the following disclaimer in the
16 1.20.2.2 jdolecek * documentation and/or other materials provided with the distribution.
17 1.20.2.2 jdolecek *
18 1.20.2.2 jdolecek * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 1.20.2.2 jdolecek * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 1.20.2.2 jdolecek * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 1.20.2.2 jdolecek * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 1.20.2.2 jdolecek * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 1.20.2.2 jdolecek * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 1.20.2.2 jdolecek * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 1.20.2.2 jdolecek * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 1.20.2.2 jdolecek * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 1.20.2.2 jdolecek * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 1.20.2.2 jdolecek * POSSIBILITY OF SUCH DAMAGE.
29 1.20.2.2 jdolecek */
30 1.20.2.2 jdolecek
31 1.20.2.2 jdolecek #include "prekern.h"
32 1.20.2.2 jdolecek
33 1.20.2.2 jdolecek #define PAD_TEXT 0xCC
34 1.20.2.2 jdolecek #define PAD_RODATA 0x00
35 1.20.2.2 jdolecek #define PAD_DATA 0x00
36 1.20.2.2 jdolecek
37 1.20.2.2 jdolecek #define ELFROUND 64
38 1.20.2.2 jdolecek
39 1.20.2.2 jdolecek static const uint8_t pads[4] = {
40 1.20.2.2 jdolecek [BTSEG_NONE] = 0x00,
41 1.20.2.2 jdolecek [BTSEG_TEXT] = 0xCC,
42 1.20.2.2 jdolecek [BTSEG_RODATA] = 0x00,
43 1.20.2.2 jdolecek [BTSEG_DATA] = 0x00
44 1.20.2.2 jdolecek };
45 1.20.2.2 jdolecek
46 1.20.2.2 jdolecek #define MM_PROT_READ 0x00
47 1.20.2.2 jdolecek #define MM_PROT_WRITE 0x01
48 1.20.2.2 jdolecek #define MM_PROT_EXECUTE 0x02
49 1.20.2.2 jdolecek
50 1.20.2.2 jdolecek static const pt_entry_t protection_codes[3] = {
51 1.20.2.2 jdolecek [MM_PROT_READ] = PG_RO | PG_NX,
52 1.20.2.2 jdolecek [MM_PROT_WRITE] = PG_RW | PG_NX,
53 1.20.2.2 jdolecek [MM_PROT_EXECUTE] = PG_RO,
54 1.20.2.2 jdolecek /* RWX does not exist */
55 1.20.2.2 jdolecek };
56 1.20.2.2 jdolecek
57 1.20.2.2 jdolecek struct bootspace bootspace;
58 1.20.2.2 jdolecek
59 1.20.2.2 jdolecek extern paddr_t kernpa_start, kernpa_end;
60 1.20.2.2 jdolecek vaddr_t iom_base;
61 1.20.2.2 jdolecek
62 1.20.2.2 jdolecek paddr_t pa_avail = 0;
63 1.20.2.2 jdolecek static const vaddr_t tmpva = (PREKERNBASE + NKL2_KIMG_ENTRIES * NBPD_L2);
64 1.20.2.2 jdolecek
65 1.20.2.2 jdolecek void
66 1.20.2.2 jdolecek mm_init(paddr_t first_pa)
67 1.20.2.2 jdolecek {
68 1.20.2.2 jdolecek pa_avail = first_pa;
69 1.20.2.2 jdolecek }
70 1.20.2.2 jdolecek
71 1.20.2.2 jdolecek static void
72 1.20.2.2 jdolecek mm_enter_pa(paddr_t pa, vaddr_t va, pte_prot_t prot)
73 1.20.2.2 jdolecek {
74 1.20.2.2 jdolecek if (PTE_BASE[pl1_i(va)] & PG_V) {
75 1.20.2.2 jdolecek fatal("mm_enter_pa: mapping already present");
76 1.20.2.2 jdolecek }
77 1.20.2.2 jdolecek PTE_BASE[pl1_i(va)] = pa | PG_V | protection_codes[prot];
78 1.20.2.2 jdolecek }
79 1.20.2.2 jdolecek
80 1.20.2.2 jdolecek static void
81 1.20.2.2 jdolecek mm_reenter_pa(paddr_t pa, vaddr_t va, pte_prot_t prot)
82 1.20.2.2 jdolecek {
83 1.20.2.2 jdolecek PTE_BASE[pl1_i(va)] = pa | PG_V | protection_codes[prot];
84 1.20.2.2 jdolecek }
85 1.20.2.2 jdolecek
86 1.20.2.2 jdolecek static void
87 1.20.2.2 jdolecek mm_flush_va(vaddr_t va)
88 1.20.2.2 jdolecek {
89 1.20.2.2 jdolecek asm volatile("invlpg (%0)" ::"r" (va) : "memory");
90 1.20.2.2 jdolecek }
91 1.20.2.2 jdolecek
92 1.20.2.2 jdolecek static paddr_t
93 1.20.2.2 jdolecek mm_palloc(size_t npages)
94 1.20.2.2 jdolecek {
95 1.20.2.2 jdolecek paddr_t pa;
96 1.20.2.2 jdolecek size_t i;
97 1.20.2.2 jdolecek
98 1.20.2.2 jdolecek /* Allocate the physical pages */
99 1.20.2.2 jdolecek pa = pa_avail;
100 1.20.2.2 jdolecek pa_avail += npages * PAGE_SIZE;
101 1.20.2.2 jdolecek
102 1.20.2.2 jdolecek /* Zero them out */
103 1.20.2.2 jdolecek for (i = 0; i < npages; i++) {
104 1.20.2.2 jdolecek mm_reenter_pa(pa + i * PAGE_SIZE, tmpva,
105 1.20.2.2 jdolecek MM_PROT_READ|MM_PROT_WRITE);
106 1.20.2.2 jdolecek mm_flush_va(tmpva);
107 1.20.2.2 jdolecek memset((void *)tmpva, 0, PAGE_SIZE);
108 1.20.2.2 jdolecek }
109 1.20.2.2 jdolecek
110 1.20.2.2 jdolecek return pa;
111 1.20.2.2 jdolecek }
112 1.20.2.2 jdolecek
113 1.20.2.2 jdolecek static bool
114 1.20.2.2 jdolecek mm_pte_is_valid(pt_entry_t pte)
115 1.20.2.2 jdolecek {
116 1.20.2.2 jdolecek return ((pte & PG_V) != 0);
117 1.20.2.2 jdolecek }
118 1.20.2.2 jdolecek
119 1.20.2.2 jdolecek static void
120 1.20.2.2 jdolecek mm_mprotect(vaddr_t startva, size_t size, pte_prot_t prot)
121 1.20.2.2 jdolecek {
122 1.20.2.2 jdolecek size_t i, npages;
123 1.20.2.2 jdolecek vaddr_t va;
124 1.20.2.2 jdolecek paddr_t pa;
125 1.20.2.2 jdolecek
126 1.20.2.2 jdolecek ASSERT(size % PAGE_SIZE == 0);
127 1.20.2.2 jdolecek npages = size / PAGE_SIZE;
128 1.20.2.2 jdolecek
129 1.20.2.2 jdolecek for (i = 0; i < npages; i++) {
130 1.20.2.2 jdolecek va = startva + i * PAGE_SIZE;
131 1.20.2.2 jdolecek pa = (PTE_BASE[pl1_i(va)] & PG_FRAME);
132 1.20.2.2 jdolecek mm_reenter_pa(pa, va, prot);
133 1.20.2.2 jdolecek mm_flush_va(va);
134 1.20.2.2 jdolecek }
135 1.20.2.2 jdolecek }
136 1.20.2.2 jdolecek
137 1.20.2.2 jdolecek void
138 1.20.2.2 jdolecek mm_bootspace_mprotect(void)
139 1.20.2.2 jdolecek {
140 1.20.2.2 jdolecek pte_prot_t prot;
141 1.20.2.2 jdolecek size_t i;
142 1.20.2.2 jdolecek
143 1.20.2.2 jdolecek /* Remap the kernel segments with proper permissions. */
144 1.20.2.2 jdolecek for (i = 0; i < BTSPACE_NSEGS; i++) {
145 1.20.2.2 jdolecek if (bootspace.segs[i].type == BTSEG_TEXT) {
146 1.20.2.2 jdolecek prot = MM_PROT_READ|MM_PROT_EXECUTE;
147 1.20.2.2 jdolecek } else if (bootspace.segs[i].type == BTSEG_RODATA) {
148 1.20.2.2 jdolecek prot = MM_PROT_READ;
149 1.20.2.2 jdolecek } else {
150 1.20.2.2 jdolecek continue;
151 1.20.2.2 jdolecek }
152 1.20.2.2 jdolecek mm_mprotect(bootspace.segs[i].va, bootspace.segs[i].sz, prot);
153 1.20.2.2 jdolecek }
154 1.20.2.2 jdolecek
155 1.20.2.2 jdolecek print_state(true, "Segments protection updated");
156 1.20.2.2 jdolecek }
157 1.20.2.2 jdolecek
158 1.20.2.2 jdolecek static size_t
159 1.20.2.2 jdolecek mm_nentries_range(vaddr_t startva, vaddr_t endva, size_t pgsz)
160 1.20.2.2 jdolecek {
161 1.20.2.2 jdolecek size_t npages;
162 1.20.2.2 jdolecek
163 1.20.2.2 jdolecek npages = roundup((endva / PAGE_SIZE), (pgsz / PAGE_SIZE)) -
164 1.20.2.2 jdolecek rounddown((startva / PAGE_SIZE), (pgsz / PAGE_SIZE));
165 1.20.2.2 jdolecek return (npages / (pgsz / PAGE_SIZE));
166 1.20.2.2 jdolecek }
167 1.20.2.2 jdolecek
168 1.20.2.2 jdolecek static void
169 1.20.2.2 jdolecek mm_map_tree(vaddr_t startva, vaddr_t endva)
170 1.20.2.2 jdolecek {
171 1.20.2.2 jdolecek size_t i, nL4e, nL3e, nL2e;
172 1.20.2.2 jdolecek size_t L4e_idx, L3e_idx, L2e_idx;
173 1.20.2.2 jdolecek paddr_t pa;
174 1.20.2.2 jdolecek
175 1.20.2.2 jdolecek /* Build L4. */
176 1.20.2.2 jdolecek L4e_idx = pl4_i(startva);
177 1.20.2.2 jdolecek nL4e = mm_nentries_range(startva, endva, NBPD_L4);
178 1.20.2.2 jdolecek ASSERT(L4e_idx == 511);
179 1.20.2.2 jdolecek ASSERT(nL4e == 1);
180 1.20.2.2 jdolecek if (!mm_pte_is_valid(L4_BASE[L4e_idx])) {
181 1.20.2.2 jdolecek pa = mm_palloc(1);
182 1.20.2.2 jdolecek L4_BASE[L4e_idx] = pa | PG_V | PG_RW;
183 1.20.2.2 jdolecek }
184 1.20.2.2 jdolecek
185 1.20.2.2 jdolecek /* Build L3. */
186 1.20.2.2 jdolecek L3e_idx = pl3_i(startva);
187 1.20.2.2 jdolecek nL3e = mm_nentries_range(startva, endva, NBPD_L3);
188 1.20.2.2 jdolecek for (i = 0; i < nL3e; i++) {
189 1.20.2.2 jdolecek if (mm_pte_is_valid(L3_BASE[L3e_idx+i])) {
190 1.20.2.2 jdolecek continue;
191 1.20.2.2 jdolecek }
192 1.20.2.2 jdolecek pa = mm_palloc(1);
193 1.20.2.2 jdolecek L3_BASE[L3e_idx+i] = pa | PG_V | PG_RW;
194 1.20.2.2 jdolecek }
195 1.20.2.2 jdolecek
196 1.20.2.2 jdolecek /* Build L2. */
197 1.20.2.2 jdolecek L2e_idx = pl2_i(startva);
198 1.20.2.2 jdolecek nL2e = mm_nentries_range(startva, endva, NBPD_L2);
199 1.20.2.2 jdolecek for (i = 0; i < nL2e; i++) {
200 1.20.2.2 jdolecek if (mm_pte_is_valid(L2_BASE[L2e_idx+i])) {
201 1.20.2.2 jdolecek continue;
202 1.20.2.2 jdolecek }
203 1.20.2.2 jdolecek pa = mm_palloc(1);
204 1.20.2.2 jdolecek L2_BASE[L2e_idx+i] = pa | PG_V | PG_RW;
205 1.20.2.2 jdolecek }
206 1.20.2.2 jdolecek }
207 1.20.2.2 jdolecek
208 1.20.2.2 jdolecek static vaddr_t
209 1.20.2.2 jdolecek mm_randva_kregion(size_t size, size_t pagesz)
210 1.20.2.2 jdolecek {
211 1.20.2.2 jdolecek vaddr_t sva, eva;
212 1.20.2.2 jdolecek vaddr_t randva;
213 1.20.2.2 jdolecek uint64_t rnd;
214 1.20.2.2 jdolecek size_t i;
215 1.20.2.2 jdolecek bool ok;
216 1.20.2.2 jdolecek
217 1.20.2.2 jdolecek while (1) {
218 1.20.2.2 jdolecek prng_get_rand(&rnd, sizeof(rnd));
219 1.20.2.2 jdolecek randva = rounddown(KASLR_WINDOW_BASE +
220 1.20.2.2 jdolecek rnd % (KASLR_WINDOW_SIZE - size), pagesz);
221 1.20.2.2 jdolecek
222 1.20.2.2 jdolecek /* Detect collisions */
223 1.20.2.2 jdolecek ok = true;
224 1.20.2.2 jdolecek for (i = 0; i < BTSPACE_NSEGS; i++) {
225 1.20.2.2 jdolecek if (bootspace.segs[i].type == BTSEG_NONE) {
226 1.20.2.2 jdolecek continue;
227 1.20.2.2 jdolecek }
228 1.20.2.2 jdolecek sva = bootspace.segs[i].va;
229 1.20.2.2 jdolecek eva = sva + bootspace.segs[i].sz;
230 1.20.2.2 jdolecek
231 1.20.2.2 jdolecek if ((sva <= randva) && (randva < eva)) {
232 1.20.2.2 jdolecek ok = false;
233 1.20.2.2 jdolecek break;
234 1.20.2.2 jdolecek }
235 1.20.2.2 jdolecek if ((sva < randva + size) && (randva + size <= eva)) {
236 1.20.2.2 jdolecek ok = false;
237 1.20.2.2 jdolecek break;
238 1.20.2.2 jdolecek }
239 1.20.2.2 jdolecek if (randva < sva && eva < (randva + size)) {
240 1.20.2.2 jdolecek ok = false;
241 1.20.2.2 jdolecek break;
242 1.20.2.2 jdolecek }
243 1.20.2.2 jdolecek }
244 1.20.2.2 jdolecek if (ok) {
245 1.20.2.2 jdolecek break;
246 1.20.2.2 jdolecek }
247 1.20.2.2 jdolecek }
248 1.20.2.2 jdolecek
249 1.20.2.2 jdolecek mm_map_tree(randva, randva + size);
250 1.20.2.2 jdolecek
251 1.20.2.2 jdolecek return randva;
252 1.20.2.2 jdolecek }
253 1.20.2.2 jdolecek
254 1.20.2.2 jdolecek static paddr_t
255 1.20.2.2 jdolecek bootspace_getend(void)
256 1.20.2.2 jdolecek {
257 1.20.2.2 jdolecek paddr_t pa, max = 0;
258 1.20.2.2 jdolecek size_t i;
259 1.20.2.2 jdolecek
260 1.20.2.2 jdolecek for (i = 0; i < BTSPACE_NSEGS; i++) {
261 1.20.2.2 jdolecek if (bootspace.segs[i].type == BTSEG_NONE) {
262 1.20.2.2 jdolecek continue;
263 1.20.2.2 jdolecek }
264 1.20.2.2 jdolecek pa = bootspace.segs[i].pa + bootspace.segs[i].sz;
265 1.20.2.2 jdolecek if (pa > max)
266 1.20.2.2 jdolecek max = pa;
267 1.20.2.2 jdolecek }
268 1.20.2.2 jdolecek
269 1.20.2.2 jdolecek return max;
270 1.20.2.2 jdolecek }
271 1.20.2.2 jdolecek
272 1.20.2.2 jdolecek static void
273 1.20.2.2 jdolecek bootspace_addseg(int type, vaddr_t va, paddr_t pa, size_t sz)
274 1.20.2.2 jdolecek {
275 1.20.2.2 jdolecek size_t i;
276 1.20.2.2 jdolecek
277 1.20.2.2 jdolecek for (i = 0; i < BTSPACE_NSEGS; i++) {
278 1.20.2.2 jdolecek if (bootspace.segs[i].type == BTSEG_NONE) {
279 1.20.2.2 jdolecek bootspace.segs[i].type = type;
280 1.20.2.2 jdolecek bootspace.segs[i].va = va;
281 1.20.2.2 jdolecek bootspace.segs[i].pa = pa;
282 1.20.2.2 jdolecek bootspace.segs[i].sz = sz;
283 1.20.2.2 jdolecek return;
284 1.20.2.2 jdolecek }
285 1.20.2.2 jdolecek }
286 1.20.2.2 jdolecek
287 1.20.2.2 jdolecek fatal("bootspace_addseg: segments full");
288 1.20.2.2 jdolecek }
289 1.20.2.2 jdolecek
290 1.20.2.2 jdolecek static size_t
291 1.20.2.2 jdolecek mm_shift_segment(vaddr_t va, size_t pagesz, size_t elfsz, size_t elfalign)
292 1.20.2.2 jdolecek {
293 1.20.2.2 jdolecek size_t shiftsize, offset;
294 1.20.2.2 jdolecek uint64_t rnd;
295 1.20.2.2 jdolecek
296 1.20.2.2 jdolecek if (elfalign == 0) {
297 1.20.2.2 jdolecek elfalign = ELFROUND;
298 1.20.2.2 jdolecek }
299 1.20.2.2 jdolecek
300 1.20.2.2 jdolecek ASSERT(pagesz >= elfalign);
301 1.20.2.2 jdolecek ASSERT(pagesz % elfalign == 0);
302 1.20.2.2 jdolecek shiftsize = roundup(elfsz, pagesz) - roundup(elfsz, elfalign);
303 1.20.2.2 jdolecek if (shiftsize == 0) {
304 1.20.2.2 jdolecek return 0;
305 1.20.2.2 jdolecek }
306 1.20.2.2 jdolecek
307 1.20.2.2 jdolecek prng_get_rand(&rnd, sizeof(rnd));
308 1.20.2.2 jdolecek offset = roundup(rnd % shiftsize, elfalign);
309 1.20.2.2 jdolecek ASSERT((va + offset) % elfalign == 0);
310 1.20.2.2 jdolecek
311 1.20.2.2 jdolecek memmove((void *)(va + offset), (void *)va, elfsz);
312 1.20.2.2 jdolecek
313 1.20.2.2 jdolecek return offset;
314 1.20.2.2 jdolecek }
315 1.20.2.2 jdolecek
316 1.20.2.2 jdolecek static void
317 1.20.2.2 jdolecek mm_map_head(void)
318 1.20.2.2 jdolecek {
319 1.20.2.2 jdolecek size_t i, npages, size;
320 1.20.2.2 jdolecek uint64_t rnd;
321 1.20.2.2 jdolecek vaddr_t randva;
322 1.20.2.2 jdolecek
323 1.20.2.2 jdolecek /*
324 1.20.2.2 jdolecek * To get the size of the head, we give a look at the read-only
325 1.20.2.2 jdolecek * mapping of the kernel we created in locore. We're identity mapped,
326 1.20.2.2 jdolecek * so kernpa = kernva.
327 1.20.2.2 jdolecek */
328 1.20.2.2 jdolecek size = elf_get_head_size((vaddr_t)kernpa_start);
329 1.20.2.2 jdolecek npages = size / PAGE_SIZE;
330 1.20.2.2 jdolecek
331 1.20.2.2 jdolecek prng_get_rand(&rnd, sizeof(rnd));
332 1.20.2.2 jdolecek randva = rounddown(HEAD_WINDOW_BASE + rnd % (HEAD_WINDOW_SIZE - size),
333 1.20.2.2 jdolecek PAGE_SIZE);
334 1.20.2.2 jdolecek mm_map_tree(randva, randva + size);
335 1.20.2.2 jdolecek
336 1.20.2.2 jdolecek /* Enter the area and build the ELF info */
337 1.20.2.2 jdolecek for (i = 0; i < npages; i++) {
338 1.20.2.2 jdolecek mm_enter_pa(kernpa_start + i * PAGE_SIZE,
339 1.20.2.2 jdolecek randva + i * PAGE_SIZE, MM_PROT_READ|MM_PROT_WRITE);
340 1.20.2.2 jdolecek }
341 1.20.2.2 jdolecek elf_build_head(randva);
342 1.20.2.2 jdolecek
343 1.20.2.2 jdolecek /* Register the values in bootspace */
344 1.20.2.2 jdolecek bootspace.head.va = randva;
345 1.20.2.2 jdolecek bootspace.head.pa = kernpa_start;
346 1.20.2.2 jdolecek bootspace.head.sz = size;
347 1.20.2.2 jdolecek }
348 1.20.2.2 jdolecek
349 1.20.2.2 jdolecek vaddr_t
350 1.20.2.2 jdolecek mm_map_segment(int segtype, paddr_t pa, size_t elfsz, size_t elfalign)
351 1.20.2.2 jdolecek {
352 1.20.2.2 jdolecek size_t i, npages, size, pagesz, offset;
353 1.20.2.2 jdolecek vaddr_t randva;
354 1.20.2.2 jdolecek char pad;
355 1.20.2.2 jdolecek
356 1.20.2.2 jdolecek if (elfsz <= PAGE_SIZE) {
357 1.20.2.2 jdolecek pagesz = NBPD_L1;
358 1.20.2.2 jdolecek } else {
359 1.20.2.2 jdolecek pagesz = NBPD_L2;
360 1.20.2.2 jdolecek }
361 1.20.2.2 jdolecek
362 1.20.2.2 jdolecek size = roundup(elfsz, pagesz);
363 1.20.2.2 jdolecek randva = mm_randva_kregion(size, pagesz);
364 1.20.2.2 jdolecek
365 1.20.2.2 jdolecek npages = size / PAGE_SIZE;
366 1.20.2.2 jdolecek for (i = 0; i < npages; i++) {
367 1.20.2.2 jdolecek mm_enter_pa(pa + i * PAGE_SIZE,
368 1.20.2.2 jdolecek randva + i * PAGE_SIZE, MM_PROT_READ|MM_PROT_WRITE);
369 1.20.2.2 jdolecek }
370 1.20.2.2 jdolecek
371 1.20.2.2 jdolecek offset = mm_shift_segment(randva, pagesz, elfsz, elfalign);
372 1.20.2.2 jdolecek ASSERT(offset + elfsz <= size);
373 1.20.2.2 jdolecek
374 1.20.2.2 jdolecek pad = pads[segtype];
375 1.20.2.2 jdolecek memset((void *)randva, pad, offset);
376 1.20.2.2 jdolecek memset((void *)(randva + offset + elfsz), pad, size - elfsz - offset);
377 1.20.2.2 jdolecek
378 1.20.2.2 jdolecek bootspace_addseg(segtype, randva, pa, size);
379 1.20.2.2 jdolecek
380 1.20.2.2 jdolecek return (randva + offset);
381 1.20.2.2 jdolecek }
382 1.20.2.2 jdolecek
383 1.20.2.2 jdolecek static void
384 1.20.2.2 jdolecek mm_map_boot(void)
385 1.20.2.2 jdolecek {
386 1.20.2.2 jdolecek size_t i, npages, size;
387 1.20.2.2 jdolecek vaddr_t randva;
388 1.20.2.2 jdolecek paddr_t bootpa;
389 1.20.2.2 jdolecek
390 1.20.2.2 jdolecek /*
391 1.20.2.2 jdolecek * The "boot" region is special: its page tree has a fixed size, but
392 1.20.2.2 jdolecek * the number of pages entered is lower.
393 1.20.2.2 jdolecek */
394 1.20.2.2 jdolecek
395 1.20.2.2 jdolecek /* Create the page tree */
396 1.20.2.2 jdolecek size = (NKL2_KIMG_ENTRIES + 1) * NBPD_L2;
397 1.20.2.2 jdolecek randva = mm_randva_kregion(size, PAGE_SIZE);
398 1.20.2.2 jdolecek
399 1.20.2.2 jdolecek /* Enter the area and build the ELF info */
400 1.20.2.2 jdolecek bootpa = bootspace_getend();
401 1.20.2.2 jdolecek size = (pa_avail - bootpa);
402 1.20.2.2 jdolecek npages = size / PAGE_SIZE;
403 1.20.2.2 jdolecek for (i = 0; i < npages; i++) {
404 1.20.2.2 jdolecek mm_enter_pa(bootpa + i * PAGE_SIZE,
405 1.20.2.2 jdolecek randva + i * PAGE_SIZE, MM_PROT_READ|MM_PROT_WRITE);
406 1.20.2.2 jdolecek }
407 1.20.2.2 jdolecek elf_build_boot(randva, bootpa);
408 1.20.2.2 jdolecek
409 1.20.2.2 jdolecek /* Enter the ISA I/O MEM */
410 1.20.2.2 jdolecek iom_base = randva + npages * PAGE_SIZE;
411 1.20.2.2 jdolecek npages = IOM_SIZE / PAGE_SIZE;
412 1.20.2.2 jdolecek for (i = 0; i < npages; i++) {
413 1.20.2.2 jdolecek mm_enter_pa(IOM_BEGIN + i * PAGE_SIZE,
414 1.20.2.2 jdolecek iom_base + i * PAGE_SIZE, MM_PROT_READ|MM_PROT_WRITE);
415 1.20.2.2 jdolecek }
416 1.20.2.2 jdolecek
417 1.20.2.2 jdolecek /* Register the values in bootspace */
418 1.20.2.2 jdolecek bootspace.boot.va = randva;
419 1.20.2.2 jdolecek bootspace.boot.pa = bootpa;
420 1.20.2.2 jdolecek bootspace.boot.sz = (size_t)(iom_base + IOM_SIZE) -
421 1.20.2.2 jdolecek (size_t)bootspace.boot.va;
422 1.20.2.2 jdolecek
423 1.20.2.2 jdolecek /* Initialize the values that are located in the "boot" region */
424 1.20.2.2 jdolecek extern uint64_t PDPpaddr;
425 1.20.2.2 jdolecek bootspace.spareva = bootspace.boot.va + NKL2_KIMG_ENTRIES * NBPD_L2;
426 1.20.2.2 jdolecek bootspace.pdir = bootspace.boot.va + (PDPpaddr - bootspace.boot.pa);
427 1.20.2.2 jdolecek bootspace.emodule = bootspace.boot.va + NKL2_KIMG_ENTRIES * NBPD_L2;
428 1.20.2.2 jdolecek }
429 1.20.2.2 jdolecek
430 1.20.2.2 jdolecek /*
431 1.20.2.2 jdolecek * There is a variable number of independent regions: one head, several kernel
432 1.20.2.2 jdolecek * segments, one boot. They are all mapped at random VAs.
433 1.20.2.2 jdolecek *
434 1.20.2.2 jdolecek * Head contains the ELF Header and ELF Section Headers, and we use them to
435 1.20.2.2 jdolecek * map the rest of the regions. Head must be placed in memory *before* the
436 1.20.2.2 jdolecek * other regions.
437 1.20.2.2 jdolecek *
438 1.20.2.2 jdolecek * At the end of this function, the bootspace structure is fully constructed.
439 1.20.2.2 jdolecek */
440 1.20.2.2 jdolecek void
441 1.20.2.2 jdolecek mm_map_kernel(void)
442 1.20.2.2 jdolecek {
443 1.20.2.2 jdolecek memset(&bootspace, 0, sizeof(bootspace));
444 1.20.2.2 jdolecek mm_map_head();
445 1.20.2.2 jdolecek print_state(true, "Head region mapped");
446 1.20.2.2 jdolecek elf_map_sections();
447 1.20.2.2 jdolecek print_state(true, "Segments mapped");
448 1.20.2.2 jdolecek mm_map_boot();
449 1.20.2.2 jdolecek print_state(true, "Boot region mapped");
450 1.20.2.2 jdolecek }
451