diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index a805b6857..f37d0d9a8 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -74,7 +74,7 @@ jobs: if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }} - name: Setup Sentry CLI - uses: mathieu-bour/setup-sentry-cli@1.2.0 + uses: mathieu-bour/setup-sentry-cli@v1 env: SENTRY_TOKEN: ${{ secrets.SENTRY_TOKEN }} with: diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index a9a81e6e4..3a33ca479 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -157,7 +157,7 @@ jobs: if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }} - name: Setup Sentry CLI - uses: mathieu-bour/setup-sentry-cli@1.2.0 + uses: mathieu-bour/setup-sentry-cli@v1 env: SENTRY_TOKEN: ${{ secrets.SENTRY_TOKEN }} with: diff --git a/.gitmodules b/.gitmodules index 70a08904b..899318949 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,7 +3,7 @@ url = https://github.com/libsdl-org/SDL.git [submodule "core/deps/libchdr"] path = core/deps/libchdr - url = https://github.com/rtissera/libchdr.git + url = https://github.com/flyinghead/libchdr.git [submodule "core/deps/luabridge"] path = core/deps/luabridge url = https://github.com/vinniefalco/LuaBridge.git diff --git a/core/deps/khronos/GL4/gl3w.c b/core/deps/khronos/GL4/gl3w.c index 661dc1c8f..f6e0c9815 100644 --- a/core/deps/khronos/GL4/gl3w.c +++ b/core/deps/khronos/GL4/gl3w.c @@ -115,7 +115,11 @@ static GL3WglProc (*glx_get_proc_address)(const GLubyte *); static int open_libgl(void) { +#if defined(__OpenBSD__) + libgl = dlopen("libGL.so", RTLD_LAZY | RTLD_LOCAL); +#else libgl = dlopen("libGL.so.1", RTLD_LAZY | RTLD_LOCAL); +#endif if (!libgl) return GL3W_ERROR_LIBRARY_OPEN; diff --git a/core/deps/libchdr b/core/deps/libchdr index 2781322c4..8c319cf7b 160000 --- a/core/deps/libchdr +++ b/core/deps/libchdr @@ -1 +1 @@ -Subproject commit 2781322c4a7f8315c5fd6499129ad4b718e35843 +Subproject commit 8c319cf7be87186857972829e343b9082341d365 diff --git a/core/hw/aica/dsp_x64.cpp b/core/hw/aica/dsp_x64.cpp index a4af8ed5a..ca397210e 100644 --- a/core/hw/aica/dsp_x64.cpp +++ b/core/hw/aica/dsp_x64.cpp @@ -38,7 +38,9 @@ constexpr size_t CodeBufferSize = 32 * 1024; static u8 *CodeBuffer; #else alignas(4096) static u8 CodeBuffer[CodeBufferSize] - #if defined(__unix__) + #if defined(__OpenBSD__) + __attribute__((section(".openbsd.mutable"))); + #elif defined(__unix__) __attribute__((section(".text"))); #elif defined(__APPLE__) __attribute__((section("__TEXT,.text"))); diff --git a/core/hw/aica/sgc_if.cpp b/core/hw/aica/sgc_if.cpp index 1847246c0..c26cbc28b 100755 --- a/core/hw/aica/sgc_if.cpp +++ b/core/hw/aica/sgc_if.cpp @@ -639,11 +639,11 @@ struct ChannelEx //SA,PCMS void UpdateSA() { - u32 addr = (ccd->SA_hi<<16) | ccd->SA_low; - if (ccd->PCMS==0) - addr&=~1; //0: 16 bit + u32 addr = (ccd->SA_hi << 16) | ccd->SA_low; + if (ccd->PCMS == 0) + addr &= ~1; //0: 16 bit - SA = &aica_ram[addr]; + SA = &aica_ram[addr & ARAM_MASK]; } //LSA,LEA void UpdateLoop() @@ -896,6 +896,7 @@ void StepDecodeSample(ChannelEx* ch,u32 CA) if (!last && PCMS<2) return ; + // TODO bound checking of sample addresses s16* sptr16=(s16*)ch->SA; s8* sptr8=(s8*)sptr16; u8* uptr8=(u8*)sptr16; diff --git a/core/hw/arm7/arm7_rec.cpp b/core/hw/arm7/arm7_rec.cpp index 9793f66cb..508a4e306 100644 --- a/core/hw/arm7/arm7_rec.cpp +++ b/core/hw/arm7/arm7_rec.cpp @@ -53,6 +53,8 @@ void (*EntryPoints[ARAM_SIZE_MAX / 4])(); #if defined(_WIN32) || defined(TARGET_IPHONE) || defined(TARGET_ARM_MAC) static u8 *ARM7_TCB; +#elif defined(__OpenBSD__) +alignas(4096) static u8 ARM7_TCB[ICacheSize] __attribute__((section(".openbsd.mutable"))); #elif defined(__unix__) || defined(__SWITCH__) alignas(4096) static u8 ARM7_TCB[ICacheSize] __attribute__((section(".text"))); #elif defined(__APPLE__) diff --git a/core/hw/naomi/naomi.cpp b/core/hw/naomi/naomi.cpp index 1b59ddafa..b34e54633 100644 --- a/core/hw/naomi/naomi.cpp +++ b/core/hw/naomi/naomi.cpp @@ -528,6 +528,7 @@ void naomi_reg_Reset(bool hard) } if (settings.naomi.multiboard) multiboard = new Multiboard(); + networkOutput.reset(); } else if (multiboard != nullptr) multiboard->reset(); diff --git a/core/hw/naomi/naomi_cart.cpp b/core/hw/naomi/naomi_cart.cpp index 62d420439..7b773d78c 100644 --- a/core/hw/naomi/naomi_cart.cpp +++ b/core/hw/naomi/naomi_cart.cpp @@ -302,6 +302,8 @@ static void loadMameRom(const char *filename, LoadProgress *progress) { u8 *dst = (u8 *)CurrentCartridge->GetPtr(game->blobs[romid].offset, len); u8 *src = (u8 *)CurrentCartridge->GetPtr(game->blobs[romid].src_offset, len); + if (dst == nullptr || src == nullptr) + throw NaomiCartException("Invalid ROM"); memcpy(dst, src, game->blobs[romid].length); DEBUG_LOG(NAOMI, "Copied: %x bytes from %07x to %07x", game->blobs[romid].length, game->blobs[romid].src_offset, game->blobs[romid].offset); } @@ -331,6 +333,8 @@ static void loadMameRom(const char *filename, LoadProgress *progress) case Normal: { u8 *dst = (u8 *)CurrentCartridge->GetPtr(game->blobs[romid].offset, len); + if (dst == nullptr) + throw NaomiCartException(std::string("Invalid ROM: truncated ") + game->blobs[romid].filename); u32 read = file->Read(dst, game->blobs[romid].length); if (config::GGPOEnable) md5.add(dst, game->blobs[romid].length); @@ -346,6 +350,8 @@ static void loadMameRom(const char *filename, LoadProgress *progress) u32 read = file->Read(buf, game->blobs[romid].length); u16 *to = (u16 *)CurrentCartridge->GetPtr(game->blobs[romid].offset, len); + if (to == nullptr) + throw NaomiCartException(std::string("Invalid ROM: truncated ") + game->blobs[romid].filename); u16 *from = (u16 *)buf; for (int i = game->blobs[romid].length / 2; --i >= 0; to++) *to++ = *from++; @@ -719,10 +725,14 @@ bool Cartridge::Write(u32 offset, u32 size, u32 data) void* Cartridge::GetPtr(u32 offset, u32& size) { - offset &= 0x1FFFffff; + offset &= 0x1fffffff; - verify(offset < RomSize); - verify((offset + size) <= RomSize); + if (offset >= RomSize || offset + size > RomSize) + { + WARN_LOG(NAOMI, "Invalid naomi cart: offset %x size %x rom size %x", offset, size, RomSize); + size = 0; + return nullptr; + } return &RomPtr[offset]; } @@ -754,7 +764,7 @@ void* NaomiCartridge::GetDmaPtr(u32& size) { INFO_LOG(NAOMI, "Error: DmaOffset >= RomSize"); size = 0; - return NULL; + return nullptr; } size = std::min(size, RomSize - (DmaOffset & 0x1fffffff)); return GetPtr(DmaOffset, size); diff --git a/core/hw/naomi/naomi_m3comm.cpp b/core/hw/naomi/naomi_m3comm.cpp index 5f22ba09f..cd53bdb92 100644 --- a/core/hw/naomi/naomi_m3comm.cpp +++ b/core/hw/naomi/naomi_m3comm.cpp @@ -53,10 +53,12 @@ struct CommBoardStat u16 dummy[7]; }; +#if !defined(__OpenBSD__) static inline u16 swap16(u16 w) { return (w >> 8) | (w << 8); } +#endif static void vblankCallback(Event event, void *param) { ((NaomiM3Comm *)param)->vblank(); diff --git a/core/hw/pvr/pvr.cpp b/core/hw/pvr/pvr.cpp index c267db300..0c6141f90 100644 --- a/core/hw/pvr/pvr.cpp +++ b/core/hw/pvr/pvr.cpp @@ -46,7 +46,8 @@ void reset(bool hard) rend_reset(); tactx_Term(); elan::reset(hard); - ta_parse_reset(); + if (hard) + ta_parse_reset(); } void init() diff --git a/core/hw/sh4/dyna/driver.cpp b/core/hw/sh4/dyna/driver.cpp index 22db2efa0..9d0df0ee1 100644 --- a/core/hw/sh4/dyna/driver.cpp +++ b/core/hw/sh4/dyna/driver.cpp @@ -23,7 +23,9 @@ static u8 *SH4_TCB; #else alignas(4096) static u8 SH4_TCB[CODE_SIZE + TEMP_CODE_SIZE] -#if defined(__unix__) || defined(__SWITCH__) +#if defined(__OpenBSD__) + __attribute__((section(".openbsd.mutable"))); +#elif defined(__unix__) || defined(__SWITCH__) __attribute__((section(".text"))); #elif defined(__APPLE__) __attribute__((section("__TEXT,.text"))); diff --git a/core/linux/context.cpp b/core/linux/context.cpp index efbb45dac..50e3b0b8d 100644 --- a/core/linux/context.cpp +++ b/core/linux/context.cpp @@ -8,15 +8,24 @@ #define __USE_GNU 1 #endif - #if !defined(TARGET_NO_EXCEPTIONS) - #include - #endif + #if !defined(TARGET_NO_EXCEPTIONS) && !defined(__OpenBSD__) + #include + #endif + + #if defined(__OpenBSD__) + #include + #endif + #endif ////// +#if defined(__OpenBSD__) +#define MCTX(p) (((ucontext_t *)(segfault_ctx)) p) +#else #define MCTX(p) (((ucontext_t *)(segfault_ctx))->uc_mcontext p) +#endif template static void bicopy(Tctx& ctx, Tseg& seg) { @@ -82,6 +91,11 @@ static void context_segfault(host_context_t* hostctx, void* segfault_ctx) #elif HOST_CPU == CPU_X64 #if defined(__FreeBSD__) || defined(__DragonFly__) bicopy(hostctx->pc, MCTX(.mc_rip)); + #elif defined(__OpenBSD__) + bicopy(hostctx->pc, MCTX(->sc_rip)); + bicopy(hostctx->rsp, MCTX(->sc_rsp)); + bicopy(hostctx->r9, MCTX(->sc_r9)); + bicopy(hostctx->rdi, MCTX(->sc_rdi)); #elif defined(__NetBSD__) bicopy(hostctx->pc, MCTX(.__gregs[_REG_RIP])); bicopy(hostctx->rsp, MCTX(.__gregs[REG_RSP])); diff --git a/core/network/output.h b/core/network/output.h index 7cc5b9aca..4f252f8f4 100644 --- a/core/network/output.h +++ b/core/network/output.h @@ -68,26 +68,24 @@ public: } } + void reset() + { + gameNameSent = false; + } + void output(const char *name, u32 value) { if (!config::NetworkOutput) return; + if (!gameNameSent) + { + send("game = " + settings.content.gameId + "\n"); + gameNameSent = true; + } char s[9]; sprintf(s, "%x", value); std::string msg = std::string(name) + " = " + std::string(s) + "\n"; // mame uses \r - std::vector errorSockets; - for (sock_t sock : clients) - if (::send(sock, msg.c_str(), msg.length(), 0) < 0) - { - int error = get_last_error(); - if (error != L_EWOULDBLOCK && error != L_EAGAIN) - errorSockets.push_back(sock); - } - for (sock_t sock : errorSockets) - { - closesocket(sock); - clients.erase(std::find(clients.begin(), clients.end(), sock)); - } + send(msg); } private: @@ -107,8 +105,26 @@ private: } } + void send(const std::string& msg) + { + std::vector errorSockets; + for (sock_t sock : clients) + if (::send(sock, msg.c_str(), msg.length(), 0) < 0) + { + int error = get_last_error(); + if (error != L_EWOULDBLOCK && error != L_EAGAIN) + errorSockets.push_back(sock); + } + for (sock_t sock : errorSockets) + { + closesocket(sock); + clients.erase(std::find(clients.begin(), clients.end(), sock)); + } + } + sock_t server = INVALID_SOCKET; std::vector clients; + bool gameNameSent = false; }; extern NetworkOutput networkOutput; diff --git a/core/oslib/audiobackend_oboe.cpp b/core/oslib/audiobackend_oboe.cpp index c7137a6f7..08bc6e2d6 100644 --- a/core/oslib/audiobackend_oboe.cpp +++ b/core/oslib/audiobackend_oboe.cpp @@ -128,9 +128,14 @@ public: NOTICE_LOG(AUDIO, "Oboe driver stopping"); if (stream != nullptr) { - stream->stop(); - stream->close(); + // Don't let the AudioErrorCallback term/reinit while we are stopping + // This won't prevent shit to hit the fan if it's already in the process + // of doing so but this is a pretty rare event and happens on devices + // that have audio issues already. + auto localStream = stream; stream.reset(); + localStream->stop(); + localStream->close(); } } diff --git a/core/reios/reios.cpp b/core/reios/reios.cpp index dd6452d40..949a660cc 100644 --- a/core/reios/reios.cpp +++ b/core/reios/reios.cpp @@ -121,8 +121,10 @@ static bool reios_locate_bootfile(const char* bootfile) // system settings flash_syscfg_block syscfg{}; int rc = static_cast(flashrom)->ReadBlock(FLASH_PT_USER, FLASH_USER_SYSCFG, &syscfg); - verify(rc != 0); - memcpy(&data[16], &syscfg.time_lo, 8); + if (rc == 0) + WARN_LOG(REIOS, "Can't read system settings from flash"); + else + memcpy(&data[16], &syscfg.time_lo, 8); memcpy(GetMemPtr(0x8c000068, sizeof(data)), data, sizeof(data)); diff --git a/core/rend/TexCache.cpp b/core/rend/TexCache.cpp index e25d3ccbe..5f781b38d 100644 --- a/core/rend/TexCache.cpp +++ b/core/rend/TexCache.cpp @@ -453,11 +453,11 @@ void BaseTextureCacheData::unprotectVRam() bool BaseTextureCacheData::Delete() { + unprotectVRam(); + if (custom_load_in_progress > 0) return false; - unprotectVRam(); - free(custom_image_data); custom_image_data = nullptr; @@ -625,6 +625,7 @@ void BaseTextureCacheData::Update() else { WARN_LOG(RENDERER, "Warning: invalid texture. Address %08X %08X size %d", sa_tex, sa, size); + unprotectVRam(); return; } } diff --git a/core/rend/dx11/dx11context.cpp b/core/rend/dx11/dx11context.cpp index 451563a5c..5e283602c 100644 --- a/core/rend/dx11/dx11context.cpp +++ b/core/rend/dx11/dx11context.cpp @@ -265,7 +265,7 @@ void DX11Context::resize() #endif if (FAILED(hr)) { - WARN_LOG(RENDERER, "ResizeBuffers failed"); + WARN_LOG(RENDERER, "ResizeBuffers failed: %x", hr); return; } @@ -274,14 +274,14 @@ void DX11Context::resize() hr = swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)&backBuffer.get()); if (FAILED(hr)) { - WARN_LOG(RENDERER, "swapChain->GetBuffer() failed"); + WARN_LOG(RENDERER, "swapChain->GetBuffer() failed: %x", hr); return; } hr = pDevice->CreateRenderTargetView(backBuffer, nullptr, &renderTargetView.get()); if (FAILED(hr)) { - WARN_LOG(RENDERER, "CreateRenderTargetView failed"); + WARN_LOG(RENDERER, "CreateRenderTargetView failed: %x", hr); return; } pDeviceContext->OMSetRenderTargets(1, &renderTargetView.get(), nullptr); diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index 2b2dd3269..63e42f264 100644 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -652,8 +652,6 @@ GLuint gl_CompileAndLink(const char *vertexShader, const char *fragmentShader) glcache.UseProgram(program); - verify(glIsProgram(program)); - return program; } @@ -810,7 +808,7 @@ bool CompilePipelineShader(PipelineShader* s) ShaderUniforms.Set(s); - return glIsProgram(s->program)==GL_TRUE; + return true; } #ifdef __ANDROID__ diff --git a/core/rend/gles/opengl_driver.cpp b/core/rend/gles/opengl_driver.cpp index 2f250abbe..55b77900c 100644 --- a/core/rend/gles/opengl_driver.cpp +++ b/core/rend/gles/opengl_driver.cpp @@ -50,13 +50,13 @@ OpenGLDriver::OpenGLDriver() for (auto& tex : vmu_lcd_tex_ids) tex = ImTextureID(); ImGui_ImplOpenGL3_Init(); - EventManager::listen(Event::Start, emuEventCallback, this); + EventManager::listen(Event::Resume, emuEventCallback, this); EventManager::listen(Event::Terminate, emuEventCallback, this); } OpenGLDriver::~OpenGLDriver() { - EventManager::unlisten(Event::Start, emuEventCallback, this); + EventManager::unlisten(Event::Resume, emuEventCallback, this); EventManager::unlisten(Event::Terminate, emuEventCallback, this); std::vector texIds; diff --git a/core/rend/gles/opengl_driver.h b/core/rend/gles/opengl_driver.h index 63b5e2a9f..9588a9965 100644 --- a/core/rend/gles/opengl_driver.h +++ b/core/rend/gles/opengl_driver.h @@ -53,7 +53,7 @@ private: { switch (event) { - case Event::Start: + case Event::Resume: gameStarted = true; break; case Event::Terminate: diff --git a/core/rend/gui.cpp b/core/rend/gui.cpp index 834ff3457..bab2f549f 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -2952,6 +2952,7 @@ void gui_term() if (inited) { inited = false; + scanner.stop(); ImGui::DestroyContext(); EventManager::unlisten(Event::Resume, emuEventCallback); EventManager::unlisten(Event::Start, emuEventCallback); diff --git a/core/sdl/sdl.cpp b/core/sdl/sdl.cpp index a33489750..886a4a4c4 100644 --- a/core/sdl/sdl.cpp +++ b/core/sdl/sdl.cpp @@ -62,8 +62,11 @@ static void sdl_open_joystick(int index) INFO_LOG(INPUT, "SDL: Cannot open joystick %d", index + 1); return; } - std::shared_ptr gamepad = std::make_shared(index < MAPLE_PORTS ? index : -1, index, pJoystick); - SDLGamepad::AddSDLGamepad(gamepad); + try { + std::shared_ptr gamepad = std::make_shared(index < MAPLE_PORTS ? index : -1, index, pJoystick); + SDLGamepad::AddSDLGamepad(gamepad); + } catch (const FlycastException& e) { + } } static void sdl_close_joystick(SDL_JoystickID instance) @@ -195,7 +198,7 @@ void input_sdl_init() checkRawInput(); -#ifdef __SWITCH__ +#if defined(__SWITCH__) || defined(__OpenBSD__) // when railed, both joycons are mapped to joystick #0, // else joycons are individually mapped to joystick #0, joystick #1, ... // https://github.com/devkitPro/SDL/blob/switch-sdl2/src/joystick/switch/SDL_sysjoystick.c#L45 diff --git a/core/sdl/sdl_gamepad.h b/core/sdl/sdl_gamepad.h index c67cf4c2c..89cc65941 100644 --- a/core/sdl/sdl_gamepad.h +++ b/core/sdl/sdl_gamepad.h @@ -170,12 +170,9 @@ public: if (joyName == nullptr) { WARN_LOG(INPUT, "Can't get joystick %d name: %s", joystick_idx, SDL_GetError()); - _name = "Joystick " + std::to_string(joystick_idx); - } - else - { - _name = joyName; + throw FlycastException("joystick failure"); } + _name = joyName; sdl_joystick_instance = SDL_JoystickInstanceID(sdl_joystick); _unique_id = "sdl_joystick_" + std::to_string(sdl_joystick_instance); INFO_LOG(INPUT, "SDL: Opened joystick %d on port %d: '%s' unique_id=%s", sdl_joystick_instance, maple_port, _name.c_str(), _unique_id.c_str());