mirror of
https://github.com/kanjitalk755/macemu.git
synced 2025-02-02 15:40:02 +00:00
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.
This commit is contained in:
parent
29207d9cf2
commit
0f358518df
@ -1,162 +0,0 @@
|
||||
/*
|
||||
* paranoia.cpp - Check undocumented features of the Darwin kernel that
|
||||
* SheepShaver relies upon
|
||||
*
|
||||
* SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
#include "sysdeps.h"
|
||||
#include "main.h"
|
||||
#include "user_strings.h"
|
||||
|
||||
#define DEBUG 1
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
// Constants
|
||||
const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack
|
||||
|
||||
// Prototypes
|
||||
extern "C" int sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss);
|
||||
extern "C" void *get_sp(void);
|
||||
extern "C" void set_r2(uint32 val);
|
||||
extern void paranoia_check(void);
|
||||
static void sigusr2_handler(int sig, siginfo_t *sip, void *scp);
|
||||
|
||||
// Global variables
|
||||
static void *sig_stack = NULL;
|
||||
|
||||
static int err = 0;
|
||||
static void *sig_sp = NULL;
|
||||
static void *sig_r4 = NULL;
|
||||
static int sig_sc_signal = 0;
|
||||
static void *sig_sc_regs = NULL;
|
||||
static uint32 sig_r2 = 0;
|
||||
|
||||
|
||||
void paranoia_check(void)
|
||||
{
|
||||
char str[256];
|
||||
|
||||
D(bug("Paranoia checks...\n"));
|
||||
|
||||
// Create and install stack for signal handler
|
||||
sig_stack = malloc(SIG_STACK_SIZE);
|
||||
if (sig_stack == NULL) {
|
||||
ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct sigaltstack old_stack;
|
||||
struct sigaltstack new_stack;
|
||||
new_stack.ss_sp = (char *)sig_stack;
|
||||
new_stack.ss_flags = 0;
|
||||
new_stack.ss_size = SIG_STACK_SIZE;
|
||||
if (sigaltstack(&new_stack, &old_stack) < 0) {
|
||||
sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno));
|
||||
ErrorAlert(str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Install SIGUSR2 signal handler
|
||||
static struct sigaction old_action;
|
||||
static struct sigaction sigusr2_action;
|
||||
sigemptyset(&sigusr2_action.sa_mask);
|
||||
sigusr2_action.sa_sigaction = sigusr2_handler;
|
||||
sigusr2_action.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
|
||||
if (sigaction(SIGUSR2, &sigusr2_action, &old_action) < 0) {
|
||||
sprintf(str, GetString(STR_SIGUSR2_INSTALL_ERR), strerror(errno));
|
||||
ErrorAlert(str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Raise SIGUSR2
|
||||
set_r2(0xaffebad5);
|
||||
raise(SIGUSR2);
|
||||
|
||||
// Check error code
|
||||
switch (err) {
|
||||
case 1:
|
||||
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);
|
||||
break;
|
||||
case 2:
|
||||
printf("FATAL: r4 in signal handler (%08lx) doesn't point to stack\n", (uint32)sig_r4);
|
||||
break;
|
||||
case 3:
|
||||
printf("FATAL: r4 in signal handler doesn't seem to point to a ucontext_t (signal number was %d, expected %d)", sig_sc_signal, SIGUSR2);
|
||||
break;
|
||||
case 4:
|
||||
printf("FATAL: sc->regs in signal handler (%08lx) doesn't point to stack\n", (uint32)sig_sc_regs);
|
||||
break;
|
||||
case 5:
|
||||
printf("FATAL: sc->regs->gpr[2] in signal handler (%08lx) doesn't have expected value (%08x)\n", (uint32)sig_r2, 0xaffebad5);
|
||||
break;
|
||||
}
|
||||
if (err) {
|
||||
printf("Maybe you need a different kernel?\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Clean up
|
||||
D(bug("...passed\n"));
|
||||
sigaction(SIGUSR2, &old_action, NULL);
|
||||
sigaltstack(&old_stack, NULL);
|
||||
free(sig_stack);
|
||||
}
|
||||
|
||||
|
||||
static void sigusr2_handler(int sig, siginfo_t *sip, void *scp)
|
||||
{
|
||||
ucontext_t *ucp = (ucontext_t *)scp;
|
||||
|
||||
// Check whether sigaltstack works
|
||||
sig_sp = get_sp();
|
||||
if (sig_sp < sig_stack || sig_sp >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) {
|
||||
err = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether r4 points to info on the stack
|
||||
sig_r4 = ucp;
|
||||
if (sig_r4 < sig_stack || sig_r4 >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) {
|
||||
err = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether context regs points to info on the stack
|
||||
sig_sc_regs = &ucp->uc_mcontext->ss.r0;
|
||||
if (sig_sc_regs < sig_stack || sig_sc_regs >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) {
|
||||
err = 4;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether r2 still holds the value we set it to
|
||||
sig_r2 = ucp->uc_mcontext->ss.r2;
|
||||
if (sig_r2 != 0xaffebad5) {
|
||||
err = 5;
|
||||
return;
|
||||
}
|
||||
}
|
@ -1,193 +0,0 @@
|
||||
/*
|
||||
* paranoia.cpp - Check undocumented features of the Linux kernel that
|
||||
* SheepShaver relies upon
|
||||
*
|
||||
* SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "sysdeps.h"
|
||||
#include "main.h"
|
||||
#include "user_strings.h"
|
||||
|
||||
typedef struct {
|
||||
uint32 u[4];
|
||||
} __attribute((aligned(16))) vector128;
|
||||
#include <linux/elf.h>
|
||||
|
||||
#define DEBUG 1
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
// Constants
|
||||
const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack
|
||||
|
||||
// Prototypes
|
||||
extern "C" void *get_sp(void);
|
||||
extern "C" void *get_r2(void);
|
||||
extern "C" void set_r2(void *);
|
||||
extern "C" void *get_r13(void);
|
||||
extern void paranoia_check(void);
|
||||
static void sigusr2_handler(int sig, sigcontext_struct *sc);
|
||||
|
||||
// Global variables
|
||||
static void *sig_stack = NULL;
|
||||
|
||||
static int err = 0;
|
||||
static void *sig_sp = NULL;
|
||||
static void *sig_r4 = NULL;
|
||||
static int sig_sc_signal = 0;
|
||||
static void *sig_sc_regs = NULL;
|
||||
static uint32 sig_r2 = 0;
|
||||
|
||||
|
||||
int raise(int sig)
|
||||
{
|
||||
// Reimplement to get rid of access to r2 (TLS pointer)
|
||||
return kill(getpid(), sig);
|
||||
}
|
||||
|
||||
void paranoia_check(void)
|
||||
{
|
||||
char str[256];
|
||||
|
||||
D(bug("Paranoia checks...\n"));
|
||||
|
||||
// Create and install stack for signal handler
|
||||
sig_stack = malloc(SIG_STACK_SIZE);
|
||||
if (sig_stack == NULL) {
|
||||
ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct sigaltstack old_stack;
|
||||
struct sigaltstack new_stack;
|
||||
new_stack.ss_sp = sig_stack;
|
||||
new_stack.ss_flags = 0;
|
||||
new_stack.ss_size = SIG_STACK_SIZE;
|
||||
if (sigaltstack(&new_stack, &old_stack) < 0) {
|
||||
sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno));
|
||||
ErrorAlert(str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Install SIGUSR2 signal handler
|
||||
static struct sigaction old_action;
|
||||
static struct sigaction sigusr2_action;
|
||||
sigemptyset(&sigusr2_action.sa_mask);
|
||||
sigusr2_action.sa_handler = (__sighandler_t)sigusr2_handler;
|
||||
sigusr2_action.sa_flags = SA_ONSTACK | SA_RESTART;
|
||||
sigusr2_action.sa_restorer = NULL;
|
||||
if (sigaction(SIGUSR2, &sigusr2_action, &old_action) < 0) {
|
||||
sprintf(str, GetString(STR_SIGUSR2_INSTALL_ERR), strerror(errno));
|
||||
ErrorAlert(str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Raise SIGUSR2
|
||||
TOC = get_r2();
|
||||
R13 = get_r13();
|
||||
set_r2((void *)0xaffebad5);
|
||||
raise(SIGUSR2);
|
||||
if (TOC != get_r2())
|
||||
err = 6;
|
||||
if (R13 != get_r13())
|
||||
err = 7;
|
||||
|
||||
// Check error code
|
||||
switch (err) {
|
||||
case 1:
|
||||
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);
|
||||
break;
|
||||
case 2:
|
||||
printf("FATAL: r4 in signal handler (%08lx) doesn't point to stack\n", (uint32)sig_r4);
|
||||
break;
|
||||
case 3:
|
||||
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);
|
||||
break;
|
||||
case 4:
|
||||
printf("FATAL: sc->regs in signal handler (%08lx) doesn't point to stack\n", (uint32)sig_sc_regs);
|
||||
break;
|
||||
case 5:
|
||||
printf("FATAL: sc->regs->gpr[2] in signal handler (%08lx) doesn't have expected value (%08x)\n", (uint32)sig_r2, 0xaffebad5);
|
||||
break;
|
||||
case 6:
|
||||
printf("FATAL: signal handler failed to restore initial r2 value (%08x, was %08x)\n", (uint32)get_r2(), (uint32)TOC);
|
||||
break;
|
||||
case 7:
|
||||
printf("FATAL: signal handler failed to restore initial r13 value (%08x, was %08x)\n", get_r13(), (uint32)R13);
|
||||
}
|
||||
if (err) {
|
||||
printf("Maybe you need a different kernel?\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Clean up
|
||||
D(bug("...passed\n"));
|
||||
sigaction(SIGUSR2, &old_action, NULL);
|
||||
sigaltstack(&old_stack, NULL);
|
||||
free(sig_stack);
|
||||
}
|
||||
|
||||
|
||||
static void sigusr2_handler(int sig, sigcontext_struct *sc)
|
||||
{
|
||||
// Check whether sigaltstack works
|
||||
sig_sp = get_sp();
|
||||
if (sig_sp < sig_stack || sig_sp >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) {
|
||||
err = 1;
|
||||
goto ret;
|
||||
}
|
||||
|
||||
// Check whether r4 points to info on the stack
|
||||
sig_r4 = sc;
|
||||
if (sig_r4 < sig_stack || sig_r4 >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) {
|
||||
err = 2;
|
||||
goto ret;
|
||||
}
|
||||
|
||||
// Check whether r4 looks like a sigcontext
|
||||
sig_sc_signal = sc->signal;
|
||||
if (sig_sc_signal != SIGUSR2) {
|
||||
err = 3;
|
||||
goto ret;
|
||||
}
|
||||
|
||||
// Check whether sc->regs points to info on the stack
|
||||
sig_sc_regs = sc->regs;
|
||||
if (sig_sc_regs < sig_stack || sig_sc_regs >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) {
|
||||
err = 4;
|
||||
goto ret;
|
||||
}
|
||||
|
||||
// Check whether r2 still holds the value we set it to
|
||||
sig_r2 = sc->regs->gpr[2];
|
||||
if (sig_r2 != 0xaffebad5) {
|
||||
err = 5;
|
||||
goto ret;
|
||||
}
|
||||
|
||||
// Restore pointer to Thread Local Storage
|
||||
ret:
|
||||
#ifdef SYSTEM_CLOBBERS_R2
|
||||
sc->regs->gpr[2] = (unsigned long)TOC;
|
||||
#endif
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
/*
|
||||
* paranoia.cpp - Check undocumented features of the NetBSD kernel that
|
||||
* SheepShaver relies upon
|
||||
*
|
||||
* SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
#include "sysdeps.h"
|
||||
#include "main.h"
|
||||
#include "user_strings.h"
|
||||
|
||||
#define DEBUG 1
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
// Constants
|
||||
const int SIG_IRQ = SIGUSR2; // Signal to trigger on interrupt
|
||||
const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack
|
||||
|
||||
// Prototypes
|
||||
extern "C" void *get_sp(void);
|
||||
extern "C" void set_r2(uint32 val);
|
||||
extern void paranoia_check(void);
|
||||
static void sigusr2_handler(int sig, siginfo_t *sip, void *scp);
|
||||
|
||||
// Global variables
|
||||
static void *sig_stack = NULL;
|
||||
|
||||
static int err = 0;
|
||||
static void *sig_sp = NULL;
|
||||
static void *sig_r4 = NULL;
|
||||
static void *sig_sc_regs = NULL;
|
||||
static uint32 sig_r2 = 0;
|
||||
|
||||
|
||||
void paranoia_check(void)
|
||||
{
|
||||
char str[256];
|
||||
|
||||
D(bug("Paranoia checks...\n"));
|
||||
|
||||
// Create and install stack for signal handler
|
||||
sig_stack = malloc(SIG_STACK_SIZE);
|
||||
if (sig_stack == NULL) {
|
||||
ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct sigaltstack old_stack;
|
||||
struct sigaltstack new_stack;
|
||||
new_stack.ss_sp = sig_stack;
|
||||
new_stack.ss_flags = 0;
|
||||
new_stack.ss_size = SIG_STACK_SIZE;
|
||||
if (sigaltstack(&new_stack, &old_stack) < 0) {
|
||||
sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno));
|
||||
ErrorAlert(str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Install SIG_IRQ signal handler
|
||||
static struct sigaction old_action;
|
||||
static struct sigaction sigusr2_action;
|
||||
sigemptyset(&sigusr2_action.sa_mask);
|
||||
sigusr2_action.sa_sigaction = sigusr2_handler;
|
||||
sigusr2_action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
|
||||
if (sigaction(SIG_IRQ, &sigusr2_action, &old_action) < 0) {
|
||||
sprintf(str, GetString(STR_SIGUSR2_INSTALL_ERR), strerror(errno));
|
||||
ErrorAlert(str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Raise SIG_IRQ
|
||||
set_r2(0xaffebad5);
|
||||
raise(SIG_IRQ);
|
||||
|
||||
// Check error code
|
||||
switch (err) {
|
||||
case 1:
|
||||
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);
|
||||
break;
|
||||
case 2:
|
||||
printf("FATAL: r4 in signal handler (%08lx) doesn't point to stack\n", (uint32)sig_r4);
|
||||
break;
|
||||
case 4:
|
||||
printf("FATAL: sc->regs in signal handler (%08lx) doesn't point to stack\n", (uint32)sig_sc_regs);
|
||||
break;
|
||||
case 5:
|
||||
printf("FATAL: sc->regs->gpr[2] in signal handler (%08lx) doesn't have expected value (%08x)\n", (uint32)sig_r2, 0xaffebad5);
|
||||
break;
|
||||
}
|
||||
if (err) {
|
||||
printf("Maybe you need a different kernel?\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Clean up
|
||||
D(bug("...passed\n"));
|
||||
sigaction(SIG_IRQ, &old_action, NULL);
|
||||
sigaltstack(&old_stack, NULL);
|
||||
free(sig_stack);
|
||||
}
|
||||
|
||||
static void sigusr2_handler(int sig, siginfo_t *sip, void *scp)
|
||||
{
|
||||
ucontext_t *ucp = (ucontext_t *)scp;
|
||||
D(bug("SIGUSR2 handler caught\n"));
|
||||
|
||||
// Check whether sigaltstack works
|
||||
D(bug(" check whether sigaltstack() works\n"));
|
||||
sig_sp = get_sp();
|
||||
if (sig_sp < sig_stack || sig_sp >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) {
|
||||
err = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether r4 points to info on the stack
|
||||
D(bug(" check whether r4 points to info on the stack\n"));
|
||||
sig_r4 = ucp;
|
||||
if (sig_r4 < sig_stack || sig_r4 >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) {
|
||||
err = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether context regs points to info on the stack
|
||||
D(bug(" check whether context regs points to info on the stack\n"));
|
||||
sig_sc_regs = ucp->uc_mcontext.__gregs;
|
||||
if (sig_sc_regs < sig_stack || sig_sc_regs >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) {
|
||||
err = 4;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether r2 still holds the value we set it to
|
||||
D(bug(" check whether r2 still holds the value we set it to\n"));
|
||||
sig_r2 = ucp->uc_mcontext.__gregs[_REG_R2];
|
||||
if (sig_r2 != 0xaffebad5) {
|
||||
err = 5;
|
||||
return;
|
||||
}
|
||||
}
|
@ -466,7 +466,7 @@ linux*)
|
||||
AUDIOSRC=audio_oss_esd.cpp
|
||||
SCSISRC=Linux/scsi_linux.cpp
|
||||
if [[ "x$EMULATED_PPC" = "xno" ]]; then
|
||||
EXTRASYSSRCS="Linux/paranoia.cpp Linux/sheepthreads.c ppc_asm.S"
|
||||
EXTRASYSSRCS="paranoia.cpp Linux/sheepthreads.c ppc_asm.S"
|
||||
fi
|
||||
;;
|
||||
freebsd*)
|
||||
@ -475,13 +475,13 @@ freebsd*)
|
||||
netbsd*)
|
||||
ETHERSRC=ether_unix.cpp
|
||||
if [[ "x$EMULATED_PPC" = "xno" ]]; then
|
||||
EXTRASYSSRCS="NetBSD/paranoia.cpp NetBSD/sheepthreads.c ppc_asm.S"
|
||||
EXTRASYSSRCS="paranoia.cpp NetBSD/sheepthreads.c ppc_asm.S"
|
||||
fi
|
||||
;;
|
||||
darwin*)
|
||||
ETHERSRC=ether_unix.cpp
|
||||
if [[ "x$EMULATED_PPC" = "xno" ]]; then
|
||||
EXTRASYSSRCS="Darwin/paranoia.cpp ppc_asm.S"
|
||||
EXTRASYSSRCS="paranoia.cpp ppc_asm.S"
|
||||
fi
|
||||
if [[ "x$ac_cv_framework_IOKit" = "xyes" ]]; then
|
||||
EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/sys_darwin.cpp"
|
||||
|
347
SheepShaver/src/Unix/paranoia.cpp
Normal file
347
SheepShaver/src/Unix/paranoia.cpp
Normal file
@ -0,0 +1,347 @@
|
||||
/*
|
||||
* paranoia.cpp - Check undocumented features of the underlying
|
||||
* kernel that SheepShaver relies upon
|
||||
*
|
||||
* SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO
|
||||
* - Check for nested signal handlers vs. sigaltstack()
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
#include "sysdeps.h"
|
||||
#include "sigregs.h"
|
||||
#include "main.h"
|
||||
#include "user_strings.h"
|
||||
|
||||
#define DEBUG 1
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
// Constants
|
||||
const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack
|
||||
|
||||
// Prototypes
|
||||
extern "C" void *get_sp(void);
|
||||
extern "C" void *get_r2(void);
|
||||
extern "C" void set_r2(void *);
|
||||
extern "C" void *get_r13(void);
|
||||
extern "C" void set_r13(void *);
|
||||
extern void paranoia_check(void);
|
||||
extern "C" void sigusr2_handler_init(int sig, siginfo_t *sip, void *scp);
|
||||
extern "C" void sigusr2_handler(int sig, siginfo_t *sip, void *scp);
|
||||
static void *tick_func(void *);
|
||||
static void *emul_func(void *);
|
||||
|
||||
// Global variables
|
||||
static void *sig_stack = NULL;
|
||||
|
||||
static int err = 0;
|
||||
static void *sig_sp = NULL;
|
||||
static void *sig_r5 = NULL;
|
||||
static int sig_sc_signal = 0;
|
||||
static void *sig_sc_regs = NULL;
|
||||
static uint32 sig_r2 = 0;
|
||||
|
||||
static pthread_t tick_thread;
|
||||
static pthread_t emul_thread;
|
||||
static volatile uint32 tick_thread_ready = 0;
|
||||
static volatile uint32 emul_thread_regs[32] = { 0, };
|
||||
static volatile uint32 &emul_thread_ready = emul_thread_regs[0];
|
||||
|
||||
|
||||
void paranoia_check(void)
|
||||
{
|
||||
char str[256];
|
||||
|
||||
printf("Paranoia checks...\n");
|
||||
|
||||
// Create and install stack for signal handler
|
||||
sig_stack = malloc(SIG_STACK_SIZE);
|
||||
if (sig_stack == NULL) {
|
||||
ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct sigaltstack old_stack;
|
||||
struct sigaltstack new_stack;
|
||||
new_stack.ss_sp = (char *)sig_stack;
|
||||
new_stack.ss_flags = 0;
|
||||
new_stack.ss_size = SIG_STACK_SIZE;
|
||||
if (sigaltstack(&new_stack, &old_stack) < 0) {
|
||||
sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno));
|
||||
ErrorAlert(str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Install SIGUSR2 signal handler
|
||||
static struct sigaction old_action;
|
||||
static struct sigaction sigusr2_action;
|
||||
sigemptyset(&sigusr2_action.sa_mask);
|
||||
sigusr2_action.sa_sigaction = sigusr2_handler;
|
||||
sigusr2_action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
|
||||
if (sigaction(SIGUSR2, &sigusr2_action, &old_action) < 0) {
|
||||
sprintf(str, GetString(STR_SIGUSR2_INSTALL_ERR), strerror(errno));
|
||||
ErrorAlert(str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Start tick thread that will trigger only one SIGUSR2
|
||||
pthread_create(&tick_thread, NULL, tick_func, NULL);
|
||||
|
||||
// Get my thread ID and execute MacOS thread function
|
||||
emul_thread = pthread_self();
|
||||
emul_func(NULL);
|
||||
|
||||
// Check error code
|
||||
switch (err) {
|
||||
case 1:
|
||||
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);
|
||||
break;
|
||||
case 2:
|
||||
printf("FATAL: r5 in signal handler (%p) doesn't point to stack\n", sig_r5);
|
||||
break;
|
||||
case 3:
|
||||
printf("FATAL: machine registers in signal handler (%p) doesn't point to stack\n", sig_sc_regs);
|
||||
break;
|
||||
case 4:
|
||||
printf("FATAL: register file in signal handler is corrupted\n");
|
||||
break;
|
||||
}
|
||||
if (err) {
|
||||
printf("Maybe you need a different kernel?\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Clean up
|
||||
printf("...passed\n");
|
||||
sigaction(SIGUSR2, &old_action, NULL);
|
||||
sigaltstack(&old_stack, NULL);
|
||||
free(sig_stack);
|
||||
}
|
||||
|
||||
static void *tick_func(void *)
|
||||
{
|
||||
tick_thread_ready = true;
|
||||
|
||||
// Wait for emul thread to initialize
|
||||
D(bug("[tick_thread] waiting for emul thread to initialize\n"));
|
||||
while (!emul_thread_ready)
|
||||
usleep(0);
|
||||
|
||||
// Trigger interrupt and terminate
|
||||
D(bug("[tick_thread] trigger interrupt\n"));
|
||||
pthread_kill(emul_thread, SIGUSR2);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *emul_func(void *)
|
||||
{
|
||||
// Wait for tick thread to initialize
|
||||
D(bug("[emul_thread] waiting for tick thread to initialize\n"));
|
||||
while (!tick_thread_ready)
|
||||
usleep(0);
|
||||
|
||||
// Fill in register and wait for an interrupt from the tick thread
|
||||
D(bug("[emul_thread] filling in registers and waiting for interrupt\n"));
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#define REG(n) "r" #n
|
||||
#else
|
||||
#define REG(n) #n
|
||||
#endif
|
||||
asm volatile ("stw " REG(2) ",2*4(%0)\n"
|
||||
"mr " REG(2) ",%0\n"
|
||||
#define SAVE_REG(n) \
|
||||
"stw " REG(n) "," #n "*4(" REG(2) ")\n" \
|
||||
"addi " REG(n) "," REG(2) ","#n"\n"
|
||||
SAVE_REG(1)
|
||||
SAVE_REG(3)
|
||||
SAVE_REG(4)
|
||||
SAVE_REG(5)
|
||||
SAVE_REG(6)
|
||||
SAVE_REG(7)
|
||||
SAVE_REG(8)
|
||||
SAVE_REG(9)
|
||||
SAVE_REG(10)
|
||||
SAVE_REG(11)
|
||||
SAVE_REG(12)
|
||||
SAVE_REG(13)
|
||||
SAVE_REG(14)
|
||||
SAVE_REG(15)
|
||||
SAVE_REG(16)
|
||||
SAVE_REG(17)
|
||||
SAVE_REG(18)
|
||||
SAVE_REG(19)
|
||||
SAVE_REG(20)
|
||||
SAVE_REG(21)
|
||||
SAVE_REG(22)
|
||||
SAVE_REG(23)
|
||||
SAVE_REG(24)
|
||||
SAVE_REG(25)
|
||||
SAVE_REG(26)
|
||||
SAVE_REG(27)
|
||||
SAVE_REG(28)
|
||||
SAVE_REG(29)
|
||||
SAVE_REG(30)
|
||||
SAVE_REG(31)
|
||||
#undef SAVE_REG
|
||||
" li " REG(0) ",1\n"
|
||||
" stw " REG(0) ",0(" REG(2) ")\n" // regs[0] == emul_thread_ready
|
||||
"0: lwz " REG(0) ",0(" REG(2) ")\n"
|
||||
" cmpi 0," REG(0) ",0\n"
|
||||
" bne+ 0b\n"
|
||||
#define LOAD_REG(n) \
|
||||
"lwz " REG(n) "," #n "*4(" REG(2) ")\n"
|
||||
LOAD_REG(1)
|
||||
LOAD_REG(3)
|
||||
LOAD_REG(4)
|
||||
LOAD_REG(5)
|
||||
LOAD_REG(6)
|
||||
LOAD_REG(7)
|
||||
LOAD_REG(8)
|
||||
LOAD_REG(9)
|
||||
LOAD_REG(10)
|
||||
LOAD_REG(11)
|
||||
LOAD_REG(12)
|
||||
LOAD_REG(13)
|
||||
LOAD_REG(14)
|
||||
LOAD_REG(15)
|
||||
LOAD_REG(16)
|
||||
LOAD_REG(17)
|
||||
LOAD_REG(18)
|
||||
LOAD_REG(19)
|
||||
LOAD_REG(20)
|
||||
LOAD_REG(21)
|
||||
LOAD_REG(22)
|
||||
LOAD_REG(23)
|
||||
LOAD_REG(24)
|
||||
LOAD_REG(25)
|
||||
LOAD_REG(26)
|
||||
LOAD_REG(27)
|
||||
LOAD_REG(28)
|
||||
LOAD_REG(29)
|
||||
LOAD_REG(30)
|
||||
LOAD_REG(31)
|
||||
LOAD_REG(2)
|
||||
#undef LOAD_REG
|
||||
: : "r" ((uintptr)&emul_thread_regs[0]) : "r0");
|
||||
#undef REG
|
||||
}
|
||||
|
||||
|
||||
void sigusr2_handler(int sig, siginfo_t *sip, void *scp)
|
||||
{
|
||||
machine_regs *r = MACHINE_REGISTERS(scp);
|
||||
|
||||
#ifdef SYSTEM_CLOBBERS_R2
|
||||
// Restore pointer to Thread Local Storage
|
||||
set_r2(TOC);
|
||||
#endif
|
||||
|
||||
#ifdef SYSTEM_CLOBBERS_R13
|
||||
// Restore pointer to .sdata section
|
||||
set_r13(R13);
|
||||
#endif
|
||||
|
||||
ucontext_t *ucp = (ucontext_t *)scp;
|
||||
D(bug("SIGUSR2 caught\n"));
|
||||
|
||||
// Check whether sigaltstack works
|
||||
sig_sp = get_sp();
|
||||
if (sig_sp < sig_stack || sig_sp >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) {
|
||||
err = 1;
|
||||
goto ret;
|
||||
}
|
||||
|
||||
// Check whether r5 points to info on the stack
|
||||
sig_r5 = ucp;
|
||||
if (sig_r5 < sig_stack || sig_r5 >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) {
|
||||
err = 2;
|
||||
goto ret;
|
||||
}
|
||||
|
||||
// Check whether context regs points to info on the stack
|
||||
sig_sc_regs = &r->gpr(0);
|
||||
if (sig_sc_regs < sig_stack || sig_sc_regs >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) {
|
||||
err = 3;
|
||||
goto ret;
|
||||
}
|
||||
|
||||
// Check whether registers still hold the values we set them to
|
||||
for (int n = 0; n < 32; n++) {
|
||||
uint32 expected = (uintptr)&emul_thread_regs[0];
|
||||
if (n == 0)
|
||||
expected = 1;
|
||||
else if (n != 2)
|
||||
expected += n;
|
||||
if (r->gpr(n) != expected) {
|
||||
D(bug("Register corruption: r%d was %08x, expected %08x\n", n, r->gpr(n), expected));
|
||||
err = 4;
|
||||
goto ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret:
|
||||
// Tell emul_func() to exit
|
||||
emul_thread_ready = false;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
void *TOC;
|
||||
void *R13;
|
||||
|
||||
extern "C" void EmulOp(void *r, uint32 pc, int selector);
|
||||
void EmulOp(void *r, uint32 pc, int selector)
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" void check_load_invoc(uint32 type, int16 id, uint32 h);
|
||||
void check_load_invoc(uint32 type, int16 id, uint32 h)
|
||||
{
|
||||
}
|
||||
|
||||
void ErrorAlert(const char *text)
|
||||
{
|
||||
printf(GetString(STR_SHELL_ERROR_PREFIX), text);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
#ifdef SYSTEM_CLOBBERS_R2
|
||||
// Get TOC pointer
|
||||
TOC = get_r2();
|
||||
#endif
|
||||
|
||||
#ifdef SYSTEM_CLOBBERS_R13
|
||||
// Get r13 register
|
||||
R13 = get_r13();
|
||||
#endif
|
||||
|
||||
// Check some things
|
||||
paranoia_check();
|
||||
}
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user