diff --git a/src/core/kernel/idle_thread.cpp b/src/core/kernel/idle_thread.cpp index 4b0a981a..5389fecc 100644 --- a/src/core/kernel/idle_thread.cpp +++ b/src/core/kernel/idle_thread.cpp @@ -51,6 +51,7 @@ void Kernel::setupIdleThread() { std::memcpy(&mem.getFCRAM()[fcramIndex], idleThreadCode, sizeof(idleThreadCode)); t.entrypoint = codeAddress; + t.tlsBase = 0; t.gprs[13] = 0; // Set SP & LR to 0 just in case. The idle thread should never access memory, but let's be safe t.gprs[14] = 0; t.gprs[15] = codeAddress; diff --git a/src/core/kernel/threads.cpp b/src/core/kernel/threads.cpp index 5dc11257..7da1d8da 100644 --- a/src/core/kernel/threads.cpp +++ b/src/core/kernel/threads.cpp @@ -83,6 +83,7 @@ void Kernel::switchToNextThread() { if (!newThreadIndex.has_value()) { log("Kernel tried to switch to the next thread but none found. Switching to random thread\n"); assert(aliveThreadCount != 0); + Helpers::panic("rpog"); int index; do { @@ -190,9 +191,12 @@ void Kernel::sleepThread(s64 ns) { if (ns < 0) { Helpers::panic("Sleeping a thread for a negative amount of ns"); } else if (ns == 0) { // Used when we want to force a thread switch - int curr = currentThreadIndex; - switchToNextThread(); // Mark thread as ready after switching, to avoid switching to the same thread - threads[curr].status = ThreadStatus::Ready; + std::optional newThreadIndex = getNextThread(); + // If there's no other thread waiting, don't bother yielding + if (newThreadIndex.has_value()) { + threads[currentThreadIndex].status = ThreadStatus::Ready; + switchThread(newThreadIndex.value()); + } } else { // If we're sleeping for > 0 ns Thread& t = threads[currentThreadIndex]; t.status = ThreadStatus::WaitSleep; diff --git a/src/core/services/apt.cpp b/src/core/services/apt.cpp index f83da50c..93bfc0cf 100644 --- a/src/core/services/apt.cpp +++ b/src/core/services/apt.cpp @@ -25,7 +25,6 @@ namespace APTCommands { namespace Result { enum : u32 { Success = 0, - Failure = 0xFFFFFFFF }; } @@ -93,8 +92,10 @@ void APTService::enable(u32 messagePointer) { void APTService::initialize(u32 messagePointer) { log("APT::Initialize\n"); - notificationEvent = kernel.makeEvent(ResetType::OneShot); - resumeEvent = kernel.makeEvent(ResetType::OneShot); + if (!notificationEvent.has_value() || !resumeEvent.has_value()) { + notificationEvent = kernel.makeEvent(ResetType::OneShot); + resumeEvent = kernel.makeEvent(ResetType::OneShot); + } mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, 0x04000000); // Translation descriptor @@ -103,12 +104,9 @@ void APTService::initialize(u32 messagePointer) { } void APTService::inquireNotification(u32 messagePointer) { - log("APT::InquireNotification (STUBBED TO FAIL)\n"); + log("APT::InquireNotification (STUBBED TO RETURN NONE)\n"); - // Thanks to our silly WaitSynchronization hacks, sometimes games will switch to the APT thread without actually getting a notif - // After REing the APT code, I figured that making InquireNotification fail is one way of making games not crash when this happens - // We should fix this in the future, when the sync object implementation is less hacky. - mem.write32(messagePointer + 4, Result::Failure); + mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, static_cast(NotificationType::None)); } @@ -120,7 +118,7 @@ void APTService::getLockHandle(u32 messagePointer) { lockHandle = kernel.makeMutex(); } - mem.write32(messagePointer + 4, Result::Failure); // Result code + mem.write32(messagePointer + 4, Result::Success); // Result code mem.write32(messagePointer + 8, 0); // AppletAttr mem.write32(messagePointer + 12, 0); // APT State (bit0 = Power Button State, bit1 = Order To Close State) mem.write32(messagePointer + 16, 0); // Translation descriptor