]> git.saurik.com Git - apple/xnu.git/blame - osfmk/arm64/arm_vm_init.c
xnu-6153.141.1.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
cb323159
A
33#include <kern/assert.h>
34#include <kern/misc_protos.h>
35#include <kern/monotonic.h>
5ba3f43e
A
36#include <mach/vm_types.h>
37#include <mach/vm_param.h>
5ba3f43e
A
38#include <vm/vm_kern.h>
39#include <vm/vm_page.h>
40#include <vm/pmap.h>
41
cb323159 42#include <machine/atomic.h>
5ba3f43e
A
43#include <arm64/proc_reg.h>
44#include <arm64/lowglobals.h>
45#include <arm/cpu_data_internal.h>
46#include <arm/misc_protos.h>
47#include <pexpert/arm64/boot.h>
d9a64523 48#include <pexpert/device_tree.h>
5ba3f43e
A
49
50#include <libkern/kernel_mach_header.h>
51#include <libkern/section_keywords.h>
52
d9a64523 53#include <san/kasan.h>
5c9f4661
A
54
55#if __ARM_KERNEL_PROTECT__
56/*
57 * If we want to support __ARM_KERNEL_PROTECT__, we need a sufficient amount of
58 * mappable space preceeding the kernel (as we unmap the kernel by cutting the
59 * range covered by TTBR1 in half). This must also cover the exception vectors.
60 */
61static_assert(KERNEL_PMAP_HEAP_RANGE_START > ARM_KERNEL_PROTECT_EXCEPTION_START);
62
63/* The exception vectors and the kernel cannot share root TTEs. */
64static_assert((KERNEL_PMAP_HEAP_RANGE_START & ~ARM_TT_ROOT_OFFMASK) > ARM_KERNEL_PROTECT_EXCEPTION_START);
65
66/*
67 * We must have enough space in the TTBR1_EL1 range to create the EL0 mapping of
68 * the exception vectors.
69 */
70static_assert((((~ARM_KERNEL_PROTECT_EXCEPTION_START) + 1) * 2ULL) <= (ARM_TT_ROOT_SIZE + ARM_TT_ROOT_INDEX_MASK));
71#endif /* __ARM_KERNEL_PROTECT__ */
72
c6bf4f31
A
73#if __APRR_SUPPORTED__ && XNU_MONITOR
74/*
75 * If APRR is supported, setting XN on L1/L2 table entries will shift the effective
76 * APRR index of L3 PTEs covering PPL-protected pages in the kernel dynamic region
77 * from PPL R/W to kernel R/W. That will effectively remove PPL write protection
78 * from those pages. Avoid setting XN at the table level for MONITOR-enabled builds
79 * that are backed by APRR.
80 */
81#define ARM_DYNAMIC_TABLE_XN ARM_TTE_TABLE_PXN
82#else
d9a64523 83#define ARM_DYNAMIC_TABLE_XN (ARM_TTE_TABLE_PXN | ARM_TTE_TABLE_XN)
c6bf4f31 84#endif
d9a64523 85
5ba3f43e
A
86#if KASAN
87extern vm_offset_t shadow_pbase;
88extern vm_offset_t shadow_ptop;
89extern vm_offset_t physmap_vbase;
90extern vm_offset_t physmap_vtop;
91#endif
92
93/*
94 * Denotes the end of xnu.
95 */
96extern void *last_kernel_symbol;
97
d9a64523
A
98extern void arm64_replace_bootstack(cpu_data_t*);
99extern void PE_slide_devicetree(vm_offset_t);
100
5ba3f43e
A
101/*
102 * KASLR parameters
103 */
104SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kernel_base;
105SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kernel_top;
106SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kext_base;
107SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kext_top;
108SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kernel_stext;
109SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kernel_etext;
110SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kernel_slide;
111SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kernel_slid_base;
112SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kernel_slid_top;
113
114SECURITY_READ_ONLY_LATE(vm_offset_t) vm_prelink_stext;
115SECURITY_READ_ONLY_LATE(vm_offset_t) vm_prelink_etext;
116SECURITY_READ_ONLY_LATE(vm_offset_t) vm_prelink_sdata;
117SECURITY_READ_ONLY_LATE(vm_offset_t) vm_prelink_edata;
118SECURITY_READ_ONLY_LATE(vm_offset_t) vm_prelink_sinfo;
119SECURITY_READ_ONLY_LATE(vm_offset_t) vm_prelink_einfo;
120SECURITY_READ_ONLY_LATE(vm_offset_t) vm_slinkedit;
121SECURITY_READ_ONLY_LATE(vm_offset_t) vm_elinkedit;
122
d9a64523
A
123SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kernel_builtinkmod_text;
124SECURITY_READ_ONLY_LATE(vm_offset_t) vm_kernel_builtinkmod_text_end;
125
5ba3f43e
A
126/* Used by <mach/arm/vm_param.h> */
127SECURITY_READ_ONLY_LATE(unsigned long) gVirtBase;
128SECURITY_READ_ONLY_LATE(unsigned long) gPhysBase;
129SECURITY_READ_ONLY_LATE(unsigned long) gPhysSize;
d9a64523
A
130SECURITY_READ_ONLY_LATE(unsigned long) gT0Sz = T0SZ_BOOT;
131SECURITY_READ_ONLY_LATE(unsigned long) gT1Sz = T1SZ_BOOT;
132
cb323159
A
133/* 23543331 - step 1 of kext / kernel __TEXT and __DATA colocation is to move
134 * all kexts before the kernel. This is only for arm64 devices and looks
d9a64523
A
135 * something like the following:
136 * -- vmaddr order --
137 * 0xffffff8004004000 __PRELINK_TEXT
138 * 0xffffff8007004000 __TEXT (xnu)
139 * 0xffffff80075ec000 __DATA (xnu)
140 * 0xffffff80076dc000 __KLD (xnu)
141 * 0xffffff80076e0000 __LAST (xnu)
142 * 0xffffff80076e4000 __LINKEDIT (xnu)
143 * 0xffffff80076e4000 __PRELINK_DATA (not used yet)
144 * 0xffffff800782c000 __PRELINK_INFO
145 * 0xffffff80078e4000 -- End of kernelcache
146 */
5ba3f43e 147
d9a64523
A
148/* 24921709 - make XNU ready for KTRR
149 *
150 * Two possible kernel cache layouts, depending on which kcgen is being used.
151 * VAs increasing downwards.
152 * Old KCGEN:
153 *
154 * __PRELINK_TEXT
155 * __TEXT
156 * __DATA_CONST
157 * __TEXT_EXEC
158 * __KLD
159 * __LAST
160 * __DATA
161 * __PRELINK_DATA (expected empty)
162 * __LINKEDIT
163 * __PRELINK_INFO
164 *
165 * New kcgen:
166 *
167 * __PRELINK_TEXT <--- First KTRR (ReadOnly) segment
168 * __PLK_DATA_CONST
169 * __PLK_TEXT_EXEC
170 * __TEXT
171 * __DATA_CONST
172 * __TEXT_EXEC
173 * __KLD
174 * __LAST <--- Last KTRR (ReadOnly) segment
175 * __DATA
176 * __BOOTDATA (if present)
177 * __LINKEDIT
178 * __PRELINK_DATA (expected populated now)
179 * __PLK_LINKEDIT
180 * __PRELINK_INFO
181 *
5ba3f43e 182 */
d9a64523 183
5ba3f43e
A
184vm_offset_t mem_size; /* Size of actual physical memory present
185 * minus any performance buffer and possibly
186 * limited by mem_limit in bytes */
187uint64_t mem_actual; /* The "One True" physical memory size
188 * actually, it's the highest physical
189 * address + 1 */
190uint64_t max_mem; /* Size of physical memory (bytes), adjusted
191 * by maxmem */
192uint64_t sane_size; /* Memory size to use for defaults
193 * calculations */
194/* This no longer appears to be used; kill it? */
195addr64_t vm_last_addr = VM_MAX_KERNEL_ADDRESS; /* Highest kernel
196 * virtual address known
197 * to the VM system */
198
d9a64523
A
199SECURITY_READ_ONLY_LATE(vm_offset_t) segEXTRADATA;
200SECURITY_READ_ONLY_LATE(unsigned long) segSizeEXTRADATA;
201
202SECURITY_READ_ONLY_LATE(vm_offset_t) segLOWESTTEXT;
cb323159 203SECURITY_READ_ONLY_LATE(vm_offset_t) segLOWEST;
d9a64523 204
5ba3f43e
A
205SECURITY_READ_ONLY_LATE(static vm_offset_t) segTEXTB;
206SECURITY_READ_ONLY_LATE(static unsigned long) segSizeTEXT;
207
c6bf4f31
A
208#if XNU_MONITOR
209SECURITY_READ_ONLY_LATE(vm_offset_t) segPPLTEXTB;
210SECURITY_READ_ONLY_LATE(unsigned long) segSizePPLTEXT;
211
212SECURITY_READ_ONLY_LATE(vm_offset_t) segPPLTRAMPB;
213SECURITY_READ_ONLY_LATE(unsigned long) segSizePPLTRAMP;
214
215SECURITY_READ_ONLY_LATE(vm_offset_t) segPPLDATACONSTB;
216SECURITY_READ_ONLY_LATE(unsigned long) segSizePPLDATACONST;
217SECURITY_READ_ONLY_LATE(void *) pmap_stacks_start = NULL;
218SECURITY_READ_ONLY_LATE(void *) pmap_stacks_end = NULL;
219#endif
5ba3f43e
A
220
221SECURITY_READ_ONLY_LATE(static vm_offset_t) segDATACONSTB;
222SECURITY_READ_ONLY_LATE(static unsigned long) segSizeDATACONST;
223
224SECURITY_READ_ONLY_LATE(static vm_offset_t) segTEXTEXECB;
225SECURITY_READ_ONLY_LATE(static unsigned long) segSizeTEXTEXEC;
226
227SECURITY_READ_ONLY_LATE(static vm_offset_t) segDATAB;
228SECURITY_READ_ONLY_LATE(static unsigned long) segSizeDATA;
229
c6bf4f31
A
230#if XNU_MONITOR
231SECURITY_READ_ONLY_LATE(vm_offset_t) segPPLDATAB;
232SECURITY_READ_ONLY_LATE(unsigned long) segSizePPLDATA;
233#endif
5ba3f43e 234
d9a64523
A
235SECURITY_READ_ONLY_LATE(vm_offset_t) segBOOTDATAB;
236SECURITY_READ_ONLY_LATE(unsigned long) segSizeBOOTDATA;
237extern vm_offset_t intstack_low_guard;
238extern vm_offset_t intstack_high_guard;
239extern vm_offset_t excepstack_high_guard;
240
5ba3f43e
A
241SECURITY_READ_ONLY_LATE(static vm_offset_t) segLINKB;
242SECURITY_READ_ONLY_LATE(static unsigned long) segSizeLINK;
243
244SECURITY_READ_ONLY_LATE(static vm_offset_t) segKLDB;
245SECURITY_READ_ONLY_LATE(static unsigned long) segSizeKLD;
d9a64523
A
246SECURITY_READ_ONLY_LATE(vm_offset_t) segLASTB;
247SECURITY_READ_ONLY_LATE(unsigned long) segSizeLAST;
5ba3f43e
A
248
249SECURITY_READ_ONLY_LATE(vm_offset_t) segPRELINKTEXTB;
250SECURITY_READ_ONLY_LATE(unsigned long) segSizePRELINKTEXT;
251
252SECURITY_READ_ONLY_LATE(static vm_offset_t) segPLKTEXTEXECB;
253SECURITY_READ_ONLY_LATE(static unsigned long) segSizePLKTEXTEXEC;
254
255SECURITY_READ_ONLY_LATE(static vm_offset_t) segPLKDATACONSTB;
256SECURITY_READ_ONLY_LATE(static unsigned long) segSizePLKDATACONST;
257
258SECURITY_READ_ONLY_LATE(static vm_offset_t) segPRELINKDATAB;
259SECURITY_READ_ONLY_LATE(static unsigned long) segSizePRELINKDATA;
260
261SECURITY_READ_ONLY_LATE(static vm_offset_t) segPLKLLVMCOVB = 0;
262SECURITY_READ_ONLY_LATE(static unsigned long) segSizePLKLLVMCOV = 0;
263
264SECURITY_READ_ONLY_LATE(static vm_offset_t) segPLKLINKEDITB;
265SECURITY_READ_ONLY_LATE(static unsigned long) segSizePLKLINKEDIT;
266
267SECURITY_READ_ONLY_LATE(static vm_offset_t) segPRELINKINFOB;
268SECURITY_READ_ONLY_LATE(static unsigned long) segSizePRELINKINFO;
269
270SECURITY_READ_ONLY_LATE(static boolean_t) use_contiguous_hint = TRUE;
271
272SECURITY_READ_ONLY_LATE(unsigned) PAGE_SHIFT_CONST;
273
274SECURITY_READ_ONLY_LATE(vm_offset_t) end_kern;
275SECURITY_READ_ONLY_LATE(vm_offset_t) etext;
276SECURITY_READ_ONLY_LATE(vm_offset_t) sdata;
277SECURITY_READ_ONLY_LATE(vm_offset_t) edata;
278
279vm_offset_t alloc_ptpage(boolean_t map_static);
280SECURITY_READ_ONLY_LATE(vm_offset_t) ropage_next;
281
282/*
283 * Bootstrap the system enough to run with virtual memory.
284 * Map the kernel's code and data, and allocate the system page table.
285 * Page_size must already be set.
286 *
287 * Parameters:
288 * first_avail: first available physical page -
289 * after kernel page tables
290 * avail_start: PA of first physical page
291 * avail_end: PA of last physical page
292 */
293SECURITY_READ_ONLY_LATE(vm_offset_t) first_avail;
294SECURITY_READ_ONLY_LATE(vm_offset_t) static_memory_end;
295SECURITY_READ_ONLY_LATE(pmap_paddr_t) avail_start;
296SECURITY_READ_ONLY_LATE(pmap_paddr_t) avail_end;
d9a64523 297SECURITY_READ_ONLY_LATE(pmap_paddr_t) real_avail_end;
cb323159 298SECURITY_READ_ONLY_LATE(unsigned long) real_phys_size;
5ba3f43e 299
5c9f4661
A
300#if __ARM_KERNEL_PROTECT__
301extern void ExceptionVectorsBase;
302extern void ExceptionVectorsEnd;
303#endif /* __ARM_KERNEL_PROTECT__ */
304
d9a64523
A
305typedef struct {
306 pmap_paddr_t pa;
307 vm_map_address_t va;
308 vm_size_t len;
309} ptov_table_entry;
310
311#define PTOV_TABLE_SIZE 8
312SECURITY_READ_ONLY_LATE(static ptov_table_entry) ptov_table[PTOV_TABLE_SIZE];
313SECURITY_READ_ONLY_LATE(static boolean_t) kva_active = FALSE;
314
315
316vm_map_address_t
317phystokv(pmap_paddr_t pa)
318{
319 for (size_t i = 0; (i < PTOV_TABLE_SIZE) && (ptov_table[i].len != 0); i++) {
320 if ((pa >= ptov_table[i].pa) && (pa < (ptov_table[i].pa + ptov_table[i].len)))
321 return (pa - ptov_table[i].pa + ptov_table[i].va);
322 }
cb323159 323 assertf((pa - gPhysBase) < real_phys_size, "%s: illegal PA: 0x%llx", __func__, (uint64_t)pa);
d9a64523
A
324 return (pa - gPhysBase + gVirtBase);
325}
326
327vm_map_address_t
328phystokv_range(pmap_paddr_t pa, vm_size_t *max_len)
329{
330 vm_size_t len;
331 for (size_t i = 0; (i < PTOV_TABLE_SIZE) && (ptov_table[i].len != 0); i++) {
332 if ((pa >= ptov_table[i].pa) && (pa < (ptov_table[i].pa + ptov_table[i].len))) {
333 len = ptov_table[i].len - (pa - ptov_table[i].pa);
334 if (*max_len > len)
335 *max_len = len;
336 return (pa - ptov_table[i].pa + ptov_table[i].va);
337 }
338 }
339 len = PAGE_SIZE - (pa & PAGE_MASK);
340 if (*max_len > len)
341 *max_len = len;
cb323159 342 assertf((pa - gPhysBase) < real_phys_size, "%s: illegal PA: 0x%llx", __func__, (uint64_t)pa);
d9a64523
A
343 return (pa - gPhysBase + gVirtBase);
344}
345
346vm_offset_t
347ml_static_vtop(vm_offset_t va)
348{
349 for (size_t i = 0; (i < PTOV_TABLE_SIZE) && (ptov_table[i].len != 0); i++) {
350 if ((va >= ptov_table[i].va) && (va < (ptov_table[i].va + ptov_table[i].len)))
351 return (va - ptov_table[i].va + ptov_table[i].pa);
352 }
cb323159 353 assertf(((vm_address_t)(va) - gVirtBase) < gPhysSize, "%s: illegal VA: %p", __func__, (void*)va);
d9a64523
A
354 return ((vm_address_t)(va) - gVirtBase + gPhysBase);
355}
356
5ba3f43e
A
357/*
358 * This rounds the given address up to the nearest boundary for a PTE contiguous
359 * hint.
360 */
361static vm_offset_t
362round_up_pte_hint_address(vm_offset_t address)
363{
364 vm_offset_t hint_size = ARM_PTE_SIZE << ARM_PTE_HINT_ENTRIES_SHIFT;
365 return ((address + (hint_size - 1)) & ~(hint_size - 1));
366}
367
368/* allocate a page for a page table: we support static and dynamic mappings.
369 *
370 * returns a virtual address for the allocated page
371 *
372 * for static mappings, we allocate from the region ropagetable_begin to ro_pagetable_end-1,
373 * which is defined in the DATA_CONST segment and will be protected RNX when vm_prot_finalize runs.
374 *
375 * for dynamic mappings, we allocate from avail_start, which should remain RWNX.
376 */
377
378vm_offset_t alloc_ptpage(boolean_t map_static) {
379 vm_offset_t vaddr;
380
c6bf4f31 381#if !(defined(KERNEL_INTEGRITY_KTRR) || defined(KERNEL_INTEGRITY_CTRR))
5ba3f43e
A
382 map_static = FALSE;
383#endif
384
385 if (!ropage_next) {
386 ropage_next = (vm_offset_t)&ropagetable_begin;
387 }
388
389 if (map_static) {
390 assert(ropage_next < (vm_offset_t)&ropagetable_end);
391
392 vaddr = ropage_next;
393 ropage_next += ARM_PGBYTES;
394
395 return vaddr;
396 } else {
397 vaddr = phystokv(avail_start);
398 avail_start += ARM_PGBYTES;
399
400 return vaddr;
401 }
402}
403
404#if DEBUG
405
406void dump_kva_l2(vm_offset_t tt_base, tt_entry_t *tt, int indent, uint64_t *rosz_out, uint64_t *rwsz_out);
407
408void dump_kva_l2(vm_offset_t tt_base, tt_entry_t *tt, int indent, uint64_t *rosz_out, uint64_t *rwsz_out) {
409 unsigned int i;
410 boolean_t cur_ro, prev_ro = 0;
411 int start_entry = -1;
412 tt_entry_t cur, prev = 0;
413 pmap_paddr_t robegin = kvtophys((vm_offset_t)&ropagetable_begin);
414 pmap_paddr_t roend = kvtophys((vm_offset_t)&ropagetable_end);
415 boolean_t tt_static = kvtophys((vm_offset_t)tt) >= robegin &&
416 kvtophys((vm_offset_t)tt) < roend;
417
418 for(i=0; i<TTE_PGENTRIES; i++) {
419 int tte_type = tt[i] & ARM_TTE_TYPE_MASK;
420 cur = tt[i] & ARM_TTE_TABLE_MASK;
421
422 if (tt_static) {
423 /* addresses mapped by this entry are static if it is a block mapping,
424 * or the table was allocated from the RO page table region */
425 cur_ro = (tte_type == ARM_TTE_TYPE_BLOCK) || (cur >= robegin && cur < roend);
426 } else {
427 cur_ro = 0;
428 }
429
430 if ((cur == 0 && prev != 0) || (cur_ro != prev_ro && prev != 0)) { // falling edge
431 uintptr_t start,end,sz;
432
433 start = (uintptr_t)start_entry << ARM_TT_L2_SHIFT;
434 start += tt_base;
435 end = ((uintptr_t)i << ARM_TT_L2_SHIFT) - 1;
436 end += tt_base;
437
438 sz = end - start + 1;
439 printf("%*s0x%08x_%08x-0x%08x_%08x %s (%luMB)\n",
440 indent*4, "",
441 (uint32_t)(start >> 32),(uint32_t)start,
442 (uint32_t)(end >> 32),(uint32_t)end,
443 prev_ro ? "Static " : "Dynamic",
444 (sz >> 20));
445
446 if (prev_ro) {
447 *rosz_out += sz;
448 } else {
449 *rwsz_out += sz;
450 }
451 }
452
453 if ((prev == 0 && cur != 0) || cur_ro != prev_ro) { // rising edge: set start
454 start_entry = i;
455 }
456
457 prev = cur;
458 prev_ro = cur_ro;
459 }
460}
461
462void dump_kva_space() {
463 uint64_t tot_rosz=0, tot_rwsz=0;
464 int ro_ptpages, rw_ptpages;
465 pmap_paddr_t robegin = kvtophys((vm_offset_t)&ropagetable_begin);
466 pmap_paddr_t roend = kvtophys((vm_offset_t)&ropagetable_end);
467 boolean_t root_static = kvtophys((vm_offset_t)cpu_tte) >= robegin &&
468 kvtophys((vm_offset_t)cpu_tte) < roend;
469 uint64_t kva_base = ~((1ULL << (64 - T1SZ_BOOT)) - 1);
470
471 printf("Root page table: %s\n", root_static ? "Static" : "Dynamic");
472
5ba3f43e
A
473 for(unsigned int i=0; i<TTE_PGENTRIES; i++) {
474 pmap_paddr_t cur;
475 boolean_t cur_ro;
476 uintptr_t start,end;
477 uint64_t rosz = 0, rwsz = 0;
478
479 if ((cpu_tte[i] & ARM_TTE_VALID) == 0)
480 continue;
481
482 cur = cpu_tte[i] & ARM_TTE_TABLE_MASK;
483 start = (uint64_t)i << ARM_TT_L1_SHIFT;
484 start = start + kva_base;
485 end = start + (ARM_TT_L1_SIZE - 1);
486 cur_ro = cur >= robegin && cur < roend;
487
488 printf("0x%08x_%08x-0x%08x_%08x %s\n",
489 (uint32_t)(start >> 32),(uint32_t)start,
490 (uint32_t)(end >> 32),(uint32_t)end,
491 cur_ro ? "Static " : "Dynamic");
492
493 dump_kva_l2(start, (tt_entry_t*)phystokv(cur), 1, &rosz, &rwsz);
494 tot_rosz += rosz;
495 tot_rwsz += rwsz;
496 }
5ba3f43e
A
497
498 printf("L2 Address space mapped: Static %lluMB Dynamic %lluMB Total %lluMB\n",
499 tot_rosz >> 20,
500 tot_rwsz >> 20,
501 (tot_rosz >> 20) + (tot_rwsz >> 20));
502
503 ro_ptpages = (int)((ropage_next - (vm_offset_t)&ropagetable_begin) >> ARM_PGSHIFT);
504 rw_ptpages = (int)(lowGlo.lgStaticSize >> ARM_PGSHIFT);
505 printf("Pages used: static %d dynamic %d\n", ro_ptpages, rw_ptpages);
506}
507
508#endif /* DEBUG */
509
c6bf4f31 510#if __ARM_KERNEL_PROTECT__ || XNU_MONITOR
5c9f4661
A
511/*
512 * arm_vm_map:
513 * root_ttp: The kernel virtual address for the root of the target page tables
514 * vaddr: The target virtual address
515 * pte: A page table entry value (may be ARM_PTE_EMPTY)
516 *
517 * This function installs pte at vaddr in root_ttp. Any page table pages needed
518 * to install pte will be allocated by this function.
519 */
520static void
521arm_vm_map(tt_entry_t * root_ttp, vm_offset_t vaddr, pt_entry_t pte)
522{
523 vm_offset_t ptpage = 0;
524 tt_entry_t * ttp = root_ttp;
525
5c9f4661
A
526 tt_entry_t * l1_ttep = NULL;
527 tt_entry_t l1_tte = 0;
5c9f4661
A
528
529 tt_entry_t * l2_ttep = NULL;
530 tt_entry_t l2_tte = 0;
531 pt_entry_t * ptep = NULL;
532 pt_entry_t cpte = 0;
533
534 /*
535 * Walk the target page table to find the PTE for the given virtual
536 * address. Allocate any page table pages needed to do this.
537 */
5c9f4661
A
538 l1_ttep = ttp + ((vaddr & ARM_TT_L1_INDEX_MASK) >> ARM_TT_L1_SHIFT);
539 l1_tte = *l1_ttep;
540
541 if (l1_tte == ARM_TTE_EMPTY) {
542 ptpage = alloc_ptpage(TRUE);
543 bzero((void *)ptpage, ARM_PGBYTES);
544 l1_tte = kvtophys(ptpage);
545 l1_tte &= ARM_TTE_TABLE_MASK;
546 l1_tte |= ARM_TTE_VALID | ARM_TTE_TYPE_TABLE;
547 *l1_ttep = l1_tte;
548 ptpage = 0;
549 }
550
551 ttp = (tt_entry_t *)phystokv(l1_tte & ARM_TTE_TABLE_MASK);
5c9f4661
A
552
553 l2_ttep = ttp + ((vaddr & ARM_TT_L2_INDEX_MASK) >> ARM_TT_L2_SHIFT);
554 l2_tte = *l2_ttep;
555
556 if (l2_tte == ARM_TTE_EMPTY) {
557 ptpage = alloc_ptpage(TRUE);
558 bzero((void *)ptpage, ARM_PGBYTES);
559 l2_tte = kvtophys(ptpage);
560 l2_tte &= ARM_TTE_TABLE_MASK;
561 l2_tte |= ARM_TTE_VALID | ARM_TTE_TYPE_TABLE;
562 *l2_ttep = l2_tte;
563 ptpage = 0;
564 }
565
566 ttp = (tt_entry_t *)phystokv(l2_tte & ARM_TTE_TABLE_MASK);
567
568 ptep = ttp + ((vaddr & ARM_TT_L3_INDEX_MASK) >> ARM_TT_L3_SHIFT);
569 cpte = *ptep;
570
571 /*
572 * If the existing PTE is not empty, then we are replacing a valid
573 * mapping.
574 */
575 if (cpte != ARM_PTE_EMPTY) {
576 panic("%s: cpte=%#llx is not empty, "
577 "vaddr=%#lx, pte=%#llx",
578 __FUNCTION__, cpte,
579 vaddr, pte);
580 }
581
582 *ptep = pte;
583}
584
c6bf4f31 585#endif // __ARM_KERNEL_PROTECT || XNU_MONITOR
cb323159
A
586
587#if __ARM_KERNEL_PROTECT__
588
5c9f4661
A
589/*
590 * arm_vm_kernel_el0_map:
591 * vaddr: The target virtual address
592 * pte: A page table entry value (may be ARM_PTE_EMPTY)
593 *
594 * This function installs pte at vaddr for the EL0 kernel mappings.
595 */
596static void
597arm_vm_kernel_el0_map(vm_offset_t vaddr, pt_entry_t pte)
598{
599 /* Calculate where vaddr will be in the EL1 kernel page tables. */
600 vm_offset_t kernel_pmap_vaddr = vaddr - ((ARM_TT_ROOT_INDEX_MASK + ARM_TT_ROOT_SIZE) / 2ULL);
601 arm_vm_map(cpu_tte, kernel_pmap_vaddr, pte);
602}
603
604/*
605 * arm_vm_kernel_el1_map:
606 * vaddr: The target virtual address
607 * pte: A page table entry value (may be ARM_PTE_EMPTY)
608 *
609 * This function installs pte at vaddr for the EL1 kernel mappings.
610 */
611static void
612arm_vm_kernel_el1_map(vm_offset_t vaddr, pt_entry_t pte) {
613 arm_vm_map(cpu_tte, vaddr, pte);
614}
615
616/*
617 * arm_vm_kernel_pte:
618 * vaddr: The target virtual address
619 *
620 * This function returns the PTE value for the given vaddr from the kernel page
621 * tables. If the region has been been block mapped, we return what an
622 * equivalent PTE value would be (as regards permissions and flags). We also
623 * remove the HINT bit (as we are not necessarily creating contiguous mappings.
624 */
625static pt_entry_t
626arm_vm_kernel_pte(vm_offset_t vaddr)
627{
628 tt_entry_t * ttp = cpu_tte;
629 tt_entry_t * ttep = NULL;
630 tt_entry_t tte = 0;
631 pt_entry_t * ptep = NULL;
632 pt_entry_t pte = 0;
633
5c9f4661
A
634 ttep = ttp + ((vaddr & ARM_TT_L1_INDEX_MASK) >> ARM_TT_L1_SHIFT);
635 tte = *ttep;
636
637 assert(tte & ARM_TTE_VALID);
638
639 if ((tte & ARM_TTE_TYPE_MASK) == ARM_TTE_TYPE_BLOCK) {
640 /* This is a block mapping; return the equivalent PTE value. */
641 pte = (pt_entry_t)(tte & ~ARM_TTE_TYPE_MASK);
642 pte |= ARM_PTE_TYPE_VALID;
643 pte |= vaddr & ((ARM_TT_L1_SIZE - 1) & ARM_PTE_PAGE_MASK);
644 pte &= ~ARM_PTE_HINT_MASK;
645 return pte;
646 }
647
648 ttp = (tt_entry_t *)phystokv(tte & ARM_TTE_TABLE_MASK);
5c9f4661
A
649 ttep = ttp + ((vaddr & ARM_TT_L2_INDEX_MASK) >> ARM_TT_L2_SHIFT);
650 tte = *ttep;
651
652 assert(tte & ARM_TTE_VALID);
653
654 if ((tte & ARM_TTE_TYPE_MASK) == ARM_TTE_TYPE_BLOCK) {
655 /* This is a block mapping; return the equivalent PTE value. */
656 pte = (pt_entry_t)(tte & ~ARM_TTE_TYPE_MASK);
657 pte |= ARM_PTE_TYPE_VALID;
658 pte |= vaddr & ((ARM_TT_L2_SIZE - 1) & ARM_PTE_PAGE_MASK);
659 pte &= ~ARM_PTE_HINT_MASK;
660 return pte;
661 }
662
663 ttp = (tt_entry_t *)phystokv(tte & ARM_TTE_TABLE_MASK);
664
665 ptep = ttp + ((vaddr & ARM_TT_L3_INDEX_MASK) >> ARM_TT_L3_SHIFT);
666 pte = *ptep;
667 pte &= ~ARM_PTE_HINT_MASK;
668 return pte;
669}
670
671/*
672 * arm_vm_prepare_kernel_el0_mappings:
673 * alloc_only: Indicates if PTE values should be copied from the EL1 kernel
674 * mappings.
675 *
676 * This function expands the kernel page tables to support the EL0 kernel
677 * mappings, and conditionally installs the PTE values for the EL0 kernel
678 * mappings (if alloc_only is false).
679 */
680static void
681arm_vm_prepare_kernel_el0_mappings(bool alloc_only)
682{
683 pt_entry_t pte = 0;
684 vm_offset_t start = ((vm_offset_t)&ExceptionVectorsBase) & ~PAGE_MASK;
685 vm_offset_t end = (((vm_offset_t)&ExceptionVectorsEnd) + PAGE_MASK) & ~PAGE_MASK;
686 vm_offset_t cur = 0;
687 vm_offset_t cur_fixed = 0;
688
689 /* Expand for/map the exceptions vectors in the EL0 kernel mappings. */
690 for (cur = start, cur_fixed = ARM_KERNEL_PROTECT_EXCEPTION_START; cur < end; cur += ARM_PGBYTES, cur_fixed += ARM_PGBYTES) {
691 /*
692 * We map the exception vectors at a different address than that
693 * of the kernelcache to avoid sharing page table pages with the
694 * kernelcache (as this may cause issues with TLB caching of
695 * page table pages.
696 */
697 if (!alloc_only) {
698 pte = arm_vm_kernel_pte(cur);
699 }
700
701 arm_vm_kernel_el1_map(cur_fixed, pte);
702 arm_vm_kernel_el0_map(cur_fixed, pte);
703 }
704
705 __builtin_arm_dmb(DMB_ISH);
706 __builtin_arm_isb(ISB_SY);
707
708 if (!alloc_only) {
709 /*
710 * If we have created the alternate exception vector mappings,
711 * the boot CPU may now switch over to them.
712 */
713 set_vbar_el1(ARM_KERNEL_PROTECT_EXCEPTION_START);
714 __builtin_arm_isb(ISB_SY);
715 }
716}
717
718/*
719 * arm_vm_populate_kernel_el0_mappings:
720 *
721 * This function adds all required mappings to the EL0 kernel mappings.
722 */
723static void
724arm_vm_populate_kernel_el0_mappings(void)
725{
726 arm_vm_prepare_kernel_el0_mappings(FALSE);
727}
728
729/*
730 * arm_vm_expand_kernel_el0_mappings:
731 *
732 * This function expands the kernel page tables to accomodate the EL0 kernel
733 * mappings.
734 */
735static void
736arm_vm_expand_kernel_el0_mappings(void)
737{
738 arm_vm_prepare_kernel_el0_mappings(TRUE);
739}
740#endif /* __ARM_KERNEL_PROTECT__ */
741
c6bf4f31 742#if defined(KERNEL_INTEGRITY_KTRR) || defined(KERNEL_INTEGRITY_CTRR)
5ba3f43e
A
743extern void bootstrap_instructions;
744
745/*
746 * arm_replace_identity_map takes the V=P map that we construct in start.s
747 * and repurposes it in order to have it map only the page we need in order
748 * to turn on the MMU. This prevents us from running into issues where
749 * KTRR will cause us to fault on executable block mappings that cross the
750 * KTRR boundary.
751 */
752static void arm_replace_identity_map(boot_args * args)
753{
754 vm_offset_t addr;
755 pmap_paddr_t paddr;
756
5ba3f43e
A
757 pmap_paddr_t l1_ptp_phys = 0;
758 tt_entry_t *l1_ptp_virt = NULL;
759 tt_entry_t *tte1 = NULL;
5ba3f43e
A
760 pmap_paddr_t l2_ptp_phys = 0;
761 tt_entry_t *l2_ptp_virt = NULL;
762 tt_entry_t *tte2 = NULL;
763 pmap_paddr_t l3_ptp_phys = 0;
764 pt_entry_t *l3_ptp_virt = NULL;
765 pt_entry_t *ptep = NULL;
766
767 addr = ((vm_offset_t)&bootstrap_instructions) & ~ARM_PGMASK;
768 paddr = kvtophys(addr);
769
770 /*
771 * The V=P page tables (at the time this comment was written) start
d9a64523
A
772 * after the last bit of kernel data, and consist of 1 L1 page and 1 or
773 * more L2 pages.
5ba3f43e
A
774 * Grab references to those pages, and allocate an L3 page.
775 */
5ba3f43e
A
776 l1_ptp_phys = args->topOfKernelData;
777 l1_ptp_virt = (tt_entry_t *)phystokv(l1_ptp_phys);
d9a64523 778 tte1 = &l1_ptp_virt[L1_TABLE_INDEX(paddr)];
5ba3f43e 779
d9a64523
A
780 l2_ptp_virt = L2_TABLE_VA(tte1);
781 l2_ptp_phys = (*tte1) & ARM_TTE_TABLE_MASK;
782 tte2 = &l2_ptp_virt[L2_TABLE_INDEX(paddr)];
5ba3f43e
A
783
784 l3_ptp_virt = (pt_entry_t *)alloc_ptpage(FALSE);
785 l3_ptp_phys = kvtophys((vm_offset_t)l3_ptp_virt);
d9a64523 786 ptep = &l3_ptp_virt[L3_TABLE_INDEX(paddr)];
5ba3f43e
A
787
788 /*
789 * Replace the large V=P mapping with a mapping that provides only the
790 * mappings needed to turn on the MMU.
791 */
d9a64523 792
5ba3f43e
A
793 bzero(l1_ptp_virt, ARM_PGBYTES);
794 *tte1 = ARM_TTE_BOOT_TABLE | (l2_ptp_phys & ARM_TTE_TABLE_MASK);
d9a64523 795
5ba3f43e
A
796 bzero(l2_ptp_virt, ARM_PGBYTES);
797 *tte2 = ARM_TTE_BOOT_TABLE | (l3_ptp_phys & ARM_TTE_TABLE_MASK);
798
799 *ptep = (paddr & ARM_PTE_MASK) |
800 ARM_PTE_TYPE_VALID |
801 ARM_PTE_SH(SH_OUTER_MEMORY) |
802 ARM_PTE_ATTRINDX(CACHE_ATTRINDX_WRITEBACK) |
803 ARM_PTE_AF |
804 ARM_PTE_AP(AP_RONA) |
805 ARM_PTE_NX;
806}
c6bf4f31 807#endif /* defined(KERNEL_INTEGRITY_KTRR) || defined(KERNEL_INTEGRITY_CTRR) */
5ba3f43e 808
d9a64523
A
809tt_entry_t *arm_kva_to_tte(vm_offset_t);
810
811tt_entry_t *
812arm_kva_to_tte(vm_offset_t va)
813{
d9a64523
A
814 tt_entry_t *tte1, *tte2;
815 tte1 = cpu_tte + L1_TABLE_INDEX(va);
816 tte2 = L2_TABLE_VA(tte1) + L2_TABLE_INDEX(va);
cb323159 817
d9a64523
A
818 return tte2;
819}
820
c6bf4f31
A
821#if XNU_MONITOR
822
823static inline pt_entry_t *
824arm_kva_to_pte(vm_offset_t va)
825{
826 tt_entry_t *tte2 = arm_kva_to_tte(va);
827 return L3_TABLE_VA(tte2) + L3_TABLE_INDEX(va);
828}
829
830#endif
d9a64523 831
cb323159
A
832#define ARM64_GRANULE_ALLOW_BLOCK (1 << 0)
833#define ARM64_GRANULE_ALLOW_HINT (1 << 1)
834
5ba3f43e
A
835/*
836 * arm_vm_page_granular_helper updates protections at the L3 level. It will (if
837 * neccessary) allocate a page for the L3 table and update the corresponding L2
838 * entry. Then, it will iterate over the L3 table, updating protections as necessary.
839 * This expects to be invoked on a L2 entry or sub L2 entry granularity, so this should
840 * not be invoked from a context that does not do L2 iteration separately (basically,
841 * don't call this except from arm_vm_page_granular_prot).
d9a64523 842 *
cb323159
A
843 * unsigned granule: 0 => force to page granule, or a combination of
844 * ARM64_GRANULE_* flags declared above.
5ba3f43e 845 */
d9a64523 846
5ba3f43e 847static void
d9a64523 848arm_vm_page_granular_helper(vm_offset_t start, vm_offset_t _end, vm_offset_t va, pmap_paddr_t pa_offset,
cb323159 849 int pte_prot_APX, int pte_prot_XN, unsigned granule,
5ba3f43e
A
850 pt_entry_t **deferred_pte, pt_entry_t *deferred_ptmp)
851{
852 if (va & ARM_TT_L2_OFFMASK) { /* ragged edge hanging over a ARM_TT_L2_SIZE boundary */
5ba3f43e 853 tt_entry_t *tte2;
5ba3f43e
A
854 tt_entry_t tmplate;
855 pmap_paddr_t pa;
856 pt_entry_t *ppte, *recursive_pte = NULL, ptmp, recursive_ptmp = 0;
857 addr64_t ppte_phys;
858 unsigned i;
859
860 va &= ~ARM_TT_L2_OFFMASK;
d9a64523 861 pa = va - gVirtBase + gPhysBase - pa_offset;
5ba3f43e 862
d9a64523
A
863 if (pa >= real_avail_end)
864 return;
5ba3f43e 865
d9a64523
A
866 tte2 = arm_kva_to_tte(va);
867
868 assert(_end >= va);
5ba3f43e
A
869 tmplate = *tte2;
870
871 if (ARM_TTE_TYPE_TABLE == (tmplate & ARM_TTE_TYPE_MASK)) {
872 /* pick up the existing page table. */
873 ppte = (pt_entry_t *)phystokv((tmplate & ARM_TTE_TABLE_MASK));
874 } else {
d9a64523
A
875 // TTE must be reincarnated with page level mappings.
876 ppte = (pt_entry_t*)alloc_ptpage(pa_offset == 0);
877 bzero(ppte, ARM_PGBYTES);
5ba3f43e
A
878 ppte_phys = kvtophys((vm_offset_t)ppte);
879
d9a64523 880 *tte2 = pa_to_tte(ppte_phys) | ARM_TTE_TYPE_TABLE | ARM_TTE_VALID;
5ba3f43e
A
881 }
882
d9a64523
A
883 vm_offset_t len = _end - va;
884 if ((pa + len) > real_avail_end)
885 _end -= (pa + len - real_avail_end);
886 assert((start - gVirtBase + gPhysBase - pa_offset) >= gPhysBase);
887
888 /* Round up to the nearest PAGE_SIZE boundary when creating mappings:
889 * PAGE_SIZE may be a multiple of ARM_PGBYTES, and we don't want to leave
890 * a ragged non-PAGE_SIZE-aligned edge. */
891 vm_offset_t rounded_end = round_page(_end);
5ba3f43e
A
892 /* Apply the desired protections to the specified page range */
893 for (i = 0; i <= (ARM_TT_L3_INDEX_MASK>>ARM_TT_L3_SHIFT); i++) {
d9a64523 894 if ((start <= va) && (va < rounded_end)) {
5ba3f43e
A
895
896 ptmp = pa | ARM_PTE_AF | ARM_PTE_SH(SH_OUTER_MEMORY) | ARM_PTE_TYPE;
897 ptmp = ptmp | ARM_PTE_ATTRINDX(CACHE_ATTRINDX_DEFAULT);
898 ptmp = ptmp | ARM_PTE_AP(pte_prot_APX);
899 ptmp = ptmp | ARM_PTE_NX;
5c9f4661
A
900#if __ARM_KERNEL_PROTECT__
901 ptmp = ptmp | ARM_PTE_NG;
902#endif /* __ARM_KERNEL_PROTECT__ */
5ba3f43e
A
903
904 if (pte_prot_XN) {
905 ptmp = ptmp | ARM_PTE_PNX;
906 }
907
908 /*
909 * If we can, apply the contiguous hint to this range. The hint is
d9a64523 910 * applicable if the current address falls within a hint-sized range that will
5ba3f43e
A
911 * be fully covered by this mapping request.
912 */
d9a64523 913 if ((va >= round_up_pte_hint_address(start)) && (round_up_pte_hint_address(va + 1) <= _end) &&
cb323159 914 (granule & ARM64_GRANULE_ALLOW_HINT) && use_contiguous_hint) {
d9a64523 915 assert((va & ((1 << ARM_PTE_HINT_ADDR_SHIFT) - 1)) == ((pa & ((1 << ARM_PTE_HINT_ADDR_SHIFT) - 1))));
5ba3f43e 916 ptmp |= ARM_PTE_HINT;
cb323159
A
917 /* Do not attempt to reapply the hint bit to an already-active mapping.
918 * This very likely means we're attempting to change attributes on an already-active mapping,
919 * which violates the requirement of the hint bit.*/
920 assert(!kva_active || (ppte[i] == ARM_PTE_TYPE_FAULT));
5ba3f43e 921 }
d9a64523
A
922 /*
923 * Do not change the contiguous bit on an active mapping. Even in a single-threaded
924 * environment, it's possible for prefetch to produce a TLB conflict by trying to pull in
925 * a hint-sized entry on top of one or more existing page-sized entries. It's also useful
926 * to make sure we're not trying to unhint a sub-range of a larger hinted range, which
927 * could produce a later TLB conflict.
928 */
929 assert(!kva_active || (ppte[i] == ARM_PTE_TYPE_FAULT) || ((ppte[i] & ARM_PTE_HINT) == (ptmp & ARM_PTE_HINT)));
930
cb323159 931 /*
d9a64523
A
932 * If we reach an entry that maps the current pte page, delay updating it until the very end.
933 * Otherwise we might end up making the PTE page read-only, leading to a fault later on in
934 * this function if we manage to outrun the TLB. This can happen on KTRR-enabled devices when
935 * marking segDATACONST read-only. Mappings for this region may straddle a PT page boundary,
936 * so we must also defer assignment of the following PTE. We will assume that if the region
937 * were to require one or more full L3 pages, it would instead use L2 blocks where possible,
cb323159 938 * therefore only requiring at most one L3 page at the beginning and one at the end.
d9a64523
A
939 */
940 if (kva_active && ((pt_entry_t*)(phystokv(pa)) == ppte)) {
cb323159
A
941 assert(recursive_pte == NULL);
942 assert(granule & ARM64_GRANULE_ALLOW_BLOCK);
5ba3f43e
A
943 recursive_pte = &ppte[i];
944 recursive_ptmp = ptmp;
945 } else if ((deferred_pte != NULL) && (&ppte[i] == &recursive_pte[1])) {
946 assert(*deferred_pte == NULL);
947 assert(deferred_ptmp != NULL);
948 *deferred_pte = &ppte[i];
949 *deferred_ptmp = ptmp;
950 } else {
951 ppte[i] = ptmp;
952 }
953 }
954
955 va += ARM_PGBYTES;
956 pa += ARM_PGBYTES;
957 }
958 if (recursive_pte != NULL)
959 *recursive_pte = recursive_ptmp;
960 }
961}
962
963/*
964 * arm_vm_page_granular_prot updates protections by iterating over the L2 entries and
965 * changing them. If a particular chunk necessitates L3 entries (for reasons of
966 * alignment or length, or an explicit request that the entry be fully expanded), we
967 * hand off to arm_vm_page_granular_helper to deal with the L3 chunk of the logic.
5ba3f43e
A
968 */
969static void
d9a64523
A
970arm_vm_page_granular_prot(vm_offset_t start, unsigned long size, pmap_paddr_t pa_offset,
971 int tte_prot_XN, int pte_prot_APX, int pte_prot_XN,
cb323159 972 unsigned granule)
5ba3f43e
A
973{
974 pt_entry_t *deferred_pte = NULL, deferred_ptmp = 0;
975 vm_offset_t _end = start + size;
976 vm_offset_t align_start = (start + ARM_TT_L2_OFFMASK) & ~ARM_TT_L2_OFFMASK;
977
978 if (size == 0x0UL)
979 return;
980
981 if (align_start > _end) {
cb323159 982 arm_vm_page_granular_helper(start, _end, start, pa_offset, pte_prot_APX, pte_prot_XN, granule, NULL, NULL);
5ba3f43e
A
983 return;
984 }
985
cb323159 986 arm_vm_page_granular_helper(start, align_start, start, pa_offset, pte_prot_APX, pte_prot_XN, granule, &deferred_pte, &deferred_ptmp);
5ba3f43e 987
d9a64523 988 while ((_end - align_start) >= ARM_TT_L2_SIZE) {
cb323159 989 if (!(granule & ARM64_GRANULE_ALLOW_BLOCK)) {
d9a64523 990 arm_vm_page_granular_helper(align_start, align_start+ARM_TT_L2_SIZE, align_start + 1, pa_offset,
cb323159
A
991 pte_prot_APX, pte_prot_XN, granule, NULL, NULL);
992 } else {
d9a64523 993 pmap_paddr_t pa = align_start - gVirtBase + gPhysBase - pa_offset;
cb323159 994 assert((pa & ARM_TT_L2_OFFMASK) == 0);
5ba3f43e 995 tt_entry_t *tte2;
5ba3f43e
A
996 tt_entry_t tmplate;
997
d9a64523 998 tte2 = arm_kva_to_tte(align_start);
5ba3f43e 999
d9a64523
A
1000 if ((pa >= gPhysBase) && (pa < real_avail_end)) {
1001 tmplate = (pa & ARM_TTE_BLOCK_L2_MASK) | ARM_TTE_TYPE_BLOCK
1002 | ARM_TTE_VALID | ARM_TTE_BLOCK_AF | ARM_TTE_BLOCK_NX
1003 | ARM_TTE_BLOCK_AP(pte_prot_APX) | ARM_TTE_BLOCK_SH(SH_OUTER_MEMORY)
1004 | ARM_TTE_BLOCK_ATTRINDX(CACHE_ATTRINDX_WRITEBACK);
cb323159 1005
5c9f4661 1006#if __ARM_KERNEL_PROTECT__
d9a64523 1007 tmplate = tmplate | ARM_TTE_BLOCK_NG;
5c9f4661 1008#endif /* __ARM_KERNEL_PROTECT__ */
d9a64523
A
1009 if (tte_prot_XN)
1010 tmplate = tmplate | ARM_TTE_BLOCK_PNX;
5ba3f43e 1011
d9a64523
A
1012 *tte2 = tmplate;
1013 }
5ba3f43e
A
1014 }
1015 align_start += ARM_TT_L2_SIZE;
1016 }
1017
1018 if (align_start < _end)
cb323159 1019 arm_vm_page_granular_helper(align_start, _end, _end, pa_offset, pte_prot_APX, pte_prot_XN, granule, &deferred_pte, &deferred_ptmp);
5ba3f43e
A
1020
1021 if (deferred_pte != NULL)
1022 *deferred_pte = deferred_ptmp;
1023}
1024
1025static inline void
cb323159 1026arm_vm_page_granular_RNX(vm_offset_t start, unsigned long size, unsigned granule)
5ba3f43e 1027{
cb323159 1028 arm_vm_page_granular_prot(start, size, 0, 1, AP_RONA, 1, granule);
5ba3f43e
A
1029}
1030
1031static inline void
cb323159 1032arm_vm_page_granular_ROX(vm_offset_t start, unsigned long size, unsigned granule)
5ba3f43e 1033{
cb323159 1034 arm_vm_page_granular_prot(start, size, 0, 0, AP_RONA, 0, granule);
5ba3f43e
A
1035}
1036
1037static inline void
cb323159 1038arm_vm_page_granular_RWNX(vm_offset_t start, unsigned long size, unsigned granule)
5ba3f43e 1039{
cb323159 1040 arm_vm_page_granular_prot(start, size, 0, 1, AP_RWNA, 1, granule);
5ba3f43e
A
1041}
1042
d9a64523
A
1043/* used in the chosen/memory-map node, populated by iBoot. */
1044typedef struct MemoryMapFileInfo {
1045 vm_offset_t paddr;
1046 size_t length;
1047} MemoryMapFileInfo;
1048
5ba3f43e
A
1049void
1050arm_vm_prot_init(boot_args * args)
1051{
5ba3f43e 1052
d9a64523
A
1053 segLOWESTTEXT = UINT64_MAX;
1054 if (segSizePRELINKTEXT && (segPRELINKTEXTB < segLOWESTTEXT)) segLOWESTTEXT = segPRELINKTEXTB;
1055 assert(segSizeTEXT);
1056 if (segTEXTB < segLOWESTTEXT) segLOWESTTEXT = segTEXTB;
1057 assert(segLOWESTTEXT < UINT64_MAX);
1058
1059 segEXTRADATA = segLOWESTTEXT;
1060 segSizeEXTRADATA = 0;
1061
cb323159
A
1062 segLOWEST = segLOWESTTEXT;
1063
d9a64523
A
1064 DTEntry memory_map;
1065 MemoryMapFileInfo *trustCacheRange;
1066 unsigned int trustCacheRangeSize;
1067 int err;
1068
1069 err = DTLookupEntry(NULL, "chosen/memory-map", &memory_map);
1070 assert(err == kSuccess);
1071
1072 err = DTGetProperty(memory_map, "TrustCache", (void**)&trustCacheRange, &trustCacheRangeSize);
1073 if (err == kSuccess) {
1074 assert(trustCacheRangeSize == sizeof(MemoryMapFileInfo));
1075
1076 segEXTRADATA = phystokv(trustCacheRange->paddr);
1077 segSizeEXTRADATA = trustCacheRange->length;
1078
cb323159
A
1079 if (segEXTRADATA <= segLOWEST) {
1080 segLOWEST = segEXTRADATA;
1081 }
1082#if !(DEBUG || DEVELOPMENT)
1083
1084
1085 else {
1086 panic("EXTRADATA is in an unexpected place: %#lx > %#lx", segEXTRADATA, segLOWEST);
1087 }
1088#endif /* !(DEBUG || DEVELOPMENT) */
1089
1090 arm_vm_page_granular_RNX(segEXTRADATA, segSizeEXTRADATA, ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT);
1091
d9a64523 1092 }
5ba3f43e
A
1093
1094 /* Map coalesced kext TEXT segment RWNX for now */
cb323159 1095 arm_vm_page_granular_RWNX(segPRELINKTEXTB, segSizePRELINKTEXT, ARM64_GRANULE_ALLOW_BLOCK); // Refined in OSKext::readPrelinkedExtensions
5ba3f43e
A
1096
1097 /* Map coalesced kext DATA_CONST segment RWNX (could be empty) */
cb323159 1098 arm_vm_page_granular_RWNX(segPLKDATACONSTB, segSizePLKDATACONST, ARM64_GRANULE_ALLOW_BLOCK); // Refined in OSKext::readPrelinkedExtensions
5ba3f43e 1099
cb323159
A
1100 /* Map coalesced kext TEXT_EXEC segment RX (could be empty) */
1101 arm_vm_page_granular_ROX(segPLKTEXTEXECB, segSizePLKTEXTEXEC, ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT); // Refined in OSKext::readPrelinkedExtensions
5ba3f43e
A
1102
1103 /* if new segments not present, set space between PRELINK_TEXT and xnu TEXT to RWNX
d9a64523 1104 * otherwise we no longer expect any space between the coalesced kext read only segments and xnu rosegments
5ba3f43e
A
1105 */
1106 if (!segSizePLKDATACONST && !segSizePLKTEXTEXEC) {
cb323159
A
1107 if (segSizePRELINKTEXT) {
1108 arm_vm_page_granular_RWNX(segPRELINKTEXTB + segSizePRELINKTEXT, segTEXTB - (segPRELINKTEXTB + segSizePRELINKTEXT),
1109 ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT);
1110 }
5ba3f43e
A
1111 } else {
1112 /*
1113 * If we have the new segments, we should still protect the gap between kext
1114 * read-only pages and kernel read-only pages, in the event that this gap
1115 * exists.
1116 */
1117 if ((segPLKDATACONSTB + segSizePLKDATACONST) < segTEXTB) {
cb323159
A
1118 arm_vm_page_granular_RWNX(segPLKDATACONSTB + segSizePLKDATACONST, segTEXTB - (segPLKDATACONSTB + segSizePLKDATACONST),
1119 ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT);
5ba3f43e
A
1120 }
1121 }
1122
1123 /*
1124 * Protection on kernel text is loose here to allow shenanigans early on. These
1125 * protections are tightened in arm_vm_prot_finalize(). This is necessary because
1126 * we currently patch LowResetVectorBase in cpu.c.
1127 *
1128 * TEXT segment contains mach headers and other non-executable data. This will become RONX later.
1129 */
cb323159 1130 arm_vm_page_granular_RNX(segTEXTB, segSizeTEXT, ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT);
5ba3f43e
A
1131
1132 /* Can DATACONST start out and stay RNX?
1133 * NO, stuff in this segment gets modified during startup (viz. mac_policy_init()/mac_policy_list)
1134 * Make RNX in prot_finalize
1135 */
c6bf4f31
A
1136#if XNU_MONITOR
1137 /* The ropagetable region will ultimately be owned by the PPL. Set permissions
1138 * on it separately to avoid applying mismatched block settings between this function,
1139 * pmap_static_allocations_done(), and arm_vm_prot_finalize(). */
1140 vm_offset_t segDATACONSTE = segDATACONSTB + segSizeDATACONST;
1141
1142 arm_vm_page_granular_RWNX(segDATACONSTB, (vm_offset_t)&ropagetable_begin - segDATACONSTB, ARM64_GRANULE_ALLOW_BLOCK);
1143 arm_vm_page_granular_RWNX((vm_offset_t)&ropagetable_begin,
1144 (vm_offset_t)&ropagetable_end - (vm_offset_t)&ropagetable_begin, ARM64_GRANULE_ALLOW_BLOCK);
1145 arm_vm_page_granular_RWNX((vm_offset_t)&ropagetable_end,
1146 segDATACONSTE - (vm_offset_t)&ropagetable_end, ARM64_GRANULE_ALLOW_BLOCK);
1147#else
cb323159 1148 arm_vm_page_granular_RWNX(segDATACONSTB, segSizeDATACONST, ARM64_GRANULE_ALLOW_BLOCK);
c6bf4f31 1149#endif
5ba3f43e 1150
cb323159 1151 arm_vm_page_granular_ROX(segTEXTEXECB, segSizeTEXTEXEC, ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT);
5ba3f43e 1152
c6bf4f31
A
1153#if XNU_MONITOR
1154 arm_vm_page_granular_ROX(segPPLTEXTB, segSizePPLTEXT, ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT);
1155 arm_vm_page_granular_ROX(segPPLTRAMPB, segSizePPLTRAMP, ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT);
1156 arm_vm_page_granular_RNX(segPPLDATACONSTB, segSizePPLDATACONST, ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT);
1157#endif
5ba3f43e
A
1158
1159 /* DATA segment will remain RWNX */
cb323159 1160 arm_vm_page_granular_RWNX(segDATAB, segSizeDATA, ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT);
c6bf4f31
A
1161#if XNU_MONITOR
1162 arm_vm_page_granular_RWNX(segPPLDATAB, segSizePPLDATA, ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT);
1163#endif
5ba3f43e 1164
cb323159
A
1165 arm_vm_page_granular_RWNX(segBOOTDATAB, segSizeBOOTDATA, 0);
1166 arm_vm_page_granular_RNX((vm_offset_t)&intstack_low_guard, PAGE_MAX_SIZE, 0);
1167 arm_vm_page_granular_RNX((vm_offset_t)&intstack_high_guard, PAGE_MAX_SIZE, 0);
1168 arm_vm_page_granular_RNX((vm_offset_t)&excepstack_high_guard, PAGE_MAX_SIZE, 0);
d9a64523 1169
cb323159
A
1170 arm_vm_page_granular_ROX(segKLDB, segSizeKLD, ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT);
1171 arm_vm_page_granular_RWNX(segLINKB, segSizeLINK, ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT);
1172 arm_vm_page_granular_RWNX(segPLKLINKEDITB, segSizePLKLINKEDIT, ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT); // Coalesced kext LINKEDIT segment
1173 arm_vm_page_granular_ROX(segLASTB, segSizeLAST, ARM64_GRANULE_ALLOW_BLOCK); // __LAST may be empty, but we cannot assume this
5ba3f43e 1174
cb323159 1175 arm_vm_page_granular_RWNX(segPRELINKDATAB, segSizePRELINKDATA, ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT); // Prelink __DATA for kexts (RW data)
5ba3f43e
A
1176
1177 if (segSizePLKLLVMCOV > 0)
cb323159 1178 arm_vm_page_granular_RWNX(segPLKLLVMCOVB, segSizePLKLLVMCOV, ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT); // LLVM code coverage data
5ba3f43e 1179
cb323159 1180 arm_vm_page_granular_RWNX(segPRELINKINFOB, segSizePRELINKINFO, ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT); /* PreLinkInfoDictionary */
5ba3f43e 1181
cb323159 1182 arm_vm_page_granular_RNX(phystokv(args->topOfKernelData), BOOTSTRAP_TABLE_SIZE, ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT); // Boot page tables; they should not be mutable.
d9a64523 1183}
5ba3f43e 1184
d9a64523
A
1185/*
1186 * return < 0 for a < b
1187 * 0 for a == b
1188 * > 0 for a > b
1189 */
1190typedef int (*cmpfunc_t)(const void *a, const void *b);
1191
1192extern void
1193qsort(void *a, size_t n, size_t es, cmpfunc_t cmp);
1194
1195static int
1196cmp_ptov_entries(const void *a, const void *b)
1197{
1198 const ptov_table_entry *entry_a = a;
1199 const ptov_table_entry *entry_b = b;
1200 // Sort in descending order of segment length
1201 if (entry_a->len < entry_b->len)
1202 return 1;
1203 else if (entry_a->len > entry_b->len)
1204 return -1;
1205 else
1206 return 0;
1207}
1208
1209SECURITY_READ_ONLY_LATE(static unsigned int) ptov_index = 0;
1210
1211#define ROUND_TWIG(addr) (((addr) + ARM_TT_TWIG_OFFMASK) & ~(ARM_TT_TWIG_OFFMASK))
1212
1213static void
cb323159 1214arm_vm_physmap_slide(ptov_table_entry *temp_ptov_table, vm_map_address_t physmap_base, vm_map_address_t orig_va, vm_size_t len, int pte_prot_APX, unsigned granule)
d9a64523
A
1215{
1216 pmap_paddr_t pa_offset;
1217
1218 assert(ptov_index < PTOV_TABLE_SIZE);
1219 assert((orig_va & ARM_PGMASK) == 0);
1220 temp_ptov_table[ptov_index].pa = orig_va - gVirtBase + gPhysBase;
1221 if (ptov_index == 0)
1222 temp_ptov_table[ptov_index].va = physmap_base;
1223 else
1224 temp_ptov_table[ptov_index].va = temp_ptov_table[ptov_index - 1].va + temp_ptov_table[ptov_index - 1].len;
cb323159 1225 if (granule & ARM64_GRANULE_ALLOW_BLOCK) {
d9a64523
A
1226 vm_map_address_t orig_offset = temp_ptov_table[ptov_index].pa & ARM_TT_TWIG_OFFMASK;
1227 vm_map_address_t new_offset = temp_ptov_table[ptov_index].va & ARM_TT_TWIG_OFFMASK;
1228 if (new_offset < orig_offset)
1229 temp_ptov_table[ptov_index].va += (orig_offset - new_offset);
1230 else if (new_offset > orig_offset)
1231 temp_ptov_table[ptov_index].va = ROUND_TWIG(temp_ptov_table[ptov_index].va) + orig_offset;
1232 }
1233 assert((temp_ptov_table[ptov_index].va & ARM_PGMASK) == 0);
1234 temp_ptov_table[ptov_index].len = round_page(len);
cb323159
A
1235 pa_offset = temp_ptov_table[ptov_index].va - orig_va;
1236 arm_vm_page_granular_prot(temp_ptov_table[ptov_index].va, temp_ptov_table[ptov_index].len, pa_offset, 1, pte_prot_APX, 1, granule);
d9a64523 1237 ++ptov_index;
5ba3f43e
A
1238}
1239
c6bf4f31
A
1240#if XNU_MONITOR
1241
1242SECURITY_READ_ONLY_LATE(static boolean_t) keep_linkedit = FALSE;
1243
1244static void
1245arm_vm_physmap_init(boot_args *args, vm_map_address_t physmap_base, vm_map_address_t dynamic_memory_begin __unused)
1246{
1247 ptov_table_entry temp_ptov_table[PTOV_TABLE_SIZE];
1248 bzero(temp_ptov_table, sizeof(temp_ptov_table));
1249
1250 // This is memory that will either be handed back to the VM layer via ml_static_mfree(),
1251 // or will be available for general-purpose use. Physical aperture mappings for this memory
1252 // must be at page granularity, so that PPL ownership or cache attribute changes can be reflected
1253 // in the physical aperture mappings.
1254
1255
1256 // Slid region between gPhysBase and beginning of protected text
1257 arm_vm_physmap_slide(temp_ptov_table, physmap_base, gVirtBase, segLOWEST - gVirtBase, AP_RWNA, 0);
1258
1259 // kext bootstrap segment
1260 arm_vm_physmap_slide(temp_ptov_table, physmap_base, segKLDB, segSizeKLD, AP_RONA, 0);
1261
1262 // Early-boot data
1263 arm_vm_physmap_slide(temp_ptov_table, physmap_base, segBOOTDATAB, segSizeBOOTDATA, AP_RONA, 0);
1264
1265#if KASAN_DYNAMIC_BLACKLIST
1266 /* KASAN's dynamic blacklist needs to query the LINKEDIT segment at runtime. As such, the
1267 * kext bootstrap code will not jettison LINKEDIT on kasan kernels, so don't bother to relocate it. */
1268 keep_linkedit = TRUE;
1269#else
1270 PE_parse_boot_argn("keepsyms", &keep_linkedit, sizeof(keep_linkedit));
1271#endif
1272 if (!keep_linkedit) {
1273 // Kernel LINKEDIT
1274 arm_vm_physmap_slide(temp_ptov_table, physmap_base, segLINKB, segSizeLINK, AP_RWNA, 0);
1275
1276 // Prelinked kernel LINKEDIT
1277 arm_vm_physmap_slide(temp_ptov_table, physmap_base, segPLKLINKEDITB, segSizePLKLINKEDIT, AP_RWNA, 0);
1278 }
1279
1280 // Prelinked kernel plists
1281 arm_vm_physmap_slide(temp_ptov_table, physmap_base, segPRELINKINFOB, segSizePRELINKINFO, AP_RWNA, 0);
1282
1283 // Device tree, ramdisk, boot args
1284 arm_vm_physmap_slide(temp_ptov_table, physmap_base, end_kern, (args->topOfKernelData - gPhysBase + gVirtBase) - end_kern, AP_RWNA, 0);
1285 PE_slide_devicetree(temp_ptov_table[ptov_index - 1].va - end_kern);
1286
1287 // Remainder of physical memory
1288 arm_vm_physmap_slide(temp_ptov_table, physmap_base, (args->topOfKernelData + BOOTSTRAP_TABLE_SIZE - gPhysBase + gVirtBase),
1289 real_avail_end - (args->topOfKernelData + BOOTSTRAP_TABLE_SIZE), AP_RWNA, 0);
1290
1291 assert((temp_ptov_table[ptov_index - 1].va + temp_ptov_table[ptov_index - 1].len) <= dynamic_memory_begin);
1292
1293 // Sort in descending order of segment length. LUT traversal is linear, so largest (most likely used)
1294 // segments should be placed earliest in the table to optimize lookup performance.
1295 qsort(temp_ptov_table, PTOV_TABLE_SIZE, sizeof(temp_ptov_table[0]), cmp_ptov_entries);
1296
1297 memcpy(ptov_table, temp_ptov_table, sizeof(ptov_table));
1298}
1299
1300#else
d9a64523
A
1301
1302static void
1303arm_vm_physmap_init(boot_args *args, vm_map_address_t physmap_base, vm_map_address_t dynamic_memory_begin __unused)
1304{
1305 ptov_table_entry temp_ptov_table[PTOV_TABLE_SIZE];
1306 bzero(temp_ptov_table, sizeof(temp_ptov_table));
1307
1308 // Will be handed back to VM layer through ml_static_mfree() in arm_vm_prot_finalize()
cb323159
A
1309 arm_vm_physmap_slide(temp_ptov_table, physmap_base, gVirtBase, segLOWEST - gVirtBase, AP_RWNA,
1310 ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT);
d9a64523 1311
cb323159
A
1312 arm_vm_page_granular_RWNX(end_kern, phystokv(args->topOfKernelData) - end_kern,
1313 ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT); /* Device Tree, RAM Disk (if present), bootArgs */
d9a64523
A
1314
1315 arm_vm_physmap_slide(temp_ptov_table, physmap_base, (args->topOfKernelData + BOOTSTRAP_TABLE_SIZE - gPhysBase + gVirtBase),
cb323159 1316 real_avail_end - (args->topOfKernelData + BOOTSTRAP_TABLE_SIZE), AP_RWNA, ARM64_GRANULE_ALLOW_BLOCK | ARM64_GRANULE_ALLOW_HINT); // rest of physmem
d9a64523
A
1317
1318 assert((temp_ptov_table[ptov_index - 1].va + temp_ptov_table[ptov_index - 1].len) <= dynamic_memory_begin);
1319
1320 // Sort in descending order of segment length. LUT traversal is linear, so largest (most likely used)
1321 // segments should be placed earliest in the table to optimize lookup performance.
cb323159 1322 qsort(temp_ptov_table, PTOV_TABLE_SIZE, sizeof(temp_ptov_table[0]), cmp_ptov_entries);
d9a64523
A
1323
1324 memcpy(ptov_table, temp_ptov_table, sizeof(ptov_table));
1325}
1326
c6bf4f31 1327#endif // XNU_MONITOR
d9a64523 1328
5ba3f43e 1329void
d9a64523 1330arm_vm_prot_finalize(boot_args * args __unused)
5ba3f43e 1331{
5ba3f43e
A
1332 /*
1333 * At this point, we are far enough along in the boot process that it will be
1334 * safe to free up all of the memory preceeding the kernel. It may in fact
1335 * be safe to do this earlier.
1336 *
1337 * This keeps the memory in the V-to-P mapping, but advertises it to the VM
1338 * as usable.
1339 */
1340
1341 /*
1342 * if old style PRELINK segment exists, free memory before it, and after it before XNU text
1343 * otherwise we're dealing with a new style kernel cache, so we should just free the
1344 * memory before PRELINK_TEXT segment, since the rest of the KEXT read only data segments
1345 * should be immediately followed by XNU's TEXT segment
1346 */
1347
cb323159 1348 ml_static_mfree(phystokv(gPhysBase), segLOWEST - gVirtBase);
5ba3f43e 1349
d9a64523
A
1350 /*
1351 * KTRR support means we will be mucking with these pages and trying to
1352 * protect them; we cannot free the pages to the VM if we do this.
1353 */
1354 if (!segSizePLKDATACONST && !segSizePLKTEXTEXEC && segSizePRELINKTEXT) {
5ba3f43e
A
1355 /* If new segments not present, PRELINK_TEXT is not dynamically sized, free DRAM between it and xnu TEXT */
1356 ml_static_mfree(segPRELINKTEXTB + segSizePRELINKTEXT, segTEXTB - (segPRELINKTEXTB + segSizePRELINKTEXT));
1357 }
1358
5ba3f43e 1359 /* tighten permissions on kext read only data and code */
cb323159
A
1360 arm_vm_page_granular_RNX(segPRELINKTEXTB, segSizePRELINKTEXT, ARM64_GRANULE_ALLOW_BLOCK);
1361 arm_vm_page_granular_RNX(segPLKDATACONSTB, segSizePLKDATACONST, ARM64_GRANULE_ALLOW_BLOCK);
5ba3f43e 1362
d9a64523
A
1363 cpu_stack_alloc(&BootCpuData);
1364 arm64_replace_bootstack(&BootCpuData);
1365 ml_static_mfree(phystokv(segBOOTDATAB - gVirtBase + gPhysBase), segSizeBOOTDATA);
1366
5c9f4661
A
1367#if __ARM_KERNEL_PROTECT__
1368 arm_vm_populate_kernel_el0_mappings();
1369#endif /* __ARM_KERNEL_PROTECT__ */
1370
c6bf4f31
A
1371#if XNU_MONITOR
1372 for (vm_offset_t va = segKLDB; va < (segKLDB + segSizeKLD); va += ARM_PGBYTES) {
1373 pt_entry_t *pte = arm_kva_to_pte(va);
1374 *pte = ARM_PTE_EMPTY;
1375 }
1376 /* Clear the original stack mappings; these pages should be mapped through ptov_table. */
1377 for (vm_offset_t va = segBOOTDATAB; va < (segBOOTDATAB + segSizeBOOTDATA); va += ARM_PGBYTES) {
1378 pt_entry_t *pte = arm_kva_to_pte(va);
1379 *pte = ARM_PTE_EMPTY;
1380 }
1381 /* Clear the original PRELINKINFO mapping. This segment should be jettisoned during I/O Kit
1382 * initialization before we reach this point. */
1383 for (vm_offset_t va = segPRELINKINFOB; va < (segPRELINKINFOB + segSizePRELINKINFO); va += ARM_PGBYTES) {
1384 pt_entry_t *pte = arm_kva_to_pte(va);
1385 *pte = ARM_PTE_EMPTY;
1386 }
1387 if (!keep_linkedit) {
1388 for (vm_offset_t va = segLINKB; va < (segLINKB + segSizeLINK); va += ARM_PGBYTES) {
1389 pt_entry_t *pte = arm_kva_to_pte(va);
1390 *pte = ARM_PTE_EMPTY;
1391 }
1392 for (vm_offset_t va = segPLKLINKEDITB; va < (segPLKLINKEDITB + segSizePLKLINKEDIT); va += ARM_PGBYTES) {
1393 pt_entry_t *pte = arm_kva_to_pte(va);
1394 *pte = ARM_PTE_EMPTY;
1395 }
1396 }
1397#endif /* XNU_MONITOR */
d9a64523 1398
c6bf4f31 1399#if defined(KERNEL_INTEGRITY_KTRR) || defined(KERNEL_INTEGRITY_CTRR)
5ba3f43e
A
1400 /*
1401 * __LAST,__pinst should no longer be executable.
1402 */
cb323159 1403 arm_vm_page_granular_RNX(segLASTB, segSizeLAST, ARM64_GRANULE_ALLOW_BLOCK);
5ba3f43e
A
1404
1405 /*
1406 * Must wait until all other region permissions are set before locking down DATA_CONST
1407 * as the kernel static page tables live in DATA_CONST on KTRR enabled systems
1408 * and will become immutable.
1409 */
1410#endif
5c9f4661 1411
c6bf4f31
A
1412#if XNU_MONITOR
1413 vm_offset_t segDATACONSTE = segDATACONSTB + segSizeDATACONST;
1414
1415 /*
1416 * For the moment, the RO pagetable allocation is part of the
1417 * constant data segment, but it is technically owned by the
1418 * PPL. Hence, we should not reprotect it.
1419 */
1420 arm_vm_page_granular_RNX(segDATACONSTB, (vm_offset_t)&ropagetable_begin - segDATACONSTB, ARM64_GRANULE_ALLOW_BLOCK);
1421 arm_vm_page_granular_RNX((vm_offset_t)&ropagetable_end,
1422 segDATACONSTE - (vm_offset_t)&ropagetable_end, ARM64_GRANULE_ALLOW_BLOCK);
1423#else
cb323159 1424 arm_vm_page_granular_RNX(segDATACONSTB, segSizeDATACONST, ARM64_GRANULE_ALLOW_BLOCK);
c6bf4f31 1425#endif
5ba3f43e 1426
d9a64523 1427 __builtin_arm_dsb(DSB_ISH);
5ba3f43e
A
1428 flush_mmu_tlb();
1429}
1430
1431#define TBI_USER 0x1
1432#define TBI_KERNEL 0x2
1433
1434boolean_t user_tbi = TRUE;
1435
1436/*
1437 * TBI (top-byte ignore) is an ARMv8 feature for ignoring the top 8 bits of
1438 * address accesses. It can be enabled separately for TTBR0 (user) and
1439 * TTBR1 (kernel). We enable it by default for user only, but allow both
1440 * to be controlled by the 'tbi' boot-arg.
1441 */
1442static void
1443set_tbi(void)
1444{
5c9f4661
A
1445#if !__ARM_KERNEL_PROTECT__
1446 /* If we are not built with __ARM_KERNEL_PROTECT__, TBI can be turned
1447 * off with a boot-arg.
1448 */
5ba3f43e
A
1449 uint64_t old_tcr, new_tcr;
1450 int tbi = 0;
1451
1452 if (PE_parse_boot_argn("tbi", &tbi, sizeof(tbi)))
1453 user_tbi = ((tbi & TBI_USER) == TBI_USER);
1454 old_tcr = new_tcr = get_tcr();
1455 new_tcr |= (user_tbi) ? TCR_TBI0_TOPBYTE_IGNORED : 0;
cb323159
A
1456
1457#if !defined(HAS_APPLE_PAC)
1458 /*
1459 * arm_vm_init() runs after rebase_threaded_starts(), so enabling TBI1
1460 * at this point will break the computed pointer signatures. TBID1
1461 * could help mitigate this problem, but for now we'll just disable
1462 * kernel TBI if PAC is being used.
1463 */
5ba3f43e 1464 new_tcr |= (tbi & TBI_KERNEL) ? TCR_TBI1_TOPBYTE_IGNORED : 0;
cb323159 1465#endif
5ba3f43e
A
1466
1467 if (old_tcr != new_tcr) {
1468 set_tcr(new_tcr);
1469 sysreg_restore.tcr_el1 = new_tcr;
1470 }
5c9f4661 1471#endif /* !__ARM_KERNEL_PROTECT__ */
5ba3f43e
A
1472}
1473
d9a64523
A
1474#define ARM64_PHYSMAP_SLIDE_RANGE (1ULL << 30) // 1 GB
1475#define ARM64_PHYSMAP_SLIDE_MASK (ARM64_PHYSMAP_SLIDE_RANGE - 1)
1476
5ba3f43e
A
1477void
1478arm_vm_init(uint64_t memory_size, boot_args * args)
1479{
5ba3f43e 1480 vm_map_address_t va_l1, va_l1_end;
5ba3f43e 1481 tt_entry_t *cpu_l1_tte;
5ba3f43e 1482 vm_map_address_t va_l2, va_l2_end;
5ba3f43e
A
1483 tt_entry_t *cpu_l2_tte;
1484 pmap_paddr_t boot_ttep;
1485 tt_entry_t *boot_tte;
1486 uint64_t mem_segments;
1487 vm_offset_t ptpage_vaddr;
d9a64523
A
1488 vm_map_address_t dynamic_memory_begin;
1489 vm_map_address_t physmap_base;
5ba3f43e
A
1490
1491
1492 /*
1493 * Get the virtual and physical memory base from boot_args.
1494 */
1495 gVirtBase = args->virtBase;
1496 gPhysBase = args->physBase;
cb323159
A
1497#if KASAN
1498 real_phys_size = args->memSize + (shadow_ptop - shadow_pbase);
1499#else
1500 real_phys_size = args->memSize;
1501#endif
1502 /*
1503 * Ensure the physical region we specify for the VM to manage ends on a
1504 * software page boundary. Note that the software page size (PAGE_SIZE)
1505 * may be a multiple of the hardware page size specified in ARM_PGBYTES.
1506 * We must round the reported memory size down to the nearest PAGE_SIZE
1507 * boundary to ensure the VM does not try to manage a page it does not
1508 * completely own. The KASAN shadow region, if present, is managed entirely
1509 * in units of the hardware page size and should not need similar treatment.
1510 */
1511 gPhysSize = mem_size = ((gPhysBase + args->memSize) & ~PAGE_MASK) - gPhysBase;
1512
5ba3f43e
A
1513 if ((memory_size != 0) && (mem_size > memory_size))
1514 mem_size = memory_size;
d9a64523
A
1515 if (mem_size >= ((VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) / 4))
1516 panic("Unsupported memory configuration %lx\n", mem_size);
1517
1518 physmap_base = phystokv(args->topOfKernelData) + BOOTSTRAP_TABLE_SIZE;
1519
1520 // Slide the physical aperture to a random page-aligned location within the slide range
1521 uint64_t physmap_slide = early_random() & ARM64_PHYSMAP_SLIDE_MASK & ~((uint64_t)PAGE_MASK);
1522 assert(physmap_slide < ARM64_PHYSMAP_SLIDE_RANGE);
1523
1524 physmap_base += physmap_slide;
1525
c6bf4f31
A
1526#if XNU_MONITOR
1527 physmap_base = ROUND_TWIG(physmap_base);
1528 static_memory_end = physmap_base + mem_size;
1529#else
d9a64523 1530 static_memory_end = physmap_base + mem_size + (PTOV_TABLE_SIZE * ARM_TT_TWIG_SIZE); // worst possible case for block alignment
c6bf4f31 1531#endif
d9a64523
A
1532#if KASAN
1533 /* add the KASAN stolen memory to the physmap */
1534 dynamic_memory_begin = static_memory_end + (shadow_ptop - shadow_pbase);
1535#else
1536 dynamic_memory_begin = static_memory_end;
c6bf4f31
A
1537#endif
1538#if XNU_MONITOR
1539 pmap_stacks_start = (void*)dynamic_memory_begin;
1540 dynamic_memory_begin += PPL_STACK_REGION_SIZE;
1541 pmap_stacks_end = (void*)dynamic_memory_begin;
d9a64523
A
1542#endif
1543 if (dynamic_memory_begin > VM_MAX_KERNEL_ADDRESS)
1544 panic("Unsupported memory configuration %lx\n", mem_size);
5ba3f43e
A
1545
1546 boot_ttep = args->topOfKernelData;
1547 boot_tte = (tt_entry_t *) phystokv(boot_ttep);
1548
d9a64523
A
1549#if DEVELOPMENT || DEBUG
1550 /* Sanity check - assert that BOOTSTRAP_TABLE_SIZE is sufficiently-large to
1551 * hold our bootstrap mappings for any possible slide */
1552 size_t bytes_mapped = dynamic_memory_begin - gVirtBase;
1553 size_t l1_entries = 1 + ((bytes_mapped + ARM_TT_L1_SIZE - 1) / ARM_TT_L1_SIZE);
1554 /* 1 L1 each for V=P and KVA, plus 1 page for each L2 */
1555 size_t pages_used = 2 * (l1_entries + 1);
1556 if (pages_used > BOOTSTRAP_TABLE_SIZE) {
1557 panic("BOOTSTRAP_TABLE_SIZE too small for memory config\n");
1558 }
1559#endif
1560
1561 /*
5ba3f43e
A
1562 * TTBR0 L1, TTBR0 L2 - 1:1 bootstrap mapping.
1563 * TTBR1 L1, TTBR1 L2 - kernel mapping
1564 */
d9a64523 1565 avail_start = boot_ttep + BOOTSTRAP_TABLE_SIZE;
5ba3f43e 1566
c6bf4f31 1567#if defined(KERNEL_INTEGRITY_KTRR) || defined(KERNEL_INTEGRITY_CTRR)
5ba3f43e
A
1568 arm_replace_identity_map(args);
1569#endif
1570
1571 /* Initialize invalid tte page */
1572 invalid_tte = (tt_entry_t *)alloc_ptpage(TRUE);
1573 invalid_ttep = kvtophys((vm_offset_t)invalid_tte);
1574 bzero(invalid_tte, ARM_PGBYTES);
1575
1576 /*
1577 * Initialize l1 page table page
1578 */
5ba3f43e
A
1579 cpu_tte = (tt_entry_t *)alloc_ptpage(TRUE);
1580 cpu_ttep = kvtophys((vm_offset_t)cpu_tte);
1581 bzero(cpu_tte, ARM_PGBYTES);
5ba3f43e 1582 avail_end = gPhysBase + mem_size;
cb323159 1583 assert(!(avail_end & PAGE_MASK));
5ba3f43e 1584
d9a64523 1585#if KASAN
cb323159 1586 real_avail_end = gPhysBase + real_phys_size;
d9a64523
A
1587#else
1588 real_avail_end = avail_end;
1589#endif
1590
5ba3f43e
A
1591 /*
1592 * Initialize l1 and l2 page table pages :
1593 * map physical memory at the kernel base virtual address
1594 * cover the kernel dynamic address range section
1595 *
1596 * the so called physical aperture should be statically mapped
1597 */
5ba3f43e 1598 va_l1 = gVirtBase;
cb323159 1599 va_l1_end = dynamic_memory_begin;
5ba3f43e
A
1600 cpu_l1_tte = cpu_tte + ((va_l1 & ARM_TT_L1_INDEX_MASK) >> ARM_TT_L1_SHIFT);
1601
1602 while (va_l1 < va_l1_end) {
d9a64523
A
1603 if (*cpu_l1_tte == ARM_TTE_EMPTY) {
1604 /* Allocate a page and setup L1 Table TTE in L1 */
1605 ptpage_vaddr = alloc_ptpage(TRUE);
1606 *cpu_l1_tte = (kvtophys(ptpage_vaddr) & ARM_TTE_TABLE_MASK) | ARM_TTE_TYPE_TABLE | ARM_TTE_VALID;
1607 bzero((void *)ptpage_vaddr, ARM_PGBYTES);
1608 }
5ba3f43e 1609
d9a64523 1610 if ((va_l1 + ARM_TT_L1_SIZE) < va_l1) {
5ba3f43e 1611 /* If this is the last L1 entry, it must cover the last mapping. */
d9a64523 1612 break;
5ba3f43e
A
1613 }
1614
d9a64523 1615 va_l1 += ARM_TT_L1_SIZE;
5ba3f43e 1616 cpu_l1_tte++;
5ba3f43e 1617 }
5ba3f43e 1618
5c9f4661
A
1619#if __ARM_KERNEL_PROTECT__
1620 /* Expand the page tables to prepare for the EL0 mappings. */
1621 arm_vm_expand_kernel_el0_mappings();
1622#endif /* __ARM_KERNEL_PROTECT__ */
1623
5ba3f43e
A
1624 /*
1625 * Now retrieve addresses for end, edata, and etext from MACH-O headers
1626 */
1627 segPRELINKTEXTB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_TEXT", &segSizePRELINKTEXT);
1628 segPLKDATACONSTB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PLK_DATA_CONST", &segSizePLKDATACONST);
1629 segPLKTEXTEXECB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PLK_TEXT_EXEC", &segSizePLKTEXTEXEC);
1630 segTEXTB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__TEXT", &segSizeTEXT);
1631 segDATACONSTB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__DATA_CONST", &segSizeDATACONST);
1632 segTEXTEXECB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__TEXT_EXEC", &segSizeTEXTEXEC);
c6bf4f31
A
1633#if XNU_MONITOR
1634 segPPLTEXTB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PPLTEXT", &segSizePPLTEXT);
1635 segPPLTRAMPB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PPLTRAMP", &segSizePPLTRAMP);
1636 segPPLDATACONSTB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PPLDATA_CONST", &segSizePPLDATACONST);
1637#endif
5ba3f43e 1638 segDATAB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__DATA", &segSizeDATA);
c6bf4f31
A
1639#if XNU_MONITOR
1640 segPPLDATAB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PPLDATA", &segSizePPLDATA);
1641#endif
d9a64523
A
1642
1643 segBOOTDATAB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__BOOTDATA", &segSizeBOOTDATA);
5ba3f43e
A
1644 segLINKB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__LINKEDIT", &segSizeLINK);
1645 segKLDB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__KLD", &segSizeKLD);
1646 segPRELINKDATAB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_DATA", &segSizePRELINKDATA);
1647 segPRELINKINFOB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_INFO", &segSizePRELINKINFO);
1648 segPLKLLVMCOVB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PLK_LLVM_COV", &segSizePLKLLVMCOV);
1649 segPLKLINKEDITB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PLK_LINKEDIT", &segSizePLKLINKEDIT);
1650 segLASTB = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__LAST", &segSizeLAST);
1651
1652 (void) PE_parse_boot_argn("use_contiguous_hint", &use_contiguous_hint, sizeof(use_contiguous_hint));
1653 assert(segSizePRELINKTEXT < 0x03000000); /* 23355738 */
1654
1655 /* if one of the new segments is present, the other one better be as well */
1656 if (segSizePLKDATACONST || segSizePLKTEXTEXEC) {
1657 assert(segSizePLKDATACONST && segSizePLKTEXTEXEC);
1658 }
1659
1660 etext = (vm_offset_t) segTEXTB + segSizeTEXT;
1661 sdata = (vm_offset_t) segDATAB;
1662 edata = (vm_offset_t) segDATAB + segSizeDATA;
1663 end_kern = round_page(getlastaddr()); /* Force end to next page */
1664
1665 vm_set_page_size();
1666
1667 vm_kernel_base = segTEXTB;
1668 vm_kernel_top = (vm_offset_t) &last_kernel_symbol;
1669 vm_kext_base = segPRELINKTEXTB;
1670 vm_kext_top = vm_kext_base + segSizePRELINKTEXT;
1671
1672 vm_prelink_stext = segPRELINKTEXTB;
1673 if (!segSizePLKTEXTEXEC && !segSizePLKDATACONST) {
1674 vm_prelink_etext = segPRELINKTEXTB + segSizePRELINKTEXT;
1675 } else {
1676 vm_prelink_etext = segPRELINKTEXTB + segSizePRELINKTEXT + segSizePLKDATACONST + segSizePLKTEXTEXEC;
1677 }
1678 vm_prelink_sinfo = segPRELINKINFOB;
1679 vm_prelink_einfo = segPRELINKINFOB + segSizePRELINKINFO;
1680 vm_slinkedit = segLINKB;
1681 vm_elinkedit = segLINKB + segSizeLINK;
1682
1683 vm_prelink_sdata = segPRELINKDATAB;
1684 vm_prelink_edata = segPRELINKDATAB + segSizePRELINKDATA;
1685
1686 arm_vm_prot_init(args);
1687
1688
1689 /*
1690 * Initialize the page tables for the low globals:
1691 * cover this address range:
1692 * LOW_GLOBAL_BASE_ADDRESS + 2MB
1693 */
5ba3f43e
A
1694 va_l1 = va_l2 = LOW_GLOBAL_BASE_ADDRESS;
1695 cpu_l1_tte = cpu_tte + ((va_l1 & ARM_TT_L1_INDEX_MASK) >> ARM_TT_L1_SHIFT);
1696 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);
5ba3f43e
A
1697 ptpage_vaddr = alloc_ptpage(TRUE);
1698 *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;
1699 bzero((void *)ptpage_vaddr, ARM_PGBYTES);
1700
1701 /*
1702 * Initialize l2 page table pages :
1703 * cover this address range:
1704 * KERNEL_DYNAMIC_ADDR - VM_MAX_KERNEL_ADDRESS
1705 */
d9a64523 1706 va_l1 = dynamic_memory_begin;
5c9f4661 1707 va_l1_end = VM_MAX_KERNEL_ADDRESS;
5ba3f43e
A
1708 cpu_l1_tte = cpu_tte + ((va_l1 & ARM_TT_L1_INDEX_MASK) >> ARM_TT_L1_SHIFT);
1709
1710 while (va_l1 < va_l1_end) {
1711 if (*cpu_l1_tte == ARM_TTE_EMPTY) {
1712 /* Allocate a page and setup L1 Table TTE in L1 */
1713 ptpage_vaddr = alloc_ptpage(TRUE);
d9a64523 1714 *cpu_l1_tte = (kvtophys(ptpage_vaddr) & ARM_TTE_TABLE_MASK) | ARM_TTE_TYPE_TABLE | ARM_TTE_VALID | ARM_DYNAMIC_TABLE_XN;
5ba3f43e
A
1715 bzero((void *)ptpage_vaddr, ARM_PGBYTES);
1716 }
1717
1718 if ((va_l1 + ARM_TT_L1_SIZE) < va_l1) {
1719 /* If this is the last L1 entry, it must cover the last mapping. */
1720 break;
1721 }
1722
1723 va_l1 += ARM_TT_L1_SIZE;
1724 cpu_l1_tte++;
1725 }
5ba3f43e
A
1726
1727#if KASAN
d9a64523
A
1728 /* record the extent of the physmap */
1729 physmap_vbase = physmap_base;
1730 physmap_vtop = static_memory_end;
5ba3f43e 1731 kasan_init();
cb323159
A
1732#endif /* KASAN */
1733
1734#if MONOTONIC
1735 mt_early_init();
1736#endif /* MONOTONIC */
5ba3f43e 1737
d9a64523 1738 set_tbi();
d9a64523
A
1739
1740 arm_vm_physmap_init(args, physmap_base, dynamic_memory_begin);
5ba3f43e 1741 set_mmu_ttb_alternate(cpu_ttep & TTBR_BADDR_MASK);
cb323159
A
1742
1743
1744 set_mmu_ttb(invalid_ttep & TTBR_BADDR_MASK);
1745
5ba3f43e 1746 flush_mmu_tlb();
c6bf4f31
A
1747#if defined(HAS_VMSA_LOCK)
1748 vmsa_lock();
1749#endif
d9a64523
A
1750 kva_active = TRUE;
1751 // global table pointers may need to be different due to physical aperture remapping
1752 cpu_tte = (tt_entry_t*)(phystokv(cpu_ttep));
1753 invalid_tte = (tt_entry_t*)(phystokv(invalid_ttep));
5ba3f43e 1754
5ba3f43e
A
1755 sane_size = mem_size - (avail_start - gPhysBase);
1756 max_mem = mem_size;
d9a64523 1757 vm_kernel_slid_base = segLOWESTTEXT;
5ba3f43e 1758 vm_kernel_slid_top = vm_prelink_einfo;
d9a64523 1759 vm_kernel_slide = segTEXTB-VM_KERNEL_LINK_ADDRESS;
5ba3f43e
A
1760 vm_kernel_stext = segTEXTB;
1761 assert(segDATACONSTB == segTEXTB + segSizeTEXT);
d9a64523 1762 assert(segTEXTEXECB == segDATACONSTB + segSizeDATACONST);
5ba3f43e
A
1763 vm_kernel_etext = segTEXTB + segSizeTEXT + segSizeDATACONST + segSizeTEXTEXEC;
1764
d9a64523 1765 dynamic_memory_begin = ROUND_TWIG(dynamic_memory_begin);
c6bf4f31
A
1766#if defined(KERNEL_INTEGRITY_CTRR) && defined(CONFIG_XNUPOST)
1767 // reserve a 32MB region without permission overrides to use later for a CTRR unit test
1768 {
1769 extern vm_offset_t ctrr_test_page;
1770 tt_entry_t *new_tte;
1771
1772 ctrr_test_page = dynamic_memory_begin;
1773 dynamic_memory_begin += ARM_TT_L2_SIZE;
1774 cpu_l1_tte = cpu_tte + ((ctrr_test_page & ARM_TT_L1_INDEX_MASK) >> ARM_TT_L1_SHIFT);
1775 assert((*cpu_l1_tte) & ARM_TTE_VALID);
1776 cpu_l2_tte = ((tt_entry_t *) phystokv(((*cpu_l1_tte) & ARM_TTE_TABLE_MASK))) + ((ctrr_test_page & ARM_TT_L2_INDEX_MASK) >> ARM_TT_L2_SHIFT);
1777 assert((*cpu_l2_tte) == ARM_TTE_EMPTY);
1778 new_tte = (tt_entry_t *)alloc_ptpage(FALSE);
1779 bzero(new_tte, ARM_PGBYTES);
1780 *cpu_l2_tte = (kvtophys((vm_offset_t)new_tte) & ARM_TTE_TABLE_MASK) | ARM_TTE_TYPE_TABLE | ARM_TTE_VALID;
1781 }
1782#endif /* defined(KERNEL_INTEGRITY_CTRR) && defined(CONFIG_XNUPOST) */
1783#if XNU_MONITOR
1784 for (vm_offset_t cur = (vm_offset_t)pmap_stacks_start; cur < (vm_offset_t)pmap_stacks_end; cur += ARM_PGBYTES) {
1785 arm_vm_map(cpu_tte, cur, ARM_PTE_EMPTY);
1786 }
1787#endif
d9a64523
A
1788 pmap_bootstrap(dynamic_memory_begin);
1789
1790 disable_preemption();
5ba3f43e
A
1791
1792 /*
1793 * Initialize l3 page table pages :
1794 * cover this address range:
1795 * 2MB + FrameBuffer size + 10MB for each 256MB segment
1796 */
1797
1798 mem_segments = (mem_size + 0x0FFFFFFF) >> 28;
1799
d9a64523 1800 va_l1 = dynamic_memory_begin;
5ba3f43e
A
1801 va_l1_end = va_l1 + ((2 + (mem_segments * 10)) << 20);
1802 va_l1_end += round_page(args->Video.v_height * args->Video.v_rowBytes);
1803 va_l1_end = (va_l1_end + 0x00000000007FFFFFULL) & 0xFFFFFFFFFF800000ULL;
1804
1805 cpu_l1_tte = cpu_tte + ((va_l1 & ARM_TT_L1_INDEX_MASK) >> ARM_TT_L1_SHIFT);
1806
1807 while (va_l1 < va_l1_end) {
1808
1809 va_l2 = va_l1;
1810
1811 if (((va_l1 & ~ARM_TT_L1_OFFMASK)+ARM_TT_L1_SIZE) < va_l1) {
1812 /* If this is the last L1 entry, it must cover the last mapping. */
1813 va_l2_end = va_l1_end;
1814 } else {
1815 va_l2_end = MIN((va_l1 & ~ARM_TT_L1_OFFMASK)+ARM_TT_L1_SIZE, va_l1_end);
1816 }
1817
1818 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);
5ba3f43e
A
1819
1820 while (va_l2 < va_l2_end) {
1821 pt_entry_t * ptp;
1822 pmap_paddr_t ptp_phys;
1823
1824 /* Allocate a page and setup L3 Table TTE in L2 */
1825 ptp = (pt_entry_t *) alloc_ptpage(FALSE);
1826 ptp_phys = (pmap_paddr_t)kvtophys((vm_offset_t)ptp);
1827
cb323159 1828 pmap_init_pte_page(kernel_pmap, ptp, va_l2, 3, TRUE, TRUE);
5ba3f43e 1829
d9a64523 1830 *cpu_l2_tte = (pa_to_tte (ptp_phys)) | ARM_TTE_TYPE_TABLE | ARM_TTE_VALID | ARM_DYNAMIC_TABLE_XN;
5ba3f43e
A
1831
1832 va_l2 += ARM_TT_L2_SIZE;
1833 cpu_l2_tte++;
1834 };
cb323159 1835
5ba3f43e
A
1836 va_l1 = va_l2_end;
1837 cpu_l1_tte++;
1838 }
5ba3f43e
A
1839
1840 /*
1841 * Initialize l3 page table pages :
1842 * cover this address range:
1843 * (VM_MAX_KERNEL_ADDRESS & CPUWINDOWS_BASE_MASK) - VM_MAX_KERNEL_ADDRESS
1844 */
5ba3f43e
A
1845 va_l1 = VM_MAX_KERNEL_ADDRESS & CPUWINDOWS_BASE_MASK;
1846 va_l1_end = VM_MAX_KERNEL_ADDRESS;
1847
1848 cpu_l1_tte = cpu_tte + ((va_l1 & ARM_TT_L1_INDEX_MASK) >> ARM_TT_L1_SHIFT);
1849
1850 while (va_l1 < va_l1_end) {
1851
1852 va_l2 = va_l1;
1853
1854 if (((va_l1 & ~ARM_TT_L1_OFFMASK)+ARM_TT_L1_SIZE) < va_l1) {
1855 /* If this is the last L1 entry, it must cover the last mapping. */
1856 va_l2_end = va_l1_end;
1857 } else {
1858 va_l2_end = MIN((va_l1 & ~ARM_TT_L1_OFFMASK)+ARM_TT_L1_SIZE, va_l1_end);
1859 }
1860
1861 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);
5ba3f43e
A
1862
1863 while (va_l2 < va_l2_end) {
1864 pt_entry_t * ptp;
1865 pmap_paddr_t ptp_phys;
1866
1867 /* Allocate a page and setup L3 Table TTE in L2 */
1868 ptp = (pt_entry_t *) alloc_ptpage(FALSE);
1869 ptp_phys = (pmap_paddr_t)kvtophys((vm_offset_t)ptp);
1870
cb323159 1871 pmap_init_pte_page(kernel_pmap, ptp, va_l2, 3, TRUE, TRUE);
5ba3f43e 1872
d9a64523 1873 *cpu_l2_tte = (pa_to_tte (ptp_phys)) | ARM_TTE_TYPE_TABLE | ARM_TTE_VALID | ARM_DYNAMIC_TABLE_XN;
5ba3f43e
A
1874
1875 va_l2 += ARM_TT_L2_SIZE;
1876 cpu_l2_tte++;
1877 };
cb323159 1878
5ba3f43e
A
1879 va_l1 = va_l2_end;
1880 cpu_l1_tte++;
1881 }
5ba3f43e
A
1882
1883#if __ARM64_PMAP_SUBPAGE_L1__ && __ARM_16K_PG__
1884 /*
1885 * In this configuration, the bootstrap mappings (arm_vm_init) and
1886 * the heap mappings occupy separate L1 regions. Explicitly set up
1887 * the heap L1 allocations here.
1888 */
1889 va_l1 = VM_MIN_KERNEL_ADDRESS & ~ARM_TT_L1_OFFMASK;
1890 cpu_l1_tte = cpu_tte + ((va_l1 & ARM_TT_L1_INDEX_MASK) >> ARM_TT_L1_SHIFT);
1891
1892 while ((va_l1 >= (VM_MIN_KERNEL_ADDRESS & ~ARM_TT_L1_OFFMASK)) && (va_l1 < VM_MAX_KERNEL_ADDRESS)) {
1893 /*
1894 * If the L1 entry has not yet been allocated, allocate it
1895 * now and treat it as a heap table.
1896 */
1897 if (*cpu_l1_tte == ARM_TTE_EMPTY) {
1898 tt_entry_t *new_tte = (tt_entry_t*)alloc_ptpage(FALSE);
1899 bzero(new_tte, ARM_PGBYTES);
d9a64523 1900 *cpu_l1_tte = (kvtophys((vm_offset_t)new_tte) & ARM_TTE_TABLE_MASK) | ARM_TTE_TYPE_TABLE | ARM_TTE_VALID | ARM_DYNAMIC_TABLE_XN;
5ba3f43e
A
1901 }
1902
1903 cpu_l1_tte++;
1904 va_l1 += ARM_TT_L1_SIZE;
1905 }
1906#endif
1907
1908 /*
1909 * Adjust avail_start so that the range that the VM owns
1910 * starts on a PAGE_SIZE aligned boundary.
1911 */
1912 avail_start = (avail_start + PAGE_MASK) & ~PAGE_MASK;
1913
c6bf4f31
A
1914#if XNU_MONITOR
1915 pmap_static_allocations_done();
1916#endif
5ba3f43e
A
1917 first_avail = avail_start;
1918 patch_low_glo_static_region(args->topOfKernelData, avail_start - args->topOfKernelData);
d9a64523 1919 enable_preemption();
5ba3f43e
A
1920}
1921