--- SheepShaver/src/Unix/main_unix.cpp 2003/10/12 05:44:14 1.9 +++ SheepShaver/src/Unix/main_unix.cpp 2003/12/05 12:41:19 1.19 @@ -109,6 +109,7 @@ #include "user_strings.h" #include "vm_alloc.h" #include "sigsegv.h" +#include "thunks.h" #define DEBUG 0 #include "debug.h" @@ -145,7 +146,7 @@ const char ROM_FILE_NAME[] = "ROM"; const char ROM_FILE_NAME2[] = "Mac OS ROM"; -const uint32 RAM_BASE = 0x20000000; // Base address of RAM +const uintptr RAM_BASE = 0x20000000; // Base address of RAM const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack @@ -172,9 +173,6 @@ void *TOC; // Small data pointer (r13 #endif uint32 RAMBase; // Base address of Mac RAM uint32 RAMSize; // Size of Mac RAM -uint32 SheepStack1Base; // SheepShaver first alternate stack base -uint32 SheepStack2Base; // SheepShaver second alternate stack base -uint32 SheepThunksBase; // SheepShaver thunks base uint32 KernelDataAddr; // Address of Kernel Data uint32 BootGlobsAddr; // Address of BootGlobs structure at top of Mac RAM uint32 PVR; // Theoretical PVR @@ -183,11 +181,10 @@ int64 BusClockSpeed; // Bus clock speed // Global variables -static char *x_display_name = NULL; // X11 display name +char *x_display_name = NULL; // X11 display name Display *x_display = NULL; // X11 display handle static int zero_fd = 0; // FD of /dev/zero -static bool sheep_area_mapped = false; // Flag: SheepShaver data area mmap()ed static bool lm_area_mapped = false; // Flag: Low Memory area mmap()ped static int kernel_area = -1; // SHM ID of Kernel Data area static bool rom_area_mapped = false; // Flag: Mac ROM mmap()ped @@ -216,6 +213,10 @@ static bool emul_thread_fatal = false; static sigregs sigsegv_regs; // Register dump when crashed #endif +uintptr SheepMem::zero_page = 0; // Address of ro page filled in with zeros +uintptr SheepMem::base = 0x60000000; // Address of SheepShaver data +uintptr SheepMem::top = 0; // Top of SheepShaver data (stack like storage) + // Prototypes static void Quit(void); @@ -224,6 +225,9 @@ static void *nvram_func(void *arg); static void *tick_func(void *arg); #if EMULATED_PPC static void sigusr2_handler(int sig); +extern void emul_ppc(uint32 start); +extern void init_emul_ppc(void); +extern void exit_emul_ppc(void); #else static void sigusr2_handler(int sig, sigcontext_struct *sc); static void sigsegv_handler(int sig, sigcontext_struct *sc); @@ -232,11 +236,7 @@ static void sigill_handler(int sig, sigc // From asm_linux.S -#if EMULATED_PPC -extern int atomic_add(int *var, int v); -extern int atomic_and(int *var, int v); -extern int atomic_or(int *var, int v); -#else +#if !EMULATED_PPC extern "C" void *get_toc(void); extern "C" void *get_sp(void); extern "C" void flush_icache_range(void *start, void *end); @@ -251,6 +251,47 @@ extern void paranoia_check(void); #endif +#if EMULATED_PPC +/* + * Atomic operations + */ + +#if HAVE_SPINLOCKS +static spinlock_t atomic_ops_lock = SPIN_LOCK_UNLOCKED; +#else +#define spin_lock(LOCK) +#define spin_unlock(LOCK) +#endif + +int atomic_add(int *var, int v) +{ + spin_lock(&atomic_ops_lock); + int ret = *var; + *var += v; + spin_unlock(&atomic_ops_lock); + return ret; +} + +int atomic_and(int *var, int v) +{ + spin_lock(&atomic_ops_lock); + int ret = *var; + *var &= v; + spin_unlock(&atomic_ops_lock); + return ret; +} + +int atomic_or(int *var, int v) +{ + spin_lock(&atomic_ops_lock); + int ret = *var; + *var |= v; + spin_unlock(&atomic_ops_lock); + return ret; +} +#endif + + /* * Main program */ @@ -269,7 +310,6 @@ int main(int argc, char **argv) char str[256]; uint32 *boot_globs; int16 i16; - int drive, driver; int rom_fd; FILE *proc_file; const char *rom_path; @@ -431,21 +471,17 @@ int main(int argc, char **argv) ErrorAlert(str); goto quit; } - kernel_data = (KernelData *)0x68ffe000; + kernel_data = (KernelData *)KERNEL_DATA_BASE; emulator_data = &kernel_data->ed; - KernelDataAddr = (uint32)kernel_data; + KernelDataAddr = KERNEL_DATA_BASE; D(bug("Kernel Data at %p, Emulator Data at %p\n", kernel_data, emulator_data)); // Create area for SheepShaver data - if (vm_acquire_fixed((char *)SHEEP_BASE, SHEEP_SIZE) < 0) { + if (!SheepMem::Init()) { sprintf(str, GetString(STR_SHEEP_MEM_MMAP_ERR), strerror(errno)); ErrorAlert(str); goto quit; } - SheepStack1Base = SHEEP_BASE + 0x10000; - SheepStack2Base = SheepStack1Base + 0x10000; - SheepThunksBase = SheepStack2Base + 0x1000; - sheep_area_mapped = true; // Create area for Mac ROM if (vm_acquire_fixed((char *)ROM_BASE, ROM_AREA_SIZE) < 0) { @@ -524,10 +560,10 @@ int main(int argc, char **argv) XPRAMInit(); // Set boot volume - drive = PrefsFindInt32("bootdrive"); + i16 = PrefsFindInt32("bootdrive"); XPRAM[0x1378] = i16 >> 8; XPRAM[0x1379] = i16 & 0xff; - driver = PrefsFindInt32("bootdriver"); + i16 = PrefsFindInt32("bootdriver"); XPRAM[0x137a] = i16 >> 8; XPRAM[0x137b] = i16 & 0xff; @@ -540,6 +576,10 @@ int main(int argc, char **argv) boot_globs[1] = htonl(RAMSize); boot_globs[2] = htonl((uint32)-1); // End of bank table + // Init thunks + if (!ThunksInit()) + goto quit; + // Init drivers SonyInit(); DiskInit(); @@ -583,16 +623,17 @@ int main(int argc, char **argv) // Initialize Kernel Data memset(kernel_data, 0, sizeof(KernelData)); if (ROMType == ROMTYPE_NEWWORLD) { - static uint32 of_dev_tree[4] = {0, 0, 0, 0}; - static uint8 vector_lookup_tbl[128]; - static uint8 vector_mask_tbl[64]; + uintptr of_dev_tree = SheepMem::Reserve(4 * sizeof(uint32)); + memset((void *)of_dev_tree, 0, 4 * sizeof(uint32)); + uintptr vector_lookup_tbl = SheepMem::Reserve(128); + uintptr vector_mask_tbl = SheepMem::Reserve(64); memset((uint8 *)kernel_data + 0xb80, 0x3d, 0x80); - memset(vector_lookup_tbl, 0, 128); - memset(vector_mask_tbl, 0, 64); + memset((void *)vector_lookup_tbl, 0, 128); + memset((void *)vector_mask_tbl, 0, 64); kernel_data->v[0xb80 >> 2] = htonl(ROM_BASE); - kernel_data->v[0xb84 >> 2] = htonl((uint32)of_dev_tree); // OF device tree base - kernel_data->v[0xb90 >> 2] = htonl((uint32)vector_lookup_tbl); - kernel_data->v[0xb94 >> 2] = htonl((uint32)vector_mask_tbl); + kernel_data->v[0xb84 >> 2] = htonl(of_dev_tree); // OF device tree base + kernel_data->v[0xb90 >> 2] = htonl(vector_lookup_tbl); + kernel_data->v[0xb94 >> 2] = htonl(vector_mask_tbl); kernel_data->v[0xb98 >> 2] = htonl(ROM_BASE); // OpenPIC base kernel_data->v[0xbb0 >> 2] = htonl(0); // ADB base kernel_data->v[0xc20 >> 2] = htonl(RAMSize); @@ -628,28 +669,21 @@ int main(int argc, char **argv) D(bug("Initializing Low Memory...\n")); memset(NULL, 0, 0x3000); WriteMacInt32(XLM_SIGNATURE, FOURCC('B','a','a','h')); // Signature to detect SheepShaver - WriteMacInt32(XLM_KERNEL_DATA, (uint32)kernel_data); // For trap replacement routines + WriteMacInt32(XLM_KERNEL_DATA, KernelDataAddr); // For trap replacement routines WriteMacInt32(XLM_PVR, PVR); // Theoretical PVR WriteMacInt32(XLM_BUS_CLOCK, BusClockSpeed); // For DriverServicesLib patch WriteMacInt16(XLM_EXEC_RETURN_OPCODE, M68K_EXEC_RETURN); // For Execute68k() (RTS from the executed 68k code will jump here and end 68k mode) -#if EMULATED_PPC - WriteMacInt32(XLM_ETHER_INIT, POWERPC_NATIVE_OP_FUNC(NATIVE_ETHER_INIT)); - WriteMacInt32(XLM_ETHER_TERM, POWERPC_NATIVE_OP_FUNC(NATIVE_ETHER_TERM)); - WriteMacInt32(XLM_ETHER_OPEN, POWERPC_NATIVE_OP_FUNC(NATIVE_ETHER_OPEN)); - WriteMacInt32(XLM_ETHER_CLOSE, POWERPC_NATIVE_OP_FUNC(NATIVE_ETHER_CLOSE)); - WriteMacInt32(XLM_ETHER_WPUT, POWERPC_NATIVE_OP_FUNC(NATIVE_ETHER_WPUT)); - WriteMacInt32(XLM_ETHER_RSRV, POWERPC_NATIVE_OP_FUNC(NATIVE_ETHER_RSRV)); - WriteMacInt32(XLM_VIDEO_DOIO, POWERPC_NATIVE_OP_FUNC(NATIVE_VIDEO_DO_DRIVER_IO)); -#else - WriteMacInt32(XLM_TOC, (uint32)TOC); // TOC pointer of emulator - WriteMacInt32(XLM_ETHER_INIT, (uint32)InitStreamModule); // DLPI ethernet driver functions - WriteMacInt32(XLM_ETHER_TERM, (uint32)TerminateStreamModule); - WriteMacInt32(XLM_ETHER_OPEN, (uint32)ether_open); - WriteMacInt32(XLM_ETHER_CLOSE, (uint32)ether_close); - WriteMacInt32(XLM_ETHER_WPUT, (uint32)ether_wput); - WriteMacInt32(XLM_ETHER_RSRV, (uint32)ether_rsrv); - WriteMacInt32(XLM_VIDEO_DOIO, (uint32)VideoDoDriverIO); + WriteMacInt32(XLM_ZERO_PAGE, SheepMem::ZeroPage()); // Pointer to read-only page with all bits set to 0 +#if !EMULATED_PPC + WriteMacInt32(XLM_TOC, (uint32)TOC); // TOC pointer of emulator #endif + WriteMacInt32(XLM_ETHER_INIT, NativeFunction(NATIVE_ETHER_INIT)); // DLPI ethernet driver functions + WriteMacInt32(XLM_ETHER_TERM, NativeFunction(NATIVE_ETHER_TERM)); + WriteMacInt32(XLM_ETHER_OPEN, NativeFunction(NATIVE_ETHER_OPEN)); + WriteMacInt32(XLM_ETHER_CLOSE, NativeFunction(NATIVE_ETHER_CLOSE)); + WriteMacInt32(XLM_ETHER_WPUT, NativeFunction(NATIVE_ETHER_WPUT)); + WriteMacInt32(XLM_ETHER_RSRV, NativeFunction(NATIVE_ETHER_RSRV)); + WriteMacInt32(XLM_VIDEO_DOIO, NativeFunction(NATIVE_VIDEO_DO_DRIVER_IO)); D(bug("Low Memory initialized\n")); // Start 60Hz thread @@ -743,6 +777,11 @@ quit: static void Quit(void) { +#if EMULATED_PPC + // Exit PowerPC emulation + exit_emul_ppc(); +#endif + // Stop 60Hz thread if (tick_thread_active) { pthread_cancel(tick_thread); @@ -799,6 +838,9 @@ static void Quit(void) DiskExit(); SonyExit(); + // Delete SheepShaver globals + SheepMem::Exit(); + // Delete RAM area if (ram_area_mapped) vm_release((char *)RAM_BASE, RAMSize); @@ -846,8 +888,6 @@ static void Quit(void) */ #if EMULATED_PPC -extern void emul_ppc(uint32 start); -extern void init_emul_ppc(void); void jump_to_rom(uint32 entry) { init_emul_ppc(); @@ -912,19 +952,6 @@ void Execute68kTrap(uint16 trap, M68kReg uint16 proc[2] = {trap, M68K_RTS}; Execute68k((uint32)proc, r); } - - -/* - * Execute PPC code from EMUL_OP routine (real mode switch) - */ - -void ExecutePPC(void (*func)()) -{ - uint32 tvect[2] = {(uint32)func, 0}; // Fake TVECT - RoutineDescriptor desc = BUILD_PPC_ROUTINE_DESCRIPTOR(0, tvect); - M68kRegisters r; - Execute68k((uint32)&desc, &r); -} #endif @@ -1003,11 +1030,7 @@ void MakeExecutable(int dummy, void *sta void PatchAfterStartup(void) { -#if EMULATED_PPC ExecuteNative(NATIVE_VIDEO_INSTALL_ACCEL); -#else - ExecutePPC(VideoInstallAccel); -#endif InstallExtFS(); } @@ -1110,7 +1133,30 @@ static void *tick_func(void *arg) void Set_pthread_attr(pthread_attr_t *attr, int priority) { - // nothing to do +#ifdef HAVE_PTHREADS + pthread_attr_init(attr); +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + // Some of these only work for superuser + if (geteuid() == 0) { + pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED); + pthread_attr_setschedpolicy(attr, SCHED_FIFO); + struct sched_param fifo_param; + fifo_param.sched_priority = ((sched_get_priority_min(SCHED_FIFO) + + sched_get_priority_max(SCHED_FIFO)) / 2 + + priority); + pthread_attr_setschedparam(attr, &fifo_param); + } + if (pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM) != 0) { +#ifdef PTHREAD_SCOPE_BOUND_NP + // If system scope is not available (eg. we're not running + // with CAP_SCHED_MGT capability on an SGI box), try bound + // scope. It exposes pthread scheduling to the kernel, + // without setting realtime priority. + pthread_attr_setscope(attr, PTHREAD_SCOPE_BOUND_NP); +#endif + } +#endif +#endif } @@ -1325,7 +1371,7 @@ static void sigusr2_handler(int sig, sig if (InterruptFlags & INTFLAG_VIA) { ClearInterruptFlag(INTFLAG_VIA); ADBInterrupt(); - ExecutePPC(VideoVBL); + ExecuteNative(NATIVE_VIDEO_VBL); } } #endif @@ -1722,6 +1768,37 @@ rti:; /* + * Helpers to share 32-bit addressable data with MacOS + */ + +bool SheepMem::Init(void) +{ + if (vm_acquire_fixed((char *)base, size) < 0) + return false; + + zero_page = base + size; + + int page_size = getpagesize(); + if (vm_acquire_fixed((char *)zero_page, page_size) < 0) + return false; + memset((char *)zero_page, 0, page_size); + if (vm_protect((char *)zero_page, page_size, VM_PAGE_READ) < 0) + return false; + + top = base + size; + return true; +} + +void SheepMem::Exit(void) +{ + if (top) { + // The zero page is next to SheepShaver globals + vm_release((void *)base, size + getpagesize()); + } +} + + +/* * Display alert */