diff --git a/CMakeLists.txt b/CMakeLists.txt index 67a7e410..5d48bc2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,6 +150,7 @@ set(FS_SOURCE_FILES src/core/fs/archive_self_ncch.cpp src/core/fs/archive_save_d src/core/fs/ivfc.cpp ) +set(APPLET_SOURCE_FILES src/core/applets/applet.cpp src/core/applets/mii_selector.cpp src/core/applets/software_keyboard.cpp src/core/applets/applet_manager.cpp) set(RENDERER_SW_SOURCE_FILES src/core/renderer_sw/renderer_sw.cpp) set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/termcolor.hpp @@ -178,7 +179,8 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/termcolor.hpp include/config.hpp include/services/ir_user.hpp include/http_server.hpp include/cheats.hpp include/action_replay.hpp include/renderer_sw/renderer_sw.hpp include/compiler_builtins.hpp include/fs/romfs.hpp include/fs/ivfc.hpp include/discord_rpc.hpp include/services/http.hpp include/result/result_cfg.hpp - include/math_util.hpp include/services/soc.hpp include/services/news_u.hpp + include/applets/applet.hpp include/applets/mii_selector.hpp include/math_util.hpp include/services/soc.hpp + include/services/news_u.hpp include/applets/software_keyboard.hpp include/applets/applet_manager.hpp ) cmrc_add_resource_library( @@ -203,6 +205,7 @@ source_group("Source Files\\Core\\Filesystem" FILES ${FS_SOURCE_FILES}) source_group("Source Files\\Core\\Kernel" FILES ${KERNEL_SOURCE_FILES}) source_group("Source Files\\Core\\Loader" FILES ${LOADER_SOURCE_FILES}) source_group("Source Files\\Core\\Services" FILES ${SERVICE_SOURCE_FILES}) +source_group("Source Files\\Core\\Applets" FILES ${APPLET_SOURCE_FILES}) source_group("Source Files\\Core\\PICA" FILES ${PICA_SOURCE_FILES}) source_group("Source Files\\Core\\Software Renderer" FILES ${RENDERER_SW_SOURCE_FILES}) source_group("Source Files\\Third Party" FILES ${THIRD_PARTY_SOURCE_FILES}) @@ -265,7 +268,7 @@ endif() source_group("Header Files\\Core" FILES ${HEADER_FILES}) set(ALL_SOURCES ${SOURCE_FILES} ${FS_SOURCE_FILES} ${CRYPTO_SOURCE_FILES} ${KERNEL_SOURCE_FILES} ${LOADER_SOURCE_FILES} ${SERVICE_SOURCE_FILES} - ${RENDERER_SW_SOURCE_FILES} ${PICA_SOURCE_FILES} ${THIRD_PARTY_SOURCE_FILES} ${HEADER_FILES}) + ${APPLET_SOURCE_FILES} ${RENDERER_SW_SOURCE_FILES} ${PICA_SOURCE_FILES} ${THIRD_PARTY_SOURCE_FILES} ${HEADER_FILES}) if(ENABLE_OPENGL) # Add the OpenGL source files to ALL_SOURCES diff --git a/include/applets/applet.hpp b/include/applets/applet.hpp new file mode 100644 index 00000000..0c3ab519 --- /dev/null +++ b/include/applets/applet.hpp @@ -0,0 +1,88 @@ +#pragma once + +#include "helpers.hpp" +#include "memory.hpp" +#include "result/result.hpp" + +namespace Applets { + namespace AppletIDs { + enum : u32 { + None = 0, + SysAppletMask = 0x100, + HomeMenu = 0x101, + AltMenu = 0x103, + Camera = 0x110, + Friends = 0x112, + GameNotes = 0x113, + Browser = 0x114, + InstructionManual = 0x115, + Notifications = 0x116, + Miiverse = 0x117, + MiiversePosting = 0x118, + AmiiboSettings = 0x119, + SysLibraryAppletMask = 0x200, + SoftwareKeyboard = 0x201, + MiiSelector = 0x202, + PNote = 0x204, // TODO: What dis? + SNote = 0x205, // What is this too? + ErrDisp = 0x206, + EshopMint = 0x207, + CirclePadProCalib = 0x208, + Notepad = 0x209, + Application = 0x300, + EshopTiger = 0x301, + LibraryAppletMask = 0x400, + SoftwareKeyboard2 = 0x401, + MiiSelector2 = 0x402, + Pnote2 = 0x404, + SNote2 = 0x405, + ErrDisp2 = 0x406, + EshopMint2 = 0x407, + CirclePadProCalib2 = 0x408, + Notepad2 = 0x409, + }; + } + + enum class APTSignal : u32 { + None = 0x0, + Wakeup = 0x1, + Request = 0x2, + Response = 0x3, + Exit = 0x4, + Message = 0x5, + HomeButtonSingle = 0x6, + HomeButtonDouble = 0x7, + DspSleep = 0x8, + DspWakeup = 0x9, + WakeupByExit = 0xA, + WakeupByPause = 0xB, + WakeupByCancel = 0xC, + WakeupByCancelAll = 0xD, + WakeupByPowerButtonClick = 0xE, + WakeupToJumpHome = 0xF, + RequestForSysApplet = 0x10, + WakeupToLaunchApplication = 0x11, + }; + + struct Parameter { + u32 senderID; + u32 destID; + APTSignal signal; + std::vector data; + }; + + class AppletBase { + Memory& mem; + + public: + virtual const char* name() = 0; + + // Called by APT::StartLibraryApplet and similar + virtual Result::HorizonResult start() = 0; + // Transfer parameters from application -> applet + virtual Result::HorizonResult receiveParameter() = 0; + virtual void reset() = 0; + + AppletBase(Memory& mem) : mem(mem) {} + }; +} // namespace Applets \ No newline at end of file diff --git a/include/applets/applet_manager.hpp b/include/applets/applet_manager.hpp new file mode 100644 index 00000000..95b54009 --- /dev/null +++ b/include/applets/applet_manager.hpp @@ -0,0 +1,17 @@ +#include "applets/mii_selector.hpp" +#include "applets/software_keyboard.hpp" +#include "helpers.hpp" +#include "memory.hpp" +#include "result/result.hpp" + +namespace Applets { + class AppletManager { + MiiSelectorApplet miiSelector; + SoftwareKeyboardApplet swkbd; + + public: + AppletManager(Memory& mem); + void reset(); + AppletBase* getApplet(u32 id); + }; +} // namespace Applets \ No newline at end of file diff --git a/include/applets/mii_selector.hpp b/include/applets/mii_selector.hpp new file mode 100644 index 00000000..e40547fb --- /dev/null +++ b/include/applets/mii_selector.hpp @@ -0,0 +1,13 @@ +#include "applets/applet.hpp" + +namespace Applets { + class MiiSelectorApplet final : public AppletBase { + public: + virtual const char* name() override { return "Mii Selector"; } + virtual Result::HorizonResult start() override; + virtual Result::HorizonResult receiveParameter() override; + virtual void reset() override; + + MiiSelectorApplet(Memory& memory) : AppletBase(memory) {} + }; +} // namespace Applets \ No newline at end of file diff --git a/include/applets/software_keyboard.hpp b/include/applets/software_keyboard.hpp new file mode 100644 index 00000000..1fb721a1 --- /dev/null +++ b/include/applets/software_keyboard.hpp @@ -0,0 +1,13 @@ +#include "applets/applet.hpp" + +namespace Applets { + class SoftwareKeyboardApplet final : public AppletBase { + public: + virtual const char* name() override { return "Software Keyboard"; } + virtual Result::HorizonResult start() override; + virtual Result::HorizonResult receiveParameter() override; + virtual void reset() override; + + SoftwareKeyboardApplet(Memory& memory) : AppletBase(memory) {} + }; +} // namespace Applets \ No newline at end of file diff --git a/include/services/apt.hpp b/include/services/apt.hpp index 56bf3083..a7df056f 100644 --- a/include/services/apt.hpp +++ b/include/services/apt.hpp @@ -6,6 +6,8 @@ #include "memory.hpp" #include "result/result.hpp" +#include "applets/applet_manager.hpp" + // Yay, more circular dependencies class Kernel; @@ -23,6 +25,7 @@ class APTService { std::optional resumeEvent = std::nullopt; ConsoleModel model = ConsoleModel::Old3DS; + Applets::AppletManager appletManager; MAKE_LOG_FUNCTION(log, aptLogger) @@ -33,17 +36,22 @@ class APTService { void checkNew3DS(u32 messagePointer); void checkNew3DSApp(u32 messagePointer); void enable(u32 messagePointer); + void getAppletInfo(u32 messagePointer); void getSharedFont(u32 messagePointer); void getWirelessRebootInfo(u32 messagePointer); void glanceParameter(u32 messagePointer); void initialize(u32 messagePointer); void inquireNotification(u32 messagePointer); + void isRegistered(u32 messagePointer); void notifyToWait(u32 messagePointer); void preloadLibraryApplet(u32 messagePointer); + void prepareToStartLibraryApplet(u32 messagePointer); void receiveParameter(u32 messagePointer); void replySleepQuery(u32 messagePointer); void setApplicationCpuTimeLimit(u32 messagePointer); void setScreencapPostPermission(u32 messagePointer); + void sendParameter(u32 messagePointer); + void startLibraryApplet(u32 messagePointer); void theSmashBrosFunction(u32 messagePointer); // Percentage of the syscore available to the application, between 5% and 89% @@ -67,7 +75,7 @@ class APTService { u32 screencapPostPermission; public: - APTService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {} + APTService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel), appletManager(mem) {} void reset(); void handleSyncRequest(u32 messagePointer); }; \ No newline at end of file diff --git a/include/services/gsp_gpu.hpp b/include/services/gsp_gpu.hpp index c9facffb..92ca36e2 100644 --- a/include/services/gsp_gpu.hpp +++ b/include/services/gsp_gpu.hpp @@ -63,7 +63,9 @@ class GPUService { // Service commands void acquireRight(u32 messagePointer); void flushDataCache(u32 messagePointer); + void importDisplayCaptureInfo(u32 messagePointer); void registerInterruptRelayQueue(u32 messagePointer); + void saveVramSysArea(u32 messagePointer); void setAxiConfigQoSMode(u32 messagePointer); void setBufferSwap(u32 messagePointer); void setInternalPriorities(u32 messagePointer); diff --git a/src/core/applets/applet.cpp b/src/core/applets/applet.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/core/applets/applet_manager.cpp b/src/core/applets/applet_manager.cpp new file mode 100644 index 00000000..c94eee28 --- /dev/null +++ b/src/core/applets/applet_manager.cpp @@ -0,0 +1,21 @@ +#include "applets/applet_manager.hpp" +using namespace Applets; + +AppletManager::AppletManager(Memory& mem) : miiSelector(mem), swkbd(mem) {} + +void AppletManager::reset() { + miiSelector.reset(); + swkbd.reset(); +} + +AppletBase* AppletManager::getApplet(u32 id) { + switch (id) { + case AppletIDs::MiiSelector: + case AppletIDs::MiiSelector2: return &miiSelector; + + case AppletIDs::SoftwareKeyboard: + case AppletIDs::SoftwareKeyboard2: return &swkbd; + + default: return nullptr; + } +} \ No newline at end of file diff --git a/src/core/applets/mii_selector.cpp b/src/core/applets/mii_selector.cpp new file mode 100644 index 00000000..211e6f07 --- /dev/null +++ b/src/core/applets/mii_selector.cpp @@ -0,0 +1,11 @@ +#include "applets/mii_selector.hpp" + +using namespace Applets; + +void MiiSelectorApplet::reset() {} +Result::HorizonResult MiiSelectorApplet::start() { return Result::Success; } + +Result::HorizonResult MiiSelectorApplet::receiveParameter() { + 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 new file mode 100644 index 00000000..2ff22792 --- /dev/null +++ b/src/core/applets/software_keyboard.cpp @@ -0,0 +1,11 @@ +#include "applets/software_keyboard.hpp" + +using namespace Applets; + +void SoftwareKeyboardApplet::reset() {} +Result::HorizonResult SoftwareKeyboardApplet::start() { return Result::Success; } + +Result::HorizonResult SoftwareKeyboardApplet::receiveParameter() { + Helpers::warn("Software keyboard: Unimplemented ReceiveParameter"); + return Result::Success; +} \ No newline at end of file diff --git a/src/core/services/apt.cpp b/src/core/services/apt.cpp index 4ad7f353..2bb3e4a2 100644 --- a/src/core/services/apt.cpp +++ b/src/core/services/apt.cpp @@ -9,10 +9,15 @@ namespace APTCommands { GetLockHandle = 0x00010040, Initialize = 0x00020080, Enable = 0x00030040, + GetAppletInfo = 0x00060040, + IsRegistered = 0x00090040, InquireNotification = 0x000B0040, + SendParameter = 0x000C0104, ReceiveParameter = 0x000D0080, GlanceParameter = 0x000E0080, PreloadLibraryApplet = 0x00160040, + PrepareToStartLibraryApplet = 0x00180040, + StartLibraryApplet = 0x001E0084, ReplySleepQuery = 0x003E0080, NotifyToWait = 0x00430040, GetSharedFont = 0x00440000, @@ -60,6 +65,8 @@ void APTService::reset() { lockHandle = std::nullopt; notificationEvent = std::nullopt; resumeEvent = std::nullopt; + + appletManager.reset(); } void APTService::handleSyncRequest(u32 messagePointer) { @@ -69,22 +76,26 @@ void APTService::handleSyncRequest(u32 messagePointer) { case APTCommands::CheckNew3DS: checkNew3DS(messagePointer); break; case APTCommands::CheckNew3DSApp: checkNew3DSApp(messagePointer); break; case APTCommands::Enable: enable(messagePointer); break; + case APTCommands::GetAppletInfo: getAppletInfo(messagePointer); break; case APTCommands::GetSharedFont: getSharedFont(messagePointer); break; case APTCommands::Initialize: initialize(messagePointer); break; case APTCommands::InquireNotification: [[likely]] inquireNotification(messagePointer); break; + case APTCommands::IsRegistered: isRegistered(messagePointer); break; case APTCommands::GetApplicationCpuTimeLimit: getApplicationCpuTimeLimit(messagePointer); break; case APTCommands::GetLockHandle: getLockHandle(messagePointer); break; case APTCommands::GetWirelessRebootInfo: getWirelessRebootInfo(messagePointer); break; case APTCommands::GlanceParameter: glanceParameter(messagePointer); break; case APTCommands::NotifyToWait: notifyToWait(messagePointer); break; case APTCommands::PreloadLibraryApplet: preloadLibraryApplet(messagePointer); break; + case APTCommands::PrepareToStartLibraryApplet: prepareToStartLibraryApplet(messagePointer); break; case APTCommands::ReceiveParameter: [[likely]] receiveParameter(messagePointer); break; case APTCommands::ReplySleepQuery: replySleepQuery(messagePointer); break; case APTCommands::SetApplicationCpuTimeLimit: setApplicationCpuTimeLimit(messagePointer); break; + case APTCommands::SendParameter: sendParameter(messagePointer); break; case APTCommands::SetScreencapPostPermission: setScreencapPostPermission(messagePointer); break; case APTCommands::TheSmashBrosFunction: theSmashBrosFunction(messagePointer); break; default: - Helpers::panicDev("APT service requested. Command: %08X\n", command); + Helpers::panic("APT service requested. Command: %08X\n", command); mem.write32(messagePointer + 4, Result::Success); break; } @@ -116,9 +127,38 @@ void APTService::appletUtility(u32 messagePointer) { } } +void APTService::getAppletInfo(u32 messagePointer) { + const u32 appID = mem.read32(messagePointer + 4); + Helpers::warn("APT::GetAppletInfo (appID = %X)\n", appID); + + mem.write32(messagePointer, IPC::responseHeader(0x06, 7, 0)); + mem.write32(messagePointer + 4, Result::Success); + + mem.write8(messagePointer + 20, 1); // 1 = registered + mem.write8(messagePointer + 24, 1); // 1 = loaded + // TODO: The rest of this +} + +void APTService::isRegistered(u32 messagePointer) { + const u32 appID = mem.read32(messagePointer + 4); + Helpers::warn("APT::IsRegistered (appID = %X)", appID); + + mem.write32(messagePointer, IPC::responseHeader(0x09, 2, 0)); + mem.write32(messagePointer + 4, Result::Success); + mem.write8(messagePointer + 8, 1); // Return that the app is always registered. This might break with home menu? +} + void APTService::preloadLibraryApplet(u32 messagePointer) { const u32 appID = mem.read32(messagePointer + 4); - log("APT::PreloadLibraryApplet (app ID = %d) (stubbed)\n", appID); + log("APT::PreloadLibraryApplet (app ID = %X) (stubbed)\n", appID); + + mem.write32(messagePointer, IPC::responseHeader(0x16, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + +void APTService::prepareToStartLibraryApplet(u32 messagePointer) { + const u32 appID = mem.read32(messagePointer + 4); + log("APT::PrepareToStartLibraryApplet (app ID = %X) (stubbed)\n", appID); mem.write32(messagePointer, IPC::responseHeader(0x16, 1, 0)); mem.write32(messagePointer + 4, Result::Success); @@ -193,6 +233,35 @@ void APTService::notifyToWait(u32 messagePointer) { mem.write32(messagePointer + 4, Result::Success); } +void APTService::sendParameter(u32 messagePointer) { + const u32 sourceAppID = mem.read32(messagePointer + 4); + const u32 destAppID = mem.read32(messagePointer + 8); + const u32 cmd = mem.read32(messagePointer + 12); + const u32 paramSize = mem.read32(messagePointer + 16); + + const u32 parameterHandle = mem.read32(messagePointer + 24); // What dis? + const u32 parameterPointer = mem.read32(messagePointer + 32); + log("APT::SendParameter (source app = %X, dest app = %X, cmd = %X, size = %X) (Stubbed)", sourceAppID, destAppID, cmd, paramSize); + + mem.write32(messagePointer, IPC::responseHeader(0x0C, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); + + if (sourceAppID != Applets::AppletIDs::Application) { + Helpers::warn("APT::SendParameter: Unimplemented source applet ID"); + } + + Applets::AppletBase* destApplet = appletManager.getApplet(destAppID); + if (destApplet == nullptr) { + Helpers::warn("APT::SendParameter: Unimplemented dest applet ID"); + } else { + auto result = destApplet->receiveParameter(); + } + + if (resumeEvent.has_value()) { + kernel.signalEvent(resumeEvent.value()); + } +} + void APTService::receiveParameter(u32 messagePointer) { const u32 app = mem.read32(messagePointer + 4); const u32 size = mem.read32(messagePointer + 8); diff --git a/src/core/services/gsp_gpu.cpp b/src/core/services/gsp_gpu.cpp index c2f7faee..0e27c0ec 100644 --- a/src/core/services/gsp_gpu.cpp +++ b/src/core/services/gsp_gpu.cpp @@ -15,6 +15,8 @@ namespace ServiceCommands { FlushDataCache = 0x00080082, SetLCDForceBlack = 0x000B0040, TriggerCmdReqQueue = 0x000C0000, + ImportDisplayCaptureInfo = 0x00180000, + SaveVramSysArea = 0x00190000, SetInternalPriorities = 0x001E0080, StoreDataCache = 0x001F0082 }; @@ -42,15 +44,17 @@ void GPUService::reset() { void GPUService::handleSyncRequest(u32 messagePointer) { const u32 command = mem.read32(messagePointer); switch (command) { + case ServiceCommands::TriggerCmdReqQueue: [[likely]] triggerCmdReqQueue(messagePointer); break; case ServiceCommands::AcquireRight: acquireRight(messagePointer); break; case ServiceCommands::FlushDataCache: flushDataCache(messagePointer); break; + case ServiceCommands::ImportDisplayCaptureInfo: importDisplayCaptureInfo(messagePointer); break; case ServiceCommands::RegisterInterruptRelayQueue: registerInterruptRelayQueue(messagePointer); break; + case ServiceCommands::SaveVramSysArea: saveVramSysArea(messagePointer); break; case ServiceCommands::SetAxiConfigQoSMode: setAxiConfigQoSMode(messagePointer); break; case ServiceCommands::SetBufferSwap: setBufferSwap(messagePointer); break; case ServiceCommands::SetInternalPriorities: setInternalPriorities(messagePointer); break; case ServiceCommands::SetLCDForceBlack: setLCDForceBlack(messagePointer); break; case ServiceCommands::StoreDataCache: storeDataCache(messagePointer); break; - case ServiceCommands::TriggerCmdReqQueue: [[likely]] triggerCmdReqQueue(messagePointer); break; case ServiceCommands::WriteHwRegs: writeHwRegs(messagePointer); break; case ServiceCommands::WriteHwRegsWithMask: writeHwRegsWithMask(messagePointer); break; default: Helpers::panic("GPU service requested. Command: %08X\n", command); @@ -456,3 +460,20 @@ void GPUService::triggerTextureCopy(u32* cmd) { // NSMB2 relies on this requestInterrupt(GPUInterrupt::PPF); } + +// Used when transitioning from the app to an OS applet, such as software keyboard, mii maker, mii selector, etc +// Stubbed until we decide to support LLE applets +void GPUService::saveVramSysArea(u32 messagePointer) { + Helpers::warn("GSP::GPU::SaveVramSysArea (stubbed)"); + + mem.write32(messagePointer, IPC::responseHeader(0x19, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + +// Used in similar fashion to the SaveVramSysArea function +void GPUService::importDisplayCaptureInfo(u32 messagePointer) { + Helpers::warn("GSP::GPU::ImportDisplayCaptureInfo (stubbed)"); + + mem.write32(messagePointer, IPC::responseHeader(0x18, 9, 0)); + mem.write32(messagePointer + 4, Result::Success); +} \ No newline at end of file