Merge branches 'pm-cpuidle', 'pm-sleep' and 'pm-domains'
[linux-2.6-microblaze.git] / drivers / misc / lkdtm / powerpc.c
1 // SPDX-License-Identifier: GPL-2.0
2
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 */
9 static 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... */
29 static 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 recover
40          * 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... */
48 static 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 recover
59          * 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 inject
68  * multihit in bolted entry 0.
69  */
70 static 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
103 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 pretty
109                  * much same thing. In any case we must recover from the
110                  * errors introduced by these functions, machine would not
111                  * 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 }