ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/Linux/paranoia.cpp
Revision: 1.4
Committed: 2005-02-27T21:52:06Z (19 years, 6 months ago) by gbeauche
Branch: MAIN
Changes since 1.3: +32 -7 lines
Log Message:
Fix native Linux/ppc with recent enough glibc that supports TLS; r2 is used
in that case. Tell me if I broke other arches, e.g. r13 is no longer saved
in Video and Ethernet stubs, though it seems to be OK.

Colateral feature: SheepShaver should now run on Linux/ppc64 with relevant
32-bit runtime. Native Linux/ppc64 support is harder as low mem globals are
32-bit in mind and e.g. the TLS register there is %r13, %r2 is the TOC
(PowerOpen/AIX ABI)

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * paranoia.cpp - Check undocumented features of the Linux kernel that
3     * SheepShaver relies upon
4     *
5 gbeauche 1.3 * SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig
6 cebix 1.1 *
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     #include <unistd.h>
23     #include <stdio.h>
24     #include <signal.h>
25     #include <errno.h>
26    
27     #include "sysdeps.h"
28     #include "main.h"
29     #include "user_strings.h"
30    
31     typedef struct {
32     uint32 u[4];
33     } __attribute((aligned(16))) vector128;
34     #include <linux/elf.h>
35    
36     #define DEBUG 1
37     #include "debug.h"
38    
39    
40     // Constants
41     const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack
42    
43     // Prototypes
44     extern "C" void *get_sp(void);
45 gbeauche 1.4 extern "C" void *get_r2(void);
46     extern "C" void set_r2(void *);
47     extern "C" void *get_r13(void);
48 cebix 1.1 extern void paranoia_check(void);
49     static void sigusr2_handler(int sig, sigcontext_struct *sc);
50    
51     // Global variables
52     static void *sig_stack = NULL;
53    
54     static int err = 0;
55     static void *sig_sp = NULL;
56     static void *sig_r4 = NULL;
57     static int sig_sc_signal = 0;
58     static void *sig_sc_regs = NULL;
59     static uint32 sig_r2 = 0;
60    
61    
62 gbeauche 1.4 int raise(int sig)
63     {
64     // Reimplement to get rid of access to r2 (TLS pointer)
65     return kill(getpid(), sig);
66     }
67    
68 cebix 1.1 void paranoia_check(void)
69     {
70     char str[256];
71    
72     D(bug("Paranoia checks...\n"));
73    
74     // Create and install stack for signal handler
75     sig_stack = malloc(SIG_STACK_SIZE);
76     if (sig_stack == NULL) {
77     ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
78     exit(1);
79     }
80    
81     struct sigaltstack old_stack;
82     struct sigaltstack new_stack;
83     new_stack.ss_sp = sig_stack;
84     new_stack.ss_flags = 0;
85     new_stack.ss_size = SIG_STACK_SIZE;
86     if (sigaltstack(&new_stack, &old_stack) < 0) {
87     sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno));
88     ErrorAlert(str);
89     exit(1);
90     }
91    
92     // Install SIGUSR2 signal handler
93     static struct sigaction old_action;
94     static struct sigaction sigusr2_action;
95     sigemptyset(&sigusr2_action.sa_mask);
96     sigusr2_action.sa_handler = (__sighandler_t)sigusr2_handler;
97     sigusr2_action.sa_flags = SA_ONSTACK | SA_RESTART;
98     sigusr2_action.sa_restorer = NULL;
99     if (sigaction(SIGUSR2, &sigusr2_action, &old_action) < 0) {
100     sprintf(str, GetString(STR_SIGUSR2_INSTALL_ERR), strerror(errno));
101     ErrorAlert(str);
102     exit(1);
103     }
104    
105     // Raise SIGUSR2
106 gbeauche 1.4 TOC = get_r2();
107     R13 = get_r13();
108     set_r2((void *)0xaffebad5);
109 cebix 1.1 raise(SIGUSR2);
110 gbeauche 1.4 if (TOC != get_r2())
111     err = 6;
112     if (R13 != get_r13())
113     err = 7;
114 cebix 1.1
115     // Check error code
116     switch (err) {
117     case 1:
118     printf("FATAL: sigaltstack() doesn't seem to work (sp in signal handler was %08lx, expected %08lx..%08lx)\n", (uint32)sig_sp, (uint32)sig_stack, (uint32)sig_stack + SIG_STACK_SIZE);
119     break;
120     case 2:
121     printf("FATAL: r4 in signal handler (%08lx) doesn't point to stack\n", (uint32)sig_r4);
122     break;
123     case 3:
124     printf("FATAL: r4 in signal handler doesn't seem to point to a sigcontext_struct (signal number was %d, expected %d)", sig_sc_signal, SIGUSR2);
125     break;
126     case 4:
127     printf("FATAL: sc->regs in signal handler (%08lx) doesn't point to stack\n", (uint32)sig_sc_regs);
128     break;
129     case 5:
130     printf("FATAL: sc->regs->gpr[2] in signal handler (%08lx) doesn't have expected value (%08x)\n", (uint32)sig_r2, 0xaffebad5);
131     break;
132 gbeauche 1.4 case 6:
133     printf("FATAL: signal handler failed to restore initial r2 value (%08x, was %08x)\n", (uint32)get_r2(), (uint32)TOC);
134     break;
135     case 7:
136     printf("FATAL: signal handler failed to restore initial r13 value (%08x, was %08x)\n", get_r13(), (uint32)R13);
137 cebix 1.1 }
138     if (err) {
139     printf("Maybe you need a different kernel?\n");
140     exit(1);
141     }
142    
143     // Clean up
144     D(bug("...passed\n"));
145     sigaction(SIGUSR2, &old_action, NULL);
146     sigaltstack(&old_stack, NULL);
147     free(sig_stack);
148     }
149    
150    
151     static void sigusr2_handler(int sig, sigcontext_struct *sc)
152     {
153     // Check whether sigaltstack works
154     sig_sp = get_sp();
155     if (sig_sp < sig_stack || sig_sp >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) {
156     err = 1;
157 gbeauche 1.4 goto ret;
158 cebix 1.1 }
159    
160     // Check whether r4 points to info on the stack
161     sig_r4 = sc;
162     if (sig_r4 < sig_stack || sig_r4 >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) {
163     err = 2;
164 gbeauche 1.4 goto ret;
165 cebix 1.1 }
166    
167     // Check whether r4 looks like a sigcontext
168     sig_sc_signal = sc->signal;
169     if (sig_sc_signal != SIGUSR2) {
170     err = 3;
171 gbeauche 1.4 goto ret;
172 cebix 1.1 }
173    
174     // Check whether sc->regs points to info on the stack
175     sig_sc_regs = sc->regs;
176     if (sig_sc_regs < sig_stack || sig_sc_regs >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) {
177     err = 4;
178 gbeauche 1.4 goto ret;
179 cebix 1.1 }
180    
181     // Check whether r2 still holds the value we set it to
182     sig_r2 = sc->regs->gpr[2];
183     if (sig_r2 != 0xaffebad5) {
184     err = 5;
185 gbeauche 1.4 goto ret;
186 cebix 1.1 }
187 gbeauche 1.4
188     // Restore pointer to Thread Local Storage
189     ret:
190     #ifdef SYSTEM_CLOBBERS_R2
191     sc->regs->gpr[2] = (unsigned long)TOC;
192     #endif
193 cebix 1.1 }