ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/paranoia.cpp
Revision: 1.1
Committed: 2005-07-04T06:09:59Z (19 years, 4 months ago) by gbeauche
Branch: MAIN
Log Message:
New paranoia checks that better match was SheepShaver is doing with threads
and sigaltstack(). At least, this time we force use of threads and also
alter r1 to see whether the current threading model relies on it or not.

File Contents

# User Rev Content
1 gbeauche 1.1 /*
2     * paranoia.cpp - Check undocumented features of the underlying
3     * kernel that SheepShaver relies upon
4     *
5     * SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20     */
21    
22     /*
23     * TODO
24     * - Check for nested signal handlers vs. sigaltstack()
25     */
26    
27     #include <unistd.h>
28     #include <stdio.h>
29     #include <signal.h>
30     #include <errno.h>
31     #include <pthread.h>
32     #include <sys/types.h>
33     #include <sys/ucontext.h>
34    
35     #include "sysdeps.h"
36     #include "sigregs.h"
37     #include "main.h"
38     #include "user_strings.h"
39    
40     #define DEBUG 1
41     #include "debug.h"
42    
43    
44     // Constants
45     const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack
46    
47     // Prototypes
48     extern "C" void *get_sp(void);
49     extern "C" void *get_r2(void);
50     extern "C" void set_r2(void *);
51     extern "C" void *get_r13(void);
52     extern "C" void set_r13(void *);
53     extern void paranoia_check(void);
54     extern "C" void sigusr2_handler_init(int sig, siginfo_t *sip, void *scp);
55     extern "C" void sigusr2_handler(int sig, siginfo_t *sip, void *scp);
56     static void *tick_func(void *);
57     static void *emul_func(void *);
58    
59     // Global variables
60     static void *sig_stack = NULL;
61    
62     static int err = 0;
63     static void *sig_sp = NULL;
64     static void *sig_r5 = NULL;
65     static int sig_sc_signal = 0;
66     static void *sig_sc_regs = NULL;
67     static uint32 sig_r2 = 0;
68    
69     static pthread_t tick_thread;
70     static pthread_t emul_thread;
71     static volatile uint32 tick_thread_ready = 0;
72     static volatile uint32 emul_thread_regs[32] = { 0, };
73     static volatile uint32 &emul_thread_ready = emul_thread_regs[0];
74    
75    
76     void paranoia_check(void)
77     {
78     char str[256];
79    
80     printf("Paranoia checks...\n");
81    
82     // Create and install stack for signal handler
83     sig_stack = malloc(SIG_STACK_SIZE);
84     if (sig_stack == NULL) {
85     ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
86     exit(1);
87     }
88    
89     struct sigaltstack old_stack;
90     struct sigaltstack new_stack;
91     new_stack.ss_sp = (char *)sig_stack;
92     new_stack.ss_flags = 0;
93     new_stack.ss_size = SIG_STACK_SIZE;
94     if (sigaltstack(&new_stack, &old_stack) < 0) {
95     sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno));
96     ErrorAlert(str);
97     exit(1);
98     }
99    
100     // Install SIGUSR2 signal handler
101     static struct sigaction old_action;
102     static struct sigaction sigusr2_action;
103     sigemptyset(&sigusr2_action.sa_mask);
104     sigusr2_action.sa_sigaction = sigusr2_handler;
105     sigusr2_action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
106     if (sigaction(SIGUSR2, &sigusr2_action, &old_action) < 0) {
107     sprintf(str, GetString(STR_SIGUSR2_INSTALL_ERR), strerror(errno));
108     ErrorAlert(str);
109     exit(1);
110     }
111    
112     // Start tick thread that will trigger only one SIGUSR2
113     pthread_create(&tick_thread, NULL, tick_func, NULL);
114    
115     // Get my thread ID and execute MacOS thread function
116     emul_thread = pthread_self();
117     emul_func(NULL);
118    
119     // Check error code
120     switch (err) {
121     case 1:
122     printf("FATAL: sigaltstack() doesn't seem to work (sp in signal handler was %p, expected %p..%p)\n", sig_sp, sig_stack, (uintptr)sig_stack + SIG_STACK_SIZE);
123     break;
124     case 2:
125     printf("FATAL: r5 in signal handler (%p) doesn't point to stack\n", sig_r5);
126     break;
127     case 3:
128     printf("FATAL: machine registers in signal handler (%p) doesn't point to stack\n", sig_sc_regs);
129     break;
130     case 4:
131     printf("FATAL: register file in signal handler is corrupted\n");
132     break;
133     }
134     if (err) {
135     printf("Maybe you need a different kernel?\n");
136     exit(1);
137     }
138    
139     // Clean up
140     printf("...passed\n");
141     sigaction(SIGUSR2, &old_action, NULL);
142     sigaltstack(&old_stack, NULL);
143     free(sig_stack);
144     }
145    
146     static void *tick_func(void *)
147     {
148     tick_thread_ready = true;
149    
150     // Wait for emul thread to initialize
151     D(bug("[tick_thread] waiting for emul thread to initialize\n"));
152     while (!emul_thread_ready)
153     usleep(0);
154    
155     // Trigger interrupt and terminate
156     D(bug("[tick_thread] trigger interrupt\n"));
157     pthread_kill(emul_thread, SIGUSR2);
158     return NULL;
159     }
160    
161     static void *emul_func(void *)
162     {
163     // Wait for tick thread to initialize
164     D(bug("[emul_thread] waiting for tick thread to initialize\n"));
165     while (!tick_thread_ready)
166     usleep(0);
167    
168     // Fill in register and wait for an interrupt from the tick thread
169     D(bug("[emul_thread] filling in registers and waiting for interrupt\n"));
170     #if defined(__APPLE__) && defined(__MACH__)
171     #define REG(n) "r" #n
172     #else
173     #define REG(n) #n
174     #endif
175     asm volatile ("stw " REG(2) ",2*4(%0)\n"
176     "mr " REG(2) ",%0\n"
177     #define SAVE_REG(n) \
178     "stw " REG(n) "," #n "*4(" REG(2) ")\n" \
179     "addi " REG(n) "," REG(2) ","#n"\n"
180     SAVE_REG(1)
181     SAVE_REG(3)
182     SAVE_REG(4)
183     SAVE_REG(5)
184     SAVE_REG(6)
185     SAVE_REG(7)
186     SAVE_REG(8)
187     SAVE_REG(9)
188     SAVE_REG(10)
189     SAVE_REG(11)
190     SAVE_REG(12)
191     SAVE_REG(13)
192     SAVE_REG(14)
193     SAVE_REG(15)
194     SAVE_REG(16)
195     SAVE_REG(17)
196     SAVE_REG(18)
197     SAVE_REG(19)
198     SAVE_REG(20)
199     SAVE_REG(21)
200     SAVE_REG(22)
201     SAVE_REG(23)
202     SAVE_REG(24)
203     SAVE_REG(25)
204     SAVE_REG(26)
205     SAVE_REG(27)
206     SAVE_REG(28)
207     SAVE_REG(29)
208     SAVE_REG(30)
209     SAVE_REG(31)
210     #undef SAVE_REG
211     " li " REG(0) ",1\n"
212     " stw " REG(0) ",0(" REG(2) ")\n" // regs[0] == emul_thread_ready
213     "0: lwz " REG(0) ",0(" REG(2) ")\n"
214     " cmpi 0," REG(0) ",0\n"
215     " bne+ 0b\n"
216     #define LOAD_REG(n) \
217     "lwz " REG(n) "," #n "*4(" REG(2) ")\n"
218     LOAD_REG(1)
219     LOAD_REG(3)
220     LOAD_REG(4)
221     LOAD_REG(5)
222     LOAD_REG(6)
223     LOAD_REG(7)
224     LOAD_REG(8)
225     LOAD_REG(9)
226     LOAD_REG(10)
227     LOAD_REG(11)
228     LOAD_REG(12)
229     LOAD_REG(13)
230     LOAD_REG(14)
231     LOAD_REG(15)
232     LOAD_REG(16)
233     LOAD_REG(17)
234     LOAD_REG(18)
235     LOAD_REG(19)
236     LOAD_REG(20)
237     LOAD_REG(21)
238     LOAD_REG(22)
239     LOAD_REG(23)
240     LOAD_REG(24)
241     LOAD_REG(25)
242     LOAD_REG(26)
243     LOAD_REG(27)
244     LOAD_REG(28)
245     LOAD_REG(29)
246     LOAD_REG(30)
247     LOAD_REG(31)
248     LOAD_REG(2)
249     #undef LOAD_REG
250     : : "r" ((uintptr)&emul_thread_regs[0]) : "r0");
251     #undef REG
252     }
253    
254    
255     void sigusr2_handler(int sig, siginfo_t *sip, void *scp)
256     {
257     machine_regs *r = MACHINE_REGISTERS(scp);
258    
259     #ifdef SYSTEM_CLOBBERS_R2
260     // Restore pointer to Thread Local Storage
261     set_r2(TOC);
262     #endif
263    
264     #ifdef SYSTEM_CLOBBERS_R13
265     // Restore pointer to .sdata section
266     set_r13(R13);
267     #endif
268    
269     ucontext_t *ucp = (ucontext_t *)scp;
270     D(bug("SIGUSR2 caught\n"));
271    
272     // Check whether sigaltstack works
273     sig_sp = get_sp();
274     if (sig_sp < sig_stack || sig_sp >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) {
275     err = 1;
276     goto ret;
277     }
278    
279     // Check whether r5 points to info on the stack
280     sig_r5 = ucp;
281     if (sig_r5 < sig_stack || sig_r5 >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) {
282     err = 2;
283     goto ret;
284     }
285    
286     // Check whether context regs points to info on the stack
287     sig_sc_regs = &r->gpr(0);
288     if (sig_sc_regs < sig_stack || sig_sc_regs >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) {
289     err = 3;
290     goto ret;
291     }
292    
293     // Check whether registers still hold the values we set them to
294     for (int n = 0; n < 32; n++) {
295     uint32 expected = (uintptr)&emul_thread_regs[0];
296     if (n == 0)
297     expected = 1;
298     else if (n != 2)
299     expected += n;
300     if (r->gpr(n) != expected) {
301     D(bug("Register corruption: r%d was %08x, expected %08x\n", n, r->gpr(n), expected));
302     err = 4;
303     goto ret;
304     }
305     }
306    
307     ret:
308     // Tell emul_func() to exit
309     emul_thread_ready = false;
310     }
311    
312    
313     #ifdef TEST
314     void *TOC;
315     void *R13;
316    
317     extern "C" void EmulOp(void *r, uint32 pc, int selector);
318     void EmulOp(void *r, uint32 pc, int selector)
319     {
320     }
321    
322     extern "C" void check_load_invoc(uint32 type, int16 id, uint32 h);
323     void check_load_invoc(uint32 type, int16 id, uint32 h)
324     {
325     }
326    
327     void ErrorAlert(const char *text)
328     {
329     printf(GetString(STR_SHELL_ERROR_PREFIX), text);
330     }
331    
332     int main(void)
333     {
334     #ifdef SYSTEM_CLOBBERS_R2
335     // Get TOC pointer
336     TOC = get_r2();
337     #endif
338    
339     #ifdef SYSTEM_CLOBBERS_R13
340     // Get r13 register
341     R13 = get_r13();
342     #endif
343    
344     // Check some things
345     paranoia_check();
346     }
347     #endif