diff --git a/include/applets/applet.hpp b/include/applets/applet.hpp index 0c3ab519b..79fba1cbc 100644 --- a/include/applets/applet.hpp +++ b/include/applets/applet.hpp @@ -67,12 +67,14 @@ namespace Applets { struct Parameter { u32 senderID; u32 destID; - APTSignal signal; + u32 signal; std::vector data; }; class AppletBase { + protected: Memory& mem; + std::optional& nextParameter; public: virtual const char* name() = 0; @@ -80,9 +82,9 @@ namespace Applets { // Called by APT::StartLibraryApplet and similar virtual Result::HorizonResult start() = 0; // Transfer parameters from application -> applet - virtual Result::HorizonResult receiveParameter() = 0; + virtual Result::HorizonResult receiveParameter(const Parameter& parameter) = 0; virtual void reset() = 0; - AppletBase(Memory& mem) : mem(mem) {} + AppletBase(Memory& mem, std::optional& nextParam) : mem(mem), nextParameter(nextParam) {} }; } // namespace Applets \ No newline at end of file diff --git a/include/applets/applet_manager.hpp b/include/applets/applet_manager.hpp index 95b540090..e75e1268e 100644 --- a/include/applets/applet_manager.hpp +++ b/include/applets/applet_manager.hpp @@ -1,3 +1,6 @@ +#pragma once +#include + #include "applets/mii_selector.hpp" #include "applets/software_keyboard.hpp" #include "helpers.hpp" @@ -8,10 +11,14 @@ namespace Applets { class AppletManager { MiiSelectorApplet miiSelector; SoftwareKeyboardApplet swkbd; + std::optional nextParameter = std::nullopt; public: AppletManager(Memory& mem); void reset(); AppletBase* getApplet(u32 id); + + Applets::Parameter glanceParameter(); + Applets::Parameter receiveParameter(); }; } // namespace Applets \ No newline at end of file diff --git a/include/applets/mii_selector.hpp b/include/applets/mii_selector.hpp index e40547fbd..c90d4b598 100644 --- a/include/applets/mii_selector.hpp +++ b/include/applets/mii_selector.hpp @@ -5,9 +5,9 @@ namespace Applets { public: virtual const char* name() override { return "Mii Selector"; } virtual Result::HorizonResult start() override; - virtual Result::HorizonResult receiveParameter() override; + virtual Result::HorizonResult receiveParameter(const Applets::Parameter& parameter) override; virtual void reset() override; - MiiSelectorApplet(Memory& memory) : AppletBase(memory) {} + MiiSelectorApplet(Memory& memory, std::optional& nextParam) : AppletBase(memory, nextParam) {} }; } // namespace Applets \ No newline at end of file diff --git a/include/applets/software_keyboard.hpp b/include/applets/software_keyboard.hpp index 1fb721a1a..f41790122 100644 --- a/include/applets/software_keyboard.hpp +++ b/include/applets/software_keyboard.hpp @@ -5,9 +5,9 @@ namespace Applets { public: virtual const char* name() override { return "Software Keyboard"; } virtual Result::HorizonResult start() override; - virtual Result::HorizonResult receiveParameter() override; + virtual Result::HorizonResult receiveParameter(const Applets::Parameter& parameter) override; virtual void reset() override; - SoftwareKeyboardApplet(Memory& memory) : AppletBase(memory) {} + SoftwareKeyboardApplet(Memory& memory, std::optional& nextParam) : AppletBase(memory, nextParam) {} }; } // namespace Applets \ No newline at end of file diff --git a/include/services/apt.hpp b/include/services/apt.hpp index a7df056fe..48a59c2d1 100644 --- a/include/services/apt.hpp +++ b/include/services/apt.hpp @@ -15,6 +15,31 @@ enum class ConsoleModel : u32 { Old3DS, New3DS }; +// https://www.3dbrew.org/wiki/NS_and_APT_Services#Command +namespace APT::Transitions { + enum : u32 { + None = 0, + Wakeup = 1, + Request = 2, + Response = 3, + Exit = 4, + Message = 5, + HomeButtonSingle = 6, + HomeButtonDouble = 7, + DSPSleep = 8, + DSPWakeup = 9, + WakeupByExit = 10, + WakuepByPause = 11, + WakeupByCancel = 12, + WakeupByCancelAll = 13, + WakeupByPowerButton = 14, + WakeupToJumpHome = 15, + RequestForApplet = 16, + WakeupToLaunchApp = 17, + ProcessDed = 0x41 + }; +} + class APTService { Handle handle = KernelHandles::APT; Memory& mem; diff --git a/include/services/gsp_gpu.hpp b/include/services/gsp_gpu.hpp index 92ca36e20..68e245803 100644 --- a/include/services/gsp_gpu.hpp +++ b/include/services/gsp_gpu.hpp @@ -65,6 +65,7 @@ class GPUService { void flushDataCache(u32 messagePointer); void importDisplayCaptureInfo(u32 messagePointer); void registerInterruptRelayQueue(u32 messagePointer); + void releaseRight(u32 messagePointer); void saveVramSysArea(u32 messagePointer); void setAxiConfigQoSMode(u32 messagePointer); void setBufferSwap(u32 messagePointer); diff --git a/src/core/applets/applet_manager.cpp b/src/core/applets/applet_manager.cpp index c94eee280..c27917777 100644 --- a/src/core/applets/applet_manager.cpp +++ b/src/core/applets/applet_manager.cpp @@ -1,9 +1,14 @@ #include "applets/applet_manager.hpp" + +#include "services/apt.hpp" + using namespace Applets; -AppletManager::AppletManager(Memory& mem) : miiSelector(mem), swkbd(mem) {} +AppletManager::AppletManager(Memory& mem) : miiSelector(mem, nextParameter), swkbd(mem, nextParameter) {} void AppletManager::reset() { + nextParameter = std::nullopt; + miiSelector.reset(); swkbd.reset(); } @@ -18,4 +23,35 @@ AppletBase* AppletManager::getApplet(u32 id) { default: return nullptr; } +} + +Applets::Parameter AppletManager::glanceParameter() { + if (nextParameter) { + // Copy parameter + Applets::Parameter param = nextParameter.value(); + // APT module clears next parameter even for GlanceParameter for these 2 signals + if (param.signal == static_cast(APTSignal::DspWakeup) || param.signal == static_cast(APTSignal::DspSleep)) { + nextParameter = std::nullopt; + } + + return param; + } + + // Default return value. This is legacy code from before applets were implemented. TODO: Update it + else { + return Applets::Parameter{ + .senderID = 0, + .destID = Applets::AppletIDs::Application, + .signal = static_cast(APTSignal::Wakeup), + .data = {}, + }; + } +} + +Applets::Parameter AppletManager::receiveParameter() { + Applets::Parameter param = glanceParameter(); + // ReceiveParameter always clears nextParameter whereas glanceParameter does not + nextParameter = std::nullopt; + + return param; } \ No newline at end of file diff --git a/src/core/applets/mii_selector.cpp b/src/core/applets/mii_selector.cpp index 211e6f077..f392d8462 100644 --- a/src/core/applets/mii_selector.cpp +++ b/src/core/applets/mii_selector.cpp @@ -5,7 +5,7 @@ using namespace Applets; void MiiSelectorApplet::reset() {} Result::HorizonResult MiiSelectorApplet::start() { return Result::Success; } -Result::HorizonResult MiiSelectorApplet::receiveParameter() { +Result::HorizonResult MiiSelectorApplet::receiveParameter(const Applets::Parameter& parameter) { Helpers::warn("Mii Selector: Unimplemented ReceiveParameter"); return Result::Success; } \ No newline at end of file diff --git a/src/core/applets/software_keyboard.cpp b/src/core/applets/software_keyboard.cpp index 2ff227927..be5a9e21d 100644 --- a/src/core/applets/software_keyboard.cpp +++ b/src/core/applets/software_keyboard.cpp @@ -5,7 +5,16 @@ using namespace Applets; void SoftwareKeyboardApplet::reset() {} Result::HorizonResult SoftwareKeyboardApplet::start() { return Result::Success; } -Result::HorizonResult SoftwareKeyboardApplet::receiveParameter() { +Result::HorizonResult SoftwareKeyboardApplet::receiveParameter(const Applets::Parameter& parameter) { Helpers::warn("Software keyboard: Unimplemented ReceiveParameter"); + + Applets::Parameter param = Applets::Parameter{ + .senderID = parameter.destID, + .destID = AppletIDs::Application, + .signal = static_cast(APTSignal::Response), + .data = {}, + }; + + nextParameter = param; return Result::Success; } \ No newline at end of file diff --git a/src/core/services/apt.cpp b/src/core/services/apt.cpp index d969f2a44..754baa139 100644 --- a/src/core/services/apt.cpp +++ b/src/core/services/apt.cpp @@ -32,31 +32,6 @@ namespace APTCommands { }; } -// https://www.3dbrew.org/wiki/NS_and_APT_Services#Command -namespace APTTransitions { - enum : u32 { - None = 0, - Wakeup = 1, - Request = 2, - Response = 3, - Exit = 4, - Message = 5, - HomeButtonSingle = 6, - HomeButtonDouble = 7, - DSPSleep = 8, - DSPWakeup = 9, - WakeupByExit = 10, - WakuepByPause = 11, - WakeupByCancel = 12, - WakeupByCancelAll = 13, - WakeupByPowerButton = 14, - WakeupToJumpHome = 15, - RequestForApplet = 16, - WakeupToLaunchApp = 17, - ProcessDed = 0x41 - }; -} - void APTService::reset() { // Set the default CPU time limit to 30%. Seems safe, as this is what Metroid 2 uses by default cpuTimeLimit = 30; @@ -259,7 +234,21 @@ void APTService::sendParameter(u32 messagePointer) { if (destApplet == nullptr) { Helpers::warn("APT::SendParameter: Unimplemented dest applet ID"); } else { - auto result = destApplet->receiveParameter(); + // Construct parameter, send it to applet + Applets::Parameter param; + param.senderID = sourceAppID; + param.destID = destAppID; + param.signal = cmd; + + // Fetch parameter data buffer + param.data.reserve(paramSize); + u32 pointer = parameterPointer; + + for (u32 i = 0; i < paramSize; i++) { + param.data.push_back(mem.read8(pointer++)); + } + + auto result = destApplet->receiveParameter(param); } if (resumeEvent.has_value()) { @@ -273,13 +262,16 @@ void APTService::receiveParameter(u32 messagePointer) { log("APT::ReceiveParameter(app ID = %X, size = %04X) (STUBBED)\n", app, size); if (size > 0x1000) Helpers::panic("APT::ReceiveParameter with size > 0x1000"); + auto parameter = appletManager.receiveParameter(); - // TODO: Properly implement this. We currently stub somewhat like 3dmoo mem.write32(messagePointer, IPC::responseHeader(0xD, 4, 4)); mem.write32(messagePointer + 4, Result::Success); - mem.write32(messagePointer + 8, 0); // Sender App ID - mem.write32(messagePointer + 12, APTTransitions::Wakeup); // Command - mem.write32(messagePointer + 16, 0); + // Sender App ID + mem.write32(messagePointer + 8, parameter.senderID); + // Command + mem.write32(messagePointer + 12, parameter.signal); + // Size of parameter data + mem.write32(messagePointer + 16, parameter.data.size()); mem.write32(messagePointer + 20, 0x10); mem.write32(messagePointer + 24, 0); mem.write32(messagePointer + 28, 0); @@ -291,13 +283,17 @@ void APTService::glanceParameter(u32 messagePointer) { log("APT::GlanceParameter(app ID = %X, size = %04X) (STUBBED)\n", app, size); if (size > 0x1000) Helpers::panic("APT::GlanceParameter with size > 0x1000"); + auto parameter = appletManager.glanceParameter(); // TODO: Properly implement this. We currently stub it similar mem.write32(messagePointer, IPC::responseHeader(0xE, 4, 4)); mem.write32(messagePointer + 4, Result::Success); - mem.write32(messagePointer + 8, 0); // Sender App ID - mem.write32(messagePointer + 12, APTTransitions::Wakeup); // Command - mem.write32(messagePointer + 16, 0); + // Sender App ID + mem.write32(messagePointer + 8, parameter.senderID); + // Command + mem.write32(messagePointer + 12, parameter.signal); + // Size of parameter data + mem.write32(messagePointer + 16, parameter.data.size()); mem.write32(messagePointer + 20, 0); mem.write32(messagePointer + 24, 0); mem.write32(messagePointer + 28, 0); diff --git a/src/core/services/gsp_gpu.cpp b/src/core/services/gsp_gpu.cpp index 0e27c0ec0..861dfb0a3 100644 --- a/src/core/services/gsp_gpu.cpp +++ b/src/core/services/gsp_gpu.cpp @@ -15,6 +15,7 @@ namespace ServiceCommands { FlushDataCache = 0x00080082, SetLCDForceBlack = 0x000B0040, TriggerCmdReqQueue = 0x000C0000, + ReleaseRight = 0x00170000, ImportDisplayCaptureInfo = 0x00180000, SaveVramSysArea = 0x00190000, SetInternalPriorities = 0x001E0080, @@ -49,6 +50,7 @@ void GPUService::handleSyncRequest(u32 messagePointer) { case ServiceCommands::FlushDataCache: flushDataCache(messagePointer); break; case ServiceCommands::ImportDisplayCaptureInfo: importDisplayCaptureInfo(messagePointer); break; case ServiceCommands::RegisterInterruptRelayQueue: registerInterruptRelayQueue(messagePointer); break; + case ServiceCommands::ReleaseRight: releaseRight(messagePointer); break; case ServiceCommands::SaveVramSysArea: saveVramSysArea(messagePointer); break; case ServiceCommands::SetAxiConfigQoSMode: setAxiConfigQoSMode(messagePointer); break; case ServiceCommands::SetBufferSwap: setBufferSwap(messagePointer); break; @@ -80,6 +82,16 @@ void GPUService::acquireRight(u32 messagePointer) { mem.write32(messagePointer + 4, Result::Success); } +void GPUService::releaseRight(u32 messagePointer) { + log("GSP::GPU::ReleaseRight\n"); + if (privilegedProcess == currentPID) { + privilegedProcess = 0xFFFFFFFF; + } + + mem.write32(messagePointer, IPC::responseHeader(0x17, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + // TODO: What is the flags field meant to be? // What is the "GSP module thread index" meant to be? // How does the shared memory handle thing work?