powerpc/64s/hash: Add some SLB debugging tests
This adds CONFIG_DEBUG_VM checks to ensure: - The kernel stack is in the SLB after it's flushed and bolted. - We don't insert an SLB for an address that is aleady in the SLB. - The kernel SLB miss handler does not take an SLB miss. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
parent
94ee42727c
commit
e15a4fea4d
@ -115,6 +115,9 @@ struct paca_struct {
|
|||||||
u16 vmalloc_sllp;
|
u16 vmalloc_sllp;
|
||||||
u8 slb_cache_ptr;
|
u8 slb_cache_ptr;
|
||||||
u8 stab_rr; /* stab/slb round-robin counter */
|
u8 stab_rr; /* stab/slb round-robin counter */
|
||||||
|
#ifdef CONFIG_DEBUG_VM
|
||||||
|
u8 in_kernel_slb_handler;
|
||||||
|
#endif
|
||||||
u32 slb_used_bitmap; /* Bitmaps for first 32 SLB entries. */
|
u32 slb_used_bitmap; /* Bitmaps for first 32 SLB entries. */
|
||||||
u32 slb_kern_bitmap;
|
u32 slb_kern_bitmap;
|
||||||
u32 slb_cache[SLB_CACHE_ENTRIES];
|
u32 slb_cache[SLB_CACHE_ENTRIES];
|
||||||
|
@ -58,6 +58,30 @@ static inline unsigned long mk_vsid_data(unsigned long ea, int ssize,
|
|||||||
return __mk_vsid_data(get_kernel_vsid(ea, ssize), ssize, flags);
|
return __mk_vsid_data(get_kernel_vsid(ea, ssize), ssize, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void assert_slb_exists(unsigned long ea)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_DEBUG_VM
|
||||||
|
unsigned long tmp;
|
||||||
|
|
||||||
|
WARN_ON_ONCE(mfmsr() & MSR_EE);
|
||||||
|
|
||||||
|
asm volatile("slbfee. %0, %1" : "=r"(tmp) : "r"(ea) : "cr0");
|
||||||
|
WARN_ON(tmp == 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assert_slb_notexists(unsigned long ea)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_DEBUG_VM
|
||||||
|
unsigned long tmp;
|
||||||
|
|
||||||
|
WARN_ON_ONCE(mfmsr() & MSR_EE);
|
||||||
|
|
||||||
|
asm volatile("slbfee. %0, %1" : "=r"(tmp) : "r"(ea) : "cr0");
|
||||||
|
WARN_ON(tmp != 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static inline void slb_shadow_update(unsigned long ea, int ssize,
|
static inline void slb_shadow_update(unsigned long ea, int ssize,
|
||||||
unsigned long flags,
|
unsigned long flags,
|
||||||
enum slb_index index)
|
enum slb_index index)
|
||||||
@ -90,6 +114,7 @@ static inline void create_shadowed_slbe(unsigned long ea, int ssize,
|
|||||||
*/
|
*/
|
||||||
slb_shadow_update(ea, ssize, flags, index);
|
slb_shadow_update(ea, ssize, flags, index);
|
||||||
|
|
||||||
|
assert_slb_notexists(ea);
|
||||||
asm volatile("slbmte %0,%1" :
|
asm volatile("slbmte %0,%1" :
|
||||||
: "r" (mk_vsid_data(ea, ssize, flags)),
|
: "r" (mk_vsid_data(ea, ssize, flags)),
|
||||||
"r" (mk_esid_data(ea, ssize, index))
|
"r" (mk_esid_data(ea, ssize, index))
|
||||||
@ -111,6 +136,8 @@ void __slb_restore_bolted_realmode(void)
|
|||||||
: "r" (be64_to_cpu(p->save_area[index].vsid)),
|
: "r" (be64_to_cpu(p->save_area[index].vsid)),
|
||||||
"r" (be64_to_cpu(p->save_area[index].esid)));
|
"r" (be64_to_cpu(p->save_area[index].esid)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert_slb_exists(local_paca->kstack);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -158,6 +185,7 @@ void slb_flush_and_restore_bolted(void)
|
|||||||
:: "r" (be64_to_cpu(p->save_area[KSTACK_INDEX].vsid)),
|
:: "r" (be64_to_cpu(p->save_area[KSTACK_INDEX].vsid)),
|
||||||
"r" (be64_to_cpu(p->save_area[KSTACK_INDEX].esid))
|
"r" (be64_to_cpu(p->save_area[KSTACK_INDEX].esid))
|
||||||
: "memory");
|
: "memory");
|
||||||
|
assert_slb_exists(get_paca()->kstack);
|
||||||
|
|
||||||
get_paca()->slb_cache_ptr = 0;
|
get_paca()->slb_cache_ptr = 0;
|
||||||
|
|
||||||
@ -410,9 +438,17 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
|
|||||||
unsigned long slbie_data = 0;
|
unsigned long slbie_data = 0;
|
||||||
|
|
||||||
for (i = 0; i < offset; i++) {
|
for (i = 0; i < offset; i++) {
|
||||||
/* EA */
|
unsigned long ea;
|
||||||
slbie_data = (unsigned long)
|
|
||||||
|
ea = (unsigned long)
|
||||||
get_paca()->slb_cache[i] << SID_SHIFT;
|
get_paca()->slb_cache[i] << SID_SHIFT;
|
||||||
|
/*
|
||||||
|
* Could assert_slb_exists here, but hypervisor
|
||||||
|
* or machine check could have come in and
|
||||||
|
* removed the entry at this point.
|
||||||
|
*/
|
||||||
|
|
||||||
|
slbie_data = ea;
|
||||||
slbie_data |= user_segment_size(slbie_data)
|
slbie_data |= user_segment_size(slbie_data)
|
||||||
<< SLBIE_SSIZE_SHIFT;
|
<< SLBIE_SSIZE_SHIFT;
|
||||||
slbie_data |= SLBIE_C; /* user slbs have C=1 */
|
slbie_data |= SLBIE_C; /* user slbs have C=1 */
|
||||||
@ -640,6 +676,7 @@ static long slb_insert_entry(unsigned long ea, unsigned long context,
|
|||||||
* User preloads should add isync afterwards in case the kernel
|
* User preloads should add isync afterwards in case the kernel
|
||||||
* accesses user memory before it returns to userspace with rfid.
|
* accesses user memory before it returns to userspace with rfid.
|
||||||
*/
|
*/
|
||||||
|
assert_slb_notexists(ea);
|
||||||
asm volatile("slbmte %0, %1" : : "r" (vsid_data), "r" (esid_data));
|
asm volatile("slbmte %0, %1" : : "r" (vsid_data), "r" (esid_data));
|
||||||
|
|
||||||
barrier();
|
barrier();
|
||||||
@ -740,7 +777,17 @@ long do_slb_fault(struct pt_regs *regs, unsigned long ea)
|
|||||||
* if they go via fast_exception_return too.
|
* if they go via fast_exception_return too.
|
||||||
*/
|
*/
|
||||||
if (id >= KERNEL_REGION_ID) {
|
if (id >= KERNEL_REGION_ID) {
|
||||||
return slb_allocate_kernel(ea, id);
|
long err;
|
||||||
|
#ifdef CONFIG_DEBUG_VM
|
||||||
|
/* Catch recursive kernel SLB faults. */
|
||||||
|
BUG_ON(local_paca->in_kernel_slb_handler);
|
||||||
|
local_paca->in_kernel_slb_handler = 1;
|
||||||
|
#endif
|
||||||
|
err = slb_allocate_kernel(ea, id);
|
||||||
|
#ifdef CONFIG_DEBUG_VM
|
||||||
|
local_paca->in_kernel_slb_handler = 0;
|
||||||
|
#endif
|
||||||
|
return err;
|
||||||
} else {
|
} else {
|
||||||
struct mm_struct *mm = current->mm;
|
struct mm_struct *mm = current->mm;
|
||||||
long err;
|
long err;
|
||||||
|
Loading…
Reference in New Issue
Block a user