]> git.saurik.com Git - apple/xnu.git/blame - osfmk/i386/pmap_x86_common.c
xnu-4570.41.2.tar.gz
[apple/xnu.git] / osfmk / i386 / pmap_x86_common.c
CommitLineData
b0d623f7 1/*
39236c6e 2 * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
b0d623f7
A
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 */
fe8ab488
A
28
29#include <mach_assert.h>
30
b0d623f7
A
31#include <vm/pmap.h>
32#include <vm/vm_map.h>
39037602 33#include <vm/vm_kern.h>
316670eb 34#include <kern/ledger.h>
b0d623f7 35#include <i386/pmap_internal.h>
b7266188 36
b7266188
A
37void pmap_remove_range(
38 pmap_t pmap,
39 vm_map_offset_t va,
40 pt_entry_t *spte,
41 pt_entry_t *epte);
42
39236c6e
A
43void pmap_remove_range_options(
44 pmap_t pmap,
45 vm_map_offset_t va,
46 pt_entry_t *spte,
47 pt_entry_t *epte,
48 int options);
49
50void pmap_reusable_range(
51 pmap_t pmap,
52 vm_map_offset_t va,
53 pt_entry_t *spte,
54 pt_entry_t *epte,
55 boolean_t reusable);
56
316670eb
A
57uint32_t pmap_update_clear_pte_count;
58
b0d623f7
A
59/*
60 * The Intel platform can nest at the PDE level, so NBPDE (i.e. 2MB) at a time,
61 * on a NBPDE boundary.
62 */
63
64/* These symbols may be referenced directly by VM */
65uint64_t pmap_nesting_size_min = NBPDE;
66uint64_t pmap_nesting_size_max = 0 - (uint64_t)NBPDE;
67
68/*
69 * kern_return_t pmap_nest(grand, subord, va_start, size)
70 *
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)
76 *
77 * Inserts a pmap into another. This is used to implement shared segments.
78 *
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.
82 */
83
84/*
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).
90 */
91
92kern_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;
95 unsigned int i;
96 uint64_t num_pde;
97
3e170ce0
A
98 assert(!is_ept_pmap(grand));
99 assert(!is_ept_pmap(subord));
100
b0d623f7
A
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;
106
107 if(size == 0) {
108 panic("pmap_nest: size is invalid - %016llX\n", size);
109 }
110
111 if (va_start != nstart)
112 panic("pmap_nest: va_start(0x%llx) != nstart(0x%llx)\n", va_start, nstart);
113
114 PMAP_TRACE(PMAP_CODE(PMAP__NEST) | DBG_FUNC_START,
5ba3f43e
A
115 VM_KERNEL_ADDRHIDE(grand), VM_KERNEL_ADDRHIDE(subord),
116 VM_KERNEL_ADDRHIDE(va_start));
b0d623f7
A
117
118 nvaddr = (vm_map_offset_t)nstart;
119 num_pde = size >> PDESHIFT;
120
121 PMAP_LOCK(subord);
122
123 subord->pm_shared = TRUE;
124
125 for (i = 0; i < num_pde;) {
126 if (((nvaddr & PDPTMASK) == 0) && (num_pde - i) >= NPDEPG && cpu_64bit) {
127
128 npde = pmap64_pdpt(subord, nvaddr);
129
130 while (0 == npde || ((*npde & INTEL_PTE_VALID) == 0)) {
131 PMAP_UNLOCK(subord);
316670eb 132 pmap_expand_pdpt(subord, nvaddr, PMAP_EXPAND_OPTIONS_NONE);
b0d623f7
A
133 PMAP_LOCK(subord);
134 npde = pmap64_pdpt(subord, nvaddr);
135 }
136 *npde |= INTEL_PDPTE_NESTED;
137 nvaddr += NBPDPT;
138 i += (uint32_t)NPDEPG;
139 }
140 else {
141 npde = pmap_pde(subord, nvaddr);
142
143 while (0 == npde || ((*npde & INTEL_PTE_VALID) == 0)) {
144 PMAP_UNLOCK(subord);
316670eb 145 pmap_expand(subord, nvaddr, PMAP_EXPAND_OPTIONS_NONE);
b0d623f7
A
146 PMAP_LOCK(subord);
147 npde = pmap_pde(subord, nvaddr);
148 }
149 nvaddr += NBPDE;
150 i++;
151 }
152 }
153
154 PMAP_UNLOCK(subord);
155
156 vaddr = (vm_map_offset_t)va_start;
157
158 PMAP_LOCK(grand);
159
160 for (i = 0;i < num_pde;) {
161 pd_entry_t tpde;
162
163 if (((vaddr & PDPTMASK) == 0) && ((num_pde - i) >= NPDEPG) && cpu_64bit) {
164 npde = pmap64_pdpt(subord, vaddr);
165 if (npde == 0)
166 panic("pmap_nest: no PDPT, subord %p nstart 0x%llx", subord, vaddr);
167 tpde = *npde;
168 pde = pmap64_pdpt(grand, vaddr);
169 if (0 == pde) {
170 PMAP_UNLOCK(grand);
316670eb 171 pmap_expand_pml4(grand, vaddr, PMAP_EXPAND_OPTIONS_NONE);
b0d623f7
A
172 PMAP_LOCK(grand);
173 pde = pmap64_pdpt(grand, vaddr);
174 }
175 if (pde == 0)
176 panic("pmap_nest: no PDPT, grand %p vaddr 0x%llx", grand, vaddr);
177 pmap_store_pte(pde, tpde);
178 vaddr += NBPDPT;
179 i += (uint32_t) NPDEPG;
180 }
181 else {
39037602 182 npde = pmap_pde(subord, vaddr);
b0d623f7 183 if (npde == 0)
39037602 184 panic("pmap_nest: no npde, subord %p vaddr 0x%llx", subord, vaddr);
b0d623f7 185 tpde = *npde;
b0d623f7
A
186 pde = pmap_pde(grand, vaddr);
187 if ((0 == pde) && cpu_64bit) {
188 PMAP_UNLOCK(grand);
316670eb 189 pmap_expand_pdpt(grand, vaddr, PMAP_EXPAND_OPTIONS_NONE);
b0d623f7
A
190 PMAP_LOCK(grand);
191 pde = pmap_pde(grand, vaddr);
192 }
193
194 if (pde == 0)
195 panic("pmap_nest: no pde, grand %p vaddr 0x%llx", grand, vaddr);
196 vaddr += NBPDE;
197 pmap_store_pte(pde, tpde);
198 i++;
199 }
200 }
201
202 PMAP_UNLOCK(grand);
203
5ba3f43e 204 PMAP_TRACE(PMAP_CODE(PMAP__NEST) | DBG_FUNC_END, KERN_SUCCESS);
b0d623f7
A
205
206 return KERN_SUCCESS;
207}
208
209/*
210 * kern_return_t pmap_unnest(grand, vaddr)
211 *
212 * grand = the pmap that we will un-nest subord from
213 * vaddr = start of range in pmap to be unnested
214 *
215 * Removes a pmap from another. This is used to implement shared segments.
216 */
217
218kern_return_t pmap_unnest(pmap_t grand, addr64_t vaddr, uint64_t size) {
b0d623f7
A
219 pd_entry_t *pde;
220 unsigned int i;
221 uint64_t num_pde;
222 addr64_t va_start, va_end;
223 uint64_t npdpt = PMAP_INVALID_PDPTNUM;
224
225 PMAP_TRACE(PMAP_CODE(PMAP__UNNEST) | DBG_FUNC_START,
5ba3f43e 226 VM_KERNEL_ADDRHIDE(grand), VM_KERNEL_ADDRHIDE(vaddr));
b0d623f7
A
227
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",
231 grand, vaddr, size);
232 }
233
3e170ce0
A
234 assert(!is_ept_pmap(grand));
235
b0d623f7
A
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;
240
241 PMAP_LOCK(grand);
242
243 num_pde = size >> PDESHIFT;
244 vaddr = va_start;
245
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;
253 vaddr += NBPDPT;
254 continue;
255 }
256 }
257 pde = pmap_pde(grand, (vm_map_offset_t)vaddr);
258 if (pde == 0)
259 panic("pmap_unnest: no pde, grand %p vaddr 0x%llx\n", grand, vaddr);
260 pmap_store_pte(pde, (pd_entry_t)0);
261 i++;
262 vaddr += NBPDE;
263 }
264
265 PMAP_UPDATE_TLBS(grand, va_start, va_end);
266
267 PMAP_UNLOCK(grand);
5ba3f43e
A
268
269 PMAP_TRACE(PMAP_CODE(PMAP__UNNEST) | DBG_FUNC_END, KERN_SUCCESS);
b0d623f7
A
270
271 return KERN_SUCCESS;
272}
273
3e170ce0
A
274kern_return_t
275pmap_unnest_options(
276 pmap_t grand,
277 addr64_t vaddr,
278 __unused uint64_t size,
279 __unused unsigned int options) {
280 return pmap_unnest(grand, vaddr, size);
281}
282
b0d623f7
A
283/* Invoked by the Mach VM to determine the platform specific unnest region */
284
285boolean_t pmap_adjust_unnest_parameters(pmap_t p, vm_map_offset_t *s, vm_map_offset_t *e) {
286 pd_entry_t *pdpte;
287 boolean_t rval = FALSE;
288
289 if (!cpu_64bit)
290 return rval;
291
292 PMAP_LOCK(p);
293
294 pdpte = pmap64_pdpt(p, *s);
295 if (pdpte && (*pdpte & INTEL_PDPTE_NESTED)) {
296 *s &= ~(NBPDPT -1);
297 rval = TRUE;
298 }
299
300 pdpte = pmap64_pdpt(p, *e);
301 if (pdpte && (*pdpte & INTEL_PDPTE_NESTED)) {
302 *e = ((*e + NBPDPT) & ~(NBPDPT -1));
303 rval = TRUE;
304 }
305
306 PMAP_UNLOCK(p);
307
308 return rval;
309}
310
311/*
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.
317 */
318ppnum_t
319pmap_find_phys(pmap_t pmap, addr64_t va)
320{
321 pt_entry_t *ptp;
322 pd_entry_t *pdep;
323 ppnum_t ppn = 0;
324 pd_entry_t pde;
325 pt_entry_t pte;
3e170ce0
A
326 boolean_t is_ept;
327
328 is_ept = is_ept_pmap(pmap);
b0d623f7
A
329
330 mp_disable_preemption();
331
332 /* This refcount test is a band-aid--several infrastructural changes
333 * are necessary to eliminate invocation of this routine from arbitrary
334 * contexts.
335 */
336
337 if (!pmap->ref_count)
338 goto pfp_exit;
339
340 pdep = pmap_pde(pmap, va);
341
3e170ce0
A
342 if ((pdep != PD_ENTRY_NULL) && ((pde = *pdep) & PTE_VALID_MASK(is_ept))) {
343 if (pde & PTE_PS) {
b0d623f7
A
344 ppn = (ppnum_t) i386_btop(pte_to_pa(pde));
345 ppn += (ppnum_t) ptenum(va);
346 }
347 else {
348 ptp = pmap_pte(pmap, va);
3e170ce0 349 if ((PT_ENTRY_NULL != ptp) && (((pte = *ptp) & PTE_VALID_MASK(is_ept)) != 0)) {
b0d623f7
A
350 ppn = (ppnum_t) i386_btop(pte_to_pa(pte));
351 }
352 }
353 }
354pfp_exit:
355 mp_enable_preemption();
356
357 return ppn;
358}
359
6d2010ae
A
360/*
361 * Update cache attributes for all extant managed mappings.
362 * Assumes PV for this page is locked, and that the page
3e170ce0
A
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.
366 *
367 * We assert that the passed set of attributes is a subset of the
368 * PHYS_CACHEABILITY_MASK.
6d2010ae 369 */
6d2010ae
A
370void
371pmap_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;
375 pmap_t pmap;
376 pt_entry_t *ptep;
3e170ce0
A
377 boolean_t is_ept;
378 unsigned ept_attributes;
6d2010ae
A
379
380 assert(IS_MANAGED_PAGE(pn));
3e170ce0
A
381 assert(((~PHYS_CACHEABILITY_MASK) & attributes) == 0);
382
383 /* We don't support the PTA bit for EPT PTEs */
384 if (attributes & INTEL_PTE_NCACHE)
385 ept_attributes = INTEL_EPT_NCACHE;
386 else
387 ept_attributes = INTEL_EPT_WB;
6d2010ae
A
388
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.
395 */
396
397 /*
398 * Alter attributes on all mappings
399 */
400 if (pv_h->pmap != PMAP_NULL) {
401 pv_e = pv_h;
402 pvh_e = (pv_hashed_entry_t)pv_e;
403
404 do {
405 pmap = pv_e->pmap;
39037602 406 vaddr = PVE_VA(pv_e);
6d2010ae 407 ptep = pmap_pte(pmap, vaddr);
3e170ce0 408
6d2010ae
A
409 if (0 == ptep)
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);
411
3e170ce0
A
412 is_ept = is_ept_pmap(pmap);
413
6d2010ae 414 nexth = (pv_hashed_entry_t)queue_next(&pvh_e->qlink);
3e170ce0
A
415 if (!is_ept) {
416 pmap_update_pte(ptep, PHYS_CACHEABILITY_MASK, attributes);
417 } else {
418 pmap_update_pte(ptep, INTEL_EPT_CACHE_MASK, ept_attributes);
419 }
6d2010ae
A
420 PMAP_UPDATE_TLBS(pmap, vaddr, vaddr + PAGE_SIZE);
421 pvh_e = nexth;
422 } while ((pv_e = (pv_rooted_entry_t)nexth) != pv_h);
423 }
424}
425
426void x86_filter_TLB_coherency_interrupts(boolean_t dofilter) {
427 assert(ml_get_interrupts_enabled() == 0 || get_preemption_level() != 0);
428
429 if (dofilter) {
430 CPU_CR3_MARK_INACTIVE();
431 } else {
432 CPU_CR3_MARK_ACTIVE();
39236c6e 433 mfence();
6d2010ae
A
434 if (current_cpu_datap()->cpu_tlb_invalid)
435 process_pmap_updates();
436 }
437}
438
439
b7266188
A
440/*
441 * Insert the given physical page (p) at
442 * the specified virtual address (v) in the
443 * target physical map with the protection requested.
444 *
445 * If specified, the page will be wired down, meaning
446 * that the related pte cannot be reclaimed.
447 *
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.
451 */
316670eb 452
5ba3f43e 453kern_return_t
b7266188 454pmap_enter(
39037602 455 pmap_t pmap,
b7266188
A
456 vm_map_offset_t vaddr,
457 ppnum_t pn,
458 vm_prot_t prot,
316670eb 459 vm_prot_t fault_type,
b7266188
A
460 unsigned int flags,
461 boolean_t wired)
316670eb 462{
5ba3f43e 463 return pmap_enter_options(pmap, vaddr, pn, prot, fault_type, flags, wired, PMAP_EXPAND_OPTIONS_NONE, NULL);
316670eb
A
464}
465
39236c6e 466
316670eb
A
467kern_return_t
468pmap_enter_options(
39037602 469 pmap_t pmap,
316670eb
A
470 vm_map_offset_t vaddr,
471 ppnum_t pn,
472 vm_prot_t prot,
473 __unused vm_prot_t fault_type,
474 unsigned int flags,
475 boolean_t wired,
39236c6e
A
476 unsigned int options,
477 void *arg)
b7266188
A
478{
479 pt_entry_t *pte;
480 pv_rooted_entry_t pv_h;
316670eb 481 ppnum_t pai;
b7266188
A
482 pv_hashed_entry_t pvh_e;
483 pv_hashed_entry_t pvh_new;
484 pt_entry_t template;
485 pmap_paddr_t old_pa;
486 pmap_paddr_t pa = (pmap_paddr_t) i386_ptob(pn);
487 boolean_t need_tlbflush = FALSE;
488 boolean_t set_NX;
489 char oattr;
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;
22ba694c 494 uint64_t delpage_pde_index = 0;
b7266188 495 pt_entry_t old_pte;
5ba3f43e 496 kern_return_t kr;
3e170ce0 497 boolean_t is_ept;
d190cdc3 498 boolean_t is_altacct;
b7266188 499
5ba3f43e
A
500 kr = KERN_FAILURE;
501
b7266188 502 pmap_intr_assert();
b7266188
A
503
504 if (pmap == PMAP_NULL)
316670eb
A
505 return KERN_INVALID_ARGUMENT;
506
3e170ce0
A
507 is_ept = is_ept_pmap(pmap);
508
316670eb
A
509 /* N.B. We can be supplied a zero page frame in the NOENTER case, it's an
510 * unused value for that scenario.
511 */
512 assert(pn != vm_page_fictitious_addr);
513
b7266188 514 if (pn == vm_page_guard_addr)
316670eb 515 return KERN_INVALID_ARGUMENT;
b7266188
A
516
517 PMAP_TRACE(PMAP_CODE(PMAP__ENTER) | DBG_FUNC_START,
5ba3f43e
A
518 VM_KERNEL_ADDRHIDE(pmap), VM_KERNEL_ADDRHIDE(vaddr), pn,
519 prot);
b7266188
A
520
521 if ((prot & VM_PROT_EXECUTE) || !nx_enabled || !pmap->nx_enabled)
522 set_NX = FALSE;
523 else
524 set_NX = TRUE;
525
316670eb
A
526 if (__improbable(set_NX && (pmap == kernel_pmap) && ((pmap_disable_kstack_nx && (flags & VM_MEM_STACK)) || (pmap_disable_kheap_nx && !(flags & VM_MEM_STACK))))) {
527 set_NX = FALSE;
528 }
529
b7266188
A
530 /*
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).
536 */
537
538 pvh_new = PV_HASHED_ENTRY_NULL;
539Retry:
540 pvh_e = PV_HASHED_ENTRY_NULL;
541
542 PMAP_LOCK(pmap);
543
544 /*
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.
548 */
39037602 549 if (superpage) {
b7266188
A
550 while ((pte = pmap64_pde(pmap, vaddr)) == PD_ENTRY_NULL) {
551 /* need room for another pde entry */
552 PMAP_UNLOCK(pmap);
5ba3f43e
A
553 kr = pmap_expand_pdpt(pmap, vaddr, options);
554 if (kr != KERN_SUCCESS)
555 goto done;
b7266188
A
556 PMAP_LOCK(pmap);
557 }
558 } else {
559 while ((pte = pmap_pte(pmap, vaddr)) == PT_ENTRY_NULL) {
560 /*
561 * Must unlock to expand the pmap
562 * going to grow pde level page(s)
563 */
564 PMAP_UNLOCK(pmap);
5ba3f43e
A
565 kr = pmap_expand(pmap, vaddr, options);
566 if (kr != KERN_SUCCESS)
567 goto done;
b7266188
A
568 PMAP_LOCK(pmap);
569 }
570 }
316670eb
A
571 if (options & PMAP_EXPAND_OPTIONS_NOENTER) {
572 PMAP_UNLOCK(pmap);
5ba3f43e
A
573 kr = KERN_SUCCESS;
574 goto done;
316670eb 575 }
b7266188 576
3e170ce0 577 if (superpage && *pte && !(*pte & PTE_PS)) {
b7266188
A
578 /*
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.
583 */
22ba694c 584 delpage_pde_index = pdeidx(pmap, vaddr);
b7266188
A
585 delpage_pm_obj = pmap->pm_obj;
586 *pte = 0;
587 }
588
b7266188
A
589 old_pa = pte_to_pa(*pte);
590 pai = pa_index(old_pa);
591 old_pa_locked = FALSE;
592
39236c6e 593 if (old_pa == 0 &&
39037602
A
594 PTE_IS_COMPRESSED(*pte)) {
595 /*
596 * "pmap" should be locked at this point, so this should
597 * not race with another pmap_enter() or pmap_remove_range().
598 */
599 assert(pmap != kernel_pmap);
600
39236c6e
A
601 /* one less "compressed" */
602 OSAddAtomic64(-1, &pmap->stats.compressed);
39037602
A
603 pmap_ledger_debit(pmap, task_ledgers.internal_compressed,
604 PAGE_SIZE);
605 if (*pte & PTE_COMPRESSED_ALT) {
606 pmap_ledger_debit(
607 pmap,
608 task_ledgers.alternate_accounting_compressed,
609 PAGE_SIZE);
610 } else {
611 /* was part of the footprint */
612 pmap_ledger_debit(pmap, task_ledgers.phys_footprint,
613 PAGE_SIZE);
614 }
39236c6e
A
615 /* marker will be cleared below */
616 }
617
b7266188
A
618 /*
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
621 * drop the lock
622 */
623 if ((0 != old_pa) && IS_MANAGED_PAGE(pai)) {
624 LOCK_PVH(pai);
625 old_pa_locked = TRUE;
626 old_pa = pte_to_pa(*pte);
627 if (0 == old_pa) {
628 UNLOCK_PVH(pai); /* another path beat us to it */
629 old_pa_locked = FALSE;
630 }
631 }
632
633 /*
634 * Special case if the incoming physical page is already mapped
635 * at this address.
636 */
637 if (old_pa == pa) {
6d2010ae 638 pt_entry_t old_attributes =
3e170ce0 639 *pte & ~(PTE_REF(is_ept) | PTE_MOD(is_ept));
b7266188
A
640
641 /*
642 * May be changing its wired attribute or protection
643 */
644
3e170ce0
A
645 template = pa_to_pte(pa);
646
647 /* ?: WORTH ASSERTING THAT AT LEAST ONE RWX (implicit valid) PASSED FOR EPT? */
648 if (!is_ept) {
649 template |= INTEL_PTE_VALID;
650 } else {
651 template |= INTEL_EPT_IPTA;
652 }
653
654 template |= pmap_get_cache_attributes(pa_index(pa), is_ept);
b7266188 655
3e170ce0
A
656 /*
657 * We don't support passing VM_MEM_NOT_CACHEABLE flags for EPT PTEs
658 */
659 if (!is_ept && (VM_MEM_NOT_CACHEABLE ==
660 (flags & (VM_MEM_NOT_CACHEABLE | VM_WIMG_USE_DEFAULT)))) {
b7266188
A
661 if (!(flags & VM_MEM_GUARDED))
662 template |= INTEL_PTE_PTA;
663 template |= INTEL_PTE_NCACHE;
664 }
3e170ce0 665 if (pmap != kernel_pmap && !is_ept)
b7266188 666 template |= INTEL_PTE_USER;
3e170ce0
A
667
668 if (prot & VM_PROT_READ)
669 template |= PTE_READ(is_ept);
670
39236c6e 671 if (prot & VM_PROT_WRITE) {
3e170ce0
A
672 template |= PTE_WRITE(is_ept);
673 if (is_ept && !pmap_ept_support_ad) {
674 template |= PTE_MOD(is_ept);
675 if (old_pa_locked) {
676 assert(IS_MANAGED_PAGE(pai));
677 pmap_phys_attributes[pai] |= PHYS_MODIFIED;
678 }
679 }
680 }
681 if (prot & VM_PROT_EXECUTE) {
682 assert(set_NX == 0);
683 template = pte_set_ex(template, is_ept);
39236c6e 684 }
b7266188
A
685
686 if (set_NX)
3e170ce0 687 template = pte_remove_ex(template, is_ept);
b7266188
A
688
689 if (wired) {
3e170ce0 690 template |= PTE_WIRED;
316670eb
A
691 if (!iswired(old_attributes)) {
692 OSAddAtomic(+1, &pmap->stats.wired_count);
693 pmap_ledger_credit(pmap, task_ledgers.wired_mem, PAGE_SIZE);
694 }
b7266188 695 } else {
6d2010ae 696 if (iswired(old_attributes)) {
b7266188 697 assert(pmap->stats.wired_count >= 1);
316670eb
A
698 OSAddAtomic(-1, &pmap->stats.wired_count);
699 pmap_ledger_debit(pmap, task_ledgers.wired_mem, PAGE_SIZE);
b7266188
A
700 }
701 }
3e170ce0 702
b7266188 703 if (superpage) /* this path can not be used */
3e170ce0 704 template |= PTE_PS; /* to change the page size! */
15129b1c
A
705
706 if (old_attributes == template)
707 goto dont_update_pte;
708
6d2010ae
A
709 /* Determine delta, PV locked */
710 need_tlbflush =
3e170ce0 711 ((old_attributes ^ template) != PTE_WIRED);
5ba3f43e 712
3e170ce0
A
713 if (need_tlbflush == TRUE && !(old_attributes & PTE_WRITE(is_ept))) {
714 if ((old_attributes ^ template) == PTE_WRITE(is_ept))
39236c6e
A
715 need_tlbflush = FALSE;
716 }
b7266188 717
3e170ce0
A
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);
721 if (old_pa_locked) {
722 assert(IS_MANAGED_PAGE(pai));
723 pmap_phys_attributes[pai] |= PHYS_REFERENCED;
724 }
725 }
726
b7266188 727 /* store modified PTE and preserve RC bits */
316670eb
A
728 pt_entry_t npte, opte;;
729 do {
730 opte = *pte;
3e170ce0 731 npte = template | (opte & (PTE_REF(is_ept) | PTE_MOD(is_ept)));
316670eb 732 } while (!pmap_cmpx_pte(pte, opte, npte));
15129b1c 733dont_update_pte:
b7266188
A
734 if (old_pa_locked) {
735 UNLOCK_PVH(pai);
736 old_pa_locked = FALSE;
737 }
b7266188
A
738 goto Done;
739 }
740
741 /*
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.
747 *
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.
752 */
753
754 if (old_pa != (pmap_paddr_t) 0) {
5ba3f43e 755 boolean_t was_altacct = FALSE;
b7266188
A
756
757 /*
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.
761 */
762
763 /* invalidate the PTE */
3e170ce0 764 pmap_update_pte(pte, PTE_VALID_MASK(is_ept), 0);
b7266188
A
765 /* propagate invalidate everywhere */
766 PMAP_UPDATE_TLBS(pmap, vaddr, vaddr + PAGE_SIZE);
767 /* remember reference and change */
768 old_pte = *pte;
3e170ce0 769 oattr = (char) (old_pte & (PTE_MOD(is_ept) | PTE_REF(is_ept)));
b7266188
A
770 /* completely invalidate the PTE */
771 pmap_store_pte(pte, 0);
772
d190cdc3
A
773 if (IS_MANAGED_PAGE(pai)) {
774 /*
775 * Remove the mapping from the pvlist for
776 * this physical page.
777 * We'll end up with either a rooted pv or a
778 * hashed pv
779 */
780 pvh_e = pmap_pv_remove(pmap, vaddr, (ppnum_t *) &pai, &old_pte, &was_altacct);
781 }
782
b7266188 783 if (IS_MANAGED_PAGE(pai)) {
6d2010ae 784 pmap_assert(old_pa_locked == TRUE);
316670eb 785 pmap_ledger_debit(pmap, task_ledgers.phys_mem, PAGE_SIZE);
b7266188 786 assert(pmap->stats.resident_count >= 1);
316670eb 787 OSAddAtomic(-1, &pmap->stats.resident_count);
39236c6e 788 if (pmap != kernel_pmap) {
d190cdc3 789 /* update pmap stats */
39236c6e 790 if (IS_REUSABLE_PAGE(pai)) {
39037602
A
791 PMAP_STATS_ASSERTF(
792 (pmap->stats.reusable > 0,
793 "reusable %d",
794 pmap->stats.reusable));
39236c6e
A
795 OSAddAtomic(-1, &pmap->stats.reusable);
796 } else if (IS_INTERNAL_PAGE(pai)) {
39037602
A
797 PMAP_STATS_ASSERTF(
798 (pmap->stats.internal > 0,
799 "internal %d",
800 pmap->stats.internal));
39236c6e
A
801 OSAddAtomic(-1, &pmap->stats.internal);
802 } else {
39037602
A
803 PMAP_STATS_ASSERTF(
804 (pmap->stats.external > 0,
805 "external %d",
806 pmap->stats.external));
39236c6e
A
807 OSAddAtomic(-1, &pmap->stats.external);
808 }
d190cdc3
A
809
810 /* update ledgers */
811 if (was_altacct) {
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);
824 } else {
825 /* not an internal page */
826 }
39236c6e 827 }
b7266188 828 if (iswired(*pte)) {
b7266188 829 assert(pmap->stats.wired_count >= 1);
316670eb
A
830 OSAddAtomic(-1, &pmap->stats.wired_count);
831 pmap_ledger_debit(pmap, task_ledgers.wired_mem,
832 PAGE_SIZE);
b7266188 833 }
3e170ce0
A
834
835 if (!is_ept) {
836 pmap_phys_attributes[pai] |= oattr;
837 } else {
838 pmap_phys_attributes[pai] |= ept_refmod_to_physmap(oattr);
839 }
b7266188 840
b7266188
A
841 } else {
842
843 /*
844 * old_pa is not managed.
845 * Do removal part of accounting.
846 */
847
39236c6e
A
848 if (pmap != kernel_pmap) {
849#if 00
850 assert(pmap->stats.device > 0);
851 OSAddAtomic(-1, &pmap->stats.device);
852#endif
853 }
b7266188
A
854 if (iswired(*pte)) {
855 assert(pmap->stats.wired_count >= 1);
316670eb
A
856 OSAddAtomic(-1, &pmap->stats.wired_count);
857 pmap_ledger_debit(pmap, task_ledgers.wired_mem, PAGE_SIZE);
b7266188
A
858 }
859 }
860 }
861
862 /*
863 * if we had a previously managed paged locked, unlock it now
864 */
865 if (old_pa_locked) {
866 UNLOCK_PVH(pai);
867 old_pa_locked = FALSE;
868 }
869
870 pai = pa_index(pa); /* now working with new incoming phys page */
871 if (IS_MANAGED_PAGE(pai)) {
872
873 /*
874 * Step 2) Enter the mapping in the PV list for this
875 * physical page.
876 */
877 pv_h = pai_to_pvh(pai);
878
879 LOCK_PVH(pai);
880
881 if (pv_h->pmap == PMAP_NULL) {
882 /*
883 * No mappings yet, use rooted pv
884 */
39037602 885 pv_h->va_and_flags = vaddr;
b7266188
A
886 pv_h->pmap = pmap;
887 queue_init(&pv_h->qlink);
39236c6e
A
888
889 if (options & PMAP_OPTIONS_INTERNAL) {
890 pmap_phys_attributes[pai] |= PHYS_INTERNAL;
891 } else {
892 pmap_phys_attributes[pai] &= ~PHYS_INTERNAL;
893 }
894 if (options & PMAP_OPTIONS_REUSABLE) {
895 pmap_phys_attributes[pai] |= PHYS_REUSABLE;
896 } else {
897 pmap_phys_attributes[pai] &= ~PHYS_REUSABLE;
898 }
39037602
A
899 if ((options & PMAP_OPTIONS_ALT_ACCT) &&
900 IS_INTERNAL_PAGE(pai)) {
39037602 901 pv_h->va_and_flags |= PVE_IS_ALTACCT;
d190cdc3 902 is_altacct = TRUE;
39037602
A
903 } else {
904 pv_h->va_and_flags &= ~PVE_IS_ALTACCT;
d190cdc3 905 is_altacct = FALSE;
39037602 906 }
b7266188
A
907 } else {
908 /*
909 * Add new pv_hashed_entry after header.
910 */
911 if ((PV_HASHED_ENTRY_NULL == pvh_e) && pvh_new) {
912 pvh_e = pvh_new;
913 pvh_new = PV_HASHED_ENTRY_NULL;
914 } else if (PV_HASHED_ENTRY_NULL == pvh_e) {
6d2010ae 915 PV_HASHED_ALLOC(&pvh_e);
b7266188
A
916 if (PV_HASHED_ENTRY_NULL == pvh_e) {
917 /*
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
924 * us.
925 */
926 if (kernel_pmap == pmap) {
6d2010ae 927 PV_HASHED_KERN_ALLOC(&pvh_e);
b7266188
A
928 } else {
929 UNLOCK_PVH(pai);
930 PMAP_UNLOCK(pmap);
6d2010ae 931 pmap_pv_throttle(pmap);
b7266188
A
932 pvh_new = (pv_hashed_entry_t) zalloc(pv_hashed_list_zone);
933 goto Retry;
934 }
935 }
936 }
5ba3f43e 937
b7266188
A
938 if (PV_HASHED_ENTRY_NULL == pvh_e)
939 panic("Mapping alias chain exhaustion, possibly induced by numerous kernel virtual double mappings");
940
39037602 941 pvh_e->va_and_flags = vaddr;
b7266188
A
942 pvh_e->pmap = pmap;
943 pvh_e->ppn = pn;
d190cdc3
A
944 if ((options & PMAP_OPTIONS_ALT_ACCT) &&
945 IS_INTERNAL_PAGE(pai)) {
946 pvh_e->va_and_flags |= PVE_IS_ALTACCT;
947 is_altacct = TRUE;
948 } else {
949 pvh_e->va_and_flags &= ~PVE_IS_ALTACCT;
950 is_altacct = FALSE;
951 }
b7266188
A
952 pv_hash_add(pvh_e, pv_h);
953
954 /*
955 * Remember that we used the pvlist entry.
956 */
957 pvh_e = PV_HASHED_ENTRY_NULL;
958 }
959
960 /*
961 * only count the mapping
962 * for 'managed memory'
963 */
316670eb 964 pmap_ledger_credit(pmap, task_ledgers.phys_mem, PAGE_SIZE);
6d2010ae 965 OSAddAtomic(+1, &pmap->stats.resident_count);
b7266188
A
966 if (pmap->stats.resident_count > pmap->stats.resident_max) {
967 pmap->stats.resident_max = pmap->stats.resident_count;
968 }
39236c6e 969 if (pmap != kernel_pmap) {
d190cdc3 970 /* update pmap stats */
39236c6e
A
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);
977 } else {
978 OSAddAtomic(+1, &pmap->stats.external);
979 PMAP_STATS_PEAK(pmap->stats.external);
980 }
d190cdc3
A
981
982 /* update ledgers */
983 if (is_altacct) {
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)) {
990 assert(!is_altacct);
991 assert(IS_INTERNAL_PAGE(pai));
992 /* internal but reusable: not in footprint */
993 } else if (IS_INTERNAL_PAGE(pai)) {
994 assert(!is_altacct);
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);
999 } else {
1000 /* not internal: not in footprint */
1001 }
39236c6e 1002 }
060df5ea
A
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.
1006 */
316670eb 1007 pmap_ledger_credit(pmap, task_ledgers.phys_mem, PAGE_SIZE);
060df5ea 1008 OSAddAtomic(+1, &pmap->stats.resident_count);
39236c6e
A
1009 if (pmap != kernel_pmap) {
1010#if 00
1011 OSAddAtomic(+1, &pmap->stats.device);
1012 PMAP_STATS_PEAK(pmap->stats.device);
1013#endif
1014 }
b7266188
A
1015 }
1016 /*
1017 * Step 3) Enter the mapping.
1018 *
1019 * Build a template to speed up entering -
1020 * only the pfn changes.
1021 */
3e170ce0
A
1022 template = pa_to_pte(pa);
1023
1024 if (!is_ept) {
1025 template |= INTEL_PTE_VALID;
1026 } else {
1027 template |= INTEL_EPT_IPTA;
1028 }
1029
1030
6d2010ae
A
1031 /*
1032 * DRK: It may be worth asserting on cache attribute flags that diverge
1033 * from the existing physical page attributes.
1034 */
b7266188 1035
3e170ce0
A
1036 template |= pmap_get_cache_attributes(pa_index(pa), is_ept);
1037
1038 /*
1039 * We don't support passing VM_MEM_NOT_CACHEABLE flags for EPT PTEs
1040 */
1041 if (!is_ept && (flags & VM_MEM_NOT_CACHEABLE)) {
b7266188
A
1042 if (!(flags & VM_MEM_GUARDED))
1043 template |= INTEL_PTE_PTA;
1044 template |= INTEL_PTE_NCACHE;
1045 }
3e170ce0 1046 if (pmap != kernel_pmap && !is_ept)
b7266188 1047 template |= INTEL_PTE_USER;
3e170ce0
A
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;
1056 }
1057 }
1058 if (prot & VM_PROT_EXECUTE) {
1059 assert(set_NX == 0);
1060 template = pte_set_ex(template, is_ept);
1061 }
1062
b7266188 1063 if (set_NX)
3e170ce0 1064 template = pte_remove_ex(template, is_ept);
b7266188
A
1065 if (wired) {
1066 template |= INTEL_PTE_WIRED;
1067 OSAddAtomic(+1, & pmap->stats.wired_count);
316670eb 1068 pmap_ledger_credit(pmap, task_ledgers.wired_mem, PAGE_SIZE);
b7266188
A
1069 }
1070 if (superpage)
1071 template |= INTEL_PTE_PS;
3e170ce0
A
1072
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;
1078 }
1079
b7266188
A
1080 pmap_store_pte(pte, template);
1081
1082 /*
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
1085 * has been stored
1086 */
1087 if (IS_MANAGED_PAGE(pai)) {
1088 UNLOCK_PVH(pai);
1089 }
1090Done:
39236c6e
A
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);
1094 else
1095 PMAP_UPDATE_TLBS(pmap, vaddr, vaddr + PAGE_SIZE);
1096 }
b7266188
A
1097 if (pvh_e != PV_HASHED_ENTRY_NULL) {
1098 PV_HASHED_FREE_LIST(pvh_e, pvh_e, 1);
1099 }
1100 if (pvh_new != PV_HASHED_ENTRY_NULL) {
1101 PV_HASHED_KERN_FREE_LIST(pvh_new, pvh_new, 1);
1102 }
1103 PMAP_UNLOCK(pmap);
1104
1105 if (delpage_pm_obj) {
1106 vm_page_t m;
1107
1108 vm_object_lock(delpage_pm_obj);
22ba694c 1109 m = vm_page_lookup(delpage_pm_obj, (delpage_pde_index * PAGE_SIZE));
b7266188
A
1110 if (m == VM_PAGE_NULL)
1111 panic("pmap_enter: pte page not in object");
1112 VM_PAGE_FREE(m);
3e170ce0 1113 vm_object_unlock(delpage_pm_obj);
b7266188 1114 OSAddAtomic(-1, &inuse_ptepages_count);
316670eb 1115 PMAP_ZINFO_PFREE(pmap, PAGE_SIZE);
b7266188
A
1116 }
1117
5ba3f43e
A
1118 kr = KERN_SUCCESS;
1119done:
1120 PMAP_TRACE(PMAP_CODE(PMAP__ENTER) | DBG_FUNC_END, kr);
1121 return kr;
b7266188
A
1122}
1123
1124/*
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.
1129 *
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.
1134 */
1135
1136void
1137pmap_remove_range(
1138 pmap_t pmap,
1139 vm_map_offset_t start_vaddr,
1140 pt_entry_t *spte,
1141 pt_entry_t *epte)
39236c6e 1142{
3e170ce0
A
1143 pmap_remove_range_options(pmap, start_vaddr, spte, epte,
1144 PMAP_OPTIONS_REMOVE);
39236c6e
A
1145}
1146
1147void
1148pmap_remove_range_options(
1149 pmap_t pmap,
1150 vm_map_offset_t start_vaddr,
1151 pt_entry_t *spte,
1152 pt_entry_t *epte,
1153 int options)
b7266188
A
1154{
1155 pt_entry_t *cpte;
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;
1159 int pvh_cnt = 0;
1160 int num_removed, num_unwired, num_found, num_invalid;
d190cdc3
A
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;
316670eb 1165 ppnum_t pai;
b7266188
A
1166 pmap_paddr_t pa;
1167 vm_map_offset_t vaddr;
3e170ce0 1168 boolean_t is_ept = is_ept_pmap(pmap);
d190cdc3 1169 boolean_t was_altacct;
b7266188
A
1170
1171 num_removed = 0;
1172 num_unwired = 0;
1173 num_found = 0;
1174 num_invalid = 0;
d190cdc3
A
1175 stats_external = 0;
1176 stats_internal = 0;
1177 stats_reusable = 0;
1178 stats_compressed = 0;
1179 ledgers_internal = 0;
1180 ledgers_compressed = 0;
1181 ledgers_alt_internal = 0;
1182 ledgers_alt_compressed = 0;
b7266188
A
1183 /* invalidate the PTEs first to "freeze" them */
1184 for (cpte = spte, vaddr = start_vaddr;
1185 cpte < epte;
1186 cpte++, vaddr += PAGE_SIZE_64) {
1187 pt_entry_t p = *cpte;
1188
1189 pa = pte_to_pa(p);
39236c6e 1190 if (pa == 0) {
d190cdc3 1191 if ((options & PMAP_OPTIONS_REMOVE) &&
39037602 1192 (PTE_IS_COMPRESSED(p))) {
d190cdc3 1193 assert(pmap != kernel_pmap);
39037602 1194 /* one less "compressed"... */
d190cdc3
A
1195 stats_compressed++;
1196 ledgers_compressed++;
39037602
A
1197 if (p & PTE_COMPRESSED_ALT) {
1198 /* ... but it used to be "ALTACCT" */
d190cdc3 1199 ledgers_alt_compressed++;
39037602
A
1200 }
1201 /* clear marker(s) */
39236c6e 1202 /* XXX probably does not need to be atomic! */
39037602 1203 pmap_update_pte(cpte, INTEL_PTE_COMPRESSED_MASK, 0);
39236c6e 1204 }
b7266188 1205 continue;
39236c6e 1206 }
b7266188
A
1207 num_found++;
1208
1209 if (iswired(p))
1210 num_unwired++;
1211
1212 pai = pa_index(pa);
1213
1214 if (!IS_MANAGED_PAGE(pai)) {
1215 /*
1216 * Outside range of managed physical memory.
1217 * Just remove the mappings.
1218 */
1219 pmap_store_pte(cpte, 0);
1220 continue;
1221 }
1222
3e170ce0 1223 if ((p & PTE_VALID_MASK(is_ept)) == 0)
b7266188
A
1224 num_invalid++;
1225
316670eb 1226 /* invalidate the PTE */
3e170ce0 1227 pmap_update_pte(cpte, PTE_VALID_MASK(is_ept), 0);
b7266188
A
1228 }
1229
1230 if (num_found == 0) {
1231 /* nothing was changed: we're done */
1232 goto update_counts;
1233 }
1234
1235 /* propagate the invalidates to other CPUs */
1236
1237 PMAP_UPDATE_TLBS(pmap, start_vaddr, vaddr);
1238
1239 for (cpte = spte, vaddr = start_vaddr;
1240 cpte < epte;
1241 cpte++, vaddr += PAGE_SIZE_64) {
1242
1243 pa = pte_to_pa(*cpte);
39037602
A
1244 if (pa == 0) {
1245 check_pte_for_compressed_marker:
1246 /*
1247 * This PTE could have been replaced with a
1248 * "compressed" marker after our first "freeze"
1249 * loop above, so check again.
1250 */
d190cdc3 1251 if ((options & PMAP_OPTIONS_REMOVE) &&
39037602 1252 (PTE_IS_COMPRESSED(*cpte))) {
d190cdc3 1253 assert(pmap != kernel_pmap);
39037602 1254 /* one less "compressed"... */
d190cdc3
A
1255 stats_compressed++;
1256 ledgers_compressed++;
39037602
A
1257 if (*cpte & PTE_COMPRESSED_ALT) {
1258 /* ... but it used to be "ALTACCT" */
d190cdc3 1259 ledgers_alt_compressed++;
39037602
A
1260 }
1261 pmap_store_pte(cpte, 0);
1262 }
b7266188 1263 continue;
39037602 1264 }
b7266188
A
1265
1266 pai = pa_index(pa);
1267
1268 LOCK_PVH(pai);
1269
1270 pa = pte_to_pa(*cpte);
1271 if (pa == 0) {
1272 UNLOCK_PVH(pai);
39037602 1273 goto check_pte_for_compressed_marker;
b7266188 1274 }
d190cdc3
A
1275
1276 /*
1277 * Remove the mapping from the pvlist for this physical page.
1278 */
1279 pvh_e = pmap_pv_remove(pmap, vaddr, (ppnum_t *) &pai, cpte, &was_altacct);
1280
b7266188 1281 num_removed++;
d190cdc3 1282 /* update pmap stats */
39236c6e 1283 if (IS_REUSABLE_PAGE(pai)) {
d190cdc3 1284 stats_reusable++;
39236c6e 1285 } else if (IS_INTERNAL_PAGE(pai)) {
d190cdc3
A
1286 stats_internal++;
1287 } else {
1288 stats_external++;
1289 }
1290 /* update ledgers */
1291 if (was_altacct) {
1292 /* internal and alternate accounting */
1293 assert(IS_INTERNAL_PAGE(pai));
1294 ledgers_internal++;
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)) {
1301 /* internal */
1302 assert(!was_altacct);
1303 assert(!IS_REUSABLE_PAGE(pai));
1304 ledgers_internal++;
39236c6e 1305 } else {
d190cdc3 1306 /* not internal */
39236c6e 1307 }
b7266188
A
1308
1309 /*
1310 * Get the modify and reference bits, then
1311 * nuke the entry in the page table
1312 */
1313 /* remember reference and change */
7e41aa88
A
1314 if (!is_ept) {
1315 pmap_phys_attributes[pai] |=
1316 *cpte & (PHYS_MODIFIED | PHYS_REFERENCED);
1317 } else {
1318 pmap_phys_attributes[pai] |=
1319 ept_refmod_to_physmap((*cpte & (INTEL_EPT_REF | INTEL_EPT_MOD))) & (PHYS_MODIFIED | PHYS_REFERENCED);
1320 }
b7266188 1321
b7266188
A
1322 /* completely invalidate the PTE */
1323 pmap_store_pte(cpte, 0);
1324
1325 UNLOCK_PVH(pai);
1326
1327 if (pvh_e != PV_HASHED_ENTRY_NULL) {
1328 pvh_e->qlink.next = (queue_entry_t) pvh_eh;
1329 pvh_eh = pvh_e;
1330
1331 if (pvh_et == PV_HASHED_ENTRY_NULL) {
1332 pvh_et = pvh_e;
1333 }
1334 pvh_cnt++;
1335 }
1336 } /* for loop */
1337
1338 if (pvh_eh != PV_HASHED_ENTRY_NULL) {
1339 PV_HASHED_FREE_LIST(pvh_eh, pvh_et, pvh_cnt);
1340 }
1341update_counts:
1342 /*
1343 * Update the counts
1344 */
1345#if TESTING
1346 if (pmap->stats.resident_count < num_removed)
1347 panic("pmap_remove_range: resident_count");
1348#endif
316670eb 1349 pmap_ledger_debit(pmap, task_ledgers.phys_mem, machine_ptob(num_removed));
39037602
A
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));
b7266188
A
1353 OSAddAtomic(-num_removed, &pmap->stats.resident_count);
1354
39236c6e 1355 if (pmap != kernel_pmap) {
d190cdc3
A
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));
1368
1369 /* update pmap stats */
1370 if (stats_external) {
1371 OSAddAtomic(-stats_external, &pmap->stats.external);
39037602 1372 }
d190cdc3
A
1373 if (stats_internal) {
1374 OSAddAtomic(-stats_internal, &pmap->stats.internal);
1375 }
1376 if (stats_reusable)
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) {
39037602
A
1382 pmap_ledger_debit(pmap,
1383 task_ledgers.internal,
d190cdc3 1384 machine_ptob(ledgers_internal));
39037602 1385 }
d190cdc3 1386 if (ledgers_compressed) {
39037602 1387 pmap_ledger_debit(pmap,
d190cdc3
A
1388 task_ledgers.internal_compressed,
1389 machine_ptob(ledgers_compressed));
39037602 1390 }
d190cdc3 1391 if (ledgers_alt_internal) {
39037602 1392 pmap_ledger_debit(pmap,
d190cdc3
A
1393 task_ledgers.alternate_accounting,
1394 machine_ptob(ledgers_alt_internal));
39037602 1395 }
d190cdc3 1396 if (ledgers_alt_compressed) {
39037602 1397 pmap_ledger_debit(pmap,
d190cdc3
A
1398 task_ledgers.alternate_accounting_compressed,
1399 machine_ptob(ledgers_alt_compressed));
39037602
A
1400 }
1401 pmap_ledger_debit(pmap,
1402 task_ledgers.phys_footprint,
d190cdc3
A
1403 machine_ptob((ledgers_internal -
1404 ledgers_alt_internal) +
1405 (ledgers_compressed -
1406 ledgers_alt_compressed)));
39236c6e
A
1407 }
1408
b7266188
A
1409#if TESTING
1410 if (pmap->stats.wired_count < num_unwired)
1411 panic("pmap_remove_range: wired_count");
1412#endif
39037602
A
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));
b7266188 1416 OSAddAtomic(-num_unwired, &pmap->stats.wired_count);
316670eb 1417 pmap_ledger_debit(pmap, task_ledgers.wired_mem, machine_ptob(num_unwired));
b7266188
A
1418
1419 return;
1420}
1421
1422
1423/*
1424 * Remove the given range of addresses
1425 * from the specified map.
1426 *
1427 * It is assumed that the start and end are properly
1428 * rounded to the hardware page size.
1429 */
1430void
1431pmap_remove(
1432 pmap_t map,
1433 addr64_t s64,
1434 addr64_t e64)
39236c6e 1435{
3e170ce0 1436 pmap_remove_options(map, s64, e64, PMAP_OPTIONS_REMOVE);
39236c6e
A
1437}
1438
1439void
1440pmap_remove_options(
1441 pmap_t map,
1442 addr64_t s64,
1443 addr64_t e64,
1444 int options)
b7266188
A
1445{
1446 pt_entry_t *pde;
1447 pt_entry_t *spte, *epte;
1448 addr64_t l64;
1449 uint64_t deadline;
3e170ce0 1450 boolean_t is_ept;
b7266188
A
1451
1452 pmap_intr_assert();
1453
1454 if (map == PMAP_NULL || s64 == e64)
1455 return;
1456
3e170ce0
A
1457 is_ept = is_ept_pmap(map);
1458
b7266188 1459 PMAP_TRACE(PMAP_CODE(PMAP__REMOVE) | DBG_FUNC_START,
5ba3f43e
A
1460 VM_KERNEL_ADDRHIDE(map), VM_KERNEL_ADDRHIDE(s64),
1461 VM_KERNEL_ADDRHIDE(e64));
b7266188
A
1462
1463 PMAP_LOCK(map);
1464
1465#if 0
1466 /*
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.
1472 */
1473 if (map == kernel_pmap) {
1474 static vm_offset_t kernel_stack_min = 0;
1475 static vm_offset_t kernel_stack_max = 0;
1476
1477 if (kernel_stack_min == 0) {
1478 kernel_stack_min = min_valid_stack_address();
1479 kernel_stack_max = max_valid_stack_address();
1480 }
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");
1484 }
1485#else
1486
1487 /*
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.
1493 */
1494
1495#endif
1496
1497 deadline = rdtsc64() + max_preemption_latency_tsc;
1498
1499 while (s64 < e64) {
1500 l64 = (s64 + pde_mapped_size) & ~(pde_mapped_size - 1);
1501 if (l64 > e64)
1502 l64 = e64;
1503 pde = pmap_pde(map, s64);
1504
3e170ce0
A
1505 if (pde && (*pde & PTE_VALID_MASK(is_ept))) {
1506 if (*pde & PTE_PS) {
b7266188
A
1507 /*
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
1511 * level 1 range.
1512 */
1513 spte = pde;
1514 epte = spte+1; /* excluded */
1515 } else {
1516 spte = pmap_pte(map, (s64 & ~(pde_mapped_size - 1)));
1517 spte = &spte[ptenum(s64)];
1518 epte = &spte[intel_btop(l64 - s64)];
1519 }
39236c6e
A
1520 pmap_remove_range_options(map, s64, spte, epte,
1521 options);
b7266188
A
1522 }
1523 s64 = l64;
1524
1525 if (s64 < e64 && rdtsc64() >= deadline) {
1526 PMAP_UNLOCK(map)
fe8ab488
A
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.
1534 */
b7266188
A
1535 PMAP_LOCK(map)
1536 deadline = rdtsc64() + max_preemption_latency_tsc;
1537 }
1538 }
1539
1540 PMAP_UNLOCK(map);
1541
5ba3f43e 1542 PMAP_TRACE(PMAP_CODE(PMAP__REMOVE) | DBG_FUNC_END);
b7266188
A
1543
1544}
1545
39236c6e
A
1546void
1547pmap_page_protect(
1548 ppnum_t pn,
1549 vm_prot_t prot)
1550{
1551 pmap_page_protect_options(pn, prot, 0, NULL);
1552}
1553
b7266188 1554/*
39236c6e 1555 * Routine: pmap_page_protect_options
b7266188
A
1556 *
1557 * Function:
1558 * Lower the permission for all mappings to a given
1559 * page.
1560 */
1561void
39236c6e 1562pmap_page_protect_options(
b7266188 1563 ppnum_t pn,
39236c6e
A
1564 vm_prot_t prot,
1565 unsigned int options,
1566 void *arg)
b7266188
A
1567{
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;
1571 int pvh_cnt = 0;
1572 pv_rooted_entry_t pv_h;
1573 pv_rooted_entry_t pv_e;
1574 pv_hashed_entry_t pvh_e;
1575 pt_entry_t *pte;
1576 int pai;
1577 pmap_t pmap;
1578 boolean_t remove;
39236c6e 1579 pt_entry_t new_pte_value;
3e170ce0 1580 boolean_t is_ept;
b7266188
A
1581
1582 pmap_intr_assert();
1583 assert(pn != vm_page_fictitious_addr);
1584 if (pn == vm_page_guard_addr)
1585 return;
1586
1587 pai = ppn_to_pai(pn);
1588
1589 if (!IS_MANAGED_PAGE(pai)) {
1590 /*
1591 * Not a managed page.
1592 */
1593 return;
1594 }
5ba3f43e
A
1595
1596 PMAP_TRACE(PMAP_CODE(PMAP__PAGE_PROTECT) | DBG_FUNC_START, pn, prot);
b7266188
A
1597
1598 /*
1599 * Determine the new protection.
1600 */
1601 switch (prot) {
1602 case VM_PROT_READ:
1603 case VM_PROT_READ | VM_PROT_EXECUTE:
1604 remove = FALSE;
1605 break;
1606 case VM_PROT_ALL:
1607 return; /* nothing to do */
1608 default:
1609 remove = TRUE;
1610 break;
1611 }
1612
1613 pv_h = pai_to_pvh(pai);
1614
1615 LOCK_PVH(pai);
1616
1617
1618 /*
1619 * Walk down PV list, if any, changing or removing all mappings.
1620 */
1621 if (pv_h->pmap == PMAP_NULL)
1622 goto done;
1623
1624 pv_e = pv_h;
1625 pvh_e = (pv_hashed_entry_t) pv_e; /* cheat */
1626
1627 do {
1628 vm_map_offset_t vaddr;
1629
3e170ce0
A
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;
1635 }
1636
b7266188 1637 pmap = pv_e->pmap;
3e170ce0 1638 is_ept = is_ept_pmap(pmap);
39037602 1639 vaddr = PVE_VA(pv_e);
b7266188
A
1640 pte = pmap_pte(pmap, vaddr);
1641
6d2010ae
A
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);
1644
b7266188
A
1645 if (0 == pte) {
1646 panic("pmap_page_protect() "
1647 "pmap=%p pn=0x%x vaddr=0x%llx\n",
1648 pmap, pn, vaddr);
1649 }
1650 nexth = (pv_hashed_entry_t) queue_next(&pvh_e->qlink);
1651
1652 /*
1653 * Remove the mapping if new protection is NONE
b7266188 1654 */
6d2010ae 1655 if (remove) {
6d2010ae
A
1656
1657 /* Remove per-pmap wired count */
1658 if (iswired(*pte)) {
1659 OSAddAtomic(-1, &pmap->stats.wired_count);
316670eb 1660 pmap_ledger_debit(pmap, task_ledgers.wired_mem, PAGE_SIZE);
6d2010ae
A
1661 }
1662
39236c6e
A
1663 if (pmap != kernel_pmap &&
1664 (options & PMAP_OPTIONS_COMPRESSOR) &&
1665 IS_INTERNAL_PAGE(pai)) {
39037602
A
1666 assert(!PTE_IS_COMPRESSED(*pte));
1667 /* mark this PTE as having been "compressed" */
3e170ce0 1668 new_pte_value = PTE_COMPRESSED;
d190cdc3 1669 if (IS_ALTACCT_PAGE(pai, pv_e)) {
39037602
A
1670 new_pte_value |= PTE_COMPRESSED_ALT;
1671 }
39236c6e
A
1672 } else {
1673 new_pte_value = 0;
1674 }
1675
1676 if (options & PMAP_OPTIONS_NOREFMOD) {
1677 pmap_store_pte(pte, new_pte_value);
b7266188 1678
39236c6e
A
1679 if (options & PMAP_OPTIONS_NOFLUSH)
1680 PMAP_UPDATE_TLBS_DELAYED(pmap, vaddr, vaddr + PAGE_SIZE, (pmap_flush_context *)arg);
1681 else
1682 PMAP_UPDATE_TLBS(pmap, vaddr, vaddr + PAGE_SIZE);
1683 } else {
1684 /*
1685 * Remove the mapping, collecting dirty bits.
1686 */
3e170ce0 1687 pmap_update_pte(pte, PTE_VALID_MASK(is_ept), 0);
39236c6e
A
1688
1689 PMAP_UPDATE_TLBS(pmap, vaddr, vaddr+PAGE_SIZE);
39037602
A
1690 if (!is_ept) {
1691 pmap_phys_attributes[pai] |=
1692 *pte & (PHYS_MODIFIED|PHYS_REFERENCED);
1693 } else {
1694 pmap_phys_attributes[pai] |=
1695 ept_refmod_to_physmap((*pte & (INTEL_EPT_REF | INTEL_EPT_MOD))) & (PHYS_MODIFIED | PHYS_REFERENCED);
1696 }
3e170ce0
A
1697 if ((options &
1698 PMAP_OPTIONS_COMPRESSOR_IFF_MODIFIED) &&
39037602
A
1699 IS_INTERNAL_PAGE(pai) &&
1700 (pmap_phys_attributes[pai] &
1701 PHYS_MODIFIED)) {
3e170ce0
A
1702 /*
1703 * Page is actually "modified" and
1704 * will be compressed. Start
1705 * accounting for it as "compressed".
1706 */
39037602 1707 assert(!(options & PMAP_OPTIONS_COMPRESSOR));
3e170ce0
A
1708 options &= ~PMAP_OPTIONS_COMPRESSOR_IFF_MODIFIED;
1709 options |= PMAP_OPTIONS_COMPRESSOR;
39037602 1710 assert(new_pte_value == 0);
d190cdc3
A
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;
1715 }
39037602 1716 }
3e170ce0 1717 }
39236c6e
A
1718 pmap_store_pte(pte, new_pte_value);
1719 }
3e170ce0 1720
b7266188
A
1721#if TESTING
1722 if (pmap->stats.resident_count < 1)
1723 panic("pmap_page_protect: resident_count");
1724#endif
316670eb 1725 pmap_ledger_debit(pmap, task_ledgers.phys_mem, PAGE_SIZE);
b7266188
A
1726 assert(pmap->stats.resident_count >= 1);
1727 OSAddAtomic(-1, &pmap->stats.resident_count);
39037602
A
1728
1729 /*
1730 * We only ever compress internal pages.
1731 */
39236c6e 1732 if (options & PMAP_OPTIONS_COMPRESSOR) {
39037602 1733 assert(IS_INTERNAL_PAGE(pai));
39236c6e 1734 }
39236c6e 1735 if (pmap != kernel_pmap) {
d190cdc3 1736 /* update pmap stats */
39236c6e
A
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);
1743 } else {
1744 assert(pmap->stats.external > 0);
1745 OSAddAtomic(-1, &pmap->stats.external);
1746 }
39037602
A
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++;
1753 }
d190cdc3
A
1754
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);
1763 }
1764 } else if (IS_REUSABLE_PAGE(pai)) {
1765 assert(!IS_ALTACCT_PAGE(pai, pv_e));
1766 assert(IS_INTERNAL_PAGE(pai));
39037602
A
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);
1771 }
1772 } else if (IS_INTERNAL_PAGE(pai)) {
d190cdc3
A
1773 assert(!IS_ALTACCT_PAGE(pai, pv_e));
1774 assert(!IS_REUSABLE_PAGE(pai));
39037602
A
1775 pmap_ledger_debit(pmap, task_ledgers.internal, PAGE_SIZE);
1776 /*
1777 * Update all stats related to physical
1778 * footprint, which only deals with
1779 * internal pages.
1780 */
1781 if (options & PMAP_OPTIONS_COMPRESSOR) {
1782 /*
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
1787 * footprint.
1788 */
39037602
A
1789 pmap_ledger_credit(pmap, task_ledgers.internal_compressed, PAGE_SIZE);
1790 } else {
1791 /*
1792 * This internal page isn't
1793 * going to the compressor,
1794 * so adjust stats to keep
1795 * phys_footprint up to date.
1796 */
d190cdc3 1797 pmap_ledger_debit(pmap, task_ledgers.phys_footprint, PAGE_SIZE);
39037602
A
1798 }
1799 }
39236c6e
A
1800 }
1801
b7266188
A
1802 /*
1803 * Deal with the pv_rooted_entry.
1804 */
1805
1806 if (pv_e == pv_h) {
1807 /*
1808 * Fix up head later.
1809 */
1810 pv_h->pmap = PMAP_NULL;
1811 } else {
1812 /*
1813 * Delete this entry.
1814 */
1815 pv_hash_remove(pvh_e);
1816 pvh_e->qlink.next = (queue_entry_t) pvh_eh;
1817 pvh_eh = pvh_e;
1818
1819 if (pvh_et == PV_HASHED_ENTRY_NULL)
1820 pvh_et = pvh_e;
1821 pvh_cnt++;
1822 }
1823 } else {
1824 /*
6d2010ae 1825 * Write-protect, after opportunistic refmod collect
b7266188 1826 */
3e170ce0
A
1827 if (!is_ept) {
1828 pmap_phys_attributes[pai] |=
1829 *pte & (PHYS_MODIFIED|PHYS_REFERENCED);
1830 } else {
1831 pmap_phys_attributes[pai] |=
1832 ept_refmod_to_physmap((*pte & (INTEL_EPT_REF | INTEL_EPT_MOD))) & (PHYS_MODIFIED | PHYS_REFERENCED);
1833 }
1834 pmap_update_pte(pte, PTE_WRITE(is_ept), 0);
39236c6e
A
1835
1836 if (options & PMAP_OPTIONS_NOFLUSH)
1837 PMAP_UPDATE_TLBS_DELAYED(pmap, vaddr, vaddr + PAGE_SIZE, (pmap_flush_context *)arg);
1838 else
1839 PMAP_UPDATE_TLBS(pmap, vaddr, vaddr+PAGE_SIZE);
b7266188
A
1840 }
1841 pvh_e = nexth;
1842 } while ((pv_e = (pv_rooted_entry_t) nexth) != pv_h);
1843
1844
1845 /*
1846 * If pv_head mapping was removed, fix it up.
1847 */
1848 if (pv_h->pmap == PMAP_NULL) {
1849 pvh_e = (pv_hashed_entry_t) queue_next(&pv_h->qlink);
1850
1851 if (pvh_e != (pv_hashed_entry_t) pv_h) {
1852 pv_hash_remove(pvh_e);
1853 pv_h->pmap = pvh_e->pmap;
d190cdc3 1854 pv_h->va_and_flags = pvh_e->va_and_flags;
b7266188
A
1855 pvh_e->qlink.next = (queue_entry_t) pvh_eh;
1856 pvh_eh = pvh_e;
1857
1858 if (pvh_et == PV_HASHED_ENTRY_NULL)
1859 pvh_et = pvh_e;
1860 pvh_cnt++;
1861 }
1862 }
1863 if (pvh_eh != PV_HASHED_ENTRY_NULL) {
1864 PV_HASHED_FREE_LIST(pvh_eh, pvh_et, pvh_cnt);
1865 }
1866done:
1867 UNLOCK_PVH(pai);
1868
5ba3f43e 1869 PMAP_TRACE(PMAP_CODE(PMAP__PAGE_PROTECT) | DBG_FUNC_END);
b7266188
A
1870}
1871
39236c6e 1872
6d2010ae
A
1873/*
1874 * Clear specified attribute bits.
1875 */
b7266188 1876void
6d2010ae
A
1877phys_attribute_clear(
1878 ppnum_t pn,
39236c6e
A
1879 int bits,
1880 unsigned int options,
1881 void *arg)
b7266188 1882{
6d2010ae
A
1883 pv_rooted_entry_t pv_h;
1884 pv_hashed_entry_t pv_e;
5ba3f43e 1885 pt_entry_t *pte = NULL;
6d2010ae
A
1886 int pai;
1887 pmap_t pmap;
1888 char attributes = 0;
d190cdc3 1889 boolean_t is_internal, is_reusable, is_altacct, is_ept;
3e170ce0
A
1890 int ept_bits_to_clear;
1891 boolean_t ept_keep_global_mod = FALSE;
fe8ab488
A
1892
1893 if ((bits & PHYS_MODIFIED) &&
1894 (options & PMAP_OPTIONS_NOFLUSH) &&
1895 arg == NULL) {
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);
1899 }
1900
3e170ce0
A
1901 /* We only support converting MOD and REF bits for EPT PTEs in this function */
1902 assert((bits & ~(PHYS_REFERENCED | PHYS_MODIFIED)) == 0);
1903
1904 ept_bits_to_clear = (unsigned)physmap_refmod_to_ept(bits & (PHYS_MODIFIED | PHYS_REFERENCED));
1905
6d2010ae
A
1906 pmap_intr_assert();
1907 assert(pn != vm_page_fictitious_addr);
1908 if (pn == vm_page_guard_addr)
1909 return;
b7266188 1910
6d2010ae 1911 pai = ppn_to_pai(pn);
b7266188 1912
6d2010ae
A
1913 if (!IS_MANAGED_PAGE(pai)) {
1914 /*
1915 * Not a managed page.
1916 */
1917 return;
b7266188 1918 }
b7266188 1919
5ba3f43e 1920 PMAP_TRACE(PMAP_CODE(PMAP__ATTRIBUTE_CLEAR) | DBG_FUNC_START, pn, bits);
b7266188 1921
6d2010ae 1922 pv_h = pai_to_pvh(pai);
b7266188 1923
6d2010ae 1924 LOCK_PVH(pai);
b7266188 1925
3e170ce0 1926
6d2010ae
A
1927 /*
1928 * Walk down PV list, clearing all modify or reference bits.
1929 * We do not have to lock the pv_list because we have
316670eb 1930 * the per-pmap lock
6d2010ae
A
1931 */
1932 if (pv_h->pmap != PMAP_NULL) {
1933 /*
1934 * There are some mappings.
1935 */
b7266188 1936
fe8ab488
A
1937 is_internal = IS_INTERNAL_PAGE(pai);
1938 is_reusable = IS_REUSABLE_PAGE(pai);
1939
6d2010ae 1940 pv_e = (pv_hashed_entry_t)pv_h;
b7266188 1941
6d2010ae
A
1942 do {
1943 vm_map_offset_t va;
fe8ab488 1944 char pte_bits;
b7266188 1945
6d2010ae 1946 pmap = pv_e->pmap;
3e170ce0 1947 is_ept = is_ept_pmap(pmap);
d190cdc3 1948 is_altacct = IS_ALTACCT_PAGE(pai, pv_e);
39037602 1949 va = PVE_VA(pv_e);
fe8ab488
A
1950 pte_bits = 0;
1951
1952 if (bits) {
1953 pte = pmap_pte(pmap, va);
1954 /* grab ref/mod bits from this PTE */
3e170ce0 1955 pte_bits = (*pte & (PTE_REF(is_ept) | PTE_MOD(is_ept)));
fe8ab488 1956 /* propagate to page's global attributes */
3e170ce0
A
1957 if (!is_ept) {
1958 attributes |= pte_bits;
1959 } else {
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;
1963 }
1964 }
fe8ab488 1965 /* which bits to clear for this PTE? */
3e170ce0
A
1966 if (!is_ept) {
1967 pte_bits &= bits;
1968 } else {
1969 pte_bits &= ept_bits_to_clear;
1970 }
fe8ab488 1971 }
b7266188 1972
6d2010ae
A
1973 /*
1974 * Clear modify and/or reference bits.
1975 */
fe8ab488
A
1976 if (pte_bits) {
1977 pmap_update_pte(pte, bits, 0);
1978
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.
1984 */
1985 if (! (options & PMAP_OPTIONS_NOFLUSH)) {
1986 /* flush TLBS now */
1987 PMAP_UPDATE_TLBS(pmap,
1988 va,
1989 va + PAGE_SIZE);
1990 } else if (arg) {
1991 /* delayed TLB flush: add "pmap" info */
1992 PMAP_UPDATE_TLBS_DELAYED(
1993 pmap,
1994 va,
1995 va + PAGE_SIZE,
1996 (pmap_flush_context *)arg);
1997 } else {
1998 /* no TLB flushing at all */
1999 }
2000 }
2001
2002 /* update pmap "reusable" stats */
2003 if ((options & PMAP_OPTIONS_CLEAR_REUSABLE) &&
2004 is_reusable &&
2005 pmap != kernel_pmap) {
2006 /* one less "reusable" */
2007 assert(pmap->stats.reusable > 0);
2008 OSAddAtomic(-1, &pmap->stats.reusable);
2009 if (is_internal) {
2010 /* one more "internal" */
2011 OSAddAtomic(+1, &pmap->stats.internal);
2012 PMAP_STATS_PEAK(pmap->stats.internal);
39037602 2013 assert(pmap->stats.internal > 0);
d190cdc3
A
2014 if (is_altacct) {
2015 /* no impact on ledgers */
39037602 2016 } else {
d190cdc3
A
2017 pmap_ledger_credit(pmap,
2018 task_ledgers.internal,
2019 PAGE_SIZE);
39037602
A
2020 pmap_ledger_credit(
2021 pmap,
2022 task_ledgers.phys_footprint,
2023 PAGE_SIZE);
2024 }
fe8ab488
A
2025 } else {
2026 /* one more "external" */
2027 OSAddAtomic(+1, &pmap->stats.external);
2028 PMAP_STATS_PEAK(pmap->stats.external);
39037602 2029 assert(pmap->stats.external > 0);
fe8ab488
A
2030 }
2031 } else if ((options & PMAP_OPTIONS_SET_REUSABLE) &&
2032 !is_reusable &&
2033 pmap != kernel_pmap) {
2034 /* one more "reusable" */
2035 OSAddAtomic(+1, &pmap->stats.reusable);
2036 PMAP_STATS_PEAK(pmap->stats.reusable);
39037602 2037 assert(pmap->stats.reusable > 0);
fe8ab488
A
2038 if (is_internal) {
2039 /* one less "internal" */
2040 assert(pmap->stats.internal > 0);
2041 OSAddAtomic(-1, &pmap->stats.internal);
d190cdc3 2042 if (is_altacct) {
39037602
A
2043 /* no impact on footprint */
2044 } else {
d190cdc3
A
2045 pmap_ledger_debit(pmap,
2046 task_ledgers.internal,
2047 PAGE_SIZE);
39037602
A
2048 pmap_ledger_debit(
2049 pmap,
2050 task_ledgers.phys_footprint,
2051 PAGE_SIZE);
2052 }
fe8ab488
A
2053 } else {
2054 /* one less "external" */
2055 assert(pmap->stats.external > 0);
2056 OSAddAtomic(-1, &pmap->stats.external);
2057 }
2058 }
b7266188 2059
6d2010ae
A
2060 pv_e = (pv_hashed_entry_t)queue_next(&pv_e->qlink);
2061
2062 } while (pv_e != (pv_hashed_entry_t)pv_h);
b7266188 2063 }
6d2010ae
A
2064 /* Opportunistic refmod collection, annulled
2065 * if both REF and MOD are being cleared.
2066 */
b7266188 2067
6d2010ae 2068 pmap_phys_attributes[pai] |= attributes;
3e170ce0
A
2069
2070 if (ept_keep_global_mod) {
2071 /*
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.
2076 */
2077 bits &= ~PHYS_MODIFIED;
2078 }
2079 pmap_phys_attributes[pai] &= ~(bits);
b7266188 2080
fe8ab488
A
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;
2086 }
2087
6d2010ae 2088 UNLOCK_PVH(pai);
b7266188 2089
5ba3f43e 2090 PMAP_TRACE(PMAP_CODE(PMAP__ATTRIBUTE_CLEAR) | DBG_FUNC_END);
b7266188
A
2091}
2092
6d2010ae
A
2093/*
2094 * Check specified attribute bits.
2095 */
2096int
2097phys_attribute_test(
2098 ppnum_t pn,
2099 int bits)
0b4c1975 2100{
6d2010ae
A
2101 pv_rooted_entry_t pv_h;
2102 pv_hashed_entry_t pv_e;
2103 pt_entry_t *pte;
2104 int pai;
2105 pmap_t pmap;
2106 int attributes = 0;
3e170ce0 2107 boolean_t is_ept;
6d2010ae
A
2108
2109 pmap_intr_assert();
2110 assert(pn != vm_page_fictitious_addr);
3e170ce0 2111 assert((bits & ~(PHYS_MODIFIED | PHYS_REFERENCED)) == 0);
6d2010ae
A
2112 if (pn == vm_page_guard_addr)
2113 return 0;
0b4c1975
A
2114
2115 pai = ppn_to_pai(pn);
2116
6d2010ae
A
2117 if (!IS_MANAGED_PAGE(pai)) {
2118 /*
2119 * Not a managed page.
2120 */
2121 return 0;
2122 }
0b4c1975 2123
6d2010ae
A
2124 /*
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
2130 */
2131 if ((pmap_phys_attributes[pai] & bits) == bits)
2132 return bits;
0b4c1975 2133
6d2010ae 2134 pv_h = pai_to_pvh(pai);
0b4c1975 2135
6d2010ae 2136 LOCK_PVH(pai);
0b4c1975 2137
6d2010ae 2138 attributes = pmap_phys_attributes[pai] & bits;
0b4c1975 2139
0b4c1975 2140
6d2010ae
A
2141 /*
2142 * Walk down PV list, checking the mappings until we
2143 * reach the end or we've found the desired attributes.
2144 */
2145 if (attributes != bits &&
2146 pv_h->pmap != PMAP_NULL) {
2147 /*
2148 * There are some mappings.
2149 */
2150 pv_e = (pv_hashed_entry_t)pv_h;
2151 do {
2152 vm_map_offset_t va;
0b4c1975 2153
6d2010ae 2154 pmap = pv_e->pmap;
3e170ce0 2155 is_ept = is_ept_pmap(pmap);
39037602 2156 va = PVE_VA(pv_e);
6d2010ae
A
2157 /*
2158 * pick up modify and/or reference bits from mapping
2159 */
0b4c1975 2160
6d2010ae 2161 pte = pmap_pte(pmap, va);
3e170ce0
A
2162 if (!is_ept) {
2163 attributes |= (int)(*pte & bits);
2164 } else {
2165 attributes |= (int)(ept_refmod_to_physmap((*pte & (INTEL_EPT_REF | INTEL_EPT_MOD))) & (PHYS_MODIFIED | PHYS_REFERENCED));
2166
2167 }
6d2010ae
A
2168
2169 pv_e = (pv_hashed_entry_t)queue_next(&pv_e->qlink);
2170
2171 } while ((attributes != bits) &&
2172 (pv_e != (pv_hashed_entry_t)pv_h));
0b4c1975 2173 }
6d2010ae 2174 pmap_phys_attributes[pai] |= attributes;
0b4c1975 2175
6d2010ae
A
2176 UNLOCK_PVH(pai);
2177 return (attributes);
2178}
0b4c1975 2179
6d2010ae
A
2180/*
2181 * Routine: pmap_change_wiring
2182 * Function: Change the wiring attribute for a map/virtual-address
2183 * pair.
2184 * In/out conditions:
2185 * The mapping must already exist in the pmap.
2186 */
0b4c1975 2187void
6d2010ae
A
2188pmap_change_wiring(
2189 pmap_t map,
2190 vm_map_offset_t vaddr,
2191 boolean_t wired)
0b4c1975 2192{
6d2010ae 2193 pt_entry_t *pte;
0b4c1975 2194
6d2010ae 2195 PMAP_LOCK(map);
0b4c1975 2196
6d2010ae 2197 if ((pte = pmap_pte(map, vaddr)) == PT_ENTRY_NULL)
4bd07ac2
A
2198 panic("pmap_change_wiring(%p,0x%llx,%d): pte missing",
2199 map, vaddr, wired);
0b4c1975 2200
6d2010ae
A
2201 if (wired && !iswired(*pte)) {
2202 /*
2203 * wiring down mapping
2204 */
316670eb 2205 pmap_ledger_credit(map, task_ledgers.wired_mem, PAGE_SIZE);
6d2010ae 2206 OSAddAtomic(+1, &map->stats.wired_count);
3e170ce0 2207 pmap_update_pte(pte, 0, PTE_WIRED);
0b4c1975 2208 }
6d2010ae
A
2209 else if (!wired && iswired(*pte)) {
2210 /*
2211 * unwiring mapping
2212 */
2213 assert(map->stats.wired_count >= 1);
2214 OSAddAtomic(-1, &map->stats.wired_count);
316670eb 2215 pmap_ledger_debit(map, task_ledgers.wired_mem, PAGE_SIZE);
3e170ce0 2216 pmap_update_pte(pte, PTE_WIRED, 0);
060df5ea 2217 }
060df5ea 2218
6d2010ae
A
2219 PMAP_UNLOCK(map);
2220}
7ddcb079
A
2221
2222/*
2223 * "Backdoor" direct map routine for early mappings.
2224 * Useful for mapping memory outside the range
2225 * Sets A, D and NC if requested
2226 */
2227
2228vm_offset_t
2229pmap_map_bd(
2230 vm_offset_t virt,
2231 vm_map_offset_t start_addr,
2232 vm_map_offset_t end_addr,
2233 vm_prot_t prot,
2234 unsigned int flags)
2235{
2236 pt_entry_t template;
5c9f4661
A
2237 pt_entry_t *ptep;
2238
7ddcb079 2239 vm_offset_t base = virt;
5c9f4661
A
2240 boolean_t doflush = FALSE;
2241
7ddcb079
A
2242 template = pa_to_pte(start_addr)
2243 | INTEL_PTE_REF
2244 | INTEL_PTE_MOD
2245 | INTEL_PTE_WIRED
2246 | INTEL_PTE_VALID;
2247
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;
2252 }
316670eb 2253
316670eb
A
2254 if ((prot & VM_PROT_EXECUTE) == 0)
2255 template |= INTEL_PTE_NX;
316670eb 2256
7ddcb079
A
2257 if (prot & VM_PROT_WRITE)
2258 template |= INTEL_PTE_WRITE;
2259
2260 while (start_addr < end_addr) {
5c9f4661
A
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");
2264 }
2265 if (pte_to_pa(*ptep)) {
2266 doflush = TRUE;
7ddcb079 2267 }
5c9f4661 2268 pmap_store_pte(ptep, template);
7ddcb079
A
2269 pte_increment_pa(template);
2270 virt += PAGE_SIZE;
2271 start_addr += PAGE_SIZE;
2272 }
5c9f4661
A
2273 if (doflush) {
2274 flush_tlb_raw();
2275 PMAP_UPDATE_TLBS(kernel_pmap, base, base + end_addr - start_addr);
2276 }
7ddcb079
A
2277 return(virt);
2278}
39236c6e 2279
5c9f4661
A
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.
2285 */
2286
2287void
2288pmap_alias(
2289 vm_offset_t ava,
2290 vm_map_offset_t start_addr,
2291 vm_map_offset_t end_addr,
2292 vm_prot_t prot,
2293 unsigned int eoptions)
2294{
2295 pt_entry_t prot_template, template;
2296 pt_entry_t *aptep, *sptep;
2297
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;
2301
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);
2311 } else {
2312 panic("pmap_alias: Invalid alias address");
2313 }
2314 }
2315 /* The aliased range should not have any active mappings */
2316 assert(pte_to_pa(*aptep) == 0);
2317
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);
2322
2323 ava += PAGE_SIZE;
2324 start_addr += PAGE_SIZE;
2325 }
2326}
2327
4bd07ac2 2328mach_vm_size_t
39236c6e
A
2329pmap_query_resident(
2330 pmap_t pmap,
2331 addr64_t s64,
3e170ce0 2332 addr64_t e64,
4bd07ac2 2333 mach_vm_size_t *compressed_bytes_p)
39236c6e
A
2334{
2335 pt_entry_t *pde;
2336 pt_entry_t *spte, *epte;
2337 addr64_t l64;
2338 uint64_t deadline;
4bd07ac2
A
2339 mach_vm_size_t resident_bytes;
2340 mach_vm_size_t compressed_bytes;
3e170ce0 2341 boolean_t is_ept;
39236c6e
A
2342
2343 pmap_intr_assert();
2344
3e170ce0 2345 if (pmap == PMAP_NULL || pmap == kernel_pmap || s64 == e64) {
4bd07ac2
A
2346 if (compressed_bytes_p) {
2347 *compressed_bytes_p = 0;
3e170ce0 2348 }
39236c6e 2349 return 0;
3e170ce0
A
2350 }
2351
2352 is_ept = is_ept_pmap(pmap);
39236c6e
A
2353
2354 PMAP_TRACE(PMAP_CODE(PMAP__QUERY_RESIDENT) | DBG_FUNC_START,
5ba3f43e
A
2355 VM_KERNEL_ADDRHIDE(pmap), VM_KERNEL_ADDRHIDE(s64),
2356 VM_KERNEL_ADDRHIDE(e64));
39236c6e 2357
4bd07ac2
A
2358 resident_bytes = 0;
2359 compressed_bytes = 0;
39236c6e
A
2360
2361 PMAP_LOCK(pmap);
2362
2363 deadline = rdtsc64() + max_preemption_latency_tsc;
2364
2365 while (s64 < e64) {
2366 l64 = (s64 + pde_mapped_size) & ~(pde_mapped_size - 1);
2367 if (l64 > e64)
2368 l64 = e64;
2369 pde = pmap_pde(pmap, s64);
2370
3e170ce0
A
2371 if (pde && (*pde & PTE_VALID_MASK(is_ept))) {
2372 if (*pde & PTE_PS) {
39236c6e
A
2373 /* superpage: not supported */
2374 } else {
2375 spte = pmap_pte(pmap,
2376 (s64 & ~(pde_mapped_size - 1)));
2377 spte = &spte[ptenum(s64)];
2378 epte = &spte[intel_btop(l64 - s64)];
2379
2380 for (; spte < epte; spte++) {
2381 if (pte_to_pa(*spte) != 0) {
4bd07ac2 2382 resident_bytes += PAGE_SIZE;
3e170ce0 2383 } else if (*spte & PTE_COMPRESSED) {
4bd07ac2 2384 compressed_bytes += PAGE_SIZE;
39236c6e
A
2385 }
2386 }
2387
2388 }
2389 }
2390 s64 = l64;
2391
2392 if (s64 < e64 && rdtsc64() >= deadline) {
2393 PMAP_UNLOCK(pmap);
2394 PMAP_LOCK(pmap);
2395 deadline = rdtsc64() + max_preemption_latency_tsc;
2396 }
2397 }
2398
2399 PMAP_UNLOCK(pmap);
2400
2401 PMAP_TRACE(PMAP_CODE(PMAP__QUERY_RESIDENT) | DBG_FUNC_END,
5ba3f43e 2402 resident_bytes);
39236c6e 2403
4bd07ac2
A
2404 if (compressed_bytes_p) {
2405 *compressed_bytes_p = compressed_bytes;
3e170ce0 2406 }
4bd07ac2 2407 return resident_bytes;
39236c6e 2408}
fe8ab488 2409
39037602
A
2410kern_return_t
2411pmap_query_page_info(
2412 pmap_t pmap,
2413 vm_map_offset_t va,
2414 int *disp_p)
2415{
2416 int disp;
2417 boolean_t is_ept;
2418 pmap_paddr_t pa;
2419 ppnum_t pai;
2420 pd_entry_t *pde;
2421 pt_entry_t *pte;
2422
2423 pmap_intr_assert();
2424 if (pmap == PMAP_NULL || pmap == kernel_pmap) {
2425 *disp_p = 0;
2426 return KERN_INVALID_ARGUMENT;
2427 }
2428
2429 disp = 0;
2430 is_ept = is_ept_pmap(pmap);
2431
2432 PMAP_LOCK(pmap);
2433
2434 pde = pmap_pde(pmap, va);
2435 if (!pde ||
2436 !(*pde & PTE_VALID_MASK(is_ept)) ||
2437 (*pde & PTE_PS)) {
2438 goto done;
2439 }
2440
2441 pte = pmap_pte(pmap, va);
2442 if (pte == PT_ENTRY_NULL) {
2443 goto done;
2444 }
2445
2446 pa = pte_to_pa(*pte);
2447 if (pa == 0) {
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;
2452 }
2453 }
2454 } else {
2455 disp |= PMAP_QUERY_PAGE_PRESENT;
2456 pai = pa_index(pa);
2457 if (!IS_MANAGED_PAGE(pai)) {
d190cdc3
A
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;
39037602
A
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;
39037602
A
2466 }
2467 }
2468
2469done:
2470 PMAP_UNLOCK(pmap);
2471 *disp_p = disp;
2472 return KERN_SUCCESS;
2473}
2474
5ba3f43e 2475void pmap_set_jit_entitled(__unused pmap_t pmap)
39037602 2476{
5ba3f43e
A
2477 /* The x86 pmap layer does not care if a map has a JIT entry. */
2478 return;
39037602
A
2479}
2480
5ba3f43e 2481bool pmap_has_prot_policy(__unused vm_prot_t prot)
fe8ab488 2482{
5ba3f43e
A
2483 /*
2484 * The x86 pmap layer does not apply any policy to any protection
2485 * types.
2486 */
2487 return FALSE;
2488}
2489
2490void pmap_release_pages_fast(void)
2491{
2492 return;
fe8ab488 2493}
5ba3f43e 2494