2 * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <mach_assert.h>
32 #include <vm/vm_map.h>
33 #include <vm/vm_kern.h>
34 #include <kern/ledger.h>
35 #include <i386/pmap_internal.h>
37 void pmap_remove_range(
43 void pmap_remove_range_options(
50 void pmap_reusable_range(
57 uint32_t pmap_update_clear_pte_count
;
60 * The Intel platform can nest at the PDE level, so NBPDE (i.e. 2MB) at a time,
61 * on a NBPDE boundary.
64 /* These symbols may be referenced directly by VM */
65 uint64_t pmap_nesting_size_min
= NBPDE
;
66 uint64_t pmap_nesting_size_max
= 0 - (uint64_t)NBPDE
;
69 * kern_return_t pmap_nest(grand, subord, va_start, size)
71 * grand = the pmap that we will nest subord into
72 * subord = the pmap that goes into the grand
73 * va_start = start of range in pmap to be inserted
74 * nstart = start of range in pmap nested pmap
75 * size = Size of nest area (up to 16TB)
77 * Inserts a pmap into another. This is used to implement shared segments.
79 * Note that we depend upon higher level VM locks to insure that things don't change while
80 * we are doing this. For example, VM should not be doing any pmap enters while it is nesting
81 * or do 2 nests at once.
85 * This routine can nest subtrees either at the PDPT level (1GiB) or at the
86 * PDE level (2MiB). We currently disallow disparate offsets for the "subord"
87 * container and the "grand" parent. A minor optimization to consider for the
88 * future: make the "subord" truly a container rather than a full-fledged
89 * pagetable hierarchy which can be unnecessarily sparse (DRK).
92 kern_return_t
pmap_nest(pmap_t grand
, pmap_t subord
, addr64_t va_start
, addr64_t nstart
, uint64_t size
) {
93 vm_map_offset_t vaddr
, nvaddr
;
94 pd_entry_t
*pde
,*npde
;
98 assert(!is_ept_pmap(grand
));
99 assert(!is_ept_pmap(subord
));
101 if ((size
& (pmap_nesting_size_min
-1)) ||
102 (va_start
& (pmap_nesting_size_min
-1)) ||
103 (nstart
& (pmap_nesting_size_min
-1)) ||
104 ((size
>> 28) > 65536)) /* Max size we can nest is 16TB */
105 return KERN_INVALID_VALUE
;
108 panic("pmap_nest: size is invalid - %016llX\n", size
);
111 if (va_start
!= nstart
)
112 panic("pmap_nest: va_start(0x%llx) != nstart(0x%llx)\n", va_start
, nstart
);
114 PMAP_TRACE(PMAP_CODE(PMAP__NEST
) | DBG_FUNC_START
,
115 VM_KERNEL_ADDRHIDE(grand
), VM_KERNEL_ADDRHIDE(subord
),
116 VM_KERNEL_ADDRHIDE(va_start
));
118 nvaddr
= (vm_map_offset_t
)nstart
;
119 num_pde
= size
>> PDESHIFT
;
123 subord
->pm_shared
= TRUE
;
125 for (i
= 0; i
< num_pde
;) {
126 if (((nvaddr
& PDPTMASK
) == 0) && (num_pde
- i
) >= NPDEPG
&& cpu_64bit
) {
128 npde
= pmap64_pdpt(subord
, nvaddr
);
130 while (0 == npde
|| ((*npde
& INTEL_PTE_VALID
) == 0)) {
132 pmap_expand_pdpt(subord
, nvaddr
, PMAP_EXPAND_OPTIONS_NONE
);
134 npde
= pmap64_pdpt(subord
, nvaddr
);
136 *npde
|= INTEL_PDPTE_NESTED
;
138 i
+= (uint32_t)NPDEPG
;
141 npde
= pmap_pde(subord
, nvaddr
);
143 while (0 == npde
|| ((*npde
& INTEL_PTE_VALID
) == 0)) {
145 pmap_expand(subord
, nvaddr
, PMAP_EXPAND_OPTIONS_NONE
);
147 npde
= pmap_pde(subord
, nvaddr
);
156 vaddr
= (vm_map_offset_t
)va_start
;
160 for (i
= 0;i
< num_pde
;) {
163 if (((vaddr
& PDPTMASK
) == 0) && ((num_pde
- i
) >= NPDEPG
) && cpu_64bit
) {
164 npde
= pmap64_pdpt(subord
, vaddr
);
166 panic("pmap_nest: no PDPT, subord %p nstart 0x%llx", subord
, vaddr
);
168 pde
= pmap64_pdpt(grand
, vaddr
);
171 pmap_expand_pml4(grand
, vaddr
, PMAP_EXPAND_OPTIONS_NONE
);
173 pde
= pmap64_pdpt(grand
, vaddr
);
176 panic("pmap_nest: no PDPT, grand %p vaddr 0x%llx", grand
, vaddr
);
177 pmap_store_pte(pde
, tpde
);
179 i
+= (uint32_t) NPDEPG
;
182 npde
= pmap_pde(subord
, vaddr
);
184 panic("pmap_nest: no npde, subord %p vaddr 0x%llx", subord
, vaddr
);
186 pde
= pmap_pde(grand
, vaddr
);
187 if ((0 == pde
) && cpu_64bit
) {
189 pmap_expand_pdpt(grand
, vaddr
, PMAP_EXPAND_OPTIONS_NONE
);
191 pde
= pmap_pde(grand
, vaddr
);
195 panic("pmap_nest: no pde, grand %p vaddr 0x%llx", grand
, vaddr
);
197 pmap_store_pte(pde
, tpde
);
204 PMAP_TRACE(PMAP_CODE(PMAP__NEST
) | DBG_FUNC_END
, KERN_SUCCESS
);
210 * kern_return_t pmap_unnest(grand, vaddr)
212 * grand = the pmap that we will un-nest subord from
213 * vaddr = start of range in pmap to be unnested
215 * Removes a pmap from another. This is used to implement shared segments.
218 kern_return_t
pmap_unnest(pmap_t grand
, addr64_t vaddr
, uint64_t size
) {
222 addr64_t va_start
, va_end
;
223 uint64_t npdpt
= PMAP_INVALID_PDPTNUM
;
225 PMAP_TRACE(PMAP_CODE(PMAP__UNNEST
) | DBG_FUNC_START
,
226 VM_KERNEL_ADDRHIDE(grand
), VM_KERNEL_ADDRHIDE(vaddr
));
228 if ((size
& (pmap_nesting_size_min
-1)) ||
229 (vaddr
& (pmap_nesting_size_min
-1))) {
230 panic("pmap_unnest(%p,0x%llx,0x%llx): unaligned...\n",
234 assert(!is_ept_pmap(grand
));
236 /* align everything to PDE boundaries */
237 va_start
= vaddr
& ~(NBPDE
-1);
238 va_end
= (vaddr
+ size
+ NBPDE
- 1) & ~(NBPDE
-1);
239 size
= va_end
- va_start
;
243 num_pde
= size
>> PDESHIFT
;
246 for (i
= 0; i
< num_pde
; ) {
247 if ((pdptnum(grand
, vaddr
) != npdpt
) && cpu_64bit
) {
248 npdpt
= pdptnum(grand
, vaddr
);
249 pde
= pmap64_pdpt(grand
, vaddr
);
250 if (pde
&& (*pde
& INTEL_PDPTE_NESTED
)) {
251 pmap_store_pte(pde
, (pd_entry_t
)0);
252 i
+= (uint32_t) NPDEPG
;
257 pde
= pmap_pde(grand
, (vm_map_offset_t
)vaddr
);
259 panic("pmap_unnest: no pde, grand %p vaddr 0x%llx\n", grand
, vaddr
);
260 pmap_store_pte(pde
, (pd_entry_t
)0);
265 PMAP_UPDATE_TLBS(grand
, va_start
, va_end
);
269 PMAP_TRACE(PMAP_CODE(PMAP__UNNEST
) | DBG_FUNC_END
, KERN_SUCCESS
);
278 __unused
uint64_t size
,
279 __unused
unsigned int options
) {
280 return pmap_unnest(grand
, vaddr
, size
);
283 /* Invoked by the Mach VM to determine the platform specific unnest region */
285 boolean_t
pmap_adjust_unnest_parameters(pmap_t p
, vm_map_offset_t
*s
, vm_map_offset_t
*e
) {
287 boolean_t rval
= FALSE
;
294 pdpte
= pmap64_pdpt(p
, *s
);
295 if (pdpte
&& (*pdpte
& INTEL_PDPTE_NESTED
)) {
300 pdpte
= pmap64_pdpt(p
, *e
);
301 if (pdpte
&& (*pdpte
& INTEL_PDPTE_NESTED
)) {
302 *e
= ((*e
+ NBPDPT
) & ~(NBPDPT
-1));
312 * pmap_find_phys returns the (4K) physical page number containing a
313 * given virtual address in a given pmap.
314 * Note that pmap_pte may return a pde if this virtual address is
315 * mapped by a large page and this is taken into account in order
316 * to return the correct page number in this case.
319 pmap_find_phys(pmap_t pmap
, addr64_t va
)
328 is_ept
= is_ept_pmap(pmap
);
330 mp_disable_preemption();
332 /* This refcount test is a band-aid--several infrastructural changes
333 * are necessary to eliminate invocation of this routine from arbitrary
337 if (!pmap
->ref_count
)
340 pdep
= pmap_pde(pmap
, va
);
342 if ((pdep
!= PD_ENTRY_NULL
) && ((pde
= *pdep
) & PTE_VALID_MASK(is_ept
))) {
344 ppn
= (ppnum_t
) i386_btop(pte_to_pa(pde
));
345 ppn
+= (ppnum_t
) ptenum(va
);
348 ptp
= pmap_pte(pmap
, va
);
349 if ((PT_ENTRY_NULL
!= ptp
) && (((pte
= *ptp
) & PTE_VALID_MASK(is_ept
)) != 0)) {
350 ppn
= (ppnum_t
) i386_btop(pte_to_pa(pte
));
355 mp_enable_preemption();
361 * Update cache attributes for all extant managed mappings.
362 * Assumes PV for this page is locked, and that the page
363 * is managed. We assume that this physical page may be mapped in
364 * both EPT and normal Intel PTEs, so we convert the attributes
365 * to the corresponding format for each pmap.
367 * We assert that the passed set of attributes is a subset of the
368 * PHYS_CACHEABILITY_MASK.
371 pmap_update_cache_attributes_locked(ppnum_t pn
, unsigned attributes
) {
372 pv_rooted_entry_t pv_h
, pv_e
;
373 pv_hashed_entry_t pvh_e
, nexth
;
374 vm_map_offset_t vaddr
;
378 unsigned ept_attributes
;
380 assert(IS_MANAGED_PAGE(pn
));
381 assert(((~PHYS_CACHEABILITY_MASK
) & attributes
) == 0);
383 /* We don't support the PTA bit for EPT PTEs */
384 if (attributes
& INTEL_PTE_NCACHE
)
385 ept_attributes
= INTEL_EPT_NCACHE
;
387 ept_attributes
= INTEL_EPT_WB
;
389 pv_h
= pai_to_pvh(pn
);
390 /* TODO: translate the PHYS_* bits to PTE bits, while they're
391 * currently identical, they may not remain so
392 * Potential optimization (here and in page_protect),
393 * parallel shootdowns, check for redundant
394 * attribute modifications.
398 * Alter attributes on all mappings
400 if (pv_h
->pmap
!= PMAP_NULL
) {
402 pvh_e
= (pv_hashed_entry_t
)pv_e
;
406 vaddr
= PVE_VA(pv_e
);
407 ptep
= pmap_pte(pmap
, vaddr
);
410 panic("pmap_update_cache_attributes_locked: Missing PTE, pmap: %p, pn: 0x%x vaddr: 0x%llx kernel_pmap: %p", pmap
, pn
, vaddr
, kernel_pmap
);
412 is_ept
= is_ept_pmap(pmap
);
414 nexth
= (pv_hashed_entry_t
)queue_next(&pvh_e
->qlink
);
416 pmap_update_pte(ptep
, PHYS_CACHEABILITY_MASK
, attributes
);
418 pmap_update_pte(ptep
, INTEL_EPT_CACHE_MASK
, ept_attributes
);
420 PMAP_UPDATE_TLBS(pmap
, vaddr
, vaddr
+ PAGE_SIZE
);
422 } while ((pv_e
= (pv_rooted_entry_t
)nexth
) != pv_h
);
426 void x86_filter_TLB_coherency_interrupts(boolean_t dofilter
) {
427 assert(ml_get_interrupts_enabled() == 0 || get_preemption_level() != 0);
430 CPU_CR3_MARK_INACTIVE();
432 CPU_CR3_MARK_ACTIVE();
434 if (current_cpu_datap()->cpu_tlb_invalid
)
435 process_pmap_updates();
441 * Insert the given physical page (p) at
442 * the specified virtual address (v) in the
443 * target physical map with the protection requested.
445 * If specified, the page will be wired down, meaning
446 * that the related pte cannot be reclaimed.
448 * NB: This is the only routine which MAY NOT lazy-evaluate
449 * or lose information. That is, this routine must actually
450 * insert this page into the given map NOW.
456 vm_map_offset_t vaddr
,
459 vm_prot_t fault_type
,
463 return pmap_enter_options(pmap
, vaddr
, pn
, prot
, fault_type
, flags
, wired
, PMAP_EXPAND_OPTIONS_NONE
, NULL
);
470 vm_map_offset_t vaddr
,
473 __unused vm_prot_t fault_type
,
476 unsigned int options
,
480 pv_rooted_entry_t pv_h
;
482 pv_hashed_entry_t pvh_e
;
483 pv_hashed_entry_t pvh_new
;
486 pmap_paddr_t pa
= (pmap_paddr_t
) i386_ptob(pn
);
487 boolean_t need_tlbflush
= FALSE
;
490 boolean_t old_pa_locked
;
491 /* 2MiB mappings are confined to x86_64 by VM */
492 boolean_t superpage
= flags
& VM_MEM_SUPERPAGE
;
493 vm_object_t delpage_pm_obj
= NULL
;
494 uint64_t delpage_pde_index
= 0;
498 boolean_t is_altacct
;
504 if (pmap
== PMAP_NULL
)
505 return KERN_INVALID_ARGUMENT
;
507 is_ept
= is_ept_pmap(pmap
);
509 /* N.B. We can be supplied a zero page frame in the NOENTER case, it's an
510 * unused value for that scenario.
512 assert(pn
!= vm_page_fictitious_addr
);
514 if (pn
== vm_page_guard_addr
)
515 return KERN_INVALID_ARGUMENT
;
517 PMAP_TRACE(PMAP_CODE(PMAP__ENTER
) | DBG_FUNC_START
,
518 VM_KERNEL_ADDRHIDE(pmap
), VM_KERNEL_ADDRHIDE(vaddr
), pn
,
521 if ((prot
& VM_PROT_EXECUTE
) || !nx_enabled
|| !pmap
->nx_enabled
)
526 if (__improbable(set_NX
&& (pmap
== kernel_pmap
) && ((pmap_disable_kstack_nx
&& (flags
& VM_MEM_STACK
)) || (pmap_disable_kheap_nx
&& !(flags
& VM_MEM_STACK
))))) {
531 * Must allocate a new pvlist entry while we're unlocked;
532 * zalloc may cause pageout (which will lock the pmap system).
533 * If we determine we need a pvlist entry, we will unlock
534 * and allocate one. Then we will retry, throughing away
535 * the allocated entry later (if we no longer need it).
538 pvh_new
= PV_HASHED_ENTRY_NULL
;
540 pvh_e
= PV_HASHED_ENTRY_NULL
;
545 * Expand pmap to include this pte. Assume that
546 * pmap is always expanded to include enough hardware
547 * pages to map one VM page.
550 while ((pte
= pmap64_pde(pmap
, vaddr
)) == PD_ENTRY_NULL
) {
551 /* need room for another pde entry */
553 kr
= pmap_expand_pdpt(pmap
, vaddr
, options
);
554 if (kr
!= KERN_SUCCESS
)
559 while ((pte
= pmap_pte(pmap
, vaddr
)) == PT_ENTRY_NULL
) {
561 * Must unlock to expand the pmap
562 * going to grow pde level page(s)
565 kr
= pmap_expand(pmap
, vaddr
, options
);
566 if (kr
!= KERN_SUCCESS
)
571 if (options
& PMAP_EXPAND_OPTIONS_NOENTER
) {
577 if (superpage
&& *pte
&& !(*pte
& PTE_PS
)) {
579 * There is still an empty page table mapped that
580 * was used for a previous base page mapping.
581 * Remember the PDE and the PDE index, so that we
582 * can free the page at the end of this function.
584 delpage_pde_index
= pdeidx(pmap
, vaddr
);
585 delpage_pm_obj
= pmap
->pm_obj
;
589 old_pa
= pte_to_pa(*pte
);
590 pai
= pa_index(old_pa
);
591 old_pa_locked
= FALSE
;
594 PTE_IS_COMPRESSED(*pte
)) {
596 * "pmap" should be locked at this point, so this should
597 * not race with another pmap_enter() or pmap_remove_range().
599 assert(pmap
!= kernel_pmap
);
601 /* one less "compressed" */
602 OSAddAtomic64(-1, &pmap
->stats
.compressed
);
603 pmap_ledger_debit(pmap
, task_ledgers
.internal_compressed
,
605 if (*pte
& PTE_COMPRESSED_ALT
) {
608 task_ledgers
.alternate_accounting_compressed
,
611 /* was part of the footprint */
612 pmap_ledger_debit(pmap
, task_ledgers
.phys_footprint
,
615 /* marker will be cleared below */
619 * if we have a previous managed page, lock the pv entry now. after
620 * we lock it, check to see if someone beat us to the lock and if so
623 if ((0 != old_pa
) && IS_MANAGED_PAGE(pai
)) {
625 old_pa_locked
= TRUE
;
626 old_pa
= pte_to_pa(*pte
);
628 UNLOCK_PVH(pai
); /* another path beat us to it */
629 old_pa_locked
= FALSE
;
634 * Special case if the incoming physical page is already mapped
638 pt_entry_t old_attributes
=
639 *pte
& ~(PTE_REF(is_ept
) | PTE_MOD(is_ept
));
642 * May be changing its wired attribute or protection
645 template = pa_to_pte(pa
);
647 /* ?: WORTH ASSERTING THAT AT LEAST ONE RWX (implicit valid) PASSED FOR EPT? */
649 template |= INTEL_PTE_VALID
;
651 template |= INTEL_EPT_IPTA
;
654 template |= pmap_get_cache_attributes(pa_index(pa
), is_ept
);
657 * We don't support passing VM_MEM_NOT_CACHEABLE flags for EPT PTEs
659 if (!is_ept
&& (VM_MEM_NOT_CACHEABLE
==
660 (flags
& (VM_MEM_NOT_CACHEABLE
| VM_WIMG_USE_DEFAULT
)))) {
661 if (!(flags
& VM_MEM_GUARDED
))
662 template |= INTEL_PTE_PTA
;
663 template |= INTEL_PTE_NCACHE
;
665 if (pmap
!= kernel_pmap
&& !is_ept
)
666 template |= INTEL_PTE_USER
;
668 if (prot
& VM_PROT_READ
)
669 template |= PTE_READ(is_ept
);
671 if (prot
& VM_PROT_WRITE
) {
672 template |= PTE_WRITE(is_ept
);
673 if (is_ept
&& !pmap_ept_support_ad
) {
674 template |= PTE_MOD(is_ept
);
676 assert(IS_MANAGED_PAGE(pai
));
677 pmap_phys_attributes
[pai
] |= PHYS_MODIFIED
;
681 if (prot
& VM_PROT_EXECUTE
) {
683 template = pte_set_ex(template, is_ept
);
687 template = pte_remove_ex(template, is_ept
);
690 template |= PTE_WIRED
;
691 if (!iswired(old_attributes
)) {
692 OSAddAtomic(+1, &pmap
->stats
.wired_count
);
693 pmap_ledger_credit(pmap
, task_ledgers
.wired_mem
, PAGE_SIZE
);
696 if (iswired(old_attributes
)) {
697 assert(pmap
->stats
.wired_count
>= 1);
698 OSAddAtomic(-1, &pmap
->stats
.wired_count
);
699 pmap_ledger_debit(pmap
, task_ledgers
.wired_mem
, PAGE_SIZE
);
703 if (superpage
) /* this path can not be used */
704 template |= PTE_PS
; /* to change the page size! */
706 if (old_attributes
== template)
707 goto dont_update_pte
;
709 /* Determine delta, PV locked */
711 ((old_attributes
^ template) != PTE_WIRED
);
713 if (need_tlbflush
== TRUE
&& !(old_attributes
& PTE_WRITE(is_ept
))) {
714 if ((old_attributes
^ template) == PTE_WRITE(is_ept
))
715 need_tlbflush
= FALSE
;
718 /* For hardware that doesn't have EPT AD support, we always set REFMOD for EPT PTEs */
719 if (is_ept
&& !pmap_ept_support_ad
) {
720 template |= PTE_REF(is_ept
);
722 assert(IS_MANAGED_PAGE(pai
));
723 pmap_phys_attributes
[pai
] |= PHYS_REFERENCED
;
727 /* store modified PTE and preserve RC bits */
728 pt_entry_t npte
, opte
;;
731 npte
= template | (opte
& (PTE_REF(is_ept
) | PTE_MOD(is_ept
)));
732 } while (!pmap_cmpx_pte(pte
, opte
, npte
));
736 old_pa_locked
= FALSE
;
742 * Outline of code from here:
743 * 1) If va was mapped, update TLBs, remove the mapping
744 * and remove old pvlist entry.
745 * 2) Add pvlist entry for new mapping
746 * 3) Enter new mapping.
748 * If the old physical page is not managed step 1) is skipped
749 * (except for updating the TLBs), and the mapping is
750 * overwritten at step 3). If the new physical page is not
751 * managed, step 2) is skipped.
754 if (old_pa
!= (pmap_paddr_t
) 0) {
755 boolean_t was_altacct
= FALSE
;
758 * Don't do anything to pages outside valid memory here.
759 * Instead convince the code that enters a new mapping
760 * to overwrite the old one.
763 /* invalidate the PTE */
764 pmap_update_pte(pte
, PTE_VALID_MASK(is_ept
), 0);
765 /* propagate invalidate everywhere */
766 PMAP_UPDATE_TLBS(pmap
, vaddr
, vaddr
+ PAGE_SIZE
);
767 /* remember reference and change */
769 oattr
= (char) (old_pte
& (PTE_MOD(is_ept
) | PTE_REF(is_ept
)));
770 /* completely invalidate the PTE */
771 pmap_store_pte(pte
, 0);
773 if (IS_MANAGED_PAGE(pai
)) {
775 * Remove the mapping from the pvlist for
776 * this physical page.
777 * We'll end up with either a rooted pv or a
780 pvh_e
= pmap_pv_remove(pmap
, vaddr
, (ppnum_t
*) &pai
, &old_pte
, &was_altacct
);
783 if (IS_MANAGED_PAGE(pai
)) {
784 pmap_assert(old_pa_locked
== TRUE
);
785 pmap_ledger_debit(pmap
, task_ledgers
.phys_mem
, PAGE_SIZE
);
786 assert(pmap
->stats
.resident_count
>= 1);
787 OSAddAtomic(-1, &pmap
->stats
.resident_count
);
788 if (pmap
!= kernel_pmap
) {
789 /* update pmap stats */
790 if (IS_REUSABLE_PAGE(pai
)) {
792 (pmap
->stats
.reusable
> 0,
794 pmap
->stats
.reusable
));
795 OSAddAtomic(-1, &pmap
->stats
.reusable
);
796 } else if (IS_INTERNAL_PAGE(pai
)) {
798 (pmap
->stats
.internal
> 0,
800 pmap
->stats
.internal
));
801 OSAddAtomic(-1, &pmap
->stats
.internal
);
804 (pmap
->stats
.external
> 0,
806 pmap
->stats
.external
));
807 OSAddAtomic(-1, &pmap
->stats
.external
);
812 assert(IS_INTERNAL_PAGE(pai
));
813 pmap_ledger_debit(pmap
, task_ledgers
.internal
, PAGE_SIZE
);
814 pmap_ledger_debit(pmap
, task_ledgers
.alternate_accounting
, PAGE_SIZE
);
815 } else if (IS_REUSABLE_PAGE(pai
)) {
816 assert(!was_altacct
);
817 assert(IS_INTERNAL_PAGE(pai
));
818 /* was already not in phys_footprint */
819 } else if (IS_INTERNAL_PAGE(pai
)) {
820 assert(!was_altacct
);
821 assert(!IS_REUSABLE_PAGE(pai
));
822 pmap_ledger_debit(pmap
, task_ledgers
.internal
, PAGE_SIZE
);
823 pmap_ledger_debit(pmap
, task_ledgers
.phys_footprint
, PAGE_SIZE
);
825 /* not an internal page */
829 assert(pmap
->stats
.wired_count
>= 1);
830 OSAddAtomic(-1, &pmap
->stats
.wired_count
);
831 pmap_ledger_debit(pmap
, task_ledgers
.wired_mem
,
836 pmap_phys_attributes
[pai
] |= oattr
;
838 pmap_phys_attributes
[pai
] |= ept_refmod_to_physmap(oattr
);
844 * old_pa is not managed.
845 * Do removal part of accounting.
848 if (pmap
!= kernel_pmap
) {
850 assert(pmap
->stats
.device
> 0);
851 OSAddAtomic(-1, &pmap
->stats
.device
);
855 assert(pmap
->stats
.wired_count
>= 1);
856 OSAddAtomic(-1, &pmap
->stats
.wired_count
);
857 pmap_ledger_debit(pmap
, task_ledgers
.wired_mem
, PAGE_SIZE
);
863 * if we had a previously managed paged locked, unlock it now
867 old_pa_locked
= FALSE
;
870 pai
= pa_index(pa
); /* now working with new incoming phys page */
871 if (IS_MANAGED_PAGE(pai
)) {
874 * Step 2) Enter the mapping in the PV list for this
877 pv_h
= pai_to_pvh(pai
);
881 if (pv_h
->pmap
== PMAP_NULL
) {
883 * No mappings yet, use rooted pv
885 pv_h
->va_and_flags
= vaddr
;
887 queue_init(&pv_h
->qlink
);
889 if (options
& PMAP_OPTIONS_INTERNAL
) {
890 pmap_phys_attributes
[pai
] |= PHYS_INTERNAL
;
892 pmap_phys_attributes
[pai
] &= ~PHYS_INTERNAL
;
894 if (options
& PMAP_OPTIONS_REUSABLE
) {
895 pmap_phys_attributes
[pai
] |= PHYS_REUSABLE
;
897 pmap_phys_attributes
[pai
] &= ~PHYS_REUSABLE
;
899 if ((options
& PMAP_OPTIONS_ALT_ACCT
) &&
900 IS_INTERNAL_PAGE(pai
)) {
901 pv_h
->va_and_flags
|= PVE_IS_ALTACCT
;
904 pv_h
->va_and_flags
&= ~PVE_IS_ALTACCT
;
909 * Add new pv_hashed_entry after header.
911 if ((PV_HASHED_ENTRY_NULL
== pvh_e
) && pvh_new
) {
913 pvh_new
= PV_HASHED_ENTRY_NULL
;
914 } else if (PV_HASHED_ENTRY_NULL
== pvh_e
) {
915 PV_HASHED_ALLOC(&pvh_e
);
916 if (PV_HASHED_ENTRY_NULL
== pvh_e
) {
918 * the pv list is empty. if we are on
919 * the kernel pmap we'll use one of
920 * the special private kernel pv_e's,
921 * else, we need to unlock
922 * everything, zalloc a pv_e, and
923 * restart bringing in the pv_e with
926 if (kernel_pmap
== pmap
) {
927 PV_HASHED_KERN_ALLOC(&pvh_e
);
931 pmap_pv_throttle(pmap
);
932 pvh_new
= (pv_hashed_entry_t
) zalloc(pv_hashed_list_zone
);
938 if (PV_HASHED_ENTRY_NULL
== pvh_e
)
939 panic("Mapping alias chain exhaustion, possibly induced by numerous kernel virtual double mappings");
941 pvh_e
->va_and_flags
= vaddr
;
944 if ((options
& PMAP_OPTIONS_ALT_ACCT
) &&
945 IS_INTERNAL_PAGE(pai
)) {
946 pvh_e
->va_and_flags
|= PVE_IS_ALTACCT
;
949 pvh_e
->va_and_flags
&= ~PVE_IS_ALTACCT
;
952 pv_hash_add(pvh_e
, pv_h
);
955 * Remember that we used the pvlist entry.
957 pvh_e
= PV_HASHED_ENTRY_NULL
;
961 * only count the mapping
962 * for 'managed memory'
964 pmap_ledger_credit(pmap
, task_ledgers
.phys_mem
, PAGE_SIZE
);
965 OSAddAtomic(+1, &pmap
->stats
.resident_count
);
966 if (pmap
->stats
.resident_count
> pmap
->stats
.resident_max
) {
967 pmap
->stats
.resident_max
= pmap
->stats
.resident_count
;
969 if (pmap
!= kernel_pmap
) {
970 /* update pmap stats */
971 if (IS_REUSABLE_PAGE(pai
)) {
972 OSAddAtomic(+1, &pmap
->stats
.reusable
);
973 PMAP_STATS_PEAK(pmap
->stats
.reusable
);
974 } else if (IS_INTERNAL_PAGE(pai
)) {
975 OSAddAtomic(+1, &pmap
->stats
.internal
);
976 PMAP_STATS_PEAK(pmap
->stats
.internal
);
978 OSAddAtomic(+1, &pmap
->stats
.external
);
979 PMAP_STATS_PEAK(pmap
->stats
.external
);
984 /* internal but also alternate accounting */
985 assert(IS_INTERNAL_PAGE(pai
));
986 pmap_ledger_credit(pmap
, task_ledgers
.internal
, PAGE_SIZE
);
987 pmap_ledger_credit(pmap
, task_ledgers
.alternate_accounting
, PAGE_SIZE
);
988 /* alternate accounting, so not in footprint */
989 } else if (IS_REUSABLE_PAGE(pai
)) {
991 assert(IS_INTERNAL_PAGE(pai
));
992 /* internal but reusable: not in footprint */
993 } else if (IS_INTERNAL_PAGE(pai
)) {
995 assert(!IS_REUSABLE_PAGE(pai
));
996 /* internal: add to footprint */
997 pmap_ledger_credit(pmap
, task_ledgers
.internal
, PAGE_SIZE
);
998 pmap_ledger_credit(pmap
, task_ledgers
.phys_footprint
, PAGE_SIZE
);
1000 /* not internal: not in footprint */
1003 } else if (last_managed_page
== 0) {
1004 /* Account for early mappings created before "managed pages"
1005 * are determined. Consider consulting the available DRAM map.
1007 pmap_ledger_credit(pmap
, task_ledgers
.phys_mem
, PAGE_SIZE
);
1008 OSAddAtomic(+1, &pmap
->stats
.resident_count
);
1009 if (pmap
!= kernel_pmap
) {
1011 OSAddAtomic(+1, &pmap
->stats
.device
);
1012 PMAP_STATS_PEAK(pmap
->stats
.device
);
1017 * Step 3) Enter the mapping.
1019 * Build a template to speed up entering -
1020 * only the pfn changes.
1022 template = pa_to_pte(pa
);
1025 template |= INTEL_PTE_VALID
;
1027 template |= INTEL_EPT_IPTA
;
1032 * DRK: It may be worth asserting on cache attribute flags that diverge
1033 * from the existing physical page attributes.
1036 template |= pmap_get_cache_attributes(pa_index(pa
), is_ept
);
1039 * We don't support passing VM_MEM_NOT_CACHEABLE flags for EPT PTEs
1041 if (!is_ept
&& (flags
& VM_MEM_NOT_CACHEABLE
)) {
1042 if (!(flags
& VM_MEM_GUARDED
))
1043 template |= INTEL_PTE_PTA
;
1044 template |= INTEL_PTE_NCACHE
;
1046 if (pmap
!= kernel_pmap
&& !is_ept
)
1047 template |= INTEL_PTE_USER
;
1048 if (prot
& VM_PROT_READ
)
1049 template |= PTE_READ(is_ept
);
1050 if (prot
& VM_PROT_WRITE
) {
1051 template |= PTE_WRITE(is_ept
);
1052 if (is_ept
&& !pmap_ept_support_ad
) {
1053 template |= PTE_MOD(is_ept
);
1054 if (IS_MANAGED_PAGE(pai
))
1055 pmap_phys_attributes
[pai
] |= PHYS_MODIFIED
;
1058 if (prot
& VM_PROT_EXECUTE
) {
1059 assert(set_NX
== 0);
1060 template = pte_set_ex(template, is_ept
);
1064 template = pte_remove_ex(template, is_ept
);
1066 template |= INTEL_PTE_WIRED
;
1067 OSAddAtomic(+1, & pmap
->stats
.wired_count
);
1068 pmap_ledger_credit(pmap
, task_ledgers
.wired_mem
, PAGE_SIZE
);
1071 template |= INTEL_PTE_PS
;
1073 /* For hardware that doesn't have EPT AD support, we always set REFMOD for EPT PTEs */
1074 if (is_ept
&& !pmap_ept_support_ad
) {
1075 template |= PTE_REF(is_ept
);
1076 if (IS_MANAGED_PAGE(pai
))
1077 pmap_phys_attributes
[pai
] |= PHYS_REFERENCED
;
1080 pmap_store_pte(pte
, template);
1083 * if this was a managed page we delayed unlocking the pv until here
1084 * to prevent pmap_page_protect et al from finding it until the pte
1087 if (IS_MANAGED_PAGE(pai
)) {
1091 if (need_tlbflush
== TRUE
) {
1092 if (options
& PMAP_OPTIONS_NOFLUSH
)
1093 PMAP_UPDATE_TLBS_DELAYED(pmap
, vaddr
, vaddr
+ PAGE_SIZE
, (pmap_flush_context
*)arg
);
1095 PMAP_UPDATE_TLBS(pmap
, vaddr
, vaddr
+ PAGE_SIZE
);
1097 if (pvh_e
!= PV_HASHED_ENTRY_NULL
) {
1098 PV_HASHED_FREE_LIST(pvh_e
, pvh_e
, 1);
1100 if (pvh_new
!= PV_HASHED_ENTRY_NULL
) {
1101 PV_HASHED_KERN_FREE_LIST(pvh_new
, pvh_new
, 1);
1105 if (delpage_pm_obj
) {
1108 vm_object_lock(delpage_pm_obj
);
1109 m
= vm_page_lookup(delpage_pm_obj
, (delpage_pde_index
* PAGE_SIZE
));
1110 if (m
== VM_PAGE_NULL
)
1111 panic("pmap_enter: pte page not in object");
1113 vm_object_unlock(delpage_pm_obj
);
1114 OSAddAtomic(-1, &inuse_ptepages_count
);
1115 PMAP_ZINFO_PFREE(pmap
, PAGE_SIZE
);
1120 PMAP_TRACE(PMAP_CODE(PMAP__ENTER
) | DBG_FUNC_END
, kr
);
1125 * Remove a range of hardware page-table entries.
1126 * The entries given are the first (inclusive)
1127 * and last (exclusive) entries for the VM pages.
1128 * The virtual address is the va for the first pte.
1130 * The pmap must be locked.
1131 * If the pmap is not the kernel pmap, the range must lie
1132 * entirely within one pte-page. This is NOT checked.
1133 * Assumes that the pte-page exists.
1139 vm_map_offset_t start_vaddr
,
1143 pmap_remove_range_options(pmap
, start_vaddr
, spte
, epte
,
1144 PMAP_OPTIONS_REMOVE
);
1148 pmap_remove_range_options(
1150 vm_map_offset_t start_vaddr
,
1156 pv_hashed_entry_t pvh_et
= PV_HASHED_ENTRY_NULL
;
1157 pv_hashed_entry_t pvh_eh
= PV_HASHED_ENTRY_NULL
;
1158 pv_hashed_entry_t pvh_e
;
1160 int num_removed
, num_unwired
, num_found
, num_invalid
;
1161 int stats_external
, stats_internal
, stats_reusable
;
1162 uint64_t stats_compressed
;
1163 int ledgers_internal
, ledgers_alt_internal
;
1164 uint64_t ledgers_compressed
, ledgers_alt_compressed
;
1167 vm_map_offset_t vaddr
;
1168 boolean_t is_ept
= is_ept_pmap(pmap
);
1169 boolean_t was_altacct
;
1178 stats_compressed
= 0;
1179 ledgers_internal
= 0;
1180 ledgers_compressed
= 0;
1181 ledgers_alt_internal
= 0;
1182 ledgers_alt_compressed
= 0;
1183 /* invalidate the PTEs first to "freeze" them */
1184 for (cpte
= spte
, vaddr
= start_vaddr
;
1186 cpte
++, vaddr
+= PAGE_SIZE_64
) {
1187 pt_entry_t p
= *cpte
;
1191 if ((options
& PMAP_OPTIONS_REMOVE
) &&
1192 (PTE_IS_COMPRESSED(p
))) {
1193 assert(pmap
!= kernel_pmap
);
1194 /* one less "compressed"... */
1196 ledgers_compressed
++;
1197 if (p
& PTE_COMPRESSED_ALT
) {
1198 /* ... but it used to be "ALTACCT" */
1199 ledgers_alt_compressed
++;
1201 /* clear marker(s) */
1202 /* XXX probably does not need to be atomic! */
1203 pmap_update_pte(cpte
, INTEL_PTE_COMPRESSED_MASK
, 0);
1214 if (!IS_MANAGED_PAGE(pai
)) {
1216 * Outside range of managed physical memory.
1217 * Just remove the mappings.
1219 pmap_store_pte(cpte
, 0);
1223 if ((p
& PTE_VALID_MASK(is_ept
)) == 0)
1226 /* invalidate the PTE */
1227 pmap_update_pte(cpte
, PTE_VALID_MASK(is_ept
), 0);
1230 if (num_found
== 0) {
1231 /* nothing was changed: we're done */
1235 /* propagate the invalidates to other CPUs */
1237 PMAP_UPDATE_TLBS(pmap
, start_vaddr
, vaddr
);
1239 for (cpte
= spte
, vaddr
= start_vaddr
;
1241 cpte
++, vaddr
+= PAGE_SIZE_64
) {
1243 pa
= pte_to_pa(*cpte
);
1245 check_pte_for_compressed_marker
:
1247 * This PTE could have been replaced with a
1248 * "compressed" marker after our first "freeze"
1249 * loop above, so check again.
1251 if ((options
& PMAP_OPTIONS_REMOVE
) &&
1252 (PTE_IS_COMPRESSED(*cpte
))) {
1253 assert(pmap
!= kernel_pmap
);
1254 /* one less "compressed"... */
1256 ledgers_compressed
++;
1257 if (*cpte
& PTE_COMPRESSED_ALT
) {
1258 /* ... but it used to be "ALTACCT" */
1259 ledgers_alt_compressed
++;
1261 pmap_store_pte(cpte
, 0);
1270 pa
= pte_to_pa(*cpte
);
1273 goto check_pte_for_compressed_marker
;
1277 * Remove the mapping from the pvlist for this physical page.
1279 pvh_e
= pmap_pv_remove(pmap
, vaddr
, (ppnum_t
*) &pai
, cpte
, &was_altacct
);
1282 /* update pmap stats */
1283 if (IS_REUSABLE_PAGE(pai
)) {
1285 } else if (IS_INTERNAL_PAGE(pai
)) {
1290 /* update ledgers */
1292 /* internal and alternate accounting */
1293 assert(IS_INTERNAL_PAGE(pai
));
1295 ledgers_alt_internal
++;
1296 } else if (IS_REUSABLE_PAGE(pai
)) {
1297 /* internal but reusable */
1298 assert(!was_altacct
);
1299 assert(IS_INTERNAL_PAGE(pai
));
1300 } else if (IS_INTERNAL_PAGE(pai
)) {
1302 assert(!was_altacct
);
1303 assert(!IS_REUSABLE_PAGE(pai
));
1310 * Get the modify and reference bits, then
1311 * nuke the entry in the page table
1313 /* remember reference and change */
1315 pmap_phys_attributes
[pai
] |=
1316 *cpte
& (PHYS_MODIFIED
| PHYS_REFERENCED
);
1318 pmap_phys_attributes
[pai
] |=
1319 ept_refmod_to_physmap((*cpte
& (INTEL_EPT_REF
| INTEL_EPT_MOD
))) & (PHYS_MODIFIED
| PHYS_REFERENCED
);
1322 /* completely invalidate the PTE */
1323 pmap_store_pte(cpte
, 0);
1327 if (pvh_e
!= PV_HASHED_ENTRY_NULL
) {
1328 pvh_e
->qlink
.next
= (queue_entry_t
) pvh_eh
;
1331 if (pvh_et
== PV_HASHED_ENTRY_NULL
) {
1338 if (pvh_eh
!= PV_HASHED_ENTRY_NULL
) {
1339 PV_HASHED_FREE_LIST(pvh_eh
, pvh_et
, pvh_cnt
);
1346 if (pmap
->stats
.resident_count
< num_removed
)
1347 panic("pmap_remove_range: resident_count");
1349 pmap_ledger_debit(pmap
, task_ledgers
.phys_mem
, machine_ptob(num_removed
));
1350 PMAP_STATS_ASSERTF((pmap
->stats
.resident_count
>= num_removed
,
1351 "pmap=%p num_removed=%d stats.resident_count=%d",
1352 pmap
, num_removed
, pmap
->stats
.resident_count
));
1353 OSAddAtomic(-num_removed
, &pmap
->stats
.resident_count
);
1355 if (pmap
!= kernel_pmap
) {
1356 PMAP_STATS_ASSERTF((pmap
->stats
.external
>= stats_external
,
1357 "pmap=%p stats_external=%d stats.external=%d",
1358 pmap
, stats_external
, pmap
->stats
.external
));
1359 PMAP_STATS_ASSERTF((pmap
->stats
.internal
>= stats_internal
,
1360 "pmap=%p stats_internal=%d stats.internal=%d",
1361 pmap
, stats_internal
, pmap
->stats
.internal
));
1362 PMAP_STATS_ASSERTF((pmap
->stats
.reusable
>= stats_reusable
,
1363 "pmap=%p stats_reusable=%d stats.reusable=%d",
1364 pmap
, stats_reusable
, pmap
->stats
.reusable
));
1365 PMAP_STATS_ASSERTF((pmap
->stats
.compressed
>= stats_compressed
,
1366 "pmap=%p stats_compressed=%lld, stats.compressed=%lld",
1367 pmap
, stats_compressed
, pmap
->stats
.compressed
));
1369 /* update pmap stats */
1370 if (stats_external
) {
1371 OSAddAtomic(-stats_external
, &pmap
->stats
.external
);
1373 if (stats_internal
) {
1374 OSAddAtomic(-stats_internal
, &pmap
->stats
.internal
);
1377 OSAddAtomic(-stats_reusable
, &pmap
->stats
.reusable
);
1378 if (stats_compressed
)
1379 OSAddAtomic64(-stats_compressed
, &pmap
->stats
.compressed
);
1380 /* update ledgers */
1381 if (ledgers_internal
) {
1382 pmap_ledger_debit(pmap
,
1383 task_ledgers
.internal
,
1384 machine_ptob(ledgers_internal
));
1386 if (ledgers_compressed
) {
1387 pmap_ledger_debit(pmap
,
1388 task_ledgers
.internal_compressed
,
1389 machine_ptob(ledgers_compressed
));
1391 if (ledgers_alt_internal
) {
1392 pmap_ledger_debit(pmap
,
1393 task_ledgers
.alternate_accounting
,
1394 machine_ptob(ledgers_alt_internal
));
1396 if (ledgers_alt_compressed
) {
1397 pmap_ledger_debit(pmap
,
1398 task_ledgers
.alternate_accounting_compressed
,
1399 machine_ptob(ledgers_alt_compressed
));
1401 pmap_ledger_debit(pmap
,
1402 task_ledgers
.phys_footprint
,
1403 machine_ptob((ledgers_internal
-
1404 ledgers_alt_internal
) +
1405 (ledgers_compressed
-
1406 ledgers_alt_compressed
)));
1410 if (pmap
->stats
.wired_count
< num_unwired
)
1411 panic("pmap_remove_range: wired_count");
1413 PMAP_STATS_ASSERTF((pmap
->stats
.wired_count
>= num_unwired
,
1414 "pmap=%p num_unwired=%d stats.wired_count=%d",
1415 pmap
, num_unwired
, pmap
->stats
.wired_count
));
1416 OSAddAtomic(-num_unwired
, &pmap
->stats
.wired_count
);
1417 pmap_ledger_debit(pmap
, task_ledgers
.wired_mem
, machine_ptob(num_unwired
));
1424 * Remove the given range of addresses
1425 * from the specified map.
1427 * It is assumed that the start and end are properly
1428 * rounded to the hardware page size.
1436 pmap_remove_options(map
, s64
, e64
, PMAP_OPTIONS_REMOVE
);
1440 pmap_remove_options(
1447 pt_entry_t
*spte
, *epte
;
1454 if (map
== PMAP_NULL
|| s64
== e64
)
1457 is_ept
= is_ept_pmap(map
);
1459 PMAP_TRACE(PMAP_CODE(PMAP__REMOVE
) | DBG_FUNC_START
,
1460 VM_KERNEL_ADDRHIDE(map
), VM_KERNEL_ADDRHIDE(s64
),
1461 VM_KERNEL_ADDRHIDE(e64
));
1467 * Check that address range in the kernel does not overlap the stacks.
1468 * We initialize local static min/max variables once to avoid making
1469 * 2 function calls for every remove. Note also that these functions
1470 * both return 0 before kernel stacks have been initialized, and hence
1471 * the panic is not triggered in this case.
1473 if (map
== kernel_pmap
) {
1474 static vm_offset_t kernel_stack_min
= 0;
1475 static vm_offset_t kernel_stack_max
= 0;
1477 if (kernel_stack_min
== 0) {
1478 kernel_stack_min
= min_valid_stack_address();
1479 kernel_stack_max
= max_valid_stack_address();
1481 if ((kernel_stack_min
<= s64
&& s64
< kernel_stack_max
) ||
1482 (kernel_stack_min
< e64
&& e64
<= kernel_stack_max
))
1483 panic("pmap_remove() attempted in kernel stack");
1488 * The values of kernel_stack_min and kernel_stack_max are no longer
1489 * relevant now that we allocate kernel stacks in the kernel map,
1490 * so the old code above no longer applies. If we wanted to check that
1491 * we weren't removing a mapping of a page in a kernel stack we'd
1492 * mark the PTE with an unused bit and check that here.
1497 deadline
= rdtsc64() + max_preemption_latency_tsc
;
1500 l64
= (s64
+ pde_mapped_size
) & ~(pde_mapped_size
- 1);
1503 pde
= pmap_pde(map
, s64
);
1505 if (pde
&& (*pde
& PTE_VALID_MASK(is_ept
))) {
1506 if (*pde
& PTE_PS
) {
1508 * If we're removing a superpage, pmap_remove_range()
1509 * must work on level 2 instead of level 1; and we're
1510 * only passing a single level 2 entry instead of a
1514 epte
= spte
+1; /* excluded */
1516 spte
= pmap_pte(map
, (s64
& ~(pde_mapped_size
- 1)));
1517 spte
= &spte
[ptenum(s64
)];
1518 epte
= &spte
[intel_btop(l64
- s64
)];
1520 pmap_remove_range_options(map
, s64
, spte
, epte
,
1525 if (s64
< e64
&& rdtsc64() >= deadline
) {
1527 /* TODO: Rapid release/reacquisition can defeat
1528 * the "backoff" intent here; either consider a
1529 * fair spinlock, or a scheme whereby each lock
1530 * attempt marks the processor as within a spinlock
1531 * acquisition, and scan CPUs here to determine
1532 * if a backoff is necessary, to avoid sacrificing
1533 * performance in the common case.
1536 deadline
= rdtsc64() + max_preemption_latency_tsc
;
1542 PMAP_TRACE(PMAP_CODE(PMAP__REMOVE
) | DBG_FUNC_END
);
1551 pmap_page_protect_options(pn
, prot
, 0, NULL
);
1555 * Routine: pmap_page_protect_options
1558 * Lower the permission for all mappings to a given
1562 pmap_page_protect_options(
1565 unsigned int options
,
1568 pv_hashed_entry_t pvh_eh
= PV_HASHED_ENTRY_NULL
;
1569 pv_hashed_entry_t pvh_et
= PV_HASHED_ENTRY_NULL
;
1570 pv_hashed_entry_t nexth
;
1572 pv_rooted_entry_t pv_h
;
1573 pv_rooted_entry_t pv_e
;
1574 pv_hashed_entry_t pvh_e
;
1579 pt_entry_t new_pte_value
;
1583 assert(pn
!= vm_page_fictitious_addr
);
1584 if (pn
== vm_page_guard_addr
)
1587 pai
= ppn_to_pai(pn
);
1589 if (!IS_MANAGED_PAGE(pai
)) {
1591 * Not a managed page.
1596 PMAP_TRACE(PMAP_CODE(PMAP__PAGE_PROTECT
) | DBG_FUNC_START
, pn
, prot
);
1599 * Determine the new protection.
1603 case VM_PROT_READ
| VM_PROT_EXECUTE
:
1607 return; /* nothing to do */
1613 pv_h
= pai_to_pvh(pai
);
1619 * Walk down PV list, if any, changing or removing all mappings.
1621 if (pv_h
->pmap
== PMAP_NULL
)
1625 pvh_e
= (pv_hashed_entry_t
) pv_e
; /* cheat */
1628 vm_map_offset_t vaddr
;
1630 if ((options
& PMAP_OPTIONS_COMPRESSOR_IFF_MODIFIED
) &&
1631 (pmap_phys_attributes
[pai
] & PHYS_MODIFIED
)) {
1632 /* page was modified, so it will be compressed */
1633 options
&= ~PMAP_OPTIONS_COMPRESSOR_IFF_MODIFIED
;
1634 options
|= PMAP_OPTIONS_COMPRESSOR
;
1638 is_ept
= is_ept_pmap(pmap
);
1639 vaddr
= PVE_VA(pv_e
);
1640 pte
= pmap_pte(pmap
, vaddr
);
1642 pmap_assert2((pa_index(pte_to_pa(*pte
)) == pn
),
1643 "pmap_page_protect: PTE mismatch, pn: 0x%x, pmap: %p, vaddr: 0x%llx, pte: 0x%llx", pn
, pmap
, vaddr
, *pte
);
1646 panic("pmap_page_protect() "
1647 "pmap=%p pn=0x%x vaddr=0x%llx\n",
1650 nexth
= (pv_hashed_entry_t
) queue_next(&pvh_e
->qlink
);
1653 * Remove the mapping if new protection is NONE
1657 /* Remove per-pmap wired count */
1658 if (iswired(*pte
)) {
1659 OSAddAtomic(-1, &pmap
->stats
.wired_count
);
1660 pmap_ledger_debit(pmap
, task_ledgers
.wired_mem
, PAGE_SIZE
);
1663 if (pmap
!= kernel_pmap
&&
1664 (options
& PMAP_OPTIONS_COMPRESSOR
) &&
1665 IS_INTERNAL_PAGE(pai
)) {
1666 assert(!PTE_IS_COMPRESSED(*pte
));
1667 /* mark this PTE as having been "compressed" */
1668 new_pte_value
= PTE_COMPRESSED
;
1669 if (IS_ALTACCT_PAGE(pai
, pv_e
)) {
1670 new_pte_value
|= PTE_COMPRESSED_ALT
;
1676 if (options
& PMAP_OPTIONS_NOREFMOD
) {
1677 pmap_store_pte(pte
, new_pte_value
);
1679 if (options
& PMAP_OPTIONS_NOFLUSH
)
1680 PMAP_UPDATE_TLBS_DELAYED(pmap
, vaddr
, vaddr
+ PAGE_SIZE
, (pmap_flush_context
*)arg
);
1682 PMAP_UPDATE_TLBS(pmap
, vaddr
, vaddr
+ PAGE_SIZE
);
1685 * Remove the mapping, collecting dirty bits.
1687 pmap_update_pte(pte
, PTE_VALID_MASK(is_ept
), 0);
1689 PMAP_UPDATE_TLBS(pmap
, vaddr
, vaddr
+PAGE_SIZE
);
1691 pmap_phys_attributes
[pai
] |=
1692 *pte
& (PHYS_MODIFIED
|PHYS_REFERENCED
);
1694 pmap_phys_attributes
[pai
] |=
1695 ept_refmod_to_physmap((*pte
& (INTEL_EPT_REF
| INTEL_EPT_MOD
))) & (PHYS_MODIFIED
| PHYS_REFERENCED
);
1698 PMAP_OPTIONS_COMPRESSOR_IFF_MODIFIED
) &&
1699 IS_INTERNAL_PAGE(pai
) &&
1700 (pmap_phys_attributes
[pai
] &
1703 * Page is actually "modified" and
1704 * will be compressed. Start
1705 * accounting for it as "compressed".
1707 assert(!(options
& PMAP_OPTIONS_COMPRESSOR
));
1708 options
&= ~PMAP_OPTIONS_COMPRESSOR_IFF_MODIFIED
;
1709 options
|= PMAP_OPTIONS_COMPRESSOR
;
1710 assert(new_pte_value
== 0);
1711 if (pmap
!= kernel_pmap
) {
1712 new_pte_value
= PTE_COMPRESSED
;
1713 if (IS_ALTACCT_PAGE(pai
, pv_e
)) {
1714 new_pte_value
|= PTE_COMPRESSED_ALT
;
1718 pmap_store_pte(pte
, new_pte_value
);
1722 if (pmap
->stats
.resident_count
< 1)
1723 panic("pmap_page_protect: resident_count");
1725 pmap_ledger_debit(pmap
, task_ledgers
.phys_mem
, PAGE_SIZE
);
1726 assert(pmap
->stats
.resident_count
>= 1);
1727 OSAddAtomic(-1, &pmap
->stats
.resident_count
);
1730 * We only ever compress internal pages.
1732 if (options
& PMAP_OPTIONS_COMPRESSOR
) {
1733 assert(IS_INTERNAL_PAGE(pai
));
1735 if (pmap
!= kernel_pmap
) {
1736 /* update pmap stats */
1737 if (IS_REUSABLE_PAGE(pai
)) {
1738 assert(pmap
->stats
.reusable
> 0);
1739 OSAddAtomic(-1, &pmap
->stats
.reusable
);
1740 } else if (IS_INTERNAL_PAGE(pai
)) {
1741 assert(pmap
->stats
.internal
> 0);
1742 OSAddAtomic(-1, &pmap
->stats
.internal
);
1744 assert(pmap
->stats
.external
> 0);
1745 OSAddAtomic(-1, &pmap
->stats
.external
);
1747 if ((options
& PMAP_OPTIONS_COMPRESSOR
) &&
1748 IS_INTERNAL_PAGE(pai
)) {
1749 /* adjust "compressed" stats */
1750 OSAddAtomic64(+1, &pmap
->stats
.compressed
);
1751 PMAP_STATS_PEAK(pmap
->stats
.compressed
);
1752 pmap
->stats
.compressed_lifetime
++;
1755 /* update ledgers */
1756 if (IS_ALTACCT_PAGE(pai
, pv_e
)) {
1757 assert(IS_INTERNAL_PAGE(pai
));
1758 pmap_ledger_debit(pmap
, task_ledgers
.internal
, PAGE_SIZE
);
1759 pmap_ledger_debit(pmap
, task_ledgers
.alternate_accounting
, PAGE_SIZE
);
1760 if (options
& PMAP_OPTIONS_COMPRESSOR
) {
1761 pmap_ledger_credit(pmap
, task_ledgers
.internal_compressed
, PAGE_SIZE
);
1762 pmap_ledger_credit(pmap
, task_ledgers
.alternate_accounting_compressed
, PAGE_SIZE
);
1764 } else if (IS_REUSABLE_PAGE(pai
)) {
1765 assert(!IS_ALTACCT_PAGE(pai
, pv_e
));
1766 assert(IS_INTERNAL_PAGE(pai
));
1767 if (options
& PMAP_OPTIONS_COMPRESSOR
) {
1768 pmap_ledger_credit(pmap
, task_ledgers
.internal_compressed
, PAGE_SIZE
);
1769 /* was not in footprint, but is now */
1770 pmap_ledger_credit(pmap
, task_ledgers
.phys_footprint
, PAGE_SIZE
);
1772 } else if (IS_INTERNAL_PAGE(pai
)) {
1773 assert(!IS_ALTACCT_PAGE(pai
, pv_e
));
1774 assert(!IS_REUSABLE_PAGE(pai
));
1775 pmap_ledger_debit(pmap
, task_ledgers
.internal
, PAGE_SIZE
);
1777 * Update all stats related to physical
1778 * footprint, which only deals with
1781 if (options
& PMAP_OPTIONS_COMPRESSOR
) {
1783 * This removal is only being
1784 * done so we can send this page
1785 * to the compressor; therefore
1786 * it mustn't affect total task
1789 pmap_ledger_credit(pmap
, task_ledgers
.internal_compressed
, PAGE_SIZE
);
1792 * This internal page isn't
1793 * going to the compressor,
1794 * so adjust stats to keep
1795 * phys_footprint up to date.
1797 pmap_ledger_debit(pmap
, task_ledgers
.phys_footprint
, PAGE_SIZE
);
1803 * Deal with the pv_rooted_entry.
1808 * Fix up head later.
1810 pv_h
->pmap
= PMAP_NULL
;
1813 * Delete this entry.
1815 pv_hash_remove(pvh_e
);
1816 pvh_e
->qlink
.next
= (queue_entry_t
) pvh_eh
;
1819 if (pvh_et
== PV_HASHED_ENTRY_NULL
)
1825 * Write-protect, after opportunistic refmod collect
1828 pmap_phys_attributes
[pai
] |=
1829 *pte
& (PHYS_MODIFIED
|PHYS_REFERENCED
);
1831 pmap_phys_attributes
[pai
] |=
1832 ept_refmod_to_physmap((*pte
& (INTEL_EPT_REF
| INTEL_EPT_MOD
))) & (PHYS_MODIFIED
| PHYS_REFERENCED
);
1834 pmap_update_pte(pte
, PTE_WRITE(is_ept
), 0);
1836 if (options
& PMAP_OPTIONS_NOFLUSH
)
1837 PMAP_UPDATE_TLBS_DELAYED(pmap
, vaddr
, vaddr
+ PAGE_SIZE
, (pmap_flush_context
*)arg
);
1839 PMAP_UPDATE_TLBS(pmap
, vaddr
, vaddr
+PAGE_SIZE
);
1842 } while ((pv_e
= (pv_rooted_entry_t
) nexth
) != pv_h
);
1846 * If pv_head mapping was removed, fix it up.
1848 if (pv_h
->pmap
== PMAP_NULL
) {
1849 pvh_e
= (pv_hashed_entry_t
) queue_next(&pv_h
->qlink
);
1851 if (pvh_e
!= (pv_hashed_entry_t
) pv_h
) {
1852 pv_hash_remove(pvh_e
);
1853 pv_h
->pmap
= pvh_e
->pmap
;
1854 pv_h
->va_and_flags
= pvh_e
->va_and_flags
;
1855 pvh_e
->qlink
.next
= (queue_entry_t
) pvh_eh
;
1858 if (pvh_et
== PV_HASHED_ENTRY_NULL
)
1863 if (pvh_eh
!= PV_HASHED_ENTRY_NULL
) {
1864 PV_HASHED_FREE_LIST(pvh_eh
, pvh_et
, pvh_cnt
);
1869 PMAP_TRACE(PMAP_CODE(PMAP__PAGE_PROTECT
) | DBG_FUNC_END
);
1874 * Clear specified attribute bits.
1877 phys_attribute_clear(
1880 unsigned int options
,
1883 pv_rooted_entry_t pv_h
;
1884 pv_hashed_entry_t pv_e
;
1885 pt_entry_t
*pte
= NULL
;
1888 char attributes
= 0;
1889 boolean_t is_internal
, is_reusable
, is_altacct
, is_ept
;
1890 int ept_bits_to_clear
;
1891 boolean_t ept_keep_global_mod
= FALSE
;
1893 if ((bits
& PHYS_MODIFIED
) &&
1894 (options
& PMAP_OPTIONS_NOFLUSH
) &&
1896 panic("phys_attribute_clear(0x%x,0x%x,0x%x,%p): "
1897 "should not clear 'modified' without flushing TLBs\n",
1898 pn
, bits
, options
, arg
);
1901 /* We only support converting MOD and REF bits for EPT PTEs in this function */
1902 assert((bits
& ~(PHYS_REFERENCED
| PHYS_MODIFIED
)) == 0);
1904 ept_bits_to_clear
= (unsigned)physmap_refmod_to_ept(bits
& (PHYS_MODIFIED
| PHYS_REFERENCED
));
1907 assert(pn
!= vm_page_fictitious_addr
);
1908 if (pn
== vm_page_guard_addr
)
1911 pai
= ppn_to_pai(pn
);
1913 if (!IS_MANAGED_PAGE(pai
)) {
1915 * Not a managed page.
1920 PMAP_TRACE(PMAP_CODE(PMAP__ATTRIBUTE_CLEAR
) | DBG_FUNC_START
, pn
, bits
);
1922 pv_h
= pai_to_pvh(pai
);
1928 * Walk down PV list, clearing all modify or reference bits.
1929 * We do not have to lock the pv_list because we have
1932 if (pv_h
->pmap
!= PMAP_NULL
) {
1934 * There are some mappings.
1937 is_internal
= IS_INTERNAL_PAGE(pai
);
1938 is_reusable
= IS_REUSABLE_PAGE(pai
);
1940 pv_e
= (pv_hashed_entry_t
)pv_h
;
1947 is_ept
= is_ept_pmap(pmap
);
1948 is_altacct
= IS_ALTACCT_PAGE(pai
, pv_e
);
1953 pte
= pmap_pte(pmap
, va
);
1954 /* grab ref/mod bits from this PTE */
1955 pte_bits
= (*pte
& (PTE_REF(is_ept
) | PTE_MOD(is_ept
)));
1956 /* propagate to page's global attributes */
1958 attributes
|= pte_bits
;
1960 attributes
|= ept_refmod_to_physmap(pte_bits
);
1961 if (!pmap_ept_support_ad
&& (pte_bits
& INTEL_EPT_MOD
)) {
1962 ept_keep_global_mod
= TRUE
;
1965 /* which bits to clear for this PTE? */
1969 pte_bits
&= ept_bits_to_clear
;
1974 * Clear modify and/or reference bits.
1977 pmap_update_pte(pte
, bits
, 0);
1979 /* Ensure all processors using this translation
1980 * invalidate this TLB entry. The invalidation
1981 * *must* follow the PTE update, to ensure that
1982 * the TLB shadow of the 'D' bit (in particular)
1983 * is synchronized with the updated PTE.
1985 if (! (options
& PMAP_OPTIONS_NOFLUSH
)) {
1986 /* flush TLBS now */
1987 PMAP_UPDATE_TLBS(pmap
,
1991 /* delayed TLB flush: add "pmap" info */
1992 PMAP_UPDATE_TLBS_DELAYED(
1996 (pmap_flush_context
*)arg
);
1998 /* no TLB flushing at all */
2002 /* update pmap "reusable" stats */
2003 if ((options
& PMAP_OPTIONS_CLEAR_REUSABLE
) &&
2005 pmap
!= kernel_pmap
) {
2006 /* one less "reusable" */
2007 assert(pmap
->stats
.reusable
> 0);
2008 OSAddAtomic(-1, &pmap
->stats
.reusable
);
2010 /* one more "internal" */
2011 OSAddAtomic(+1, &pmap
->stats
.internal
);
2012 PMAP_STATS_PEAK(pmap
->stats
.internal
);
2013 assert(pmap
->stats
.internal
> 0);
2015 /* no impact on ledgers */
2017 pmap_ledger_credit(pmap
,
2018 task_ledgers
.internal
,
2022 task_ledgers
.phys_footprint
,
2026 /* one more "external" */
2027 OSAddAtomic(+1, &pmap
->stats
.external
);
2028 PMAP_STATS_PEAK(pmap
->stats
.external
);
2029 assert(pmap
->stats
.external
> 0);
2031 } else if ((options
& PMAP_OPTIONS_SET_REUSABLE
) &&
2033 pmap
!= kernel_pmap
) {
2034 /* one more "reusable" */
2035 OSAddAtomic(+1, &pmap
->stats
.reusable
);
2036 PMAP_STATS_PEAK(pmap
->stats
.reusable
);
2037 assert(pmap
->stats
.reusable
> 0);
2039 /* one less "internal" */
2040 assert(pmap
->stats
.internal
> 0);
2041 OSAddAtomic(-1, &pmap
->stats
.internal
);
2043 /* no impact on footprint */
2045 pmap_ledger_debit(pmap
,
2046 task_ledgers
.internal
,
2050 task_ledgers
.phys_footprint
,
2054 /* one less "external" */
2055 assert(pmap
->stats
.external
> 0);
2056 OSAddAtomic(-1, &pmap
->stats
.external
);
2060 pv_e
= (pv_hashed_entry_t
)queue_next(&pv_e
->qlink
);
2062 } while (pv_e
!= (pv_hashed_entry_t
)pv_h
);
2064 /* Opportunistic refmod collection, annulled
2065 * if both REF and MOD are being cleared.
2068 pmap_phys_attributes
[pai
] |= attributes
;
2070 if (ept_keep_global_mod
) {
2072 * If the hardware doesn't support AD bits for EPT PTEs and someone is
2073 * requesting that we clear the modified bit for a phys page, we need
2074 * to ensure that there are no EPT mappings for the page with the
2075 * modified bit set. If there are, we cannot clear the global modified bit.
2077 bits
&= ~PHYS_MODIFIED
;
2079 pmap_phys_attributes
[pai
] &= ~(bits
);
2081 /* update this page's "reusable" status */
2082 if (options
& PMAP_OPTIONS_CLEAR_REUSABLE
) {
2083 pmap_phys_attributes
[pai
] &= ~PHYS_REUSABLE
;
2084 } else if (options
& PMAP_OPTIONS_SET_REUSABLE
) {
2085 pmap_phys_attributes
[pai
] |= PHYS_REUSABLE
;
2090 PMAP_TRACE(PMAP_CODE(PMAP__ATTRIBUTE_CLEAR
) | DBG_FUNC_END
);
2094 * Check specified attribute bits.
2097 phys_attribute_test(
2101 pv_rooted_entry_t pv_h
;
2102 pv_hashed_entry_t pv_e
;
2110 assert(pn
!= vm_page_fictitious_addr
);
2111 assert((bits
& ~(PHYS_MODIFIED
| PHYS_REFERENCED
)) == 0);
2112 if (pn
== vm_page_guard_addr
)
2115 pai
= ppn_to_pai(pn
);
2117 if (!IS_MANAGED_PAGE(pai
)) {
2119 * Not a managed page.
2125 * Fast check... if bits already collected
2126 * no need to take any locks...
2127 * if not set, we need to recheck after taking
2128 * the lock in case they got pulled in while
2129 * we were waiting for the lock
2131 if ((pmap_phys_attributes
[pai
] & bits
) == bits
)
2134 pv_h
= pai_to_pvh(pai
);
2138 attributes
= pmap_phys_attributes
[pai
] & bits
;
2142 * Walk down PV list, checking the mappings until we
2143 * reach the end or we've found the desired attributes.
2145 if (attributes
!= bits
&&
2146 pv_h
->pmap
!= PMAP_NULL
) {
2148 * There are some mappings.
2150 pv_e
= (pv_hashed_entry_t
)pv_h
;
2155 is_ept
= is_ept_pmap(pmap
);
2158 * pick up modify and/or reference bits from mapping
2161 pte
= pmap_pte(pmap
, va
);
2163 attributes
|= (int)(*pte
& bits
);
2165 attributes
|= (int)(ept_refmod_to_physmap((*pte
& (INTEL_EPT_REF
| INTEL_EPT_MOD
))) & (PHYS_MODIFIED
| PHYS_REFERENCED
));
2169 pv_e
= (pv_hashed_entry_t
)queue_next(&pv_e
->qlink
);
2171 } while ((attributes
!= bits
) &&
2172 (pv_e
!= (pv_hashed_entry_t
)pv_h
));
2174 pmap_phys_attributes
[pai
] |= attributes
;
2177 return (attributes
);
2181 * Routine: pmap_change_wiring
2182 * Function: Change the wiring attribute for a map/virtual-address
2184 * In/out conditions:
2185 * The mapping must already exist in the pmap.
2190 vm_map_offset_t vaddr
,
2197 if ((pte
= pmap_pte(map
, vaddr
)) == PT_ENTRY_NULL
)
2198 panic("pmap_change_wiring(%p,0x%llx,%d): pte missing",
2201 if (wired
&& !iswired(*pte
)) {
2203 * wiring down mapping
2205 pmap_ledger_credit(map
, task_ledgers
.wired_mem
, PAGE_SIZE
);
2206 OSAddAtomic(+1, &map
->stats
.wired_count
);
2207 pmap_update_pte(pte
, 0, PTE_WIRED
);
2209 else if (!wired
&& iswired(*pte
)) {
2213 assert(map
->stats
.wired_count
>= 1);
2214 OSAddAtomic(-1, &map
->stats
.wired_count
);
2215 pmap_ledger_debit(map
, task_ledgers
.wired_mem
, PAGE_SIZE
);
2216 pmap_update_pte(pte
, PTE_WIRED
, 0);
2223 * "Backdoor" direct map routine for early mappings.
2224 * Useful for mapping memory outside the range
2225 * Sets A, D and NC if requested
2231 vm_map_offset_t start_addr
,
2232 vm_map_offset_t end_addr
,
2236 pt_entry_t
template;
2239 vm_offset_t base
= virt
;
2240 boolean_t doflush
= FALSE
;
2242 template = pa_to_pte(start_addr
)
2248 if ((flags
& (VM_MEM_NOT_CACHEABLE
| VM_WIMG_USE_DEFAULT
)) == VM_MEM_NOT_CACHEABLE
) {
2249 template |= INTEL_PTE_NCACHE
;
2250 if (!(flags
& (VM_MEM_GUARDED
)))
2251 template |= INTEL_PTE_PTA
;
2254 if ((prot
& VM_PROT_EXECUTE
) == 0)
2255 template |= INTEL_PTE_NX
;
2257 if (prot
& VM_PROT_WRITE
)
2258 template |= INTEL_PTE_WRITE
;
2260 while (start_addr
< end_addr
) {
2261 ptep
= pmap_pte(kernel_pmap
, (vm_map_offset_t
)virt
);
2262 if (ptep
== PT_ENTRY_NULL
) {
2263 panic("pmap_map_bd: Invalid kernel address");
2265 if (pte_to_pa(*ptep
)) {
2268 pmap_store_pte(ptep
, template);
2269 pte_increment_pa(template);
2271 start_addr
+= PAGE_SIZE
;
2275 PMAP_UPDATE_TLBS(kernel_pmap
, base
, base
+ end_addr
- start_addr
);
2280 /* Create a virtual alias beginning at 'ava' of the specified kernel virtual
2281 * range. The aliased pagetable range is expanded if
2282 * PMAP_EXPAND_OPTIONS_ALIASMAP is specified. Performs no synchronization,
2283 * assumes caller has stabilized the source and destination ranges. Currently
2284 * used to populate sections of the trampoline "doublemap" at CPU startup.
2290 vm_map_offset_t start_addr
,
2291 vm_map_offset_t end_addr
,
2293 unsigned int eoptions
)
2295 pt_entry_t prot_template
, template;
2296 pt_entry_t
*aptep
, *sptep
;
2298 prot_template
= INTEL_PTE_REF
| INTEL_PTE_MOD
| INTEL_PTE_WIRED
| INTEL_PTE_VALID
;
2299 if ((prot
& VM_PROT_EXECUTE
) == 0)
2300 prot_template
|= INTEL_PTE_NX
;
2302 if (prot
& VM_PROT_WRITE
)
2303 prot_template
|= INTEL_PTE_WRITE
;
2304 assert(((start_addr
| end_addr
) & PAGE_MASK
) == 0);
2305 while (start_addr
< end_addr
) {
2306 aptep
= pmap_pte(kernel_pmap
, (vm_map_offset_t
)ava
);
2307 if (aptep
== PT_ENTRY_NULL
) {
2308 if (eoptions
& PMAP_EXPAND_OPTIONS_ALIASMAP
) {
2309 pmap_expand(kernel_pmap
, ava
, PMAP_EXPAND_OPTIONS_ALIASMAP
);
2310 aptep
= pmap_pte(kernel_pmap
, (vm_map_offset_t
)ava
);
2312 panic("pmap_alias: Invalid alias address");
2315 /* The aliased range should not have any active mappings */
2316 assert(pte_to_pa(*aptep
) == 0);
2318 sptep
= pmap_pte(kernel_pmap
, start_addr
);
2319 assert(sptep
!= PT_ENTRY_NULL
&& (pte_to_pa(*sptep
) != 0));
2320 template = pa_to_pte(pte_to_pa(*sptep
)) | prot_template
;
2321 pmap_store_pte(aptep
, template);
2324 start_addr
+= PAGE_SIZE
;
2329 pmap_query_resident(
2333 mach_vm_size_t
*compressed_bytes_p
)
2336 pt_entry_t
*spte
, *epte
;
2339 mach_vm_size_t resident_bytes
;
2340 mach_vm_size_t compressed_bytes
;
2345 if (pmap
== PMAP_NULL
|| pmap
== kernel_pmap
|| s64
== e64
) {
2346 if (compressed_bytes_p
) {
2347 *compressed_bytes_p
= 0;
2352 is_ept
= is_ept_pmap(pmap
);
2354 PMAP_TRACE(PMAP_CODE(PMAP__QUERY_RESIDENT
) | DBG_FUNC_START
,
2355 VM_KERNEL_ADDRHIDE(pmap
), VM_KERNEL_ADDRHIDE(s64
),
2356 VM_KERNEL_ADDRHIDE(e64
));
2359 compressed_bytes
= 0;
2363 deadline
= rdtsc64() + max_preemption_latency_tsc
;
2366 l64
= (s64
+ pde_mapped_size
) & ~(pde_mapped_size
- 1);
2369 pde
= pmap_pde(pmap
, s64
);
2371 if (pde
&& (*pde
& PTE_VALID_MASK(is_ept
))) {
2372 if (*pde
& PTE_PS
) {
2373 /* superpage: not supported */
2375 spte
= pmap_pte(pmap
,
2376 (s64
& ~(pde_mapped_size
- 1)));
2377 spte
= &spte
[ptenum(s64
)];
2378 epte
= &spte
[intel_btop(l64
- s64
)];
2380 for (; spte
< epte
; spte
++) {
2381 if (pte_to_pa(*spte
) != 0) {
2382 resident_bytes
+= PAGE_SIZE
;
2383 } else if (*spte
& PTE_COMPRESSED
) {
2384 compressed_bytes
+= PAGE_SIZE
;
2392 if (s64
< e64
&& rdtsc64() >= deadline
) {
2395 deadline
= rdtsc64() + max_preemption_latency_tsc
;
2401 PMAP_TRACE(PMAP_CODE(PMAP__QUERY_RESIDENT
) | DBG_FUNC_END
,
2404 if (compressed_bytes_p
) {
2405 *compressed_bytes_p
= compressed_bytes
;
2407 return resident_bytes
;
2411 pmap_query_page_info(
2424 if (pmap
== PMAP_NULL
|| pmap
== kernel_pmap
) {
2426 return KERN_INVALID_ARGUMENT
;
2430 is_ept
= is_ept_pmap(pmap
);
2434 pde
= pmap_pde(pmap
, va
);
2436 !(*pde
& PTE_VALID_MASK(is_ept
)) ||
2441 pte
= pmap_pte(pmap
, va
);
2442 if (pte
== PT_ENTRY_NULL
) {
2446 pa
= pte_to_pa(*pte
);
2448 if (PTE_IS_COMPRESSED(*pte
)) {
2449 disp
|= PMAP_QUERY_PAGE_COMPRESSED
;
2450 if (*pte
& PTE_COMPRESSED_ALT
) {
2451 disp
|= PMAP_QUERY_PAGE_COMPRESSED_ALTACCT
;
2455 disp
|= PMAP_QUERY_PAGE_PRESENT
;
2457 if (!IS_MANAGED_PAGE(pai
)) {
2458 } else if (pmap_pv_is_altacct(pmap
, va
, pai
)) {
2459 assert(IS_INTERNAL_PAGE(pai
));
2460 disp
|= PMAP_QUERY_PAGE_INTERNAL
;
2461 disp
|= PMAP_QUERY_PAGE_ALTACCT
;
2462 } else if (IS_REUSABLE_PAGE(pai
)) {
2463 disp
|= PMAP_QUERY_PAGE_REUSABLE
;
2464 } else if (IS_INTERNAL_PAGE(pai
)) {
2465 disp
|= PMAP_QUERY_PAGE_INTERNAL
;
2472 return KERN_SUCCESS
;
2475 void pmap_set_jit_entitled(__unused pmap_t pmap
)
2477 /* The x86 pmap layer does not care if a map has a JIT entry. */
2481 bool pmap_has_prot_policy(__unused vm_prot_t prot
)
2484 * The x86 pmap layer does not apply any policy to any protection
2490 void pmap_release_pages_fast(void)