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