diff --git a/CMakeLists.txt b/CMakeLists.txt index aa809b7ec..b9563f699 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,6 +122,7 @@ file (GLOB CXBXR_HEADER_EMU_IMPORT ) file (GLOB CXBXR_HEADER_EMU "${CXBXR_ROOT_DIR}/src/common/AddressRanges.h" + "${CXBXR_ROOT_DIR}/src/common/FilePaths.hpp" "${CXBXR_ROOT_DIR}/src/common/audio/converter.hpp" "${CXBXR_ROOT_DIR}/src/common/util/gloffscreen/glextensions.h" "${CXBXR_ROOT_DIR}/src/common/util/gloffscreen/gloffscreen.h" @@ -176,6 +177,7 @@ file (GLOB CXBXR_HEADER_EMU "${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlKi.h" "${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlLogging.h" "${CXBXR_ROOT_DIR}/src/core/kernel/init/CxbxKrnl.h" + "${CXBXR_ROOT_DIR}/src/core/kernel/init/KrnlPatches.hpp" "${CXBXR_ROOT_DIR}/src/core/kernel/memory-manager/PhysicalMemory.h" "${CXBXR_ROOT_DIR}/src/core/kernel/memory-manager/PoolManager.h" "${CXBXR_ROOT_DIR}/src/core/kernel/memory-manager/VMManager.h" @@ -183,6 +185,7 @@ file (GLOB CXBXR_HEADER_EMU "${CXBXR_ROOT_DIR}/src/core/kernel/support/EmuFile.h" "${CXBXR_ROOT_DIR}/src/core/kernel/support/EmuFS.h" "${CXBXR_ROOT_DIR}/src/core/kernel/support/EmuNtDll.h" + "${CXBXR_ROOT_DIR}/src/core/kernel/support/PatchRdtsc.hpp" "${CXBXR_ROOT_DIR}/src/devices/ADM1032Device.h" "${CXBXR_ROOT_DIR}/src/devices/EEPROMDevice.h" "${CXBXR_ROOT_DIR}/src/devices/network/NVNetDevice.h" @@ -360,6 +363,7 @@ file (GLOB CXBXR_SOURCE_EMU "${CXBXR_ROOT_DIR}/src/core/kernel/support/EmuFile.cpp" "${CXBXR_ROOT_DIR}/src/core/kernel/support/EmuFS.cpp" "${CXBXR_ROOT_DIR}/src/core/kernel/support/EmuNtDll.cpp" + "${CXBXR_ROOT_DIR}/src/core/kernel/support/PatchRdtsc.cpp" "${CXBXR_ROOT_DIR}/src/devices/ADM1032Device.cpp" "${CXBXR_ROOT_DIR}/src/devices/EEPROMDevice.cpp" "${CXBXR_ROOT_DIR}/src/devices/network/NVNetDevice.cpp" diff --git a/src/common/EmuEEPROM.cpp b/src/common/EmuEEPROM.cpp index 43edd394e..1d1fb885f 100644 --- a/src/common/EmuEEPROM.cpp +++ b/src/common/EmuEEPROM.cpp @@ -143,7 +143,7 @@ xbox::XBOX_EEPROM *CxbxRestoreEEPROM(char *szFilePath_EEPROM_bin) unsigned int FileSize = len_li.u.LowPart; if (FileSize != 256) { - CxbxKrnlCleanup("%s : EEPROM.bin file is not 256 bytes large!\n", __func__); + CxbxrKrnlAbort("%s : EEPROM.bin file is not 256 bytes large!\n", __func__); return nullptr; } diff --git a/src/common/FilePaths.hpp b/src/common/FilePaths.hpp new file mode 100644 index 000000000..36486aada --- /dev/null +++ b/src/common/FilePaths.hpp @@ -0,0 +1,162 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx-Reloaded project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * All rights reserved +// * +// ****************************************************************** +#pragma once + +//TODO: Possible move CxbxResolveHostToFullPath inline function someplace else if become useful elsewhere. +// Let filesystem library clean it up for us, including resolve host's symbolic link path. +// Since internal kernel do translate to full path than preserved host symoblic link path. +static inline void CxbxResolveHostToFullPath(std::filesystem::path& file_path, std::string_view finish_error_sentence) { + std::error_code error; + std::filesystem::path sanityPath = std::filesystem::canonical(file_path, error); + if (error.value() != 0) { + CxbxrKrnlAbortEx(LOG_PREFIX_INIT, "Could not resolve to %s: %s", finish_error_sentence.data(), file_path.string().c_str()); + } + file_path = sanityPath; +} +// TODO: Eventually, we should remove this function to start using std::filesystem::path method for all host paths. +static inline void CxbxResolveHostToFullPath(std::string& file_path, std::string_view finish_error_sentence) { + std::filesystem::path sanityPath(file_path); + CxbxResolveHostToFullPath(sanityPath, finish_error_sentence); + file_path = sanityPath.string(); +} + +// NOTE: Do NOT modify g_BasePath variables after this call! +void CxbxrInitFilePaths() +{ + if (g_Settings) { + g_DataFilePath = g_Settings->GetDataLocation(); + } + else { + char dataLoc[MAX_PATH]; + g_EmuShared->GetDataLocation(dataLoc); + g_DataFilePath = dataLoc; + } + + // Make sure our data folder exists : + bool result = std::filesystem::exists(g_DataFilePath); + if (!result && !std::filesystem::create_directory(g_DataFilePath)) { + CxbxrKrnlAbort("%s : Couldn't create Cxbx-Reloaded's data folder!", __func__); + } + + // Make sure the EmuDisk folder exists + g_DiskBasePath = g_DataFilePath + "\\EmuDisk"; + result = std::filesystem::exists(g_DiskBasePath); + if (!result && !std::filesystem::create_directory(g_DiskBasePath)) { + CxbxrKrnlAbort("%s : Couldn't create Cxbx-Reloaded EmuDisk folder!", __func__); + } + CxbxResolveHostToFullPath(g_DiskBasePath, "Cxbx-Reloaded's EmuDisk directory"); + g_DiskBasePath = std::filesystem::path(g_DiskBasePath).append("").string(); + + // Make sure the EmuDMu folder exists + g_MuBasePath = g_DataFilePath + "\\EmuMu"; + result = std::filesystem::exists(g_MuBasePath); + if (!result && !std::filesystem::create_directory(g_MuBasePath)) { + CxbxrKrnlAbort("%s : Couldn't create Cxbx-Reloaded EmuMu folder!", __func__); + } + CxbxResolveHostToFullPath(g_MuBasePath, "Cxbx-Reloaded's EmuMu directory"); + g_MuBasePath = std::filesystem::path(g_MuBasePath).append("").string(); + + snprintf(szFilePath_EEPROM_bin, MAX_PATH, "%s\\EEPROM.bin", g_DataFilePath.c_str()); + + GetModuleFileName(GetModuleHandle(nullptr), szFilePath_CxbxReloaded_Exe, MAX_PATH); +} + +// Loads a keys.bin file as generated by dump-xbox +// See https://github.com/JayFoxRox/xqemu-tools/blob/master/dump-xbox.c +static void LoadXboxKeys() +{ + std::string keys_path = g_DataFilePath + "\\keys.bin"; + + // Attempt to open Keys.bin + FILE* fp = fopen(keys_path.c_str(), "rb"); + + if (fp != nullptr) { + // Determine size of Keys.bin + xbox::XBOX_KEY_DATA keys[2]; + fseek(fp, 0, SEEK_END); + long size = ftell(fp); + rewind(fp); + + // If the size of Keys.bin is correct (two keys), read it + if (size == xbox::XBOX_KEY_LENGTH * 2) { + fread(keys, xbox::XBOX_KEY_LENGTH, 2, fp); + + memcpy(xbox::XboxEEPROMKey, &keys[0], xbox::XBOX_KEY_LENGTH); + memcpy(xbox::XboxCertificateKey, &keys[1], xbox::XBOX_KEY_LENGTH); + } + else { + EmuLog(LOG_LEVEL::WARNING, "Keys.bin has an incorrect filesize. Should be %d bytes", xbox::XBOX_KEY_LENGTH * 2); + } + + fclose(fp); + return; + } + + // If we didn't already exit the function, keys.bin could not be loaded + EmuLog(LOG_LEVEL::WARNING, "Failed to load Keys.bin. Cxbx-Reloaded will be unable to read Save Data from a real Xbox"); +} + +static HANDLE hMapDataHash = nullptr; + +static bool CxbxLockFilePath() +{ + std::stringstream filePathHash("Local\\"); + uint64_t hashValue = XXH3_64bits(g_DataFilePath.c_str(), g_DataFilePath.length() + 1); + if (!hashValue) { + CxbxrKrnlAbort("%s : Couldn't generate Cxbx-Reloaded's data folder hash!", __func__); + } + + filePathHash << std::hex << hashValue; + + hMapDataHash = CreateFileMapping( + INVALID_HANDLE_VALUE, // Paging file + nullptr, // default security attributes + PAGE_READONLY, // readonly access + 0, // size: high 32 bits + /*Dummy size*/4, // size: low 32 bits + filePathHash.str().c_str() // name of map object + ); + + if (hMapDataHash == nullptr) { + return false; + } + + if (GetLastError() == ERROR_ALREADY_EXISTS) { + PopupError(nullptr, "Data path directory is currently in use.\nUse a different data path directory or stop emulation from another process."); + CloseHandle(hMapDataHash); + return false; + } + + return true; +} + +static void CxbxUnlockFilePath() +{ + // Close opened file path lockdown shared memory. + if (hMapDataHash) { + CloseHandle(hMapDataHash); + hMapDataHash = nullptr; + } +} diff --git a/src/common/Settings.cpp b/src/common/Settings.cpp index 6b082b6d6..af16fdda7 100644 --- a/src/common/Settings.cpp +++ b/src/common/Settings.cpp @@ -809,7 +809,7 @@ void Settings::SyncToEmulator() g_EmuShared->SetHackSettings(&m_hacks); // register data location setting - g_EmuShared->SetStorageLocation(GetDataLocation().c_str()); + g_EmuShared->SetDataLocation(GetDataLocation().c_str()); // reset title mount path g_EmuShared->SetTitleMountPath(""); diff --git a/src/common/input/InputManager.cpp b/src/common/input/InputManager.cpp index 894d32356..fe3e46740 100644 --- a/src/common/input/InputManager.cpp +++ b/src/common/input/InputManager.cpp @@ -96,7 +96,7 @@ void InputDeviceManager::Initialize(bool is_gui, HWND hwnd) lck.unlock(); if (Sdl::InitStatus < 0 || XInput::InitStatus < 0 || RawInput::InitStatus < 0) { - CxbxKrnlCleanup("Failed to initialize input subsystem! Consult debug log for more information"); + CxbxrKrnlAbort("Failed to initialize input subsystem! Consult debug log for more information"); } UpdateOpt(is_gui); diff --git a/src/common/win32/EmuShared.cpp b/src/common/win32/EmuShared.cpp index 476dadd17..66b820dbb 100644 --- a/src/common/win32/EmuShared.cpp +++ b/src/common/win32/EmuShared.cpp @@ -84,7 +84,7 @@ bool EmuShared::Init(long long sessionID) ); if(hMapObject == NULL) - return false; // CxbxKrnlCleanupEx(CXBXR_MODULE::INIT, "Could not map shared memory!"); + return false; // CxbxrKrnlAbortEx(CXBXR_MODULE::INIT, "Could not map shared memory!"); if(GetLastError() == ERROR_ALREADY_EXISTS) bRequireConstruction = false; @@ -105,7 +105,7 @@ bool EmuShared::Init(long long sessionID) if (g_EmuShared == nullptr) { CloseHandle(hMapObject); - return false; // CxbxKrnlCleanupEx(CXBXR_MODULE::INIT, "Could not map view of shared memory!"); + return false; // CxbxrKrnlAbortEx(CXBXR_MODULE::INIT, "Could not map view of shared memory!"); } } diff --git a/src/common/win32/EmuShared.h b/src/common/win32/EmuShared.h index 1f685437c..9fb36fae6 100644 --- a/src/common/win32/EmuShared.h +++ b/src/common/win32/EmuShared.h @@ -246,10 +246,10 @@ class EmuShared : public Mutex void SetLogPopupTestCase(const bool value) { Lock(); m_core.bLogPopupTestCase = value; Unlock(); } // ****************************************************************** - // * File storage location + // * Data location path // ****************************************************************** - void GetStorageLocation(char *path) { Lock(); strncpy(path, m_core.szStorageLocation, xbox::max_path); Unlock(); } - void SetStorageLocation(const char *path) { Lock(); strncpy(m_core.szStorageLocation, path, xbox::max_path); Unlock(); } + void GetDataLocation(char *path) { Lock(); strncpy(path, m_core.szStorageLocation, xbox::max_path); Unlock(); } + void SetDataLocation(const char *path) { Lock(); strncpy(m_core.szStorageLocation, path, xbox::max_path); Unlock(); } // ****************************************************************** // * ClipCursor flag Accessors diff --git a/src/common/win32/Threads.cpp b/src/common/win32/Threads.cpp index 4484b31ca..b9d07cf3f 100644 --- a/src/common/win32/Threads.cpp +++ b/src/common/win32/Threads.cpp @@ -196,7 +196,7 @@ class Win7Policy final : public AffinityPolicy public: bool Initialize() { if (!GetProcessAffinityMask(g_CurrentProcessHandle, &CPUXbox, &CPUOthers)) - CxbxKrnlCleanupEx(CXBXR_MODULE::INIT, "GetProcessAffinityMask failed."); + CxbxrKrnlAbortEx(CXBXR_MODULE::INIT, "GetProcessAffinityMask failed."); // For the other threads, remove one bit from the processor mask: CPUOthers = ((CPUXbox - 1) & CPUXbox); diff --git a/src/core/common/imgui/ui.cpp b/src/core/common/imgui/ui.cpp index f4bf2eba4..680a2bf93 100644 --- a/src/core/common/imgui/ui.cpp +++ b/src/core/common/imgui/ui.cpp @@ -20,14 +20,14 @@ bool ImGuiUI::Initialize() IMGUI_CHECKVERSION(); m_imgui_context = ImGui::CreateContext(); if (!m_imgui_context) { - CxbxKrnlCleanup("Unable to create ImGui context!"); + CxbxrKrnlAbort("Unable to create ImGui context!"); return false; } ImGuiIO& io = ImGui::GetIO(); #if 0 // TODO: Currently most voted for memory, so this block of code is disabled. And may will add an option between file vs memory. // May be best ideal to do manual update call than ImGui's internal auto update. - g_EmuShared->GetStorageLocation(m_file_path); + g_EmuShared->GetDataLocation(m_file_path); if (m_file_path[0] == '\0') { return false; } @@ -45,6 +45,11 @@ bool ImGuiUI::Initialize() g_EmuShared->GetOverlaySettings(&m_settings); g_EmuShared->GetFlagsLLE(&m_lle_flags); + + // Internal initialize (when necessary, move into its own function.) + fps_counter = 30.0f; + + // Miscs m_audio.Initialize(); m_video.Initialize(); @@ -56,7 +61,7 @@ void ImGuiUI::Shutdown() size_t ini_size = IMGUI_INI_SIZE_MAX; const char* temp_ini_settings = ImGui::SaveIniSettingsToMemory(&ini_size); if (ini_size > IMGUI_INI_SIZE_MAX) { - CxbxKrnlCleanup("ImGui ini settings is too large: %d > %d (IMGUI_INI_SIZE_MAX)", ini_size, IMGUI_INI_SIZE_MAX); + CxbxrKrnlAbort("ImGui ini settings is too large: %d > %d (IMGUI_INI_SIZE_MAX)", ini_size, IMGUI_INI_SIZE_MAX); } g_EmuShared->SetImGuiIniSettings(temp_ini_settings); g_EmuShared->SetOverlaySettings(&m_settings); @@ -76,6 +81,36 @@ void ImGuiUI::ToggleImGui() g_EmuShared->SetImGuiFocusFlag(m_is_focus); } +static clock_t g_DeltaTime = 0; // Used for benchmarking/fps count +static unsigned int g_Frames = 0; + +// ****************************************************************** +// * update the current milliseconds per frame +// ****************************************************************** +void ImGuiUI::UpdateCurrentMSpFAndFPS() { + if (g_EmuShared) { + + fps_counter = (float)(g_Frames * 0.5 + fps_counter * 0.5); + g_EmuShared->SetCurrentFPS(&fps_counter); + } +} + +void ImGuiUI::UpdateFPSCounter() +{ + static clock_t lastDrawFunctionCallTime = 0; + clock_t currentDrawFunctionCallTime = clock(); + + g_DeltaTime += currentDrawFunctionCallTime - lastDrawFunctionCallTime; + lastDrawFunctionCallTime = currentDrawFunctionCallTime; + g_Frames++; + + if (g_DeltaTime >= CLOCKS_PER_SEC) { + UpdateCurrentMSpFAndFPS(); + g_Frames = 0; + g_DeltaTime -= CLOCKS_PER_SEC; + } +} + void ImGuiUI::DrawMenu() { if (!m_is_focus) { @@ -116,9 +151,6 @@ void ImGuiUI::DrawWidgets() ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing)) { if (m_settings.fps) { - - float fps_counter; - g_EmuShared->GetCurrentFPS(&fps_counter); ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "FPS: %.2f MS / F : %.2f", fps_counter, (float)(1000.0 / fps_counter)); } diff --git a/src/core/common/imgui/ui.hpp b/src/core/common/imgui/ui.hpp index 931547437..19abf1498 100644 --- a/src/core/common/imgui/ui.hpp +++ b/src/core/common/imgui/ui.hpp @@ -28,6 +28,7 @@ public: void ToggleImGui(); bool IsImGuiFocus(); + void UpdateFPSCounter(); void DrawMenu(); void DrawWidgets(); @@ -48,6 +49,8 @@ protected: callback(this, arg); } + void UpdateCurrentMSpFAndFPS(); + std::mutex m_imgui_mutex; ImGuiContext* m_imgui_context; char m_file_path[FILENAME_MAX+1]; @@ -57,6 +60,7 @@ protected: ImGuiVideo m_video; overlay_settings m_settings; unsigned int m_lle_flags; + float fps_counter; // Make them as settings storage. /*bool m_show_fps; bool m_show_LLE_stats; diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 059daf0d3..ede4bcc3d 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -223,8 +223,6 @@ static inline void EmuVerifyResourceIsRegistered(xbox::X_D3DRes static void UpdateCurrentMSpFAndFPS(); // Used for benchmarking/fps count static void CxbxImpl_SetRenderTarget(xbox::X_D3DSurface *pRenderTarget, xbox::X_D3DSurface *pNewZStencil); -extern void UpdateFPSCounter(); - #define CXBX_D3DCOMMON_IDENTIFYING_MASK (X_D3DCOMMON_TYPE_MASK | X_D3DCOMMON_D3DCREATED) @@ -864,7 +862,7 @@ inline bool IsResourceTypeGPUReadable(const DWORD ResourceType) // assert(false); // Fixup's are not allowed to be registered break; default: - CxbxKrnlCleanup("Unhandled resource type"); + CxbxrKrnlAbort("Unhandled resource type"); } return false; @@ -1697,7 +1695,7 @@ void EmuD3DInit() { // xbox Direct3DCreate8 returns "1" always, so we need our own ptr if(FAILED(Direct3DCreate9Ex(D3D_SDK_VERSION, &g_pDirect3D))) - CxbxKrnlCleanup("Could not initialize Direct3D8!"); + CxbxrKrnlAbort("Could not initialize Direct3D8!"); g_pDirect3D->GetDeviceCaps(g_EmuCDPD.Adapter, g_EmuCDPD.DeviceType, &g_D3DCaps); @@ -1801,14 +1799,14 @@ static DWORD WINAPI EmuRenderWindow(LPVOID lpParam) { if(bRet == -1) { - CxbxKrnlCleanup("GetMessage failed!"); + CxbxrKrnlAbort("GetMessage failed!"); } TranslateMessage(&msg); DispatchMessage(&msg); } - CxbxKrnlCleanup(nullptr); + CxbxrKrnlAbort(nullptr); } return 0; @@ -2050,7 +2048,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar case SIZE_MINIMIZED: { if(g_XBVideo.bFullScreen) - CxbxKrnlCleanup(nullptr); + CxbxrKrnlAbort(nullptr); if(!g_bEmuSuspended) { @@ -2479,7 +2477,7 @@ static void CreateDefaultD3D9Device DEBUG_D3DRESULT(hr, "IDirect3D::CreateDeviceEx"); if(FAILED(hr)) - CxbxKrnlCleanup("IDirect3D::CreateDeviceEx failed"); + CxbxrKrnlAbort("IDirect3D::CreateDeviceEx failed"); // Which texture formats does this device support? DetermineSupportedD3DFormats(); @@ -2796,7 +2794,7 @@ ConvertedIndexBuffer& CxbxUpdateActiveIndexBuffer if (CacheEntry.pHostIndexBuffer == nullptr) { CacheEntry.pHostIndexBuffer = CxbxCreateIndexBuffer(RequiredIndexCount); if (!CacheEntry.pHostIndexBuffer) - CxbxKrnlCleanup("CxbxUpdateActiveIndexBuffer: IndexBuffer Create Failed!"); + CxbxrKrnlAbort("CxbxUpdateActiveIndexBuffer: IndexBuffer Create Failed!"); } // TODO : Speeds this up, perhaps by hashing less often, and/or by @@ -2815,7 +2813,7 @@ ConvertedIndexBuffer& CxbxUpdateActiveIndexBuffer HRESULT hRet = CacheEntry.pHostIndexBuffer->Lock(0, /*entire SizeToLock=*/0, (D3DLockData **)&pHostIndexBufferData, D3DLOCK_DISCARD); DEBUG_D3DRESULT(hRet, "CacheEntry.pHostIndexBuffer->Lock"); if (pHostIndexBufferData == nullptr) { - CxbxKrnlCleanup("CxbxUpdateActiveIndexBuffer: Could not lock index buffer!"); + CxbxrKrnlAbort("CxbxUpdateActiveIndexBuffer: Could not lock index buffer!"); } // Determine highest and lowest index in use : @@ -2839,7 +2837,7 @@ ConvertedIndexBuffer& CxbxUpdateActiveIndexBuffer DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetIndices"); if (FAILED(hRet)) - CxbxKrnlCleanup("CxbxUpdateActiveIndexBuffer: SetIndices Failed!"); + CxbxrKrnlAbort("CxbxUpdateActiveIndexBuffer: SetIndices Failed!"); return CacheEntry; } @@ -2852,13 +2850,13 @@ void UpdateHostBackBufferDesc() 0, D3DBACKBUFFER_TYPE_MONO, &pCurrentHostBackBuffer); if (hRet != D3D_OK) { - CxbxKrnlCleanup("Unable to get host backbuffer surface"); + CxbxrKrnlAbort("Unable to get host backbuffer surface"); } hRet = pCurrentHostBackBuffer->GetDesc(&g_HostBackBufferDesc); if (hRet != D3D_OK) { pCurrentHostBackBuffer->Release(); - CxbxKrnlCleanup("Unable to determine host backbuffer dimensions"); + CxbxrKrnlAbort("Unable to determine host backbuffer dimensions"); } pCurrentHostBackBuffer->Release(); @@ -3026,11 +3024,11 @@ void Direct3D_CreateDevice_Start CxbxVertexShaderSetFlags(); if (!XboxRenderStates.Init()) { - CxbxKrnlCleanup("Failed to init XboxRenderStates"); + CxbxrKrnlAbort("Failed to init XboxRenderStates"); } if (!XboxTextureStates.Init(&XboxRenderStates)) { - CxbxKrnlCleanup("Failed to init XboxTextureStates"); + CxbxrKrnlAbort("Failed to init XboxTextureStates"); } SetXboxMultiSampleType(pPresentationParameters->MultiSampleType); @@ -3084,7 +3082,7 @@ void Direct3D_CreateDevice_End // At this point, g_pXbox_BackBufferSurface should now point to a valid render target // if it still doesn't, we cannot continue without crashing at draw time if (g_pXbox_BackBufferSurface == xbox::zeroptr) { - CxbxKrnlCleanup("Unable to determine default Xbox backbuffer"); + CxbxrKrnlAbort("Unable to determine default Xbox backbuffer"); } // Set the backbuffer as the initial rendertarget @@ -4047,7 +4045,7 @@ xbox::X_D3DSurface* WINAPI xbox::EMUPATCH(D3DDevice_GetBackBuffer2) DEBUG_D3DRESULT(hRet, "g_pD3DDevice->GetBackBuffer"); if (FAILED(hRet)) - CxbxKrnlCleanup("Unable to retrieve back buffer"); + CxbxrKrnlAbort("Unable to retrieve back buffer"); SetHostSurface(pXboxBackBuffer, pCurrentHostBackBuffer); // No iTextureStage! @@ -4070,7 +4068,7 @@ xbox::X_D3DSurface* WINAPI xbox::EMUPATCH(D3DDevice_GetBackBuffer2) // Now pXboxBackbuffer points to the requested Xbox backbuffer if (pXboxBackBuffer == nullptr) { - CxbxKrnlCleanup("D3DDevice_GetBackBuffer2: Could not get Xbox backbuffer"); + CxbxrKrnlAbort("D3DDevice_GetBackBuffer2: Could not get Xbox backbuffer"); } @@ -5483,7 +5481,7 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(D3DDevice_Swap) frameStartTime = std::chrono::steady_clock::now(); - UpdateFPSCounter(); + g_renderbase->UpdateFPSCounter(); if (Flags == CXBX_SWAP_PRESENT_FORWARD) // Only do this when forwarded from Present { @@ -5746,7 +5744,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex PCFormat = D3DFMT_A8R8G8B8; } else { // Otherwise, use a best matching format - /*CxbxKrnlCleanup*/EmuLog(LOG_LEVEL::WARNING, "Encountered a completely incompatible %s format!", ResourceTypeName); + /*CxbxrKrnlAbort*/EmuLog(LOG_LEVEL::WARNING, "Encountered a completely incompatible %s format!", ResourceTypeName); PCFormat = EmuXB2PC_D3DFormat(X_Format); } } @@ -5874,7 +5872,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex // If the fallback failed, show an error and exit execution. if (hRet != D3D_OK) { // We cannot safely continue in this state. - CxbxKrnlCleanup("CreateImageSurface Failed!\n\nError: %s\nDesc: %s", + CxbxrKrnlAbort("CreateImageSurface Failed!\n\nError: %s\nDesc: %s", DXGetErrorString(hRet), DXGetErrorDescription(hRet)); } @@ -5942,7 +5940,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex if (hRet != D3D_OK) { - CxbxKrnlCleanup("CreateTexture Failed!\n\n" + CxbxrKrnlAbort("CreateTexture Failed!\n\n" "Error: 0x%X\nFormat: %d\nDimensions: %dx%d", hRet, PCFormat, hostWidth, hostHeight); } @@ -5968,7 +5966,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex } if (hRet != D3D_OK) { - CxbxKrnlCleanup("CreateVolumeTexture Failed!\n\nError: %s\nDesc: %s", + CxbxrKrnlAbort("CreateVolumeTexture Failed!\n\nError: %s\nDesc: %s", DXGetErrorString(hRet), DXGetErrorDescription(hRet)); } @@ -5997,7 +5995,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex } if (hRet != D3D_OK) { - CxbxKrnlCleanup("CreateCubeTexture Failed!\n\nError: \nDesc: "/*, + CxbxrKrnlAbort("CreateCubeTexture Failed!\n\nError: \nDesc: "/*, DXGetErrorString(hRet), DXGetErrorDescription(hRet)*/); } @@ -6127,7 +6125,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex pDst, dwDstRowPitch, dwDstSlicePitch, pxMipDepth,//used pxMipDepth here because in 3D mip map the 3rd dimension also shrinked to 1/2 at each mip level. iTextureStage)) { - CxbxKrnlCleanup("Unhandled conversion!"); + CxbxrKrnlAbort("Unhandled conversion!"); } } } @@ -6555,7 +6553,7 @@ void UpdateFixedFunctionVertexShaderState() auto hRet = g_pD3DDevice->SetVertexShaderConstantF(0, (float*)&ffShaderState, fixedFunctionStateSize); if (FAILED(hRet)) { - CxbxKrnlCleanup("Failed to write fixed-function HLSL state"); + CxbxrKrnlAbort("Failed to write fixed-function HLSL state"); } } @@ -7165,14 +7163,14 @@ void CxbxAssureQuadListD3DIndexBuffer(UINT NrOfQuadIndices) // Create a new native index buffer of the above determined size : g_pQuadToTriangleHostIndexBuffer = CxbxCreateIndexBuffer(NrOfTriangleIndices); if (g_pQuadToTriangleHostIndexBuffer == nullptr) - CxbxKrnlCleanup("CxbxAssureQuadListD3DIndexBuffer : IndexBuffer Create Failed!"); + CxbxrKrnlAbort("CxbxAssureQuadListD3DIndexBuffer : IndexBuffer Create Failed!"); // Put quadlist-to-triangle-list index mappings into this buffer : INDEX16* pHostIndexBufferData = nullptr; hRet = g_pQuadToTriangleHostIndexBuffer->Lock(0, /*entire SizeToLock=*/0, (D3DLockData **)&pHostIndexBufferData, D3DLOCK_DISCARD); DEBUG_D3DRESULT(hRet, "g_pQuadToTriangleHostIndexBuffer->Lock"); if (pHostIndexBufferData == nullptr) - CxbxKrnlCleanup("CxbxAssureQuadListD3DIndexBuffer : Could not lock index buffer!"); + CxbxrKrnlAbort("CxbxAssureQuadListD3DIndexBuffer : Could not lock index buffer!"); memcpy(pHostIndexBufferData, CxbxAssureQuadListIndexData(NrOfQuadIndices), NrOfTriangleIndices * sizeof(INDEX16)); @@ -7184,7 +7182,7 @@ void CxbxAssureQuadListD3DIndexBuffer(UINT NrOfQuadIndices) DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetIndices"); if (FAILED(hRet)) - CxbxKrnlCleanup("CxbxAssureQuadListD3DIndexBuffer : SetIndices Failed!"); // +DxbxD3DErrorString(hRet)); + CxbxrKrnlAbort("CxbxAssureQuadListD3DIndexBuffer : SetIndices Failed!"); // +DxbxD3DErrorString(hRet)); } // TODO : Move to own file @@ -7198,7 +7196,7 @@ void CxbxDrawIndexedClosingLine(INDEX16 LowIndex, INDEX16 HighIndex) if (g_pClosingLineLoopHostIndexBuffer == nullptr) { g_pClosingLineLoopHostIndexBuffer = CxbxCreateIndexBuffer(VERTICES_PER_LINE); if (g_pClosingLineLoopHostIndexBuffer == nullptr) - CxbxKrnlCleanup("Unable to create g_pClosingLineLoopHostIndexBuffer for D3DPT_LINELOOP emulation"); + CxbxrKrnlAbort("Unable to create g_pClosingLineLoopHostIndexBuffer for D3DPT_LINELOOP emulation"); } INDEX16 *pCxbxClosingLineLoopIndexBufferData = nullptr; diff --git a/src/core/hle/D3D8/Direct3D9/TextureStates.cpp b/src/core/hle/D3D8/Direct3D9/TextureStates.cpp index 15182a217..8bc7630b8 100644 --- a/src/core/hle/D3D8/Direct3D9/TextureStates.cpp +++ b/src/core/hle/D3D8/Direct3D9/TextureStates.cpp @@ -361,9 +361,9 @@ DWORD NormalizeValue(DWORD xboxState, DWORD value) { uint32_t XboxTextureStateConverter::Get(int textureStage, DWORD xboxState) { if (textureStage < 0 || textureStage > 3) - CxbxKrnlCleanup("Requested texture stage was out of range: %d", textureStage); + CxbxrKrnlAbort("Requested texture stage was out of range: %d", textureStage); if (xboxState < xbox::X_D3DTSS_FIRST || xboxState > xbox::X_D3DTSS_LAST) - CxbxKrnlCleanup("Requested texture state was out of range: %d", xboxState); + CxbxrKrnlAbort("Requested texture state was out of range: %d", xboxState); // Read the value of the current stage/state from the Xbox data structure DWORD rawValue = D3D__TextureState[(textureStage * xbox::X_D3DTS_STAGESIZE) + XboxTextureStateOffsets[xboxState]]; diff --git a/src/core/hle/D3D8/XbConvert.cpp b/src/core/hle/D3D8/XbConvert.cpp index 1ea57bd1b..07eac0918 100644 --- a/src/core/hle/D3D8/XbConvert.cpp +++ b/src/core/hle/D3D8/XbConvert.cpp @@ -1047,7 +1047,7 @@ D3DFORMAT EmuXB2PC_D3DFormat(xbox::X_D3DFORMAT Format) case ((xbox::X_D3DFORMAT)0xffffffff): return D3DFMT_UNKNOWN; // TODO -oCXBX: Not sure if this counts as swizzled or not... default: - CxbxKrnlCleanup("EmuXB2PC_D3DFormat: Unknown Format (0x%.08X)", Format); + CxbxrKrnlAbort("EmuXB2PC_D3DFormat: Unknown Format (0x%.08X)", Format); } return D3DFMT_UNKNOWN; @@ -1129,7 +1129,7 @@ xbox::X_D3DFORMAT EmuPC2XB_D3DFormat(D3DFORMAT Format, bool bPreferLinear) result = xbox::X_D3DFMT_VERTEXDATA; break; default: - CxbxKrnlCleanup("EmuPC2XB_D3DFormat: Unknown Format (%d)", Format); + CxbxrKrnlAbort("EmuPC2XB_D3DFormat: Unknown Format (%d)", Format); } return result; diff --git a/src/core/hle/D3D8/XbConvert.h b/src/core/hle/D3D8/XbConvert.h index 57cd45c72..aefb51b46 100644 --- a/src/core/hle/D3D8/XbConvert.h +++ b/src/core/hle/D3D8/XbConvert.h @@ -90,7 +90,7 @@ else if((uint32)State < 20) else if((uint32)State > 255) State = (D3DTRANSFORMSTATETYPE)(State - 250); else - CxbxKrnlCleanupEx(LOG_PREFIX_D3DCVT, "Unknown Transform State Type (%d)", State); + CxbxrKrnlAbortEx(LOG_PREFIX_D3DCVT, "Unknown Transform State Type (%d)", State); //*/ // convert from xbox to pc texture transform state types @@ -115,7 +115,7 @@ inline D3DTRANSFORMSTATETYPE EmuXB2PC_D3DTS(xbox::X_D3DTRANSFORMSTATETYPE State) return D3DTS_WORLDMATRIX(State - 256); } - CxbxKrnlCleanupEx(LOG_PREFIX_D3DCVT, "Unknown Transform State Type (%d)", State); + CxbxrKrnlAbortEx(LOG_PREFIX_D3DCVT, "Unknown Transform State Type (%d)", State); return (D3DTRANSFORMSTATETYPE)0; } diff --git a/src/core/hle/D3D8/XbPixelShader.cpp b/src/core/hle/D3D8/XbPixelShader.cpp index bd38db034..307fbe850 100644 --- a/src/core/hle/D3D8/XbPixelShader.cpp +++ b/src/core/hle/D3D8/XbPixelShader.cpp @@ -43,7 +43,7 @@ #include "core\hle\D3D8\Direct3D9\PixelShader.h" // EmuCompilePixelShader #include "core\hle\D3D8\XbD3D8Logging.h" // For D3DErrorString() -#include "core\kernel\init\CxbxKrnl.h" // For CxbxKrnlCleanup() +#include "core\kernel\init\CxbxKrnl.h" // For CxbxrKrnlAbort() #include "util\hasher.h" #include "core\hle\D3D8\Direct3D9\FixedFunctionPixelShader.hlsli" @@ -930,7 +930,7 @@ IDirect3DPixelShader9* GetFixedFunctionShader() IDirect3DPixelShader9* pShader = nullptr; auto hRet = g_pD3DDevice->CreatePixelShader((DWORD*)pShaderBlob->GetBufferPointer(), &pShader); if (hRet != S_OK) - CxbxKrnlCleanup("Failed to compile fixed function pixel shader"); + CxbxrKrnlAbort("Failed to compile fixed function pixel shader"); pShaderBlob->Release(); // Insert the shader into the cache diff --git a/src/core/hle/D3D8/XbVertexBuffer.cpp b/src/core/hle/D3D8/XbVertexBuffer.cpp index 23338d780..2ce7b99d2 100644 --- a/src/core/hle/D3D8/XbVertexBuffer.cpp +++ b/src/core/hle/D3D8/XbVertexBuffer.cpp @@ -84,7 +84,7 @@ void CxbxPatchedStream::Activate(CxbxDrawContext *pDrawContext, UINT HostStreamN uiCachedHostVertexStride); //DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetStreamSource"); if (FAILED(hRet)) { - CxbxKrnlCleanup("Failed to set the type patched buffer as the new stream source!\n"); + CxbxrKrnlAbort("Failed to set the type patched buffer as the new stream source!\n"); // TODO : test-case : XDK Cartoon hits the above case when the vertex cache size is 0. } } @@ -244,7 +244,7 @@ void CxbxVertexBufferConverter::ConvertStream if (pDrawContext->pXboxVertexStreamZeroData != xbox::zeroptr) { // There should only be one stream (stream zero) in this case if (XboxStreamNumber != 0) { - CxbxKrnlCleanup("Trying to patch a Draw..UP with more than stream zero!"); + CxbxrKrnlAbort("Trying to patch a Draw..UP with more than stream zero!"); } pXboxVertexData = (uint8_t *)pDrawContext->pXboxVertexStreamZeroData; @@ -350,7 +350,7 @@ void CxbxVertexBufferConverter::ConvertStream pHostVertexData = (uint8_t*)malloc(dwHostVertexDataSize); if (pHostVertexData == nullptr) { - CxbxKrnlCleanup("Couldn't allocate the new stream zero buffer"); + CxbxrKrnlAbort("Couldn't allocate the new stream zero buffer"); } } else { HRESULT hRet = g_pD3DDevice->CreateVertexBuffer( @@ -363,14 +363,14 @@ void CxbxVertexBufferConverter::ConvertStream ); if (FAILED(hRet)) { - CxbxKrnlCleanup("Failed to create vertex buffer"); + CxbxrKrnlAbort("Failed to create vertex buffer"); } } // If we need to lock a host vertex buffer, do so now if (pHostVertexData == nullptr && pNewHostVertexBuffer != nullptr) { if (FAILED(pNewHostVertexBuffer->Lock(0, 0, (D3DLockData **)&pHostVertexData, D3DLOCK_DISCARD))) { - CxbxKrnlCleanup("Couldn't lock vertex buffer"); + CxbxrKrnlAbort("Couldn't lock vertex buffer"); } } @@ -609,7 +609,7 @@ void CxbxVertexBufferConverter::ConvertStream void CxbxVertexBufferConverter::Apply(CxbxDrawContext *pDrawContext) { if ((pDrawContext->XboxPrimitiveType < xbox::X_D3DPT_POINTLIST) || (pDrawContext->XboxPrimitiveType > xbox::X_D3DPT_POLYGON)) - CxbxKrnlCleanup("Unknown primitive type: 0x%.02X\n", pDrawContext->XboxPrimitiveType); + CxbxrKrnlAbort("Unknown primitive type: 0x%.02X\n", pDrawContext->XboxPrimitiveType); CxbxVertexDeclaration* pCxbxVertexDeclaration = CxbxGetVertexDeclaration(); diff --git a/src/core/hle/D3D8/XbVertexShader.cpp b/src/core/hle/D3D8/XbVertexShader.cpp index 9adc3e3b7..d2afc8c0f 100644 --- a/src/core/hle/D3D8/XbVertexShader.cpp +++ b/src/core/hle/D3D8/XbVertexShader.cpp @@ -574,7 +574,7 @@ namespace XboxVertexShaderDecoder } if (pShader->Instructions.size() >= VSH_MAX_INTERMEDIATE_COUNT) { - CxbxKrnlCleanup("Shader exceeds conversion buffer!"); + CxbxrKrnlAbort("Shader exceeds conversion buffer!"); } VSH_INTERMEDIATE_FORMAT intermediate; @@ -1161,14 +1161,14 @@ void CxbxUpdateHostVertexShader() EmuCompileFixedFunction(&pBlob); if (pBlob) { hRet = g_pD3DDevice->CreateVertexShader((DWORD*)pBlob->GetBufferPointer(), &ffHlsl); - if (FAILED(hRet)) CxbxKrnlCleanup("Failed to create fixed-function shader"); + if (FAILED(hRet)) CxbxrKrnlAbort("Failed to create fixed-function shader"); } } fixedFunctionShader = ffHlsl; } hRet = g_pD3DDevice->SetVertexShader(fixedFunctionShader); - if (FAILED(hRet)) CxbxKrnlCleanup("Failed to set fixed-function shader"); + if (FAILED(hRet)) CxbxrKrnlAbort("Failed to set fixed-function shader"); } else if (g_Xbox_VertexShaderMode == VertexShaderMode::Passthrough && g_bUsePassthroughHLSL) { if (passthroughshader == nullptr) { diff --git a/src/core/hle/DSOUND/DirectSound/DirectSound.cpp b/src/core/hle/DSOUND/DirectSound/DirectSound.cpp index bf1198767..1e8d2d80b 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSound.cpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSound.cpp @@ -174,13 +174,13 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(DirectSoundCreate) } if (dsErrorMsg != nullptr) { - CxbxKrnlCleanup(dsErrorMsg, hRet); + CxbxrKrnlAbort(dsErrorMsg, hRet); } hRet = g_pDSound8->SetCooperativeLevel(GET_FRONT_WINDOW_HANDLE, DSSCL_PRIORITY); if (hRet != DS_OK) { - CxbxKrnlCleanup("g_pDSound8->SetCooperativeLevel Failed!"); + CxbxrKrnlAbort("g_pDSound8->SetCooperativeLevel Failed!"); } // clear sound buffer cache @@ -208,7 +208,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(DirectSoundCreate) hRet = g_pDSound8->CreateSoundBuffer(&bufferDesc, &g_pDSoundPrimaryBuffer, nullptr); if (hRet != DS_OK) { - CxbxKrnlCleanup("Creating primary buffer for DirectSound Failed!"); + CxbxrKrnlAbort("Creating primary buffer for DirectSound Failed!"); } /* Quote from MDSN "For the primary buffer, you must use the @@ -221,7 +221,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(DirectSoundCreate) hRet = g_pDSoundPrimaryBuffer->QueryInterface(IID_IDirectSound3DListener8, (LPVOID*)&g_pDSoundPrimary3DListener8); if (hRet != DS_OK) { - CxbxKrnlCleanup("Creating primary 3D Listener for DirectSound Failed!"); + CxbxrKrnlAbort("Creating primary 3D Listener for DirectSound Failed!"); } initialized = true; diff --git a/src/core/hle/DSOUND/DirectSound/DirectSoundBuffer.cpp b/src/core/hle/DSOUND/DirectSound/DirectSoundBuffer.cpp index db660d044..d301ab418 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSoundBuffer.cpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSoundBuffer.cpp @@ -173,7 +173,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(DirectSoundCreateBuffer) hRet = xbox::EMUPATCH(DirectSoundCreate)(nullptr, &g_pDSound8, nullptr); if (hRet != DS_OK) { - CxbxKrnlCleanup("Unable to initialize DirectSound!"); + CxbxrKrnlAbort("Unable to initialize DirectSound!"); } } @@ -238,7 +238,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(DirectSoundCreateBuffer) EmuLog(LOG_LEVEL::WARNING, output.str().c_str()); output.str(""); output << static_cast(hRet); - CxbxKrnlCleanup("DSB: DSoundBufferCreate error: %s", output.str().c_str()); + CxbxrKrnlAbort("DSB: DSoundBufferCreate error: %s", output.str().c_str()); } else { if (pdsbd->dwFlags & DSBCAPS_CTRL3D) { @@ -460,7 +460,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(IDirectSoundBuffer_Lock) } if (hRet != DS_OK) { - CxbxKrnlCleanup("IDirectSoundBuffer_Lock Failed!"); + CxbxrKrnlAbort("IDirectSoundBuffer_Lock Failed!"); } // Host lock position @@ -632,7 +632,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(IDirectSoundBuffer_Play) pThis->X_lock.dwLockBytes2); if (dwFlags & ~(X_DSBPLAY_LOOPING | X_DSBPLAY_FROMSTART | X_DSBPLAY_SYNCHPLAYBACK)) { - CxbxKrnlCleanup("Unsupported Playing Flags"); + CxbxrKrnlAbort("Unsupported Playing Flags"); } pThis->EmuPlayFlags = dwFlags; diff --git a/src/core/hle/DSOUND/DirectSound/DirectSoundInline.hpp b/src/core/hle/DSOUND/DirectSound/DirectSoundInline.hpp index ec5a8d9ed..3c42651b6 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSoundInline.hpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSoundInline.hpp @@ -274,7 +274,7 @@ static inline void GeneratePCMFormat( } if (DSBufferDesc.lpwfxFormat == nullptr) { - CxbxKrnlCleanup("Unable to allocate DSBufferDesc.Xb_lpwfxFormat"); + CxbxrKrnlAbort("Unable to allocate DSBufferDesc.Xb_lpwfxFormat"); } if (Xb_lpwfxFormat != xbox::zeroptr) { @@ -358,7 +358,7 @@ static inline void DSoundGenericUnlock( HRESULT hRet = pDSBuffer->Unlock(Host_lock.pLockPtr1, Host_lock.dwLockBytes1, Host_lock.pLockPtr2, Host_lock.dwLockBytes2); if (hRet != DS_OK) { - CxbxKrnlCleanup("DirectSoundBuffer Unlock Failed!"); + CxbxrKrnlAbort("DirectSoundBuffer Unlock Failed!"); } Host_lock.pLockPtr1 = nullptr; @@ -485,7 +485,7 @@ static inline void DSoundBufferRelease( if (pDS3DBuffer != nullptr) { refCount = pDS3DBuffer->Release(); if (refCount > 0) { - CxbxKrnlCleanup("Nope, wasn't fully cleaned up."); + CxbxrKrnlAbort("Nope, wasn't fully cleaned up."); } } @@ -554,7 +554,7 @@ static inline void DSoundBufferResizeUpdate( hRet = pThis->EmuDirectSoundBuffer8->Lock(0, 0, &pThis->Host_lock.pLockPtr1, &pThis->Host_lock.dwLockBytes1, nullptr, nullptr, DSBLOCK_ENTIREBUFFER); if (hRet != DS_OK) { - CxbxKrnlCleanup("Unable to lock region buffer!"); + CxbxrKrnlAbort("Unable to lock region buffer!"); } DSoundGenericUnlock(pThis->EmuFlags, pThis->EmuDirectSoundBuffer8, @@ -630,7 +630,7 @@ static inline void DSoundBufferRegenWithNewFormat( HRESULT hRet = pDSBuffer->GetStatus(&dwStatus); if (hRet != DS_OK) { - CxbxKrnlCleanup("Unable to retrieve current status for replace DS buffer!"); + CxbxrKrnlAbort("Unable to retrieve current status for replace DS buffer!"); } pDSBuffer->Stop(); @@ -638,7 +638,7 @@ static inline void DSoundBufferRegenWithNewFormat( hRet = pDSBuffer->GetCurrentPosition(&dwPlayCursor, nullptr); if (hRet != DS_OK) { - CxbxKrnlCleanup("Unable to retrieve current position for replace DS buffer!"); + CxbxrKrnlAbort("Unable to retrieve current position for replace DS buffer!"); } // TODO: Untested if transfer buffer to new audio buffer is necessary. @@ -922,7 +922,7 @@ static inline HRESULT HybridDirectSoundBuffer_Play( { if (dwFlags & ~(X_DSBPLAY_LOOPING | X_DSBPLAY_FROMSTART | X_DSBPLAY_SYNCHPLAYBACK)) { - CxbxKrnlCleanup("Unsupported Playing Flags"); + CxbxrKrnlAbort("Unsupported Playing Flags"); } // rewind buffer if ((dwFlags & X_DSBPLAY_FROMSTART)) { diff --git a/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp b/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp index 1697e7252..991a2eeec 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp @@ -222,7 +222,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(DirectSoundCreateStream) hRet = xbox::EMUPATCH(DirectSoundCreate)(nullptr, &g_pDSound8, nullptr); if (hRet != DS_OK) { - CxbxKrnlCleanup("Unable to initialize DirectSound!"); + CxbxrKrnlAbort("Unable to initialize DirectSound!"); } } @@ -299,7 +299,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(DirectSoundCreateStream) EmuLog(LOG_LEVEL::WARNING, output.str().c_str()); output.str(""); output << static_cast(hRet); - CxbxKrnlCleanup("DSS: DSoundBufferCreate error: %s", output.str().c_str()); + CxbxrKrnlAbort("DSS: DSoundBufferCreate error: %s", output.str().c_str()); } else { if (DSBufferDesc.dwFlags & DSBCAPS_CTRL3D) { diff --git a/src/core/hle/Intercept.cpp b/src/core/hle/Intercept.cpp index 4c28dfeb5..9d5062a1c 100644 --- a/src/core/hle/Intercept.cpp +++ b/src/core/hle/Intercept.cpp @@ -191,7 +191,7 @@ void CDECL EmuOutputMessage(xb_output_message mFlag, break; } case XB_OUTPUT_MESSAGE_ERROR: { - CxbxKrnlCleanup("%s", message); + CxbxrKrnlAbort("%s", message); break; } case XB_OUTPUT_MESSAGE_DEBUG: @@ -381,9 +381,9 @@ void EmuHLEIntercept(Xbe::Header *pXbeHeader) << std::endl; // Make sure the Symbol Cache directory exists - std::string cachePath = std::string(szFolder_CxbxReloadedData) + "\\SymbolCache\\"; + std::string cachePath = g_DataFilePath + "\\SymbolCache\\"; if (!std::filesystem::exists(cachePath) && !std::filesystem::create_directory(cachePath)) { - CxbxKrnlCleanup("Couldn't create Cxbx-Reloaded SymbolCache folder!"); + CxbxrKrnlAbort("Couldn't create Cxbx-Reloaded SymbolCache folder!"); } // Hash the loaded XBE's header, use it as a filename diff --git a/src/core/hle/XAPI/Xapi.cpp b/src/core/hle/XAPI/Xapi.cpp index 0cdef1d9a..d1c968ece 100644 --- a/src/core/hle/XAPI/Xapi.cpp +++ b/src/core/hle/XAPI/Xapi.cpp @@ -370,7 +370,7 @@ void SetupXboxDeviceTypes() // Sanity check: Where all these device offsets within Xbox memory if ((deviceTableStartOffset >= g_SystemMaxMemory) || (deviceTableEndOffset >= g_SystemMaxMemory)) { - CxbxKrnlCleanup("DeviceTable Location is outside of Xbox Memory range"); + CxbxrKrnlAbort("DeviceTable Location is outside of Xbox Memory range"); } // Iterate through the table until we find gamepad @@ -903,7 +903,7 @@ xbox::void_xt WINAPI xbox::EMUPATCH(XRegisterThreadNotifyRoutine) { // I honestly don't expect this to happen, but if it does... if(g_iThreadNotificationCount >= 16) - CxbxKrnlCleanup("Too many thread notification routines installed\n"); + CxbxrKrnlAbort("Too many thread notification routines installed\n"); // Find an empty spot in the thread notification array for(int i = 0; i < 16; i++) @@ -1141,7 +1141,7 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XLaunchNewImageA) // Other options include LDT_NONE, LDT_FROM_DEBUGGER_CMDLINE and LDT_FROM_UPDATE } else - CxbxKrnlCleanup("The xbe rebooted to Dashboard and xboxdash.xbe could not be found"); + CxbxrKrnlAbort("The xbe rebooted to Dashboard and xboxdash.xbe could not be found"); } strncpy(&(xbox::LaunchDataPage->Header.szLaunchPath[0]), lpTitlePath, 520); diff --git a/src/core/hle/XGRAPHIC/XGraphic.cpp b/src/core/hle/XGRAPHIC/XGraphic.cpp index 78e7200a8..eee2c68d8 100644 --- a/src/core/hle/XGRAPHIC/XGraphic.cpp +++ b/src/core/hle/XGRAPHIC/XGraphic.cpp @@ -31,7 +31,7 @@ #include "core\kernel\support\Emu.h" #include "common\Logging.h" -#include "core\kernel\init\CxbxKrnl.h" // For CxbxKrnlCleanup() +#include "core\kernel\init\CxbxKrnl.h" // For CxbxrKrnlAbort() #include "core\hle\XAPI\Xapi.h" // For EMUPATCH #include "core\hle\D3D8\XbD3D8Logging.h" // for log rendering of X_D3DFORMAT, etc. #include "core\hle\XGRAPHIC\XGraphic.h" @@ -84,7 +84,7 @@ xbox::void_xt WINAPI xbox::EMUPATCH(XGSwizzleRect) else { if(pPoint != NULL && (pPoint->x != 0 || pPoint->y != 0)) - CxbxKrnlCleanup("Temporarily unsupported swizzle (very easy fix)"); + CxbxrKrnlAbort("Temporarily unsupported swizzle (very easy fix)"); DWORD dwMaxY = Height; DWORD dwChunkSize = Width; @@ -150,7 +150,7 @@ xbox::void_xt WINAPI xbox::EMUPATCH(XGSwizzleBox) else { if(pPoint != NULL && (pPoint->u != 0 || pPoint->v != 0 || pPoint->w != 0)) - CxbxKrnlCleanup("Temporarily unsupported swizzle (very easy fix)"); + CxbxrKrnlAbort("Temporarily unsupported swizzle (very easy fix)"); DWORD dwMaxY = Height; DWORD dwMaxZ = Depth; @@ -232,10 +232,10 @@ xbox::void_xt WINAPI xbox::EMUPATCH(XGSetTextureHeader) LOG_FUNC_END; /*if( Data != 0 ) - CxbxKrnlCleanup("Data != 0 (XGSetTextureHeader)" ); + CxbxrKrnlAbort("Data != 0 (XGSetTextureHeader)" ); if( Pitch != 0 ) - CxbxKrnlCleanup("Pitch != 0 (XGSetTextureHeader)" );*/ + CxbxrKrnlAbort("Pitch != 0 (XGSetTextureHeader)" );*/ pTexture->Common = X_D3DCOMMON_TYPE_TEXTURE + 1; // Set refcount to 1 pTexture->Data = Data; diff --git a/src/core/kernel/exports/EmuKrnl.cpp b/src/core/kernel/exports/EmuKrnl.cpp index 4863d0282..3b3342fd9 100644 --- a/src/core/kernel/exports/EmuKrnl.cpp +++ b/src/core/kernel/exports/EmuKrnl.cpp @@ -148,7 +148,7 @@ extern void ExecuteDpcQueue(); void KiUnexpectedInterrupt() { xbox::KeBugCheck(TRAP_CAUSE_UNKNOWN); // see - CxbxKrnlCleanup("Unexpected Software Interrupt!"); + CxbxrKrnlAbort("Unexpected Software Interrupt!"); } void CallSoftwareInterrupt(const xbox::KIRQL SoftwareIrql) diff --git a/src/core/kernel/exports/EmuKrnlEx.cpp b/src/core/kernel/exports/EmuKrnlEx.cpp index 526d36e0c..f91cb4f7a 100644 --- a/src/core/kernel/exports/EmuKrnlEx.cpp +++ b/src/core/kernel/exports/EmuKrnlEx.cpp @@ -41,7 +41,7 @@ namespace NtDll #include "core\kernel\support\EmuNtDll.h" // For NtDelayExecution(), etc. }; -#include "core\kernel\init\CxbxKrnl.h" // For CxbxKrnlCleanup +#include "core\kernel\init\CxbxKrnl.h" // For CxbxrKrnlAbort #include "core\kernel\support\Emu.h" // For EmuLog(LOG_LEVEL::WARNING, ) #include "EmuKrnl.h" // For InsertHeadList, InsertTailList, RemoveHeadList diff --git a/src/core/kernel/exports/EmuKrnlHal.cpp b/src/core/kernel/exports/EmuKrnlHal.cpp index f9ca8df39..7ee429377 100644 --- a/src/core/kernel/exports/EmuKrnlHal.cpp +++ b/src/core/kernel/exports/EmuKrnlHal.cpp @@ -33,7 +33,7 @@ #include "Logging.h" // For LOG_FUNC() #include "EmuKrnl.h" // For InitializeListHead(), etc. #include "EmuKrnlLogging.h" -#include "core\kernel\init\CxbxKrnl.h" // For CxbxKrnlCleanup, and CxbxExec +#include "core\kernel\init\CxbxKrnl.h" // For CxbxrKrnlAbort, and CxbxExec #include "core\kernel\support\Emu.h" // For EmuLog(LOG_LEVEL::WARNING, ) #include "EmuKrnl.h" #include "devices\x86\EmuX86.h" // HalReadWritePciSpace needs this @@ -489,7 +489,7 @@ XBSYSAPI EXPORTNUM(49) xbox::void_xt DECLSPEC_NORETURN NTAPI xbox::HalReturnToFi switch (Routine) { case ReturnFirmwareHalt: - CxbxKrnlCleanup("Emulated Xbox is halted"); + CxbxrKrnlAbort("Emulated Xbox is halted"); break; case ReturnFirmwareReboot: diff --git a/src/core/kernel/exports/EmuKrnlIo.cpp b/src/core/kernel/exports/EmuKrnlIo.cpp index b0b9c333f..cce67332f 100644 --- a/src/core/kernel/exports/EmuKrnlIo.cpp +++ b/src/core/kernel/exports/EmuKrnlIo.cpp @@ -32,7 +32,7 @@ #include // For IoCompletionObjectType, etc. #include "Logging.h" // For LOG_FUNC() #include "EmuKrnlLogging.h" -#include "core\kernel\init\CxbxKrnl.h" // For CxbxKrnlCleanup +#include "core\kernel\init\CxbxKrnl.h" // For CxbxrKrnlAbort #include "core\kernel\support\Emu.h" // For EmuLog(LOG_LEVEL::WARNING, ) #include "core\kernel\support\EmuFile.h" // For CxbxCreateSymbolicLink(), etc. #include "CxbxDebugger.h" diff --git a/src/core/kernel/exports/EmuKrnlKe.cpp b/src/core/kernel/exports/EmuKrnlKe.cpp index b5ff210cd..0ef47775a 100644 --- a/src/core/kernel/exports/EmuKrnlKe.cpp +++ b/src/core/kernel/exports/EmuKrnlKe.cpp @@ -75,7 +75,7 @@ namespace NtDll #include "core\kernel\support\EmuNtDll.h" // For NtDelayExecution(), etc. }; -#include "core\kernel\init\CxbxKrnl.h" // For CxbxKrnlCleanup +#include "core\kernel\init\CxbxKrnl.h" // For CxbxrKrnlAbort #include "core\kernel\support\Emu.h" // For EmuLog(LOG_LEVEL::WARNING, ) #include "EmuKrnl.h" // For InitializeListHead(), etc. #include "EmuKrnlKi.h" // For KiRemoveTreeTimer(), KiInsertTreeTimer() @@ -465,7 +465,7 @@ XBSYSAPI EXPORTNUM(96) xbox::ntstatus_xt NTAPI xbox::KeBugCheckEx int result = MessageBoxA(g_hEmuWindow, buffer, "KeBugCheck", MB_YESNO | MB_ICONWARNING); if (result == IDNO) { - CxbxKrnlCleanup(NULL); + CxbxrKrnlAbort(NULL); } KeBugCheckIgnored = true; diff --git a/src/core/kernel/exports/EmuKrnlMm.cpp b/src/core/kernel/exports/EmuKrnlMm.cpp index 5c304c3c9..3ca239736 100644 --- a/src/core/kernel/exports/EmuKrnlMm.cpp +++ b/src/core/kernel/exports/EmuKrnlMm.cpp @@ -34,7 +34,7 @@ #include "Logging.h" // For LOG_FUNC() #include "EmuKrnl.h" // For DefaultLaunchDataPage #include "EmuKrnlLogging.h" -#include "core\kernel\init\CxbxKrnl.h" // For CxbxKrnlCleanup +#include "core\kernel\init\CxbxKrnl.h" // For CxbxrKrnlAbort #include "core\kernel\support\Emu.h" // For EmuLog(LOG_LEVEL::WARNING, ) #include "core\kernel\memory-manager\VMManager.h" #include "EmuShared.h" diff --git a/src/core/kernel/exports/EmuKrnlNt.cpp b/src/core/kernel/exports/EmuKrnlNt.cpp index a5c1a2db9..f821a18be 100644 --- a/src/core/kernel/exports/EmuKrnlNt.cpp +++ b/src/core/kernel/exports/EmuKrnlNt.cpp @@ -39,7 +39,7 @@ namespace NtDll #include "core\kernel\support\EmuNtDll.h" }; -#include "core\kernel\init\CxbxKrnl.h" // For CxbxKrnlCleanup +#include "core\kernel\init\CxbxKrnl.h" // For CxbxrKrnlAbort #include "core\kernel\exports\EmuKrnlKe.h" #include "core\kernel\support\Emu.h" // For EmuLog(LOG_LEVEL::WARNING, ) #include "core\kernel\support\EmuFile.h" // For EmuNtSymbolicLinkObject, NtStatusToString(), etc. @@ -1099,7 +1099,7 @@ XBSYSAPI EXPORTNUM(207) xbox::ntstatus_xt NTAPI xbox::NtQueryDirectoryFile NTSTATUS ret; if (FileInformationClass != FileDirectoryInformation) // Due to unicode->string conversion - CxbxKrnlCleanup("Unsupported FileInformationClass"); + CxbxrKrnlAbort("Unsupported FileInformationClass"); NtDll::UNICODE_STRING NtFileMask; diff --git a/src/core/kernel/exports/EmuKrnlOb.cpp b/src/core/kernel/exports/EmuKrnlOb.cpp index 08b84cf17..f2a747b1f 100644 --- a/src/core/kernel/exports/EmuKrnlOb.cpp +++ b/src/core/kernel/exports/EmuKrnlOb.cpp @@ -39,7 +39,7 @@ #include // For ObDirectoryObjectType, etc. #include "Logging.h" // For LOG_FUNC() #include "EmuKrnlLogging.h" -#include "core\kernel\init\CxbxKrnl.h" // For CxbxKrnlCleanup +#include "core\kernel\init\CxbxKrnl.h" // For CxbxrKrnlAbort #include "EmuKrnl.h" // For OBJECT_TO_OBJECT_HEADER() #include "core\kernel\support\EmuFile.h" // For EmuNtSymbolicLinkObject, NtStatusToString(), etc. #include diff --git a/src/core/kernel/exports/EmuKrnlPs.cpp b/src/core/kernel/exports/EmuKrnlPs.cpp index 41c01669b..db23f8fa8 100644 --- a/src/core/kernel/exports/EmuKrnlPs.cpp +++ b/src/core/kernel/exports/EmuKrnlPs.cpp @@ -318,7 +318,7 @@ XBSYSAPI EXPORTNUM(257) xbox::ntstatus_xt NTAPI xbox::PsSetCreateThreadNotifyRou // I honestly don't expect this to happen, but if it does... if (g_iThreadNotificationCount >= PSP_MAX_CREATE_THREAD_NOTIFY) - CxbxKrnlCleanup("Too many thread notification routines installed\n"); + CxbxrKrnlAbort("Too many thread notification routines installed\n"); // Find an empty spot in the thread notification array for (int i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++) diff --git a/src/core/kernel/exports/EmuKrnlRtl.cpp b/src/core/kernel/exports/EmuKrnlRtl.cpp index 0c5ae3848..614d21601 100644 --- a/src/core/kernel/exports/EmuKrnlRtl.cpp +++ b/src/core/kernel/exports/EmuKrnlRtl.cpp @@ -40,7 +40,7 @@ namespace NtDll #include "core\kernel\support\EmuNtDll.h" }; -#include "core\kernel\init\CxbxKrnl.h" // For CxbxKrnlCleanup() +#include "core\kernel\init\CxbxKrnl.h" // For CxbxrKrnlAbort() #include "core\kernel\support\Emu.h" // For EmuLog(LOG_LEVEL::WARNING, ) #include @@ -701,7 +701,7 @@ XBSYSAPI EXPORTNUM(277) xbox::void_xt NTAPI xbox::RtlEnterCriticalSection ); if (!nt_success(result)) { - CxbxKrnlCleanup("Waiting for event of a critical section returned %lx.", result); + CxbxrKrnlAbort("Waiting for event of a critical section returned %lx.", result); }; } CriticalSection->OwningThread = thread; diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index 822a0e1e6..3889de9ae 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -35,6 +35,7 @@ #include "common\xbdm\CxbxXbdm.h" // For Cxbx_LibXbdmThunkTable #include "CxbxVersion.h" #include "core\kernel\support\Emu.h" +#include "core/kernel/support/PatchRdtsc.hpp" #include "devices\x86\EmuX86.h" #include "core\kernel\support\EmuFile.h" #include "core\kernel\support\EmuFS.h" // EmuInitFS @@ -71,6 +72,11 @@ #include "Timer.h" // For Timer_Init #include "common\input\InputManager.h" // For the InputDeviceManager +#include "common/FilePaths.hpp" + +// Intended only for CxbxrKrnl.cpp usage. +#include "KrnlPatches.hpp" + /*! thread local storage */ Xbe::TLS *CxbxKrnl_TLS = NULL; /*! thread local storage data */ @@ -83,15 +89,15 @@ Xbe::Header *CxbxKrnl_XbeHeader = NULL; bool g_bIsDebugKernel = false; HWND CxbxKrnl_hEmuParent = NULL; -DebugMode CxbxKrnl_DebugMode = DebugMode::DM_NONE; -std::string CxbxKrnl_DebugFileName = ""; +DebugMode CxbxrKrnl_DebugMode = DebugMode::DM_NONE; +std::string CxbxrKrnl_DebugFileName = ""; Xbe::Certificate *g_pCertificate = NULL; /*! thread handles */ static std::vector g_hThreads; char szFilePath_CxbxReloaded_Exe[MAX_PATH] = { 0 }; -char szFolder_CxbxReloadedData[MAX_PATH] = { 0 }; +std::string g_DataFilePath; char szFilePath_EEPROM_bin[MAX_PATH] = { 0 }; char szFilePath_Xbe[xbox::max_path*2] = { 0 }; // NOTE: LAUNCH_DATA_HEADER's szLaunchPath is xbox::max_path*2 = 520 @@ -114,36 +120,6 @@ ULONG g_CxbxFatalErrorCode = FATAL_ERROR_NONE; // Define function located in EmuXApi so we can call it from here void SetupXboxDeviceTypes(); -void ApplyMediaPatches() -{ - // Patch the XBE Header to allow running from all media types - g_pCertificate->dwAllowedMedia |= 0 - | XBEIMAGE_MEDIA_TYPE_HARD_DISK - | XBEIMAGE_MEDIA_TYPE_DVD_X2 - | XBEIMAGE_MEDIA_TYPE_DVD_CD - | XBEIMAGE_MEDIA_TYPE_CD - | XBEIMAGE_MEDIA_TYPE_DVD_5_RO - | XBEIMAGE_MEDIA_TYPE_DVD_9_RO - | XBEIMAGE_MEDIA_TYPE_DVD_5_RW - | XBEIMAGE_MEDIA_TYPE_DVD_9_RW - ; - // Patch the XBE Header to allow running on all regions - g_pCertificate->dwGameRegion = 0 - | XBEIMAGE_GAME_REGION_MANUFACTURING - | XBEIMAGE_GAME_REGION_NA - | XBEIMAGE_GAME_REGION_JAPAN - | XBEIMAGE_GAME_REGION_RESTOFWORLD - ; - // Patch the XBE Security Flag - // This field is only present if the Xbe Size is >= than our Certificate Structure - // This works as our structure is large enough to fit the newer certificate size, - // while dwSize is the actual size of the certificate in the Xbe. - // Source: Various Hacked Kernels - if (g_pCertificate->dwSize >= sizeof(Xbe::Certificate)) { - g_pCertificate->dwSecurityFlags &= ~1; - } -} - void SetupPerTitleKeys() { // Generate per-title keys from the XBE Certificate @@ -220,9 +196,6 @@ void RestoreExeImageHeader() ExeOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS] = NewOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS]; } -// Forward declaration to avoid moving the definition of LoadXboxKeys -void LoadXboxKeys(std::string path); - // Returns the Win32 error in string format. Returns an empty string if there is no error. std::string CxbxGetErrorCodeAsString(DWORD errorCode) { @@ -428,174 +401,6 @@ static void CxbxKrnlClockThread(void* pVoid) xbox::KiClockIsr(IncrementScaling); } -std::vector g_RdtscPatches; - -#define OPCODE_PATCH_RDTSC 0x90EF // OUT DX, EAX; NOP - -bool IsRdtscInstruction(xbox::addr_xt addr) -{ - // First the fastest check - does addr contain exact patch from PatchRdtsc? - // Second check - is addr on the rdtsc patch list? - return (*(uint16_t*)addr == OPCODE_PATCH_RDTSC) - // Note : It's not needed to check for g_SkipRdtscPatching, - // as when that's set, the g_RdtscPatches vector will be empty - // anyway, failing this lookup : - && (std::find(g_RdtscPatches.begin(), g_RdtscPatches.end(), addr) != g_RdtscPatches.end()); -} - -void PatchRdtsc(xbox::addr_xt addr) -{ - // Patch away rdtsc with an opcode we can intercept - // We use a privilaged instruction rather than int 3 for debugging - // When using int 3, attached debuggers trap and rdtsc is used often enough - // that it makes Cxbx-Reloaded unusable - // A privilaged instruction (like OUT) does not suffer from this - EmuLogInit(LOG_LEVEL::DEBUG, "Patching rdtsc opcode at 0x%.8X", (DWORD)addr); - *(uint16_t*)addr = OPCODE_PATCH_RDTSC; - g_RdtscPatches.push_back(addr); -} - -const uint8_t rdtsc_pattern[] = { - 0x89,//{ 0x0F,0x31,0x89 }, // two false positives in Stranger's Wrath - 0xC3,//{ 0x0F,0x31,0xC3 }, - 0x8B,//{ 0x0F,0x31,0x8B }, // one false positive in Sonic Rider .text 88 5C 0F 31, two false positives in Stranger's Wrath - 0xB9,//{ 0x0F,0x31,0xB9 }, - 0xC7,//{ 0x0F,0x31,0xC7 }, - 0x8D,//{ 0x0F,0x31,0x8D }, - 0x68,//{ 0x0F,0x31,0x68 }, - 0x5A,//{ 0x0F,0x31,0x5A }, - 0x29,//{ 0x0F,0x31,0x29 }, - 0xF3,//{ 0x0F,0x31,0xF3 }, - 0xE9,//{ 0x0F,0x31,0xE9 }, - 0x2B,//{ 0x0F,0x31,0x2B }, - 0x50,//{ 0x0F,0x31,0x50 }, // 0x50 only used in ExaSkeleton .text , but encounter false positive in RalliSport .text 83 E2 0F 31 - 0x0F,//{ 0x0F,0x31,0x0F }, - 0x3B,//{ 0x0F,0x31,0x3B }, - 0xD9,//{ 0x0F,0x31,0xD9 }, - 0x57,//{ 0x0F,0x31,0x57 }, - 0xB9,//{ 0x0F,0x31,0xB9 }, - 0x85,//{ 0x0F,0x31,0x85 }, - 0x83,//{ 0x0F,0x31,0x83 }, - 0x33,//{ 0x0F,0x31,0x33 }, - 0xF7,//{ 0x0F,0x31,0xF7 }, // one false positive in Stranger's Wrath - 0x8A,//{ 0x0F,0x31,0x8A }, // 8A and 56 only apears in RalliSport 2 .text , need to watch whether any future false positive. - 0x56,//{ 0x0F,0x31,0x56 } - 0x6A, // 6A, 39, EB, F6, A1, 01 only appear in Unreal Championship, 01 is at WMVDEC section - 0x39, - 0xEB, - 0xF6, - 0xA1, - 0x01, // one false positive in Group S Challenge [1.05] .text E8 0F 31 01 00 - 0xA3 -}; -const int sizeof_rdtsc_pattern = sizeof(rdtsc_pattern); - -void PatchRdtscInstructions() -{ - uint8_t rdtsc[2] = { 0x0F, 0x31 }; - DWORD sizeOfImage = CxbxKrnl_XbeHeader->dwSizeofImage; - - // Iterate through each CODE section - for (uint32_t sectionIndex = 0; sectionIndex < CxbxKrnl_Xbe->m_Header.dwSections; sectionIndex++) { - if (!CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwFlags.bExecutable) { - continue; - } - - // Skip some segments known to never contain rdtsc (to avoid false positives) - if (std::string(CxbxKrnl_Xbe->m_szSectionName[sectionIndex]) == "DSOUND" - || std::string(CxbxKrnl_Xbe->m_szSectionName[sectionIndex]) == "XGRPH" - || std::string(CxbxKrnl_Xbe->m_szSectionName[sectionIndex]) == ".data" - || std::string(CxbxKrnl_Xbe->m_szSectionName[sectionIndex]) == ".rdata" - || std::string(CxbxKrnl_Xbe->m_szSectionName[sectionIndex]) == "XMV" - || std::string(CxbxKrnl_Xbe->m_szSectionName[sectionIndex]) == "XONLINE" - || std::string(CxbxKrnl_Xbe->m_szSectionName[sectionIndex]) == "MDLPL") { - continue; - } - - EmuLogInit(LOG_LEVEL::INFO, "Searching for rdtsc in section %s", CxbxKrnl_Xbe->m_szSectionName[sectionIndex]); - xbox::addr_xt startAddr = CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwVirtualAddr; - //rdtsc is two bytes instruction, it needs at least one opcode byte after it to finish a function, so the endAddr need to substract 3 bytes. - xbox::addr_xt endAddr = startAddr + CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwSizeofRaw-3; - for (xbox::addr_xt addr = startAddr; addr <= endAddr; addr++) - { - if (memcmp((void*)addr, rdtsc, 2) == 0) - { - uint8_t next_byte = *(uint8_t*)(addr + 2); - // If the following byte matches the known pattern. - int i = 0; - for (i = 0; i= sizeof_rdtsc_pattern) - { - //no pattern matched, keep record for detections we treat as non-rdtsc for future debugging. - EmuLogInit(LOG_LEVEL::INFO, "Skipped potential rdtsc: Unknown opcode pattern 0x%.2X, @ 0x%.8X", next_byte, (DWORD)addr); - } - } - } - } - - EmuLogInit(LOG_LEVEL::INFO, "Done patching rdtsc, total %d rdtsc instructions patched", g_RdtscPatches.size()); -} - void MapThunkTable(uint32_t* kt, uint32_t* pThunkTable) { const bool SendDebugReports = (pThunkTable == CxbxKrnl_KernelThunkTable) && CxbxDebugger::CanReport(); @@ -684,6 +489,532 @@ bool HandleFirstLaunch() return true; } +FILE* CxbxrKrnlSetupVerboseLog(int BootFlags) +{ + std::string tempStr; + // Get KernelDebugMode : + CxbxrKrnl_DebugMode = DebugMode::DM_NONE; + if (cli_config::GetValue(cli_config::debug_mode, &tempStr)) { + CxbxrKrnl_DebugMode = (DebugMode)std::atoi(tempStr.c_str()); + } + + // Get KernelDebugFileName : + CxbxrKrnl_DebugFileName = ""; + if (!cli_config::GetValue(cli_config::debug_file, &CxbxrKrnl_DebugFileName)) { + CxbxrKrnl_DebugFileName = ""; + } + + // debug console allocation (if configured) + if (CxbxrKrnl_DebugMode == DM_CONSOLE) + { + if (AllocConsole()) + { + HANDLE StdHandle = GetStdHandle(STD_OUTPUT_HANDLE); + // Maximise the console scroll buffer height : + CONSOLE_SCREEN_BUFFER_INFO coninfo; + GetConsoleScreenBufferInfo(StdHandle, &coninfo); + coninfo.dwSize.Y = SHRT_MAX - 1; // = 32767-1 = 32766 = maximum value that works + SetConsoleScreenBufferSize(StdHandle, coninfo.dwSize); + (void)freopen("CONOUT$", "wt", stdout); + (void)freopen("CONIN$", "rt", stdin); + SetConsoleTitle("Cxbx-Reloaded : Kernel Debug Console"); + SetConsoleTextAttribute(StdHandle, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED); + } + } + else + { + FreeConsole(); + if (CxbxrKrnl_DebugMode == DM_FILE) { + // Peform clean write to kernel log for first boot. Unless multi-xbe boot occur then perform append to existing log. + FILE* krnlLog = freopen(CxbxrKrnl_DebugFileName.c_str(), ((BootFlags == DebugMode::DM_NONE) ? "wt" : "at"), stdout); + // Append separator for better readability after reboot. + if (BootFlags != DebugMode::DM_NONE) { + std::cout << "\n------REBOOT------REBOOT------REBOOT------REBOOT------REBOOT------\n" << std::endl; + } + return krnlLog; + } + else { + char buffer[16]; + if (GetConsoleTitle(buffer, 16) != NULL) + (void)freopen("nul", "w", stdout); + } + } + return nullptr; +} + +static void CxbxrKrnlSyncGUI() +{ + if (CxbxKrnl_hEmuParent != NULL) { + ipc_send_gui_update(IPC_UPDATE_GUI::KRNL_IS_READY, static_cast(GetCurrentProcessId())); + + // Force wait until GUI process is ready + do { + int waitCounter = 10; + bool isReady = false; + + while (waitCounter > 0) { + g_EmuShared->GetIsReady(&isReady); + if (isReady) { + break; + } + waitCounter--; + Sleep(100); + } + if (!isReady) { + EmuLog(LOG_LEVEL::WARNING, "GUI process is not ready!"); + PopupReturn mbRet = PopupWarningEx(nullptr, PopupButtons::RetryCancel, PopupReturn::Cancel, + "GUI process is not ready, do you wish to retry?"); + if (mbRet == PopupReturn::Retry) { + continue; + } + CxbxKrnlShutDown(); + } + break; + } while (true); + } +} + +static void CxbxrKrnlSetupMemorySystem(int BootFlags, unsigned emulate_system, unsigned reserved_systems, blocks_reserved_t blocks_reserved) +{ +#ifndef CXBXR_EMU + // Only for GUI executable with emulation code. + blocks_reserved_t blocks_reserved_gui = { 0 }; + // Reserve console system's memory ranges before start initialize. + if (!ReserveAddressRanges(emulate_system, blocks_reserved_gui)) { + CxbxrKrnlAbort("Failed to reserve required memory ranges!", GetLastError()); + } + // Initialize the memory manager + g_VMManager.Initialize(emulate_system, BootFlags, blocks_reserved_gui); +#else + // Release unnecessary memory ranges to allow console/host to use those memory ranges. + FreeAddressRanges(emulate_system, reserved_systems, blocks_reserved); + // Initialize the memory manager + g_VMManager.Initialize(emulate_system, BootFlags, blocks_reserved); +#endif + + // Commit the memory used by the xbe header + size_t HeaderSize = CxbxKrnl_Xbe->m_Header.dwSizeofHeaders; + VAddr XbeBase = XBE_IMAGE_BASE; + g_VMManager.XbAllocateVirtualMemory(&XbeBase, 0, &HeaderSize, XBOX_MEM_COMMIT, XBOX_PAGE_READWRITE); + + // Copy over loaded Xbe Headers to specified base address + memcpy((void*)CxbxKrnl_Xbe->m_Header.dwBaseAddr, &CxbxKrnl_Xbe->m_Header, sizeof(Xbe::Header)); + memcpy((void*)(CxbxKrnl_Xbe->m_Header.dwBaseAddr + sizeof(Xbe::Header)), CxbxKrnl_Xbe->m_HeaderEx, CxbxKrnl_Xbe->m_ExSize); + + // Load all sections marked as preload using the in-memory copy of the xbe header + xbox::PXBEIMAGE_SECTION sectionHeaders = (xbox::PXBEIMAGE_SECTION)CxbxKrnl_Xbe->m_Header.dwSectionHeadersAddr; + for (uint32_t i = 0; i < CxbxKrnl_Xbe->m_Header.dwSections; i++) { + if ((sectionHeaders[i].Flags & XBEIMAGE_SECTION_PRELOAD) != 0) { + NTSTATUS result = xbox::XeLoadSection(§ionHeaders[i]); + if (FAILED(result)) { + EmuLogInit(LOG_LEVEL::WARNING, "Failed to preload XBE section: %s", CxbxKrnl_Xbe->m_szSectionName[i]); + } + } + } +} + +static bool CxbxrKrnlXbeSystemSelector(int BootFlags, unsigned& reserved_systems, blocks_reserved_t blocks_reserved) +{ + XbeType xbeType = XbeType::xtRetail; + // Get title path : + std::string xbePath; + cli_config::GetValue(cli_config::load, &xbePath); + xbePath = std::filesystem::absolute(std::filesystem::path(xbePath)).string(); + + // NOTE: This is a safety to clean the file path for any malicious file path attempt. + // Might want to move this into a utility function. + size_t n, i; + // Remove useless slashes before and after semicolon. + std::string semicolon_search[] = { "\\;", ";\\", "/;", ";/" }; + std::string semicolon_str = ";"; + for (n = 0, i = 0; i < semicolon_search->size(); i++, n = 0) { + while ((n = xbePath.find(semicolon_search[i], n)) != std::string::npos) { + xbePath.replace(n, semicolon_search[i].size(), semicolon_str); + n += semicolon_str.size(); + } + } + + // Once clean up process is done, proceed set to global variable string. + strncpy(szFilePath_Xbe, xbePath.c_str(), xbox::max_path - 1); + std::replace(xbePath.begin(), xbePath.end(), ';', '/'); + // Load Xbe (this one will reside above WinMain's virtual_memory_placeholder) + std::filesystem::path xbeDirectory = std::filesystem::path(xbePath).parent_path(); + +#ifdef CHIHIRO_WORK + // If the Xbe is Chihiro, and we were not launched by SEGABOOT, we need to load SEGABOOT from the Chihiro Media Board rom instead! + // If the XBE path contains a boot.id, it must be a Chihiro title + // This is necessary as some Chihiro games use the Debug xor instead of the Chihiro ones + // which means we cannot rely on that alone. + if (BootFlags == BOOT_NONE && std::filesystem::exists(xbeDirectory / "boot.id")) { + + std::string chihiroMediaBoardRom = g_DataFilePath + "/EmuDisk/" + MediaBoardRomFile; + if (!std::filesystem::exists(chihiroMediaBoardRom)) { + CxbxrKrnlAbort("Chihiro Media Board ROM (fpr21042_m29w160et.bin) could not be found"); + } + + // Open a handle to the mediaboard rom + FILE* fpRom = fopen(chihiroMediaBoardRom.c_str(), "rb"); + if (fpRom == nullptr) { + CxbxrKrnlAbort("Chihiro Media Board ROM (fpr21042_m29w160et.bin) could not opened for read"); + } + + // Verify the size of media board rom + fseek(fpRom, 0, SEEK_END); + auto length = ftell(fpRom); + if (length != 2 * ONE_MB) { + CxbxrKrnlAbort("Chihiro Media Board ROM (fpr21042_m29w160et.bin) has an invalid size"); + + } + fseek(fpRom, 0, SEEK_SET); + + // Extract SEGABOOT_OLD.XBE and SEGABOOT.XBE from Media Rom + // We only do this if SEGABOOT_OLD and SEGABOOT.XBE are *not* already present + std::string chihiroSegaBootOld = g_DataFilePath + "/EmuDisk/" + MediaBoardSegaBoot0; + std::string chihiroSegaBootNew = g_DataFilePath + "/EmuDisk/" + MediaBoardSegaBoot1; + if (!std::filesystem::exists(chihiroSegaBootOld) || !std::filesystem::exists(chihiroSegaBootNew)) { + FILE* fpSegaBootOld = fopen(chihiroSegaBootOld.c_str(), "wb"); + FILE* fpSegaBootNew = fopen(chihiroSegaBootNew.c_str(), "wb"); + if (fpSegaBootNew == nullptr || fpSegaBootOld == nullptr) { + CxbxrKrnlAbort("Could not open SEGABOOT for writing"); + + } + + // Extract SEGABOOT (Old) + void* buffer = malloc(ONE_MB); + if (buffer == nullptr) { + CxbxrKrnlAbort("Could not allocate buffer for SEGABOOT"); + + } + + fread(buffer, 1, ONE_MB, fpRom); + fwrite(buffer, 1, ONE_MB, fpSegaBootOld); + + // Extract SEGABOOT (New) + fread(buffer, 1, ONE_MB, fpRom); + fwrite(buffer, 1, ONE_MB, fpSegaBootNew); + + free(buffer); + + fclose(fpSegaBootOld); + fclose(fpSegaBootNew); + fclose(fpRom); + + } + + g_EmuShared->SetTitleMountPath(xbeDirectory.string().c_str()); + + // Launch Segaboot + CxbxLaunchNewXbe(chihiroSegaBootNew); + CxbxKrnlShutDown(true); + TerminateProcess(GetCurrentProcess(), EXIT_SUCCESS); + + } +#endif // Chihiro wip block + + CxbxKrnl_Xbe = new Xbe(xbePath.c_str(), false); // TODO : Instead of using the Xbe class, port Dxbx _ReadXbeBlock() + + if (CxbxKrnl_Xbe->HasFatalError()) { + CxbxrKrnlAbort(CxbxKrnl_Xbe->GetError().c_str()); + return false; + } + + // Check the signature of the xbe + if (CxbxKrnl_Xbe->CheckSignature()) { + EmuLogInit(LOG_LEVEL::INFO, "Valid xbe signature. Xbe is legit"); + } + else { + EmuLogInit(LOG_LEVEL::WARNING, "Invalid xbe signature. Homebrew, tampered or pirated xbe?"); + } + + // Check the integrity of the xbe sections + for (uint32_t sectionIndex = 0; sectionIndex < CxbxKrnl_Xbe->m_Header.dwSections; sectionIndex++) { + if (CxbxKrnl_Xbe->CheckSectionIntegrity(sectionIndex)) { + EmuLogInit(LOG_LEVEL::INFO, "SHA hash check of section %s successful", CxbxKrnl_Xbe->m_szSectionName[sectionIndex]); + } + else { + EmuLogInit(LOG_LEVEL::WARNING, "SHA hash of section %s doesn't match, section is corrupted", CxbxKrnl_Xbe->m_szSectionName[sectionIndex]); + } + } + + // If CLI has given console type, then enforce it. + if (cli_config::hasKey(cli_config::system_chihiro)) { + EmuLogInit(LOG_LEVEL::INFO, "Auto detect is disabled, running as chihiro."); + xbeType = XbeType::xtChihiro; + } + else if (cli_config::hasKey(cli_config::system_devkit)) { + EmuLogInit(LOG_LEVEL::INFO, "Auto detect is disabled, running as devkit."); + xbeType = XbeType::xtDebug; + } + else if (cli_config::hasKey(cli_config::system_retail)) { + EmuLogInit(LOG_LEVEL::INFO, "Auto detect is disabled, running as retail."); + xbeType = XbeType::xtRetail; + } + // Otherwise, use auto detect method. + else { + // Detect XBE type : + xbeType = CxbxKrnl_Xbe->GetXbeType(); + EmuLogInit(LOG_LEVEL::INFO, "Auto detect: XbeType = %s", GetXbeTypeToStr(xbeType)); + } + + EmuLogInit(LOG_LEVEL::INFO, "Host's compatible system types: %2X", reserved_systems); + unsigned int emulate_system = 0; + // Set reserved_systems which system we will about to emulate. + if (isSystemFlagSupport(reserved_systems, SYSTEM_CHIHIRO) && xbeType == XbeType::xtChihiro) { + emulate_system = SYSTEM_CHIHIRO; + } + else if (isSystemFlagSupport(reserved_systems, SYSTEM_DEVKIT) && xbeType == XbeType::xtDebug) { + emulate_system = SYSTEM_DEVKIT; + } + else if (isSystemFlagSupport(reserved_systems, SYSTEM_XBOX) && xbeType == XbeType::xtRetail) { + emulate_system = SYSTEM_XBOX; + } + // If none of system type requested to emulate isn't supported on host's end. Then enforce failure. + else { + CxbxrKrnlAbort("Unable to emulate system type due to host is not able to reserve required memory ranges."); + return false; + } + // Clear emulation system from reserved systems to be free. + reserved_systems &= ~emulate_system; + + // Once we have determine which system type to run as, enforce it in future reboots. + if ((BootFlags & BOOT_QUICK_REBOOT) == 0) { + const char* system_str = GetSystemTypeToStr(emulate_system); + cli_config::SetSystemType(system_str); + } + + // Register if we're running an Chihiro executable or a debug xbe, otherwise it's an Xbox retail executable + g_bIsChihiro = (xbeType == XbeType::xtChihiro); + g_bIsDebug = (xbeType == XbeType::xtDebug); + g_bIsRetail = (xbeType == XbeType::xtRetail); + +#ifdef CHIHIRO_WORK + // If this is a Chihiro title, we need to patch the init flags to disable HDD setup + // The Chihiro kernel does this, so we should too! + if (g_bIsChihiro) { + CxbxKrnl_Xbe->m_Header.dwInitFlags.bDontSetupHarddisk = true; + } +#else + if (g_bIsChihiro) { + CxbxrKrnlAbort("Emulating Chihiro mode does not work yet. Please use different title to emulate."); + } +#endif + + CxbxrKrnlSetupMemorySystem(BootFlags, emulate_system, reserved_systems, blocks_reserved); + return true; +} + +// HACK: Attempt to patch out XBE header reads +static void CxbxrKrnlXbePatchXBEHSig() { + // This works by searching for the XBEH signature and replacing it with what appears in host address space instead + // Test case: Half Life 2 + // Iterate through each CODE section + for (uint32_t sectionIndex = 0; sectionIndex < CxbxKrnl_Xbe->m_Header.dwSections; sectionIndex++) { + if (!CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwFlags.bExecutable) { + continue; + } + + EmuLogInit(LOG_LEVEL::INFO, "Searching for XBEH in section %s", CxbxKrnl_Xbe->m_szSectionName[sectionIndex]); + xbox::addr_xt startAddr = CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwVirtualAddr; + xbox::addr_xt endAddr = startAddr + CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwSizeofRaw; + for (xbox::addr_xt addr = startAddr; addr < endAddr; addr++) { + if (*(uint32_t*)addr == 0x48454258) { + EmuLogInit(LOG_LEVEL::INFO, "Patching XBEH at 0x%08X", addr); + *((uint32_t*)addr) = *(uint32_t*)XBE_IMAGE_BASE; + } + } + } +} + +static size_t CxbxrKrnlGetRelativePath(std::filesystem::path& get_relative_path) { + // Determine location for where possible auto mount D letter if ";" delimiter exist. + // Also used to store in EmuShared's title mount path permanent storage on first emulation launch. + // Unless it's launch within Cxbx-Reloaded's EmuDisk directly, then we don't store anything in title mount path storage. + std::string relative_path(szFilePath_Xbe); + size_t lastFind = relative_path.find(';'); + // First find if there is a semicolon when dashboard or title disc (such as demo disc) has it. + // Then we must obey the current directory it asked for. + if (lastFind != std::string::npos) { + if (relative_path.find(';', lastFind + 1) != std::string::npos) { + CxbxrKrnlAbortEx(LOG_PREFIX_INIT, "Cannot contain multiple of ; symbol."); + } + relative_path = relative_path.substr(0, lastFind); + } + else { + relative_path = relative_path.substr(0, relative_path.find_last_of("\\/")); + } + CxbxResolveHostToFullPath(relative_path, "xbe's directory"); + + get_relative_path = relative_path; + return lastFind; +} + +static void CxbxrKrnlSetupSymLinks(int CxbxCdrom0DeviceIndex, int lastFind, std::filesystem::path& relative_path) +{ + // Create default symbolic links : + EmuLogInit(LOG_LEVEL::DEBUG, "Creating default symbolic links."); + // TODO: DriveD should auto mount based on the launchdata page's ; delimiter in the xbe path. + // This is the only symbolic link the Xbox Kernel sets, the rest are set by the application, usually via XAPI. + // If the Xbe is located outside of the emulated HDD, mounting it as DeviceCdrom0 is correct + // If the Xbe is located inside the emulated HDD, the full path should be used, eg: "\\Harddisk0\\partition2\\xboxdash.xbe" +#ifdef CXBX_KERNEL_REWORK_ENABLED + if (lastFind != std::string::npos) { +#else + // HACK: It is a hack to override XDK's default mount to CdRom0 which may not exist when launch to dashboard directly. + // Otherwise, titles may launch to dashboard, more specifically xbox live title, and back. + if (CxbxCdrom0DeviceIndex == -1 || lastFind != std::string::npos) { +#endif + CxbxCreateSymbolicLink(DriveD, relative_path.string()); + } +} + +static void CxbxrKrnlSetupCdRom0Path(int BootFlags, int lastFind, std::filesystem::path relative_path, bool isEmuDisk) +{ + int CxbxCdrom0DeviceIndex = -1; + // Check if title mounth path is already set. This may occur from early boot of Chihiro title. + char title_mount_path[sizeof(szFilePath_Xbe)]; + g_EmuShared->GetTitleMountPath(title_mount_path); + std::filesystem::path default_mount_path = title_mount_path; + + if (default_mount_path.native()[0] == 0 && BootFlags == BOOT_NONE) { + // Remember our first initialize mount path for CdRom0 and Mbfs. + if (!isEmuDisk) { + g_EmuShared->SetTitleMountPath(relative_path.string().c_str()); + default_mount_path = relative_path.c_str(); + } + } + + // TODO: Find a place to make permanent placement for DeviceCdrom0 that does not have disc loaded. + if (default_mount_path.native()[0] != 0) { + // NOTE: Don't need to perform CxbxResolveHostToFullPath again for default_mount_path. + CxbxCdrom0DeviceIndex = CxbxRegisterDeviceHostPath(DeviceCdrom0, default_mount_path.string()); + // Since Chihiro also map Mbfs to the same path as Cdrom0, we'll map it the same way. + if (g_bIsChihiro) { + (void)CxbxRegisterDeviceHostPath(DriveMbfs, default_mount_path.string()); + } + } + + CxbxrKrnlSetupSymLinks(CxbxCdrom0DeviceIndex, lastFind, relative_path); +} + +static void CxbxrKrnlRegisterDevicePaths() +{ + // Partition 0 contains configuration data, and is accessed as a native file, instead as a folder : + CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition0, g_DiskBasePath + "Partition0", /*IsFile=*/true); + // The first two partitions are for Data and Shell files, respectively : + CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition1, g_DiskBasePath + "Partition1"); + CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition2, g_DiskBasePath + "Partition2"); + // The following partitions are for caching purposes - for now we allocate up to 7 (as xbmp needs that many) : + CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition3, g_DiskBasePath + "Partition3"); + CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition4, g_DiskBasePath + "Partition4"); + CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition5, g_DiskBasePath + "Partition5"); + CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition6, g_DiskBasePath + "Partition6"); + CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition7, g_DiskBasePath + "Partition7"); + CxbxRegisterDeviceHostPath(DevicePrefix + "\\Chihiro", g_DiskBasePath + "Chihiro"); + + // Create the MU directories and the bin files + CxbxRegisterDeviceHostPath(DeviceMU0, g_MuBasePath + "F", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU1, g_MuBasePath + "G", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU2, g_MuBasePath + "H", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU3, g_MuBasePath + "I", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU4, g_MuBasePath + "J", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU5, g_MuBasePath + "K", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU6, g_MuBasePath + "L", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU7, g_MuBasePath + "M", false, sizeof(FATX_SUPERBLOCK)); +} + +static bool CxbxrKrnlPrepareXbeMap() +{ + + // Our executable DOS image header must be loaded at 0x00010000 + // Assert(ExeDosHeader == XBE_IMAGE_BASE); + + // Determine EXE's header locations & size : + ExeNtHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)ExeDosHeader + ExeDosHeader->e_lfanew); // = + 0x138 + ExeOptionalHeader = (PIMAGE_OPTIONAL_HEADER) & (ExeNtHeader->OptionalHeader); + + // verify base of code of our executable is 0x00001000 + if (ExeNtHeader->OptionalHeader.BaseOfCode != CXBX_BASE_OF_CODE) + { + PopupFatal(nullptr, "Cxbx-Reloaded executuable requires it's base of code to be 0x00001000"); + return false; // TODO : Halt(0); + } + +#ifndef CXBXR_EMU + // verify virtual_memory_placeholder is located at 0x00011000 + if ((UINT_PTR)(&(virtual_memory_placeholder[0])) != (XBE_IMAGE_BASE + CXBX_BASE_OF_CODE)) + { + PopupFatal(nullptr, "virtual_memory_placeholder is not loaded to base address 0x00011000 (which is a requirement for Xbox emulation)"); + return false; // TODO : Halt(0); + } +#endif + + // Create a safe copy of the complete EXE header: + DWORD ExeHeaderSize = ExeOptionalHeader->SizeOfHeaders; // Should end up as 0x400 + NewDosHeader = (PIMAGE_DOS_HEADER)VirtualAlloc(nullptr, ExeHeaderSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + + if (NewDosHeader == nullptr) { + PopupFatal(nullptr, "Unable to VirtualAlloc with 0x%X size for NewDosHeader", ExeHeaderSize); + return false; + } + + memcpy(NewDosHeader, ExeDosHeader, ExeHeaderSize); + + // Determine NewOptionalHeader, required by RestoreExeImageHeader + NewNtHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)NewDosHeader + ExeDosHeader->e_lfanew); + NewOptionalHeader = (PIMAGE_OPTIONAL_HEADER) & (NewNtHeader->OptionalHeader); + + // Make sure the new DOS header points to the new relative NtHeader location: + NewDosHeader->e_lfanew = (ULONG_PTR)NewNtHeader - XBE_IMAGE_BASE; + + // Note : NewOptionalHeader->ImageBase can stay at ExeOptionalHeader->ImageBase = 0x00010000 + + // Note : Since virtual_memory_placeholder prevents overlap between reserved xbox memory + // and Cxbx.exe sections, section headers don't have to be patched up. + + // Mark the virtual memory range completely accessible + DWORD OldProtection; + if (0 == VirtualProtect((void*)XBE_IMAGE_BASE, XBE_MAX_VA - XBE_IMAGE_BASE, PAGE_EXECUTE_READWRITE, &OldProtection)) { + DWORD err = GetLastError(); + + // Translate ErrorCode to String. + LPTSTR Error = 0; + if (::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + err, + 0, + (LPTSTR)&Error, + 0, + NULL) == 0) { + // Failed in translating. + } + + // Free the buffer. + if (Error) { + ::LocalFree(Error); + Error = 0; + } + } + + // Clear out the virtual memory range + memset((void*)XBE_IMAGE_BASE, 0, XBE_MAX_VA - XBE_IMAGE_BASE); + + // Restore enough of the executable image headers to keep WinAPI's working : + RestoreExeImageHeader(); + + return true; +} + +/*! initialize emulation */ +[[noreturn]] static void CxbxrKrnlInit( + void* pTLSData, + Xbe::TLS* pTLS, + Xbe::LibraryVersion* LibraryVersion, + Xbe::Header* XbeHeader, + uint32_t XbeHeaderSize, + void (*Entry)(), + int BootFlags +); + void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_reserved) { // First of all, check if the EmuShared version matches the emu version and abort otherwise @@ -725,14 +1056,8 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res /* Initialize popup message management from kernel side. */ log_init_popup_msg(); - /* Initialize Cxbx File Paths */ - CxbxInitFilePaths(); - - // Skip '/load' switch - // Get XBE Name : - std::string xbePath; - cli_config::GetValue(cli_config::load, &xbePath); - xbePath = std::filesystem::absolute(std::filesystem::path(xbePath)).string(); + /* Initialize Cxbx-Reloaded File Paths */ + CxbxrInitFilePaths(); // Get DCHandle : // We must save this handle now to keep the child window working in the case we need to display the UEM @@ -742,18 +1067,6 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res } CxbxKrnl_hEmuParent = IsWindow(hWnd) ? hWnd : nullptr; - // Get KernelDebugMode : - DebugMode DbgMode = DebugMode::DM_NONE; - if (cli_config::GetValue(cli_config::debug_mode, &tempStr)) { - DbgMode = (DebugMode)std::atoi(tempStr.c_str()); - } - - // Get KernelDebugFileName : - std::string DebugFileName = ""; - if (cli_config::GetValue(cli_config::debug_file, &tempStr)) { - DebugFileName = tempStr; - } - int BootFlags; g_EmuShared->GetBootFlags(&BootFlags); @@ -767,34 +1080,7 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res g_VMManager.GetPersistentMemory(); } - if (CxbxKrnl_hEmuParent != NULL) { - ipc_send_gui_update(IPC_UPDATE_GUI::KRNL_IS_READY, static_cast(GetCurrentProcessId())); - - // Force wait until GUI process is ready - do { - int waitCounter = 10; - bool isReady = false; - - while (waitCounter > 0) { - g_EmuShared->GetIsReady(&isReady); - if (isReady) { - break; - } - waitCounter--; - Sleep(100); - } - if (!isReady) { - EmuLog(LOG_LEVEL::WARNING, "GUI process is not ready!"); - PopupReturn mbRet = PopupWarningEx(nullptr, PopupButtons::RetryCancel, PopupReturn::Cancel, - "GUI process is not ready, do you wish to retry?"); - if (mbRet == PopupReturn::Retry) { - continue; - } - CxbxKrnlShutDown(); - } - break; - } while (true); - } + CxbxrKrnlSyncGUI(); g_EmuShared->SetIsReady(false); @@ -823,46 +1109,12 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res CxbxKrnlShutDown(); } - /* Must be called after CxbxInitFilePaths and previous kernel process shutdown. */ + /* Must be called after CxbxrInitFilePaths and previous kernel process shutdown. */ if (!CxbxLockFilePath()) { return; } - FILE* krnlLog = nullptr; - // debug console allocation (if configured) - if (DbgMode == DM_CONSOLE) - { - if (AllocConsole()) - { - HANDLE StdHandle = GetStdHandle(STD_OUTPUT_HANDLE); - // Maximise the console scroll buffer height : - CONSOLE_SCREEN_BUFFER_INFO coninfo; - GetConsoleScreenBufferInfo(StdHandle, &coninfo); - coninfo.dwSize.Y = SHRT_MAX - 1; // = 32767-1 = 32766 = maximum value that works - SetConsoleScreenBufferSize(StdHandle, coninfo.dwSize); - (void)freopen("CONOUT$", "wt", stdout); - (void)freopen("CONIN$", "rt", stdin); - SetConsoleTitle("Cxbx-Reloaded : Kernel Debug Console"); - SetConsoleTextAttribute(StdHandle, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED); - } - } - else - { - FreeConsole(); - if (DbgMode == DM_FILE) { - // Peform clean write to kernel log for first boot. Unless multi-xbe boot occur then perform append to existing log. - krnlLog = freopen(DebugFileName.c_str(), ((BootFlags == DebugMode::DM_NONE) ? "wt" : "at"), stdout); - // Append separator for better readability after reboot. - if (BootFlags != DebugMode::DM_NONE) { - std::cout << "\n------REBOOT------REBOOT------REBOOT------REBOOT------REBOOT------\n" << std::endl; - } - } - else { - char buffer[16]; - if (GetConsoleTitle(buffer, 16) != NULL) - (void)freopen("nul", "w", stdout); - } - } + FILE* krnlLog = CxbxrKrnlSetupVerboseLog(BootFlags); bool isLogEnabled; g_EmuShared->GetIsKrnlLogEnabled(&isLogEnabled); @@ -893,81 +1145,12 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res } // Now we got the arguments, start by initializing the Xbox memory map : - // PrepareXBoxMemoryMap() - { - // Our executable DOS image header must be loaded at 0x00010000 - // Assert(ExeDosHeader == XBE_IMAGE_BASE); - - // Determine EXE's header locations & size : - ExeNtHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)ExeDosHeader + ExeDosHeader->e_lfanew); // = + 0x138 - ExeOptionalHeader = (PIMAGE_OPTIONAL_HEADER)&(ExeNtHeader->OptionalHeader); - - // verify base of code of our executable is 0x00001000 - if (ExeNtHeader->OptionalHeader.BaseOfCode != CXBX_BASE_OF_CODE) - { - PopupFatal(nullptr, "Cxbx-Reloaded executuable requires it's base of code to be 0x00001000"); - return; // TODO : Halt(0); - } - -#ifndef CXBXR_EMU - // verify virtual_memory_placeholder is located at 0x00011000 - if ((UINT_PTR)(&(virtual_memory_placeholder[0])) != (XBE_IMAGE_BASE + CXBX_BASE_OF_CODE)) - { - PopupFatal(nullptr, "virtual_memory_placeholder is not loaded to base address 0x00011000 (which is a requirement for Xbox emulation)"); - return; // TODO : Halt(0); - } -#endif - - // Create a safe copy of the complete EXE header: - DWORD ExeHeaderSize = ExeOptionalHeader->SizeOfHeaders; // Should end up as 0x400 - NewDosHeader = (PIMAGE_DOS_HEADER)VirtualAlloc(nullptr, ExeHeaderSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - memcpy(NewDosHeader, ExeDosHeader, ExeHeaderSize); - - // Determine NewOptionalHeader, required by RestoreExeImageHeader - NewNtHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)NewDosHeader + ExeDosHeader->e_lfanew); - NewOptionalHeader = (PIMAGE_OPTIONAL_HEADER)&(NewNtHeader->OptionalHeader); - - // Make sure the new DOS header points to the new relative NtHeader location: - NewDosHeader->e_lfanew = (ULONG_PTR)NewNtHeader - XBE_IMAGE_BASE; - - // Note : NewOptionalHeader->ImageBase can stay at ExeOptionalHeader->ImageBase = 0x00010000 - - // Note : Since virtual_memory_placeholder prevents overlap between reserved xbox memory - // and Cxbx.exe sections, section headers don't have to be patched up. - - // Mark the virtual memory range completely accessible - DWORD OldProtection; - if (0 == VirtualProtect((void*)XBE_IMAGE_BASE, XBE_MAX_VA - XBE_IMAGE_BASE, PAGE_EXECUTE_READWRITE, &OldProtection)) { - DWORD err = GetLastError(); - - // Translate ErrorCode to String. - LPTSTR Error = 0; - if (::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - err, - 0, - (LPTSTR)&Error, - 0, - NULL) == 0) { - // Failed in translating. - } - - // Free the buffer. - if (Error) { - ::LocalFree(Error); - Error = 0; - } - } - - // Clear out the virtual memory range - memset((void*)XBE_IMAGE_BASE, 0, XBE_MAX_VA - XBE_IMAGE_BASE); - - // Restore enough of the executable image headers to keep WinAPI's working : - RestoreExeImageHeader(); + if (!CxbxrKrnlPrepareXbeMap()) { + return; // TODO : Halt(0); } - // Load Per-Xbe Keys from the Cxbx-Reloaded AppData directory - LoadXboxKeys(szFolder_CxbxReloadedData); + // Load Xbox Keys from the Cxbx-Reloaded AppData directory + LoadXboxKeys(); EEPROM = CxbxRestoreEEPROM(szFilePath_EEPROM_bin); if (EEPROM == nullptr) @@ -979,252 +1162,19 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res // TODO : Instead of loading an Xbe here, initialize the kernel so that it will launch the Xbe on itself. // using XeLoadImage from LaunchDataPage->Header.szLaunchPath - // Now we can load and run the XBE : - // MapAndRunXBE(XbePath, DCHandle); - XbeType xbeType = XbeType::xtRetail; - { - // NOTE: This is a safety to clean the file path for any malicious file path attempt. - // Might want to move this into a utility function. - size_t n, i; - // Remove useless slashes before and after semicolon. - std::string semicolon_search[] = { "\\;", ";\\", "/;", ";/" }; - std::string semicolon_str = ";"; - for (n = 0, i = 0; i < semicolon_search->size(); i++, n = 0) { - while ((n = xbePath.find(semicolon_search[i], n)) != std::string::npos) { - xbePath.replace(n, semicolon_search[i].size(), semicolon_str); - n += semicolon_str.size(); - } - } - - // Once clean up process is done, proceed set to global variable string. - strncpy(szFilePath_Xbe, xbePath.c_str(), xbox::max_path - 1); - std::replace(xbePath.begin(), xbePath.end(), ';', '/'); - // Load Xbe (this one will reside above WinMain's virtual_memory_placeholder) - std::filesystem::path xbeDirectory = std::filesystem::path(xbePath).parent_path(); - -#ifdef CHIHIRO_WORK - // If the Xbe is Chihiro, and we were not launched by SEGABOOT, we need to load SEGABOOT from the Chihiro Media Board rom instead! - // If the XBE path contains a boot.id, it must be a Chihiro title - // This is necessary as some Chihiro games use the Debug xor instead of the Chihiro ones - // which means we cannot rely on that alone. - if (BootFlags == BOOT_NONE && std::filesystem::exists(xbeDirectory / "boot.id")) { - - std::string chihiroMediaBoardRom = std::string(szFolder_CxbxReloadedData) + std::string("/EmuDisk/") + MediaBoardRomFile; - if (!std::filesystem::exists(chihiroMediaBoardRom)) { - CxbxKrnlCleanup("Chihiro Media Board ROM (fpr21042_m29w160et.bin) could not be found"); - } - - // Open a handle to the mediaboard rom - FILE* fpRom = fopen(chihiroMediaBoardRom.c_str(), "rb"); - if (fpRom == nullptr) { - CxbxKrnlCleanup("Chihiro Media Board ROM (fpr21042_m29w160et.bin) could not opened for read"); - } - - // Verify the size of media board rom - fseek(fpRom, 0, SEEK_END); - auto length = ftell(fpRom); - if (length != 2 * ONE_MB) { - CxbxKrnlCleanup("Chihiro Media Board ROM (fpr21042_m29w160et.bin) has an invalid size"); - - } - fseek(fpRom, 0, SEEK_SET); - - // Extract SEGABOOT_OLD.XBE and SEGABOOT.XBE from Media Rom - // We only do this if SEGABOOT_OLD and SEGABOOT.XBE are *not* already present - std::string chihiroSegaBootOld = std::string(szFolder_CxbxReloadedData) + std::string("/EmuDisk/") + MediaBoardSegaBoot0; - std::string chihiroSegaBootNew = std::string(szFolder_CxbxReloadedData) + std::string("/EmuDisk/") + MediaBoardSegaBoot1; - if (!std::filesystem::exists(chihiroSegaBootOld) || !std::filesystem::exists(chihiroSegaBootNew)) { - FILE* fpSegaBootOld = fopen(chihiroSegaBootOld.c_str(), "wb"); - FILE* fpSegaBootNew = fopen(chihiroSegaBootNew.c_str(), "wb"); - if (fpSegaBootNew == nullptr || fpSegaBootOld == nullptr) { - CxbxKrnlCleanup("Could not open SEGABOOT for writing"); - - } - - // Extract SEGABOOT (Old) - void* buffer = malloc(ONE_MB); - if (buffer == nullptr) { - CxbxKrnlCleanup("Could not allocate buffer for SEGABOOT"); - - } - - fread(buffer, 1, ONE_MB, fpRom); - fwrite(buffer, 1, ONE_MB, fpSegaBootOld); - - // Extract SEGABOOT (New) - fread(buffer, 1, ONE_MB, fpRom); - fwrite(buffer, 1, ONE_MB, fpSegaBootNew); - - free(buffer); - - fclose(fpSegaBootOld); - fclose(fpSegaBootNew); - fclose(fpRom); - - } - - g_EmuShared->SetTitleMountPath(xbeDirectory.string().c_str()); - - // Launch Segaboot - CxbxLaunchNewXbe(chihiroSegaBootNew); - CxbxKrnlShutDown(true); - TerminateProcess(GetCurrentProcess(), EXIT_SUCCESS); - - } -#endif // Chihiro wip block - - CxbxKrnl_Xbe = new Xbe(xbePath.c_str(), false); // TODO : Instead of using the Xbe class, port Dxbx _ReadXbeBlock() - - if (CxbxKrnl_Xbe->HasFatalError()) { - CxbxKrnlCleanup(CxbxKrnl_Xbe->GetError().c_str()); - return; - } - - // Check the signature of the xbe - if (CxbxKrnl_Xbe->CheckSignature()) { - EmuLogInit(LOG_LEVEL::INFO, "Valid xbe signature. Xbe is legit"); - } - else { - EmuLogInit(LOG_LEVEL::WARNING, "Invalid xbe signature. Homebrew, tampered or pirated xbe?"); - } - - // Check the integrity of the xbe sections - for (uint32_t sectionIndex = 0; sectionIndex < CxbxKrnl_Xbe->m_Header.dwSections; sectionIndex++) { - if (CxbxKrnl_Xbe->CheckSectionIntegrity(sectionIndex)) { - EmuLogInit(LOG_LEVEL::INFO, "SHA hash check of section %s successful", CxbxKrnl_Xbe->m_szSectionName[sectionIndex]); - } - else { - EmuLogInit(LOG_LEVEL::WARNING, "SHA hash of section %s doesn't match, section is corrupted", CxbxKrnl_Xbe->m_szSectionName[sectionIndex]); - } - } - - // If CLI has given console type, then enforce it. - if (cli_config::hasKey(cli_config::system_chihiro)) { - EmuLogInit(LOG_LEVEL::INFO, "Auto detect is disabled, running as chihiro."); - xbeType = XbeType::xtChihiro; - } - else if (cli_config::hasKey(cli_config::system_devkit)) { - EmuLogInit(LOG_LEVEL::INFO, "Auto detect is disabled, running as devkit."); - xbeType = XbeType::xtDebug; - } - else if (cli_config::hasKey(cli_config::system_retail)) { - EmuLogInit(LOG_LEVEL::INFO, "Auto detect is disabled, running as retail."); - xbeType = XbeType::xtRetail; - } - // Otherwise, use auto detect method. - else { - // Detect XBE type : - xbeType = CxbxKrnl_Xbe->GetXbeType(); - EmuLogInit(LOG_LEVEL::INFO, "Auto detect: XbeType = %s", GetXbeTypeToStr(xbeType)); - } - - EmuLogInit(LOG_LEVEL::INFO, "Host's compatible system types: %2X", reserved_systems); - unsigned int emulate_system = 0; - // Set reserved_systems which system we will about to emulate. - if (isSystemFlagSupport(reserved_systems, SYSTEM_CHIHIRO) && xbeType == XbeType::xtChihiro) { - emulate_system = SYSTEM_CHIHIRO; - } - else if (isSystemFlagSupport(reserved_systems, SYSTEM_DEVKIT) && xbeType == XbeType::xtDebug) { - emulate_system = SYSTEM_DEVKIT; - } - else if (isSystemFlagSupport(reserved_systems, SYSTEM_XBOX) && xbeType == XbeType::xtRetail) { - emulate_system = SYSTEM_XBOX; - } - // If none of system type requested to emulate isn't supported on host's end. Then enforce failure. - else { - CxbxKrnlCleanup("Unable to emulate system type due to host is not able to reserve required memory ranges."); - return; - } - // Clear emulation system from reserved systems to be free. - reserved_systems &= ~emulate_system; - - // Once we have determine which system type to run as, enforce it in future reboots. - if ((BootFlags & BOOT_QUICK_REBOOT) == 0) { - const char* system_str = GetSystemTypeToStr(emulate_system); - cli_config::SetSystemType(system_str); - } - - // Register if we're running an Chihiro executable or a debug xbe, otherwise it's an Xbox retail executable - g_bIsChihiro = (xbeType == XbeType::xtChihiro); - g_bIsDebug = (xbeType == XbeType::xtDebug); - g_bIsRetail = (xbeType == XbeType::xtRetail); - -#ifdef CHIHIRO_WORK - // If this is a Chihiro title, we need to patch the init flags to disable HDD setup - // The Chihiro kernel does this, so we should too! - if (g_bIsChihiro) { - CxbxKrnl_Xbe->m_Header.dwInitFlags.bDontSetupHarddisk = true; - } -#else - if (g_bIsChihiro) { - CxbxKrnlCleanup("Emulating Chihiro mode does not work yet. Please use different title to emulate."); - } -#endif - -#ifndef CXBXR_EMU - // Only for GUI executable with emulation code. - blocks_reserved_t blocks_reserved_gui = { 0 }; - // Reserve console system's memory ranges before start initialize. - if (!ReserveAddressRanges(emulate_system, blocks_reserved_gui)) { - CxbxKrnlCleanup("Failed to reserve required memory ranges!", GetLastError()); - } - // Initialize the memory manager - g_VMManager.Initialize(emulate_system, BootFlags, blocks_reserved_gui); -#else - // Release unnecessary memory ranges to allow console/host to use those memory ranges. - FreeAddressRanges(emulate_system, reserved_systems, blocks_reserved); - // Initialize the memory manager - g_VMManager.Initialize(emulate_system, BootFlags, blocks_reserved); -#endif - - // Commit the memory used by the xbe header - size_t HeaderSize = CxbxKrnl_Xbe->m_Header.dwSizeofHeaders; - VAddr XbeBase = XBE_IMAGE_BASE; - g_VMManager.XbAllocateVirtualMemory(&XbeBase, 0, &HeaderSize, XBOX_MEM_COMMIT, XBOX_PAGE_READWRITE); - - - // Copy over loaded Xbe Headers to specified base address - memcpy((void*)CxbxKrnl_Xbe->m_Header.dwBaseAddr, &CxbxKrnl_Xbe->m_Header, sizeof(Xbe::Header)); - memcpy((void*)(CxbxKrnl_Xbe->m_Header.dwBaseAddr + sizeof(Xbe::Header)), CxbxKrnl_Xbe->m_HeaderEx, CxbxKrnl_Xbe->m_ExSize); - - // Load all sections marked as preload using the in-memory copy of the xbe header - xbox::PXBEIMAGE_SECTION sectionHeaders = (xbox::PXBEIMAGE_SECTION)CxbxKrnl_Xbe->m_Header.dwSectionHeadersAddr; - for (uint32_t i = 0; i < CxbxKrnl_Xbe->m_Header.dwSections; i++) { - if ((sectionHeaders[i].Flags & XBEIMAGE_SECTION_PRELOAD) != 0) { - NTSTATUS result = xbox::XeLoadSection(§ionHeaders[i]); - if (FAILED(result)) { - EmuLogInit(LOG_LEVEL::WARNING, "Failed to preload XBE section: %s", CxbxKrnl_Xbe->m_szSectionName[i]); - } - } - } - - // We need to remember a few XbeHeader fields, so we can switch between a valid ExeHeader and XbeHeader : - StoreXbeImageHeader(); - - // Restore enough of the executable image headers to keep WinAPI's working : - RestoreExeImageHeader(); - - // HACK: Attempt to patch out XBE header reads - // This works by searching for the XBEH signature and replacing it with what appears in host address space instead - // Test case: Half Life 2 - // Iterate through each CODE section - for (uint32_t sectionIndex = 0; sectionIndex < CxbxKrnl_Xbe->m_Header.dwSections; sectionIndex++) { - if (!CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwFlags.bExecutable) { - continue; - } - - EmuLogInit(LOG_LEVEL::INFO, "Searching for XBEH in section %s", CxbxKrnl_Xbe->m_szSectionName[sectionIndex]); - xbox::addr_xt startAddr = CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwVirtualAddr; - xbox::addr_xt endAddr = startAddr + CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwSizeofRaw; - for (xbox::addr_xt addr = startAddr; addr < endAddr; addr++) { - if (*(uint32_t*)addr == 0x48454258) { - EmuLogInit(LOG_LEVEL::INFO, "Patching XBEH at 0x%08X", addr); - *((uint32_t*)addr) = *(uint32_t*)XBE_IMAGE_BASE; - } - } - } + // Now we can load the XBE : + if (!CxbxrKrnlXbeSystemSelector(BootFlags, reserved_systems, blocks_reserved)) { + return; } + // We need to remember a few XbeHeader fields, so we can switch between a valid ExeHeader and XbeHeader : + StoreXbeImageHeader(); + + // Restore enough of the executable image headers to keep WinAPI's working : + RestoreExeImageHeader(); + + CxbxrKrnlXbePatchXBEHSig(); + g_ExceptionManager = new ExceptionManager(); // If in need to add VEHs, move this line earlier. (just in case) // Launch the XBE : @@ -1236,12 +1186,10 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res xbox::addr_xt EntryPoint = CxbxKrnl_Xbe->m_Header.dwEntryAddr; EntryPoint ^= XOR_EP_KEY[to_underlying(CxbxKrnl_Xbe->GetXbeType())]; // Launch XBE - CxbxKrnlInit( + CxbxrKrnlInit( XbeTlsData, XbeTls, - CxbxKrnl_Xbe->m_LibraryVersion, - DbgMode, - DebugFileName.c_str(), + CxbxKrnl_Xbe->m_LibraryVersion, (Xbe::Header*)CxbxKrnl_Xbe->m_Header.dwBaseAddr, CxbxKrnl_Xbe->m_Header.dwSizeofHeaders, (void(*)())EntryPoint, @@ -1255,66 +1203,52 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res } #pragma optimize("", on) -// Loads a keys.bin file as generated by dump-xbox -// See https://github.com/JayFoxRox/xqemu-tools/blob/master/dump-xbox.c -void LoadXboxKeys(std::string path) +// Dump Xbe information +// TODO: May need to relocate elsewhere, like in a log file than here. +static void CxbxrLogDumpXbeInfo(Xbe::LibraryVersion* libVersionInfo) { - std::string keys_path = path + "\\keys.bin"; - - // Attempt to open Keys.bin - FILE* fp = fopen(keys_path.c_str(), "rb"); - - if (fp != nullptr) { - // Determine size of Keys.bin - xbox::XBOX_KEY_DATA keys[2]; - fseek(fp, 0, SEEK_END); - long size = ftell(fp); - rewind(fp); - - // If the size of Keys.bin is correct (two keys), read it - if (size == xbox::XBOX_KEY_LENGTH * 2) { - fread(keys, xbox::XBOX_KEY_LENGTH, 2, fp); - - memcpy(xbox::XboxEEPROMKey, &keys[0], xbox::XBOX_KEY_LENGTH); - memcpy(xbox::XboxCertificateKey, &keys[1], xbox::XBOX_KEY_LENGTH); - } - else { - EmuLog(LOG_LEVEL::WARNING, "Keys.bin has an incorrect filesize. Should be %d bytes", xbox::XBOX_KEY_LENGTH * 2); - } - - fclose(fp); - return; + if (CxbxKrnl_Xbe != nullptr) { + EmuLogInit(LOG_LEVEL::INFO, "Title : %s", CxbxKrnl_Xbe->m_szAsciiTitle); } - // If we didn't already exit the function, keys.bin could not be loaded - EmuLog(LOG_LEVEL::WARNING, "Failed to load Keys.bin. Cxbx-Reloaded will be unable to read Save Data from a real Xbox"); -} + // Dump Xbe certificate + if (g_pCertificate != NULL) { + std::stringstream titleIdHex; + titleIdHex << std::hex << g_pCertificate->dwTitleId; -//TODO: Possible move CxbxResolveHostToFullPath inline function someplace else if become useful elsewhere. -// Let filesystem library clean it up for us, including resolve host's symbolic link path. -// Since internal kernel do translate to full path than preserved host symoblic link path. -static inline void CxbxResolveHostToFullPath(std::filesystem::path& file_path, std::string_view finish_error_sentence) { - std::error_code error; - std::filesystem::path sanityPath = std::filesystem::canonical(file_path, error); - if (error.value() != 0) { - CxbxKrnlCleanupEx(LOG_PREFIX_INIT, "Could not resolve to %s: %s", finish_error_sentence.data(), file_path.string().c_str()); + EmuLogInit(LOG_LEVEL::INFO, "XBE TitleID : %s", FormatTitleId(g_pCertificate->dwTitleId).c_str()); + EmuLogInit(LOG_LEVEL::INFO, "XBE TitleID (Hex) : 0x%s", titleIdHex.str().c_str()); + EmuLogInit(LOG_LEVEL::INFO, "XBE Version : 1.%02d", g_pCertificate->dwVersion); + EmuLogInit(LOG_LEVEL::INFO, "XBE TitleName : %.40ls", g_pCertificate->wsTitleName); + EmuLogInit(LOG_LEVEL::INFO, "XBE Region : %s", CxbxKrnl_Xbe->GameRegionToString()); + } + + // Dump Xbe library build numbers + if (libVersionInfo != NULL) { + for (uint32_t v = 0; v < CxbxKrnl_XbeHeader->dwLibraryVersions; v++) { + EmuLogInit(LOG_LEVEL::INFO, "XBE Library %u : %.8s (version %d)", v, libVersionInfo->szName, libVersionInfo->wBuildVersion); + libVersionInfo++; + } } - file_path = sanityPath; -} -// TODO: Eventually, we should remove this function to start using std::filesystem::path method for all host paths. -static inline void CxbxResolveHostToFullPath(std::string& file_path, std::string_view finish_error_sentence) { - std::filesystem::path sanityPath(file_path); - CxbxResolveHostToFullPath(sanityPath, finish_error_sentence); - file_path = sanityPath.string(); } -__declspec(noreturn) void CxbxKrnlInit +// Process Hacks +static void CxbxrKrnlInitHacks() +{ + int HackEnabled = 0; + g_EmuShared->GetDisablePixelShaders(&HackEnabled); + g_DisablePixelShaders = !!HackEnabled; + g_EmuShared->GetUseAllCores(&HackEnabled); + g_UseAllCores = !!HackEnabled; + g_EmuShared->GetSkipRdtscPatching(&HackEnabled); + g_SkipRdtscPatching = !!HackEnabled; +} + +[[noreturn]] static void CxbxrKrnlInit ( void *pTLSData, Xbe::TLS *pTLS, Xbe::LibraryVersion *pLibraryVersion, - DebugMode DbgMode, - const char *szDebugFilename, Xbe::Header *pXbeHeader, uint32_t dwXbeHeaderSize, void(*Entry)(), @@ -1331,8 +1265,6 @@ __declspec(noreturn) void CxbxKrnlInit CxbxKrnl_TLS = pTLS; CxbxKrnl_TLSData = pTLSData; CxbxKrnl_XbeHeader = pXbeHeader; - CxbxKrnl_DebugMode = DbgMode; - CxbxKrnl_DebugFileName = (char*)szDebugFilename; // A patch to dwCertificateAddr is a requirement due to Windows TLS is overwriting dwGameRegion data address. // By using unalternated certificate data, it should no longer cause any problem with titles running and Cxbx's log as well. @@ -1354,7 +1286,7 @@ __declspec(noreturn) void CxbxKrnlInit { #ifdef _DEBUG_TRACE EmuLogInit(LOG_LEVEL::INFO, "Debug Trace Enabled."); - EmuLogInit(LOG_LEVEL::INFO, "CxbxKrnlInit\n" + EmuLogInit(LOG_LEVEL::INFO, "CxbxrKrnlInit\n" "(\n" " hwndParent : 0x%.08p\n" " pTLSData : 0x%.08p\n" @@ -1366,7 +1298,7 @@ __declspec(noreturn) void CxbxKrnlInit " dwXBEHeaderSize : 0x%.08X\n" " Entry : 0x%.08p\n" ");", - CxbxKrnl_hEmuParent, pTLSData, pTLS, pLibraryVersion, DbgMode, szDebugFilename, pXbeHeader, dwXbeHeaderSize, Entry); + CxbxKrnl_hEmuParent, pTLSData, pTLS, pLibraryVersion, CxbxrKrnl_DebugMode, CxbxrKrnl_DebugFileName.c_str(), pXbeHeader, dwXbeHeaderSize, Entry); #else EmuLogInit(LOG_LEVEL::INFO, "Debug Trace Disabled."); #endif @@ -1375,22 +1307,8 @@ __declspec(noreturn) void CxbxKrnlInit #ifdef _DEBUG_TRACE // VerifyHLEDataBase(); #endif - // TODO : The following seems to cause a crash when booting the game "Forza Motorsport", - // according to https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/issues/101#issuecomment-277230140 - { - // Create a fake kernel header for XapiRestrictCodeSelectorLimit - // Thanks advancingdragon / DirtBox - PDUMMY_KERNEL DummyKernel = (PDUMMY_KERNEL)XBOX_KERNEL_BASE; - memset(DummyKernel, 0, sizeof(DUMMY_KERNEL)); - // XapiRestrictCodeSelectorLimit only checks these fields. - DummyKernel->DosHeader.e_lfanew = sizeof(IMAGE_DOS_HEADER); // RVA of NtHeaders - DummyKernel->FileHeader.SizeOfOptionalHeader = 0; - DummyKernel->FileHeader.NumberOfSections = 1; - // as long as this doesn't start with "INIT" - strncpy_s((PSTR)DummyKernel->SectionHeader.Name, 8, "DONGS", 8); - EmuLogInit(LOG_LEVEL::INFO, "Initialized dummy kernel image header."); - } + CxbxrKrnlSetupDummyHeader(); // Read which components need to be LLE'ed per user request { @@ -1402,36 +1320,11 @@ __declspec(noreturn) void CxbxKrnlInit bLLE_JIT = (CxbxLLE_Flags & LLE_JIT) > 0; } - // Process Hacks - { - int HackEnabled = 0; - g_EmuShared->GetDisablePixelShaders(&HackEnabled); - g_DisablePixelShaders = !!HackEnabled; - g_EmuShared->GetUseAllCores(&HackEnabled); - g_UseAllCores = !!HackEnabled; - g_EmuShared->GetSkipRdtscPatching(&HackEnabled); - g_SkipRdtscPatching = !!HackEnabled; - } + CxbxrKrnlInitHacks(); #ifdef _DEBUG_PRINT_CURRENT_CONF PrintCurrentConfigurationLog(); #endif - - // Initialize devices : - { - char cxbxr_data_path[sizeof(szFilePath_Xbe)]; - g_EmuShared->GetStorageLocation(cxbxr_data_path); - - g_DiskBasePath = std::string(cxbxr_data_path) + "\\EmuDisk"; - g_MuBasePath = std::string(cxbxr_data_path) + "\\EmuMu"; - CxbxResolveHostToFullPath(g_DiskBasePath, "Cxbx-Reloaded's EmuDisk directory"); - CxbxResolveHostToFullPath(g_MuBasePath, "Cxbx-Reloaded's EmuMu directory"); - // Since canonical always remove the extra slash, we need to manually add it back. - // TODO: Once g_DiskBasePath is filesystem::path, replace g_DiskBasePath's + operators to / for include path separator internally. - g_DiskBasePath = std::filesystem::path(g_DiskBasePath).append("").string(); - g_MuBasePath = std::filesystem::path(g_MuBasePath).append("").string(); - // NOTE: Do NOT modify global variables above after this point! - } // Determine xbe path std::filesystem::path xbePath; @@ -1442,72 +1335,15 @@ __declspec(noreturn) void CxbxKrnlInit } CxbxResolveHostToFullPath(xbePath, "xbe's file"); - // Determine location for where possible auto mount D letter if ";" delimiter exist. - // Also used to store in EmuShared's title mount path permanent storage on first emulation launch. - // Unless it's launch within Cxbx-Reloaded's EmuDisk directly, then we don't store anything in title mount path storage. - std::string relative_path(szFilePath_Xbe); - size_t lastFind = relative_path.find(';'); - // First find if there is a semicolon when dashboard or title disc (such as demo disc) has it. - // Then we must obey the current directory it asked for. - if (lastFind != std::string::npos) { - if (relative_path.find(';', lastFind + 1) != std::string::npos) { - CxbxKrnlCleanupEx(LOG_PREFIX_INIT, "Cannot contain multiple of ; symbol."); - } - relative_path = relative_path.substr(0, lastFind); - } - else { - relative_path = relative_path.substr(0, relative_path.find_last_of("\\/")); - } - CxbxResolveHostToFullPath(relative_path, "xbe's directory"); + std::filesystem::path relative_path; + size_t lastFind = CxbxrKrnlGetRelativePath(relative_path); g_DiskBasePathHandle = CreateFile(g_DiskBasePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - int CxbxCdrom0DeviceIndex = -1; + + CxbxrKrnlRegisterDevicePaths(); + bool isEmuDisk = CxbxrIsPathInsideEmuDisk(relative_path); - // Check if title mounth path is already set. This may occur from early boot of Chihiro title. - char title_mount_path[sizeof(szFilePath_Xbe)]; - const char* p_default_mount_path = title_mount_path; - g_EmuShared->GetTitleMountPath(title_mount_path); - - if (p_default_mount_path[0] == '\0' && BootFlags == BOOT_NONE) { - // Remember our first initialize mount path for CdRom0 and Mbfs. - if (!isEmuDisk) { - g_EmuShared->SetTitleMountPath(relative_path.c_str()); - p_default_mount_path = relative_path.c_str(); - } - } - - // TODO: Find a place to make permanent placement for DeviceCdrom0 that does not have disc loaded. - if (p_default_mount_path[0] != '\0') { - // NOTE: Don't need to perform CxbxResolveHostToFullPath again for p_default_mount_path. - CxbxCdrom0DeviceIndex = CxbxRegisterDeviceHostPath(DeviceCdrom0, p_default_mount_path); - // Since Chihiro also map Mbfs to the same path as Cdrom0, we'll map it the same way. - if (g_bIsChihiro) { - (void)CxbxRegisterDeviceHostPath(DriveMbfs, p_default_mount_path); - } - } - - // Partition 0 contains configuration data, and is accessed as a native file, instead as a folder : - CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition0, g_DiskBasePath + "Partition0", /*IsFile=*/true); - // The first two partitions are for Data and Shell files, respectively : - CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition1, g_DiskBasePath + "Partition1"); - CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition2, g_DiskBasePath + "Partition2"); - // The following partitions are for caching purposes - for now we allocate up to 7 (as xbmp needs that many) : - CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition3, g_DiskBasePath + "Partition3"); - CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition4, g_DiskBasePath + "Partition4"); - CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition5, g_DiskBasePath + "Partition5"); - CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition6, g_DiskBasePath + "Partition6"); - CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition7, g_DiskBasePath + "Partition7"); - CxbxRegisterDeviceHostPath(DevicePrefix + "\\Chihiro", g_DiskBasePath + "Chihiro"); - - // Create the MU directories and the bin files - CxbxRegisterDeviceHostPath(DeviceMU0, g_MuBasePath + "F", false, sizeof(FATX_SUPERBLOCK)); - CxbxRegisterDeviceHostPath(DeviceMU1, g_MuBasePath + "G", false, sizeof(FATX_SUPERBLOCK)); - CxbxRegisterDeviceHostPath(DeviceMU2, g_MuBasePath + "H", false, sizeof(FATX_SUPERBLOCK)); - CxbxRegisterDeviceHostPath(DeviceMU3, g_MuBasePath + "I", false, sizeof(FATX_SUPERBLOCK)); - CxbxRegisterDeviceHostPath(DeviceMU4, g_MuBasePath + "J", false, sizeof(FATX_SUPERBLOCK)); - CxbxRegisterDeviceHostPath(DeviceMU5, g_MuBasePath + "K", false, sizeof(FATX_SUPERBLOCK)); - CxbxRegisterDeviceHostPath(DeviceMU6, g_MuBasePath + "L", false, sizeof(FATX_SUPERBLOCK)); - CxbxRegisterDeviceHostPath(DeviceMU7, g_MuBasePath + "M", false, sizeof(FATX_SUPERBLOCK)); + CxbxrKrnlSetupCdRom0Path(BootFlags, lastFind, relative_path, isEmuDisk); std::mbstate_t ps = std::mbstate_t(); const char *src = g_MuBasePath.c_str(); @@ -1515,24 +1351,6 @@ __declspec(noreturn) void CxbxKrnlInit std::mbsrtowcs(wMuBasePath.data(), &src, wMuBasePath.size(), &ps); g_io_mu_metadata = new io_mu_metadata(wMuBasePath); - // Create default symbolic links : - EmuLogInit(LOG_LEVEL::DEBUG, "Creating default symbolic links."); - { - // TODO: DriveD should auto mount based on the launchdata page's ; delimiter in the xbe path. - // This is the only symbolic link the Xbox Kernel sets, the rest are set by the application, usually via XAPI. - // If the Xbe is located outside of the emulated HDD, mounting it as DeviceCdrom0 is correct - // If the Xbe is located inside the emulated HDD, the full path should be used, eg: "\\Harddisk0\\partition2\\xboxdash.xbe" -#ifdef CXBX_KERNEL_REWORK_ENABLED - if (lastFind != std::string::npos) { -#else - // HACK: It is a hack to override XDK's default mount to CdRom0 which may not exist when launch to dashboard directly. - // Otherwise, titles may launch to dashboard, more specifically xbox live title, and back. - if (CxbxCdrom0DeviceIndex == -1 || lastFind != std::string::npos) { -#endif - CxbxCreateSymbolicLink(DriveD, relative_path); - } - } - // Determine Xbox path to XBE and place it in XeImageFileName { std::string fileName; @@ -1581,33 +1399,7 @@ __declspec(noreturn) void CxbxKrnlInit EmuLogInit(LOG_LEVEL::INFO, "XeImageFileName = %s", xbox::XeImageFileName.Buffer); } - // Dump Xbe information - { - if (CxbxKrnl_Xbe != nullptr) { - EmuLogInit(LOG_LEVEL::INFO, "Title : %s", CxbxKrnl_Xbe->m_szAsciiTitle); - } - - // Dump Xbe certificate - if (g_pCertificate != NULL) { - std::stringstream titleIdHex; - titleIdHex << std::hex << g_pCertificate->dwTitleId; - - EmuLogInit(LOG_LEVEL::INFO, "XBE TitleID : %s", FormatTitleId(g_pCertificate->dwTitleId).c_str()); - EmuLogInit(LOG_LEVEL::INFO, "XBE TitleID (Hex) : 0x%s", titleIdHex.str().c_str()); - EmuLogInit(LOG_LEVEL::INFO, "XBE Version : 1.%02d", g_pCertificate->dwVersion); - EmuLogInit(LOG_LEVEL::INFO, "XBE TitleName : %.40ls", g_pCertificate->wsTitleName); - EmuLogInit(LOG_LEVEL::INFO, "XBE Region : %s", CxbxKrnl_Xbe->GameRegionToString()); - } - - // Dump Xbe library build numbers - Xbe::LibraryVersion* libVersionInfo = pLibraryVersion;// (LibraryVersion *)(CxbxKrnl_XbeHeader->dwLibraryVersionsAddr); - if (libVersionInfo != NULL) { - for (uint32_t v = 0; v < CxbxKrnl_XbeHeader->dwLibraryVersions; v++) { - EmuLogInit(LOG_LEVEL::INFO, "XBE Library %u : %.8s (version %d)", v, libVersionInfo->szName, libVersionInfo->wBuildVersion); - libVersionInfo++; - } - } - } + CxbxrLogDumpXbeInfo(pLibraryVersion); CxbxKrnlRegisterThread(GetCurrentThread()); @@ -1699,7 +1491,7 @@ __declspec(noreturn) void CxbxKrnlInit InitXboxThread(); g_AffinityPolicy->SetAffinityXbox(); if (!xbox::ObInitSystem()) { - // TODO: Replace EmuLogEx to CxbxKrnlCleanupEx when ObInitSystem's calls are properly implement. + // TODO: Replace EmuLogEx to CxbxrKrnlAbortEx when ObInitSystem's calls are properly implement. EmuLogEx(LOG_PREFIX_INIT, LOG_LEVEL::WARNING, "Unable to intialize xbox::ObInitSystem."); } xbox::KiInitSystem(); @@ -1734,85 +1526,6 @@ __declspec(noreturn) void CxbxKrnlInit CxbxKrnlTerminateThread(); } -void CxbxInitFilePaths() -{ - if (g_Settings) { - std::string dataLoc = g_Settings->GetDataLocation(); - std::strncpy(szFolder_CxbxReloadedData, dataLoc.c_str(), dataLoc.length() + 1); - } - else { - g_EmuShared->GetStorageLocation(szFolder_CxbxReloadedData); - } - - // Make sure our data folder exists : - bool result = std::filesystem::exists(szFolder_CxbxReloadedData); - if (!result && !std::filesystem::create_directory(szFolder_CxbxReloadedData)) { - CxbxKrnlCleanup("%s : Couldn't create Cxbx-Reloaded's data folder!", __func__); - } - - // Make sure the EmuDisk folder exists - std::string emuDisk = std::string(szFolder_CxbxReloadedData) + std::string("\\EmuDisk"); - result = std::filesystem::exists(emuDisk); - if (!result && !std::filesystem::create_directory(emuDisk)) { - CxbxKrnlCleanup("%s : Couldn't create Cxbx-Reloaded EmuDisk folder!", __func__); - } - - // Make sure the EmuDMu folder exists - std::string emuMu = std::string(szFolder_CxbxReloadedData) + std::string("\\EmuMu"); - result = std::filesystem::exists(emuMu); - if (!result && !std::filesystem::create_directory(emuMu)) { - CxbxKrnlCleanup("%s : Couldn't create Cxbx-Reloaded EmuMu folder!", __func__); - } - - snprintf(szFilePath_EEPROM_bin, MAX_PATH, "%s\\EEPROM.bin", szFolder_CxbxReloadedData); - - GetModuleFileName(GetModuleHandle(nullptr), szFilePath_CxbxReloaded_Exe, MAX_PATH); -} - -HANDLE hMapDataHash = nullptr; - -bool CxbxLockFilePath() -{ - std::stringstream filePathHash("Local\\"); - uint64_t hashValue = XXH3_64bits(szFolder_CxbxReloadedData, strlen(szFolder_CxbxReloadedData) + 1); - if (!hashValue) { - CxbxKrnlCleanup("%s : Couldn't generate Cxbx-Reloaded's data folder hash!", __func__); - } - - filePathHash << std::hex << hashValue; - - hMapDataHash = CreateFileMapping - ( - INVALID_HANDLE_VALUE, // Paging file - nullptr, // default security attributes - PAGE_READONLY, // readonly access - 0, // size: high 32 bits - /*Dummy size*/4, // size: low 32 bits - filePathHash.str().c_str() // name of map object - ); - - if (hMapDataHash == nullptr) { - return false; - } - - if (GetLastError() == ERROR_ALREADY_EXISTS) { - PopupError(nullptr, "Data path directory is currently in use.\nUse a different data path directory or stop emulation from another process."); - CloseHandle(hMapDataHash); - return false; - } - - return true; -} - -void CxbxUnlockFilePath() -{ - // Close opened file path lockdown shared memory. - if (hMapDataHash) { - CloseHandle(hMapDataHash); - hMapDataHash = nullptr; - } -} - // REMARK: the following is useless, but PatrickvL has asked to keep it for documentation purposes /*xbox::LAUNCH_DATA_PAGE DefaultLaunchDataPage = { @@ -1824,7 +1537,7 @@ void CxbxUnlockFilePath() } };*/ -__declspec(noreturn) void CxbxKrnlCleanupEx(CXBXR_MODULE cxbxr_module, const char *szErrorMessage, ...) +[[noreturn]] void CxbxrKrnlAbortEx(CXBXR_MODULE cxbxr_module, const char *szErrorMessage, ...) { g_bEmuException = true; @@ -1992,13 +1705,13 @@ void CxbxKrnlPrintUEM(ULONG ErrorCode) xbox::ExSaveNonVolatileSetting(xbox::XC_MAX_ALL, Type, &Eeprom, sizeof(Eeprom)); } else { - CxbxKrnlCleanup("Could not display the fatal error screen"); + CxbxrKrnlAbort("Could not display the fatal error screen"); } if (g_bIsChihiro) { // The Chihiro doesn't display the UEM - CxbxKrnlCleanup("The running Chihiro xbe has encountered a fatal error and needs to close"); + CxbxrKrnlAbort("The running Chihiro xbe has encountered a fatal error and needs to close"); } g_CxbxFatalErrorCode = ErrorCode; @@ -2046,43 +1759,12 @@ void CxbxPrintUEMInfo(ULONG ErrorCode) } } -__declspec(noreturn) void CxbxKrnlTerminateThread() +[[noreturn]] void CxbxKrnlTerminateThread() { TerminateThread(GetCurrentThread(), 0); } void CxbxKrnlPanic() { - CxbxKrnlCleanup("Kernel Panic!"); -} - -static clock_t g_DeltaTime = 0; // Used for benchmarking/fps count -static unsigned int g_Frames = 0; - -// ****************************************************************** -// * update the current milliseconds per frame -// ****************************************************************** -static void UpdateCurrentMSpFAndFPS() { - if (g_EmuShared) { - static float currentFPSVal = 30; - - currentFPSVal = (float)(g_Frames*0.5 + currentFPSVal * 0.5); - g_EmuShared->SetCurrentFPS(¤tFPSVal); - } -} - -void UpdateFPSCounter() -{ - static clock_t lastDrawFunctionCallTime = 0; - clock_t currentDrawFunctionCallTime = clock(); - - g_DeltaTime += currentDrawFunctionCallTime - lastDrawFunctionCallTime; - lastDrawFunctionCallTime = currentDrawFunctionCallTime; - g_Frames++; - - if (g_DeltaTime >= CLOCKS_PER_SEC) { - UpdateCurrentMSpFAndFPS(); - g_Frames = 0; - g_DeltaTime -= CLOCKS_PER_SEC; - } + CxbxrKrnlAbort("Kernel Panic!"); } diff --git a/src/core/kernel/init/CxbxKrnl.h b/src/core/kernel/init/CxbxKrnl.h index 7d01e4e6a..f22a61fa5 100644 --- a/src/core/kernel/init/CxbxKrnl.h +++ b/src/core/kernel/init/CxbxKrnl.h @@ -146,13 +146,10 @@ bool HandleFirstLaunch(); /*! Cxbx Kernel Entry Point */ void CxbxKrnlEmulate(unsigned int system, blocks_reserved_t blocks_reserved); -/*! initialize emulation */ -__declspec(noreturn) void CxbxKrnlInit(void *pTLSData, Xbe::TLS *pTLS, Xbe::LibraryVersion *LibraryVersion, DebugMode DbgMode, const char *szDebugFilename, Xbe::Header *XbeHeader, uint32_t XbeHeaderSize, void (*Entry)(), int BootFlags); - /*! cleanup emulation */ -__declspec(noreturn) void CxbxKrnlCleanupEx(CXBXR_MODULE cxbxr_module, const char *szErrorMessage, ...); +[[noreturn]] void CxbxrKrnlAbortEx(CXBXR_MODULE cxbxr_module, const char *szErrorMessage, ...); -#define CxbxKrnlCleanup(fmt, ...) CxbxKrnlCleanupEx(LOG_PREFIX, fmt, ##__VA_ARGS__) +#define CxbxrKrnlAbort(fmt, ...) CxbxrKrnlAbortEx(LOG_PREFIX, fmt, ##__VA_ARGS__) /*! register a thread handle */ void CxbxKrnlRegisterThread(HANDLE hThread); @@ -173,7 +170,7 @@ void CxbxKrnlPrintUEM(ULONG ErrorCode); void CxbxPrintUEMInfo(ULONG ErrorCode); /*! terminate the calling thread */ -__declspec(noreturn) void CxbxKrnlTerminateThread(); +[[noreturn]] void CxbxKrnlTerminateThread(); /*! kernel panic (trap for unimplemented kernel functions) */ void CxbxKrnlPanic(); @@ -183,11 +180,7 @@ void CxbxKrnlNoFunc(); void CxbxInitPerformanceCounters(); // Implemented in EmuKrnlKe.cpp -void CxbxInitFilePaths(); - -// For emulation usage only -bool CxbxLockFilePath(); -void CxbxUnlockFilePath(); +void CxbxrInitFilePaths(); bool CxbxIsElevated(); @@ -215,12 +208,10 @@ extern Xbe *CxbxKrnl_Xbe; /*! parent window handle */ extern HWND CxbxKrnl_hEmuParent; -extern DebugMode CxbxKrnl_DebugMode; -extern std::string CxbxKrnl_DebugFileName; /*! file paths */ extern char szFilePath_CxbxReloaded_Exe[MAX_PATH]; -extern char szFolder_CxbxReloadedData[MAX_PATH]; +extern std::string g_DataFilePath; extern char szFilePath_EEPROM_bin[MAX_PATH]; extern char szFilePath_Xbe[xbox::max_path*2]; diff --git a/src/core/kernel/init/KrnlPatches.hpp b/src/core/kernel/init/KrnlPatches.hpp new file mode 100644 index 000000000..3789f659d --- /dev/null +++ b/src/core/kernel/init/KrnlPatches.hpp @@ -0,0 +1,77 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx-Reloaded project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * All rights reserved +// * +// ****************************************************************** +#pragma once + +// NOTE: This file is intended to be used only with Cxbxkrnl.cpp file. +// NOTE2: If need to extern function/variable, please do in Cxbxkrnl.h file. + +static void CxbxrKrnlSetupDummyHeader() { + // TODO : The following seems to cause a crash when booting the game "Forza Motorsport", + // according to https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/issues/101#issuecomment-277230140 + + // Create a fake kernel header for XapiRestrictCodeSelectorLimit + // Thanks advancingdragon / DirtBox + PDUMMY_KERNEL DummyKernel = (PDUMMY_KERNEL)XBOX_KERNEL_BASE; + memset(DummyKernel, 0, sizeof(DUMMY_KERNEL)); + + // XapiRestrictCodeSelectorLimit only checks these fields. + DummyKernel->DosHeader.e_lfanew = sizeof(IMAGE_DOS_HEADER); // RVA of NtHeaders + DummyKernel->FileHeader.SizeOfOptionalHeader = 0; + DummyKernel->FileHeader.NumberOfSections = 1; + // as long as this doesn't start with "INIT" + strncpy_s((PSTR)DummyKernel->SectionHeader.Name, 8, "DONGS", 8); + EmuLogInit(LOG_LEVEL::INFO, "Initialized dummy kernel image header."); +} + +// TODO: If possible, maybe make this as optional patch when kernel emulation is fully done. +static void ApplyMediaPatches() +{ + // Patch the XBE Header to allow running from all media types + g_pCertificate->dwAllowedMedia |= 0 + | XBEIMAGE_MEDIA_TYPE_HARD_DISK + | XBEIMAGE_MEDIA_TYPE_DVD_X2 + | XBEIMAGE_MEDIA_TYPE_DVD_CD + | XBEIMAGE_MEDIA_TYPE_CD + | XBEIMAGE_MEDIA_TYPE_DVD_5_RO + | XBEIMAGE_MEDIA_TYPE_DVD_9_RO + | XBEIMAGE_MEDIA_TYPE_DVD_5_RW + | XBEIMAGE_MEDIA_TYPE_DVD_9_RW + ; + // Patch the XBE Header to allow running on all regions + g_pCertificate->dwGameRegion = 0 + | XBEIMAGE_GAME_REGION_MANUFACTURING + | XBEIMAGE_GAME_REGION_NA + | XBEIMAGE_GAME_REGION_JAPAN + | XBEIMAGE_GAME_REGION_RESTOFWORLD + ; + // Patch the XBE Security Flag + // This field is only present if the Xbe Size is >= than our Certificate Structure + // This works as our structure is large enough to fit the newer certificate size, + // while dwSize is the actual size of the certificate in the Xbe. + // Source: Various Hacked Kernels + if (g_pCertificate->dwSize >= sizeof(Xbe::Certificate)) { + g_pCertificate->dwSecurityFlags &= ~1; + } +} diff --git a/src/core/kernel/memory-manager/PoolManager.cpp b/src/core/kernel/memory-manager/PoolManager.cpp index 5398c37ce..b64eb6fee 100644 --- a/src/core/kernel/memory-manager/PoolManager.cpp +++ b/src/core/kernel/memory-manager/PoolManager.cpp @@ -259,7 +259,7 @@ void PoolManager::DeallocatePool(VAddr addr) assert((Entry->PoolType & POOL_TYPE_MASK) != 0); if (!IS_POOL_HEADER_MARKED_ALLOCATED(Entry)) { - CxbxKrnlCleanup("Pool at address 0x%X is already free!", addr); + CxbxrKrnlAbort("Pool at address 0x%X is already free!", addr); } MARK_POOL_HEADER_FREED(Entry); diff --git a/src/core/kernel/memory-manager/VMManager.cpp b/src/core/kernel/memory-manager/VMManager.cpp index 082e353fb..8927722c0 100644 --- a/src/core/kernel/memory-manager/VMManager.cpp +++ b/src/core/kernel/memory-manager/VMManager.cpp @@ -104,7 +104,7 @@ void VMManager::Initialize(unsigned int SystemType, int BootFlags, blocks_reserv for (int i = 0; i < 64; i++) { LPVOID ret = VirtualAlloc((LPVOID)(PAGE_TABLES_BASE + i * m_AllocationGranularity), m_AllocationGranularity, MEM_COMMIT, PAGE_READWRITE); if (ret != (LPVOID)(PAGE_TABLES_BASE + i * KiB(64))) { - CxbxKrnlCleanup("VirtualAlloc failed to commit the memory for the page tables. The error was 0x%08X", GetLastError()); + CxbxrKrnlAbort("VirtualAlloc failed to commit the memory for the page tables. The error was 0x%08X", GetLastError()); } } @@ -293,14 +293,14 @@ void VMManager::InitializeSystemAllocations() void VMManager::GetPersistentMemory() { if (m_PersistentMemoryHandle != nullptr) { - CxbxKrnlCleanup("Persistent memory is already opened!"); + CxbxrKrnlAbort("Persistent memory is already opened!"); return; } std::string persisted_mem_sid = str_persistent_memory_s + std::to_string(cli_config::GetSessionID()); m_PersistentMemoryHandle = OpenFileMapping(FILE_MAP_READ, FALSE, persisted_mem_sid.c_str()); if (m_PersistentMemoryHandle == nullptr) { - CxbxKrnlCleanup("Couldn't open persistent memory! OpenFileMapping failed with error 0x%08X", GetLastError()); + CxbxrKrnlAbort("Couldn't open persistent memory! OpenFileMapping failed with error 0x%08X", GetLastError()); return; } } @@ -308,13 +308,13 @@ void VMManager::GetPersistentMemory() void VMManager::RestorePersistentMemory() { if (m_PersistentMemoryHandle == nullptr) { - CxbxKrnlCleanup("Persistent memory is not open!"); + CxbxrKrnlAbort("Persistent memory is not open!"); return; } PersistedMemory* persisted_mem = (PersistedMemory*)MapViewOfFile(m_PersistentMemoryHandle, FILE_MAP_READ, 0, 0, 0); if (persisted_mem == nullptr) { - CxbxKrnlCleanup("Couldn't restore persistent memory! MapViewOfFile failed with error 0x%08X", GetLastError()); + CxbxrKrnlAbort("Couldn't restore persistent memory! MapViewOfFile failed with error 0x%08X", GetLastError()); return; } @@ -457,12 +457,12 @@ void VMManager::SavePersistentMemory() std::string persistent_mem_sid = str_persistent_memory_s + std::to_string(cli_config::GetSessionID()); m_PersistentMemoryHandle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, num_persisted_ptes * PAGE_SIZE + num_persisted_ptes * 4 * 2 + sizeof(PersistedMemory), persistent_mem_sid.c_str()); if (m_PersistentMemoryHandle == NULL) { - CxbxKrnlCleanup("Couldn't persist memory! CreateFileMapping failed with error 0x%08X", GetLastError()); + CxbxrKrnlAbort("Couldn't persist memory! CreateFileMapping failed with error 0x%08X", GetLastError()); return; } addr = MapViewOfFile(m_PersistentMemoryHandle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); if (addr == nullptr) { - CxbxKrnlCleanup("Couldn't persist memory! MapViewOfFile failed with error 0x%08X", GetLastError()); + CxbxrKrnlAbort("Couldn't persist memory! MapViewOfFile failed with error 0x%08X", GetLastError()); return; } diff --git a/src/core/kernel/support/Emu.cpp b/src/core/kernel/support/Emu.cpp index 021f975d8..0f31fdea0 100644 --- a/src/core/kernel/support/Emu.cpp +++ b/src/core/kernel/support/Emu.cpp @@ -30,6 +30,7 @@ #include #include "core\kernel\init\CxbxKrnl.h" +#include "core/kernel/support/PatchRdtsc.hpp" #include "Emu.h" #include "devices\x86\EmuX86.h" #include "EmuShared.h" diff --git a/src/core/kernel/support/EmuFile.cpp b/src/core/kernel/support/EmuFile.cpp index 0ca8cb825..bca69a3a3 100644 --- a/src/core/kernel/support/EmuFile.cpp +++ b/src/core/kernel/support/EmuFile.cpp @@ -98,7 +98,7 @@ io_mu_metadata::io_mu_metadata(const std::wstring_view root_path) : m_root_path( std::wstring path = m_root_path + static_cast(L'F' + i) + L".bin"; std::fstream fs(path, std::ios_base::in | std::ios_base::out | std::ios_base::binary); if (!fs.is_open()) { - CxbxKrnlCleanup("%s: could not open MU bin file at \"%ls\"!", __func__, path.c_str()); + CxbxrKrnlAbort("%s: could not open MU bin file at \"%ls\"!", __func__, path.c_str()); } fs.seekg(0); fs.read(m_buff[i], sizeof(FATX_SUPERBLOCK)); @@ -209,7 +209,7 @@ void CxbxCreatePartitionHeaderFile(std::string filename, bool partition0 = false { HANDLE hf = CreateFile(filename.c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); if (!hf) { - CxbxKrnlCleanup("CxbxCreatePartitionHeaderFile Failed\nUnable to create file: %s (%s)", filename.c_str()); + CxbxrKrnlAbort("CxbxCreatePartitionHeaderFile Failed\nUnable to create file: %s (%s)", filename.c_str()); return; } @@ -229,7 +229,7 @@ XboxPartitionTable CxbxGetPartitionTable() XboxPartitionTable table; FILE* fp = fopen((g_DiskBasePath + "Partition0.bin").c_str(), "rb"); if (fp == nullptr) { - CxbxKrnlCleanup("CxbxGetPartitionTable Failed:\nUnable to open file: %s", (g_DiskBasePath + "Partition0.bin").c_str()); + CxbxrKrnlAbort("CxbxGetPartitionTable Failed:\nUnable to open file: %s", (g_DiskBasePath + "Partition0.bin").c_str()); } fread(&table, sizeof(XboxPartitionTable), 1, fp); @@ -267,7 +267,7 @@ std::wstring CxbxGetFinalPathNameByHandle(HANDLE hFile) DWORD size = GetFinalPathNameByHandleW(hFile, path.data(), INITIAL_BUF_SIZE, VOLUME_NAME_DOS); if (size == 0) { - CxbxKrnlCleanup("CxbxGetPartitionNumberFromHandle Failed:\nUnable to determine path for HANDLE 0x%08X", hFile); + CxbxrKrnlAbort("CxbxGetPartitionNumberFromHandle Failed:\nUnable to determine path for HANDLE 0x%08X", hFile); } // If the function fails because lpszFilePath is too small to hold the string plus the terminating null character, @@ -581,7 +581,7 @@ NTSTATUS CxbxConvertFilePath( RelativePath.erase(0, 5); // Remove '$HOME' } else - CxbxKrnlCleanup(("Unsupported path macro : " + OriginalPath).c_str()); + CxbxrKrnlAbort(("Unsupported path macro : " + OriginalPath).c_str()); } // Check if the path starts with a relative path indicator : else if (RelativePath[0] == '.') {// "4x4 Evo 2" needs this @@ -938,7 +938,7 @@ NTSTATUS EmuNtSymbolicLinkObject::Init(std::string aSymbolicLinkName, std::strin if (RootDirectoryHandle == INVALID_HANDLE_VALUE) { result = STATUS_DEVICE_DOES_NOT_EXIST; // TODO : Is this the correct error? - CxbxKrnlCleanup((std::string("Could not map ") + HostSymbolicLinkPath).c_str()); + CxbxrKrnlAbort((std::string("Could not map ") + HostSymbolicLinkPath).c_str()); } else { @@ -1321,7 +1321,7 @@ void CxbxLaunchNewXbe(const std::string& XbePath) { std::string cliCommands; if (!cli_config::GenCMD(cliCommands)) { - CxbxKrnlCleanup("Could not launch %s", XbePath.c_str()); + CxbxrKrnlAbort("Could not launch %s", XbePath.c_str()); } CxbxDebugger::ReportNewTarget(cliCommands.c_str()); @@ -1332,7 +1332,7 @@ void CxbxLaunchNewXbe(const std::string& XbePath) { { if (const auto &err = CxbxExec(false, nullptr, false)) { - CxbxKrnlCleanup("Could not launch %s\n\nThe reason was: %s", XbePath.c_str(), err->c_str()); + CxbxrKrnlAbort("Could not launch %s\n\nThe reason was: %s", XbePath.c_str(), err->c_str()); } } diff --git a/src/core/kernel/support/PatchRdtsc.cpp b/src/core/kernel/support/PatchRdtsc.cpp new file mode 100644 index 000000000..2ac0bcec0 --- /dev/null +++ b/src/core/kernel/support/PatchRdtsc.cpp @@ -0,0 +1,200 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx-Reloaded project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * All rights reserved +// * +// ****************************************************************** + +#define LOG_PREFIX CXBXR_MODULE::CXBXR +#define LOG_PREFIX_INIT CXBXR_MODULE::INIT + +#include +#include +#include + +#include "core\kernel\init\CxbxKrnl.h" + +static std::vector g_RdtscPatches; + +#define OPCODE_PATCH_RDTSC 0x90EF // OUT DX, EAX; NOP + +bool IsRdtscInstruction(xbox::addr_xt addr) +{ + // First the fastest check - does addr contain exact patch from PatchRdtsc? + // Second check - is addr on the rdtsc patch list? + return (*(uint16_t*)addr == OPCODE_PATCH_RDTSC) + // Note : It's not needed to check for g_SkipRdtscPatching, + // as when that's set, the g_RdtscPatches vector will be empty + // anyway, failing this lookup : + && (std::find(g_RdtscPatches.begin(), g_RdtscPatches.end(), addr) != g_RdtscPatches.end()); +} + +static void PatchRdtsc(xbox::addr_xt addr) +{ + // Patch away rdtsc with an opcode we can intercept + // We use a privilaged instruction rather than int 3 for debugging + // When using int 3, attached debuggers trap and rdtsc is used often enough + // that it makes Cxbx-Reloaded unusable + // A privilaged instruction (like OUT) does not suffer from this + EmuLogInit(LOG_LEVEL::DEBUG, "Patching rdtsc opcode at 0x%.8X", (DWORD)addr); + *(uint16_t*)addr = OPCODE_PATCH_RDTSC; + g_RdtscPatches.push_back(addr); +} + +static const uint8_t rdtsc_pattern[] = { + 0x89,//{ 0x0F,0x31,0x89 }, // two false positives in Stranger's Wrath + 0xC3,//{ 0x0F,0x31,0xC3 }, + 0x8B,//{ 0x0F,0x31,0x8B }, // one false positive in Sonic Rider .text 88 5C 0F 31, two false positives in Stranger's Wrath + 0xB9,//{ 0x0F,0x31,0xB9 }, + 0xC7,//{ 0x0F,0x31,0xC7 }, + 0x8D,//{ 0x0F,0x31,0x8D }, + 0x68,//{ 0x0F,0x31,0x68 }, + 0x5A,//{ 0x0F,0x31,0x5A }, + 0x29,//{ 0x0F,0x31,0x29 }, + 0xF3,//{ 0x0F,0x31,0xF3 }, + 0xE9,//{ 0x0F,0x31,0xE9 }, + 0x2B,//{ 0x0F,0x31,0x2B }, + 0x50,//{ 0x0F,0x31,0x50 }, // 0x50 only used in ExaSkeleton .text , but encounter false positive in RalliSport .text 83 E2 0F 31 + 0x0F,//{ 0x0F,0x31,0x0F }, + 0x3B,//{ 0x0F,0x31,0x3B }, + 0xD9,//{ 0x0F,0x31,0xD9 }, + 0x57,//{ 0x0F,0x31,0x57 }, + 0xB9,//{ 0x0F,0x31,0xB9 }, + 0x85,//{ 0x0F,0x31,0x85 }, + 0x83,//{ 0x0F,0x31,0x83 }, + 0x33,//{ 0x0F,0x31,0x33 }, + 0xF7,//{ 0x0F,0x31,0xF7 }, // one false positive in Stranger's Wrath + 0x8A,//{ 0x0F,0x31,0x8A }, // 8A and 56 only apears in RalliSport 2 .text , need to watch whether any future false positive. + 0x56,//{ 0x0F,0x31,0x56 } + 0x6A, // 6A, 39, EB, F6, A1, 01 only appear in Unreal Championship, 01 is at WMVDEC section + 0x39, + 0xEB, + 0xF6, + 0xA1, + 0x01, // one false positive in Group S Challenge [1.05] .text E8 0F 31 01 00 + 0xA3 +}; +static const int sizeof_rdtsc_pattern = sizeof(rdtsc_pattern); + +void PatchRdtscInstructions() +{ + uint8_t rdtsc[2] = { 0x0F, 0x31 }; + + // Iterate through each CODE section + for (uint32_t sectionIndex = 0; sectionIndex < CxbxKrnl_Xbe->m_Header.dwSections; sectionIndex++) { + if (!CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwFlags.bExecutable) { + continue; + } + + // Skip some segments known to never contain rdtsc (to avoid false positives) + if (std::string(CxbxKrnl_Xbe->m_szSectionName[sectionIndex]) == "DSOUND" + || std::string(CxbxKrnl_Xbe->m_szSectionName[sectionIndex]) == "XGRPH" + || std::string(CxbxKrnl_Xbe->m_szSectionName[sectionIndex]) == ".data" + || std::string(CxbxKrnl_Xbe->m_szSectionName[sectionIndex]) == ".rdata" + || std::string(CxbxKrnl_Xbe->m_szSectionName[sectionIndex]) == "XMV" + || std::string(CxbxKrnl_Xbe->m_szSectionName[sectionIndex]) == "XONLINE" + || std::string(CxbxKrnl_Xbe->m_szSectionName[sectionIndex]) == "MDLPL") { + continue; + } + + EmuLogInit(LOG_LEVEL::INFO, "Searching for rdtsc in section %s", CxbxKrnl_Xbe->m_szSectionName[sectionIndex]); + xbox::addr_xt startAddr = CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwVirtualAddr; + //rdtsc is two bytes instruction, it needs at least one opcode byte after it to finish a function, so the endAddr need to substract 3 bytes. + xbox::addr_xt endAddr = startAddr + CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwSizeofRaw - 3; + for (xbox::addr_xt addr = startAddr; addr <= endAddr; addr++) + { + if (memcmp((void*)addr, rdtsc, 2) == 0) + { + uint8_t next_byte = *(uint8_t*)(addr + 2); + // If the following byte matches the known pattern. + int i = 0; + for (i = 0; i < sizeof_rdtsc_pattern; i++) + { + if (next_byte == rdtsc_pattern[i]) + { + if (next_byte == 0x8B) + { + if (*(uint8_t*)(addr - 2) == 0x88 && *(uint8_t*)(addr - 1) == 0x5C) + { + EmuLogInit(LOG_LEVEL::INFO, "Skipped false positive: rdtsc pattern 0x%.2X, @ 0x%.8X", next_byte, (DWORD)addr); + continue; + } + + if (*(uint8_t*)(addr - 2) == 0x24 && *(uint8_t*)(addr - 1) == 0x0C) + { + EmuLogInit(LOG_LEVEL::INFO, "Skipped false positive: rdtsc pattern 0x%.2X, @ 0x%.8X", next_byte, (DWORD)addr); + continue; + } + } + if (next_byte == 0x89) + { + if (*(uint8_t*)(addr + 4) == 0x8B && *(uint8_t*)(addr - 5) == 0x04) + { + EmuLogInit(LOG_LEVEL::INFO, "Skipped false positive: rdtsc pattern 0x%.2X, @ 0x%.8X", next_byte, (DWORD)addr); + continue; + } + + } + if (next_byte == 0x50) + { + if (*(uint8_t*)(addr - 2) == 0x83 && *(uint8_t*)(addr - 1) == 0xE2) + { + EmuLogInit(LOG_LEVEL::INFO, "Skipped false positive: rdtsc pattern 0x%.2X, @ 0x%.8X", next_byte, (DWORD)addr); + continue; + } + + } + if (next_byte == 0x01) + { + if (*(uint8_t*)(addr - 1) == 0xE8 && *(uint8_t*)(addr + 3) == 0x00) + { + EmuLogInit(LOG_LEVEL::INFO, "Skipped false positive: rdtsc pattern 0x%.2X, @ 0x%.8X", next_byte, (DWORD)addr); + continue; + } + + } + if (next_byte == 0xF7) + { + if (*(uint8_t*)(addr - 1) == 0xE8 && *(uint8_t*)(addr + 3) == 0xFF) + { + EmuLogInit(LOG_LEVEL::INFO, "Skipped false positive: rdtsc pattern 0x%.2X, @ 0x%.8X", next_byte, (DWORD)addr); + continue; + } + + } + PatchRdtsc(addr); + //the first for loop already increment addr per loop. we only increment one more time so the addr will point to the byte next to the found rdtsc instruction. this is important since there is at least one case that two rdtsc instructions are next to each other. + addr += 1; + //if a match found, break the pattern matching loop and keep looping addr for next rdtsc. + break; + } + } + if (i >= sizeof_rdtsc_pattern) + { + //no pattern matched, keep record for detections we treat as non-rdtsc for future debugging. + EmuLogInit(LOG_LEVEL::INFO, "Skipped potential rdtsc: Unknown opcode pattern 0x%.2X, @ 0x%.8X", next_byte, (DWORD)addr); + } + } + } + } + + EmuLogInit(LOG_LEVEL::INFO, "Done patching rdtsc, total %d rdtsc instructions patched", g_RdtscPatches.size()); +} diff --git a/src/core/kernel/support/PatchRdtsc.hpp b/src/core/kernel/support/PatchRdtsc.hpp new file mode 100644 index 000000000..488724f46 --- /dev/null +++ b/src/core/kernel/support/PatchRdtsc.hpp @@ -0,0 +1,34 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx-Reloaded project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * All rights reserved +// * +// ****************************************************************** +#pragma once + +#include "core\kernel\exports\xboxkrnl.h" + +// NOTE: This file is intended to be used only with Cxbxkrnl.cpp file. +// NOTE2: If need to include header, please do in Cxbxkrnl.cpp file. + +bool IsRdtscInstruction(xbox::addr_xt addr); + +void PatchRdtscInstructions(); diff --git a/src/devices/usb/OHCI.cpp b/src/devices/usb/OHCI.cpp index b863cad6a..0a5976c5f 100644 --- a/src/devices/usb/OHCI.cpp +++ b/src/devices/usb/OHCI.cpp @@ -335,7 +335,7 @@ void OHCI::OHCI_FrameBoundaryWorker() if (!m_Registers.HcDoneHead) { // From the OHCI standard: "This is set to zero whenever HC writes the content of this // register to HCCA. It also sets the WritebackDoneHead of HcInterruptStatus." - CxbxKrnlCleanup("HcDoneHead is zero but WritebackDoneHead interrupt is not set!\n"); + CxbxrKrnlAbort("HcDoneHead is zero but WritebackDoneHead interrupt is not set!\n"); } if (m_Registers.HcInterrupt & m_Registers.HcInterruptStatus) { @@ -372,7 +372,7 @@ void OHCI::OHCI_FrameBoundaryWorker() void OHCI::OHCI_FatalError() { // According to the standard, an OHCI will stop operating, and set itself into error state - // (which can be queried by MMIO). Instead of calling directly CxbxKrnlCleanup, we let the + // (which can be queried by MMIO). Instead of calling directly CxbxrKrnlAbort, we let the // HCD know the problem so that it can try to solve it OHCI_SetInterrupt(OHCI_INTR_UE); diff --git a/src/devices/usb/USBDevice.cpp b/src/devices/usb/USBDevice.cpp index bf3b99b5c..4073cece0 100644 --- a/src/devices/usb/USBDevice.cpp +++ b/src/devices/usb/USBDevice.cpp @@ -486,7 +486,7 @@ void USBDevice::USB_PacketCopy(USBPacket* p, void* ptr, size_t bytes) IoVecFromBuffer(iov->IoVecStruct, iov->IoVecNumber, p->ActualLength, ptr, bytes); break; default: - CxbxKrnlCleanup("%s has an invalid pid: %x\n", __func__, p->Pid); + CxbxrKrnlAbort("%s has an invalid pid: %x\n", __func__, p->Pid); } p->ActualLength += bytes; } diff --git a/src/devices/video/nv2a.cpp b/src/devices/video/nv2a.cpp index cc7baeeaf..73214a7b1 100644 --- a/src/devices/video/nv2a.cpp +++ b/src/devices/video/nv2a.cpp @@ -1040,7 +1040,6 @@ void cxbx_gl_render_overlays(NV2AState *d) } } -extern void UpdateFPSCounter(); void NV2ADevice::UpdateHostDisplay(NV2AState *d) { PGRAPHState *pg = &d->pgraph; @@ -1096,7 +1095,7 @@ void NV2ADevice::UpdateHostDisplay(NV2AState *d) // glo_set_current(NULL); - UpdateFPSCounter(); + g_renderbase->UpdateFPSCounter(); } // TODO: Fix this properly @@ -1140,7 +1139,7 @@ void CxbxReserveNV2AMemory(NV2AState *d) for (int i = 0; i < 16; i++) { LPVOID ret = VirtualAlloc((LPVOID)(NV2A_ADDR + NV_PRAMIN_ADDR + i * 64 * ONE_KB), 64 * ONE_KB, MEM_COMMIT, PAGE_READWRITE); if (ret != (LPVOID)(NV2A_ADDR + NV_PRAMIN_ADDR + i * 64 * ONE_KB)) { - CxbxKrnlCleanup("VirtualAlloc failed to commit the memory for the nv2a pramin. The error was 0x%08X", GetLastError()); + CxbxrKrnlAbort("VirtualAlloc failed to commit the memory for the nv2a pramin. The error was 0x%08X", GetLastError()); } } diff --git a/src/gui/DlgEepromConfig.cpp b/src/gui/DlgEepromConfig.cpp index 06e56d13c..17bc59d58 100644 --- a/src/gui/DlgEepromConfig.cpp +++ b/src/gui/DlgEepromConfig.cpp @@ -198,7 +198,7 @@ void WriteEepromInMemory(HWND hDlg) // Finally, recalculate the hash and the checksums uint8_t EepromKey[16] = { 0 }; - std::basic_ifstream EepromFile(std::string(szFolder_CxbxReloadedData) + "\\keys.bin", std::ios::binary); + std::basic_ifstream EepromFile(g_DataFilePath + "\\keys.bin", std::ios::binary); if (EepromFile.is_open()) { EepromFile.read(EepromKey, 16); EepromFile.close(); diff --git a/src/gui/WinMain.cpp b/src/gui/WinMain.cpp index 23ea55e40..41b4b20a0 100644 --- a/src/gui/WinMain.cpp +++ b/src/gui/WinMain.cpp @@ -112,9 +112,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine WndMain *MainWindow = new WndMain(hInstance); - // NOTE: CxbxInitFilePaths must be initalize AFTER WndMain for data directory option from user. - /* Initialize Cxbx File Paths */ - CxbxInitFilePaths(); + // NOTE: CxbxrInitFilePaths must be initalize AFTER WndMain for data directory option from user. + /* Initialize Cxbx-Reloaded File Paths */ + CxbxrInitFilePaths(); /*! wait for window to be created, or failure */ while(!MainWindow->isCreated() && MainWindow->ProcessMessages()) diff --git a/src/gui/WndMain.cpp b/src/gui/WndMain.cpp index b1146b69f..479476607 100644 --- a/src/gui/WndMain.cpp +++ b/src/gui/WndMain.cpp @@ -214,8 +214,8 @@ WndMain::WndMain(HINSTANCE x_hInstance) : g_Settings->Verify(); - // NOTE: This is a requirement for pre-verification from GUI. Used in CxbxInitFilePaths function. - g_EmuShared->SetStorageLocation(g_Settings->GetDataLocation().c_str()); + // NOTE: This is a requirement for pre-verification from GUI. Used in CxbxrInitFilePaths function. + g_EmuShared->SetDataLocation(g_Settings->GetDataLocation().c_str()); unsigned int i = 0; do {