Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 | /* * Copyright (c) 2007-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /** * Machine-dependent structures for the physical map module. * * This header file contains the types and prototypes that make up the public * pmap API that's exposed to the rest of the kernel. Any types/prototypes used * strictly by the pmap itself should be placed into one of the osfmk/arm/pmap/ * header files. * * To prevent circular dependencies and exposing anything not needed by the * rest of the kernel, this file shouldn't include ANY of the internal * osfmk/arm/pmap/ header files. */ #ifndef _ARM_PMAP_H_ #define _ARM_PMAP_H_ #include <mach_assert.h> #include <arm64/proc_reg.h> #ifndef ASSEMBLER #include <stdatomic.h> #include <stdbool.h> #include <libkern/section_keywords.h> #include <mach/kern_return.h> #include <mach/machine/vm_types.h> #include <arm64/sptm/pmap/pmap_public.h> #include <kern/ast.h> #include <mach/arm/thread_status.h> #include <os/refcnt.h> #include <arm64/tlb.h> /* Shift for 2048 max virtual ASIDs (2048 pmaps). */ #define ASID_SHIFT (11) /* Max supported ASIDs (can be virtual). */ #define MAX_ASIDS (1 << ASID_SHIFT) /* Shift for the maximum ARM ASID value (256 or 65536) */ #ifndef ARM_ASID_SHIFT #if HAS_16BIT_ASID #define ARM_ASID_SHIFT (16) #else #define ARM_ASID_SHIFT (8) #endif /* HAS_16BIT_ASID */ #endif /* ARM_ASID_SHIFT */ /* Max ASIDs supported by the hardware. */ #define ARM_MAX_ASIDS (1 << ARM_ASID_SHIFT) /* Number of bits in a byte. */ #define NBBY (8) /** * The maximum number of hardware ASIDs used by the pmap for user address spaces. * * One ASID is always dedicated to the kernel (ASID 0). On systems with software- * based spectre/meltdown mitigations, each address space technically uses two * hardware ASIDs (one for EL1 and one for EL0) so the total number of available * ASIDs a user process can use is halved on those systems. */ #if __ARM_KERNEL_PROTECT__ #define MAX_HW_ASIDS (ARM_MAX_ASIDS >> 1) #else #define MAX_HW_ASIDS ARM_MAX_ASIDS #endif /* __ARM_KERNEL_PROTECT__ */ /** * Maximum number of Virtual Machine IDs. * * All even number physical VMIDs are reserved for SK usage. Thus only 128 * logical VMIDs are available. Software will convert the logical VMID to * the proper odd numbered physical VMID when allocating/freeing VMIDs. */ #ifndef ARM_VMID_SHIFT #define ARM_VMID_SHIFT (7) #endif /* ARM_VMID_SHIFT */ #define ARM_MAX_VMIDS (1 << ARM_VMID_SHIFT) /* XPRR virtual register map */ /* Maximum number of CPU windows per-cpu. */ #define CPUWINDOWS_MAX 4 #if defined(ARM_LARGE_MEMORY) /* * 2 L1 tables (Linear KVA and V=P), plus 2*16 L2 tables map up to (16*64GB) 1TB of DRAM * Upper limit on how many pages can be consumed by bootstrap page tables */ #define BOOTSTRAP_TABLE_SIZE (ARM_PGBYTES * 34) #else /* defined(ARM_LARGE_MEMORY) */ #define BOOTSTRAP_TABLE_SIZE (ARM_PGBYTES * 8) #endif /* defined(ARM_LARGE_MEMORY) */ typedef uint64_t tt_entry_t; /* translation table entry type */ typedef uint64_t pt_entry_t; /* page table entry type */ /* Used to represent a NULL page/translation table entry pointer. */ #define PT_ENTRY_NULL ((pt_entry_t *) 0) #define TT_ENTRY_NULL ((tt_entry_t *) 0) /** * Number of PTE pointers in a single PVE. This must be 2, since the algorithm * has been optimized to that case. Should this change in the future, both * enter_pv() and remove_pv() will need to be modified accordingly. In addition * to this, the documentation and the LLDB macros that walk PV lists will also * need to be adapted. */ #define PTE_PER_PVE 2 _Static_assert(PTE_PER_PVE == 2, "PTE_PER_PVE is not 2"); /** * Structure to track the active mappings for a given page. This structure is * used in the pv_head_table when a physical page has more than one mapping to * it. Each entry in this linked list of structures can represent * up to PTE_PER_PVE mappings. */ typedef struct pv_entry { /* Linked list to the next mapping of the physical page. */ struct pv_entry *pve_next; /* Pointer to the page table entry for this mapping. */ pt_entry_t *pve_ptep[PTE_PER_PVE]; } pv_entry_t; /** * Structure that tracks free pv_entry nodes for the pv_head_table. Each one * of these nodes represents a single mapping to a physical page, so a new node * is allocated whenever a new mapping is created. */ typedef struct { pv_entry_t *list; uint32_t count; } pv_free_list_t; /** * Forward declaration of the structure that controls page table geometry and * TTE/PTE format. */ struct page_table_attr; struct pmap_cpu_data { unsigned int cpu_number; bool copywindow_strong_sync[CPUWINDOWS_MAX]; bool inflight_disconnect; pv_free_list_t pv_free; pv_entry_t *pv_free_spill_marker; }; typedef struct pmap_cpu_data pmap_cpu_data_t; #include <mach/vm_prot.h> #include <mach/vm_statistics.h> #include <mach/machine/vm_param.h> #include <kern/kern_types.h> #include <kern/thread.h> #include <kern/queue.h> #include <sys/cdefs.h> /* Base address for low globals. */ #if defined(ARM_LARGE_MEMORY) #define LOW_GLOBAL_BASE_ADDRESS 0xfffffe0000000000ULL #else /* defined(ARM_LARGE_MEMORY) */ #define LOW_GLOBAL_BASE_ADDRESS 0xfffffff000000000ULL #endif /* defined(ARM_LARGE_MEMORY) */ /* * This indicates (roughly) where there is free space for the VM * to use for the heap; this does not need to be precise. */ #if defined(KERNEL_INTEGRITY_KTRR) || defined(KERNEL_INTEGRITY_CTRR) #if defined(ARM_LARGE_MEMORY) #define KERNEL_PMAP_HEAP_RANGE_START (VM_MIN_KERNEL_AND_KEXT_ADDRESS+ARM_TT_L1_SIZE) #else /* defined(ARM_LARGE_MEMORY) */ #define KERNEL_PMAP_HEAP_RANGE_START VM_MIN_KERNEL_AND_KEXT_ADDRESS #endif /* defined(ARM_LARGE_MEMORY) */ #else /* defined(KERNEL_INTEGRITY_KTRR) || defined(KERNEL_INTEGRITY_CTRR) */ #if defined(ARM_LARGE_MEMORY) /* For large memory systems with no KTRR/CTRR such as virtual machines */ #define KERNEL_PMAP_HEAP_RANGE_START (VM_MIN_KERNEL_AND_KEXT_ADDRESS+ARM_TT_L1_SIZE) #else #define KERNEL_PMAP_HEAP_RANGE_START LOW_GLOBAL_BASE_ADDRESS #endif #endif /* defined(KERNEL_INTEGRITY_KTRR) || defined(KERNEL_INTEGRITY_CTRR) */ /** * For setups where the VM page size does not match the hardware page size (the * VM page size must be a multiple of the hardware page size), we will need to * determine what the page ratio is. */ #define PAGE_RATIO ((1 << PAGE_SHIFT) >> ARM_PGSHIFT) #define TEST_PAGE_RATIO_4 (PAGE_RATIO == 4) /* superpages */ #define SUPERPAGE_NBASEPAGES 1 /* No superpages support */ /* Convert addresses to pages and vice versa. No rounding is used. */ #define arm_atop(x) (((vm_map_address_t)(x)) >> ARM_PGSHIFT) #define arm_ptoa(x) (((vm_map_address_t)(x)) << ARM_PGSHIFT) /** * Round off or truncate to the nearest page. These will work for either * addresses or counts (i.e. 1 byte rounds to 1 page bytes). */ #define arm_round_page(x) ((((vm_map_address_t)(x)) + ARM_PGMASK) & ~ARM_PGMASK) #define arm_trunc_page(x) (((vm_map_address_t)(x)) & ~ARM_PGMASK) extern void flush_mmu_tlb_region(vm_offset_t va, unsigned length); extern uint64_t get_mmu_control(void); extern uint64_t get_aux_control(void); extern void set_aux_control(uint64_t); extern void set_mmu_ttb(uint64_t); extern void set_mmu_ttb_alternate(uint64_t); extern uint64_t get_tcr(void); extern void set_tcr(uint64_t); extern uint64_t pmap_get_arm64_prot(pmap_t, vm_offset_t); extern pmap_paddr_t get_mmu_ttb(void); extern pmap_paddr_t mmu_kvtop(vm_offset_t va); extern pmap_paddr_t mmu_kvtop_wpreflight(vm_offset_t va); extern pmap_paddr_t mmu_uvtop(vm_offset_t va); /* Convert address offset to translation table index */ #define ttel0num(a) ((a & ARM_TTE_L0_MASK) >> ARM_TT_L0_SHIFT) #define ttel1num(a) ((a & ARM_TTE_L1_MASK) >> ARM_TT_L1_SHIFT) #define ttel2num(a) ((a & ARM_TTE_L2_MASK) >> ARM_TT_L2_SHIFT) #define pa_to_tte(a) ((a) & ARM_TTE_TABLE_MASK) #define tte_to_pa(p) ((p) & ARM_TTE_TABLE_MASK) #define pa_to_pte(a) ((a) & ARM_PTE_PAGE_MASK) #define pte_to_pa(p) ((p) & ARM_PTE_PAGE_MASK) #define pte_to_ap(p) (((p) & ARM_PTE_APMASK) >> ARM_PTE_APSHIFT) #define pte_increment_pa(p) ((p) += ptoa(1)) #define TLBFLUSH_SIZE (ARM_TTE_MAX/((sizeof(unsigned int))*BYTE_SIZE)) #define pmap_cs_log(level, fmt, args...) #define pmap_cs_log_debug(fmt, args...) #define pmap_cs_log_info(fmt, args...) #define pmap_cs_log_error(fmt, args...) #define pmap_cs_log_force(level, fmt, args...) /** * Wrapper struct that represents a locked entry in the PV head table. * This struct should only be obtained as the return value from pvh_try_lock() * or the pvh_lock* functions. */ typedef struct { /* The pv_head_table entry obtained from the lock operation. */ uintptr_t pvh; /** * Token obtained from thread_priority_floor_start(), the lock was * placed in sleep mode using pvh_lock_enter_sleep_mode(). */ thread_pri_floor_t pri_token; /* The index of the locked physical page. */ unsigned int pai; } locked_pvh_t; /* Convert translation/page table entry to kernel virtual address. */ #define ttetokv(a) (phystokv(tte_to_pa(a))) #define ptetokv(a) (phystokv(pte_to_pa(a))) struct pmap { /* Pointer to the root translation table. */ tt_entry_t *tte; /* Physical page of the root translation table. */ pmap_paddr_t ttep; /* * The min and max fields represent the lowest and highest addressable VAs * as dictated strictly by the paging hierarchy (root level + root table size) * in conjunction with whether the root table is used with TTBR0, TTBR1, or VTTBR. * These fields do not encapsulate any higher-level address-space partitioning * policies. */ /* Lowest supported VA (inclusive) */ vm_map_address_t min; /* Highest supported VA (exclusive) */ vm_map_address_t max; #if ARM_PARAMETERIZED_PMAP /* Details about the page table layout. */ const struct page_table_attr * pmap_pt_attr; #endif /* ARM_PARAMETERIZED_PMAP */ /* Ledger tracking phys mappings */ ledger_t ledger; decl_lck_rw_data(, rwlock); /* Global list of pmaps */ queue_chain_t pmaps; /* Information representing the "nested" (shared) region in this pmap. */ struct pmap *nested_pmap; vm_map_address_t nested_region_addr; vm_map_offset_t nested_region_size; vm_map_offset_t nested_region_true_start; vm_map_offset_t nested_region_true_end; bitmap_t *nested_region_unnested_table_bitmap; /* PMAP reference count */ os_ref_atomic_t ref_count; /* Number of pmaps that nested this pmap without bounds set. */ uint32_t nested_no_bounds_refcnt; union { /** * Represents the address space identifier (ASID) for this pmap. * The value 0 is reserved for the kernel pmap; this field will * also be 0 for nested pmaps as those pmaps are never directly * activated on a CPU. This represents a virtual ASID that * is used to globally identify an address space on * the system. Depending upon hardware configuration, this * identifier may have a 1:1 correspondence with the hardware * ASID. */ uint16_t asid; /** * Represents the virtual machine identifier (VMID) for this pmap. * The value 0 is reserved. */ uint16_t vmid; }; #if MACH_ASSERT int pmap_pid; char pmap_procname[17]; #endif /* MACH_ASSERT */ bool reserved0; bool pmap_vm_map_cs_enforced; bool reserved1; unsigned int reserved2; unsigned int reserved3; #if defined(CONFIG_ROSETTA) /* Whether the pmap is used for Rosetta. */ bool is_rosetta; #else bool reserved4; #endif /* defined(CONFIG_ROSETTA) */ #if DEVELOPMENT || DEBUG bool footprint_suspended; bool footprint_was_suspended; #endif /* DEVELOPMENT || DEBUG */ /* Whether the No-Execute functionality is enabled. */ bool nx_enabled; /* Whether this pmap represents a 64-bit address space. */ bool is_64bit; /* Nested a pmap when the bounds were not set. */ bool nested_has_no_bounds_ref; /* The nesting bounds have been set. */ bool nested_bounds_set; #if HAS_APPLE_PAC bool disable_jop; #else bool reserved5; #endif /* HAS_APPLE_PAC */ bool reserved6; #define PMAP_TYPE_USER 0 /* ordinary pmap */ #define PMAP_TYPE_KERNEL 1 /* kernel pmap */ #define PMAP_TYPE_COMMPAGE 2 /* commpage pmap */ #define PMAP_TYPE_NESTED 3 /* pmap nested within another pmap */ uint8_t type; /* * TrustedExecutionMonitor manages its own address space data structure and * the PMAP is used as the owning structure for keeping this structure. */ uint32_t reserved7[4]; void *reserved8; uint8_t reserved9; /* The ID of the vm_map that this pmap is backing, if any */ vm_map_serial_t associated_vm_map_serial_id; }; #define PMAP_VASID(pmap) ((pmap)->asid) #define PMAP_HWASID(pmap) ((pmap)->asid & (MAX_HW_ASIDS - 1)) #if VM_DEBUG extern int pmap_list_resident_pages( pmap_t pmap, vm_offset_t *listp, int space); #else /* VM_DEBUG */ #define pmap_list_resident_pages(pmap, listp, space) (0) #endif /* VM_DEBUG */ extern int copysafe(vm_map_address_t from, vm_map_address_t to, uint32_t cnt, int type, uint32_t *bytes_copied); /* Globals shared between arm_vm_init and pmap */ extern tt_entry_t *cpu_tte; /* First CPUs translation table (shared with kernel pmap) */ extern pmap_paddr_t cpu_ttep; /* Physical translation table addr */ extern void *ropagetable_begin; extern void *ropagetable_end; extern tt_entry_t *invalid_tte; /* Global invalid translation table */ extern pmap_paddr_t invalid_ttep; /* Physical invalid translation table addr */ #define PMAP_CONTEXT(pmap, thread) /** * Platform dependent Prototypes */ extern void pmap_clear_user_ttb(void); extern void pmap_bootstrap(vm_offset_t); extern vm_map_address_t pmap_ptov(pmap_t, ppnum_t); extern pmap_paddr_t pmap_find_pa(pmap_t map, addr64_t va); extern pmap_paddr_t pmap_find_pa_nofault(pmap_t map, addr64_t va); extern ppnum_t pmap_find_phys(pmap_t map, addr64_t va); extern ppnum_t pmap_find_phys_nofault(pmap_t map, addr64_t va); extern void pmap_switch_user(thread_t th, vm_map_t map); extern void pmap_set_pmap(pmap_t pmap, thread_t thread); extern void pmap_gc(void); #if HAS_APPLE_PAC extern void * pmap_sign_user_ptr(void *value, ptrauth_key key, uint64_t data, uint64_t jop_key); extern void * pmap_auth_user_ptr(void *value, ptrauth_key key, uint64_t data, uint64_t jop_key); #endif /* HAS_APPLE_PAC */ /** * Interfaces implemented as macros. */ #define PMAP_SWITCH_USER(th, new_map, my_cpu) pmap_switch_user((th), (new_map)) #define pmap_kernel() (kernel_pmap) #define pmap_kernel_va(VA) \ (((VA) >= VM_MIN_KERNEL_ADDRESS) && ((VA) <= VM_MAX_KERNEL_ADDRESS)) #define pmap_attribute(pmap, addr, size, attr, value) (KERN_INVALID_ADDRESS) #define copyinmsg(from, to, cnt) copyin(from, to, cnt) #define copyoutmsg(from, to, cnt) copyout(from, to, cnt) /* Unimplemented interfaces. */ #define MACRO_NOOP #define pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr) MACRO_NOOP #define pmap_pageable(pmap, start, end, pageable) MACRO_NOOP extern pmap_paddr_t kvtophys(vm_offset_t va); extern pmap_paddr_t kvtophys_nofail(vm_offset_t va); extern vm_map_address_t phystokv(pmap_paddr_t pa); extern vm_map_address_t phystokv_range(pmap_paddr_t pa, vm_size_t *max_len); extern vm_map_address_t pmap_map(vm_map_address_t va, vm_offset_t sa, vm_offset_t ea, vm_prot_t prot, unsigned int flags); extern vm_map_address_t pmap_map_high_window_bd( vm_offset_t pa, vm_size_t len, vm_prot_t prot); extern kern_return_t pmap_map_block(pmap_t pmap, addr64_t va, ppnum_t pa, uint32_t size, vm_prot_t prot, int attr, unsigned int flags); extern kern_return_t pmap_map_block_addr(pmap_t pmap, addr64_t va, pmap_paddr_t pa, uint32_t size, vm_prot_t prot, int attr, unsigned int flags); extern void pmap_map_globals(void); #define PMAP_MAP_BD_DEVICE 0x0 #define PMAP_MAP_BD_WCOMB 0x1 #define PMAP_MAP_BD_POSTED 0x2 #define PMAP_MAP_BD_POSTED_REORDERED 0x3 #define PMAP_MAP_BD_POSTED_COMBINED_REORDERED 0x4 #define PMAP_MAP_BD_MASK 0x7 extern vm_map_address_t pmap_map_bd_with_options(vm_map_address_t va, vm_offset_t sa, vm_offset_t ea, vm_prot_t prot, int32_t options); extern vm_map_address_t pmap_map_bd(vm_map_address_t va, vm_offset_t sa, vm_offset_t ea, vm_prot_t prot); extern void pmap_init_pte_page(pmap_t, pt_entry_t *, vm_offset_t, unsigned int ttlevel, boolean_t alloc_ptd); extern boolean_t pmap_valid_address(pmap_paddr_t addr); extern void pmap_disable_NX(pmap_t pmap); extern void pmap_set_nested(pmap_t pmap); extern void pmap_create_commpages(vm_map_address_t *kernel_data_addr, vm_map_address_t *kernel_text_addr, vm_map_address_t *kernel_ro_data_addr, vm_map_address_t *user_text_addr); extern void pmap_insert_commpage(pmap_t pmap); extern vm_offset_t pmap_cpu_windows_copy_addr(int cpu_num, unsigned int index); extern unsigned int pmap_map_cpu_windows_copy(ppnum_t pn, vm_prot_t prot, unsigned int wimg_bits); extern void pmap_unmap_cpu_windows_copy(unsigned int index); extern vm_offset_t pmap_ro_zone_align(vm_offset_t); extern void pmap_ro_zone_memcpy(zone_id_t zid, vm_offset_t va, vm_offset_t offset, vm_offset_t new_data, vm_size_t new_data_size); extern uint64_t pmap_ro_zone_atomic_op(zone_id_t zid, vm_offset_t va, vm_offset_t offset, uint32_t op, uint64_t value); extern void pmap_ro_zone_bzero(zone_id_t zid, vm_offset_t va, vm_offset_t offset, vm_size_t size); extern boolean_t pmap_valid_page(ppnum_t pn); extern boolean_t pmap_bootloader_page(ppnum_t pn); extern boolean_t pmap_is_empty(pmap_t pmap, vm_map_offset_t start, vm_map_offset_t end); #define ARM_PMAP_MAX_OFFSET_DEFAULT 0x01 #define ARM_PMAP_MAX_OFFSET_MIN 0x02 #define ARM_PMAP_MAX_OFFSET_MAX 0x04 #define ARM_PMAP_MAX_OFFSET_DEVICE 0x08 #define ARM_PMAP_MAX_OFFSET_JUMBO 0x10 #if XNU_PLATFORM_iPhoneOS && EXTENDED_USER_VA_SUPPORT #define ARM_PMAP_MAX_OFFSET_EXTRA_JUMBO 0x20 #endif /* XNU_PLATFORM_iPhoneOS && EXTENDED_USER_VA_SUPPORT */ extern vm_map_offset_t pmap_max_offset(boolean_t is64, unsigned int option); extern vm_map_offset_t pmap_max_64bit_offset(unsigned int option); extern vm_map_offset_t pmap_max_32bit_offset(unsigned int option); boolean_t pmap_virtual_region(unsigned int region_select, vm_map_offset_t *startp, vm_map_size_t *size); boolean_t pmap_enforces_execute_only(pmap_t pmap); void pmap_abandon_measurement(void); /* pmap dispatch indices */ #define ARM_FAST_FAULT_INDEX 0 #define ARM_FORCE_FAST_FAULT_INDEX 1 #define MAPPING_FREE_PRIME_INDEX 2 #define MAPPING_REPLENISH_INDEX 3 #define PHYS_ATTRIBUTE_CLEAR_INDEX 4 #define PHYS_ATTRIBUTE_SET_INDEX 5 #define PMAP_BATCH_SET_CACHE_ATTRIBUTES_INDEX 6 #define PMAP_CHANGE_WIRING_INDEX 7 #define PMAP_CREATE_INDEX 8 #define PMAP_DESTROY_INDEX 9 #define PMAP_ENTER_OPTIONS_INDEX 10 /* #define PMAP_EXTRACT_INDEX 11 -- Not used*/ #define PMAP_FIND_PA_INDEX 12 #define PMAP_INSERT_COMMPAGE_INDEX 13 #define PMAP_IS_EMPTY_INDEX 14 #define PMAP_MAP_CPU_WINDOWS_COPY_INDEX 15 #define PMAP_MARK_PAGE_AS_PMAP_PAGE_INDEX 16 #define PMAP_NEST_INDEX 17 #define PMAP_PAGE_PROTECT_OPTIONS_INDEX 18 #define PMAP_PROTECT_OPTIONS_INDEX 19 #define PMAP_QUERY_PAGE_INFO_INDEX 20 #define PMAP_QUERY_RESIDENT_INDEX 21 #define PMAP_REFERENCE_INDEX 22 #define PMAP_REMOVE_OPTIONS_INDEX 23 #define PMAP_SET_CACHE_ATTRIBUTES_INDEX 25 #define PMAP_SET_NESTED_INDEX 26 #define PMAP_SET_PROCESS_INDEX 27 #define PMAP_SWITCH_INDEX 28 #define PMAP_SWITCH_USER_TTB_INDEX 29 #define PMAP_CLEAR_USER_TTB_INDEX 30 #define PMAP_UNMAP_CPU_WINDOWS_COPY_INDEX 31 #define PMAP_UNNEST_OPTIONS_INDEX 32 #define PMAP_FOOTPRINT_SUSPEND_INDEX 33 #define PMAP_CPU_DATA_INIT_INDEX 34 #define PMAP_RELEASE_PAGES_TO_KERNEL_INDEX 35 #define PMAP_SET_JIT_ENTITLED_INDEX 36 #define PMAP_UPDATE_COMPRESSOR_PAGE_INDEX 55 #define PMAP_TRIM_INDEX 56 #define PMAP_LEDGER_VERIFY_SIZE_INDEX 57 #define PMAP_LEDGER_ALLOC_INDEX 58 #define PMAP_LEDGER_FREE_INDEX 59 #if HAS_APPLE_PAC #define PMAP_SIGN_USER_PTR 60 #define PMAP_AUTH_USER_PTR 61 #endif /* HAS_APPLE_PAC */ #define PHYS_ATTRIBUTE_CLEAR_RANGE_INDEX 66 #if __has_feature(ptrauth_calls) && (defined(XNU_TARGET_OS_OSX) || (DEVELOPMENT || DEBUG)) #define PMAP_DISABLE_USER_JOP_INDEX 69 #endif /* __has_feature(ptrauth_calls) && (defined(XNU_TARGET_OS_OSX) || (DEVELOPMENT || DEBUG)) */ #define PMAP_SET_VM_MAP_CS_ENFORCED_INDEX 72 #define PMAP_SET_COMPILATION_SERVICE_CDHASH_INDEX 73 #define PMAP_MATCH_COMPILATION_SERVICE_CDHASH_INDEX 74 #define PMAP_NOP_INDEX 75 #define PMAP_RO_ZONE_MEMCPY_INDEX 76 #define PMAP_RO_ZONE_ATOMIC_OP_INDEX 77 #if DEVELOPMENT || DEBUG #define PMAP_TEST_TEXT_CORRUPTION_INDEX 79 #endif /* DEVELOPMENT || DEBUG */ #define PMAP_SET_LOCAL_SIGNING_PUBLIC_KEY_INDEX 84 #define PMAP_UNRESTRICT_LOCAL_SIGNING_INDEX 85 #define PMAP_RO_ZONE_BZERO_INDEX 90 #define PMAP_SET_TPRO_INDEX 98 #define PMAP_COUNT 99 /** * Value used when initializing pmap per-cpu data to denote that the structure * hasn't been initialized with its associated CPU number yet. */ #define PMAP_INVALID_CPU_NUM (~0U) /** * Align the pmap per-cpu data to the L2 cache size for each individual CPU's * data. This prevents accesses from one CPU affecting another, especially * when atomically updating fields. */ struct pmap_cpu_data_array_entry { pmap_cpu_data_t cpu_data; } __attribute__((aligned(MAX_L2_CLINE_BYTES))); /* Initialize the pmap per-CPU data for the current CPU. */ extern void pmap_cpu_data_init(void); /* Get the pmap per-CPU data for the current CPU. */ extern pmap_cpu_data_t *pmap_get_cpu_data(void); /* Get the pmap per-CPU data for an arbitrary CPU. */ extern pmap_cpu_data_t *pmap_get_remote_cpu_data(unsigned int cpu); /* * For long-running PV list operations, we pick a reasonable maximum chunk size * beyond which we will exit to preemptible context to avoid excessive preemption * latency and PVH lock timeouts. */ #define PMAP_MAX_PV_LIST_CHUNK_SIZE 64 /* * For most batched page operations, we pick a sane default page count * interval at which to check for pending preemption and exit the PPL if found. */ #define PMAP_DEFAULT_PREEMPTION_CHECK_PAGE_INTERVAL 64 static inline bool _pmap_pending_preemption_real(void) { return !!(*((volatile ast_t*)ast_pending()) & AST_URGENT); } #if SCHED_HYGIENE_DEBUG && (DEBUG || DEVELOPMENT) bool pmap_pending_preemption(void); // more complicated, so externally defined #else /* SCHED_HYGIENE_DEBUG && (DEBUG || DEVELOPMENT) */ #define pmap_pending_preemption _pmap_pending_preemption_real #endif /* SCHED_HYGIENE_DEBUG && (DEBUG || DEVELOPMENT) */ #define MARK_AS_PMAP_TEXT #define MARK_AS_PMAP_DATA #define MARK_AS_PMAP_RODATA extern void pmap_nop(pmap_t); extern lck_grp_t pmap_lck_grp; extern void CleanPoC_DcacheRegion_Force_nopreempt_nohid_nobarrier(vm_offset_t va, size_t length); #define pmap_force_dcache_clean(va, sz) CleanPoC_DcacheRegion_Force(va, sz) #define pmap_simple_lock(l) simple_lock(l, &pmap_lck_grp) #define pmap_simple_unlock(l) simple_unlock(l) #define pmap_simple_lock_try(l) simple_lock_try(l, &pmap_lck_grp) #define pmap_simple_lock_assert(l, t) simple_lock_assert(l, t) #if DEVELOPMENT || DEBUG extern kern_return_t pmap_test_text_corruption(pmap_paddr_t); #endif /* DEVELOPMENT || DEBUG */ /* Check if a page has any mappings. */ extern bool pmap_is_page_free(pmap_paddr_t paddr); #endif /* #ifndef ASSEMBLER */ #if __ARM_KERNEL_PROTECT__ /* * The exception vector mappings start at the middle of the kernel page table * range (so that the EL0 mapping can be located at the base of the range). */ #define ARM_KERNEL_PROTECT_EXCEPTION_START ((~((ARM_TT_ROOT_SIZE + ARM_TT_ROOT_INDEX_MASK) / 2ULL)) + 1ULL) #endif /* __ARM_KERNEL_PROTECT__ */ #endif /* #ifndef _ARM_PMAP_H_ */ |