130 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#include "lkdtm.h"4#include <linux/slab.h>5#include <linux/vmalloc.h>6#include <asm/mmu.h>7 8/* Inserts new slb entries */9static void insert_slb_entry(unsigned long p, int ssize, int page_size)10{11 unsigned long flags;12 13 flags = SLB_VSID_KERNEL | mmu_psize_defs[page_size].sllp;14 preempt_disable();15 16 asm volatile("slbmte %0,%1" :17 : "r" (mk_vsid_data(p, ssize, flags)),18 "r" (mk_esid_data(p, ssize, SLB_NUM_BOLTED))19 : "memory");20 21 asm volatile("slbmte %0,%1" :22 : "r" (mk_vsid_data(p, ssize, flags)),23 "r" (mk_esid_data(p, ssize, SLB_NUM_BOLTED + 1))24 : "memory");25 preempt_enable();26}27 28/* Inject slb multihit on vmalloc-ed address i.e 0xD00... */29static int inject_vmalloc_slb_multihit(void)30{31 char *p;32 33 p = vmalloc(PAGE_SIZE);34 if (!p)35 return -ENOMEM;36 37 insert_slb_entry((unsigned long)p, MMU_SEGSIZE_1T, mmu_vmalloc_psize);38 /*39 * This triggers exception, If handled correctly we must recover40 * from this error.41 */42 p[0] = '!';43 vfree(p);44 return 0;45}46 47/* Inject slb multihit on kmalloc-ed address i.e 0xC00... */48static int inject_kmalloc_slb_multihit(void)49{50 char *p;51 52 p = kmalloc(2048, GFP_KERNEL);53 if (!p)54 return -ENOMEM;55 56 insert_slb_entry((unsigned long)p, MMU_SEGSIZE_1T, mmu_linear_psize);57 /*58 * This triggers exception, If handled correctly we must recover59 * from this error.60 */61 p[0] = '!';62 kfree(p);63 return 0;64}65 66/*67 * Few initial SLB entries are bolted. Add a test to inject68 * multihit in bolted entry 0.69 */70static void insert_dup_slb_entry_0(void)71{72 unsigned long test_address = PAGE_OFFSET, *test_ptr;73 unsigned long esid, vsid;74 unsigned long i = 0;75 76 test_ptr = (unsigned long *)test_address;77 preempt_disable();78 79 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));80 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));81 82 /* for i !=0 we would need to mask out the old entry number */83 asm volatile("slbmte %0,%1" :84 : "r" (vsid),85 "r" (esid | SLB_NUM_BOLTED)86 : "memory");87 88 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));89 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));90 91 /* for i !=0 we would need to mask out the old entry number */92 asm volatile("slbmte %0,%1" :93 : "r" (vsid),94 "r" (esid | (SLB_NUM_BOLTED + 1))95 : "memory");96 97 pr_info("%s accessing test address 0x%lx: 0x%lx\n",98 __func__, test_address, *test_ptr);99 100 preempt_enable();101}102 103static void lkdtm_PPC_SLB_MULTIHIT(void)104{105 if (!radix_enabled()) {106 pr_info("Injecting SLB multihit errors\n");107 /*108 * These need not be separate tests, And they do pretty109 * much same thing. In any case we must recover from the110 * errors introduced by these functions, machine would not111 * survive these tests in case of failure to handle.112 */113 inject_vmalloc_slb_multihit();114 inject_kmalloc_slb_multihit();115 insert_dup_slb_entry_0();116 pr_info("Recovered from SLB multihit errors\n");117 } else {118 pr_err("XFAIL: This test is for ppc64 and with hash mode MMU only\n");119 }120}121 122static struct crashtype crashtypes[] = {123 CRASHTYPE(PPC_SLB_MULTIHIT),124};125 126struct crashtype_category powerpc_crashtypes = {127 .crashtypes = crashtypes,128 .len = ARRAY_SIZE(crashtypes),129};130