#include "types.h" #if defined(__unix__) || defined(__APPLE__) || defined(__SWITCH__) #if defined(__APPLE__) #define _XOPEN_SOURCE 1 #define __USE_GNU 1 #include #endif #include #include #if defined(__linux__) && !defined(__ANDROID__) #include #endif #include #ifdef __linux__ #include #endif #include "oslib/host_context.h" #include "hw/sh4/dyna/ngen.h" #include "rend/TexCache.h" #include "hw/mem/addrspace.h" #include "hw/mem/mem_watch.h" #include "emulator.h" #ifdef __SWITCH__ #include extern "C" char __start__; #define siginfo_t switch_siginfo_t #endif // __SWITCH__ void context_from_segfault(host_context_t* hctx, void* segfault_ctx); void context_to_segfault(host_context_t* hctx, void* segfault_ctx); #ifndef __SWITCH__ static struct sigaction next_segv_handler; #endif #if defined(__APPLE__) static struct sigaction next_bus_handler; #endif void fault_handler(int sn, siginfo_t * si, void *segfault_ctx) { // Ram watcher for net rollback if (memwatch::writeAccess(si->si_addr)) return; // code protection in RAM if (bm_RamWriteAccess(si->si_addr)) return; // texture protection in VRAM if (VramLockedWrite((u8*)si->si_addr)) return; #if FEAT_SHREC == DYNAREC_JIT // FPCB jump table protection if (addrspace::bm_lockedWrite((u8*)si->si_addr)) return; // fast mem access rewriting host_context_t ctx; context_from_segfault(&ctx, segfault_ctx); if (sh4Dynarec->rewrite(ctx, si->si_addr)) { context_to_segfault(&ctx, segfault_ctx); return; } ERROR_LOG(COMMON, "SIGSEGV @ %p invalid access to %p", (void *)ctx.pc, si->si_addr); #endif #ifdef __SWITCH__ MemoryInfo meminfo; u32 pageinfo; svcQueryMemory(&meminfo, &pageinfo, (u64)&__start__); ERROR_LOG(COMMON, ".text base: %p -> offset: %lx", (void*)meminfo.addr, ctx.pc - meminfo.addr); #else if (next_segv_handler.sa_sigaction != nullptr) next_segv_handler.sa_sigaction(sn, si, segfault_ctx); else #endif // !__SWITCH__ die("segfault"); } #undef HOST_CTX_READY void os_InstallFaultHandler() { #ifndef __SWITCH__ struct sigaction act; memset(&act, 0, sizeof(act)); act.sa_handler = SIG_IGN; sigaction(SIGPIPE, &act, nullptr); act.sa_sigaction = fault_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; sigaction(SIGSEGV, &act, &next_segv_handler); #endif #if defined(__APPLE__) //this is broken on osx/ios/mach in general sigaction(SIGBUS, &act, &next_bus_handler); #endif } void os_UninstallFaultHandler() { #ifndef __SWITCH__ sigaction(SIGSEGV, &next_segv_handler, nullptr); #endif #if defined(__APPLE__) sigaction(SIGBUS, &next_bus_handler, nullptr); #endif } #if !defined(__unix__) && !defined(LIBRETRO) && !defined(__SWITCH__) [[noreturn]] void os_DebugBreak() { __builtin_trap(); } #endif // RunFast mode is the combination of the following conditions: // * the VFP11 coprocessor is in flush-to-zero mode // * the VFP11 coprocessor is in default NaN mode // * all exception enable bits are cleared. static void enable_runfast() { #if HOST_CPU == CPU_ARM && !defined(ARMCC) static const unsigned int x = 0x04086060; // reset and disable FP exceptions, flush-to-zero, default NaN mode static const unsigned int y = 0x03000000; // round to zero int r; asm volatile ( "fmrx %0, fpscr \n\t" //r0 = FPSCR "and %0, %0, %1 \n\t" //r0 = r0 & 0x04086060 "orr %0, %0, %2 \n\t" //r0 = r0 | 0x03000000 "fmxr fpscr, %0 \n\t" //FPSCR = r0 : "=r"(r) : "r"(x), "r"(y) ); DEBUG_LOG(BOOT, "ARM VFP-Run Fast (NFP) enabled !"); #endif } // Some old CPUs lack the NX (no exec) flag so READ_IMPLIES_EXEC is set by default on these platforms. // However resetting the flag isn't going to magically change the way the CPU works. So I wonder how useful this is. // It's not needed on modern 64-bit architectures anyway. static void linux_fix_personality() { #if defined(__linux__) && !defined(__ANDROID__) && (HOST_CPU == CPU_X86 || HOST_CPU == CPU_ARM) DEBUG_LOG(BOOT, "Personality: %08X", personality(0xFFFFFFFF)); personality(~READ_IMPLIES_EXEC & personality(0xFFFFFFFF)); DEBUG_LOG(BOOT, "Updated personality: %08X", personality(0xFFFFFFFF)); #endif } #if defined(__unix__) && !defined(LIBRETRO) && !defined(__ANDROID__) static void sigintHandler(int) { dc_exit(); } #endif void common_linux_setup() { linux_fix_personality(); enable_runfast(); os_InstallFaultHandler(); #if defined(__unix__) && !defined(LIBRETRO) && !defined(__ANDROID__) // exit cleanly on ^C signal(SIGINT, sigintHandler); #endif DEBUG_LOG(BOOT, "Linux paging: sysconf %ld PAGE_SIZE %ld PAGE_MASK %lX", sysconf(_SC_PAGESIZE), (unsigned long)PAGE_SIZE, (long)PAGE_MASK); verify(PAGE_MASK==(sysconf(_SC_PAGESIZE)-1)); } #ifndef __APPLE__ void os_SetThreadName(const char *name) { #ifdef __linux__ if (strlen(name) > 16) { static char tmp[17]; strncpy(tmp, name, 16); name = tmp; } pthread_setname_np(pthread_self(), name); #endif } #endif #endif // __unix__ or __APPLE__ or __SWITCH__