xref: /openbmc/qemu/tests/tcg/s390x/signals-s390x.c (revision e7f8a3aae271d279edb1c0c318c6d83b0b3924ce)
1*e7f8a3aaSIlya Leoshkevich #include <assert.h>
2*e7f8a3aaSIlya Leoshkevich #include <signal.h>
3*e7f8a3aaSIlya Leoshkevich #include <string.h>
4*e7f8a3aaSIlya Leoshkevich #include <sys/mman.h>
5*e7f8a3aaSIlya Leoshkevich #include <ucontext.h>
6*e7f8a3aaSIlya Leoshkevich #include <unistd.h>
7*e7f8a3aaSIlya Leoshkevich 
8*e7f8a3aaSIlya Leoshkevich /*
9*e7f8a3aaSIlya Leoshkevich  * Various instructions that generate SIGILL and SIGSEGV. They could have been
10*e7f8a3aaSIlya Leoshkevich  * defined in a separate .s file, but this would complicate the build, so the
11*e7f8a3aaSIlya Leoshkevich  * inline asm is used instead.
12*e7f8a3aaSIlya Leoshkevich  */
13*e7f8a3aaSIlya Leoshkevich 
14*e7f8a3aaSIlya Leoshkevich void illegal_op(void);
15*e7f8a3aaSIlya Leoshkevich void after_illegal_op(void);
16*e7f8a3aaSIlya Leoshkevich asm(".globl\tillegal_op\n"
17*e7f8a3aaSIlya Leoshkevich     "illegal_op:\t.byte\t0x00,0x00\n"
18*e7f8a3aaSIlya Leoshkevich     "\t.globl\tafter_illegal_op\n"
19*e7f8a3aaSIlya Leoshkevich     "after_illegal_op:\tbr\t%r14");
20*e7f8a3aaSIlya Leoshkevich 
21*e7f8a3aaSIlya Leoshkevich void stg(void *dst, unsigned long src);
22*e7f8a3aaSIlya Leoshkevich asm(".globl\tstg\n"
23*e7f8a3aaSIlya Leoshkevich     "stg:\tstg\t%r3,0(%r2)\n"
24*e7f8a3aaSIlya Leoshkevich     "\tbr\t%r14");
25*e7f8a3aaSIlya Leoshkevich 
26*e7f8a3aaSIlya Leoshkevich void mvc_8(void *dst, void *src);
27*e7f8a3aaSIlya Leoshkevich asm(".globl\tmvc_8\n"
28*e7f8a3aaSIlya Leoshkevich     "mvc_8:\tmvc\t0(8,%r2),0(%r3)\n"
29*e7f8a3aaSIlya Leoshkevich     "\tbr\t%r14");
30*e7f8a3aaSIlya Leoshkevich 
31*e7f8a3aaSIlya Leoshkevich static void safe_puts(const char *s)
32*e7f8a3aaSIlya Leoshkevich {
33*e7f8a3aaSIlya Leoshkevich     write(0, s, strlen(s));
34*e7f8a3aaSIlya Leoshkevich     write(0, "\n", 1);
35*e7f8a3aaSIlya Leoshkevich }
36*e7f8a3aaSIlya Leoshkevich 
37*e7f8a3aaSIlya Leoshkevich enum exception {
38*e7f8a3aaSIlya Leoshkevich     exception_operation,
39*e7f8a3aaSIlya Leoshkevich     exception_translation,
40*e7f8a3aaSIlya Leoshkevich     exception_protection,
41*e7f8a3aaSIlya Leoshkevich };
42*e7f8a3aaSIlya Leoshkevich 
43*e7f8a3aaSIlya Leoshkevich static struct {
44*e7f8a3aaSIlya Leoshkevich     int sig;
45*e7f8a3aaSIlya Leoshkevich     void *addr;
46*e7f8a3aaSIlya Leoshkevich     unsigned long psw_addr;
47*e7f8a3aaSIlya Leoshkevich     enum exception exception;
48*e7f8a3aaSIlya Leoshkevich } expected;
49*e7f8a3aaSIlya Leoshkevich 
50*e7f8a3aaSIlya Leoshkevich static void handle_signal(int sig, siginfo_t *info, void *ucontext)
51*e7f8a3aaSIlya Leoshkevich {
52*e7f8a3aaSIlya Leoshkevich     void *page;
53*e7f8a3aaSIlya Leoshkevich     int err;
54*e7f8a3aaSIlya Leoshkevich 
55*e7f8a3aaSIlya Leoshkevich     if (sig != expected.sig) {
56*e7f8a3aaSIlya Leoshkevich         safe_puts("[  FAILED  ] wrong signal");
57*e7f8a3aaSIlya Leoshkevich         _exit(1);
58*e7f8a3aaSIlya Leoshkevich     }
59*e7f8a3aaSIlya Leoshkevich 
60*e7f8a3aaSIlya Leoshkevich     if (info->si_addr != expected.addr) {
61*e7f8a3aaSIlya Leoshkevich         safe_puts("[  FAILED  ] wrong si_addr");
62*e7f8a3aaSIlya Leoshkevich         _exit(1);
63*e7f8a3aaSIlya Leoshkevich     }
64*e7f8a3aaSIlya Leoshkevich 
65*e7f8a3aaSIlya Leoshkevich     if (((ucontext_t *)ucontext)->uc_mcontext.psw.addr != expected.psw_addr) {
66*e7f8a3aaSIlya Leoshkevich         safe_puts("[  FAILED  ] wrong psw.addr");
67*e7f8a3aaSIlya Leoshkevich         _exit(1);
68*e7f8a3aaSIlya Leoshkevich     }
69*e7f8a3aaSIlya Leoshkevich 
70*e7f8a3aaSIlya Leoshkevich     switch (expected.exception) {
71*e7f8a3aaSIlya Leoshkevich     case exception_translation:
72*e7f8a3aaSIlya Leoshkevich         page = mmap(expected.addr, 4096, PROT_READ | PROT_WRITE,
73*e7f8a3aaSIlya Leoshkevich                     MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
74*e7f8a3aaSIlya Leoshkevich         if (page != expected.addr) {
75*e7f8a3aaSIlya Leoshkevich             safe_puts("[  FAILED  ] mmap() failed");
76*e7f8a3aaSIlya Leoshkevich             _exit(1);
77*e7f8a3aaSIlya Leoshkevich         }
78*e7f8a3aaSIlya Leoshkevich         break;
79*e7f8a3aaSIlya Leoshkevich     case exception_protection:
80*e7f8a3aaSIlya Leoshkevich         err = mprotect(expected.addr, 4096, PROT_READ | PROT_WRITE);
81*e7f8a3aaSIlya Leoshkevich         if (err != 0) {
82*e7f8a3aaSIlya Leoshkevich             safe_puts("[  FAILED  ] mprotect() failed");
83*e7f8a3aaSIlya Leoshkevich             _exit(1);
84*e7f8a3aaSIlya Leoshkevich         }
85*e7f8a3aaSIlya Leoshkevich         break;
86*e7f8a3aaSIlya Leoshkevich     default:
87*e7f8a3aaSIlya Leoshkevich         break;
88*e7f8a3aaSIlya Leoshkevich     }
89*e7f8a3aaSIlya Leoshkevich }
90*e7f8a3aaSIlya Leoshkevich 
91*e7f8a3aaSIlya Leoshkevich static void check_sigsegv(void *func, enum exception exception,
92*e7f8a3aaSIlya Leoshkevich                           unsigned long val)
93*e7f8a3aaSIlya Leoshkevich {
94*e7f8a3aaSIlya Leoshkevich     int prot;
95*e7f8a3aaSIlya Leoshkevich     unsigned long *page;
96*e7f8a3aaSIlya Leoshkevich     unsigned long *addr;
97*e7f8a3aaSIlya Leoshkevich     int err;
98*e7f8a3aaSIlya Leoshkevich 
99*e7f8a3aaSIlya Leoshkevich     prot = exception == exception_translation ? PROT_NONE : PROT_READ;
100*e7f8a3aaSIlya Leoshkevich     page = mmap(NULL, 4096, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
101*e7f8a3aaSIlya Leoshkevich     assert(page != MAP_FAILED);
102*e7f8a3aaSIlya Leoshkevich     if (exception == exception_translation) {
103*e7f8a3aaSIlya Leoshkevich         /* Hopefully nothing will be mapped at this address. */
104*e7f8a3aaSIlya Leoshkevich         err = munmap(page, 4096);
105*e7f8a3aaSIlya Leoshkevich         assert(err == 0);
106*e7f8a3aaSIlya Leoshkevich     }
107*e7f8a3aaSIlya Leoshkevich     addr = page + (val & 0x1ff);
108*e7f8a3aaSIlya Leoshkevich 
109*e7f8a3aaSIlya Leoshkevich     expected.sig = SIGSEGV;
110*e7f8a3aaSIlya Leoshkevich     expected.addr = page;
111*e7f8a3aaSIlya Leoshkevich     expected.psw_addr = (unsigned long)func;
112*e7f8a3aaSIlya Leoshkevich     expected.exception = exception;
113*e7f8a3aaSIlya Leoshkevich     if (func == stg) {
114*e7f8a3aaSIlya Leoshkevich         stg(addr, val);
115*e7f8a3aaSIlya Leoshkevich     } else {
116*e7f8a3aaSIlya Leoshkevich         assert(func == mvc_8);
117*e7f8a3aaSIlya Leoshkevich         mvc_8(addr, &val);
118*e7f8a3aaSIlya Leoshkevich     }
119*e7f8a3aaSIlya Leoshkevich     assert(*addr == val);
120*e7f8a3aaSIlya Leoshkevich 
121*e7f8a3aaSIlya Leoshkevich     err = munmap(page, 4096);
122*e7f8a3aaSIlya Leoshkevich     assert(err == 0);
123*e7f8a3aaSIlya Leoshkevich }
124*e7f8a3aaSIlya Leoshkevich 
125*e7f8a3aaSIlya Leoshkevich int main(void)
126*e7f8a3aaSIlya Leoshkevich {
127*e7f8a3aaSIlya Leoshkevich     struct sigaction act;
128*e7f8a3aaSIlya Leoshkevich     int err;
129*e7f8a3aaSIlya Leoshkevich 
130*e7f8a3aaSIlya Leoshkevich     memset(&act, 0, sizeof(act));
131*e7f8a3aaSIlya Leoshkevich     act.sa_sigaction = handle_signal;
132*e7f8a3aaSIlya Leoshkevich     act.sa_flags = SA_SIGINFO;
133*e7f8a3aaSIlya Leoshkevich     err = sigaction(SIGILL, &act, NULL);
134*e7f8a3aaSIlya Leoshkevich     assert(err == 0);
135*e7f8a3aaSIlya Leoshkevich     err = sigaction(SIGSEGV, &act, NULL);
136*e7f8a3aaSIlya Leoshkevich     assert(err == 0);
137*e7f8a3aaSIlya Leoshkevich 
138*e7f8a3aaSIlya Leoshkevich     safe_puts("[ RUN      ] Operation exception");
139*e7f8a3aaSIlya Leoshkevich     expected.sig = SIGILL;
140*e7f8a3aaSIlya Leoshkevich     expected.addr = illegal_op;
141*e7f8a3aaSIlya Leoshkevich     expected.psw_addr = (unsigned long)after_illegal_op;
142*e7f8a3aaSIlya Leoshkevich     expected.exception = exception_operation;
143*e7f8a3aaSIlya Leoshkevich     illegal_op();
144*e7f8a3aaSIlya Leoshkevich     safe_puts("[       OK ]");
145*e7f8a3aaSIlya Leoshkevich 
146*e7f8a3aaSIlya Leoshkevich     safe_puts("[ RUN      ] Translation exception from stg");
147*e7f8a3aaSIlya Leoshkevich     check_sigsegv(stg, exception_translation, 42);
148*e7f8a3aaSIlya Leoshkevich     safe_puts("[       OK ]");
149*e7f8a3aaSIlya Leoshkevich 
150*e7f8a3aaSIlya Leoshkevich     safe_puts("[ RUN      ] Translation exception from mvc");
151*e7f8a3aaSIlya Leoshkevich     check_sigsegv(mvc_8, exception_translation, 4242);
152*e7f8a3aaSIlya Leoshkevich     safe_puts("[       OK ]");
153*e7f8a3aaSIlya Leoshkevich 
154*e7f8a3aaSIlya Leoshkevich     safe_puts("[ RUN      ] Protection exception from stg");
155*e7f8a3aaSIlya Leoshkevich     check_sigsegv(stg, exception_protection, 424242);
156*e7f8a3aaSIlya Leoshkevich     safe_puts("[       OK ]");
157*e7f8a3aaSIlya Leoshkevich 
158*e7f8a3aaSIlya Leoshkevich     safe_puts("[ RUN      ] Protection exception from mvc");
159*e7f8a3aaSIlya Leoshkevich     check_sigsegv(mvc_8, exception_protection, 42424242);
160*e7f8a3aaSIlya Leoshkevich     safe_puts("[       OK ]");
161*e7f8a3aaSIlya Leoshkevich 
162*e7f8a3aaSIlya Leoshkevich     safe_puts("[  PASSED  ]");
163*e7f8a3aaSIlya Leoshkevich 
164*e7f8a3aaSIlya Leoshkevich     _exit(0);
165*e7f8a3aaSIlya Leoshkevich }
166