os: refactor/rewrite entire namespace.

This commit is contained in:
Michael Scire 2020-04-08 02:21:35 -07:00
parent 6193283f03
commit 065485b971
181 changed files with 5353 additions and 1929 deletions

View file

@ -29,18 +29,18 @@ namespace ams::dmnt::cheat::impl {
class CheatProcessManager {
private:
static constexpr size_t ThreadStackSize = 0x4000;
static constexpr int DetectThreadPriority = 39;
static constexpr int VirtualMachineThreadPriority = 48;
static constexpr int DebugEventsThreadPriority = 24;
static constexpr s32 DetectThreadPriority = 11;
static constexpr s32 VirtualMachineThreadPriority = 20;
static constexpr s32 DebugEventsThreadPriority = -1;
private:
os::Mutex cheat_lock;
os::Event debug_events_event; /* Autoclear. */
os::Thread detect_thread, debug_events_thread;
os::ThreadType detect_thread, debug_events_thread;
os::SystemEvent cheat_process_event;
Handle cheat_process_debug_handle = INVALID_HANDLE;
Handle cheat_process_debug_handle = svc::InvalidHandle;
CheatProcessMetadata cheat_process_metadata = {};
os::Thread vm_thread;
os::ThreadType vm_thread;
bool needs_reload_vm = false;
CheatVirtualMachine cheat_vm;
@ -121,13 +121,13 @@ namespace ams::dmnt::cheat::impl {
}
void CloseActiveCheatProcess() {
if (this->cheat_process_debug_handle != INVALID_HANDLE) {
if (this->cheat_process_debug_handle != svc::InvalidHandle) {
/* Knock out the debug events thread. */
R_ABORT_UNLESS(this->debug_events_thread.CancelSynchronization());
os::CancelThreadSynchronization(std::addressof(this->debug_events_thread));
/* Close resources. */
R_ABORT_UNLESS(svcCloseHandle(this->cheat_process_debug_handle));
this->cheat_process_debug_handle = INVALID_HANDLE;
R_ABORT_UNLESS(svc::CloseHandle(this->cheat_process_debug_handle));
this->cheat_process_debug_handle = svc::InvalidHandle;
/* Save cheat toggles. */
if (this->always_save_cheat_toggles || this->should_save_cheat_toggles) {
@ -153,7 +153,7 @@ namespace ams::dmnt::cheat::impl {
bool HasActiveCheatProcess() {
/* Note: This function *MUST* be called only with the cheat lock held. */
os::ProcessId pid;
bool has_cheat_process = this->cheat_process_debug_handle != INVALID_HANDLE;
bool has_cheat_process = this->cheat_process_debug_handle != svc::InvalidHandle;
has_cheat_process &= R_SUCCEEDED(os::TryGetProcessId(&pid, this->cheat_process_debug_handle));
has_cheat_process &= R_SUCCEEDED(pm::dmnt::GetApplicationProcessId(&pid));
has_cheat_process &= (pid == this->cheat_process_metadata.process_id);
@ -175,7 +175,7 @@ namespace ams::dmnt::cheat::impl {
}
Handle HookToCreateApplicationProcess() const {
Handle h = INVALID_HANDLE;
Handle h = svc::InvalidHandle;
R_ABORT_UNLESS(pm::dmnt::HookToCreateApplicationProcess(&h));
return h;
}
@ -185,10 +185,7 @@ namespace ams::dmnt::cheat::impl {
}
public:
CheatProcessManager() {
/* Create cheat process detection event. */
R_ABORT_UNLESS(this->cheat_process_event.InitializeAsInterProcessEvent());
CheatProcessManager() : cheat_lock(false), debug_events_event(os::EventClearMode_AutoClear), cheat_process_event(os::EventClearMode_AutoClear, true) {
/* Learn whether we should enable cheats by default. */
{
u8 en = 0;
@ -203,14 +200,14 @@ namespace ams::dmnt::cheat::impl {
}
/* Spawn application detection thread, spawn cheat vm thread. */
R_ABORT_UNLESS(this->detect_thread.Initialize(&CheatProcessManager::DetectLaunchThread, this, this->detect_thread_stack, ThreadStackSize, DetectThreadPriority));
R_ABORT_UNLESS(this->vm_thread.Initialize(&CheatProcessManager::VirtualMachineThread, this, this->vm_thread_stack, ThreadStackSize, VirtualMachineThreadPriority));
R_ABORT_UNLESS(this->debug_events_thread.Initialize(&CheatProcessManager::DebugEventsThread, this, this->debug_events_thread_stack, ThreadStackSize, DebugEventsThreadPriority));
R_ABORT_UNLESS(os::CreateThread(std::addressof(this->detect_thread), DetectLaunchThread, this, this->detect_thread_stack, ThreadStackSize, DetectThreadPriority));
R_ABORT_UNLESS(os::CreateThread(std::addressof(this->vm_thread), VirtualMachineThread, this, this->vm_thread_stack, ThreadStackSize, VirtualMachineThreadPriority));
R_ABORT_UNLESS(os::CreateThread(std::addressof(this->debug_events_thread), DebugEventsThread, this, this->debug_events_thread_stack, ThreadStackSize, DebugEventsThreadPriority));
/* Start threads. */
R_ABORT_UNLESS(this->detect_thread.Start());
R_ABORT_UNLESS(this->vm_thread.Start());
R_ABORT_UNLESS(this->debug_events_thread.Start());
os::StartThread(std::addressof(this->detect_thread));
os::StartThread(std::addressof(this->vm_thread));
os::StartThread(std::addressof(this->debug_events_thread));
}
bool GetHasActiveCheatProcess() {
@ -620,10 +617,10 @@ namespace ams::dmnt::cheat::impl {
/* Get process handle, use it to learn memory extents. */
{
Handle proc_h = INVALID_HANDLE;
Handle proc_h = svc::InvalidHandle;
ncm::ProgramLocation loc = {};
cfg::OverrideStatus status = {};
ON_SCOPE_EXIT { if (proc_h != INVALID_HANDLE) { R_ABORT_UNLESS(svcCloseHandle(proc_h)); } };
ON_SCOPE_EXIT { if (proc_h != svc::InvalidHandle) { R_ABORT_UNLESS(svcCloseHandle(proc_h)); } };
R_ABORT_UNLESS_IF_NEW_PROCESS(pm::dmnt::AtmosphereGetProcessInfo(&proc_h, &loc, &status, this->cheat_process_metadata.process_id));
this->cheat_process_metadata.program_id = loc.program_id;
@ -988,96 +985,104 @@ namespace ams::dmnt::cheat::impl {
/* Manager global. */
CheatProcessManager g_cheat_process_manager;
TYPED_STORAGE(CheatProcessManager) g_cheat_process_manager;
}
void InitializeCheatManager() {
/* Initialize the debug events manager (spawning its threads). */
InitializeDebugEventsManager();
/* Create the cheat process manager (spawning its threads). */
new (GetPointer(g_cheat_process_manager)) CheatProcessManager;
}
bool GetHasActiveCheatProcess() {
return g_cheat_process_manager.GetHasActiveCheatProcess();
return GetReference(g_cheat_process_manager).GetHasActiveCheatProcess();
}
Handle GetCheatProcessEventHandle() {
return g_cheat_process_manager.GetCheatProcessEventHandle();
return GetReference(g_cheat_process_manager).GetCheatProcessEventHandle();
}
Result GetCheatProcessMetadata(CheatProcessMetadata *out) {
return g_cheat_process_manager.GetCheatProcessMetadata(out);
return GetReference(g_cheat_process_manager).GetCheatProcessMetadata(out);
}
Result ForceOpenCheatProcess() {
return g_cheat_process_manager.ForceOpenCheatProcess();
return GetReference(g_cheat_process_manager).ForceOpenCheatProcess();
}
Result ReadCheatProcessMemoryUnsafe(u64 process_addr, void *out_data, size_t size) {
return g_cheat_process_manager.ReadCheatProcessMemoryUnsafe(process_addr, out_data, size);
return GetReference(g_cheat_process_manager).ReadCheatProcessMemoryUnsafe(process_addr, out_data, size);
}
Result WriteCheatProcessMemoryUnsafe(u64 process_addr, void *data, size_t size) {
return g_cheat_process_manager.WriteCheatProcessMemoryUnsafe(process_addr, data, size);
return GetReference(g_cheat_process_manager).WriteCheatProcessMemoryUnsafe(process_addr, data, size);
}
Result GetCheatProcessMappingCount(u64 *out_count) {
return g_cheat_process_manager.GetCheatProcessMappingCount(out_count);
return GetReference(g_cheat_process_manager).GetCheatProcessMappingCount(out_count);
}
Result GetCheatProcessMappings(MemoryInfo *mappings, size_t max_count, u64 *out_count, u64 offset) {
return g_cheat_process_manager.GetCheatProcessMappings(mappings, max_count, out_count, offset);
return GetReference(g_cheat_process_manager).GetCheatProcessMappings(mappings, max_count, out_count, offset);
}
Result ReadCheatProcessMemory(u64 proc_addr, void *out_data, size_t size) {
return g_cheat_process_manager.ReadCheatProcessMemory(proc_addr, out_data, size);
return GetReference(g_cheat_process_manager).ReadCheatProcessMemory(proc_addr, out_data, size);
}
Result WriteCheatProcessMemory(u64 proc_addr, const void *data, size_t size) {
return g_cheat_process_manager.WriteCheatProcessMemory(proc_addr, data, size);
return GetReference(g_cheat_process_manager).WriteCheatProcessMemory(proc_addr, data, size);
}
Result QueryCheatProcessMemory(MemoryInfo *mapping, u64 address) {
return g_cheat_process_manager.QueryCheatProcessMemory(mapping, address);
return GetReference(g_cheat_process_manager).QueryCheatProcessMemory(mapping, address);
}
Result GetCheatCount(u64 *out_count) {
return g_cheat_process_manager.GetCheatCount(out_count);
return GetReference(g_cheat_process_manager).GetCheatCount(out_count);
}
Result GetCheats(CheatEntry *cheats, size_t max_count, u64 *out_count, u64 offset) {
return g_cheat_process_manager.GetCheats(cheats, max_count, out_count, offset);
return GetReference(g_cheat_process_manager).GetCheats(cheats, max_count, out_count, offset);
}
Result GetCheatById(CheatEntry *out_cheat, u32 cheat_id) {
return g_cheat_process_manager.GetCheatById(out_cheat, cheat_id);
return GetReference(g_cheat_process_manager).GetCheatById(out_cheat, cheat_id);
}
Result ToggleCheat(u32 cheat_id) {
return g_cheat_process_manager.ToggleCheat(cheat_id);
return GetReference(g_cheat_process_manager).ToggleCheat(cheat_id);
}
Result AddCheat(u32 *out_id, const CheatDefinition &def, bool enabled) {
return g_cheat_process_manager.AddCheat(out_id, def, enabled);
return GetReference(g_cheat_process_manager).AddCheat(out_id, def, enabled);
}
Result RemoveCheat(u32 cheat_id) {
return g_cheat_process_manager.RemoveCheat(cheat_id);
return GetReference(g_cheat_process_manager).RemoveCheat(cheat_id);
}
Result GetFrozenAddressCount(u64 *out_count) {
return g_cheat_process_manager.GetFrozenAddressCount(out_count);
return GetReference(g_cheat_process_manager).GetFrozenAddressCount(out_count);
}
Result GetFrozenAddresses(FrozenAddressEntry *frz_addrs, size_t max_count, u64 *out_count, u64 offset) {
return g_cheat_process_manager.GetFrozenAddresses(frz_addrs, max_count, out_count, offset);
return GetReference(g_cheat_process_manager).GetFrozenAddresses(frz_addrs, max_count, out_count, offset);
}
Result GetFrozenAddress(FrozenAddressEntry *frz_addr, u64 address) {
return g_cheat_process_manager.GetFrozenAddress(frz_addr, address);
return GetReference(g_cheat_process_manager).GetFrozenAddress(frz_addr, address);
}
Result EnableFrozenAddress(u64 *out_value, u64 address, u64 width) {
return g_cheat_process_manager.EnableFrozenAddress(out_value, address, width);
return GetReference(g_cheat_process_manager).EnableFrozenAddress(out_value, address, width);
}
Result DisableFrozenAddress(u64 address) {
return g_cheat_process_manager.DisableFrozenAddress(address);
return GetReference(g_cheat_process_manager).DisableFrozenAddress(address);
}
}

View file

@ -18,6 +18,8 @@
namespace ams::dmnt::cheat::impl {
void InitializeCheatManager();
bool GetHasActiveCheatProcess();
Handle GetCheatProcessEventHandle();
Result GetCheatProcessMetadata(CheatProcessMetadata *out);

View file

@ -25,10 +25,11 @@ namespace ams::dmnt::cheat::impl {
public:
static constexpr size_t NumCores = 4;
static constexpr size_t ThreadStackSize = os::MemoryPageSize;
static constexpr size_t ThreadPriority = 24;
static constexpr s32 ThreadPriority = -3;
private:
std::array<uintptr_t, NumCores> message_queue_buffers;
std::array<os::MessageQueue, NumCores> message_queues;
std::array<os::Thread, NumCores> threads;
std::array<os::ThreadType, NumCores> threads;
os::Event continued_event;
alignas(os::MemoryPageSize) u8 thread_stacks[NumCores][ThreadStackSize];
@ -91,16 +92,24 @@ namespace ams::dmnt::cheat::impl {
}
public:
DebugEventsManager() : message_queues{os::MessageQueue(1), os::MessageQueue(1), os::MessageQueue(1), os::MessageQueue(1)}, thread_stacks{} {
DebugEventsManager()
: message_queues{
os::MessageQueue(std::addressof(message_queue_buffers[0]), 1),
os::MessageQueue(std::addressof(message_queue_buffers[1]), 1),
os::MessageQueue(std::addressof(message_queue_buffers[2]), 1),
os::MessageQueue(std::addressof(message_queue_buffers[3]), 1)},
continued_event(os::EventClearMode_AutoClear),
thread_stacks{}
{
for (size_t i = 0; i < NumCores; i++) {
/* Create thread. */
R_ABORT_UNLESS(this->threads[i].Initialize(&DebugEventsManager::PerCoreThreadFunction, reinterpret_cast<void *>(this), this->thread_stacks[i], ThreadStackSize, ThreadPriority, i));
R_ABORT_UNLESS(os::CreateThread(std::addressof(this->threads[i]), PerCoreThreadFunction, this, this->thread_stacks[i], ThreadStackSize, ThreadPriority, i));
/* Set core mask. */
R_ABORT_UNLESS(svcSetThreadCoreMask(this->threads[i].GetHandle(), i, (1u << i)));
os::SetThreadCoreMask(std::addressof(this->threads[i]), i, (1u << i));
/* Start thread. */
R_ABORT_UNLESS(this->threads[i].Start());
os::StartThread(std::addressof(this->threads[i]));
}
}
@ -108,7 +117,7 @@ namespace ams::dmnt::cheat::impl {
/* Loop getting all debug events. */
svc::DebugEventInfo d;
size_t target_core = NumCores - 1;
while (R_SUCCEEDED(svcGetDebugEvent(reinterpret_cast<u8 *>(&d), cheat_dbg_hnd))) {
while (R_SUCCEEDED(svc::GetDebugEvent(std::addressof(d), cheat_dbg_hnd))) {
if (d.type == svc::DebugEvent_AttachThread) {
target_core = GetTargetCore(d, cheat_dbg_hnd);
}
@ -121,12 +130,16 @@ namespace ams::dmnt::cheat::impl {
};
/* Manager global. */
DebugEventsManager g_events_manager;
TYPED_STORAGE(DebugEventsManager) g_events_manager;
}
void InitializeDebugEventsManager() {
new (GetPointer(g_events_manager)) DebugEventsManager;
}
void ContinueCheatProcess(Handle cheat_dbg_hnd) {
g_events_manager.ContinueCheatProcess(cheat_dbg_hnd);
GetReference(g_events_manager).ContinueCheatProcess(cheat_dbg_hnd);
}
}

View file

@ -18,6 +18,8 @@
namespace ams::dmnt::cheat::impl {
void InitializeDebugEventsManager();
void ContinueCheatProcess(Handle cheat_dbg_hnd);
}

View file

@ -15,6 +15,7 @@
*/
#include "dmnt_service.hpp"
#include "cheat/dmnt_cheat_service.hpp"
#include "cheat/impl/dmnt_cheat_api.hpp"
extern "C" {
extern u32 __start__;
@ -122,12 +123,15 @@ namespace {
constexpr size_t ThreadStackSize = 0x4000;
alignas(os::MemoryPageSize) u8 g_extra_thread_stacks[NumExtraThreads][ThreadStackSize];
os::Thread g_extra_threads[NumExtraThreads];
os::ThreadType g_extra_threads[NumExtraThreads];
}
int main(int argc, char **argv)
{
/* Initialize the cheat manager. */
ams::dmnt::cheat::impl::InitializeCheatManager();
/* Create services. */
/* TODO: Implement rest of dmnt:- in ams.tma development branch. */
/* R_ABORT_UNLESS((g_server_manager.RegisterServer<dmnt::cheat::CheatService>(DebugMonitorServiceName, DebugMonitorMaxSessions))); */
@ -139,16 +143,16 @@ int main(int argc, char **argv)
/* Initialize threads. */
if constexpr (NumExtraThreads > 0) {
const s32 priority = os::GetCurrentThreadPriority();
const s32 priority = os::GetThreadCurrentPriority(os::GetCurrentThread());
for (size_t i = 0; i < NumExtraThreads; i++) {
R_ABORT_UNLESS(g_extra_threads[i].Initialize(LoopServerThread, nullptr, g_extra_thread_stacks[i], ThreadStackSize, priority));
R_ABORT_UNLESS(os::CreateThread(std::addressof(g_extra_threads[i]), LoopServerThread, nullptr, g_extra_thread_stacks[i], ThreadStackSize, priority));
}
}
/* Start extra threads. */
if constexpr (NumExtraThreads > 0) {
for (size_t i = 0; i < NumExtraThreads; i++) {
R_ABORT_UNLESS(g_extra_threads[i].Start());
os::StartThread(std::addressof(g_extra_threads[i]));
}
}
@ -158,7 +162,7 @@ int main(int argc, char **argv)
/* Wait for extra threads to finish. */
if constexpr (NumExtraThreads > 0) {
for (size_t i = 0; i < NumExtraThreads; i++) {
R_ABORT_UNLESS(g_extra_threads[i].Join());
os::WaitThread(std::addressof(g_extra_threads[i]));
}
}
}

View file

@ -40,10 +40,10 @@ namespace ams::dmnt {
/* Nintendo uses actual pointers as file handles. We'll add a layer of indirection... */
bool g_sd_initialized = false;
os::Mutex g_sd_lock;
os::Mutex g_sd_lock(false);
FsFileSystem g_sd_fs;
os::Mutex g_file_handle_lock;
os::Mutex g_file_handle_lock(false);
u64 g_cur_fd;
std::unordered_map<TargetIOFileHandle, FsFile> g_file_handles;