xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/powerpc/mm/wild_bctr.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright 2018, Michael Ellerman, IBM Corp.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Test that an out-of-bounds branch to counter behaves as expected.
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <setjmp.h>
9*4882a593Smuzhiyun #include <stdio.h>
10*4882a593Smuzhiyun #include <stdlib.h>
11*4882a593Smuzhiyun #include <string.h>
12*4882a593Smuzhiyun #include <sys/mman.h>
13*4882a593Smuzhiyun #include <sys/types.h>
14*4882a593Smuzhiyun #include <sys/wait.h>
15*4882a593Smuzhiyun #include <ucontext.h>
16*4882a593Smuzhiyun #include <unistd.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include "utils.h"
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #define BAD_NIP	0x788c545a18000000ull
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun static struct pt_regs signal_regs;
24*4882a593Smuzhiyun static jmp_buf setjmp_env;
25*4882a593Smuzhiyun 
save_regs(ucontext_t * ctxt)26*4882a593Smuzhiyun static void save_regs(ucontext_t *ctxt)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun 	struct pt_regs *regs = ctxt->uc_mcontext.regs;
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun 	memcpy(&signal_regs, regs, sizeof(signal_regs));
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun 
segv_handler(int signum,siginfo_t * info,void * ctxt_v)33*4882a593Smuzhiyun static void segv_handler(int signum, siginfo_t *info, void *ctxt_v)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	save_regs(ctxt_v);
36*4882a593Smuzhiyun 	longjmp(setjmp_env, 1);
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun 
usr2_handler(int signum,siginfo_t * info,void * ctxt_v)39*4882a593Smuzhiyun static void usr2_handler(int signum, siginfo_t *info, void *ctxt_v)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun 	save_regs(ctxt_v);
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun 
ok(void)44*4882a593Smuzhiyun static int ok(void)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun 	printf("Everything is OK in here.\n");
47*4882a593Smuzhiyun 	return 0;
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #define REG_POISON	0x5a5a
51*4882a593Smuzhiyun #define POISONED_REG(n)	((((unsigned long)REG_POISON) << 48) | ((n) << 32) | \
52*4882a593Smuzhiyun 			 (((unsigned long)REG_POISON) << 16) | (n))
53*4882a593Smuzhiyun 
poison_regs(void)54*4882a593Smuzhiyun static inline void poison_regs(void)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun 	#define POISON_REG(n)	\
57*4882a593Smuzhiyun 	  "lis  " __stringify(n) "," __stringify(REG_POISON) ";" \
58*4882a593Smuzhiyun 	  "addi " __stringify(n) "," __stringify(n) "," __stringify(n) ";" \
59*4882a593Smuzhiyun 	  "sldi " __stringify(n) "," __stringify(n) ", 32 ;" \
60*4882a593Smuzhiyun 	  "oris " __stringify(n) "," __stringify(n) "," __stringify(REG_POISON) ";" \
61*4882a593Smuzhiyun 	  "addi " __stringify(n) "," __stringify(n) "," __stringify(n) ";"
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	asm (POISON_REG(15)
64*4882a593Smuzhiyun 	     POISON_REG(16)
65*4882a593Smuzhiyun 	     POISON_REG(17)
66*4882a593Smuzhiyun 	     POISON_REG(18)
67*4882a593Smuzhiyun 	     POISON_REG(19)
68*4882a593Smuzhiyun 	     POISON_REG(20)
69*4882a593Smuzhiyun 	     POISON_REG(21)
70*4882a593Smuzhiyun 	     POISON_REG(22)
71*4882a593Smuzhiyun 	     POISON_REG(23)
72*4882a593Smuzhiyun 	     POISON_REG(24)
73*4882a593Smuzhiyun 	     POISON_REG(25)
74*4882a593Smuzhiyun 	     POISON_REG(26)
75*4882a593Smuzhiyun 	     POISON_REG(27)
76*4882a593Smuzhiyun 	     POISON_REG(28)
77*4882a593Smuzhiyun 	     POISON_REG(29)
78*4882a593Smuzhiyun 	     : // inputs
79*4882a593Smuzhiyun 	     : // outputs
80*4882a593Smuzhiyun 	     : "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25",
81*4882a593Smuzhiyun 	       "26", "27", "28", "29"
82*4882a593Smuzhiyun 	);
83*4882a593Smuzhiyun 	#undef POISON_REG
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun 
check_regs(void)86*4882a593Smuzhiyun static int check_regs(void)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	unsigned long i;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	for (i = 15; i <= 29; i++)
91*4882a593Smuzhiyun 		FAIL_IF(signal_regs.gpr[i] != POISONED_REG(i));
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	printf("Regs OK\n");
94*4882a593Smuzhiyun 	return 0;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun 
dump_regs(void)97*4882a593Smuzhiyun static void dump_regs(void)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun 	for (int i = 0; i < 32; i += 4) {
100*4882a593Smuzhiyun 		printf("r%02d 0x%016lx  r%02d 0x%016lx  " \
101*4882a593Smuzhiyun 		       "r%02d 0x%016lx  r%02d 0x%016lx\n",
102*4882a593Smuzhiyun 		       i, signal_regs.gpr[i],
103*4882a593Smuzhiyun 		       i+1, signal_regs.gpr[i+1],
104*4882a593Smuzhiyun 		       i+2, signal_regs.gpr[i+2],
105*4882a593Smuzhiyun 		       i+3, signal_regs.gpr[i+3]);
106*4882a593Smuzhiyun 	}
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun #ifdef _CALL_AIXDESC
110*4882a593Smuzhiyun struct opd {
111*4882a593Smuzhiyun 	unsigned long ip;
112*4882a593Smuzhiyun 	unsigned long toc;
113*4882a593Smuzhiyun 	unsigned long env;
114*4882a593Smuzhiyun };
115*4882a593Smuzhiyun static struct opd bad_opd = {
116*4882a593Smuzhiyun 	.ip = BAD_NIP,
117*4882a593Smuzhiyun };
118*4882a593Smuzhiyun #define BAD_FUNC (&bad_opd)
119*4882a593Smuzhiyun #else
120*4882a593Smuzhiyun #define BAD_FUNC BAD_NIP
121*4882a593Smuzhiyun #endif
122*4882a593Smuzhiyun 
test_wild_bctr(void)123*4882a593Smuzhiyun int test_wild_bctr(void)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	int (*func_ptr)(void);
126*4882a593Smuzhiyun 	struct sigaction segv = {
127*4882a593Smuzhiyun 		.sa_sigaction = segv_handler,
128*4882a593Smuzhiyun 		.sa_flags = SA_SIGINFO
129*4882a593Smuzhiyun 	};
130*4882a593Smuzhiyun 	struct sigaction usr2 = {
131*4882a593Smuzhiyun 		.sa_sigaction = usr2_handler,
132*4882a593Smuzhiyun 		.sa_flags = SA_SIGINFO
133*4882a593Smuzhiyun 	};
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	FAIL_IF(sigaction(SIGSEGV, &segv, NULL));
136*4882a593Smuzhiyun 	FAIL_IF(sigaction(SIGUSR2, &usr2, NULL));
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	bzero(&signal_regs, sizeof(signal_regs));
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	if (setjmp(setjmp_env) == 0) {
141*4882a593Smuzhiyun 		func_ptr = ok;
142*4882a593Smuzhiyun 		func_ptr();
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 		kill(getpid(), SIGUSR2);
145*4882a593Smuzhiyun 		printf("Regs before:\n");
146*4882a593Smuzhiyun 		dump_regs();
147*4882a593Smuzhiyun 		bzero(&signal_regs, sizeof(signal_regs));
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 		poison_regs();
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 		func_ptr = (int (*)(void))BAD_FUNC;
152*4882a593Smuzhiyun 		func_ptr();
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 		FAIL_IF(1); /* we didn't segv? */
155*4882a593Smuzhiyun 	}
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	FAIL_IF(signal_regs.nip != BAD_NIP);
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	printf("All good - took SEGV as expected branching to 0x%llx\n", BAD_NIP);
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	dump_regs();
162*4882a593Smuzhiyun 	FAIL_IF(check_regs());
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	return 0;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
main(void)167*4882a593Smuzhiyun int main(void)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	return test_harness(test_wild_bctr, "wild_bctr");
170*4882a593Smuzhiyun }
171