// Copyright 2010 Dolphin Emulator Project // Licensed under GPLv2+ // Refer to the license.txt file included. #include #include #include "Common/CommonPaths.h" #include "Common/FileUtil.h" #include "Common/Thread.h" #include "Core/ConfigManager.h" #include "Core/GeckoCode.h" #include "Core/HW/Memmap.h" #include "Core/PowerPC/PowerPC.h" namespace Gecko { static const u32 INSTALLER_BASE_ADDRESS = 0x80001800; static const u32 INSTALLER_END_ADDRESS = 0x80003000; // return true if a code exists bool GeckoCode::Exist(u32 address, u32 data) const { for (const GeckoCode::Code& code : codes) { if (code.address == address && code.data == data) return true; } return false; } // return true if the code is identical bool GeckoCode::Compare(const GeckoCode& compare) const { if (codes.size() != compare.codes.size()) return false; unsigned int exist = 0; for (const GeckoCode::Code& code : codes) { if (compare.Exist(code.address, code.data)) exist++; } return exist == codes.size(); } static bool code_handler_installed = false; // the currently active codes static std::vector active_codes; static std::mutex active_codes_lock; void SetActiveCodes(const std::vector& gcodes) { std::lock_guard lk(active_codes_lock); active_codes.clear(); // add enabled codes for (const GeckoCode& gecko_code : gcodes) { if (gecko_code.enabled) { // TODO: apply modifiers // TODO: don't need description or creator string, just takin up memory active_codes.push_back(gecko_code); } } code_handler_installed = false; } static bool InstallCodeHandler() { std::string data; std::string _rCodeHandlerFilename = File::GetSysDirectory() + GECKO_CODE_HANDLER; if (!File::ReadFileToString(_rCodeHandlerFilename, data)) { NOTICE_LOG(ACTIONREPLAY, "Could not enable cheats because codehandler.bin was missing."); return false; } u8 mmioAddr = 0xCC; if (SConfig::GetInstance().bWii) { mmioAddr = 0xCD; } // Install code handler for (size_t i = 0, e = data.length(); i < e; ++i) PowerPC::HostWrite_U8(data[i], (u32)(INSTALLER_BASE_ADDRESS + i)); // Patch the code handler to the system starting up for (unsigned int h = 0; h < data.length(); h += 4) { // Patch MMIO address if (PowerPC::HostRead_U32(INSTALLER_BASE_ADDRESS + h) == (0x3f000000u | ((mmioAddr ^ 1) << 8))) { NOTICE_LOG(ACTIONREPLAY, "Patching MMIO access at %08x", INSTALLER_BASE_ADDRESS + h); PowerPC::HostWrite_U32(0x3f000000u | mmioAddr << 8, INSTALLER_BASE_ADDRESS + h); } } u32 codelist_base_address = INSTALLER_BASE_ADDRESS + (u32)data.length() - 8; u32 codelist_end_address = INSTALLER_END_ADDRESS; // Write a magic value to 'gameid' (codehandleronly does not actually read this). PowerPC::HostWrite_U32(0xd01f1bad, INSTALLER_BASE_ADDRESS); // Create GCT in memory PowerPC::HostWrite_U32(0x00d0c0de, codelist_base_address); PowerPC::HostWrite_U32(0x00d0c0de, codelist_base_address + 4); std::lock_guard lk(active_codes_lock); int i = 0; for (const GeckoCode& active_code : active_codes) { if (active_code.enabled) { for (const GeckoCode::Code& code : active_code.codes) { // Make sure we have enough memory to hold the code list if ((codelist_base_address + 24 + i) < codelist_end_address) { PowerPC::HostWrite_U32(code.address, codelist_base_address + 8 + i); PowerPC::HostWrite_U32(code.data, codelist_base_address + 12 + i); i += 8; } } } } PowerPC::HostWrite_U32(0xff000000, codelist_base_address + 8 + i); PowerPC::HostWrite_U32(0x00000000, codelist_base_address + 12 + i); // Turn on codes PowerPC::HostWrite_U8(1, INSTALLER_BASE_ADDRESS + 7); // Invalidate the icache and any asm codes for (unsigned int j = 0; j < (INSTALLER_END_ADDRESS - INSTALLER_BASE_ADDRESS); j += 32) { PowerPC::ppcState.iCache.Invalidate(INSTALLER_BASE_ADDRESS + j); } for (unsigned int k = codelist_base_address; k < codelist_end_address; k += 32) { PowerPC::ppcState.iCache.Invalidate(k); } return true; } void RunCodeHandler() { if (SConfig::GetInstance().bEnableCheats && active_codes.size() > 0) { if (!code_handler_installed || PowerPC::HostRead_U32(INSTALLER_BASE_ADDRESS) - 0xd01f1bad > 5) code_handler_installed = InstallCodeHandler(); if (!code_handler_installed) { // A warning was already issued. return; } if (PC == LR) { u32 oldLR = LR; PowerPC::CoreMode oldMode = PowerPC::GetMode(); PC = INSTALLER_BASE_ADDRESS + 0xA8; LR = 0; // Execute the code handler in interpreter mode to track when it exits PowerPC::SetMode(PowerPC::MODE_INTERPRETER); while (PC != 0) PowerPC::SingleStep(); PowerPC::SetMode(oldMode); PC = LR = oldLR; } } } } // namespace Gecko