mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-04 23:50:27 +00:00
Prevent corruption of the VHPT collision chain by protecting it with
a mutex. The only volatile chain operations are insertion and deletion but since updating an existing PTE also updates the VHPT entry itself, and we have the VHPT mutex in both other cases, we also lock when we update an existing PTE even though no chain operation is involved. Note that we perform the insertion and deletion careful enough that we don't need to lock traversals. If we need to lock traversals, we also need to lock from the exception handler, which we can't without creating a trapframe. We're now able to withstand a -j8 buildworld. More work is needed to withstand Murphy fields. In other words: we still have a bogon... Approved by: re@ (blanket)
This commit is contained in:
parent
721b850f30
commit
9b9ce577d4
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=115176
|
@ -198,6 +198,7 @@ vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */
|
|||
static boolean_t pmap_initialized = FALSE; /* Has pmap_init completed? */
|
||||
|
||||
vm_offset_t vhpt_base, vhpt_size;
|
||||
struct mtx pmap_vhptmutex;
|
||||
|
||||
/*
|
||||
* We use an object to own the kernel's 'page tables'. For simplicity,
|
||||
|
@ -452,6 +453,9 @@ pmap_bootstrap()
|
|||
|
||||
vhpt_base = IA64_PHYS_TO_RR7(vhpt_base);
|
||||
bzero((void *) vhpt_base, (1L << vhpt_size));
|
||||
|
||||
mtx_init(&pmap_vhptmutex, "VHPT collision chain lock", NULL, MTX_DEF);
|
||||
|
||||
__asm __volatile("mov cr.pta=%0;; srlz.i;;"
|
||||
:: "r" (vhpt_base + (1<<8) + (vhpt_size<<2) + 1));
|
||||
|
||||
|
@ -982,13 +986,17 @@ pmap_enter_vhpt(struct ia64_lpte *pte, vm_offset_t va)
|
|||
if (vhpte->pte_chain)
|
||||
pmap_vhpt_collisions++;
|
||||
|
||||
mtx_lock(&pmap_vhptmutex);
|
||||
|
||||
pte->pte_chain = vhpte->pte_chain;
|
||||
vhpte->pte_chain = ia64_tpa((vm_offset_t) pte);
|
||||
ia64_mf();
|
||||
vhpte->pte_chain = ia64_tpa((vm_offset_t)pte);
|
||||
ia64_mf();
|
||||
|
||||
if (!vhpte->pte_p && pte->pte_p)
|
||||
pmap_install_pte(vhpte, pte);
|
||||
else
|
||||
ia64_mf();
|
||||
|
||||
mtx_unlock(&pmap_vhptmutex);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -999,11 +1007,14 @@ pmap_update_vhpt(struct ia64_lpte *pte, vm_offset_t va)
|
|||
{
|
||||
struct ia64_lpte *vhpte;
|
||||
|
||||
vhpte = (struct ia64_lpte *) ia64_thash(va);
|
||||
vhpte = (struct ia64_lpte *)ia64_thash(va);
|
||||
|
||||
if ((!vhpte->pte_p || vhpte->pte_tag == pte->pte_tag)
|
||||
&& pte->pte_p)
|
||||
mtx_lock(&pmap_vhptmutex);
|
||||
|
||||
if ((!vhpte->pte_p || vhpte->pte_tag == pte->pte_tag) && pte->pte_p)
|
||||
pmap_install_pte(vhpte, pte);
|
||||
|
||||
mtx_unlock(&pmap_vhptmutex);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1017,37 +1028,37 @@ pmap_remove_vhpt(vm_offset_t va)
|
|||
struct ia64_lpte *lpte;
|
||||
struct ia64_lpte *vhpte;
|
||||
u_int64_t tag;
|
||||
int error = ENOENT;
|
||||
|
||||
vhpte = (struct ia64_lpte *) ia64_thash(va);
|
||||
vhpte = (struct ia64_lpte *)ia64_thash(va);
|
||||
|
||||
/*
|
||||
* If the VHPTE is invalid, there can't be a collision chain.
|
||||
*/
|
||||
if (!vhpte->pte_p) {
|
||||
KASSERT(!vhpte->pte_chain, ("bad vhpte"));
|
||||
printf("can't remove vhpt entry for 0x%lx\n", va);
|
||||
goto done;
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
lpte = vhpte;
|
||||
pte = (struct ia64_lpte *) IA64_PHYS_TO_RR7(vhpte->pte_chain);
|
||||
tag = ia64_ttag(va);
|
||||
|
||||
mtx_lock(&pmap_vhptmutex);
|
||||
|
||||
pte = (struct ia64_lpte *)IA64_PHYS_TO_RR7(vhpte->pte_chain);
|
||||
KASSERT(pte != NULL, ("foo"));
|
||||
|
||||
while (pte->pte_tag != tag) {
|
||||
lpte = pte;
|
||||
if (pte->pte_chain)
|
||||
pte = (struct ia64_lpte *) IA64_PHYS_TO_RR7(pte->pte_chain);
|
||||
else {
|
||||
printf("can't remove vhpt entry for 0x%lx\n", va);
|
||||
goto done;
|
||||
if (pte->pte_chain == 0) {
|
||||
mtx_unlock(&pmap_vhptmutex);
|
||||
return (ENOENT);
|
||||
}
|
||||
pte = (struct ia64_lpte *)IA64_PHYS_TO_RR7(pte->pte_chain);
|
||||
}
|
||||
|
||||
/*
|
||||
* Snip this pv_entry out of the collision chain.
|
||||
*/
|
||||
/* Snip this pv_entry out of the collision chain. */
|
||||
lpte->pte_chain = pte->pte_chain;
|
||||
ia64_mf();
|
||||
|
||||
/*
|
||||
* If the VHPTE matches as well, change it to map the first
|
||||
|
@ -1055,19 +1066,15 @@ pmap_remove_vhpt(vm_offset_t va)
|
|||
*/
|
||||
if (vhpte->pte_tag == tag) {
|
||||
if (vhpte->pte_chain) {
|
||||
pte = (struct ia64_lpte *)
|
||||
IA64_PHYS_TO_RR7(vhpte->pte_chain);
|
||||
pte = (void*)IA64_PHYS_TO_RR7(vhpte->pte_chain);
|
||||
pmap_install_pte(vhpte, pte);
|
||||
} else {
|
||||
} else
|
||||
vhpte->pte_p = 0;
|
||||
ia64_mf();
|
||||
}
|
||||
}
|
||||
|
||||
mtx_unlock(&pmap_vhptmutex);
|
||||
pmap_vhpt_resident--;
|
||||
error = 0;
|
||||
done:
|
||||
return error;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1079,28 +1086,19 @@ pmap_find_vhpt(vm_offset_t va)
|
|||
struct ia64_lpte *pte;
|
||||
u_int64_t tag;
|
||||
|
||||
pte = (struct ia64_lpte *) ia64_thash(va);
|
||||
if (!pte->pte_chain) {
|
||||
pte = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
tag = ia64_ttag(va);
|
||||
pte = (struct ia64_lpte *) IA64_PHYS_TO_RR7(pte->pte_chain);
|
||||
|
||||
pte = (struct ia64_lpte *)ia64_thash(va);
|
||||
if (pte->pte_chain == 0)
|
||||
return (NULL);
|
||||
pte = (struct ia64_lpte *)IA64_PHYS_TO_RR7(pte->pte_chain);
|
||||
while (pte->pte_tag != tag) {
|
||||
if (pte->pte_chain) {
|
||||
pte = (struct ia64_lpte *) IA64_PHYS_TO_RR7(pte->pte_chain);
|
||||
} else {
|
||||
pte = 0;
|
||||
break;
|
||||
}
|
||||
if (pte->pte_chain == 0)
|
||||
return (NULL);
|
||||
pte = (struct ia64_lpte *)IA64_PHYS_TO_RR7(pte->pte_chain);
|
||||
}
|
||||
|
||||
done:
|
||||
return pte;
|
||||
return (pte);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Remove an entry from the list of managed mappings.
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue