dmnt: update for new sf semantics

This commit is contained in:
Michael Scire 2021-01-18 18:43:36 -08:00
parent 2d7a85d14f
commit 88a99bc68e
3 changed files with 191 additions and 71 deletions

View File

@ -16,43 +16,39 @@
#pragma once
#include <stratosphere.hpp>
/* TODO: In libstratosphere, eventually? */
#define AMS_DMNT_I_CHEAT_INTERFACE_INTERFACE_INFO(C, H) \
AMS_SF_METHOD_INFO(C, H, 65000, void, HasCheatProcess, (sf::Out<bool> out), (out)) \
AMS_SF_METHOD_INFO(C, H, 65001, void, GetCheatProcessEvent, (sf::OutCopyHandle out_event), (out_event)) \
AMS_SF_METHOD_INFO(C, H, 65002, Result, GetCheatProcessMetadata, (sf::Out<dmnt::cheat::CheatProcessMetadata> out_metadata), (out_metadata)) \
AMS_SF_METHOD_INFO(C, H, 65003, Result, ForceOpenCheatProcess, (), ()) \
AMS_SF_METHOD_INFO(C, H, 65004, Result, PauseCheatProcess, (), ()) \
AMS_SF_METHOD_INFO(C, H, 65005, Result, ResumeCheatProcess, (), ()) \
AMS_SF_METHOD_INFO(C, H, 65100, Result, GetCheatProcessMappingCount, (sf::Out<u64> out_count), (out_count)) \
AMS_SF_METHOD_INFO(C, H, 65101, Result, GetCheatProcessMappings, (const sf::OutArray<MemoryInfo> &mappings, sf::Out<u64> out_count, u64 offset), (mappings, out_count, offset)) \
AMS_SF_METHOD_INFO(C, H, 65102, Result, ReadCheatProcessMemory, (const sf::OutBuffer &buffer, u64 address, u64 out_size), (buffer, address, out_size)) \
AMS_SF_METHOD_INFO(C, H, 65103, Result, WriteCheatProcessMemory, (const sf::InBuffer &buffer, u64 address, u64 in_size), (buffer, address, in_size)) \
AMS_SF_METHOD_INFO(C, H, 65104, Result, QueryCheatProcessMemory, (sf::Out<MemoryInfo> mapping, u64 address), (mapping, address)) \
AMS_SF_METHOD_INFO(C, H, 65200, Result, GetCheatCount, (sf::Out<u64> out_count), (out_count)) \
AMS_SF_METHOD_INFO(C, H, 65201, Result, GetCheats, (const sf::OutArray<dmnt::cheat::CheatEntry> &cheats, sf::Out<u64> out_count, u64 offset), (cheats, out_count, offset)) \
AMS_SF_METHOD_INFO(C, H, 65202, Result, GetCheatById, (sf::Out<dmnt::cheat::CheatEntry> cheat, u32 cheat_id), (cheat, cheat_id)) \
AMS_SF_METHOD_INFO(C, H, 65203, Result, ToggleCheat, (u32 cheat_id), (cheat_id)) \
AMS_SF_METHOD_INFO(C, H, 65204, Result, AddCheat, (const dmnt::cheat::CheatDefinition &cheat, sf::Out<u32> out_cheat_id, bool enabled), (cheat, out_cheat_id, enabled)) \
AMS_SF_METHOD_INFO(C, H, 65205, Result, RemoveCheat, (u32 cheat_id), (cheat_id)) \
AMS_SF_METHOD_INFO(C, H, 65206, Result, ReadStaticRegister, (sf::Out<u64> out, u8 which), (out, which)) \
AMS_SF_METHOD_INFO(C, H, 65207, Result, WriteStaticRegister, (u8 which, u64 value), (which, value)) \
AMS_SF_METHOD_INFO(C, H, 65208, Result, ResetStaticRegisters, (), ()) \
AMS_SF_METHOD_INFO(C, H, 65300, Result, GetFrozenAddressCount, (sf::Out<u64> out_count), (out_count)) \
AMS_SF_METHOD_INFO(C, H, 65301, Result, GetFrozenAddresses, (const sf::OutArray<dmnt::cheat::FrozenAddressEntry> &addresses, sf::Out<u64> out_count, u64 offset), (addresses, out_count, offset)) \
AMS_SF_METHOD_INFO(C, H, 65302, Result, GetFrozenAddress, (sf::Out<dmnt::cheat::FrozenAddressEntry> entry, u64 address), (entry, address)) \
AMS_SF_METHOD_INFO(C, H, 65303, Result, EnableFrozenAddress, (sf::Out<u64> out_value, u64 address, u64 width), (out_value, address, width)) \
AMS_SF_METHOD_INFO(C, H, 65304, Result, DisableFrozenAddress, (u64 address), (address))
AMS_SF_DEFINE_INTERFACE(ams::dmnt::cheat::impl, ICheatInterface, AMS_DMNT_I_CHEAT_INTERFACE_INTERFACE_INFO)
namespace ams::dmnt::cheat {
/* TODO: In libstratosphere, eventually? */
namespace impl {
#define AMS_DMNT_I_CHEAT_INTERFACE_INTERFACE_INFO(C, H) \
AMS_SF_METHOD_INFO(C, H, 65000, void, HasCheatProcess, (sf::Out<bool> out)) \
AMS_SF_METHOD_INFO(C, H, 65001, void, GetCheatProcessEvent, (sf::OutCopyHandle out_event)) \
AMS_SF_METHOD_INFO(C, H, 65002, Result, GetCheatProcessMetadata, (sf::Out<CheatProcessMetadata> out_metadata)) \
AMS_SF_METHOD_INFO(C, H, 65003, Result, ForceOpenCheatProcess, ()) \
AMS_SF_METHOD_INFO(C, H, 65004, Result, PauseCheatProcess, ()) \
AMS_SF_METHOD_INFO(C, H, 65005, Result, ResumeCheatProcess, ()) \
AMS_SF_METHOD_INFO(C, H, 65100, Result, GetCheatProcessMappingCount, (sf::Out<u64> out_count)) \
AMS_SF_METHOD_INFO(C, H, 65101, Result, GetCheatProcessMappings, (const sf::OutArray<MemoryInfo> &mappings, sf::Out<u64> out_count, u64 offset)) \
AMS_SF_METHOD_INFO(C, H, 65102, Result, ReadCheatProcessMemory, (const sf::OutBuffer &buffer, u64 address, u64 out_size)) \
AMS_SF_METHOD_INFO(C, H, 65103, Result, WriteCheatProcessMemory, (const sf::InBuffer &buffer, u64 address, u64 in_size)) \
AMS_SF_METHOD_INFO(C, H, 65104, Result, QueryCheatProcessMemory, (sf::Out<MemoryInfo> mapping, u64 address)) \
AMS_SF_METHOD_INFO(C, H, 65200, Result, GetCheatCount, (sf::Out<u64> out_count)) \
AMS_SF_METHOD_INFO(C, H, 65201, Result, GetCheats, (const sf::OutArray<CheatEntry> &cheats, sf::Out<u64> out_count, u64 offset)) \
AMS_SF_METHOD_INFO(C, H, 65202, Result, GetCheatById, (sf::Out<CheatEntry> cheat, u32 cheat_id)) \
AMS_SF_METHOD_INFO(C, H, 65203, Result, ToggleCheat, (u32 cheat_id)) \
AMS_SF_METHOD_INFO(C, H, 65204, Result, AddCheat, (const CheatDefinition &cheat, sf::Out<u32> out_cheat_id, bool enabled)) \
AMS_SF_METHOD_INFO(C, H, 65205, Result, RemoveCheat, (u32 cheat_id)) \
AMS_SF_METHOD_INFO(C, H, 65206, Result, ReadStaticRegister, (sf::Out<u64> out, u8 which)) \
AMS_SF_METHOD_INFO(C, H, 65207, Result, WriteStaticRegister, (u8 which, u64 value)) \
AMS_SF_METHOD_INFO(C, H, 65208, Result, ResetStaticRegisters, ()) \
AMS_SF_METHOD_INFO(C, H, 65300, Result, GetFrozenAddressCount, (sf::Out<u64> out_count)) \
AMS_SF_METHOD_INFO(C, H, 65301, Result, GetFrozenAddresses, (const sf::OutArray<FrozenAddressEntry> &addresses, sf::Out<u64> out_count, u64 offset)) \
AMS_SF_METHOD_INFO(C, H, 65302, Result, GetFrozenAddress, (sf::Out<FrozenAddressEntry> entry, u64 address)) \
AMS_SF_METHOD_INFO(C, H, 65303, Result, EnableFrozenAddress, (sf::Out<u64> out_value, u64 address, u64 width)) \
AMS_SF_METHOD_INFO(C, H, 65304, Result, DisableFrozenAddress, (u64 address))
AMS_SF_DEFINE_INTERFACE(ICheatInterface, AMS_DMNT_I_CHEAT_INTERFACE_INTERFACE_INFO)
}
class CheatService final {
class CheatService {
public:
void HasCheatProcess(sf::Out<bool> out);
void GetCheatProcessEvent(sf::OutCopyHandle out_event);

View File

@ -26,6 +26,58 @@ namespace ams::dmnt::cheat::impl {
constexpr size_t MaxCheatCount = 0x80;
constexpr size_t MaxFrozenAddressCount = 0x80;
class FrozenAddressMapEntry : public util::IntrusiveRedBlackTreeBaseNode<FrozenAddressMapEntry> {
public:
using LightCompareType = u64;
private:
u64 m_address;
FrozenAddressValue m_value;
public:
constexpr FrozenAddressMapEntry(u64 address, FrozenAddressValue value) : m_address(address), m_value(value) { /* ... */ }
constexpr u64 GetAddress() const { return m_address; }
constexpr const FrozenAddressValue &GetValue() const { return m_value; }
constexpr FrozenAddressValue &GetValue() { return m_value; }
static constexpr ALWAYS_INLINE int Compare(const LightCompareType &lval, const FrozenAddressMapEntry &rhs) {
const auto rval = rhs.GetAddress();
if (lval < rval) {
return -1;
} else if (lval == rval) {
return 0;
} else {
return 1;
}
}
static constexpr ALWAYS_INLINE int Compare(const FrozenAddressMapEntry &lhs, const FrozenAddressMapEntry &rhs) {
return Compare(lhs.GetAddress(), rhs);
}
};
constinit os::SdkMutex g_text_file_buffer_lock;
constinit char g_text_file_buffer[64_KB];
constinit u8 g_frozen_address_map_memory[sizeof(FrozenAddressMapEntry) * MaxFrozenAddressCount];
constinit lmem::HeapHandle g_frozen_address_map_heap;
FrozenAddressMapEntry *AllocateFrozenAddress(u64 address, FrozenAddressValue value) {
FrozenAddressMapEntry *entry = static_cast<FrozenAddressMapEntry *>(lmem::AllocateFromUnitHeap(g_frozen_address_map_heap));
if (entry != nullptr) {
new (entry) FrozenAddressMapEntry(address, value);
}
return entry;
}
void DeallocateFrozenAddress(FrozenAddressMapEntry *entry) {
entry->~FrozenAddressMapEntry();
lmem::FreeToUnitHeap(g_frozen_address_map_heap, entry);
}
using FrozenAddressMap = typename util::IntrusiveRedBlackTreeBaseTraits<FrozenAddressMapEntry>::TreeType<FrozenAddressMapEntry>;
/* Manager class. */
class CheatProcessManager {
private:
@ -48,7 +100,7 @@ namespace ams::dmnt::cheat::impl {
bool always_save_cheat_toggles = false;
bool should_save_cheat_toggles = false;
CheatEntry cheat_entries[MaxCheatCount] = {};
std::map<u64, FrozenAddressValue> frozen_addresses_map;
FrozenAddressMap frozen_addresses_map = {};
alignas(os::MemoryPageSize) u8 detect_thread_stack[ThreadStackSize] = {};
alignas(os::MemoryPageSize) u8 debug_events_thread_stack[ThreadStackSize] = {};
@ -149,7 +201,14 @@ namespace ams::dmnt::cheat::impl {
this->ResetAllCheatEntries();
/* Clear frozen addresses. */
this->frozen_addresses_map.clear();
{
auto it = this->frozen_addresses_map.begin();
while (it != this->frozen_addresses_map.end()) {
FrozenAddressMapEntry *entry = std::addressof(*it);
it = this->frozen_addresses_map.erase(it);
DeallocateFrozenAddress(entry);
}
}
/* Signal to our fans. */
this->cheat_process_event.Signal();
@ -249,7 +308,11 @@ namespace ams::dmnt::cheat::impl {
Result WriteCheatProcessMemoryUnsafe(u64 proc_addr, const void *data, size_t size) {
R_TRY(svcWriteDebugProcessMemory(this->GetCheatProcessHandle(), data, proc_addr, size));
for (auto& [address, value] : this->frozen_addresses_map) {
for (auto &entry : this->frozen_addresses_map) {
/* Get address/value. */
const u64 address = entry.GetAddress();
auto &value = entry.GetValue();
/* Map is ordered, so break when we can. */
if (address >= proc_addr + size) {
break;
@ -508,7 +571,7 @@ namespace ams::dmnt::cheat::impl {
R_TRY(this->EnsureCheatProcess());
*out_count = this->frozen_addresses_map.size();
*out_count = std::distance(this->frozen_addresses_map.begin(), this->frozen_addresses_map.end());
return ResultSuccess();
}
@ -518,14 +581,14 @@ namespace ams::dmnt::cheat::impl {
R_TRY(this->EnsureCheatProcess());
u64 total_count = 0, written_count = 0;
for (auto const& [address, value] : this->frozen_addresses_map) {
for (const auto &entry : this->frozen_addresses_map) {
if (written_count >= max_count) {
break;
}
if (offset <= total_count) {
frz_addrs[written_count].address = address;
frz_addrs[written_count].value = value;
frz_addrs[written_count].address = entry.GetAddress();
frz_addrs[written_count].value = entry.GetValue();
written_count++;
}
total_count++;
@ -540,11 +603,11 @@ namespace ams::dmnt::cheat::impl {
R_TRY(this->EnsureCheatProcess());
const auto it = this->frozen_addresses_map.find(address);
const auto it = this->frozen_addresses_map.find_light(address);
R_UNLESS(it != this->frozen_addresses_map.end(), ResultFrozenAddressNotFound());
frz_addr->address = it->first;
frz_addr->value = it->second;
frz_addr->address = it->GetAddress();
frz_addr->value = it->GetValue();
return ResultSuccess();
}
@ -553,16 +616,17 @@ namespace ams::dmnt::cheat::impl {
R_TRY(this->EnsureCheatProcess());
R_UNLESS(this->frozen_addresses_map.size() < MaxFrozenAddressCount, ResultFrozenAddressOutOfResource());
const auto it = this->frozen_addresses_map.find(address);
const auto it = this->frozen_addresses_map.find_light(address);
R_UNLESS(it == this->frozen_addresses_map.end(), ResultFrozenAddressAlreadyExists());
FrozenAddressValue value = {};
value.width = width;
R_TRY(this->ReadCheatProcessMemoryUnsafe(address, &value.value, width));
this->frozen_addresses_map[address] = value;
FrozenAddressMapEntry *entry = AllocateFrozenAddress(address, value);
R_UNLESS(entry != nullptr, ResultFrozenAddressOutOfResource());
this->frozen_addresses_map.insert(*entry);
*out_value = value.value;
return ResultSuccess();
}
@ -572,10 +636,13 @@ namespace ams::dmnt::cheat::impl {
R_TRY(this->EnsureCheatProcess());
const auto it = this->frozen_addresses_map.find(address);
const auto it = this->frozen_addresses_map.find_light(address);
R_UNLESS(it != this->frozen_addresses_map.end(), ResultFrozenAddressNotFound());
FrozenAddressMapEntry *entry = std::addressof(*it);
this->frozen_addresses_map.erase(it);
DeallocateFrozenAddress(entry);
return ResultSuccess();
}
@ -659,7 +726,10 @@ namespace ams::dmnt::cheat::impl {
}
/* Apply frozen addresses. */
for (auto const& [address, value] : this_ptr->frozen_addresses_map) {
for (const auto &entry : this_ptr->frozen_addresses_map) {
const auto address = entry.GetAddress();
const auto &value = entry.GetValue();
/* Use Write SVC directly, to avoid the usual frozen address update logic. */
svcWriteDebugProcessMemory(this_ptr->GetCheatProcessHandle(), &value.value, address, value.width);
}
@ -983,22 +1053,20 @@ namespace ams::dmnt::cheat::impl {
if (R_FAILED(fs::GetFileSize(std::addressof(file_size), file))) {
return false;
}
/* Allocate cheat txt buffer. */
char *cht_txt = static_cast<char *>(std::malloc(file_size + 1));
if (cht_txt == nullptr) {
if (file_size < 0 || file_size >= static_cast<s64>(sizeof(g_text_file_buffer))) {
return false;
}
ON_SCOPE_EXIT { std::free(cht_txt); };
std::scoped_lock lk(g_text_file_buffer_lock);
/* Read cheats into buffer. */
if (R_FAILED(fs::ReadFile(file, 0, cht_txt, file_size))) {
if (R_FAILED(fs::ReadFile(file, 0, g_text_file_buffer, file_size))) {
return false;
}
cht_txt[file_size] = '\x00';
g_text_file_buffer[file_size] = '\x00';
/* Parse cheat buffer. */
return this->ParseCheats(cht_txt, std::strlen(cht_txt));
return this->ParseCheats(g_text_file_buffer, std::strlen(g_text_file_buffer));
}
bool CheatProcessManager::LoadCheatToggles(const ncm::ProgramId program_id) {
@ -1022,22 +1090,20 @@ namespace ams::dmnt::cheat::impl {
if (R_FAILED(fs::GetFileSize(std::addressof(file_size), file))) {
return false;
}
/* Allocate toggle txt buffer. */
char *tg_txt = static_cast<char *>(std::malloc(file_size + 1));
if (tg_txt == nullptr) {
if (file_size < 0 || file_size >= static_cast<s64>(sizeof(g_text_file_buffer))) {
return false;
}
ON_SCOPE_EXIT { std::free(tg_txt); };
std::scoped_lock lk(g_text_file_buffer_lock);
/* Read cheats into buffer. */
if (R_FAILED(fs::ReadFile(file, 0, tg_txt, file_size))) {
if (R_FAILED(fs::ReadFile(file, 0, g_text_file_buffer, file_size))) {
return false;
}
tg_txt[file_size] = '\x00';
g_text_file_buffer[file_size] = '\x00';
/* Parse toggle buffer. */
this->should_save_cheat_toggles = this->ParseCheatToggles(tg_txt, std::strlen(tg_txt));
this->should_save_cheat_toggles = this->ParseCheatToggles(g_text_file_buffer, std::strlen(g_text_file_buffer));
return this->should_save_cheat_toggles;
}
@ -1086,6 +1152,9 @@ namespace ams::dmnt::cheat::impl {
/* Initialize the debug events manager (spawning its threads). */
InitializeDebugEventsManager();
/* Initialize the frozen address map heap. */
g_frozen_address_map_heap = lmem::CreateUnitHeap(g_frozen_address_map_memory, sizeof(g_frozen_address_map_memory), sizeof(FrozenAddressMapEntry), lmem::CreateOption_ThreadSafe);
/* Create the cheat process manager (spawning its threads). */
new (GetPointer(g_cheat_process_manager)) CheatProcessManager;
}

View File

@ -24,14 +24,16 @@ extern "C" {
u32 __nx_applet_type = AppletType_None;
u32 __nx_fs_num_sessions = 1;
/* TODO: Evaluate how much this can be reduced by. */
#define INNER_HEAP_SIZE 0x20000
#define INNER_HEAP_SIZE 0x0
size_t nx_inner_heap_size = INNER_HEAP_SIZE;
char nx_inner_heap[INNER_HEAP_SIZE];
void __libnx_initheap(void);
void __appInit(void);
void __appExit(void);
void *__libnx_thread_alloc(size_t size);
void __libnx_thread_free(void *mem);
}
namespace ams {
@ -60,9 +62,32 @@ void __libnx_initheap(void) {
fake_heap_end = (char*)addr + size;
}
namespace {
constinit u8 g_fs_heap_memory[4_KB];
lmem::HeapHandle g_fs_heap_handle;
void *AllocateForFs(size_t size) {
return lmem::AllocateFromExpHeap(g_fs_heap_handle, size);
}
void DeallocateForFs(void *p, size_t size) {
return lmem::FreeToExpHeap(g_fs_heap_handle, p);
}
void InitializeFsHeap() {
g_fs_heap_handle = lmem::CreateExpHeap(g_fs_heap_memory, sizeof(g_fs_heap_memory), lmem::CreateOption_None);
}
}
void __appInit(void) {
hos::InitializeForStratosphere();
InitializeFsHeap();
fs::SetAllocator(AllocateForFs, DeallocateForFs);
sm::DoWithSession([&]() {
R_ABORT_UNLESS(pmdmntInitialize());
R_ABORT_UNLESS(pminfoInitialize());
@ -114,6 +139,8 @@ namespace {
sf::hipc::ServerManager<NumServers, ServerOptions, NumSessions> g_server_manager;
constinit sf::UnmanagedServiceObject<dmnt::cheat::impl::ICheatInterface, dmnt::cheat::CheatService> g_cheat_service;
void LoopServerThread(void *arg) {
g_server_manager.LoopProcess();
}
@ -128,6 +155,34 @@ namespace {
}
namespace ams {
void *Malloc(size_t size) {
AMS_ABORT("ams::Malloc was called");
}
void Free(void *ptr) {
AMS_ABORT("ams::Free was called");
}
}
void *operator new(size_t size) {
AMS_ABORT("operator new(size_t) was called");
}
void operator delete(void *p) {
AMS_ABORT("operator delete(void *) was called");
}
void *__libnx_thread_alloc(size_t size) {
AMS_ABORT("__libnx_thread_alloc was called");
}
void __libnx_thread_free(void *mem) {
AMS_ABORT("__libnx_thread_free was called");
}
int main(int argc, char **argv)
{
/* Set thread name. */
@ -139,8 +194,8 @@ int main(int argc, char **argv)
/* Create services. */
/* TODO: Implement rest of dmnt:- in ams.tma development branch. */
/* R_ABORT_UNLESS((g_server_manager.RegisterServer<dmnt::cheat::CheatService>(DebugMonitorServiceName, DebugMonitorMaxSessions))); */
R_ABORT_UNLESS((g_server_manager.RegisterServer<dmnt::cheat::impl::ICheatInterface, dmnt::cheat::CheatService>(CheatServiceName, CheatMaxSessions)));
/* TODO: register debug service */
R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_cheat_service.GetShared(), CheatServiceName, CheatMaxSessions));
/* Loop forever, servicing our services. */
/* Nintendo loops four threads processing on the manager -- we'll loop an extra fifth for our cheat service. */