1 /*
2 * Copyright (c) 2020 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 * This header file stores the types, and prototypes used strictly by the pmap
30 * itself. The public pmap API exported to the rest of the kernel should be
31 * located in osfmk/arm/pmap.h.
32 *
33 * This file will automatically include all of the other internal arm/pmap/
34 * headers so .c files will only need to include this one header.
35 */
36 #ifndef _ARM_PMAP_PMAP_INTERNAL_H_
37 #define _ARM_PMAP_PMAP_INTERNAL_H_
38
39 #include <stdint.h>
40
41 #include <kern/debug.h>
42 #include <kern/locks.h>
43 #include <mach/vm_types.h>
44 #include <mach_assert.h>
45
46 #include <arm/cpu_data.h>
47 #include <arm64/proc_reg.h>
48
49 /**
50 * arm/pmap.h and the other /arm/pmap/ internal header files are safe to be
51 * included in this file since they shouldn't rely on any of the internal pmap
52 * header files (so no circular dependencies). Implementation files will only
53 * need to include this one header to get all of the relevant pmap types.
54 */
55 #include <arm/pmap.h>
56 #include <arm/pmap/pmap_data.h>
57 #include <arm/pmap/pmap_pt_geometry.h>
58
59 #if XNU_MONITOR
60 /**
61 * Temporary macros and prototypes needed to implement the ppl_handler_table.
62 *
63 * Eventually all calls to these macros will be in pmap_ppl_interface.c and
64 * these macros can be moved into that .c file.
65 *
66 * The <function>_internal() externs in here are also only included to be used
67 * by the ppl_handler_table. Once the ppl_handler_table moves into
68 * pmap_ppl_interface.c, then these prototypes can be removed (the
69 * PMAP_SUPPORT_PROTOTYPES() macro creates these prototypes automatically).
70 *
71 * TODO: Move PMAP_SUPPORT_PROTOTYPES_*() macros into pmap_ppl_interface.c and
72 * remove these _internal() prototypes.
73 */
74
75 extern pmap_paddr_t pmap_release_ppl_pages_to_kernel_internal(void);
76 extern kern_return_t mapping_free_prime_internal(void);
77
78 extern void pmap_ledger_verify_size_internal(size_t);
79 extern ledger_t pmap_ledger_alloc_internal(void);
80 extern void pmap_ledger_free_internal(ledger_t);
81
82 /**
83 * This macro generates prototypes for the *_internal functions, which represent
84 * the PPL interface. When the PPL is enabled, this will also generate
85 * prototypes for the PPL entrypoints (*_ppl), as well as generating the
86 * entrypoints themselves.
87 *
88 * Since these macros generate code, they should only be called from a single
89 * implementation file for each PPL entry point.
90 */
91 #define GEN_ASM_NAME(__function_name) _##__function_name##_ppl
92
93 #define PMAP_SUPPORT_PROTOTYPES_WITH_ASM_INTERNAL(__return_type, __function_name, __function_args, __function_index, __assembly_function_name) \
94 extern __return_type __function_name##_internal __function_args; \
95 extern __return_type __function_name##_ppl __function_args; \
96 __asm__ (".text \n" \
97 ".align 2 \n" \
98 ".globl " #__assembly_function_name "\n" \
99 #__assembly_function_name ":\n" \
100 "mov x15, " #__function_index "\n" \
101 "b _aprr_ppl_enter\n")
102
103 #define PMAP_SUPPORT_PROTOTYPES_WITH_ASM(__return_type, __function_name, __function_args, __function_index, __assembly_function_name) \
104 PMAP_SUPPORT_PROTOTYPES_WITH_ASM_INTERNAL(__return_type, __function_name, __function_args, __function_index, __assembly_function_name)
105
106 #define PMAP_SUPPORT_PROTOTYPES(__return_type, __function_name, __function_args, __function_index) \
107 PMAP_SUPPORT_PROTOTYPES_WITH_ASM(__return_type, __function_name, __function_args, __function_index, GEN_ASM_NAME(__function_name))
108 #else /* XNU_MONITOR */
109 #define PMAP_SUPPORT_PROTOTYPES(__return_type, __function_name, __function_args, __function_index) \
110 extern __return_type __function_name##_internal __function_args
111 #endif /* XNU_MONITOR */
112
113 /**
114 * Global variables exported to the rest of the internal pmap implementation.
115 */
116 extern lck_grp_t pmap_lck_grp;
117 extern bool hib_entry_pmap_lockdown;
118 extern pmap_paddr_t avail_start;
119 extern pmap_paddr_t avail_end;
120 extern uint32_t pmap_max_asids;
121
122 /**
123 * Functions exported to the rest of the internal pmap implementation.
124 */
125
126 #if XNU_MONITOR
127 extern void pmap_set_xprr_perm(unsigned int, unsigned int, unsigned int);
128 extern void pa_set_range_xprr_perm(pmap_paddr_t, pmap_paddr_t, unsigned int, unsigned int);
129 #endif /* XNU_MONITOR */
130
131 extern int pmap_remove_range_options(
132 pmap_t, vm_map_address_t, pt_entry_t *, pt_entry_t *, vm_map_address_t *, bool *, int);
133
134 extern void pmap_tte_deallocate(
135 pmap_t, vm_offset_t, vm_offset_t, bool, tt_entry_t *, unsigned int);
136
137 #if defined(PVH_FLAG_EXEC)
138 extern void pmap_set_ptov_ap(unsigned int, unsigned int, boolean_t);
139 #endif /* defined(PVH_FLAG_EXEC) */
140
141
142 extern pmap_t current_pmap(void);
143 extern void pmap_tt_ledger_credit(pmap_t, vm_size_t);
144 extern void pmap_tt_ledger_debit(pmap_t, vm_size_t);
145
146 extern void write_pte(pt_entry_t *, pt_entry_t);
147
148 /**
149 * The qsort function is used by various parts of the pmap but doesn't contain
150 * its own header file with prototype so it must be manually extern'd.
151 *
152 * The `cmpfunc_t` type is a pointer to a function that should return the
153 * following:
154 *
155 * return < 0 for a < b
156 * 0 for a == b
157 * > 0 for a > b
158 */
159 typedef int (*cmpfunc_t)(const void *a, const void *b);
160 extern void qsort(void *a, size_t n, size_t es, cmpfunc_t cmp);
161
162 /**
163 * Inline and macro functions exported for usage by other pmap modules.
164 *
165 * In an effort to not cause any performance regressions while breaking up the
166 * pmap, I'm keeping all functions originally marked as "static inline", as
167 * inline and moving them into header files to be shared across the pmap
168 * modules. In reality, many of these functions probably don't need to be inline
169 * and can be moved back into a .c file.
170 *
171 * TODO: rdar://70538514 (PMAP Cleanup: re-evaluate whether inline functions should actually be inline)
172 */
173
174 /**
175 * Macro used to ensure that pmap data structures aren't modified during
176 * hibernation image copying.
177 */
178 #if HIBERNATION
179 #define ASSERT_NOT_HIBERNATING() (assertf(!hib_entry_pmap_lockdown, \
180 "Attempted to modify PMAP data structures after hibernation image copying has begun."))
181 #else
182 #define ASSERT_NOT_HIBERNATING()
183 #endif /* HIBERNATION */
184
185 /* Helper macro for rounding an address up to a correctly aligned value. */
186 #define PMAP_ALIGN(addr, align) ((addr) + ((align) - 1) & ~((align) - 1))
187
188 /**
189 * pmap_data.h must be included before this point so that pmap_lock_mode_t is
190 * defined before the rest of the locking code.
191 */
192
193 /**
194 * Initialize a pmap object's reader/writer lock.
195 *
196 * @param pmap The pmap whose lock to initialize.
197 */
198 static inline void
pmap_lock_init(pmap_t pmap)199 pmap_lock_init(pmap_t pmap)
200 {
201 lck_rw_init(&pmap->rwlock, &pmap_lck_grp, 0);
202 pmap->rwlock.lck_rw_can_sleep = FALSE;
203 }
204
205 /**
206 * Destroy a pmap object's reader/writer lock.
207 *
208 * @param pmap The pmap whose lock to destroy.
209 */
210 static inline void
pmap_lock_destroy(pmap_t pmap)211 pmap_lock_destroy(pmap_t pmap)
212 {
213 lck_rw_destroy(&pmap->rwlock, &pmap_lck_grp);
214 }
215
216 /**
217 * Assert that the pmap lock is held in the given mode.
218 *
219 * @param pmap The pmap whose lock to assert is being held.
220 * @param mode The mode the lock should be held in.
221 */
222 static inline void
pmap_assert_locked(__unused pmap_t pmap,__unused pmap_lock_mode_t mode)223 pmap_assert_locked(__unused pmap_t pmap, __unused pmap_lock_mode_t mode)
224 {
225 #if MACH_ASSERT
226 switch (mode) {
227 case PMAP_LOCK_SHARED:
228 LCK_RW_ASSERT(&pmap->rwlock, LCK_RW_ASSERT_SHARED);
229 break;
230 case PMAP_LOCK_EXCLUSIVE:
231 LCK_RW_ASSERT(&pmap->rwlock, LCK_RW_ASSERT_EXCLUSIVE);
232 break;
233 default:
234 panic("%s: Unknown pmap_lock_mode. pmap=%p, mode=%d", __FUNCTION__, pmap, mode);
235 }
236 #endif
237 }
238
239 /**
240 * Assert that the pmap lock is held in any mode.
241 *
242 * @param pmap The pmap whose lock should be held.
243 */
244 __unused static inline void
pmap_assert_locked_any(__unused pmap_t pmap)245 pmap_assert_locked_any(__unused pmap_t pmap)
246 {
247 LCK_RW_ASSERT(&pmap->rwlock, LCK_RW_ASSERT_HELD);
248 }
249
250 /**
251 * Acquire a pmap object's reader/writer lock as either shared (read-only) or
252 * exclusive (read/write).
253 *
254 * @note Failed attempts to grab the lock will NOT go to sleep, they'll spin
255 * until the lock can be acquired.
256 *
257 * @param pmap The pmap whose lock to acquire.
258 * @param mode Whether to grab the lock as shared (read-only) or exclusive (read/write).
259 */
260 static inline void
pmap_lock(pmap_t pmap,pmap_lock_mode_t mode)261 pmap_lock(pmap_t pmap, pmap_lock_mode_t mode)
262 {
263 #if !XNU_MONITOR
264 mp_disable_preemption();
265 #endif
266
267 switch (mode) {
268 case PMAP_LOCK_SHARED:
269 lck_rw_lock_shared(&pmap->rwlock);
270 break;
271 case PMAP_LOCK_EXCLUSIVE:
272 lck_rw_lock_exclusive(&pmap->rwlock);
273 break;
274 default:
275 panic("%s: Unknown pmap_lock_mode. pmap=%p, mode=%d", __func__, pmap, mode);
276 }
277 }
278
279 /**
280 * Attempt to acquire the pmap lock in the specified mode. If the lock couldn't
281 * be acquired, then spin until it can be or a preemption is pending.
282 *
283 * @param pmap The pmap whose lock to attempt to acquire.
284 * @param mode Whether to grab the lock as shared (read-only) or exclusive (read/write).
285 *
286 * @return true if the lock was acquired, false if it was not and the caller should
287 * abort to some preemptible state to allow the preemption.
288 */
289 static inline bool
pmap_lock_preempt(pmap_t pmap,pmap_lock_mode_t mode)290 pmap_lock_preempt(pmap_t pmap, pmap_lock_mode_t mode)
291 {
292 bool ret = false;
293
294 /**
295 * When the lock cannot be acquired, we check if we are preemptible.
296 *
297 * If we are already preemptible, there's no point of exiting this function and aborting.
298 *
299 * Also, if we are very early in boot, we should just spin. This is similar to how
300 * pmap_verify_preemptible() is used in pmap.
301 */
302 do {
303 #if !XNU_MONITOR
304 mp_disable_preemption();
305 #endif
306
307 bool (^check_preemption)(void) = ^{
308 return pmap_pending_preemption();
309 };
310
311 switch (mode) {
312 case PMAP_LOCK_SHARED:
313 ret = lck_rw_lock_shared_b(&pmap->rwlock, check_preemption);
314 break;
315 case PMAP_LOCK_EXCLUSIVE:
316 ret = lck_rw_lock_exclusive_b(&pmap->rwlock, check_preemption);
317 break;
318 default:
319 panic("%s: Unknown pmap_lock_mode. pmap=%p, mode=%d", __func__, pmap, mode);
320 }
321
322 if (!ret) {
323 #if !XNU_MONITOR
324 mp_enable_preemption();
325 #endif
326 }
327 } while (!ret && (preemption_enabled() || (startup_phase < STARTUP_SUB_EARLY_BOOT)));
328
329 return ret;
330 }
331
332 /**
333 * Attempt to acquire the pmap lock in the specified mode. If the lock couldn't
334 * be acquired, then return immediately instead of spinning.
335 *
336 * @param pmap The pmap whose lock to attempt to acquire.
337 * @param mode Whether to grab the lock as shared (read-only) or exclusive (read/write).
338 *
339 * @return True if the lock was acquired, false otherwise.
340 */
341 static inline bool
pmap_try_lock(pmap_t pmap,pmap_lock_mode_t mode)342 pmap_try_lock(pmap_t pmap, pmap_lock_mode_t mode)
343 {
344 bool ret = false;
345
346 #if !XNU_MONITOR
347 mp_disable_preemption();
348 #endif
349
350 switch (mode) {
351 case PMAP_LOCK_SHARED:
352 ret = lck_rw_try_lock_shared(&pmap->rwlock);
353 break;
354 case PMAP_LOCK_EXCLUSIVE:
355 ret = lck_rw_try_lock_exclusive(&pmap->rwlock);
356 break;
357 default:
358 panic("%s: Unknown pmap_lock_mode. pmap=%p, mode=%d", __func__, pmap, mode);
359 }
360
361 if (!ret) {
362 #if !XNU_MONITOR
363 mp_enable_preemption();
364 #endif
365 }
366
367 return ret;
368 }
369
370 /**
371 * Attempts to promote an already acquired pmap lock from shared to exclusive.
372 *
373 * @param pmap The pmap whose lock should be promoted from shared to exclusive.
374 *
375 * @return True if successfully promoted, otherwise false upon failure in
376 * which case the shared lock is dropped.
377 */
378 static inline bool
pmap_lock_shared_to_exclusive(pmap_t pmap)379 pmap_lock_shared_to_exclusive(pmap_t pmap)
380 {
381 pmap_assert_locked(pmap, PMAP_LOCK_SHARED);
382
383 bool locked = lck_rw_lock_shared_to_exclusive(&pmap->rwlock);
384
385 #if !XNU_MONITOR
386 if (!locked) {
387 mp_enable_preemption();
388 }
389 #endif
390
391 return locked;
392 }
393
394 /**
395 * Release a pmap object's reader/writer lock.
396 *
397 * @param pmap The pmap whose lock to release.
398 * @param mode Which mode the lock should be in at time of release.
399 */
400 static inline void
pmap_unlock(pmap_t pmap,pmap_lock_mode_t mode)401 pmap_unlock(pmap_t pmap, pmap_lock_mode_t mode)
402 {
403 switch (mode) {
404 case PMAP_LOCK_SHARED:
405 lck_rw_unlock_shared(&pmap->rwlock);
406 break;
407 case PMAP_LOCK_EXCLUSIVE:
408 lck_rw_unlock_exclusive(&pmap->rwlock);
409 break;
410 default:
411 panic("%s: Unknown pmap_lock_mode. pmap=%p, mode=%d", __func__, pmap, mode);
412 }
413
414 #if !XNU_MONITOR
415 mp_enable_preemption();
416 #endif
417 }
418
419 #if __arm64__
420 /*
421 * Disable interrupts and return previous state.
422 *
423 * The PPL has its own interrupt state facility separately from
424 * ml_set_interrupts_enable(), since that function is not part of the
425 * PPL, and so doing things like manipulating untrusted data and
426 * taking ASTs.
427 *
428 * @return The previous interrupt state, to be restored with
429 * pmap_interrupts_restore().
430 */
431 static inline uint64_t __attribute__((warn_unused_result)) __used
pmap_interrupts_disable(void)432 pmap_interrupts_disable(void)
433 {
434 uint64_t state = __builtin_arm_rsr64("DAIF");
435
436 /* Ensure that debug exceptions are masked. */
437 assert((state & DAIF_DEBUGF) == DAIF_DEBUGF);
438
439 if ((state & DAIF_ALL) != DAIF_ALL) {
440 __builtin_arm_wsr64("DAIFSet", DAIFSC_ALL);
441 }
442
443 return state;
444 }
445
446 /*
447 * Restore previous interrupt state.
448 *
449 * @param state The previous interrupt state to restore.
450 */
451 static inline void __used
pmap_interrupts_restore(uint64_t state)452 pmap_interrupts_restore(uint64_t state)
453 {
454 // no unknown bits?
455 assert((state & ~DAIF_ALL) == 0);
456
457 /* Assert that previous state had debug exceptions masked. */
458 assert((state & DAIF_DEBUGF) == DAIF_DEBUGF);
459
460 if (state != DAIF_ALL) {
461 __builtin_arm_wsr64("DAIF", state);
462 }
463 }
464
465 /*
466 * Query interrupt state.
467 *
468 * ml_get_interrupts_enabled() is safe enough at the time of writing
469 * this comment, but because it is not considered part of the PPL, so
470 * could change without notice, and because it presently only checks
471 * DAIF_IRQ, we have our own version.
472 *
473 * @return true if interrupts are enable (not fully disabled).
474 */
475
476 static inline bool __attribute__((warn_unused_result)) __used
pmap_interrupts_enabled(void)477 pmap_interrupts_enabled(void)
478 {
479 return (__builtin_arm_rsr64("DAIF") & DAIF_ALL) != DAIF_ALL;
480 }
481 #endif /* __arm64__ */
482
483 #endif /* _ARM_PMAP_PMAP_INTERNAL_H_ */
484