0001
0002
0003 #include "lkdtm.h"
0004 #include <linux/slab.h>
0005 #include <linux/vmalloc.h>
0006 #include <asm/mmu.h>
0007
0008
0009 static void insert_slb_entry(unsigned long p, int ssize, int page_size)
0010 {
0011 unsigned long flags;
0012
0013 flags = SLB_VSID_KERNEL | mmu_psize_defs[page_size].sllp;
0014 preempt_disable();
0015
0016 asm volatile("slbmte %0,%1" :
0017 : "r" (mk_vsid_data(p, ssize, flags)),
0018 "r" (mk_esid_data(p, ssize, SLB_NUM_BOLTED))
0019 : "memory");
0020
0021 asm volatile("slbmte %0,%1" :
0022 : "r" (mk_vsid_data(p, ssize, flags)),
0023 "r" (mk_esid_data(p, ssize, SLB_NUM_BOLTED + 1))
0024 : "memory");
0025 preempt_enable();
0026 }
0027
0028
0029 static int inject_vmalloc_slb_multihit(void)
0030 {
0031 char *p;
0032
0033 p = vmalloc(PAGE_SIZE);
0034 if (!p)
0035 return -ENOMEM;
0036
0037 insert_slb_entry((unsigned long)p, MMU_SEGSIZE_1T, mmu_vmalloc_psize);
0038
0039
0040
0041
0042 p[0] = '!';
0043 vfree(p);
0044 return 0;
0045 }
0046
0047
0048 static int inject_kmalloc_slb_multihit(void)
0049 {
0050 char *p;
0051
0052 p = kmalloc(2048, GFP_KERNEL);
0053 if (!p)
0054 return -ENOMEM;
0055
0056 insert_slb_entry((unsigned long)p, MMU_SEGSIZE_1T, mmu_linear_psize);
0057
0058
0059
0060
0061 p[0] = '!';
0062 kfree(p);
0063 return 0;
0064 }
0065
0066
0067
0068
0069
0070 static void insert_dup_slb_entry_0(void)
0071 {
0072 unsigned long test_address = PAGE_OFFSET, *test_ptr;
0073 unsigned long esid, vsid;
0074 unsigned long i = 0;
0075
0076 test_ptr = (unsigned long *)test_address;
0077 preempt_disable();
0078
0079 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
0080 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
0081
0082
0083 asm volatile("slbmte %0,%1" :
0084 : "r" (vsid),
0085 "r" (esid | SLB_NUM_BOLTED)
0086 : "memory");
0087
0088 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
0089 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
0090
0091
0092 asm volatile("slbmte %0,%1" :
0093 : "r" (vsid),
0094 "r" (esid | (SLB_NUM_BOLTED + 1))
0095 : "memory");
0096
0097 pr_info("%s accessing test address 0x%lx: 0x%lx\n",
0098 __func__, test_address, *test_ptr);
0099
0100 preempt_enable();
0101 }
0102
0103 static void lkdtm_PPC_SLB_MULTIHIT(void)
0104 {
0105 if (!radix_enabled()) {
0106 pr_info("Injecting SLB multihit errors\n");
0107
0108
0109
0110
0111
0112
0113 inject_vmalloc_slb_multihit();
0114 inject_kmalloc_slb_multihit();
0115 insert_dup_slb_entry_0();
0116 pr_info("Recovered from SLB multihit errors\n");
0117 } else {
0118 pr_err("XFAIL: This test is for ppc64 and with hash mode MMU only\n");
0119 }
0120 }
0121
0122 static struct crashtype crashtypes[] = {
0123 CRASHTYPE(PPC_SLB_MULTIHIT),
0124 };
0125
0126 struct crashtype_category powerpc_crashtypes = {
0127 .crashtypes = crashtypes,
0128 .len = ARRAY_SIZE(crashtypes),
0129 };