diff --git a/stratosphere/dmnt/source/dmnt_cheat_manager.cpp b/stratosphere/dmnt/source/dmnt_cheat_manager.cpp index 7f42b2369..274fc973d 100644 --- a/stratosphere/dmnt/source/dmnt_cheat_manager.cpp +++ b/stratosphere/dmnt/source/dmnt_cheat_manager.cpp @@ -14,6 +14,7 @@ * along with this program. If not, see . */ +#include #include #include "dmnt_cheat_manager.hpp" #include "dmnt_cheat_vm.hpp" @@ -32,6 +33,9 @@ static Handle g_cheat_process_debug_hnd = 0; /* Global cheat entry storage. */ static CheatEntry g_cheat_entries[DmntCheatManager::MaxCheatCount]; +/* Global frozen address storage. */ +static std::map g_frozen_addresses_map; + void DmntCheatManager::CloseActiveCheatProcess() { if (g_cheat_process_debug_hnd != 0) { /* Close process resources. */ @@ -42,6 +46,9 @@ void DmntCheatManager::CloseActiveCheatProcess() { /* Clear cheat list. */ ResetAllCheatEntries(); + /* Clear frozen addresses. */ + ResetFrozenAddresses(); + /* Signal to our fans. */ g_cheat_process_event->Signal(); } @@ -186,6 +193,11 @@ Result DmntCheatManager::QueryCheatProcessMemory(MemoryInfo *mapping, u64 addres return ResultDmntCheatNotAttached; } +void DmntCheatManager::ResetFrozenAddresses() { + /* Just clear the map. */ + g_frozen_addresses_map.clear(); +} + void DmntCheatManager::ResetCheatEntry(size_t i) { if (i < DmntCheatManager::MaxCheatCount) { g_cheat_entries[i].enabled = false; @@ -466,6 +478,102 @@ Result DmntCheatManager::RemoveCheat(u32 cheat_id) { return 0; } +Result DmntCheatManager::GetFrozenAddressCount(u64 *out_count) { + std::scoped_lock lk(g_cheat_lock); + + if (!HasActiveCheatProcess()) { + return ResultDmntCheatNotAttached; + } + + *out_count = g_frozen_addresses_map.size(); + return 0; +} + +Result DmntCheatManager::GetFrozenAddresses(FrozenAddressEntry *frz_addrs, size_t max_count, u64 *out_count, u64 offset) { + std::scoped_lock lk(g_cheat_lock); + + if (!HasActiveCheatProcess()) { + return ResultDmntCheatNotAttached; + } + + u64 count = 0; + *out_count = 0; + for (auto const& [address, value] : g_frozen_addresses_map) { + if ((*out_count) >= max_count) { + break; + } + + count++; + if (count > offset) { + const u64 cur_ind = (*out_count)++; + frz_addrs[cur_ind].address = address; + frz_addrs[cur_ind].value = value; + } + } + + return 0; +} + +Result DmntCheatManager::GetFrozenAddress(FrozenAddressEntry *frz_addr, u64 address) { + std::scoped_lock lk(g_cheat_lock); + + if (!HasActiveCheatProcess()) { + return ResultDmntCheatNotAttached; + } + + const auto it = g_frozen_addresses_map.find(address); + if (it == g_frozen_addresses_map.end()) { + return ResultDmntCheatAddressNotFrozen; + } + + frz_addr->address = it->first; + frz_addr->value = it->second; + return 0; +} + +Result DmntCheatManager::EnableFrozenAddress(u64 address, u64 width) { + std::scoped_lock lk(g_cheat_lock); + + if (!HasActiveCheatProcess()) { + return ResultDmntCheatNotAttached; + } + + if (g_frozen_addresses_map.size() >= DmntCheatManager::MaxFrozenAddressCount) { + return ResultDmntCheatTooManyFrozenAddresses; + } + + const auto it = g_frozen_addresses_map.find(address); + if (it != g_frozen_addresses_map.end()) { + return ResultDmntCheatAddressAlreadyFrozen; + } + + Result rc; + FrozenAddressValue value = {0}; + value.width = width; + if (R_FAILED((rc = ReadCheatProcessMemoryForVm(address, &value.value, width)))) { + return rc; + } + + g_frozen_addresses_map[address] = value; + return 0; +} + +Result DmntCheatManager::DisableFrozenAddress(u64 address) { + std::scoped_lock lk(g_cheat_lock); + + if (!HasActiveCheatProcess()) { + return ResultDmntCheatNotAttached; + } + + const auto it = g_frozen_addresses_map.find(address); + if (it == g_frozen_addresses_map.end()) { + return ResultDmntCheatAddressNotFrozen; + } + + g_frozen_addresses_map.erase(address); + return 0; +} + Handle DmntCheatManager::PrepareDebugNextApplication() { Result rc; Handle event_h; @@ -691,6 +799,11 @@ void DmntCheatManager::VmThread(void *arg) { g_cheat_vm->Execute(&g_cheat_process_metadata); } } + + /* Apply frozen addresses. */ + for (auto const& [address, value] : g_frozen_addresses_map) { + WriteCheatProcessMemoryForVm(address, &value.value, value.width); + } } } svcSleepThread(0x5000000ul); diff --git a/stratosphere/dmnt/source/dmnt_cheat_manager.hpp b/stratosphere/dmnt/source/dmnt_cheat_manager.hpp index 2b8a11dcb..37525adb4 100644 --- a/stratosphere/dmnt/source/dmnt_cheat_manager.hpp +++ b/stratosphere/dmnt/source/dmnt_cheat_manager.hpp @@ -23,6 +23,7 @@ class DmntCheatManager { public: static constexpr size_t MaxCheatCount = 0x80; + static constexpr size_t MaxFrozenAddressCount = 0x80; private: static Handle PrepareDebugNextApplication(); static void OnNewApplicationLaunch(); @@ -39,6 +40,8 @@ class DmntCheatManager { static CheatEntry *GetCheatEntryById(size_t i); static bool ParseCheats(const char *cht_txt, size_t len); static bool LoadCheats(u64 title_id, const u8 *build_id); + + static void ResetFrozenAddresses(); public: static bool GetHasActiveCheatProcess(); static Handle GetCheatProcessEventHandle(); @@ -61,5 +64,11 @@ class DmntCheatManager { static Result AddCheat(u32 *out_id, CheatDefinition *def, bool enabled); static Result RemoveCheat(u32 cheat_id); + static Result GetFrozenAddressCount(u64 *out_count); + static Result GetFrozenAddresses(FrozenAddressEntry *frz_addrs, size_t max_count, u64 *out_count, u64 offset); + static Result GetFrozenAddress(FrozenAddressEntry *frz_addr, u64 address); + static Result EnableFrozenAddress(u64 address, u64 width); + static Result DisableFrozenAddress(u64 address); + static void InitializeCheatManager(); }; diff --git a/stratosphere/dmnt/source/dmnt_cheat_service.cpp b/stratosphere/dmnt/source/dmnt_cheat_service.cpp index 69abea9c8..8ccd6266c 100644 --- a/stratosphere/dmnt/source/dmnt_cheat_service.cpp +++ b/stratosphere/dmnt/source/dmnt_cheat_service.cpp @@ -143,16 +143,35 @@ Result DmntCheatService::RemoveCheat(u32 cheat_id) { /* ========================================================================================= */ Result DmntCheatService::GetFrozenAddressCount(Out out_count) { - /* TODO */ - return 0xF601; + return DmntCheatManager::GetFrozenAddressCount(out_count.GetPointer()); } -Result DmntCheatService::GetFrozenAddresses(OutBuffer addresses, Out out_count, u64 offset) { - /* TODO */ - return 0xF601; +Result DmntCheatService::GetFrozenAddresses(OutBuffer frz_addrs, Out out_count, u64 offset) { + if (frz_addrs.buffer == nullptr) { + return ResultDmntCheatNullBuffer; + } + + return DmntCheatManager::GetFrozenAddresses(frz_addrs.buffer, frz_addrs.num_elements, out_count.GetPointer(), offset); } -Result DmntCheatService::ToggleAddressFrozen(uintptr_t address) { - /* TODO */ - return 0xF601; +Result DmntCheatService::GetFrozenAddress(Out entry, u64 address) { + return DmntCheatManager::GetFrozenAddress(entry.GetPointer(), address); +} + +Result DmntCheatService::EnableFrozenAddress(u64 address, u64 width) { + switch (width) { + case 1: + case 2: + case 4: + case 8: + break; + default: + return ResultDmntCheatInvalidFreezeWidth; + } + + return DmntCheatManager::EnableFrozenAddress(address, width); +} + +Result DmntCheatService::DisableFrozenAddress(u64 address) { + return DmntCheatManager::DisableFrozenAddress(address); } diff --git a/stratosphere/dmnt/source/dmnt_cheat_service.hpp b/stratosphere/dmnt/source/dmnt_cheat_service.hpp index a921465a0..abb43d523 100644 --- a/stratosphere/dmnt/source/dmnt_cheat_service.hpp +++ b/stratosphere/dmnt/source/dmnt_cheat_service.hpp @@ -45,7 +45,9 @@ enum DmntCheatCmd { /* Interact with Frozen Addresses */ DmntCheat_Cmd_GetFrozenAddressCount = 65300, DmntCheat_Cmd_GetFrozenAddresses = 65301, - DmntCheat_Cmd_ToggleAddressFrozen = 65302, + DmntCheat_Cmd_GetFrozenAddress = 65302, + DmntCheat_Cmd_EnableFrozenAddress = 65303, + DmntCheat_Cmd_DisableFrozenAddress = 65304, }; class DmntCheatService final : public IServiceObject { @@ -69,8 +71,10 @@ class DmntCheatService final : public IServiceObject { Result RemoveCheat(u32 cheat_id); Result GetFrozenAddressCount(Out out_count); - Result GetFrozenAddresses(OutBuffer addresses, Out out_count, u64 offset); - Result ToggleAddressFrozen(uintptr_t address); + Result GetFrozenAddresses(OutBuffer addresses, Out out_count, u64 offset); + Result GetFrozenAddress(Out entry, u64 address); + Result EnableFrozenAddress(u64 address, u64 width); + Result DisableFrozenAddress(u64 address); public: DEFINE_SERVICE_DISPATCH_TABLE { @@ -94,6 +98,8 @@ class DmntCheatService final : public IServiceObject { MakeServiceCommandMeta(), MakeServiceCommandMeta(), - MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), }; }; diff --git a/stratosphere/dmnt/source/dmnt_cheat_types.hpp b/stratosphere/dmnt/source/dmnt_cheat_types.hpp index 133baf425..830777c86 100644 --- a/stratosphere/dmnt/source/dmnt_cheat_types.hpp +++ b/stratosphere/dmnt/source/dmnt_cheat_types.hpp @@ -45,4 +45,14 @@ struct CheatEntry { bool enabled; uint32_t cheat_id; CheatDefinition definition; +}; + +struct FrozenAddressValue { + u64 value; + u8 width; +}; + +struct FrozenAddressEntry { + u64 address; + FrozenAddressValue value; }; \ No newline at end of file diff --git a/stratosphere/dmnt/source/dmnt_results.hpp b/stratosphere/dmnt/source/dmnt_results.hpp index 752e9de07..f4e908a12 100644 --- a/stratosphere/dmnt/source/dmnt_results.hpp +++ b/stratosphere/dmnt/source/dmnt_results.hpp @@ -28,4 +28,9 @@ static constexpr Result ResultDmntCheatNullBuffer = MAKERESULT(Module_Dmnt, 6 static constexpr Result ResultDmntCheatInvalidBuffer = MAKERESULT(Module_Dmnt, 6502); static constexpr Result ResultDmntCheatUnknownChtId = MAKERESULT(Module_Dmnt, 6503); static constexpr Result ResultDmntCheatOutOfCheats = MAKERESULT(Module_Dmnt, 6504); -static constexpr Result ResultDmntCheatInvalidCheat = MAKERESULT(Module_Dmnt, 6505); \ No newline at end of file +static constexpr Result ResultDmntCheatInvalidCheat = MAKERESULT(Module_Dmnt, 6505); + +static constexpr Result ResultDmntCheatInvalidFreezeWidth = MAKERESULT(Module_Dmnt, 6600); +static constexpr Result ResultDmntCheatAddressAlreadyFrozen = MAKERESULT(Module_Dmnt, 6601); +static constexpr Result ResultDmntCheatAddressNotFrozen = MAKERESULT(Module_Dmnt, 6602); +static constexpr Result ResultDmntCheatTooManyFrozenAddresses = MAKERESULT(Module_Dmnt, 6603); \ No newline at end of file