194742Sobrien// SPDX-License-Identifier: GPL-2.0
294742Sobrien
3146890Speter#include "lkdtm.h"
4146890Speter#include <linux/slab.h>
5179626Speter#include <linux/vmalloc.h>
6240316Seadler#include <asm/mmu.h>
7146890Speter
8146890Speter/* Inserts new slb entries */
9146890Speterstatic void insert_slb_entry(unsigned long p, int ssize, int page_size)
10146890Speter{
11146890Speter	unsigned long flags;
12146890Speter
13146890Speter	flags = SLB_VSID_KERNEL | mmu_psize_defs[page_size].sllp;
14146890Speter	preempt_disable();
15146890Speter
16146890Speter	asm volatile("slbmte %0,%1" :
17146890Speter		     : "r" (mk_vsid_data(p, ssize, flags)),
18146890Speter		       "r" (mk_esid_data(p, ssize, SLB_NUM_BOLTED))
19146890Speter		     : "memory");
20146890Speter
2194742Sobrien	asm volatile("slbmte %0,%1" :
2295253Sru			: "r" (mk_vsid_data(p, ssize, flags)),
23159014Sjmg			  "r" (mk_esid_data(p, ssize, SLB_NUM_BOLTED + 1))
2496991Srwatson			: "memory");
2596991Srwatson	preempt_enable();
2696991Srwatson}
27102773Srwatson
28102773Srwatson/* Inject slb multihit on vmalloc-ed address i.e 0xD00... */
29156279Srwatsonstatic int inject_vmalloc_slb_multihit(void)
30156279Srwatson{
31250778Sadrian	char *p;
3294917Simp
33126445Sobrien	p = vmalloc(PAGE_SIZE);
34248805Simp	if (!p)
35248805Simp		return -ENOMEM;
36146933Simp
3794847Sjhb	insert_slb_entry((unsigned long)p, MMU_SEGSIZE_1T, mmu_vmalloc_psize);
3894847Sjhb	/*
3994847Sjhb	 * This triggers exception, If handled correctly we must recover
4094915Sken	 * from this error.
4199607Smjacob	 */
4294915Sken	p[0] = '!';
4394915Sken	vfree(p);
4494915Sken	return 0;
4594915Sken}
4694915Sken
4794915Sken/* Inject slb multihit on kmalloc-ed address i.e 0xC00... */
4894915Skenstatic int inject_kmalloc_slb_multihit(void)
4994915Sken{
50169922Sjfv	char *p;
51219647Sdavidch
5297611Sbillf	p = kmalloc(2048, GFP_KERNEL);
5394918Sgshapiro	if (!p)
5494918Sgshapiro		return -ENOMEM;
5594918Sgshapiro
5694918Sgshapiro	insert_slb_entry((unsigned long)p, MMU_SEGSIZE_1T, mmu_linear_psize);
5794918Sgshapiro	/*
58106187Sdes	 * This triggers exception, If handled correctly we must recover
59106187Sdes	 * from this error.
6095455Sdes	 */
6198750Sdes	p[0] = '!';
62205686Sdes	kfree(p);
63205686Sdes	return 0;
64205686Sdes}
6596268Sgad
6696268Sgad/*
67250778Sadrian * Few initial SLB entries are bolted. Add a test to inject
6896332Speter * multihit in bolted entry 0.
6996332Speter */
70100314Srustatic void insert_dup_slb_entry_0(void)
71146921Sru{
72146921Sru	unsigned long test_address = PAGE_OFFSET, *test_ptr;
7397611Sbillf	unsigned long esid, vsid;
74190171Srnoland	unsigned long i = 0;
75115825Sfanf
76126445Sobrien	test_ptr = (unsigned long *)test_address;
77117645Sdwmalone	preempt_disable();
78118204Sbp
79118204Sbp	asm volatile("slbmfee  %0,%1" : "=r" (esid) : "r" (i));
80127337Smlaier	asm volatile("slbmfev  %0,%1" : "=r" (vsid) : "r" (i));
81126445Sobrien
82146837Sobrien	/* for i !=0 we would need to mask out the old entry number */
83146837Sobrien	asm volatile("slbmte %0,%1" :
84146837Sobrien			: "r" (vsid),
85146837Sobrien			  "r" (esid | SLB_NUM_BOLTED)
86133182Spjd			: "memory");
87148779Spjd
88133182Spjd	asm volatile("slbmfee  %0,%1" : "=r" (esid) : "r" (i));
89133182Spjd	asm volatile("slbmfev  %0,%1" : "=r" (vsid) : "r" (i));
90133182Spjd
91133182Spjd	/* for i !=0 we would need to mask out the old entry number */
92133841Spjd	asm volatile("slbmte %0,%1" :
93143521Spjd			: "r" (vsid),
94133182Spjd			  "r" (esid | (SLB_NUM_BOLTED + 1))
95148779Spjd			: "memory");
96133182Spjd
97168419Spjd	pr_info("%s accessing test address 0x%lx: 0x%lx\n",
98132311Salfred		__func__, test_address, *test_ptr);
99132311Salfred
100132311Salfred	preempt_enable();
101132268Salfred}
102195405Sflz
103146960Simpstatic void lkdtm_PPC_SLB_MULTIHIT(void)
104148772Scperciva{
105148871Scperciva	if (!radix_enabled()) {
106161748Scperciva		pr_info("Injecting SLB multihit errors\n");
107221900Scperciva		/*
108149464Semax		 * These need not be separate tests, And they do pretty
109149464Semax		 * much same thing. In any case we must recover from the
110149464Semax		 * errors introduced by these functions, machine would not
111149464Semax		 * survive these tests in case of failure to handle.
112149464Semax		 */
113151618Sceri		inject_vmalloc_slb_multihit();
114200194Scperciva		inject_kmalloc_slb_multihit();
115200194Scperciva		insert_dup_slb_entry_0();
116204061Sedwin		pr_info("Recovered from SLB multihit errors\n");
117204061Sedwin	} else {
118204061Sedwin		pr_err("XFAIL: This test is for ppc64 and with hash mode MMU only\n");
119204061Sedwin	}
120204061Sedwin}
121204061Sedwin
122206455Sbmsstatic struct crashtype crashtypes[] = {
123230843Sjimharris	CRASHTYPE(PPC_SLB_MULTIHIT),
124241828Seadler};
125241828Seadler
126241891Seadlerstruct crashtype_category powerpc_crashtypes = {
127241828Seadler	.crashtypes = crashtypes,
128247716Sjilles	.len	    = ARRAY_SIZE(crashtypes),
129247716Sjilles};
130247716Sjilles