ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/main_unix.cpp
(Generate patch)

Comparing SheepShaver/src/Unix/main_unix.cpp (file contents):
Revision 1.13 by gbeauche, 2003-11-03T21:28:25Z vs.
Revision 1.41 by gbeauche, 2004-06-22T17:10:07Z

# Line 1 | Line 1
1   /*
2   *  main_unix.cpp - Emulation core, Unix implementation
3   *
4 < *  SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig
4 > *  SheepShaver (C) 1997-2004 Christian Bauer and Marc Hellwig
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 65 | Line 65
65   *  ExecutePPC (or any function that might cause a mode switch). The signal
66   *  stack is restored before exiting the SIGUSR2 handler.
67   *
68 + *  There is apparently another problem when processing signals. In
69 + *  fullscreen mode, we get quick updates of the mouse position. This
70 + *  causes an increased number of calls to TriggerInterrupt(). And,
71 + *  since IRQ_NEST is not fully handled atomically, nested calls to
72 + *  ppc_interrupt() may cause stack corruption to eventually crash the
73 + *  emulator.
74 + *
75 + *  FIXME:
76 + *  The current solution is to allocate another signal stack when
77 + *  processing ppc_interrupt(). However, it may be better to detect
78 + *  the INTFLAG_ADB case and handle it specifically with some extra mutex?
79 + *
80   *  TODO:
81   *    check if SIGSEGV handler works for all registers (including FP!)
82   */
# Line 109 | Line 121
121   #include "user_strings.h"
122   #include "vm_alloc.h"
123   #include "sigsegv.h"
124 + #include "thunks.h"
125  
126   #define DEBUG 0
127   #include "debug.h"
# Line 131 | Line 144
144   #endif
145  
146  
147 + // Enable emulation of unaligned lmw/stmw?
148 + #define EMULATE_UNALIGNED_LOADSTORE_MULTIPLE 1
149 +
150   // Enable Execute68k() safety checks?
151   #define SAFE_EXEC_68K 0
152  
# Line 140 | Line 156
156   // Interrupts in native mode?
157   #define INTERRUPTS_IN_NATIVE_MODE 1
158  
159 + // Number of alternate stacks for signal handlers?
160 + #define SIG_STACK_COUNT 4
161 +
162  
163   // Constants
164   const char ROM_FILE_NAME[] = "ROM";
165   const char ROM_FILE_NAME2[] = "Mac OS ROM";
166  
167 < const uint32 RAM_BASE = 0x20000000;                     // Base address of RAM
167 > const uintptr RAM_BASE = 0x20000000;            // Base address of RAM
168   const uint32 SIG_STACK_SIZE = 0x10000;          // Size of signal stack
169  
170  
171   #if !EMULATED_PPC
153 // Structure in which registers are saved in a signal handler;
154 // sigcontext->regs points to it
155 // (see arch/ppc/kernel/signal.c)
156 typedef struct {
157        uint32 u[4];
158 } __attribute((aligned(16))) vector128;
159 #include <linux/elf.h>
160
172   struct sigregs {
173 <        elf_gregset_t   gp_regs;                                // Identical to pt_regs
174 <        double                  fp_regs[ELF_NFPREG];    // f0..f31 and fpsrc
175 <        //more (uninteresting) stuff following here
173 >        uint32 nip;
174 >        uint32 link;
175 >        uint32 ctr;
176 >        uint32 msr;
177 >        uint32 xer;
178 >        uint32 ccr;
179 >        uint32 gpr[32];
180 > };
181 >
182 > #if defined(__linux__)
183 > #include <sys/ucontext.h>
184 > #define MACHINE_REGISTERS(scp)  ((machine_regs *)(((ucontext_t *)scp)->uc_mcontext.regs))
185 >
186 > struct machine_regs : public pt_regs
187 > {
188 >        u_long & cr()                           { return pt_regs::ccr; }
189 >        uint32 cr() const                       { return pt_regs::ccr; }
190 >        uint32 lr() const                       { return pt_regs::link; }
191 >        uint32 ctr() const                      { return pt_regs::ctr; }
192 >        uint32 xer() const                      { return pt_regs::xer; }
193 >        uint32 msr() const                      { return pt_regs::msr; }
194 >        uint32 dar() const                      { return pt_regs::dar; }
195 >        u_long & pc()                           { return pt_regs::nip; }
196 >        uint32 pc() const                       { return pt_regs::nip; }
197 >        u_long & gpr(int i)                     { return pt_regs::gpr[i]; }
198 >        uint32 gpr(int i) const         { return pt_regs::gpr[i]; }
199   };
200   #endif
201  
202 + #if defined(__APPLE__) && defined(__MACH__)
203 + #include <sys/signal.h>
204 + extern "C" int sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss);
205 +
206 + #include <sys/ucontext.h>
207 + #define MACHINE_REGISTERS(scp)  ((machine_regs *)(((ucontext_t *)scp)->uc_mcontext))
208 +
209 + struct machine_regs : public mcontext
210 + {
211 +        uint32 & cr()                           { return ss.cr; }
212 +        uint32 cr() const                       { return ss.cr; }
213 +        uint32 lr() const                       { return ss.lr; }
214 +        uint32 ctr() const                      { return ss.ctr; }
215 +        uint32 xer() const                      { return ss.xer; }
216 +        uint32 msr() const                      { return ss.srr1; }
217 +        uint32 dar() const                      { return es.dar; }
218 +        uint32 & pc()                           { return ss.srr0; }
219 +        uint32 pc() const                       { return ss.srr0; }
220 +        uint32 & gpr(int i)                     { return (&ss.r0)[i]; }
221 +        uint32 gpr(int i) const         { return (&ss.r0)[i]; }
222 + };
223 + #endif
224 +
225 + static void build_sigregs(sigregs *srp, machine_regs *mrp)
226 + {
227 +        srp->nip = mrp->pc();
228 +        srp->link = mrp->lr();
229 +        srp->ctr = mrp->ctr();
230 +        srp->msr = mrp->msr();
231 +        srp->xer = mrp->xer();
232 +        srp->ccr = mrp->cr();
233 +        for (int i = 0; i < 32; i++)
234 +                srp->gpr[i] = mrp->gpr(i);
235 + }
236 +
237 + static struct sigaltstack sig_stacks[SIG_STACK_COUNT];  // Stacks for signal handlers
238 + static int sig_stack_id = 0;                                                    // Stack slot currently used
239 +
240 + static inline void sig_stack_acquire(void)
241 + {
242 +        if (++sig_stack_id == SIG_STACK_COUNT) {
243 +                printf("FATAL: signal stack overflow\n");
244 +                return;
245 +        }
246 +        sigaltstack(&sig_stacks[sig_stack_id], NULL);
247 + }
248 +
249 + static inline void sig_stack_release(void)
250 + {
251 +        if (--sig_stack_id < 0) {
252 +                printf("FATAL: signal stack underflow\n");
253 +                return;
254 +        }
255 +        sigaltstack(&sig_stacks[sig_stack_id], NULL);
256 + }
257 + #endif
258 +
259  
260   // Global variables (exported)
261   #if !EMULATED_PPC
# Line 172 | Line 263 | void *TOC;                             // Small data pointer (r13
263   #endif
264   uint32 RAMBase;                 // Base address of Mac RAM
265   uint32 RAMSize;                 // Size of Mac RAM
175 uint32 SheepStack1Base; // SheepShaver first alternate stack base
176 uint32 SheepStack2Base; // SheepShaver second alternate stack base
177 uint32 SheepThunksBase; // SheepShaver thunks base
266   uint32 KernelDataAddr;  // Address of Kernel Data
267   uint32 BootGlobsAddr;   // Address of BootGlobs structure at top of Mac RAM
268 + uint32 DRCacheAddr;             // Address of DR Cache
269   uint32 PVR;                             // Theoretical PVR
270   int64 CPUClockSpeed;    // Processor clock speed (Hz)
271   int64 BusClockSpeed;    // Bus clock speed (Hz)
# Line 185 | Line 274 | int64 BusClockSpeed;   // Bus clock speed
274   // Global variables
275   char *x_display_name = NULL;                            // X11 display name
276   Display *x_display = NULL;                                      // X11 display handle
277 + #ifdef X11_LOCK_TYPE
278 + X11_LOCK_TYPE x_display_lock = X11_LOCK_INIT; // X11 display lock
279 + #endif
280  
281   static int zero_fd = 0;                                         // FD of /dev/zero
190 static bool sheep_area_mapped = false;          // Flag: SheepShaver data area mmap()ed
282   static bool lm_area_mapped = false;                     // Flag: Low Memory area mmap()ped
283   static int kernel_area = -1;                            // SHM ID of Kernel Data area
284   static bool rom_area_mapped = false;            // Flag: Mac ROM mmap()ped
285   static bool ram_area_mapped = false;            // Flag: Mac RAM mmap()ped
286 + static bool dr_cache_area_mapped = false;       // Flag: Mac DR Cache mmap()ped
287 + static bool dr_emulator_area_mapped = false;// Flag: Mac DR Emulator mmap()ped
288   static KernelData *kernel_data;                         // Pointer to Kernel Data
289   static EmulatorData *emulator_data;
290  
291   static uint8 last_xpram[XPRAM_SIZE];            // Buffer for monitoring XPRAM changes
292  
293   static bool nvram_thread_active = false;        // Flag: NVRAM watchdog installed
294 + static volatile bool nvram_thread_cancel;       // Flag: Cancel NVRAM thread
295   static pthread_t nvram_thread;                          // NVRAM watchdog
296   static bool tick_thread_active = false;         // Flag: MacOS thread installed
297 + static volatile bool tick_thread_cancel;        // Flag: Cancel 60Hz thread
298   static pthread_t tick_thread;                           // 60Hz thread
299   static pthread_t emul_thread;                           // MacOS thread
300  
# Line 207 | Line 302 | static bool ready_for_signals = false;
302   static int64 num_segv = 0;                                      // Number of handled SEGV signals
303  
304   static struct sigaction sigusr2_action;         // Interrupt signal (of emulator thread)
305 < #if !EMULATED_PPC
305 > #if EMULATED_PPC
306 > static uintptr sig_stack = 0;                           // Stack for PowerPC interrupt routine
307 > #else
308   static struct sigaction sigsegv_action;         // Data access exception signal (of emulator thread)
309   static struct sigaction sigill_action;          // Illegal instruction signal (of emulator thread)
213 static void *sig_stack = NULL;                          // Stack for signal handlers
214 static void *extra_stack = NULL;                        // Stack for SIGSEGV inside interrupt handler
310   static bool emul_thread_fatal = false;          // Flag: MacOS thread crashed, tick thread shall dump debug output
311   static sigregs sigsegv_regs;                            // Register dump when crashed
312 + static const char *crash_reason = NULL;         // Reason of the crash (SIGSEGV, SIGBUS, SIGILL)
313   #endif
314  
315 + uint32  SheepMem::page_size;                            // Size of a native page
316 + uintptr SheepMem::zero_page = 0;                        // Address of ro page filled in with zeros
317 + uintptr SheepMem::base = 0x60000000;            // Address of SheepShaver data
318 + uintptr SheepMem::top = 0;                                      // Top of SheepShaver data (stack like storage)
319 +
320  
321   // Prototypes
322   static void Quit(void);
# Line 223 | Line 324 | static void *emul_func(void *arg);
324   static void *nvram_func(void *arg);
325   static void *tick_func(void *arg);
326   #if EMULATED_PPC
226 static void sigusr2_handler(int sig);
327   extern void emul_ppc(uint32 start);
328   extern void init_emul_ppc(void);
329   extern void exit_emul_ppc(void);
330   #else
331 < static void sigusr2_handler(int sig, sigcontext_struct *sc);
332 < static void sigsegv_handler(int sig, sigcontext_struct *sc);
333 < static void sigill_handler(int sig, sigcontext_struct *sc);
331 > static void sigusr2_handler(int sig, siginfo_t *sip, void *scp);
332 > static void sigsegv_handler(int sig, siginfo_t *sip, void *scp);
333 > static void sigill_handler(int sig, siginfo_t *sip, void *scp);
334   #endif
335  
336  
# Line 252 | Line 352 | extern void paranoia_check(void);
352  
353   #if EMULATED_PPC
354   /*
355 + *  Return signal stack base
356 + */
357 +
358 + uintptr SignalStackBase(void)
359 + {
360 +        return sig_stack + SIG_STACK_SIZE;
361 + }
362 +
363 +
364 + /*
365   *  Atomic operations
366   */
367  
# Line 375 | Line 485 | int main(int argc, char **argv)
485          PVR = 0x00040000;                       // Default: 604
486          CPUClockSpeed = 100000000;      // Default: 100MHz
487          BusClockSpeed = 100000000;      // Default: 100MHz
488 < #if !EMULATED_PPC
488 > #if EMULATED_PPC
489 >        PVR = 0x000c0000;                       // Default: 7400 (with AltiVec)
490 > #elif defined(__APPLE__) && defined(__MACH__)
491 >        proc_file = popen("ioreg -c IOPlatformDevice", "r");
492 >        if (proc_file) {
493 >                char line[256];
494 >                bool powerpc_node = false;
495 >                while (fgets(line, sizeof(line) - 1, proc_file)) {
496 >                        // Read line
497 >                        int len = strlen(line);
498 >                        if (len == 0)
499 >                                continue;
500 >                        line[len - 1] = 0;
501 >
502 >                        // Parse line
503 >                        if (strstr(line, "o PowerPC,"))
504 >                                powerpc_node = true;
505 >                        else if (powerpc_node) {
506 >                                uint32 value;
507 >                                char head[256];
508 >                                if (sscanf(line, "%[ |]\"cpu-version\" = <%x>", head, &value) == 2)
509 >                                        PVR = value;
510 >                                else if (sscanf(line, "%[ |]\"clock-frequency\" = <%x>", head, &value) == 2)
511 >                                        CPUClockSpeed = value;
512 >                                else if (sscanf(line, "%[ |]\"bus-frequency\" = <%x>", head, &value) == 2)
513 >                                        BusClockSpeed = value;
514 >                                else if (strchr(line, '}'))
515 >                                        powerpc_node = false;
516 >                        }
517 >                }
518 >                fclose(proc_file);
519 >        } else {
520 >                sprintf(str, GetString(STR_PROC_CPUINFO_WARN), strerror(errno));
521 >                WarningAlert(str);
522 >        }
523 > #else
524          proc_file = fopen("/proc/cpuinfo", "r");
525          if (proc_file) {
526                  char line[256];
# Line 389 | Line 534 | int main(int argc, char **argv)
534                          // Parse line
535                          int i;
536                          char value[256];
537 <                        if (sscanf(line, "cpu : %s", value) == 1) {
537 >                        if (sscanf(line, "cpu : %[0-9A-Za-a]", value) == 1) {
538                                  if (strcmp(value, "601") == 0)
539                                          PVR = 0x00010000;
540                                  else if (strcmp(value, "603") == 0)
# Line 410 | Line 555 | int main(int argc, char **argv)
555                                          PVR = 0x00320000;
556                                  else if (strcmp(value, "860") == 0)
557                                          PVR = 0x00500000;
558 +                                else if (strcmp(value, "7400") == 0)
559 +                                        PVR = 0x000c0000;
560 +                                else if (strcmp(value, "7410") == 0)
561 +                                        PVR = 0x800c0000;
562                                  else
563                                          printf("WARNING: Unknown CPU type '%s', assuming 604\n", value);
564                          }
# Line 421 | Line 570 | int main(int argc, char **argv)
570                  sprintf(str, GetString(STR_PROC_CPUINFO_WARN), strerror(errno));
571                  WarningAlert(str);
572          }
573 +
574 +        // Get actual bus frequency
575 +        proc_file = fopen("/proc/device-tree/clock-frequency", "r");
576 +        if (proc_file) {
577 +                union { uint8 b[4]; uint32 l; } value;
578 +                if (fread(value.b, sizeof(value), 1, proc_file) == 1)
579 +                        BusClockSpeed = value.l;
580 +                fclose(proc_file);
581 +        }
582   #endif
583          D(bug("PVR: %08x (assumed)\n", PVR));
584  
# Line 445 | Line 603 | int main(int argc, char **argv)
603                  goto quit;
604          }
605  
606 + #ifndef PAGEZERO_HACK
607          // Create Low Memory area (0x0000..0x3000)
608          if (vm_acquire_fixed((char *)0, 0x3000) < 0) {
609                  sprintf(str, GetString(STR_LOW_MEM_MMAP_ERR), strerror(errno));
# Line 452 | Line 611 | int main(int argc, char **argv)
611                  goto quit;
612          }
613          lm_area_mapped = true;
614 + #endif
615  
616          // Create areas for Kernel Data
617          kernel_area = shmget(IPC_PRIVATE, KERNEL_AREA_SIZE, 0600);
# Line 470 | Line 630 | int main(int argc, char **argv)
630                  ErrorAlert(str);
631                  goto quit;
632          }
633 <        kernel_data = (KernelData *)0x68ffe000;
633 >        kernel_data = (KernelData *)KERNEL_DATA_BASE;
634          emulator_data = &kernel_data->ed;
635 <        KernelDataAddr = (uint32)kernel_data;
635 >        KernelDataAddr = KERNEL_DATA_BASE;
636          D(bug("Kernel Data at %p, Emulator Data at %p\n", kernel_data, emulator_data));
637  
638 +        // Create area for DR Cache
639 +        if (vm_acquire_fixed((void *)DR_EMULATOR_BASE, DR_EMULATOR_SIZE) < 0) {
640 +                sprintf(str, GetString(STR_DR_EMULATOR_MMAP_ERR), strerror(errno));
641 +                ErrorAlert(str);
642 +                goto quit;
643 +        }
644 +        dr_emulator_area_mapped = true;
645 +        if (vm_acquire_fixed((void *)DR_CACHE_BASE, DR_CACHE_SIZE) < 0) {
646 +                sprintf(str, GetString(STR_DR_CACHE_MMAP_ERR), strerror(errno));
647 +                ErrorAlert(str);
648 +                goto quit;
649 +        }
650 +        dr_cache_area_mapped = true;
651 + #if !EMULATED_PPC
652 +        if (vm_protect((char *)DR_CACHE_BASE, DR_CACHE_SIZE, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE) < 0) {
653 +                sprintf(str, GetString(STR_DR_CACHE_MMAP_ERR), strerror(errno));
654 +                ErrorAlert(str);
655 +                goto quit;
656 +        }
657 + #endif
658 +        DRCacheAddr = DR_CACHE_BASE;
659 +        D(bug("DR Cache at %p\n", DRCacheAddr));
660 +
661          // Create area for SheepShaver data
662 <        if (vm_acquire_fixed((char *)SHEEP_BASE, SHEEP_SIZE) < 0) {
662 >        if (!SheepMem::Init()) {
663                  sprintf(str, GetString(STR_SHEEP_MEM_MMAP_ERR), strerror(errno));
664                  ErrorAlert(str);
665                  goto quit;
666          }
484        SheepStack1Base = SHEEP_BASE + 0x10000;
485        SheepStack2Base = SheepStack1Base + 0x10000;
486        SheepThunksBase = SheepStack2Base + 0x1000;
487        sheep_area_mapped = true;
667  
668          // Create area for Mac ROM
669          if (vm_acquire_fixed((char *)ROM_BASE, ROM_AREA_SIZE) < 0) {
# Line 492 | Line 671 | int main(int argc, char **argv)
671                  ErrorAlert(str);
672                  goto quit;
673          }
674 < #if !EMULATED_PPC || defined(__powerpc__)
674 > #if !EMULATED_PPC
675          if (vm_protect((char *)ROM_BASE, ROM_AREA_SIZE, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE) < 0) {
676                  sprintf(str, GetString(STR_ROM_MMAP_ERR), strerror(errno));
677                  ErrorAlert(str);
# Line 562 | Line 741 | int main(int argc, char **argv)
741          // Load NVRAM
742          XPRAMInit();
743  
744 +        // Load XPRAM default values if signature not found
745 +        if (XPRAM[0x130c] != 0x4e || XPRAM[0x130d] != 0x75
746 +         || XPRAM[0x130e] != 0x4d || XPRAM[0x130f] != 0x63) {
747 +                D(bug("Loading XPRAM default values\n"));
748 +                memset(XPRAM + 0x1300, 0, 0x100);
749 +                XPRAM[0x130c] = 0x4e;   // "NuMc" signature
750 +                XPRAM[0x130d] = 0x75;
751 +                XPRAM[0x130e] = 0x4d;
752 +                XPRAM[0x130f] = 0x63;
753 +                XPRAM[0x1301] = 0x80;   // InternalWaitFlags = DynWait (don't wait for SCSI devices upon bootup)
754 +                XPRAM[0x1310] = 0xa8;   // Standard PRAM values
755 +                XPRAM[0x1311] = 0x00;
756 +                XPRAM[0x1312] = 0x00;
757 +                XPRAM[0x1313] = 0x22;
758 +                XPRAM[0x1314] = 0xcc;
759 +                XPRAM[0x1315] = 0x0a;
760 +                XPRAM[0x1316] = 0xcc;
761 +                XPRAM[0x1317] = 0x0a;
762 +                XPRAM[0x131c] = 0x00;
763 +                XPRAM[0x131d] = 0x02;
764 +                XPRAM[0x131e] = 0x63;
765 +                XPRAM[0x131f] = 0x00;
766 +                XPRAM[0x1308] = 0x13;
767 +                XPRAM[0x1309] = 0x88;
768 +                XPRAM[0x130a] = 0x00;
769 +                XPRAM[0x130b] = 0xcc;
770 +                XPRAM[0x1376] = 0x00;   // OSDefault = MacOS
771 +                XPRAM[0x1377] = 0x01;
772 +        }
773 +
774          // Set boot volume
775          i16 = PrefsFindInt32("bootdrive");
776          XPRAM[0x1378] = i16 >> 8;
# Line 579 | Line 788 | int main(int argc, char **argv)
788          boot_globs[1] = htonl(RAMSize);
789          boot_globs[2] = htonl((uint32)-1);                      // End of bank table
790  
791 +        // Init thunks
792 +        if (!ThunksInit())
793 +                goto quit;
794 +
795          // Init drivers
796          SonyInit();
797          DiskInit();
# Line 588 | Line 801 | int main(int argc, char **argv)
801          // Init external file system
802          ExtFSInit();
803  
804 +        // Init ADB
805 +        ADBInit();
806 +
807          // Init audio
808          AudioInit();
809  
# Line 622 | Line 838 | int main(int argc, char **argv)
838          // Initialize Kernel Data
839          memset(kernel_data, 0, sizeof(KernelData));
840          if (ROMType == ROMTYPE_NEWWORLD) {
841 <                static uint32 of_dev_tree[4] = {0, 0, 0, 0};
842 <                static uint8 vector_lookup_tbl[128];
843 <                static uint8 vector_mask_tbl[64];
841 >                uintptr of_dev_tree = SheepMem::Reserve(4 * sizeof(uint32));
842 >                memset((void *)of_dev_tree, 0, 4 * sizeof(uint32));
843 >                uintptr vector_lookup_tbl = SheepMem::Reserve(128);
844 >                uintptr vector_mask_tbl = SheepMem::Reserve(64);
845                  memset((uint8 *)kernel_data + 0xb80, 0x3d, 0x80);
846 <                memset(vector_lookup_tbl, 0, 128);
847 <                memset(vector_mask_tbl, 0, 64);
846 >                memset((void *)vector_lookup_tbl, 0, 128);
847 >                memset((void *)vector_mask_tbl, 0, 64);
848                  kernel_data->v[0xb80 >> 2] = htonl(ROM_BASE);
849 <                kernel_data->v[0xb84 >> 2] = htonl((uint32)of_dev_tree);        // OF device tree base
850 <                kernel_data->v[0xb90 >> 2] = htonl((uint32)vector_lookup_tbl);
851 <                kernel_data->v[0xb94 >> 2] = htonl((uint32)vector_mask_tbl);
849 >                kernel_data->v[0xb84 >> 2] = htonl(of_dev_tree);                        // OF device tree base
850 >                kernel_data->v[0xb90 >> 2] = htonl(vector_lookup_tbl);
851 >                kernel_data->v[0xb94 >> 2] = htonl(vector_mask_tbl);
852                  kernel_data->v[0xb98 >> 2] = htonl(ROM_BASE);                           // OpenPIC base
853                  kernel_data->v[0xbb0 >> 2] = htonl(0);                                          // ADB base
854                  kernel_data->v[0xc20 >> 2] = htonl(RAMSize);
# Line 644 | Line 861 | int main(int argc, char **argv)
861                  kernel_data->v[0xc50 >> 2] = htonl(RAMBase);
862                  kernel_data->v[0xc54 >> 2] = htonl(RAMSize);
863                  kernel_data->v[0xf60 >> 2] = htonl(PVR);
864 <                kernel_data->v[0xf64 >> 2] = htonl(CPUClockSpeed);
865 <                kernel_data->v[0xf68 >> 2] = htonl(BusClockSpeed);
866 <                kernel_data->v[0xf6c >> 2] = htonl(CPUClockSpeed);
864 >                kernel_data->v[0xf64 >> 2] = htonl(CPUClockSpeed);                      // clock-frequency
865 >                kernel_data->v[0xf68 >> 2] = htonl(BusClockSpeed);                      // bus-frequency
866 >                kernel_data->v[0xf6c >> 2] = htonl(BusClockSpeed / 4);          // timebase-frequency
867          } else {
868                  kernel_data->v[0xc80 >> 2] = htonl(RAMSize);
869                  kernel_data->v[0xc84 >> 2] = htonl(RAMSize);
# Line 658 | Line 875 | int main(int argc, char **argv)
875                  kernel_data->v[0xcb0 >> 2] = htonl(RAMBase);
876                  kernel_data->v[0xcb4 >> 2] = htonl(RAMSize);
877                  kernel_data->v[0xf80 >> 2] = htonl(PVR);
878 <                kernel_data->v[0xf84 >> 2] = htonl(CPUClockSpeed);
879 <                kernel_data->v[0xf88 >> 2] = htonl(BusClockSpeed);
880 <                kernel_data->v[0xf8c >> 2] = htonl(CPUClockSpeed);
878 >                kernel_data->v[0xf84 >> 2] = htonl(CPUClockSpeed);                      // clock-frequency
879 >                kernel_data->v[0xf88 >> 2] = htonl(BusClockSpeed);                      // bus-frequency
880 >                kernel_data->v[0xf8c >> 2] = htonl(BusClockSpeed / 4);          // timebase-frequency
881          }
882  
883          // Initialize extra low memory
884          D(bug("Initializing Low Memory...\n"));
885          memset(NULL, 0, 0x3000);
886          WriteMacInt32(XLM_SIGNATURE, FOURCC('B','a','a','h'));                  // Signature to detect SheepShaver
887 <        WriteMacInt32(XLM_KERNEL_DATA, (uint32)kernel_data);                    // For trap replacement routines
887 >        WriteMacInt32(XLM_KERNEL_DATA, KernelDataAddr);                                 // For trap replacement routines
888          WriteMacInt32(XLM_PVR, PVR);                                                                    // Theoretical PVR
889          WriteMacInt32(XLM_BUS_CLOCK, BusClockSpeed);                                    // For DriverServicesLib patch
890          WriteMacInt16(XLM_EXEC_RETURN_OPCODE, M68K_EXEC_RETURN);                // For Execute68k() (RTS from the executed 68k code will jump here and end 68k mode)
891 < #if EMULATED_PPC
892 <        WriteMacInt32(XLM_ETHER_INIT, POWERPC_NATIVE_OP_FUNC(NATIVE_ETHER_INIT));
893 <        WriteMacInt32(XLM_ETHER_TERM, POWERPC_NATIVE_OP_FUNC(NATIVE_ETHER_TERM));
677 <        WriteMacInt32(XLM_ETHER_OPEN, POWERPC_NATIVE_OP_FUNC(NATIVE_ETHER_OPEN));
678 <        WriteMacInt32(XLM_ETHER_CLOSE, POWERPC_NATIVE_OP_FUNC(NATIVE_ETHER_CLOSE));
679 <        WriteMacInt32(XLM_ETHER_WPUT, POWERPC_NATIVE_OP_FUNC(NATIVE_ETHER_WPUT));
680 <        WriteMacInt32(XLM_ETHER_RSRV, POWERPC_NATIVE_OP_FUNC(NATIVE_ETHER_RSRV));
681 <        WriteMacInt32(XLM_VIDEO_DOIO, POWERPC_NATIVE_OP_FUNC(NATIVE_VIDEO_DO_DRIVER_IO));
682 < #else
683 <        WriteMacInt32(XLM_TOC, (uint32)TOC);                                                    // TOC pointer of emulator
684 <        WriteMacInt32(XLM_ETHER_INIT, (uint32)InitStreamModule);                // DLPI ethernet driver functions
685 <        WriteMacInt32(XLM_ETHER_TERM, (uint32)TerminateStreamModule);
686 <        WriteMacInt32(XLM_ETHER_OPEN, (uint32)ether_open);
687 <        WriteMacInt32(XLM_ETHER_CLOSE, (uint32)ether_close);
688 <        WriteMacInt32(XLM_ETHER_WPUT, (uint32)ether_wput);
689 <        WriteMacInt32(XLM_ETHER_RSRV, (uint32)ether_rsrv);
690 <        WriteMacInt32(XLM_VIDEO_DOIO, (uint32)VideoDoDriverIO);
891 >        WriteMacInt32(XLM_ZERO_PAGE, SheepMem::ZeroPage());                             // Pointer to read-only page with all bits set to 0
892 > #if !EMULATED_PPC
893 >        WriteMacInt32(XLM_TOC, (uint32)TOC);                                                            // TOC pointer of emulator
894   #endif
895 +        WriteMacInt32(XLM_ETHER_INIT, NativeFunction(NATIVE_ETHER_INIT));       // DLPI ethernet driver functions
896 +        WriteMacInt32(XLM_ETHER_TERM, NativeFunction(NATIVE_ETHER_TERM));
897 +        WriteMacInt32(XLM_ETHER_OPEN, NativeFunction(NATIVE_ETHER_OPEN));
898 +        WriteMacInt32(XLM_ETHER_CLOSE, NativeFunction(NATIVE_ETHER_CLOSE));
899 +        WriteMacInt32(XLM_ETHER_WPUT, NativeFunction(NATIVE_ETHER_WPUT));
900 +        WriteMacInt32(XLM_ETHER_RSRV, NativeFunction(NATIVE_ETHER_RSRV));
901 +        WriteMacInt32(XLM_VIDEO_DOIO, NativeFunction(NATIVE_VIDEO_DO_DRIVER_IO));
902          D(bug("Low Memory initialized\n"));
903  
904          // Start 60Hz thread
905 +        tick_thread_cancel = false;
906          tick_thread_active = (pthread_create(&tick_thread, NULL, tick_func, NULL) == 0);
907          D(bug("Tick thread installed (%ld)\n", tick_thread));
908  
909          // Start NVRAM watchdog thread
910          memcpy(last_xpram, XPRAM, XPRAM_SIZE);
911 +        nvram_thread_cancel = false;
912          nvram_thread_active = (pthread_create(&nvram_thread, NULL, nvram_func, NULL) == 0);
913          D(bug("NVRAM thread installed (%ld)\n", nvram_thread));
914  
915   #if !EMULATED_PPC
916          // Create and install stacks for signal handlers
917 <        sig_stack = malloc(SIG_STACK_SIZE);
918 <        D(bug("Signal stack at %p\n", sig_stack));
919 <        if (sig_stack == NULL) {
920 <                ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
921 <                goto quit;
922 <        }
923 <        extra_stack = malloc(SIG_STACK_SIZE);
924 <        D(bug("Extra stack at %p\n", extra_stack));
925 <        if (extra_stack == NULL) {
926 <                ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
927 <                goto quit;
928 <        }
929 <        struct sigaltstack new_stack;
718 <        new_stack.ss_sp = sig_stack;
719 <        new_stack.ss_flags = 0;
720 <        new_stack.ss_size = SIG_STACK_SIZE;
721 <        if (sigaltstack(&new_stack, NULL) < 0) {
917 >        for (int i = 0; i < SIG_STACK_COUNT; i++) {
918 >                void *sig_stack = malloc(SIG_STACK_SIZE);
919 >                D(bug("Signal stack %d at %p\n", i, sig_stack));
920 >                if (sig_stack == NULL) {
921 >                        ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
922 >                        goto quit;
923 >                }
924 >                sig_stacks[i].ss_sp = sig_stack;
925 >                sig_stacks[i].ss_flags = 0;
926 >                sig_stacks[i].ss_size = SIG_STACK_SIZE;
927 >        }
928 >        sig_stack_id = 0;
929 >        if (sigaltstack(&sig_stacks[0], NULL) < 0) {
930                  sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno));
931                  ErrorAlert(str);
932                  goto quit;
# Line 726 | Line 934 | int main(int argc, char **argv)
934   #endif
935  
936   #if !EMULATED_PPC
937 <        // Install SIGSEGV handler
937 >        // Install SIGSEGV and SIGBUS handlers
938          sigemptyset(&sigsegv_action.sa_mask);   // Block interrupts during SEGV handling
939          sigaddset(&sigsegv_action.sa_mask, SIGUSR2);
940 <        sigsegv_action.sa_handler = (__sighandler_t)sigsegv_handler;
941 <        sigsegv_action.sa_flags = SA_ONSTACK;
940 >        sigsegv_action.sa_sigaction = sigsegv_handler;
941 >        sigsegv_action.sa_flags = SA_ONSTACK | SA_SIGINFO;
942 > #ifdef HAVE_SIGNAL_SA_RESTORER
943          sigsegv_action.sa_restorer = NULL;
944 + #endif
945          if (sigaction(SIGSEGV, &sigsegv_action, NULL) < 0) {
946                  sprintf(str, GetString(STR_SIGSEGV_INSTALL_ERR), strerror(errno));
947                  ErrorAlert(str);
948                  goto quit;
949          }
950 +        if (sigaction(SIGBUS, &sigsegv_action, NULL) < 0) {
951 +                sprintf(str, GetString(STR_SIGSEGV_INSTALL_ERR), strerror(errno));
952 +                ErrorAlert(str);
953 +                goto quit;
954 +        }
955  
956          // Install SIGILL handler
957          sigemptyset(&sigill_action.sa_mask);    // Block interrupts during ILL handling
958          sigaddset(&sigill_action.sa_mask, SIGUSR2);
959 <        sigill_action.sa_handler = (__sighandler_t)sigill_handler;
960 <        sigill_action.sa_flags = SA_ONSTACK;
959 >        sigill_action.sa_sigaction = sigill_handler;
960 >        sigill_action.sa_flags = SA_ONSTACK | SA_SIGINFO;
961 > #ifdef HAVE_SIGNAL_SA_RESTORER
962          sigill_action.sa_restorer = NULL;
963 + #endif
964          if (sigaction(SIGILL, &sigill_action, NULL) < 0) {
965                  sprintf(str, GetString(STR_SIGILL_INSTALL_ERR), strerror(errno));
966                  ErrorAlert(str);
# Line 751 | Line 968 | int main(int argc, char **argv)
968          }
969   #endif
970  
971 + #if !EMULATED_PPC
972          // Install interrupt signal handler
973          sigemptyset(&sigusr2_action.sa_mask);
974 <        sigusr2_action.sa_handler = (__sighandler_t)sigusr2_handler;
975 <        sigusr2_action.sa_flags = 0;
976 < #if !EMULATED_PPC
759 <        sigusr2_action.sa_flags = SA_ONSTACK | SA_RESTART;
760 < #endif
974 >        sigusr2_action.sa_sigaction = sigusr2_handler;
975 >        sigusr2_action.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
976 > #ifdef HAVE_SIGNAL_SA_RESTORER
977          sigusr2_action.sa_restorer = NULL;
978 + #endif
979          if (sigaction(SIGUSR2, &sigusr2_action, NULL) < 0) {
980                  sprintf(str, GetString(STR_SIGUSR2_INSTALL_ERR), strerror(errno));
981                  ErrorAlert(str);
982                  goto quit;
983          }
984 + #endif
985  
986          // Get my thread ID and execute MacOS thread function
987          emul_thread = pthread_self();
# Line 789 | Line 1007 | static void Quit(void)
1007  
1008          // Stop 60Hz thread
1009          if (tick_thread_active) {
1010 +                tick_thread_cancel = true;
1011                  pthread_cancel(tick_thread);
1012                  pthread_join(tick_thread, NULL);
1013          }
1014  
1015          // Stop NVRAM watchdog thread
1016          if (nvram_thread_active) {
1017 +                nvram_thread_cancel = true;
1018                  pthread_cancel(nvram_thread);
1019                  pthread_join(nvram_thread, NULL);
1020          }
1021  
1022   #if !EMULATED_PPC
1023 <        // Uninstall SIGSEGV handler
1023 >        // Uninstall SIGSEGV and SIGBUS handlers
1024          sigemptyset(&sigsegv_action.sa_mask);
1025          sigsegv_action.sa_handler = SIG_DFL;
1026          sigsegv_action.sa_flags = 0;
1027          sigaction(SIGSEGV, &sigsegv_action, NULL);
1028 +        sigaction(SIGBUS, &sigsegv_action, NULL);
1029  
1030          // Uninstall SIGILL handler
1031          sigemptyset(&sigill_action.sa_mask);
1032          sigill_action.sa_handler = SIG_DFL;
1033          sigill_action.sa_flags = 0;
1034          sigaction(SIGILL, &sigill_action, NULL);
1035 +
1036 +        // Delete stacks for signal handlers
1037 +        for (int i = 0; i < SIG_STACK_COUNT; i++) {
1038 +                void *sig_stack = sig_stacks[i].ss_sp;
1039 +                if (sig_stack)
1040 +                        free(sig_stack);
1041 +        }
1042   #endif
1043  
1044          // Save NVRAM
# Line 831 | Line 1059 | static void Quit(void)
1059          // Exit audio
1060          AudioExit();
1061  
1062 +        // Exit ADB
1063 +        ADBExit();
1064 +
1065          // Exit video
1066          VideoExit();
1067  
# Line 843 | Line 1074 | static void Quit(void)
1074          DiskExit();
1075          SonyExit();
1076  
1077 +        // Delete thunks
1078 +        ThunksExit();
1079 +
1080 +        // Delete SheepShaver globals
1081 +        SheepMem::Exit();
1082 +
1083          // Delete RAM area
1084          if (ram_area_mapped)
1085                  vm_release((char *)RAM_BASE, RAMSize);
# Line 851 | Line 1088 | static void Quit(void)
1088          if (rom_area_mapped)
1089                  vm_release((char *)ROM_BASE, ROM_AREA_SIZE);
1090  
1091 +        // Delete DR cache areas
1092 +        if (dr_emulator_area_mapped)
1093 +                vm_release((void *)DR_EMULATOR_BASE, DR_EMULATOR_SIZE);
1094 +        if (dr_cache_area_mapped)
1095 +                vm_release((void *)DR_CACHE_BASE, DR_CACHE_SIZE);
1096 +
1097          // Delete Kernel Data area
1098          if (kernel_area >= 0) {
1099                  shmdt((void *)KERNEL_DATA_BASE);
# Line 954 | Line 1197 | void Execute68kTrap(uint16 trap, M68kReg
1197          uint16 proc[2] = {trap, M68K_RTS};
1198          Execute68k((uint32)proc, r);
1199   }
957
958
959 /*
960 *  Execute PPC code from EMUL_OP routine (real mode switch)
961 */
962
963 void ExecutePPC(void (*func)())
964 {
965        uint32 tvect[2] = {(uint32)func, 0};    // Fake TVECT
966        RoutineDescriptor desc = BUILD_PPC_ROUTINE_DESCRIPTOR(0, tvect);
967        M68kRegisters r;
968        Execute68k((uint32)&desc, &r);
969 }
1200   #endif
1201  
1202  
# Line 1045 | Line 1275 | void MakeExecutable(int dummy, void *sta
1275  
1276   void PatchAfterStartup(void)
1277   {
1048 #if EMULATED_PPC
1278          ExecuteNative(NATIVE_VIDEO_INSTALL_ACCEL);
1050 #else
1051        ExecutePPC(VideoInstallAccel);
1052 #endif
1279          InstallExtFS();
1280   }
1281  
# Line 1058 | Line 1284 | void PatchAfterStartup(void)
1284   *  NVRAM watchdog thread (saves NVRAM every minute)
1285   */
1286  
1287 < static void *nvram_func(void *arg)
1287 > static void nvram_watchdog(void)
1288   {
1289 <        struct timespec req = {60, 0};  // 1 minute
1289 >        if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) {
1290 >                memcpy(last_xpram, XPRAM, XPRAM_SIZE);
1291 >                SaveXPRAM();
1292 >        }
1293 > }
1294  
1295 <        for (;;) {
1296 <                pthread_testcancel();
1297 <                nanosleep(&req, NULL);
1298 <                pthread_testcancel();
1299 <                if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) {
1300 <                        memcpy(last_xpram, XPRAM, XPRAM_SIZE);
1071 <                        SaveXPRAM();
1072 <                }
1295 > static void *nvram_func(void *arg)
1296 > {
1297 >        while (!nvram_thread_cancel) {
1298 >                for (int i=0; i<60 && !nvram_thread_cancel; i++)
1299 >                        Delay_usec(999999);             // Only wait 1 second so we quit promptly when nvram_thread_cancel becomes true
1300 >                nvram_watchdog();
1301          }
1302          return NULL;
1303   }
# Line 1082 | Line 1310 | static void *nvram_func(void *arg)
1310   static void *tick_func(void *arg)
1311   {
1312          int tick_counter = 0;
1313 <        struct timespec req = {0, 16625000};
1313 >        uint64 start = GetTicks_usec();
1314 >        int64 ticks = 0;
1315 >        uint64 next = GetTicks_usec();
1316  
1317 <        for (;;) {
1317 >        while (!tick_thread_cancel) {
1318  
1319                  // Wait
1320 <                nanosleep(&req, NULL);
1320 >                next += 16625;
1321 >                int64 delay = next - GetTicks_usec();
1322 >                if (delay > 0)
1323 >                        Delay_usec(delay);
1324 >                else if (delay < -16625)
1325 >                        next = GetTicks_usec();
1326 >                ticks++;
1327  
1328   #if !EMULATED_PPC
1329                  // Did we crash?
1330                  if (emul_thread_fatal) {
1331  
1332                          // Yes, dump registers
1333 <                        pt_regs *r = (pt_regs *)&sigsegv_regs;
1333 >                        sigregs *r = &sigsegv_regs;
1334                          char str[256];
1335 <                        sprintf(str, "SIGSEGV\n"
1335 >                        if (crash_reason == NULL)
1336 >                                crash_reason = "SIGSEGV";
1337 >                        sprintf(str, "%s\n"
1338                                  "   pc %08lx     lr %08lx    ctr %08lx    msr %08lx\n"
1339                                  "  xer %08lx     cr %08lx  \n"
1340                                  "   r0 %08lx     r1 %08lx     r2 %08lx     r3 %08lx\n"
# Line 1107 | Line 1345 | static void *tick_func(void *arg)
1345                                  "  r20 %08lx    r21 %08lx    r22 %08lx    r23 %08lx\n"
1346                                  "  r24 %08lx    r25 %08lx    r26 %08lx    r27 %08lx\n"
1347                                  "  r28 %08lx    r29 %08lx    r30 %08lx    r31 %08lx\n",
1348 +                                crash_reason,
1349                                  r->nip, r->link, r->ctr, r->msr,
1350                                  r->xer, r->ccr,
1351                                  r->gpr[0], r->gpr[1], r->gpr[2], r->gpr[3],
# Line 1142 | Line 1381 | static void *tick_func(void *arg)
1381                          TriggerInterrupt();
1382                  }
1383          }
1384 +
1385 +        uint64 end = GetTicks_usec();
1386 +        D(bug("%Ld ticks in %Ld usec = %f ticks/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start)));
1387          return NULL;
1388   }
1389  
# Line 1152 | Line 1394 | static void *tick_func(void *arg)
1394  
1395   void Set_pthread_attr(pthread_attr_t *attr, int priority)
1396   {
1397 <        // nothing to do
1397 > #ifdef HAVE_PTHREADS
1398 >        pthread_attr_init(attr);
1399 > #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
1400 >        // Some of these only work for superuser
1401 >        if (geteuid() == 0) {
1402 >                pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED);
1403 >                pthread_attr_setschedpolicy(attr, SCHED_FIFO);
1404 >                struct sched_param fifo_param;
1405 >                fifo_param.sched_priority = ((sched_get_priority_min(SCHED_FIFO) +
1406 >                                              sched_get_priority_max(SCHED_FIFO)) / 2 +
1407 >                                             priority);
1408 >                pthread_attr_setschedparam(attr, &fifo_param);
1409 >        }
1410 >        if (pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM) != 0) {
1411 > #ifdef PTHREAD_SCOPE_BOUND_NP
1412 >            // If system scope is not available (eg. we're not running
1413 >            // with CAP_SCHED_MGT capability on an SGI box), try bound
1414 >            // scope.  It exposes pthread scheduling to the kernel,
1415 >            // without setting realtime priority.
1416 >            pthread_attr_setscope(attr, PTHREAD_SCOPE_BOUND_NP);
1417 > #endif
1418 >        }
1419 > #endif
1420 > #endif
1421   }
1422  
1423  
# Line 1239 | Line 1504 | void B2_delete_mutex(B2_mutex *mutex)
1504   *  Trigger signal USR2 from another thread
1505   */
1506  
1507 < #if !EMULATED_PPC || ASYNC_IRQ
1507 > #if !EMULATED_PPC
1508   void TriggerInterrupt(void)
1509   {
1510          if (ready_for_signals)
# Line 1271 | Line 1536 | void ClearInterruptFlag(uint32 flag)
1536  
1537   void DisableInterrupt(void)
1538   {
1539 + #if EMULATED_PPC
1540 +        WriteMacInt32(XLM_IRQ_NEST, int32(ReadMacInt32(XLM_IRQ_NEST)) + 1);
1541 + #else
1542          atomic_add((int *)XLM_IRQ_NEST, 1);
1543 + #endif
1544   }
1545  
1546  
# Line 1281 | Line 1550 | void DisableInterrupt(void)
1550  
1551   void EnableInterrupt(void)
1552   {
1553 + #if EMULATED_PPC
1554 +        WriteMacInt32(XLM_IRQ_NEST, int32(ReadMacInt32(XLM_IRQ_NEST)) - 1);
1555 + #else
1556          atomic_add((int *)XLM_IRQ_NEST, -1);
1557 + #endif
1558   }
1559  
1560  
# Line 1289 | Line 1562 | void EnableInterrupt(void)
1562   *  USR2 handler
1563   */
1564  
1565 < #if EMULATED_PPC
1566 < static void sigusr2_handler(int sig)
1294 < {
1295 < #if ASYNC_IRQ
1296 <        extern void HandleInterrupt(void);
1297 <        HandleInterrupt();
1298 < #endif
1299 < }
1300 < #else
1301 < static void sigusr2_handler(int sig, sigcontext_struct *sc)
1565 > #if !EMULATED_PPC
1566 > static void sigusr2_handler(int sig, siginfo_t *sip, void *scp)
1567   {
1568 <        pt_regs *r = sc->regs;
1568 >        machine_regs *r = MACHINE_REGISTERS(scp);
1569  
1570          // Do nothing if interrupts are disabled
1571          if (*(int32 *)XLM_IRQ_NEST > 0)
# Line 1314 | Line 1579 | static void sigusr2_handler(int sig, sig
1579                  case MODE_68K:
1580                          // 68k emulator active, trigger 68k interrupt level 1
1581                          WriteMacInt16(ntohl(kernel_data->v[0x67c >> 2]), 1);
1582 <                        r->ccr |= ntohl(kernel_data->v[0x674 >> 2]);
1582 >                        r->cr() |= ntohl(kernel_data->v[0x674 >> 2]);
1583                          break;
1584  
1585   #if INTERRUPTS_IN_NATIVE_MODE
1586                  case MODE_NATIVE:
1587                          // 68k emulator inactive, in nanokernel?
1588 <                        if (r->gpr[1] != KernelDataAddr) {
1588 >                        if (r->gpr(1) != KernelDataAddr) {
1589 >
1590 >                                // Set extra stack for nested interrupts
1591 >                                sig_stack_acquire();
1592 >                                
1593                                  // Prepare for 68k interrupt level 1
1594                                  WriteMacInt16(ntohl(kernel_data->v[0x67c >> 2]), 1);
1595                                  WriteMacInt32(ntohl(kernel_data->v[0x658 >> 2]) + 0xdc, ReadMacInt32(ntohl(kernel_data->v[0x658 >> 2]) + 0xdc) | ntohl(kernel_data->v[0x674 >> 2]));
1596  
1597                                  // Execute nanokernel interrupt routine (this will activate the 68k emulator)
1598 <                                atomic_add((int32 *)XLM_IRQ_NEST, 1);
1598 >                                DisableInterrupt();
1599                                  if (ROMType == ROMTYPE_NEWWORLD)
1600                                          ppc_interrupt(ROM_BASE + 0x312b1c, KernelDataAddr);
1601                                  else
1602                                          ppc_interrupt(ROM_BASE + 0x312a3c, KernelDataAddr);
1603 +
1604 +                                // Reset normal signal stack
1605 +                                sig_stack_release();
1606                          }
1607                          break;
1608   #endif
# Line 1341 | Line 1613 | static void sigusr2_handler(int sig, sig
1613                          if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) {
1614  
1615                                  // Set extra stack for SIGSEGV handler
1616 <                                struct sigaltstack new_stack;
1345 <                                new_stack.ss_sp = extra_stack;
1346 <                                new_stack.ss_flags = 0;
1347 <                                new_stack.ss_size = SIG_STACK_SIZE;
1348 <                                sigaltstack(&new_stack, NULL);
1616 >                                sig_stack_acquire();
1617   #if 1
1618                                  // Execute full 68k interrupt routine
1619                                  M68kRegisters r;
# Line 1367 | Line 1635 | static void sigusr2_handler(int sig, sig
1635                                          if (InterruptFlags & INTFLAG_VIA) {
1636                                                  ClearInterruptFlag(INTFLAG_VIA);
1637                                                  ADBInterrupt();
1638 <                                                ExecutePPC(VideoVBL);
1638 >                                                ExecuteNative(NATIVE_VIDEO_VBL);
1639                                          }
1640                                  }
1641   #endif
1642                                  // Reset normal signal stack
1643 <                                new_stack.ss_sp = sig_stack;
1376 <                                new_stack.ss_flags = 0;
1377 <                                new_stack.ss_size = SIG_STACK_SIZE;
1378 <                                sigaltstack(&new_stack, NULL);
1643 >                                sig_stack_release();
1644                          }
1645                          break;
1646   #endif
# Line 1389 | Line 1654 | static void sigusr2_handler(int sig, sig
1654   */
1655  
1656   #if !EMULATED_PPC
1657 < static void sigsegv_handler(int sig, sigcontext_struct *sc)
1657 > static void sigsegv_handler(int sig, siginfo_t *sip, void *scp)
1658   {
1659 <        pt_regs *r = sc->regs;
1659 >        machine_regs *r = MACHINE_REGISTERS(scp);
1660  
1661          // Get effective address
1662 <        uint32 addr = r->dar;
1662 >        uint32 addr = r->dar();
1663          
1664   #if ENABLE_VOSF
1665          // Handle screen fault.
1666          extern bool Screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction);
1667 <        if (Screen_fault_handler((sigsegv_address_t)addr, (sigsegv_address_t)r->nip))
1667 >        if (Screen_fault_handler((sigsegv_address_t)addr, (sigsegv_address_t)r->pc()))
1668                  return;
1669   #endif
1670  
1671          num_segv++;
1672  
1673 <        // Fault in Mac ROM or RAM?
1674 <        bool mac_fault = (r->nip >= ROM_BASE) && (r->nip < (ROM_BASE + ROM_AREA_SIZE)) || (r->nip >= RAMBase) && (r->nip < (RAMBase + RAMSize));
1673 >        // Fault in Mac ROM or RAM or DR Cache?
1674 >        bool mac_fault = (r->pc() >= ROM_BASE) && (r->pc() < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc() >= RAMBase) && (r->pc() < (RAMBase + RAMSize)) || (r->pc() >= DR_CACHE_BASE && r->pc() < (DR_CACHE_BASE + DR_CACHE_SIZE));
1675          if (mac_fault) {
1676  
1677                  // "VM settings" during MacOS 8 installation
1678 <                if (r->nip == ROM_BASE + 0x488160 && r->gpr[20] == 0xf8000000) {
1679 <                        r->nip += 4;
1680 <                        r->gpr[8] = 0;
1678 >                if (r->pc() == ROM_BASE + 0x488160 && r->gpr(20) == 0xf8000000) {
1679 >                        r->pc() += 4;
1680 >                        r->gpr(8) = 0;
1681                          return;
1682          
1683                  // MacOS 8.5 installation
1684 <                } else if (r->nip == ROM_BASE + 0x488140 && r->gpr[16] == 0xf8000000) {
1685 <                        r->nip += 4;
1686 <                        r->gpr[8] = 0;
1684 >                } else if (r->pc() == ROM_BASE + 0x488140 && r->gpr(16) == 0xf8000000) {
1685 >                        r->pc() += 4;
1686 >                        r->gpr(8) = 0;
1687                          return;
1688          
1689                  // MacOS 8 serial drivers on startup
1690 <                } else if (r->nip == ROM_BASE + 0x48e080 && (r->gpr[8] == 0xf3012002 || r->gpr[8] == 0xf3012000)) {
1691 <                        r->nip += 4;
1692 <                        r->gpr[8] = 0;
1690 >                } else if (r->pc() == ROM_BASE + 0x48e080 && (r->gpr(8) == 0xf3012002 || r->gpr(8) == 0xf3012000)) {
1691 >                        r->pc() += 4;
1692 >                        r->gpr(8) = 0;
1693                          return;
1694          
1695                  // MacOS 8.1 serial drivers on startup
1696 <                } else if (r->nip == ROM_BASE + 0x48c5e0 && (r->gpr[20] == 0xf3012002 || r->gpr[20] == 0xf3012000)) {
1697 <                        r->nip += 4;
1696 >                } else if (r->pc() == ROM_BASE + 0x48c5e0 && (r->gpr(20) == 0xf3012002 || r->gpr(20) == 0xf3012000)) {
1697 >                        r->pc() += 4;
1698                          return;
1699 <                } else if (r->nip == ROM_BASE + 0x4a10a0 && (r->gpr[20] == 0xf3012002 || r->gpr[20] == 0xf3012000)) {
1700 <                        r->nip += 4;
1699 >                } else if (r->pc() == ROM_BASE + 0x4a10a0 && (r->gpr(20) == 0xf3012002 || r->gpr(20) == 0xf3012000)) {
1700 >                        r->pc() += 4;
1701 >                        return;
1702 >        
1703 >                // MacOS 8.6 serial drivers on startup (with DR Cache and OldWorld ROM)
1704 >                } else if ((r->pc() - DR_CACHE_BASE) < DR_CACHE_SIZE && (r->gpr(16) == 0xf3012002 || r->gpr(16) == 0xf3012000)) {
1705 >                        r->pc() += 4;
1706 >                        return;
1707 >                } else if ((r->pc() - DR_CACHE_BASE) < DR_CACHE_SIZE && (r->gpr(20) == 0xf3012002 || r->gpr(20) == 0xf3012000)) {
1708 >                        r->pc() += 4;
1709                          return;
1710                  }
1711  
1712                  // Get opcode and divide into fields
1713 <                uint32 opcode = *((uint32 *)r->nip);
1713 >                uint32 opcode = *((uint32 *)r->pc());
1714                  uint32 primop = opcode >> 26;
1715                  uint32 exop = (opcode >> 1) & 0x3ff;
1716                  uint32 ra = (opcode >> 16) & 0x1f;
# Line 1526 | Line 1799 | static void sigsegv_handler(int sig, sig
1799                                  transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1800                          case 45:        // sthu
1801                                  transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1802 + #if EMULATE_UNALIGNED_LOADSTORE_MULTIPLE
1803 +                        case 46:        // lmw
1804 +                                if ((addr % 4) != 0) {
1805 +                                        uint32 ea = addr;
1806 +                                        D(bug("WARNING: unaligned lmw to EA=%08x from IP=%08x\n", ea, r->pc()));
1807 +                                        for (int i = rd; i <= 31; i++) {
1808 +                                                r->gpr(i) = ReadMacInt32(ea);
1809 +                                                ea += 4;
1810 +                                        }
1811 +                                        r->pc() += 4;
1812 +                                        goto rti;
1813 +                                }
1814 +                                break;
1815 +                        case 47:        // stmw
1816 +                                if ((addr % 4) != 0) {
1817 +                                        uint32 ea = addr;
1818 +                                        D(bug("WARNING: unaligned stmw to EA=%08x from IP=%08x\n", ea, r->pc()));
1819 +                                        for (int i = rd; i <= 31; i++) {
1820 +                                                WriteMacInt32(ea, r->gpr(i));
1821 +                                                ea += 4;
1822 +                                        }
1823 +                                        r->pc() += 4;
1824 +                                        goto rti;
1825 +                                }
1826 +                                break;
1827 + #endif
1828                  }
1829          
1830 <                // Ignore ROM writes
1831 <                if (transfer_type == TYPE_STORE && addr >= ROM_BASE && addr < ROM_BASE + ROM_SIZE) {
1832 < //                      D(bug("WARNING: %s write access to ROM at %08lx, pc %08lx\n", transfer_size == SIZE_BYTE ? "Byte" : transfer_size == SIZE_HALFWORD ? "Halfword" : "Word", addr, r->nip));
1830 >                // Ignore ROM writes (including to the zero page, which is read-only)
1831 >                if (transfer_type == TYPE_STORE &&
1832 >                        ((addr >= ROM_BASE && addr < ROM_BASE + ROM_SIZE) ||
1833 >                         (addr >= SheepMem::ZeroPage() && addr < SheepMem::ZeroPage() + SheepMem::PageSize()))) {
1834 > //                      D(bug("WARNING: %s write access to ROM at %08lx, pc %08lx\n", transfer_size == SIZE_BYTE ? "Byte" : transfer_size == SIZE_HALFWORD ? "Halfword" : "Word", addr, r->pc()));
1835                          if (addr_mode == MODE_U || addr_mode == MODE_UX)
1836 <                                r->gpr[ra] = addr;
1837 <                        r->nip += 4;
1836 >                                r->gpr(ra) = addr;
1837 >                        r->pc() += 4;
1838                          goto rti;
1839                  }
1840  
1841                  // Ignore illegal memory accesses?
1842                  if (PrefsFindBool("ignoresegv")) {
1843                          if (addr_mode == MODE_U || addr_mode == MODE_UX)
1844 <                                r->gpr[ra] = addr;
1844 >                                r->gpr(ra) = addr;
1845                          if (transfer_type == TYPE_LOAD)
1846 <                                r->gpr[rd] = 0;
1847 <                        r->nip += 4;
1846 >                                r->gpr(rd) = 0;
1847 >                        r->pc() += 4;
1848                          goto rti;
1849                  }
1850  
# Line 1551 | Line 1852 | static void sigsegv_handler(int sig, sig
1852                  if (!PrefsFindBool("nogui")) {
1853                          char str[256];
1854                          if (transfer_type == TYPE_LOAD || transfer_type == TYPE_STORE)
1855 <                                sprintf(str, GetString(STR_MEM_ACCESS_ERR), transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_HALFWORD ? "halfword" : "word", transfer_type == TYPE_LOAD ? GetString(STR_MEM_ACCESS_READ) : GetString(STR_MEM_ACCESS_WRITE), addr, r->nip, r->gpr[24], r->gpr[1]);
1855 >                                sprintf(str, GetString(STR_MEM_ACCESS_ERR), transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_HALFWORD ? "halfword" : "word", transfer_type == TYPE_LOAD ? GetString(STR_MEM_ACCESS_READ) : GetString(STR_MEM_ACCESS_WRITE), addr, r->pc(), r->gpr(24), r->gpr(1));
1856                          else
1857 <                                sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->nip, r->gpr[24], r->gpr[1], opcode);
1857 >                                sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc(), r->gpr(24), r->gpr(1), opcode);
1858                          ErrorAlert(str);
1859                          QuitEmulator();
1860                          return;
# Line 1561 | Line 1862 | static void sigsegv_handler(int sig, sig
1862          }
1863  
1864          // For all other errors, jump into debugger (sort of...)
1865 +        crash_reason = (sig == SIGBUS) ? "SIGBUS" : "SIGSEGV";
1866          if (!ready_for_signals) {
1867 <                printf("SIGSEGV\n");
1868 <                printf(" sigcontext %p, pt_regs %p\n", sc, r);
1867 >                printf("%s\n");
1868 >                printf(" sigcontext %p, machine_regs %p\n", scp, r);
1869                  printf(
1870                          "   pc %08lx     lr %08lx    ctr %08lx    msr %08lx\n"
1871                          "  xer %08lx     cr %08lx  \n"
# Line 1575 | Line 1877 | static void sigsegv_handler(int sig, sig
1877                          "  r20 %08lx    r21 %08lx    r22 %08lx    r23 %08lx\n"
1878                          "  r24 %08lx    r25 %08lx    r26 %08lx    r27 %08lx\n"
1879                          "  r28 %08lx    r29 %08lx    r30 %08lx    r31 %08lx\n",
1880 <                        r->nip, r->link, r->ctr, r->msr,
1881 <                        r->xer, r->ccr,
1882 <                        r->gpr[0], r->gpr[1], r->gpr[2], r->gpr[3],
1883 <                        r->gpr[4], r->gpr[5], r->gpr[6], r->gpr[7],
1884 <                        r->gpr[8], r->gpr[9], r->gpr[10], r->gpr[11],
1885 <                        r->gpr[12], r->gpr[13], r->gpr[14], r->gpr[15],
1886 <                        r->gpr[16], r->gpr[17], r->gpr[18], r->gpr[19],
1887 <                        r->gpr[20], r->gpr[21], r->gpr[22], r->gpr[23],
1888 <                        r->gpr[24], r->gpr[25], r->gpr[26], r->gpr[27],
1889 <                        r->gpr[28], r->gpr[29], r->gpr[30], r->gpr[31]);
1880 >                        crash_reason,
1881 >                        r->pc(), r->lr(), r->ctr(), r->msr(),
1882 >                        r->xer(), r->cr(),
1883 >                        r->gpr(0), r->gpr(1), r->gpr(2), r->gpr(3),
1884 >                        r->gpr(4), r->gpr(5), r->gpr(6), r->gpr(7),
1885 >                        r->gpr(8), r->gpr(9), r->gpr(10), r->gpr(11),
1886 >                        r->gpr(12), r->gpr(13), r->gpr(14), r->gpr(15),
1887 >                        r->gpr(16), r->gpr(17), r->gpr(18), r->gpr(19),
1888 >                        r->gpr(20), r->gpr(21), r->gpr(22), r->gpr(23),
1889 >                        r->gpr(24), r->gpr(25), r->gpr(26), r->gpr(27),
1890 >                        r->gpr(28), r->gpr(29), r->gpr(30), r->gpr(31));
1891                  exit(1);
1892                  QuitEmulator();
1893                  return;
1894          } else {
1895                  // We crashed. Save registers, tell tick thread and loop forever
1896 <                sigsegv_regs = *(sigregs *)r;
1896 >                build_sigregs(&sigsegv_regs, r);
1897                  emul_thread_fatal = true;
1898                  for (;;) ;
1899          }
# Line 1602 | Line 1905 | rti:;
1905   *  SIGILL handler
1906   */
1907  
1908 < static void sigill_handler(int sig, sigcontext_struct *sc)
1908 > static void sigill_handler(int sig, siginfo_t *sip, void *scp)
1909   {
1910 <        pt_regs *r = sc->regs;
1910 >        machine_regs *r = MACHINE_REGISTERS(scp);
1911          char str[256];
1912  
1913          // Fault in Mac ROM or RAM?
1914 <        bool mac_fault = (r->nip >= ROM_BASE) && (r->nip < (ROM_BASE + ROM_AREA_SIZE)) || (r->nip >= RAMBase) && (r->nip < (RAMBase + RAMSize));
1914 >        bool mac_fault = (r->pc() >= ROM_BASE) && (r->pc() < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc() >= RAMBase) && (r->pc() < (RAMBase + RAMSize));
1915          if (mac_fault) {
1916  
1917                  // Get opcode and divide into fields
1918 <                uint32 opcode = *((uint32 *)r->nip);
1918 >                uint32 opcode = *((uint32 *)r->pc());
1919                  uint32 primop = opcode >> 26;
1920                  uint32 exop = (opcode >> 1) & 0x3ff;
1921                  uint32 ra = (opcode >> 16) & 0x1f;
# Line 1623 | Line 1926 | static void sigill_handler(int sig, sigc
1926                  switch (primop) {
1927                          case 9:         // POWER instructions
1928                          case 22:
1929 < power_inst:             sprintf(str, GetString(STR_POWER_INSTRUCTION_ERR), r->nip, r->gpr[1], opcode);
1929 > power_inst:             sprintf(str, GetString(STR_POWER_INSTRUCTION_ERR), r->pc(), r->gpr(1), opcode);
1930                                  ErrorAlert(str);
1931                                  QuitEmulator();
1932                                  return;
# Line 1631 | Line 1934 | power_inst:            sprintf(str, GetString(STR_
1934                          case 31:
1935                                  switch (exop) {
1936                                          case 83:        // mfmsr
1937 <                                                r->gpr[rd] = 0xf072;
1938 <                                                r->nip += 4;
1937 >                                                r->gpr(rd) = 0xf072;
1938 >                                                r->pc() += 4;
1939                                                  goto rti;
1940  
1941                                          case 210:       // mtsr
1942                                          case 242:       // mtsrin
1943                                          case 306:       // tlbie
1944 <                                                r->nip += 4;
1944 >                                                r->pc() += 4;
1945                                                  goto rti;
1946  
1947                                          case 339: {     // mfspr
# Line 1654 | Line 1957 | power_inst:            sprintf(str, GetString(STR_
1957                                                          case 957:       // PMC3
1958                                                          case 958:       // PMC4
1959                                                          case 959:       // SDA
1960 <                                                                r->nip += 4;
1960 >                                                                r->pc() += 4;
1961                                                                  goto rti;
1962                                                          case 25:        // SDR1
1963 <                                                                r->gpr[rd] = 0xdead001f;
1964 <                                                                r->nip += 4;
1963 >                                                                r->gpr(rd) = 0xdead001f;
1964 >                                                                r->pc() += 4;
1965                                                                  goto rti;
1966                                                          case 287:       // PVR
1967 <                                                                r->gpr[rd] = PVR;
1968 <                                                                r->nip += 4;
1967 >                                                                r->gpr(rd) = PVR;
1968 >                                                                r->pc() += 4;
1969                                                                  goto rti;
1970                                                  }
1971                                                  break;
# Line 1698 | Line 2001 | power_inst:            sprintf(str, GetString(STR_
2001                                                          case 957:       // PMC3
2002                                                          case 958:       // PMC4
2003                                                          case 959:       // SDA
2004 <                                                                r->nip += 4;
2004 >                                                                r->pc() += 4;
2005                                                                  goto rti;
2006                                                  }
2007                                                  break;
# Line 1717 | Line 2020 | power_inst:            sprintf(str, GetString(STR_
2020  
2021                  // In GUI mode, show error alert
2022                  if (!PrefsFindBool("nogui")) {
2023 <                        sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->nip, r->gpr[24], r->gpr[1], opcode);
2023 >                        sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc(), r->gpr(24), r->gpr(1), opcode);
2024                          ErrorAlert(str);
2025                          QuitEmulator();
2026                          return;
# Line 1725 | Line 2028 | power_inst:            sprintf(str, GetString(STR_
2028          }
2029  
2030          // For all other errors, jump into debugger (sort of...)
2031 +        crash_reason = "SIGILL";
2032          if (!ready_for_signals) {
2033 <                printf("SIGILL\n");
2034 <                printf(" sigcontext %p, pt_regs %p\n", sc, r);
2033 >                printf("%s\n");
2034 >                printf(" sigcontext %p, machine_regs %p\n", scp, r);
2035                  printf(
2036                          "   pc %08lx     lr %08lx    ctr %08lx    msr %08lx\n"
2037                          "  xer %08lx     cr %08lx  \n"
# Line 1739 | Line 2043 | power_inst:            sprintf(str, GetString(STR_
2043                          "  r20 %08lx    r21 %08lx    r22 %08lx    r23 %08lx\n"
2044                          "  r24 %08lx    r25 %08lx    r26 %08lx    r27 %08lx\n"
2045                          "  r28 %08lx    r29 %08lx    r30 %08lx    r31 %08lx\n",
2046 <                        r->nip, r->link, r->ctr, r->msr,
2047 <                        r->xer, r->ccr,
2048 <                        r->gpr[0], r->gpr[1], r->gpr[2], r->gpr[3],
2049 <                        r->gpr[4], r->gpr[5], r->gpr[6], r->gpr[7],
2050 <                        r->gpr[8], r->gpr[9], r->gpr[10], r->gpr[11],
2051 <                        r->gpr[12], r->gpr[13], r->gpr[14], r->gpr[15],
2052 <                        r->gpr[16], r->gpr[17], r->gpr[18], r->gpr[19],
2053 <                        r->gpr[20], r->gpr[21], r->gpr[22], r->gpr[23],
2054 <                        r->gpr[24], r->gpr[25], r->gpr[26], r->gpr[27],
2055 <                        r->gpr[28], r->gpr[29], r->gpr[30], r->gpr[31]);
2046 >                        crash_reason,
2047 >                        r->pc(), r->lr(), r->ctr(), r->msr(),
2048 >                        r->xer(), r->cr(),
2049 >                        r->gpr(0), r->gpr(1), r->gpr(2), r->gpr(3),
2050 >                        r->gpr(4), r->gpr(5), r->gpr(6), r->gpr(7),
2051 >                        r->gpr(8), r->gpr(9), r->gpr(10), r->gpr(11),
2052 >                        r->gpr(12), r->gpr(13), r->gpr(14), r->gpr(15),
2053 >                        r->gpr(16), r->gpr(17), r->gpr(18), r->gpr(19),
2054 >                        r->gpr(20), r->gpr(21), r->gpr(22), r->gpr(23),
2055 >                        r->gpr(24), r->gpr(25), r->gpr(26), r->gpr(27),
2056 >                        r->gpr(28), r->gpr(29), r->gpr(30), r->gpr(31));
2057                  exit(1);
2058                  QuitEmulator();
2059                  return;
2060          } else {
2061                  // We crashed. Save registers, tell tick thread and loop forever
2062 <                sigsegv_regs = *(sigregs *)r;
2062 >                build_sigregs(&sigsegv_regs, r);
2063                  emul_thread_fatal = true;
2064                  for (;;) ;
2065          }
# Line 1764 | Line 2069 | rti:;
2069  
2070  
2071   /*
2072 + *  Helpers to share 32-bit addressable data with MacOS
2073 + */
2074 +
2075 + bool SheepMem::Init(void)
2076 + {
2077 +        // Size of a native page
2078 +        page_size = getpagesize();
2079 +
2080 +        // Allocate SheepShaver globals
2081 +        if (vm_acquire_fixed((char *)base, size) < 0)
2082 +                return false;
2083 +
2084 +        // Allocate page with all bits set to 0
2085 +        zero_page = base + size;
2086 +        if (vm_acquire_fixed((char *)zero_page, page_size) < 0)
2087 +                return false;
2088 +        memset((char *)zero_page, 0, page_size);
2089 +        if (vm_protect((char *)zero_page, page_size, VM_PAGE_READ) < 0)
2090 +                return false;
2091 +
2092 + #if EMULATED_PPC
2093 +        // Allocate alternate stack for PowerPC interrupt routine
2094 +        sig_stack = zero_page + page_size;
2095 +        if (vm_acquire_fixed((char *)sig_stack, SIG_STACK_SIZE) < 0)
2096 +                return false;
2097 + #endif
2098 +
2099 +        top = base + size;
2100 +        return true;
2101 + }
2102 +
2103 + void SheepMem::Exit(void)
2104 + {
2105 +        if (top) {
2106 +                // Delete SheepShaver globals
2107 +                vm_release((void *)base, size);
2108 +
2109 +                // Delete zero page
2110 +                vm_release((void *)zero_page, page_size);
2111 +
2112 + #if EMULATED_PPC
2113 +                // Delete alternate stack for PowerPC interrupt routine
2114 +                vm_release((void *)sig_stack, SIG_STACK_SIZE);
2115 + #endif
2116 +        }
2117 + }
2118 +
2119 +
2120 + /*
2121   *  Display alert
2122   */
2123  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines