diff options
Diffstat (limited to 'sys/powerpc/aim/copyinout.c')
-rw-r--r-- | sys/powerpc/aim/copyinout.c | 35 |
1 files changed, 22 insertions, 13 deletions
diff --git a/sys/powerpc/aim/copyinout.c b/sys/powerpc/aim/copyinout.c index ab2d1f32..15623ed 100644 --- a/sys/powerpc/aim/copyinout.c +++ b/sys/powerpc/aim/copyinout.c @@ -81,9 +81,7 @@ static __inline void set_user_sr(pmap_t pm, const void *addr) { struct slb *slb; - register_t esid, vsid, slb1, slb2; - - esid = USER_ADDR >> ADDR_SR_SHFT; + register_t slbv; /* Try lockless look-up first */ slb = user_va_to_slb_entry(pm, (vm_offset_t)addr); @@ -91,20 +89,24 @@ set_user_sr(pmap_t pm, const void *addr) if (slb == NULL) { /* If it isn't there, we need to pre-fault the VSID */ PMAP_LOCK(pm); - vsid = va_to_vsid(pm, (vm_offset_t)addr); + slbv = va_to_vsid(pm, (vm_offset_t)addr) << SLBV_VSID_SHIFT; PMAP_UNLOCK(pm); } else { - vsid = slb->slbv >> SLBV_VSID_SHIFT; + slbv = slb->slbv; } - slb1 = vsid << SLBV_VSID_SHIFT; - slb2 = (esid << SLBE_ESID_SHIFT) | SLBE_VALID | USER_SR; + /* Mark segment no-execute */ + slbv |= SLBV_N; + + /* If we have already set this VSID, we can just return */ + if (curthread->td_pcb->pcb_cpu.aim.usr_vsid == slbv) + return; + __asm __volatile ("isync; slbie %0; slbmte %1, %2; isync" :: + "r"(USER_ADDR), "r"(slbv), "r"(USER_SLB_SLBE)); curthread->td_pcb->pcb_cpu.aim.usr_segm = (uintptr_t)addr >> ADDR_SR_SHFT; - __asm __volatile ("slbie %0; slbmte %1, %2" :: "r"(esid << 28), - "r"(slb1), "r"(slb2)); - isync(); + curthread->td_pcb->pcb_cpu.aim.usr_vsid = slbv; } #else static __inline void @@ -114,9 +116,16 @@ set_user_sr(pmap_t pm, const void *addr) vsid = va_to_vsid(pm, (vm_offset_t)addr); - isync(); - __asm __volatile ("mtsr %0,%1" :: "n"(USER_SR), "r"(vsid)); - isync(); + /* If we have already set this VSID, we can just return */ + if (curthread->td_pcb->pcb_cpu.aim.usr_vsid == vsid) + return; + + /* Mark segment no-execute */ + vsid |= SR_N; + + __asm __volatile("isync"); + curthread->td_pcb->pcb_cpu.aim.usr_vsid = vsid; + __asm __volatile("mtsr %0,%1; isync" :: "n"(USER_SR), "r"(vsid)); } #endif |