Changeset View
Changeset View
Standalone View
Standalone View
head/sys/riscv/riscv/pmap.c
Show First 20 Lines • Show All 4,068 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Clear the modify bits on the specified physical page. | * Clear the modify bits on the specified physical page. | ||||
*/ | */ | ||||
void | void | ||||
pmap_clear_modify(vm_page_t m) | pmap_clear_modify(vm_page_t m) | ||||
{ | { | ||||
struct md_page *pvh; | |||||
struct rwlock *lock; | |||||
pmap_t pmap; | |||||
pv_entry_t next_pv, pv; | |||||
pd_entry_t *l2, oldl2; | |||||
pt_entry_t *l3, oldl3; | |||||
vm_offset_t va; | |||||
int md_gen, pvh_gen; | |||||
KASSERT((m->oflags & VPO_UNMANAGED) == 0, | KASSERT((m->oflags & VPO_UNMANAGED) == 0, | ||||
("pmap_clear_modify: page %p is not managed", m)); | ("pmap_clear_modify: page %p is not managed", m)); | ||||
VM_OBJECT_ASSERT_WLOCKED(m->object); | VM_OBJECT_ASSERT_WLOCKED(m->object); | ||||
KASSERT(!vm_page_xbusied(m), | KASSERT(!vm_page_xbusied(m), | ||||
("pmap_clear_modify: page %p is exclusive busied", m)); | ("pmap_clear_modify: page %p is exclusive busied", m)); | ||||
/* | /* | ||||
* If the page is not PGA_WRITEABLE, then no PTEs can have PG_M set. | * If the page is not PGA_WRITEABLE, then no PTEs can have PG_M set. | ||||
* If the object containing the page is locked and the page is not | * If the object containing the page is locked and the page is not | ||||
* exclusive busied, then PGA_WRITEABLE cannot be concurrently set. | * exclusive busied, then PGA_WRITEABLE cannot be concurrently set. | ||||
*/ | */ | ||||
if ((m->aflags & PGA_WRITEABLE) == 0) | if ((m->aflags & PGA_WRITEABLE) == 0) | ||||
return; | return; | ||||
pvh = (m->flags & PG_FICTITIOUS) != 0 ? &pv_dummy : | |||||
/* RISCVTODO: We lack support for tracking if a page is modified */ | pa_to_pvh(VM_PAGE_TO_PHYS(m)); | ||||
lock = VM_PAGE_TO_PV_LIST_LOCK(m); | |||||
rw_rlock(&pvh_global_lock); | |||||
rw_wlock(lock); | |||||
restart: | |||||
TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_next, next_pv) { | |||||
pmap = PV_PMAP(pv); | |||||
if (!PMAP_TRYLOCK(pmap)) { | |||||
pvh_gen = pvh->pv_gen; | |||||
rw_wunlock(lock); | |||||
PMAP_LOCK(pmap); | |||||
rw_wlock(lock); | |||||
if (pvh_gen != pvh->pv_gen) { | |||||
PMAP_UNLOCK(pmap); | |||||
goto restart; | |||||
} | |||||
} | |||||
va = pv->pv_va; | |||||
l2 = pmap_l2(pmap, va); | |||||
oldl2 = pmap_load(l2); | |||||
if ((oldl2 & PTE_W) != 0) { | |||||
if (pmap_demote_l2_locked(pmap, l2, va, &lock)) { | |||||
if ((oldl2 & PTE_SW_WIRED) == 0) { | |||||
/* | |||||
* Write protect the mapping to a | |||||
* single page so that a subsequent | |||||
* write access may repromote. | |||||
*/ | |||||
va += VM_PAGE_TO_PHYS(m) - | |||||
PTE_TO_PHYS(oldl2); | |||||
l3 = pmap_l2_to_l3(l2, va); | |||||
oldl3 = pmap_load(l3); | |||||
if ((oldl3 & PTE_V) != 0) { | |||||
while (!atomic_fcmpset_long(l3, | |||||
&oldl3, oldl3 & ~(PTE_D | | |||||
PTE_W))) | |||||
cpu_spinwait(); | |||||
vm_page_dirty(m); | |||||
pmap_invalidate_page(pmap, va); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
PMAP_UNLOCK(pmap); | |||||
} | |||||
TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) { | |||||
pmap = PV_PMAP(pv); | |||||
if (!PMAP_TRYLOCK(pmap)) { | |||||
md_gen = m->md.pv_gen; | |||||
pvh_gen = pvh->pv_gen; | |||||
rw_wunlock(lock); | |||||
PMAP_LOCK(pmap); | |||||
rw_wlock(lock); | |||||
if (pvh_gen != pvh->pv_gen || md_gen != m->md.pv_gen) { | |||||
PMAP_UNLOCK(pmap); | |||||
goto restart; | |||||
} | |||||
} | |||||
l2 = pmap_l2(pmap, pv->pv_va); | |||||
KASSERT((pmap_load(l2) & PTE_RWX) == 0, | |||||
("pmap_clear_modify: found a 2mpage in page %p's pv list", | |||||
m)); | |||||
l3 = pmap_l2_to_l3(l2, pv->pv_va); | |||||
if ((pmap_load(l3) & (PTE_D | PTE_W)) == (PTE_D | PTE_W)) { | |||||
pmap_clear_bits(l3, PTE_D); | |||||
pmap_invalidate_page(pmap, pv->pv_va); | |||||
} | |||||
PMAP_UNLOCK(pmap); | |||||
} | |||||
rw_wunlock(lock); | |||||
rw_runlock(&pvh_global_lock); | |||||
} | } | ||||
void * | void * | ||||
pmap_mapbios(vm_paddr_t pa, vm_size_t size) | pmap_mapbios(vm_paddr_t pa, vm_size_t size) | ||||
{ | { | ||||
return ((void *)PHYS_TO_DMAP(pa)); | return ((void *)PHYS_TO_DMAP(pa)); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 220 Lines • Show Last 20 Lines |