]> git.saurik.com Git - apple/xnu.git/blame - osfmk/arm64/arm_vm_init.c
xnu-4570.1.46.tar.gz
[apple/xnu.git] / osfmk / arm64 / arm_vm_init.c
CommitLineData
5ba3f43e
A
1/*
2 * Copyright (c) 2007-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <mach_debug.h>
30#include <mach_kdp.h>
31#include <debug.h>
32
33#include <mach/vm_types.h>
34#include <mach/vm_param.h>
35#include <kern/misc_protos.h>
36#include <kern/assert.h>
37#include <vm/vm_kern.h>
38#include <vm/vm_page.h>
39#include <vm/pmap.h>
40
41#include <arm64/proc_reg.h>
42#include <arm64/lowglobals.h>
43#include <arm/cpu_data_internal.h>
44#include <arm/misc_protos.h>
45#include <pexpert/arm64/boot.h>
46
47#include <libkern/kernel_mach_header.h>
48#include <libkern/section_keywords.h>
49
50#if KASAN
51extern vm_offset_t shadow_pbase;
52extern vm_offset_t shadow_ptop;
53extern vm_offset_t physmap_vbase;
54extern vm_offset_t physmap_vtop;
55#endif
56
57/*
58 * Denotes the end of xnu.
59 */
60extern void *last_kernel_symbol;
61
62/*
63 * KASLR parameters
64 */
65SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kernel_base;
66SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kernel_top;
67SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kext_base;
68SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kext_top;
69SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kernel_stext;
70SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kernel_etext;
71SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kernel_slide;
72SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kernel_slid_base;
73SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kernel_slid_top;
74
75SECURITY_READ_ONLY_LATE(vm_offset_t) vm_prelink_stext;
76SECURITY_READ_ONLY_LATE(vm_offset_t) vm_prelink_etext;
77SECURITY_READ_ONLY_LATE(vm_offset_t) vm_prelink_sdata;
78SECURITY_READ_ONLY_LATE(vm_offset_t) vm_prelink_edata;
79SECURITY_READ_ONLY_LATE(vm_offset_t) vm_prelink_sinfo;
80SECURITY_READ_ONLY_LATE(vm_offset_t) vm_prelink_einfo;
81SECURITY_READ_ONLY_LATE(vm_offset_t) vm_slinkedit;
82SECURITY_READ_ONLY_LATE(vm_offset_t) vm_elinkedit;
83
84/* Used by <mach/arm/vm_param.h> */
85SECURITY_READ_ONLY_LATE(unsigned long) gVirtBase;
86SECURITY_READ_ONLY_LATE(unsigned long) gPhysBase;
87SECURITY_READ_ONLY_LATE(unsigned long) gPhysSize;
88
89
90/*
91 * NOTE: mem_size is bogus on large memory machines.
92 * We will pin it to 0x80000000 if there is more than 2 GB
93 * This is left only for compatibility and max_mem should be used.
94 */
95vm_offset_t mem_size; /* Size of actual physical memory present
96 * minus any performance buffer and possibly
97 * limited by mem_limit in bytes */
98uint64_t mem_actual; /* The "One True" physical memory size
99 * actually, it's the highest physical
100 * address + 1 */
101uint64_t max_mem; /* Size of physical memory (bytes), adjusted
102 * by maxmem */
103uint64_t sane_size; /* Memory size to use for defaults
104 * calculations */
105/* This no longer appears to be used; kill it? */
106addr64_t vm_last_addr = VM_MAX_KERNEL_ADDRESS; /* Highest kernel
107 * virtual address known
108 * to the VM system */
109
110SECURITY_READ_ONLY_LATE(static vm_offset_t) segTEXTB;
111SECURITY_READ_ONLY_LATE(static unsigned long) segSizeTEXT;
112
113
114SECURITY_READ_ONLY_LATE(static vm_offset_t) segDATACONSTB;
115SECURITY_READ_ONLY_LATE(static unsigned long) segSizeDATACONST;
116
117SECURITY_READ_ONLY_LATE(static vm_offset_t) segTEXTEXECB;
118SECURITY_READ_ONLY_LATE(static unsigned long) segSizeTEXTEXEC;
119
120SECURITY_READ_ONLY_LATE(static vm_offset_t) segDATAB;
121SECURITY_READ_ONLY_LATE(static unsigned long) segSizeDATA;
122
123
124SECURITY_READ_ONLY_LATE(static vm_offset_t) segLINKB;
125SECURITY_READ_ONLY_LATE(static unsigned long) segSizeLINK;
126
127SECURITY_READ_ONLY_LATE(static vm_offset_t) segKLDB;
128SECURITY_READ_ONLY_LATE(static unsigned long) segSizeKLD;
129SECURITY_READ_ONLY_LATE(static vm_offset_t) segLASTB;
130SECURITY_READ_ONLY_LATE(static unsigned long) segSizeLAST;
131
132SECURITY_READ_ONLY_LATE(vm_offset_t) segPRELINKTEXTB;
133SECURITY_READ_ONLY_LATE(unsigned long) segSizePRELINKTEXT;
134
135SECURITY_READ_ONLY_LATE(static vm_offset_t) segPLKTEXTEXECB;
136SECURITY_READ_ONLY_LATE(static unsigned long) segSizePLKTEXTEXEC;
137
138SECURITY_READ_ONLY_LATE(static vm_offset_t) segPLKDATACONSTB;
139SECURITY_READ_ONLY_LATE(static unsigned long) segSizePLKDATACONST;
140
141SECURITY_READ_ONLY_LATE(static vm_offset_t) segPRELINKDATAB;
142SECURITY_READ_ONLY_LATE(static unsigned long) segSizePRELINKDATA;
143
144SECURITY_READ_ONLY_LATE(static vm_offset_t) segPLKLLVMCOVB = 0;
145SECURITY_READ_ONLY_LATE(static unsigned long) segSizePLKLLVMCOV = 0;
146
147SECURITY_READ_ONLY_LATE(static vm_offset_t) segPLKLINKEDITB;
148SECURITY_READ_ONLY_LATE(static unsigned long) segSizePLKLINKEDIT;
149
150SECURITY_READ_ONLY_LATE(static vm_offset_t) segPRELINKINFOB;
151SECURITY_READ_ONLY_LATE(static unsigned long) segSizePRELINKINFO;
152
153SECURITY_READ_ONLY_LATE(static boolean_t) use_contiguous_hint = TRUE;
154
155SECURITY_READ_ONLY_LATE(unsigned) PAGE_SHIFT_CONST;
156
157SECURITY_READ_ONLY_LATE(vm_offset_t) end_kern;
158SECURITY_READ_ONLY_LATE(vm_offset_t) etext;
159SECURITY_READ_ONLY_LATE(vm_offset_t) sdata;
160SECURITY_READ_ONLY_LATE(vm_offset_t) edata;
161
162vm_offset_t alloc_ptpage(boolean_t map_static);
163SECURITY_READ_ONLY_LATE(vm_offset_t) ropage_next;
164
165/*
166 * Bootstrap the system enough to run with virtual memory.
167 * Map the kernel's code and data, and allocate the system page table.
168 * Page_size must already be set.
169 *
170 * Parameters:
171 * first_avail: first available physical page -
172 * after kernel page tables
173 * avail_start: PA of first physical page
174 * avail_end: PA of last physical page
175 */
176SECURITY_READ_ONLY_LATE(vm_offset_t) first_avail;
177SECURITY_READ_ONLY_LATE(vm_offset_t) static_memory_end;
178SECURITY_READ_ONLY_LATE(pmap_paddr_t) avail_start;
179SECURITY_READ_ONLY_LATE(pmap_paddr_t) avail_end;
180
181#define MEM_SIZE_MAX 0x100000000ULL
182
183#if defined(KERNEL_INTEGRITY_KTRR)
184#if __ARM64_TWO_LEVEL_PMAP__
185/* We could support this configuration, but it adds memory overhead. */
186#error This configuration is not supported
187#endif
188#endif
189
190/*
191 * This rounds the given address up to the nearest boundary for a PTE contiguous
192 * hint.
193 */
194static vm_offset_t
195round_up_pte_hint_address(vm_offset_t address)
196{
197 vm_offset_t hint_size = ARM_PTE_SIZE << ARM_PTE_HINT_ENTRIES_SHIFT;
198 return ((address + (hint_size - 1)) & ~(hint_size - 1));
199}
200
201/* allocate a page for a page table: we support static and dynamic mappings.
202 *
203 * returns a virtual address for the allocated page
204 *
205 * for static mappings, we allocate from the region ropagetable_begin to ro_pagetable_end-1,
206 * which is defined in the DATA_CONST segment and will be protected RNX when vm_prot_finalize runs.
207 *
208 * for dynamic mappings, we allocate from avail_start, which should remain RWNX.
209 */
210
211vm_offset_t alloc_ptpage(boolean_t map_static) {
212 vm_offset_t vaddr;
213
214#if !(defined(KERNEL_INTEGRITY_KTRR))
215 map_static = FALSE;
216#endif
217
218 if (!ropage_next) {
219 ropage_next = (vm_offset_t)&ropagetable_begin;
220 }
221
222 if (map_static) {
223 assert(ropage_next < (vm_offset_t)&ropagetable_end);
224
225 vaddr = ropage_next;
226 ropage_next += ARM_PGBYTES;
227
228 return vaddr;
229 } else {
230 vaddr = phystokv(avail_start);
231 avail_start += ARM_PGBYTES;
232
233 return vaddr;
234 }
235}
236
237#if DEBUG
238
239void dump_kva_l2(vm_offset_t tt_base, tt_entry_t *tt, int indent, uint64_t *rosz_out, uint64_t *rwsz_out);
240
241void dump_kva_l2(vm_offset_t tt_base, tt_entry_t *tt, int indent, uint64_t *rosz_out, uint64_t *rwsz_out) {
242 unsigned int i;
243 boolean_t cur_ro, prev_ro = 0;
244 int start_entry = -1;
245 tt_entry_t cur, prev = 0;
246 pmap_paddr_t robegin = kvtophys((vm_offset_t)&ropagetable_begin);
247 pmap_paddr_t roend = kvtophys((vm_offset_t)&ropagetable_end);
248 boolean_t tt_static = kvtophys((vm_offset_t)tt) >= robegin &&
249 kvtophys((vm_offset_t)tt) < roend;
250
251 for(i=0; i<TTE_PGENTRIES; i++) {
252 int tte_type = tt[i] & ARM_TTE_TYPE_MASK;
253 cur = tt[i] & ARM_TTE_TABLE_MASK;
254
255 if (tt_static) {
256 /* addresses mapped by this entry are static if it is a block mapping,
257 * or the table was allocated from the RO page table region */
258 cur_ro = (tte_type == ARM_TTE_TYPE_BLOCK) || (cur >= robegin && cur < roend);
259 } else {
260 cur_ro = 0;
261 }
262
263 if ((cur == 0 && prev != 0) || (cur_ro != prev_ro && prev != 0)) { // falling edge
264 uintptr_t start,end,sz;
265
266 start = (uintptr_t)start_entry << ARM_TT_L2_SHIFT;
267 start += tt_base;
268 end = ((uintptr_t)i << ARM_TT_L2_SHIFT) - 1;
269 end += tt_base;
270
271 sz = end - start + 1;
272 printf("%*s0x%08x_%08x-0x%08x_%08x %s (%luMB)\n",
273 indent*4, "",
274 (uint32_t)(start >> 32),(uint32_t)start,
275 (uint32_t)(end >> 32),(uint32_t)end,
276 prev_ro ? "Static " : "Dynamic",
277 (sz >> 20));
278
279 if (prev_ro) {
280 *rosz_out += sz;
281 } else {
282 *rwsz_out += sz;
283 }
284 }
285
286 if ((prev == 0 && cur != 0) || cur_ro != prev_ro) { // rising edge: set start
287 start_entry = i;
288 }
289
290 prev = cur;
291 prev_ro = cur_ro;
292 }
293}
294
295void dump_kva_space() {
296 uint64_t tot_rosz=0, tot_rwsz=0;
297 int ro_ptpages, rw_ptpages;
298 pmap_paddr_t robegin = kvtophys((vm_offset_t)&ropagetable_begin);
299 pmap_paddr_t roend = kvtophys((vm_offset_t)&ropagetable_end);
300 boolean_t root_static = kvtophys((vm_offset_t)cpu_tte) >= robegin &&
301 kvtophys((vm_offset_t)cpu_tte) < roend;
302 uint64_t kva_base = ~((1ULL << (64 - T1SZ_BOOT)) - 1);
303
304 printf("Root page table: %s\n", root_static ? "Static" : "Dynamic");
305
306#if !__ARM64_TWO_LEVEL_PMAP__
307 for(unsigned int i=0; i<TTE_PGENTRIES; i++) {
308 pmap_paddr_t cur;
309 boolean_t cur_ro;
310 uintptr_t start,end;
311 uint64_t rosz = 0, rwsz = 0;
312
313 if ((cpu_tte[i] & ARM_TTE_VALID) == 0)
314 continue;
315
316 cur = cpu_tte[i] & ARM_TTE_TABLE_MASK;
317 start = (uint64_t)i << ARM_TT_L1_SHIFT;
318 start = start + kva_base;
319 end = start + (ARM_TT_L1_SIZE - 1);
320 cur_ro = cur >= robegin && cur < roend;
321
322 printf("0x%08x_%08x-0x%08x_%08x %s\n",
323 (uint32_t)(start >> 32),(uint32_t)start,
324 (uint32_t)(end >> 32),(uint32_t)end,
325 cur_ro ? "Static " : "Dynamic");
326
327 dump_kva_l2(start, (tt_entry_t*)phystokv(cur), 1, &rosz, &rwsz);
328 tot_rosz += rosz;
329 tot_rwsz += rwsz;
330 }
331#else
332 dump_kva_l2(kva_base, cpu_tte, 0, &tot_rosz, &tot_rwsz);
333#endif /* !_ARM64_TWO_LEVEL_PMAP__ */
334
335 printf("L2 Address space mapped: Static %lluMB Dynamic %lluMB Total %lluMB\n",
336 tot_rosz >> 20,
337 tot_rwsz >> 20,
338 (tot_rosz >> 20) + (tot_rwsz >> 20));
339
340 ro_ptpages = (int)((ropage_next - (vm_offset_t)&ropagetable_begin) >> ARM_PGSHIFT);
341 rw_ptpages = (int)(lowGlo.lgStaticSize >> ARM_PGSHIFT);
342 printf("Pages used: static %d dynamic %d\n", ro_ptpages, rw_ptpages);
343}
344
345#endif /* DEBUG */
346
347#if defined(KERNEL_INTEGRITY_KTRR)
348extern void bootstrap_instructions;
349
350/*
351 * arm_replace_identity_map takes the V=P map that we construct in start.s
352 * and repurposes it in order to have it map only the page we need in order
353 * to turn on the MMU. This prevents us from running into issues where
354 * KTRR will cause us to fault on executable block mappings that cross the
355 * KTRR boundary.
356 */
357static void arm_replace_identity_map(boot_args * args)
358{
359 vm_offset_t addr;
360 pmap_paddr_t paddr;
361
362#if !__ARM64_TWO_LEVEL_PMAP__
363 pmap_paddr_t l1_ptp_phys = 0;
364 tt_entry_t *l1_ptp_virt = NULL;
365 tt_entry_t *tte1 = NULL;
366#endif
367 pmap_paddr_t l2_ptp_phys = 0;
368 tt_entry_t *l2_ptp_virt = NULL;
369 tt_entry_t *tte2 = NULL;
370 pmap_paddr_t l3_ptp_phys = 0;
371 pt_entry_t *l3_ptp_virt = NULL;
372 pt_entry_t *ptep = NULL;
373
374 addr = ((vm_offset_t)&bootstrap_instructions) & ~ARM_PGMASK;
375 paddr = kvtophys(addr);
376
377 /*
378 * The V=P page tables (at the time this comment was written) start
379 * after the last bit of kernel data, and consist of 1 to 2 pages.
380 * Grab references to those pages, and allocate an L3 page.
381 */
382#if !__ARM64_TWO_LEVEL_PMAP__
383 l1_ptp_phys = args->topOfKernelData;
384 l1_ptp_virt = (tt_entry_t *)phystokv(l1_ptp_phys);
385 tte1 = &l1_ptp_virt[(((paddr) & ARM_TT_L1_INDEX_MASK) >> ARM_TT_L1_SHIFT)];
386
387 l2_ptp_phys = l1_ptp_phys + ARM_PGBYTES;
388#else
389 l2_ptp_phys = args->topOfKernelData;
390#endif
391 l2_ptp_virt = (tt_entry_t *)phystokv(l2_ptp_phys);
392 tte2 = &l2_ptp_virt[(((paddr) & ARM_TT_L2_INDEX_MASK) >> ARM_TT_L2_SHIFT)];
393
394 l3_ptp_virt = (pt_entry_t *)alloc_ptpage(FALSE);
395 l3_ptp_phys = kvtophys((vm_offset_t)l3_ptp_virt);
396 ptep = &l3_ptp_virt[(((paddr) & ARM_TT_L3_INDEX_MASK) >> ARM_TT_L3_SHIFT)];
397
398 /*
399 * Replace the large V=P mapping with a mapping that provides only the
400 * mappings needed to turn on the MMU.
401 */
402#if !__ARM64_TWO_LEVEL_PMAP__
403 bzero(l1_ptp_virt, ARM_PGBYTES);
404 *tte1 = ARM_TTE_BOOT_TABLE | (l2_ptp_phys & ARM_TTE_TABLE_MASK);
405#endif
406 bzero(l2_ptp_virt, ARM_PGBYTES);
407 *tte2 = ARM_TTE_BOOT_TABLE | (l3_ptp_phys & ARM_TTE_TABLE_MASK);
408
409 *ptep = (paddr & ARM_PTE_MASK) |
410 ARM_PTE_TYPE_VALID |
411 ARM_PTE_SH(SH_OUTER_MEMORY) |
412 ARM_PTE_ATTRINDX(CACHE_ATTRINDX_WRITEBACK) |
413 ARM_PTE_AF |
414 ARM_PTE_AP(AP_RONA) |
415 ARM_PTE_NX;
416}
417#endif /* defined(KERNEL_INTEGRITY_KTRR)*/
418
419/*
420 * arm_vm_page_granular_helper updates protections at the L3 level. It will (if
421 * neccessary) allocate a page for the L3 table and update the corresponding L2
422 * entry. Then, it will iterate over the L3 table, updating protections as necessary.
423 * This expects to be invoked on a L2 entry or sub L2 entry granularity, so this should
424 * not be invoked from a context that does not do L2 iteration separately (basically,
425 * don't call this except from arm_vm_page_granular_prot).
426 */
427static void
428arm_vm_page_granular_helper(vm_offset_t start, vm_offset_t _end, vm_offset_t va,
429 int pte_prot_APX, int pte_prot_XN, int forceCoarse,
430 pt_entry_t **deferred_pte, pt_entry_t *deferred_ptmp)
431{
432 if (va & ARM_TT_L2_OFFMASK) { /* ragged edge hanging over a ARM_TT_L2_SIZE boundary */
433#if __ARM64_TWO_LEVEL_PMAP__
434 tt_entry_t *tte2;
435#else
436 tt_entry_t *tte1, *tte2;
437#endif
438 tt_entry_t tmplate;
439 pmap_paddr_t pa;
440 pt_entry_t *ppte, *recursive_pte = NULL, ptmp, recursive_ptmp = 0;
441 addr64_t ppte_phys;
442 unsigned i;
443
444 va &= ~ARM_TT_L2_OFFMASK;
445 pa = va - gVirtBase + gPhysBase;
446
447#if __ARM64_TWO_LEVEL_PMAP__
448 tte2 = &cpu_tte[(((va) & ARM_TT_L2_INDEX_MASK) >> ARM_TT_L2_SHIFT)];
449#else
450 tte1 = &cpu_tte[(((va) & ARM_TT_L1_INDEX_MASK) >> ARM_TT_L1_SHIFT)];
451 tte2 = &((tt_entry_t*) phystokv((*tte1) & ARM_TTE_TABLE_MASK))[(((va) & ARM_TT_L2_INDEX_MASK) >> ARM_TT_L2_SHIFT)];
452#endif
453
454 tmplate = *tte2;
455
456 if (ARM_TTE_TYPE_TABLE == (tmplate & ARM_TTE_TYPE_MASK)) {
457 /* pick up the existing page table. */
458 ppte = (pt_entry_t *)phystokv((tmplate & ARM_TTE_TABLE_MASK));
459 } else {
460 // TTE must be reincarnated COARSE.
461 ppte = (pt_entry_t*)alloc_ptpage(TRUE);
462 ppte_phys = kvtophys((vm_offset_t)ppte);
463
464 pmap_init_pte_static_page(kernel_pmap, ppte, pa);
465
466 *tte2 = pa_to_tte(ppte_phys) | ARM_TTE_TYPE_TABLE | ARM_TTE_VALID;
467 }
468
469 /* Apply the desired protections to the specified page range */
470 for (i = 0; i <= (ARM_TT_L3_INDEX_MASK>>ARM_TT_L3_SHIFT); i++) {
471 if ((start <= va) && (va < _end)) {
472
473 ptmp = pa | ARM_PTE_AF | ARM_PTE_SH(SH_OUTER_MEMORY) | ARM_PTE_TYPE;
474 ptmp = ptmp | ARM_PTE_ATTRINDX(CACHE_ATTRINDX_DEFAULT);
475 ptmp = ptmp | ARM_PTE_AP(pte_prot_APX);
476 ptmp = ptmp | ARM_PTE_NX;
477
478 if (pte_prot_XN) {
479 ptmp = ptmp | ARM_PTE_PNX;
480 }
481
482 /*
483 * If we can, apply the contiguous hint to this range. The hint is
484 * applicable if we are not trying to create per-page mappings and
485 * if the current address falls within a hint-sized range that will
486 * be fully covered by this mapping request.
487 */
488 if ((va >= round_up_pte_hint_address(start)) && (round_up_pte_hint_address(va + 1) < _end) &&
489 !forceCoarse && use_contiguous_hint) {
490 ptmp |= ARM_PTE_HINT;
491 }
492
493 if ((pt_entry_t*)(phystokv(pa)) == ppte) {
494 assert(recursive_pte == NULL);
495 /* This assert should be reenabled as part of rdar://problem/30149465 */
496 assert(!forceCoarse);
497 recursive_pte = &ppte[i];
498 recursive_ptmp = ptmp;
499 } else if ((deferred_pte != NULL) && (&ppte[i] == &recursive_pte[1])) {
500 assert(*deferred_pte == NULL);
501 assert(deferred_ptmp != NULL);
502 *deferred_pte = &ppte[i];
503 *deferred_ptmp = ptmp;
504 } else {
505 ppte[i] = ptmp;
506 }
507 }
508
509 va += ARM_PGBYTES;
510 pa += ARM_PGBYTES;
511 }
512 if (recursive_pte != NULL)
513 *recursive_pte = recursive_ptmp;
514 }
515}
516
517/*
518 * arm_vm_page_granular_prot updates protections by iterating over the L2 entries and
519 * changing them. If a particular chunk necessitates L3 entries (for reasons of
520 * alignment or length, or an explicit request that the entry be fully expanded), we
521 * hand off to arm_vm_page_granular_helper to deal with the L3 chunk of the logic.
522 *
523 * Note that counterintuitively a forceCoarse request is a request to expand the entries
524 * out to L3, i.e. to make *finer* grained mappings. That comes from historical arm32
525 * nomenclature in which the 4K granule is "coarse" vs. the 1K "fine" granule (which we
526 * don't use).
527 */
528static void
529arm_vm_page_granular_prot(vm_offset_t start, unsigned long size,
530 int tte_prot_XN, int pte_prot_APX, int pte_prot_XN, int forceCoarse)
531{
532 pt_entry_t *deferred_pte = NULL, deferred_ptmp = 0;
533 vm_offset_t _end = start + size;
534 vm_offset_t align_start = (start + ARM_TT_L2_OFFMASK) & ~ARM_TT_L2_OFFMASK;
535
536 if (size == 0x0UL)
537 return;
538
539 if (align_start > _end) {
540 arm_vm_page_granular_helper(start, _end, start, pte_prot_APX, pte_prot_XN, forceCoarse, NULL, NULL);
541 return;
542 }
543
544 arm_vm_page_granular_helper(start, align_start, start, pte_prot_APX, pte_prot_XN, forceCoarse, &deferred_pte, &deferred_ptmp);
545
546 while ((_end - align_start) >= ARM_TT_L2_SIZE) {
547 if (forceCoarse)
548 arm_vm_page_granular_helper(align_start, align_start+ARM_TT_L2_SIZE, align_start + 1,
549 pte_prot_APX, pte_prot_XN, forceCoarse, NULL, NULL);
550 else {
551#if __ARM64_TWO_LEVEL_PMAP__
552 tt_entry_t *tte2;
553#else
554 tt_entry_t *tte1, *tte2;
555#endif
556 tt_entry_t tmplate;
557
558#if __ARM64_TWO_LEVEL_PMAP__
559 tte2 = &cpu_tte[((align_start & ARM_TT_L2_INDEX_MASK) >> ARM_TT_L2_SHIFT)];
560#else
561 tte1 = &cpu_tte[((align_start & ARM_TT_L1_INDEX_MASK) >> ARM_TT_L1_SHIFT)];
562 tte2 = &((tt_entry_t*) phystokv((*tte1) & ARM_TTE_TABLE_MASK))[((align_start & ARM_TT_L2_INDEX_MASK) >> ARM_TT_L2_SHIFT)];
563#endif
564
565 tmplate = *tte2;
566
567 tmplate = (tmplate & ~ARM_TTE_BLOCK_APMASK) | ARM_TTE_BLOCK_AP(pte_prot_APX);
568 tmplate = tmplate | ARM_TTE_BLOCK_NX;
569 if (tte_prot_XN)
570 tmplate = tmplate | ARM_TTE_BLOCK_PNX;
571
572 *tte2 = tmplate;
573 }
574 align_start += ARM_TT_L2_SIZE;
575 }
576
577 if (align_start < _end)
578 arm_vm_page_granular_helper(align_start, _end, _end, pte_prot_APX, pte_prot_XN, forceCoarse, &deferred_pte, &deferred_ptmp);
579
580 if (deferred_pte != NULL)
581 *deferred_pte = deferred_ptmp;
582}
583
584static inline void
585arm_vm_page_granular_RNX(vm_offset_t start, unsigned long size, int forceCoarse)
586{
587 arm_vm_page_granular_prot(start, size, 1, AP_RONA, 1, forceCoarse);
588}
589
590static inline void
591arm_vm_page_granular_ROX(vm_offset_t start, unsigned long size, int forceCoarse)
592{
593 arm_vm_page_granular_prot(start, size, 0, AP_RONA, 0, forceCoarse);
594}
595
596static inline void
597arm_vm_page_granular_RWNX(vm_offset_t start, unsigned long size, int forceCoarse)
598{
599 arm_vm_page_granular_prot(start, size, 1, AP_RWNA, 1, forceCoarse);
600}
601
602static inline void
603arm_vm_page_granular_RWX(vm_offset_t start, unsigned long size, int forceCoarse)
604{
605 arm_vm_page_granular_prot(start, size, 0, AP_RWNA, 0, forceCoarse);
606}
607
608void
609arm_vm_prot_init(boot_args * args)
610{
611 /*
612 * Enforce W^X protections on sections that have been identified so far. This will be
613 * further refined for each KEXT's TEXT and DATA segments in readPrelinkedExtensions()
614 */
615 bool use_small_page_mappings = FALSE;
616
617 /*
618 * First off, we'll create mappings for any physical memory preceeding the kernel TEXT.
619 * This is memory that we want to give to the VM; this will be accomplished through an
620 * ml_static_mfree call in arm_vm_prot_finalize. This allows the pmap/vm bootstrap
621 * routines to assume they will have a physically contiguous chunk of memory to deal
622 * with during bootstrap, while reclaiming this memory later.
623 */
624 arm_vm_page_granular_RWNX(gVirtBase, segPRELINKTEXTB - gVirtBase, use_small_page_mappings); // Memory for the VM
625
626 /* Map coalesced kext TEXT segment RWNX for now */
627 arm_vm_page_granular_RWNX(segPRELINKTEXTB, segSizePRELINKTEXT, FALSE); // Refined in OSKext::readPrelinkedExtensions
628
629 /* Map coalesced kext DATA_CONST segment RWNX (could be empty) */
630 arm_vm_page_granular_RWNX(segPLKDATACONSTB, segSizePLKDATACONST, FALSE); // Refined in OSKext::readPrelinkedExtensions
631
632 /* Map coalesced kext TEXT_EXEC segment RWX (could be empty) */
633 arm_vm_page_granular_ROX(segPLKTEXTEXECB, segSizePLKTEXTEXEC, FALSE); // Refined in OSKext::readPrelinkedExtensions
634
635 /* if new segments not present, set space between PRELINK_TEXT and xnu TEXT to RWNX
636 * otherwise we no longer expecting any space between the coalesced kext read only segments and xnu rosegments
637 */
638 if (!segSizePLKDATACONST && !segSizePLKTEXTEXEC) {
639 arm_vm_page_granular_RWNX(segPRELINKTEXTB + segSizePRELINKTEXT, segTEXTB - (segPRELINKTEXTB + segSizePRELINKTEXT), FALSE);
640 } else {
641 /*
642 * If we have the new segments, we should still protect the gap between kext
643 * read-only pages and kernel read-only pages, in the event that this gap
644 * exists.
645 */
646 if ((segPLKDATACONSTB + segSizePLKDATACONST) < segTEXTB) {
647 arm_vm_page_granular_RWNX(segPLKDATACONSTB + segSizePLKDATACONST, segTEXTB - (segPLKDATACONSTB + segSizePLKDATACONST), FALSE);
648 }
649 }
650
651 /*
652 * Protection on kernel text is loose here to allow shenanigans early on. These
653 * protections are tightened in arm_vm_prot_finalize(). This is necessary because
654 * we currently patch LowResetVectorBase in cpu.c.
655 *
656 * TEXT segment contains mach headers and other non-executable data. This will become RONX later.
657 */
658 arm_vm_page_granular_RNX(segTEXTB, segSizeTEXT, FALSE);
659
660 /* Can DATACONST start out and stay RNX?
661 * NO, stuff in this segment gets modified during startup (viz. mac_policy_init()/mac_policy_list)
662 * Make RNX in prot_finalize
663 */
664 arm_vm_page_granular_RWNX(segDATACONSTB, segSizeDATACONST, FALSE);
665
666 /* TEXTEXEC contains read only executable code: becomes ROX in prot_finalize */
667 arm_vm_page_granular_RWX(segTEXTEXECB, segSizeTEXTEXEC, FALSE);
668
669
670 /* DATA segment will remain RWNX */
671 arm_vm_page_granular_RWNX(segDATAB, segSizeDATA, FALSE);
672
673 arm_vm_page_granular_ROX(segKLDB, segSizeKLD, FALSE);
674 arm_vm_page_granular_RWNX(segLINKB, segSizeLINK, FALSE);
675 arm_vm_page_granular_ROX(segLASTB, segSizeLAST, FALSE); // __LAST may be empty, but we cannot assume this
676
677 arm_vm_page_granular_RWNX(segPRELINKDATAB, segSizePRELINKDATA, FALSE); // Prelink __DATA for kexts (RW data)
678
679 if (segSizePLKLLVMCOV > 0)
680 arm_vm_page_granular_RWNX(segPLKLLVMCOVB, segSizePLKLLVMCOV, FALSE); // LLVM code coverage data
681
682 arm_vm_page_granular_RWNX(segPLKLINKEDITB, segSizePLKLINKEDIT, use_small_page_mappings); // Coalesced kext LINKEDIT segment
683
684 arm_vm_page_granular_RWNX(segPRELINKINFOB, segSizePRELINKINFO, FALSE); /* PreLinkInfoDictionary */
685 arm_vm_page_granular_RWNX(end_kern, phystokv(args->topOfKernelData) - end_kern, use_small_page_mappings); /* Device Tree, RAM Disk (if present), bootArgs */
686
687 /*
688 * This is offset by 4 pages to make room for the boot page tables; we could probably
689 * include them in the overall mapping, but we'll be paranoid for now.
690 */
691 vm_offset_t extra = 0;
692#if KASAN
693 /* add the KASAN stolen memory to the physmap */
694 extra = shadow_ptop - shadow_pbase;
695
696 /* record the extent of the physmap */
697 physmap_vbase = phystokv(args->topOfKernelData) + ARM_PGBYTES * 4;
698 physmap_vtop = static_memory_end;
699#endif
700 arm_vm_page_granular_RNX(phystokv(args->topOfKernelData), ARM_PGBYTES * 4, FALSE); // Boot page tables; they should not be mutable.
701 arm_vm_page_granular_RWNX(phystokv(args->topOfKernelData) + ARM_PGBYTES * 4,
702 extra + static_memory_end - ((phystokv(args->topOfKernelData) + ARM_PGBYTES * 4)), use_small_page_mappings); // rest of physmem
703}
704
705void
706arm_vm_prot_finalize(boot_args * args)
707{
708#pragma unused(args)
709 /*
710 * At this point, we are far enough along in the boot process that it will be
711 * safe to free up all of the memory preceeding the kernel. It may in fact
712 * be safe to do this earlier.
713 *
714 * This keeps the memory in the V-to-P mapping, but advertises it to the VM
715 * as usable.
716 */
717
718 /*
719 * if old style PRELINK segment exists, free memory before it, and after it before XNU text
720 * otherwise we're dealing with a new style kernel cache, so we should just free the
721 * memory before PRELINK_TEXT segment, since the rest of the KEXT read only data segments
722 * should be immediately followed by XNU's TEXT segment
723 */
724
725 ml_static_mfree(gVirtBase, segPRELINKTEXTB - gVirtBase);
726
727 if (!segSizePLKDATACONST && !segSizePLKTEXTEXEC) {
728 /* If new segments not present, PRELINK_TEXT is not dynamically sized, free DRAM between it and xnu TEXT */
729 ml_static_mfree(segPRELINKTEXTB + segSizePRELINKTEXT, segTEXTB - (segPRELINKTEXTB + segSizePRELINKTEXT));
730 }
731
732 /*
733 * LowResetVectorBase patching should be done by now, so tighten executable
734 * protections.
735 */
736 arm_vm_page_granular_ROX(segTEXTEXECB, segSizeTEXTEXEC, FALSE);
737
738 /* tighten permissions on kext read only data and code */
739 if (segSizePLKDATACONST && segSizePLKTEXTEXEC) {
740 arm_vm_page_granular_RNX(segPRELINKTEXTB, segSizePRELINKTEXT, FALSE);
741 arm_vm_page_granular_ROX(segPLKTEXTEXECB, segSizePLKTEXTEXEC, FALSE);
742 arm_vm_page_granular_RNX(segPLKDATACONSTB, segSizePLKDATACONST, FALSE);
743 }
744
745#if defined(KERNEL_INTEGRITY_KTRR)
746 /*
747 * __LAST,__pinst should no longer be executable.
748 */
749 arm_vm_page_granular_RNX(segLASTB, segSizeLAST, FALSE);
750
751 /*
752 * Must wait until all other region permissions are set before locking down DATA_CONST
753 * as the kernel static page tables live in DATA_CONST on KTRR enabled systems
754 * and will become immutable.
755 */
756#endif
757 arm_vm_page_granular_RNX(segDATACONSTB, segSizeDATACONST, FALSE);
758
759#ifndef __ARM_L1_PTW__
760 FlushPoC_Dcache();
761#endif
762 flush_mmu_tlb();
763}
764
765#define TBI_USER 0x1
766#define TBI_KERNEL 0x2
767
768boolean_t user_tbi = TRUE;
769
770/*
771 * TBI (top-byte ignore) is an ARMv8 feature for ignoring the top 8 bits of
772 * address accesses. It can be enabled separately for TTBR0 (user) and
773 * TTBR1 (kernel). We enable it by default for user only, but allow both
774 * to be controlled by the 'tbi' boot-arg.
775 */
776static void
777set_tbi(void)
778{
779 uint64_t old_tcr, new_tcr;
780 int tbi = 0;
781
782 if (PE_parse_boot_argn("tbi", &tbi, sizeof(tbi)))
783 user_tbi = ((tbi & TBI_USER) == TBI_USER);
784 old_tcr = new_tcr = get_tcr();
785 new_tcr |= (user_tbi) ? TCR_TBI0_TOPBYTE_IGNORED : 0;
786 new_tcr |= (tbi & TBI_KERNEL) ? TCR_TBI1_TOPBYTE_IGNORED : 0;
787
788 if (old_tcr != new_tcr) {
789 set_tcr(new_tcr);
790 sysreg_restore.tcr_el1 = new_tcr;
791 }
792}
793
794void
795arm_vm_init(uint64_t memory_size, boot_args * args)
796{
797#if !__ARM64_TWO_LEVEL_PMAP__
798 vm_map_address_t va_l1, va_l1_end;
799 pmap_paddr_t pa_l1;
800 tt_entry_t *cpu_l1_tte;
801#else
802 /*
803 * If we are using two level page tables, rather than the
804 * 3 level page tables that xnu defaults to for ARM64,
805 * then a great deal of the code in this path becomes
806 * redundant. As a result, most of the logic having to
807 * do with L1 pages will be excluded from such
808 * configurations in this function.
809 */
810#endif
811 vm_map_address_t va_l2, va_l2_end;
812 pmap_paddr_t pa_l2;
813 tt_entry_t *cpu_l2_tte;
814 pmap_paddr_t boot_ttep;
815 tt_entry_t *boot_tte;
816 uint64_t mem_segments;
817 vm_offset_t ptpage_vaddr;
818
819
820 /*
821 * Get the virtual and physical memory base from boot_args.
822 */
823 gVirtBase = args->virtBase;
824 gPhysBase = args->physBase;
825 gPhysSize = args->memSize;
826 mem_size = args->memSize;
827 if ((memory_size != 0) && (mem_size > memory_size))
828 mem_size = memory_size;
829 if (mem_size > MEM_SIZE_MAX )
830 mem_size = MEM_SIZE_MAX;
831 static_memory_end = gVirtBase + mem_size;
832
833 boot_ttep = args->topOfKernelData;
834 boot_tte = (tt_entry_t *) phystokv(boot_ttep);
835
836 /*
837 * Four pages:
838 * TTBR0 L1, TTBR0 L2 - 1:1 bootstrap mapping.
839 * TTBR1 L1, TTBR1 L2 - kernel mapping
840 */
841 avail_start = boot_ttep + 4*ARM_PGBYTES;
842
843#if defined(KERNEL_INTEGRITY_KTRR)
844 arm_replace_identity_map(args);
845#endif
846
847 /* Initialize invalid tte page */
848 invalid_tte = (tt_entry_t *)alloc_ptpage(TRUE);
849 invalid_ttep = kvtophys((vm_offset_t)invalid_tte);
850 bzero(invalid_tte, ARM_PGBYTES);
851
852 /*
853 * Initialize l1 page table page
854 */
855#if __ARM64_TWO_LEVEL_PMAP__
856 /*
857 * If we're using a two level page table, we still need to
858 * set the cpu_ttep to avail_start, as this will be the root
859 * of our page table regardless of how many levels we are
860 * using.
861 */
862#endif
863 cpu_tte = (tt_entry_t *)alloc_ptpage(TRUE);
864 cpu_ttep = kvtophys((vm_offset_t)cpu_tte);
865 bzero(cpu_tte, ARM_PGBYTES);
866
867 avail_end = gPhysBase + mem_size;
868
869 /*
870 * Initialize l1 and l2 page table pages :
871 * map physical memory at the kernel base virtual address
872 * cover the kernel dynamic address range section
873 *
874 * the so called physical aperture should be statically mapped
875 */
876
877#if !__ARM64_TWO_LEVEL_PMAP__
878 pa_l1 = gPhysBase;
879 va_l1 = gVirtBase;
880 va_l1_end = gVirtBase + mem_size;
881#if KASAN
882 /* add the KASAN stolen memory to the physmap */
883 va_l1_end = gVirtBase + (shadow_ptop - gPhysBase);
884#endif
885 cpu_l1_tte = cpu_tte + ((va_l1 & ARM_TT_L1_INDEX_MASK) >> ARM_TT_L1_SHIFT);
886
887 while (va_l1 < va_l1_end) {
888 tt_entry_t *new_tte = (tt_entry_t *)alloc_ptpage(TRUE);
889 /* Allocate a page and setup L1 Table TTE in L1 */
890 *cpu_l1_tte = (kvtophys((vm_offset_t)new_tte) & ARM_TTE_TABLE_MASK) | ARM_TTE_TYPE_TABLE | ARM_TTE_VALID;
891 bzero((void *)new_tte, ARM_PGBYTES);
892
893 va_l2 = va_l1;
894
895 if (((va_l1 & ~ARM_TT_L1_OFFMASK)+ARM_TT_L1_SIZE) < va_l1) {
896 /* If this is the last L1 entry, it must cover the last mapping. */
897 va_l2_end = va_l1_end;
898 } else {
899 va_l2_end = MIN((va_l1 & ~ARM_TT_L1_OFFMASK)+ARM_TT_L1_SIZE, va_l1_end);
900 }
901
902 pa_l2 = pa_l1;
903 cpu_l2_tte = ((tt_entry_t *) phystokv(((*cpu_l1_tte) & ARM_TTE_TABLE_MASK))) + ((va_l1 & ARM_TT_L2_INDEX_MASK) >> ARM_TT_L2_SHIFT);
904#else
905 va_l2 = gVirtBase;
906 va_l2_end = gVirtBase + mem_size;
907 pa_l2 = gPhysBase;
908 cpu_l2_tte = cpu_tte + ((va_l2 & ARM_TT_L2_INDEX_MASK) >> ARM_TT_L2_SHIFT);
909
910#if KASAN
911 /* add the KASAN stolen memory to the physmap */
912 va_l2_end = gVirtBase + (shadow_ptop - gPhysBase);
913#endif
914
915#endif
916
917 while (va_l2 < va_l2_end) {
918 /* Set up L2 Block TTE in L2 */
919 *cpu_l2_tte = (pa_l2 & ARM_TTE_BLOCK_L2_MASK) | ARM_TTE_TYPE_BLOCK
920 | ARM_TTE_VALID | ARM_TTE_BLOCK_AF
921 | ARM_TTE_BLOCK_AP(AP_RWNA) | ARM_TTE_BLOCK_SH(SH_OUTER_MEMORY)
922 | ARM_TTE_BLOCK_ATTRINDX(CACHE_ATTRINDX_WRITEBACK);
923 va_l2 += ARM_TT_L2_SIZE;
924 pa_l2 += ARM_TT_L2_SIZE;
925 cpu_l2_tte++;
926 }
927#if !__ARM64_TWO_LEVEL_PMAP__
928 cpu_l1_tte++;
929 va_l1 = va_l2;
930 pa_l1 = pa_l2;
931 }
932#endif
933
934 /*
935 * Now retrieve addresses for end, edata, and etext from MACH-O headers
936 */
937 segPRELINKTEXTB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_TEXT", &segSizePRELINKTEXT);
938 segPLKDATACONSTB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PLK_DATA_CONST", &segSizePLKDATACONST);
939 segPLKTEXTEXECB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PLK_TEXT_EXEC", &segSizePLKTEXTEXEC);
940 segTEXTB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__TEXT", &segSizeTEXT);
941 segDATACONSTB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__DATA_CONST", &segSizeDATACONST);
942 segTEXTEXECB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__TEXT_EXEC", &segSizeTEXTEXEC);
943 segDATAB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__DATA", &segSizeDATA);
944 segLINKB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__LINKEDIT", &segSizeLINK);
945 segKLDB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__KLD", &segSizeKLD);
946 segPRELINKDATAB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_DATA", &segSizePRELINKDATA);
947 segPRELINKINFOB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_INFO", &segSizePRELINKINFO);
948 segPLKLLVMCOVB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PLK_LLVM_COV", &segSizePLKLLVMCOV);
949 segPLKLINKEDITB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PLK_LINKEDIT", &segSizePLKLINKEDIT);
950 segLASTB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__LAST", &segSizeLAST);
951
952 (void) PE_parse_boot_argn("use_contiguous_hint", &use_contiguous_hint, sizeof(use_contiguous_hint));
953 assert(segSizePRELINKTEXT < 0x03000000); /* 23355738 */
954
955 /* if one of the new segments is present, the other one better be as well */
956 if (segSizePLKDATACONST || segSizePLKTEXTEXEC) {
957 assert(segSizePLKDATACONST && segSizePLKTEXTEXEC);
958 }
959
960 etext = (vm_offset_t) segTEXTB + segSizeTEXT;
961 sdata = (vm_offset_t) segDATAB;
962 edata = (vm_offset_t) segDATAB + segSizeDATA;
963 end_kern = round_page(getlastaddr()); /* Force end to next page */
964
965 vm_set_page_size();
966
967 vm_kernel_base = segTEXTB;
968 vm_kernel_top = (vm_offset_t) &last_kernel_symbol;
969 vm_kext_base = segPRELINKTEXTB;
970 vm_kext_top = vm_kext_base + segSizePRELINKTEXT;
971
972 vm_prelink_stext = segPRELINKTEXTB;
973 if (!segSizePLKTEXTEXEC && !segSizePLKDATACONST) {
974 vm_prelink_etext = segPRELINKTEXTB + segSizePRELINKTEXT;
975 } else {
976 vm_prelink_etext = segPRELINKTEXTB + segSizePRELINKTEXT + segSizePLKDATACONST + segSizePLKTEXTEXEC;
977 }
978 vm_prelink_sinfo = segPRELINKINFOB;
979 vm_prelink_einfo = segPRELINKINFOB + segSizePRELINKINFO;
980 vm_slinkedit = segLINKB;
981 vm_elinkedit = segLINKB + segSizeLINK;
982
983 vm_prelink_sdata = segPRELINKDATAB;
984 vm_prelink_edata = segPRELINKDATAB + segSizePRELINKDATA;
985
986 arm_vm_prot_init(args);
987
988
989 /*
990 * Initialize the page tables for the low globals:
991 * cover this address range:
992 * LOW_GLOBAL_BASE_ADDRESS + 2MB
993 */
994#if __ARM64_TWO_LEVEL_PMAP__
995 va_l2 = LOW_GLOBAL_BASE_ADDRESS;
996 cpu_l2_tte = cpu_tte + ((va_l2 & ARM_TT_L2_INDEX_MASK) >> ARM_TT_L2_SHIFT);
997#else
998 va_l1 = va_l2 = LOW_GLOBAL_BASE_ADDRESS;
999 cpu_l1_tte = cpu_tte + ((va_l1 & ARM_TT_L1_INDEX_MASK) >> ARM_TT_L1_SHIFT);
1000 cpu_l2_tte = ((tt_entry_t *) phystokv(((*cpu_l1_tte) & ARM_TTE_TABLE_MASK))) + ((va_l2 & ARM_TT_L2_INDEX_MASK) >> ARM_TT_L2_SHIFT);
1001#endif
1002 ptpage_vaddr = alloc_ptpage(TRUE);
1003 *cpu_l2_tte = (kvtophys(ptpage_vaddr) & ARM_TTE_TABLE_MASK) | ARM_TTE_TYPE_TABLE | ARM_TTE_VALID | ARM_TTE_TABLE_PXN | ARM_TTE_TABLE_XN;
1004 bzero((void *)ptpage_vaddr, ARM_PGBYTES);
1005
1006 /*
1007 * Initialize l2 page table pages :
1008 * cover this address range:
1009 * KERNEL_DYNAMIC_ADDR - VM_MAX_KERNEL_ADDRESS
1010 */
1011#if !__ARM64_TWO_LEVEL_PMAP__
1012 va_l1 = (gVirtBase+MEM_SIZE_MAX+ ~0xFFFFFFFFFF800000ULL) & 0xFFFFFFFFFF800000ULL;
1013 va_l1_end = VM_MAX_KERNEL_ADDRESS;
1014 cpu_l1_tte = cpu_tte + ((va_l1 & ARM_TT_L1_INDEX_MASK) >> ARM_TT_L1_SHIFT);
1015
1016 while (va_l1 < va_l1_end) {
1017 if (*cpu_l1_tte == ARM_TTE_EMPTY) {
1018 /* Allocate a page and setup L1 Table TTE in L1 */
1019 ptpage_vaddr = alloc_ptpage(TRUE);
1020 *cpu_l1_tte = (kvtophys(ptpage_vaddr) & ARM_TTE_TABLE_MASK) | ARM_TTE_TYPE_TABLE | ARM_TTE_VALID | ARM_TTE_TABLE_PXN | ARM_TTE_TABLE_XN;
1021 bzero((void *)ptpage_vaddr, ARM_PGBYTES);
1022 }
1023
1024 if ((va_l1 + ARM_TT_L1_SIZE) < va_l1) {
1025 /* If this is the last L1 entry, it must cover the last mapping. */
1026 break;
1027 }
1028
1029 va_l1 += ARM_TT_L1_SIZE;
1030 cpu_l1_tte++;
1031 }
1032#endif
1033
1034#if KASAN
1035 kasan_init();
1036#endif
1037
1038 set_mmu_ttb(invalid_ttep & TTBR_BADDR_MASK);
1039 set_mmu_ttb_alternate(cpu_ttep & TTBR_BADDR_MASK);
1040 set_tbi();
1041 flush_mmu_tlb();
1042
1043 /*
1044 * TODO: We're hardcoding the expected virtual TEXT base here;
1045 * that gives us an ugly dependency on a linker argument in
1046 * the make files. Clean this up, so we don't hardcode it
1047 * twice; this is nothing but trouble.
1048 */
1049 sane_size = mem_size - (avail_start - gPhysBase);
1050 max_mem = mem_size;
1051 vm_kernel_slid_base = segPRELINKTEXTB;
1052 vm_kernel_slid_top = vm_prelink_einfo;
1053 vm_kernel_slide = segTEXTB-0xfffffff007004000;
1054 vm_kernel_stext = segTEXTB;
1055 assert(segDATACONSTB == segTEXTB + segSizeTEXT);
1056 assert(segTEXTEXECB == segDATACONSTB + segSizeDATACONST);
1057 vm_kernel_etext = segTEXTB + segSizeTEXT + segSizeDATACONST + segSizeTEXTEXEC;
1058
1059 pmap_bootstrap((gVirtBase+MEM_SIZE_MAX+ ~0xFFFFFFFFFF800000ULL) & 0xFFFFFFFFFF800000ULL);
1060
1061 /*
1062 * Initialize l3 page table pages :
1063 * cover this address range:
1064 * 2MB + FrameBuffer size + 10MB for each 256MB segment
1065 */
1066
1067 mem_segments = (mem_size + 0x0FFFFFFF) >> 28;
1068
1069#if !__ARM64_TWO_LEVEL_PMAP__
1070 va_l1 = (gVirtBase+MEM_SIZE_MAX+ ~0xFFFFFFFFFF800000ULL) & 0xFFFFFFFFFF800000ULL;
1071 va_l1_end = va_l1 + ((2 + (mem_segments * 10)) << 20);
1072 va_l1_end += round_page(args->Video.v_height * args->Video.v_rowBytes);
1073 va_l1_end = (va_l1_end + 0x00000000007FFFFFULL) & 0xFFFFFFFFFF800000ULL;
1074
1075 cpu_l1_tte = cpu_tte + ((va_l1 & ARM_TT_L1_INDEX_MASK) >> ARM_TT_L1_SHIFT);
1076
1077 while (va_l1 < va_l1_end) {
1078
1079 va_l2 = va_l1;
1080
1081 if (((va_l1 & ~ARM_TT_L1_OFFMASK)+ARM_TT_L1_SIZE) < va_l1) {
1082 /* If this is the last L1 entry, it must cover the last mapping. */
1083 va_l2_end = va_l1_end;
1084 } else {
1085 va_l2_end = MIN((va_l1 & ~ARM_TT_L1_OFFMASK)+ARM_TT_L1_SIZE, va_l1_end);
1086 }
1087
1088 cpu_l2_tte = ((tt_entry_t *) phystokv(((*cpu_l1_tte) & ARM_TTE_TABLE_MASK))) + ((va_l2 & ARM_TT_L2_INDEX_MASK) >> ARM_TT_L2_SHIFT);
1089#else
1090 va_l2 = (gVirtBase+MEM_SIZE_MAX+ ~0xFFFFFFFFFF800000ULL) & 0xFFFFFFFFFF800000ULL;
1091 va_l2_end = va_l2 + ((2 + (mem_segments * 10)) << 20);
1092 va_l2_end += round_page(args->Video.v_height * args->Video.v_rowBytes);
1093 va_l2_end = (va_l2_end + 0x00000000007FFFFFULL) & 0xFFFFFFFFFF800000ULL;
1094 cpu_l2_tte = cpu_tte + ((va_l2 & ARM_TT_L2_INDEX_MASK) >> ARM_TT_L2_SHIFT);
1095#endif
1096
1097 while (va_l2 < va_l2_end) {
1098 pt_entry_t * ptp;
1099 pmap_paddr_t ptp_phys;
1100
1101 /* Allocate a page and setup L3 Table TTE in L2 */
1102 ptp = (pt_entry_t *) alloc_ptpage(FALSE);
1103 ptp_phys = (pmap_paddr_t)kvtophys((vm_offset_t)ptp);
1104
1105 pmap_init_pte_page(kernel_pmap, ptp, va_l2, 3, TRUE);
1106
1107 *cpu_l2_tte = (pa_to_tte (ptp_phys)) | ARM_TTE_TYPE_TABLE | ARM_TTE_VALID | ARM_TTE_TABLE_PXN | ARM_TTE_TABLE_XN;
1108
1109 va_l2 += ARM_TT_L2_SIZE;
1110 cpu_l2_tte++;
1111 };
1112#if !__ARM64_TWO_LEVEL_PMAP__
1113 va_l1 = va_l2_end;
1114 cpu_l1_tte++;
1115 }
1116#endif
1117
1118 /*
1119 * Initialize l3 page table pages :
1120 * cover this address range:
1121 * (VM_MAX_KERNEL_ADDRESS & CPUWINDOWS_BASE_MASK) - VM_MAX_KERNEL_ADDRESS
1122 */
1123#if !__ARM64_TWO_LEVEL_PMAP__
1124 va_l1 = VM_MAX_KERNEL_ADDRESS & CPUWINDOWS_BASE_MASK;
1125 va_l1_end = VM_MAX_KERNEL_ADDRESS;
1126
1127 cpu_l1_tte = cpu_tte + ((va_l1 & ARM_TT_L1_INDEX_MASK) >> ARM_TT_L1_SHIFT);
1128
1129 while (va_l1 < va_l1_end) {
1130
1131 va_l2 = va_l1;
1132
1133 if (((va_l1 & ~ARM_TT_L1_OFFMASK)+ARM_TT_L1_SIZE) < va_l1) {
1134 /* If this is the last L1 entry, it must cover the last mapping. */
1135 va_l2_end = va_l1_end;
1136 } else {
1137 va_l2_end = MIN((va_l1 & ~ARM_TT_L1_OFFMASK)+ARM_TT_L1_SIZE, va_l1_end);
1138 }
1139
1140 cpu_l2_tte = ((tt_entry_t *) phystokv(((*cpu_l1_tte) & ARM_TTE_TABLE_MASK))) + ((va_l2 & ARM_TT_L2_INDEX_MASK) >> ARM_TT_L2_SHIFT);
1141#else
1142 va_l2 = VM_MAX_KERNEL_ADDRESS & CPUWINDOWS_BASE_MASK;
1143 va_l2_end = VM_MAX_KERNEL_ADDRESS;
1144 cpu_l2_tte = cpu_tte + ((va_l2 & ARM_TT_L2_INDEX_MASK) >> ARM_TT_L2_SHIFT);
1145#endif
1146
1147 while (va_l2 < va_l2_end) {
1148 pt_entry_t * ptp;
1149 pmap_paddr_t ptp_phys;
1150
1151 /* Allocate a page and setup L3 Table TTE in L2 */
1152 ptp = (pt_entry_t *) alloc_ptpage(FALSE);
1153 ptp_phys = (pmap_paddr_t)kvtophys((vm_offset_t)ptp);
1154
1155 pmap_init_pte_page(kernel_pmap, ptp, va_l2, 3, TRUE);
1156
1157 *cpu_l2_tte = (pa_to_tte (ptp_phys)) | ARM_TTE_TYPE_TABLE | ARM_TTE_VALID | ARM_TTE_TABLE_PXN | ARM_TTE_TABLE_XN;
1158
1159 va_l2 += ARM_TT_L2_SIZE;
1160 cpu_l2_tte++;
1161 };
1162#if !__ARM64_TWO_LEVEL_PMAP__
1163 va_l1 = va_l2_end;
1164 cpu_l1_tte++;
1165 }
1166#endif
1167
1168#if __ARM64_PMAP_SUBPAGE_L1__ && __ARM_16K_PG__
1169 /*
1170 * In this configuration, the bootstrap mappings (arm_vm_init) and
1171 * the heap mappings occupy separate L1 regions. Explicitly set up
1172 * the heap L1 allocations here.
1173 */
1174 va_l1 = VM_MIN_KERNEL_ADDRESS & ~ARM_TT_L1_OFFMASK;
1175 cpu_l1_tte = cpu_tte + ((va_l1 & ARM_TT_L1_INDEX_MASK) >> ARM_TT_L1_SHIFT);
1176
1177 while ((va_l1 >= (VM_MIN_KERNEL_ADDRESS & ~ARM_TT_L1_OFFMASK)) && (va_l1 < VM_MAX_KERNEL_ADDRESS)) {
1178 /*
1179 * If the L1 entry has not yet been allocated, allocate it
1180 * now and treat it as a heap table.
1181 */
1182 if (*cpu_l1_tte == ARM_TTE_EMPTY) {
1183 tt_entry_t *new_tte = (tt_entry_t*)alloc_ptpage(FALSE);
1184 bzero(new_tte, ARM_PGBYTES);
1185 *cpu_l1_tte = (kvtophys((vm_offset_t)new_tte) & ARM_TTE_TABLE_MASK) | ARM_TTE_TYPE_TABLE | ARM_TTE_VALID | ARM_TTE_TABLE_PXN | ARM_TTE_TABLE_XN;
1186 }
1187
1188 cpu_l1_tte++;
1189 va_l1 += ARM_TT_L1_SIZE;
1190 }
1191#endif
1192
1193 /*
1194 * Adjust avail_start so that the range that the VM owns
1195 * starts on a PAGE_SIZE aligned boundary.
1196 */
1197 avail_start = (avail_start + PAGE_MASK) & ~PAGE_MASK;
1198
1199
1200 first_avail = avail_start;
1201 patch_low_glo_static_region(args->topOfKernelData, avail_start - args->topOfKernelData);
1202}
1203