arm64: Handle changing self-referential DMAP pages
Support changing the property of a DMAP page that holds it's own page table entry. Because we need to perform a break-before-make sequence to change the properties of pages a page that also holds it's own page table entry will fault in the make part of the sequence. Handle this by mapping the page with a temporary mapping as we already do when demoting a superpage. Reviewed by: kib Sponsored by: Arm Ltd Differential Revision: https://reviews.freebsd.org/D55943
This commit is contained in:
@@ -8248,6 +8248,7 @@ pmap_change_props_locked(vm_offset_t va, vm_size_t size, vm_prot_t prot,
|
|||||||
vm_paddr_t pa;
|
vm_paddr_t pa;
|
||||||
pt_entry_t pte, *ptep, *newpte;
|
pt_entry_t pte, *ptep, *newpte;
|
||||||
pt_entry_t bits, mask;
|
pt_entry_t bits, mask;
|
||||||
|
char *tmpptep;
|
||||||
int lvl, rv;
|
int lvl, rv;
|
||||||
|
|
||||||
PMAP_LOCK_ASSERT(kernel_pmap, MA_OWNED);
|
PMAP_LOCK_ASSERT(kernel_pmap, MA_OWNED);
|
||||||
@@ -8377,6 +8378,24 @@ pmap_change_props_locked(vm_offset_t va, vm_size_t size, vm_prot_t prot,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tmpptep = 0;
|
||||||
|
if (tmpva <= (vm_offset_t)ptep &&
|
||||||
|
tmpva + pte_size > (vm_offset_t)ptep) {
|
||||||
|
vm_paddr_t pte_pa;
|
||||||
|
|
||||||
|
mtx_lock(&cmap_lock);
|
||||||
|
tmpptep = cmap1_addr;
|
||||||
|
pte_pa = DMAP_TO_PHYS((vm_offset_t)ptep);
|
||||||
|
pmap_store(cmap1_pte, ATTR_AF |
|
||||||
|
pmap_sh_attr | ATTR_S1_AP(ATTR_S1_AP_RW) |
|
||||||
|
ATTR_S1_XN | ATTR_KERN_GP |
|
||||||
|
ATTR_S1_IDX(VM_MEMATTR_WRITE_BACK) |
|
||||||
|
PHYS_TO_PTE(pte_pa &~L3_OFFSET) | L3_PAGE);
|
||||||
|
dsb(ishst);
|
||||||
|
ptep = (pt_entry_t *)(tmpptep +
|
||||||
|
((vm_offset_t)ptep & PAGE_MASK));
|
||||||
|
}
|
||||||
|
|
||||||
/* Update the entry */
|
/* Update the entry */
|
||||||
pte = pmap_load(ptep);
|
pte = pmap_load(ptep);
|
||||||
pte &= ~mask;
|
pte &= ~mask;
|
||||||
@@ -8403,6 +8422,13 @@ pmap_change_props_locked(vm_offset_t va, vm_size_t size, vm_prot_t prot,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tmpptep != 0) {
|
||||||
|
pmap_clear(cmap1_pte);
|
||||||
|
pmap_s1_invalidate_page(kernel_pmap,
|
||||||
|
(vm_offset_t)tmpptep, true);
|
||||||
|
mtx_unlock(&cmap_lock);
|
||||||
|
}
|
||||||
|
|
||||||
pa = PTE_TO_PHYS(pte);
|
pa = PTE_TO_PHYS(pte);
|
||||||
if (!VIRT_IN_DMAP(tmpva) && PHYS_IN_DMAP(pa)) {
|
if (!VIRT_IN_DMAP(tmpva) && PHYS_IN_DMAP(pa)) {
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user