mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-29 23:32:23 +00:00
dmnt-cheat: workaround for 6.0.0+ kernel bug.
This commit is contained in:
parent
b6d3df3335
commit
aac64b1ded
2 changed files with 58 additions and 24 deletions
|
@ -34,7 +34,7 @@ static Handle g_cheat_process_debug_hnd = 0;
|
||||||
static bool g_enable_cheats_by_default = true;
|
static bool g_enable_cheats_by_default = true;
|
||||||
|
|
||||||
/* For debug event thread management. */
|
/* For debug event thread management. */
|
||||||
static HosMutex g_debug_event_thread_lock;
|
static HosMutex g_debug_event_thread_lock, g_attach_lock;
|
||||||
static bool g_has_debug_events_thread = false;
|
static bool g_has_debug_events_thread = false;
|
||||||
|
|
||||||
/* To save some copying. */
|
/* To save some copying. */
|
||||||
|
@ -46,6 +46,10 @@ static CheatEntry g_cheat_entries[DmntCheatManager::MaxCheatCount];
|
||||||
/* Global frozen address storage. */
|
/* Global frozen address storage. */
|
||||||
static std::map<u64, FrozenAddressValue> g_frozen_addresses_map;
|
static std::map<u64, FrozenAddressValue> g_frozen_addresses_map;
|
||||||
|
|
||||||
|
/* WORKAROUND: These prevent a kernel deadlock from occurring on 6.0.0+ */
|
||||||
|
static HosThread g_workaround_threads[4];
|
||||||
|
static void KernelWorkaroundThreadFunc(void *arg) { svcSleepThread(INT64_MAX); }
|
||||||
|
|
||||||
void DmntCheatManager::StartDebugEventsThread() {
|
void DmntCheatManager::StartDebugEventsThread() {
|
||||||
std::scoped_lock<HosMutex> lk(g_debug_event_thread_lock);
|
std::scoped_lock<HosMutex> lk(g_debug_event_thread_lock);
|
||||||
|
|
||||||
|
@ -119,20 +123,18 @@ bool DmntCheatManager::HasActiveCheatProcess() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DmntCheatManager::ContinueCheatProcess() {
|
void DmntCheatManager::ContinueCheatProcess() {
|
||||||
if (HasActiveCheatProcess()) {
|
|
||||||
/* Loop getting debug events. */
|
/* Loop getting debug events. */
|
||||||
u64 debug_event_buf[0x50];
|
u8 debug_event_buf[0x50];
|
||||||
while (R_SUCCEEDED(svcGetDebugEvent((u8 *)debug_event_buf, g_cheat_process_debug_hnd))) {
|
while (R_SUCCEEDED(svcGetDebugEvent((u8 *)debug_event_buf, g_cheat_process_debug_hnd))) {
|
||||||
/* ... */
|
/* ... */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Continue the process. */
|
/* Continue the process, if needed. */
|
||||||
if (kernelAbove300()) {
|
if (kernelAbove300()) {
|
||||||
svcContinueDebugEvent(g_cheat_process_debug_hnd, 5, nullptr, 0);
|
svcContinueDebugEvent(g_cheat_process_debug_hnd, 5, nullptr, 0);
|
||||||
} else {
|
} else {
|
||||||
svcLegacyContinueDebugEvent(g_cheat_process_debug_hnd, 5, 0);
|
svcLegacyContinueDebugEvent(g_cheat_process_debug_hnd, 5, 0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DmntCheatManager::ReadCheatProcessMemoryForVm(u64 proc_addr, void *out_data, size_t size) {
|
Result DmntCheatManager::ReadCheatProcessMemoryForVm(u64 proc_addr, void *out_data, size_t size) {
|
||||||
|
@ -690,18 +692,28 @@ static void StartDebugProcess(u64 pid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DmntCheatManager::ForceOpenCheatProcess() {
|
Result DmntCheatManager::ForceOpenCheatProcess() {
|
||||||
std::scoped_lock<HosMutex> lk(g_cheat_lock);
|
std::scoped_lock<HosMutex> attach_lk(g_attach_lock);
|
||||||
Result rc;
|
Result rc;
|
||||||
|
|
||||||
|
/* Acquire the cheat lock for long enough to close the process if needed. */
|
||||||
|
{
|
||||||
|
std::scoped_lock<HosMutex> lk(g_cheat_lock);
|
||||||
|
|
||||||
if (HasActiveCheatProcess()) {
|
if (HasActiveCheatProcess()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Close the current application, if it's open. */
|
/* Close the current application, if it's open. */
|
||||||
CloseActiveCheatProcess();
|
CloseActiveCheatProcess();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Intentionally yield the cheat lock to the debug events thread. */
|
||||||
/* Wait to not have debug events thread. */
|
/* Wait to not have debug events thread. */
|
||||||
WaitDebugEventsThread();
|
WaitDebugEventsThread();
|
||||||
|
|
||||||
|
/* At this point, we can re-acquire the lock for the rest of the function. */
|
||||||
|
std::scoped_lock<HosMutex> lk(g_cheat_lock);
|
||||||
|
|
||||||
/* Get the current application process ID. */
|
/* Get the current application process ID. */
|
||||||
if (R_FAILED((rc = pmdmntGetApplicationPid(&g_cheat_process_metadata.process_id)))) {
|
if (R_FAILED((rc = pmdmntGetApplicationPid(&g_cheat_process_metadata.process_id)))) {
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -762,7 +774,6 @@ Result DmntCheatManager::ForceOpenCheatProcess() {
|
||||||
if (R_FAILED((rc = svcDebugActiveProcess(&g_cheat_process_debug_hnd, g_cheat_process_metadata.process_id)))) {
|
if (R_FAILED((rc = svcDebugActiveProcess(&g_cheat_process_debug_hnd, g_cheat_process_metadata.process_id)))) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start debug events thread. */
|
/* Start debug events thread. */
|
||||||
StartDebugEventsThread();
|
StartDebugEventsThread();
|
||||||
|
|
||||||
|
@ -773,15 +784,22 @@ Result DmntCheatManager::ForceOpenCheatProcess() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DmntCheatManager::OnNewApplicationLaunch() {
|
void DmntCheatManager::OnNewApplicationLaunch() {
|
||||||
std::scoped_lock<HosMutex> lk(g_cheat_lock);
|
std::scoped_lock<HosMutex> attach_lk(g_attach_lock);
|
||||||
Result rc;
|
Result rc;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::scoped_lock<HosMutex> lk(g_cheat_lock);
|
||||||
/* Close the current application, if it's open. */
|
/* Close the current application, if it's open. */
|
||||||
CloseActiveCheatProcess();
|
CloseActiveCheatProcess();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Intentionally yield the cheat lock to the debug events thread. */
|
||||||
/* Wait to not have debug events thread. */
|
/* Wait to not have debug events thread. */
|
||||||
WaitDebugEventsThread();
|
WaitDebugEventsThread();
|
||||||
|
|
||||||
|
/* At this point, we can re-acquire the lock for the rest of the function. */
|
||||||
|
std::scoped_lock<HosMutex> lk(g_cheat_lock);
|
||||||
|
|
||||||
/* Get the new application's process ID. */
|
/* Get the new application's process ID. */
|
||||||
if (R_FAILED((rc = pmdmntGetApplicationPid(&g_cheat_process_metadata.process_id)))) {
|
if (R_FAILED((rc = pmdmntGetApplicationPid(&g_cheat_process_metadata.process_id)))) {
|
||||||
fatalSimple(rc);
|
fatalSimple(rc);
|
||||||
|
@ -909,6 +927,7 @@ void DmntCheatManager::VmThread(void *arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DmntCheatManager::DebugEventsThread(void *arg) {
|
void DmntCheatManager::DebugEventsThread(void *arg) {
|
||||||
|
|
||||||
while (R_SUCCEEDED(svcWaitSynchronizationSingle(g_cheat_process_debug_hnd, U64_MAX))) {
|
while (R_SUCCEEDED(svcWaitSynchronizationSingle(g_cheat_process_debug_hnd, U64_MAX))) {
|
||||||
std::scoped_lock<HosMutex> lk(g_cheat_lock);
|
std::scoped_lock<HosMutex> lk(g_cheat_lock);
|
||||||
|
|
||||||
|
@ -916,6 +935,7 @@ void DmntCheatManager::DebugEventsThread(void *arg) {
|
||||||
if (HasActiveCheatProcess()) {
|
if (HasActiveCheatProcess()) {
|
||||||
ContinueCheatProcess();
|
ContinueCheatProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -955,6 +975,20 @@ void DmntCheatManager::InitializeCheatManager() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* WORKAROUND: On 6.0.0+, we must ensure that every core has at least one non-game thread. */
|
||||||
|
/* This prevents a kernel deadlock when continuing debug events. */
|
||||||
|
if (kernelAbove600()) {
|
||||||
|
for (size_t i = 0; i < sizeof(g_workaround_threads) / sizeof(g_workaround_threads[0]); i++) {
|
||||||
|
if (R_FAILED(g_workaround_threads[i].Initialize(&KernelWorkaroundThreadFunc, nullptr, 0x1000, 0, i))) {
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (R_FAILED(g_workaround_threads[i].Start())) {
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Spawn application detection thread, spawn cheat vm thread. */
|
/* Spawn application detection thread, spawn cheat vm thread. */
|
||||||
if (R_FAILED(g_detect_thread.Initialize(&DmntCheatManager::DetectThread, nullptr, 0x4000, 39))) {
|
if (R_FAILED(g_detect_thread.Initialize(&DmntCheatManager::DetectThread, nullptr, 0x4000, 39))) {
|
||||||
std::abort();
|
std::abort();
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
void DmntCheatVm::OpenDebugLogFile() {
|
void DmntCheatVm::OpenDebugLogFile() {
|
||||||
#ifdef DMNT_CHEAT_VM_DEBUG_LOG
|
#ifdef DMNT_CHEAT_VM_DEBUG_LOG
|
||||||
CloseDebugLogFile();
|
CloseDebugLogFile();
|
||||||
this->debug_log_file = fopen("cheat_vm_log.txt", "wb");
|
this->debug_log_file = fopen("cheat_vm_log.txt", "ab");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue