From 92f0064b47f085f37a71983260a8cc0da40f8cb9 Mon Sep 17 00:00:00 2001 From: wwylele Date: Thu, 25 Jan 2018 15:39:54 +0200 Subject: [PATCH] APT/Applet: move applet managing into its own class --- src/core/CMakeLists.txt | 3 + src/core/hle/applets/applet.cpp | 20 +- src/core/hle/applets/applet.h | 13 +- src/core/hle/applets/erreula.cpp | 20 +- src/core/hle/applets/erreula.h | 3 +- src/core/hle/applets/mii_selector.cpp | 20 +- src/core/hle/applets/mii_selector.h | 3 +- src/core/hle/applets/mint.cpp | 20 +- src/core/hle/applets/mint.h | 3 +- src/core/hle/applets/swkbd.cpp | 20 +- src/core/hle/applets/swkbd.h | 3 +- src/core/hle/service/apt/applet_manager.cpp | 440 ++++++++++++++++ src/core/hle/service/apt/applet_manager.h | 178 +++++++ src/core/hle/service/apt/apt.cpp | 549 +++----------------- src/core/hle/service/apt/apt.h | 84 --- src/core/hle/service/apt/errors.h | 16 + src/core/hle/service/ns/ns.h | 1 + 17 files changed, 773 insertions(+), 623 deletions(-) create mode 100644 src/core/hle/service/apt/applet_manager.cpp create mode 100644 src/core/hle/service/apt/applet_manager.h create mode 100644 src/core/hle/service/apt/errors.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 8e16f8864..74d4bfbee 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -164,6 +164,8 @@ add_library(core STATIC hle/service/am/am_sys.h hle/service/am/am_u.cpp hle/service/am/am_u.h + hle/service/apt/applet_manager.cpp + hle/service/apt/applet_manager.h hle/service/apt/apt.cpp hle/service/apt/apt.h hle/service/apt/apt_a.cpp @@ -174,6 +176,7 @@ add_library(core STATIC hle/service/apt/apt_u.h hle/service/apt/bcfnt/bcfnt.cpp hle/service/apt/bcfnt/bcfnt.h + hle/service/apt/errors.h hle/service/boss/boss.cpp hle/service/boss/boss.h hle/service/boss/boss_p.cpp diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp index 496305205..7c8aedfeb 100644 --- a/src/core/hle/applets/applet.cpp +++ b/src/core/hle/applets/applet.cpp @@ -15,7 +15,6 @@ #include "core/hle/applets/mint.h" #include "core/hle/applets/swkbd.h" #include "core/hle/result.h" -#include "core/hle/service/apt/apt.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -43,23 +42,24 @@ static CoreTiming::EventType* applet_update_event = nullptr; /// The interval at which the Applet update callback will be called, 16.6ms static const u64 applet_update_interval_us = 16666; -ResultCode Applet::Create(Service::APT::AppletId id) { +ResultCode Applet::Create(Service::APT::AppletId id, + std::weak_ptr manager) { switch (id) { case Service::APT::AppletId::SoftwareKeyboard1: case Service::APT::AppletId::SoftwareKeyboard2: - applets[id] = std::make_shared(id); + applets[id] = std::make_shared(id, std::move(manager)); break; case Service::APT::AppletId::Ed1: case Service::APT::AppletId::Ed2: - applets[id] = std::make_shared(id); + applets[id] = std::make_shared(id, std::move(manager)); break; case Service::APT::AppletId::Error: case Service::APT::AppletId::Error2: - applets[id] = std::make_shared(id); + applets[id] = std::make_shared(id, std::move(manager)); break; case Service::APT::AppletId::Mint: case Service::APT::AppletId::Mint2: - applets[id] = std::make_shared(id); + applets[id] = std::make_shared(id, std::move(manager)); break; default: LOG_ERROR(Service_APT, "Could not create applet %u", static_cast(id)); @@ -110,6 +110,14 @@ bool Applet::IsRunning() const { return is_running; } +void Applet::SendParameter(const Service::APT::MessageParameter& parameter) { + if (auto locked = manager.lock()) { + locked->CancelAndSendParameter(parameter); + } else { + LOG_ERROR(Service_APT, "called after destructing applet manager"); + } +} + bool IsLibraryAppletRunning() { // Check the applets map for instances of any applet for (auto itr = applets.begin(); itr != applets.end(); ++itr) diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h index ebeed9813..317554b00 100644 --- a/src/core/hle/applets/applet.h +++ b/src/core/hle/applets/applet.h @@ -6,7 +6,7 @@ #include #include "core/hle/result.h" -#include "core/hle/service/apt/apt.h" +#include "core/hle/service/apt/applet_manager.h" namespace HLE { namespace Applets { @@ -21,7 +21,8 @@ public: * @param id Id of the applet to create. * @returns ResultCode Whether the operation was successful or not. */ - static ResultCode Create(Service::APT::AppletId id); + static ResultCode Create(Service::APT::AppletId id, + std::weak_ptr manager); /** * Retrieves the Applet instance identified by the specified id. @@ -55,7 +56,8 @@ public: virtual void Update() = 0; protected: - explicit Applet(Service::APT::AppletId id) : id(id) {} + Applet(Service::APT::AppletId id, std::weak_ptr manager) + : id(id), manager(std::move(manager)) {} /** * Handles the Applet start event, triggered from the application. @@ -69,6 +71,11 @@ protected: /// Whether this applet is currently running instead of the host application or not. bool is_running = false; + + void SendParameter(const Service::APT::MessageParameter& parameter); + +private: + std::weak_ptr manager; }; /// Returns whether a library applet is currently running diff --git a/src/core/hle/applets/erreula.cpp b/src/core/hle/applets/erreula.cpp index 518f371f5..f36ad54e1 100644 --- a/src/core/hle/applets/erreula.cpp +++ b/src/core/hle/applets/erreula.cpp @@ -10,8 +10,8 @@ namespace HLE { namespace Applets { ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& parameter) { - if (parameter.signal != static_cast(Service::APT::SignalType::Request)) { - LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); + if (parameter.signal != Service::APT::SignalType::Request) { + LOG_ERROR(Service_APT, "unsupported signal %u", static_cast(parameter.signal)); UNIMPLEMENTED(); // TODO(Subv): Find the right error code return ResultCode(-1); @@ -36,13 +36,13 @@ ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& param // Send the response message with the newly created SharedMemory Service::APT::MessageParameter result; - result.signal = static_cast(Service::APT::SignalType::Response); + result.signal = Service::APT::SignalType::Response; result.buffer.clear(); - result.destination_id = static_cast(Service::APT::AppletId::Application); - result.sender_id = static_cast(id); + result.destination_id = Service::APT::AppletId::Application; + result.sender_id = id; result.object = framebuffer_memory; - Service::APT::SendParameter(result); + SendParameter(result); return RESULT_SUCCESS; } @@ -57,10 +57,10 @@ ResultCode ErrEula::StartImpl(const Service::APT::AppletStartupParameter& parame Service::APT::MessageParameter message; message.buffer.resize(parameter.buffer.size()); std::fill(message.buffer.begin(), message.buffer.end(), 0); - message.signal = static_cast(Service::APT::SignalType::WakeupByExit); - message.destination_id = static_cast(Service::APT::AppletId::Application); - message.sender_id = static_cast(id); - Service::APT::SendParameter(message); + message.signal = Service::APT::SignalType::WakeupByExit; + message.destination_id = Service::APT::AppletId::Application; + message.sender_id = id; + SendParameter(message); is_running = false; return RESULT_SUCCESS; diff --git a/src/core/hle/applets/erreula.h b/src/core/hle/applets/erreula.h index 681bbea0c..0350a04b1 100644 --- a/src/core/hle/applets/erreula.h +++ b/src/core/hle/applets/erreula.h @@ -12,7 +12,8 @@ namespace Applets { class ErrEula final : public Applet { public: - explicit ErrEula(Service::APT::AppletId id) : Applet(id) {} + explicit ErrEula(Service::APT::AppletId id, std::weak_ptr manager) + : Applet(id, std::move(manager)) {} ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp index f225c23a5..2cb01f957 100644 --- a/src/core/hle/applets/mii_selector.cpp +++ b/src/core/hle/applets/mii_selector.cpp @@ -18,8 +18,8 @@ namespace HLE { namespace Applets { ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& parameter) { - if (parameter.signal != static_cast(Service::APT::SignalType::Request)) { - LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); + if (parameter.signal != Service::APT::SignalType::Request) { + LOG_ERROR(Service_APT, "unsupported signal %u", static_cast(parameter.signal)); UNIMPLEMENTED(); // TODO(Subv): Find the right error code return ResultCode(-1); @@ -43,13 +43,13 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p // Send the response message with the newly created SharedMemory Service::APT::MessageParameter result; - result.signal = static_cast(Service::APT::SignalType::Response); + result.signal = Service::APT::SignalType::Response; result.buffer.clear(); - result.destination_id = static_cast(Service::APT::AppletId::Application); - result.sender_id = static_cast(id); + result.destination_id = Service::APT::AppletId::Application; + result.sender_id = id; result.object = framebuffer_memory; - Service::APT::SendParameter(result); + SendParameter(result); return RESULT_SUCCESS; } @@ -72,10 +72,10 @@ ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& pa Service::APT::MessageParameter message; message.buffer.resize(sizeof(MiiResult)); std::memcpy(message.buffer.data(), &result, message.buffer.size()); - message.signal = static_cast(Service::APT::SignalType::WakeupByExit); - message.destination_id = static_cast(Service::APT::AppletId::Application); - message.sender_id = static_cast(id); - Service::APT::SendParameter(message); + message.signal = Service::APT::SignalType::WakeupByExit; + message.destination_id = Service::APT::AppletId::Application; + message.sender_id = id; + SendParameter(message); is_running = false; return RESULT_SUCCESS; diff --git a/src/core/hle/applets/mii_selector.h b/src/core/hle/applets/mii_selector.h index 136ce8948..c2f68da56 100644 --- a/src/core/hle/applets/mii_selector.h +++ b/src/core/hle/applets/mii_selector.h @@ -60,7 +60,8 @@ ASSERT_REG_POSITION(guest_mii_name, 0x6C); class MiiSelector final : public Applet { public: - MiiSelector(Service::APT::AppletId id) : Applet(id) {} + MiiSelector(Service::APT::AppletId id, std::weak_ptr manager) + : Applet(id, std::move(manager)) {} ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; diff --git a/src/core/hle/applets/mint.cpp b/src/core/hle/applets/mint.cpp index 50d79190b..a7132ac28 100644 --- a/src/core/hle/applets/mint.cpp +++ b/src/core/hle/applets/mint.cpp @@ -10,8 +10,8 @@ namespace HLE { namespace Applets { ResultCode Mint::ReceiveParameter(const Service::APT::MessageParameter& parameter) { - if (parameter.signal != static_cast(Service::APT::SignalType::Request)) { - LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); + if (parameter.signal != Service::APT::SignalType::Request) { + LOG_ERROR(Service_APT, "unsupported signal %u", static_cast(parameter.signal)); UNIMPLEMENTED(); // TODO(Subv): Find the right error code return ResultCode(-1); @@ -36,13 +36,13 @@ ResultCode Mint::ReceiveParameter(const Service::APT::MessageParameter& paramete // Send the response message with the newly created SharedMemory Service::APT::MessageParameter result; - result.signal = static_cast(Service::APT::SignalType::Response); + result.signal = Service::APT::SignalType::Response; result.buffer.clear(); - result.destination_id = static_cast(Service::APT::AppletId::Application); - result.sender_id = static_cast(id); + result.destination_id = Service::APT::AppletId::Application; + result.sender_id = id; result.object = framebuffer_memory; - Service::APT::SendParameter(result); + SendParameter(result); return RESULT_SUCCESS; } @@ -57,10 +57,10 @@ ResultCode Mint::StartImpl(const Service::APT::AppletStartupParameter& parameter Service::APT::MessageParameter message; message.buffer.resize(parameter.buffer.size()); std::fill(message.buffer.begin(), message.buffer.end(), 0); - message.signal = static_cast(Service::APT::SignalType::WakeupByExit); - message.destination_id = static_cast(Service::APT::AppletId::Application); - message.sender_id = static_cast(id); - Service::APT::SendParameter(message); + message.signal = Service::APT::SignalType::WakeupByExit; + message.destination_id = Service::APT::AppletId::Application; + message.sender_id = id; + SendParameter(message); is_running = false; return RESULT_SUCCESS; diff --git a/src/core/hle/applets/mint.h b/src/core/hle/applets/mint.h index d23dc40f9..dfe233399 100644 --- a/src/core/hle/applets/mint.h +++ b/src/core/hle/applets/mint.h @@ -12,7 +12,8 @@ namespace Applets { class Mint final : public Applet { public: - explicit Mint(Service::APT::AppletId id) : Applet(id) {} + explicit Mint(Service::APT::AppletId id, std::weak_ptr manager) + : Applet(id, std::move(manager)) {} ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp index 10b774c38..48a08798e 100644 --- a/src/core/hle/applets/swkbd.cpp +++ b/src/core/hle/applets/swkbd.cpp @@ -21,8 +21,8 @@ namespace HLE { namespace Applets { ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) { - if (parameter.signal != static_cast(Service::APT::SignalType::Request)) { - LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); + if (parameter.signal != Service::APT::SignalType::Request) { + LOG_ERROR(Service_APT, "unsupported signal %u", static_cast(parameter.signal)); UNIMPLEMENTED(); // TODO(Subv): Find the right error code return ResultCode(-1); @@ -46,13 +46,13 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con // Send the response message with the newly created SharedMemory Service::APT::MessageParameter result; - result.signal = static_cast(Service::APT::SignalType::Response); + result.signal = Service::APT::SignalType::Response; result.buffer.clear(); - result.destination_id = static_cast(Service::APT::AppletId::Application); - result.sender_id = static_cast(id); + result.destination_id = Service::APT::AppletId::Application; + result.sender_id = id; result.object = framebuffer_memory; - Service::APT::SendParameter(result); + SendParameter(result); return RESULT_SUCCESS; } @@ -107,10 +107,10 @@ void SoftwareKeyboard::Finalize() { Service::APT::MessageParameter message; message.buffer.resize(sizeof(SoftwareKeyboardConfig)); std::memcpy(message.buffer.data(), &config, message.buffer.size()); - message.signal = static_cast(Service::APT::SignalType::WakeupByExit); - message.destination_id = static_cast(Service::APT::AppletId::Application); - message.sender_id = static_cast(id); - Service::APT::SendParameter(message); + message.signal = Service::APT::SignalType::WakeupByExit; + message.destination_id = Service::APT::AppletId::Application; + message.sender_id = id; + SendParameter(message); is_running = false; } diff --git a/src/core/hle/applets/swkbd.h b/src/core/hle/applets/swkbd.h index cc92a8f19..f11dc45e4 100644 --- a/src/core/hle/applets/swkbd.h +++ b/src/core/hle/applets/swkbd.h @@ -52,7 +52,8 @@ static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config class SoftwareKeyboard final : public Applet { public: - SoftwareKeyboard(Service::APT::AppletId id) : Applet(id) {} + SoftwareKeyboard(Service::APT::AppletId id, std::weak_ptr manager) + : Applet(id, std::move(manager)) {} ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; diff --git a/src/core/hle/service/apt/applet_manager.cpp b/src/core/hle/service/apt/applet_manager.cpp new file mode 100644 index 000000000..d8a6d79b9 --- /dev/null +++ b/src/core/hle/service/apt/applet_manager.cpp @@ -0,0 +1,440 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/common_paths.h" +#include "core/hle/applets/applet.h" +#include "core/hle/service/apt/applet_manager.h" +#include "core/hle/service/apt/errors.h" +#include "core/hle/service/cfg/cfg.h" +#include "core/hle/service/ns/ns.h" + +namespace Service { +namespace APT { + +enum class AppletPos { Application = 0, Library = 1, System = 2, SysLibrary = 3, Resident = 4 }; + +struct AppletTitleData { + // There are two possible applet ids for each applet. + std::array applet_ids; + + // There's a specific TitleId per region for each applet. + static constexpr size_t NumRegions = 7; + std::array title_ids; +}; + +static constexpr size_t NumApplets = 29; +static constexpr std::array applet_titleids = {{ + {AppletId::HomeMenu, AppletId::None, 0x4003000008202, 0x4003000008F02, 0x4003000009802, + 0x4003000008202, 0x400300000A102, 0x400300000A902, 0x400300000B102}, + {AppletId::AlternateMenu, AppletId::None, 0x4003000008102, 0x4003000008102, 0x4003000008102, + 0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102}, + {AppletId::Camera, AppletId::None, 0x4003000008402, 0x4003000009002, 0x4003000009902, + 0x4003000008402, 0x400300000A202, 0x400300000AA02, 0x400300000B202}, + {AppletId::FriendList, AppletId::None, 0x4003000008D02, 0x4003000009602, 0x4003000009F02, + 0x4003000008D02, 0x400300000A702, 0x400300000AF02, 0x400300000B702}, + {AppletId::GameNotes, AppletId::None, 0x4003000008702, 0x4003000009302, 0x4003000009C02, + 0x4003000008702, 0x400300000A502, 0x400300000AD02, 0x400300000B502}, + {AppletId::InternetBrowser, AppletId::None, 0x4003000008802, 0x4003000009402, 0x4003000009D02, + 0x4003000008802, 0x400300000A602, 0x400300000AE02, 0x400300000B602}, + {AppletId::InstructionManual, AppletId::None, 0x4003000008602, 0x4003000009202, 0x4003000009B02, + 0x4003000008602, 0x400300000A402, 0x400300000AC02, 0x400300000B402}, + {AppletId::Notifications, AppletId::None, 0x4003000008E02, 0x4003000009702, 0x400300000A002, + 0x4003000008E02, 0x400300000A802, 0x400300000B002, 0x400300000B802}, + {AppletId::Miiverse, AppletId::None, 0x400300000BC02, 0x400300000BD02, 0x400300000BE02, + 0x400300000BC02, 0x4003000009E02, 0x4003000009502, 0x400300000B902}, + // These values obtained from an older NS dump firmware 4.5 + {AppletId::MiiversePost, AppletId::None, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02, + 0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02}, + // {AppletId::MiiversePost, AppletId::None, 0x4003000008302, 0x4003000008B02, 0x400300000BA02, + // 0x4003000008302, 0x0, 0x0, 0x0}, + {AppletId::AmiiboSettings, AppletId::None, 0x4003000009502, 0x4003000009E02, 0x400300000B902, + 0x4003000009502, 0x0, 0x4003000008C02, 0x400300000BF02}, + {AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2, 0x400300000C002, 0x400300000C802, + 0x400300000D002, 0x400300000C002, 0x400300000D802, 0x400300000DE02, 0x400300000E402}, + {AppletId::Ed1, AppletId::Ed2, 0x400300000C102, 0x400300000C902, 0x400300000D102, + 0x400300000C102, 0x400300000D902, 0x400300000DF02, 0x400300000E502}, + {AppletId::PnoteApp, AppletId::PnoteApp2, 0x400300000C302, 0x400300000CB02, 0x400300000D302, + 0x400300000C302, 0x400300000DB02, 0x400300000E102, 0x400300000E702}, + {AppletId::SnoteApp, AppletId::SnoteApp2, 0x400300000C402, 0x400300000CC02, 0x400300000D402, + 0x400300000C402, 0x400300000DC02, 0x400300000E202, 0x400300000E802}, + {AppletId::Error, AppletId::Error2, 0x400300000C502, 0x400300000C502, 0x400300000C502, + 0x400300000C502, 0x400300000CF02, 0x400300000CF02, 0x400300000CF02}, + {AppletId::Mint, AppletId::Mint2, 0x400300000C602, 0x400300000CE02, 0x400300000D602, + 0x400300000C602, 0x400300000DD02, 0x400300000E302, 0x400300000E902}, + {AppletId::Extrapad, AppletId::Extrapad2, 0x400300000CD02, 0x400300000CD02, 0x400300000CD02, + 0x400300000CD02, 0x400300000D502, 0x400300000D502, 0x400300000D502}, + {AppletId::Memolib, AppletId::Memolib2, 0x400300000F602, 0x400300000F602, 0x400300000F602, + 0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602}, + // TODO(Subv): Fill in the rest of the titleids +}}; + +static u64 GetTitleIdForApplet(AppletId id) { + ASSERT_MSG(id != AppletId::None, "Invalid applet id"); + + auto itr = std::find_if(applet_titleids.begin(), applet_titleids.end(), + [id](const AppletTitleData& data) { + return data.applet_ids[0] == id || data.applet_ids[1] == id; + }); + + ASSERT_MSG(itr != applet_titleids.end(), "Unknown applet id 0x%03X", static_cast(id)); + + return itr->title_ids[CFG::GetRegionValue()]; +} + +AppletManager::AppletSlotData* AppletManager::GetAppletSlotData(AppletId id) { + auto GetSlot = [this](AppletSlot slot) -> AppletSlotData* { + return &applet_slots[static_cast(slot)]; + }; + + if (id == AppletId::Application) { + auto* slot = GetSlot(AppletSlot::Application); + if (slot->applet_id != AppletId::None) + return slot; + + return nullptr; + } + + if (id == AppletId::AnySystemApplet) { + auto* system_slot = GetSlot(AppletSlot::SystemApplet); + if (system_slot->applet_id != AppletId::None) + return system_slot; + + // The Home Menu is also a system applet, but it lives in its own slot to be able to run + // concurrently with other system applets. + auto* home_slot = GetSlot(AppletSlot::HomeMenu); + if (home_slot->applet_id != AppletId::None) + return home_slot; + + return nullptr; + } + + if (id == AppletId::AnyLibraryApplet || id == AppletId::AnySysLibraryApplet) { + auto* slot = GetSlot(AppletSlot::LibraryApplet); + if (slot->applet_id == AppletId::None) + return nullptr; + + u32 applet_pos = slot->attributes.applet_pos; + + if (id == AppletId::AnyLibraryApplet && applet_pos == static_cast(AppletPos::Library)) + return slot; + + if (id == AppletId::AnySysLibraryApplet && + applet_pos == static_cast(AppletPos::SysLibrary)) + return slot; + + return nullptr; + } + + if (id == AppletId::HomeMenu || id == AppletId::AlternateMenu) { + auto* slot = GetSlot(AppletSlot::HomeMenu); + if (slot->applet_id != AppletId::None) + return slot; + + return nullptr; + } + + for (auto& slot : applet_slots) { + if (slot.applet_id == id) + return &slot; + } + + return nullptr; +} + +AppletManager::AppletSlotData* AppletManager::GetAppletSlotData(AppletAttributes attributes) { + // Mapping from AppletPos to AppletSlot + static constexpr std::array applet_position_slots = { + AppletSlot::Application, AppletSlot::LibraryApplet, AppletSlot::SystemApplet, + AppletSlot::LibraryApplet, AppletSlot::Error, AppletSlot::LibraryApplet}; + + u32 applet_pos = attributes.applet_pos; + if (applet_pos >= applet_position_slots.size()) + return nullptr; + + AppletSlot slot = applet_position_slots[applet_pos]; + + if (slot == AppletSlot::Error) + return nullptr; + + // The Home Menu is a system applet, however, it has its own applet slot so that it can run + // concurrently with other system applets. + if (slot == AppletSlot::SystemApplet && attributes.is_home_menu) + return &applet_slots[static_cast(AppletSlot::HomeMenu)]; + + return &applet_slots[static_cast(slot)]; +} + +void AppletManager::CancelAndSendParameter(const MessageParameter& parameter) { + next_parameter = parameter; + // Signal the event to let the receiver know that a new parameter is ready to be read + auto* const slot_data = GetAppletSlotData(static_cast(parameter.destination_id)); + if (slot_data == nullptr) { + LOG_DEBUG(Service_APT, "No applet was registered with the id %03X", + static_cast(parameter.destination_id)); + return; + } + + slot_data->parameter_event->Signal(); +} + +ResultCode AppletManager::SendParameter(const MessageParameter& parameter) { + // A new parameter can not be sent if the previous one hasn't been consumed yet + if (next_parameter) { + return ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status); + } + CancelAndSendParameter(parameter); + if (auto dest_applet = HLE::Applets::Applet::Get(parameter.destination_id)) { + return dest_applet->ReceiveParameter(parameter); + } else { + return RESULT_SUCCESS; + } +} + +ResultVal AppletManager::GlanceParameter(AppletId app_id) { + if (!next_parameter) { + return ResultCode(ErrorDescription::NoData, ErrorModule::Applet, ErrorSummary::InvalidState, + ErrorLevel::Status); + } + + if (next_parameter->destination_id != app_id) { + return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, + ErrorLevel::Status); + } + + MessageParameter parameter = *next_parameter; + + // Note: The NS module always clears the DSPSleep and DSPWakeup signals even in GlanceParameter. + if (next_parameter->signal == SignalType::DspSleep || + next_parameter->signal == SignalType::DspWakeup) + next_parameter = boost::none; + + return MakeResult(parameter); +} + +ResultVal AppletManager::ReceiveParameter(AppletId app_id) { + auto result = GlanceParameter(app_id); + if (result.Succeeded()) { + // Clear the parameter + next_parameter = boost::none; + } + return result; +} + +bool AppletManager::CancelParameter(bool check_sender, AppletId sender_appid, bool check_receiver, + AppletId receiver_appid) { + bool cancellation_success = true; + + if (!next_parameter) { + cancellation_success = false; + } else { + if (check_sender && next_parameter->sender_id != sender_appid) + cancellation_success = false; + + if (check_receiver && next_parameter->destination_id != receiver_appid) + cancellation_success = false; + } + + if (cancellation_success) + next_parameter = boost::none; + + return cancellation_success; +} + +ResultVal AppletManager::Initialize(AppletId app_id, + AppletAttributes attributes) { + auto* const slot_data = GetAppletSlotData(attributes); + + // Note: The real NS service does not check if the attributes value is valid before accessing + // the data in the array + ASSERT_MSG(slot_data, "Invalid application attributes"); + + if (slot_data->registered) { + return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status); + } + + slot_data->applet_id = static_cast(app_id); + slot_data->attributes.raw = attributes.raw; + + if (slot_data->applet_id == AppletId::Application || + slot_data->applet_id == AppletId::HomeMenu) { + // Initialize the APT parameter to wake up the application. + next_parameter.emplace(); + next_parameter->signal = SignalType::Wakeup; + next_parameter->sender_id = AppletId::None; + next_parameter->destination_id = app_id; + // Not signaling the parameter event will cause the application (or Home Menu) to hang + // during startup. In the real console, it is usually the Kernel and Home Menu who cause NS + // to signal the HomeMenu and Application parameter events, respectively. + slot_data->parameter_event->Signal(); + } + + return MakeResult( + {slot_data->notification_event, slot_data->parameter_event}); +} + +ResultCode AppletManager::Enable(AppletAttributes attributes) { + auto* const slot_data = GetAppletSlotData(attributes); + + if (!slot_data) { + return ResultCode(ErrCodes::InvalidAppletSlot, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status); + } + + slot_data->registered = true; + + return RESULT_SUCCESS; +} + +bool AppletManager::IsRegistered(AppletId app_id) { + const auto* slot_data = GetAppletSlotData(app_id); + + // Check if an LLE applet was registered first, then fallback to HLE applets + bool is_registered = slot_data && slot_data->registered; + + if (!is_registered) { + if (app_id == AppletId::AnyLibraryApplet) { + is_registered = HLE::Applets::IsLibraryAppletRunning(); + } else if (auto applet = HLE::Applets::Applet::Get(app_id)) { + // The applet exists, set it as registered. + is_registered = true; + } + } + + return is_registered; +} + +ResultCode AppletManager::PrepareToStartLibraryApplet(AppletId applet_id) { + // The real APT service returns an error if there's a pending APT parameter when this function + // is called. + if (next_parameter) { + return ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status); + } + + const auto& slot = applet_slots[static_cast(AppletSlot::LibraryApplet)]; + + if (slot.registered) { + return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status); + } + + auto process = NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id)); + if (process) { + return RESULT_SUCCESS; + } + + // If we weren't able to load the native applet title, try to fallback to an HLE implementation. + auto applet = HLE::Applets::Applet::Get(applet_id); + if (applet) { + LOG_WARNING(Service_APT, "applet has already been started id=%08X", + static_cast(applet_id)); + return RESULT_SUCCESS; + } else { + return HLE::Applets::Applet::Create(applet_id, shared_from_this()); + } +} + +ResultCode AppletManager::PreloadLibraryApplet(AppletId applet_id) { + const auto& slot = applet_slots[static_cast(AppletSlot::LibraryApplet)]; + + if (slot.registered) { + return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status); + } + + auto process = NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id)); + if (process) { + return RESULT_SUCCESS; + } + + // If we weren't able to load the native applet title, try to fallback to an HLE implementation. + auto applet = HLE::Applets::Applet::Get(applet_id); + if (applet) { + LOG_WARNING(Service_APT, "applet has already been started id=%08X", + static_cast(applet_id)); + return RESULT_SUCCESS; + } else { + return HLE::Applets::Applet::Create(applet_id, shared_from_this()); + } +} + +ResultCode AppletManager::FinishPreloadingLibraryApplet(AppletId applet_id) { + // TODO(Subv): This function should fail depending on the applet preparation state. + auto& slot = applet_slots[static_cast(AppletSlot::LibraryApplet)]; + slot.loaded = true; + return RESULT_SUCCESS; +} + +ResultCode AppletManager::StartLibraryApplet(AppletId applet_id, + Kernel::SharedPtr object, + const std::vector& buffer) { + MessageParameter param; + param.destination_id = applet_id; + param.sender_id = AppletId::Application; + param.object = object; + param.signal = SignalType::Wakeup; + param.buffer = buffer; + CancelAndSendParameter(param); + + // In case the applet is being HLEd, attempt to communicate with it. + if (auto applet = HLE::Applets::Applet::Get(applet_id)) { + AppletStartupParameter parameter; + parameter.object = object; + parameter.buffer = buffer; + return applet->Start(parameter); + } else { + return RESULT_SUCCESS; + } +} + +ResultVal AppletManager::GetAppletInfo(AppletId app_id) { + const auto* slot = GetAppletSlotData(app_id); + + if (slot == nullptr || !slot->registered) { + // See if there's an HLE applet and try to use it before erroring out. + auto hle_applet = HLE::Applets::Applet::Get(app_id); + if (hle_applet == nullptr) { + return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, + ErrorSummary::NotFound, ErrorLevel::Status); + } + LOG_WARNING(Service_APT, "Using HLE applet info for applet %03X", static_cast(app_id)); + // TODO(Subv): Get the title id for the current applet and write it in the response[2-3] + return MakeResult({0, Service::FS::MediaType::NAND, true, true, 0}); + } + + if (app_id == AppletId::Application) { + // TODO(Subv): Implement this once Application launching is implemented + LOG_ERROR(Service_APT, "Unimplemented GetAppletInfo(Application)"); + return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, + ErrorLevel::Status); + } + + return MakeResult({GetTitleIdForApplet(app_id), Service::FS::MediaType::NAND, + slot->registered, slot->loaded, slot->attributes.raw}); +} + +AppletManager::AppletManager() { + for (size_t slot = 0; slot < applet_slots.size(); ++slot) { + auto& slot_data = applet_slots[slot]; + slot_data.slot = static_cast(slot); + slot_data.applet_id = AppletId::None; + slot_data.attributes.raw = 0; + slot_data.registered = false; + slot_data.loaded = false; + slot_data.notification_event = + Kernel::Event::Create(Kernel::ResetType::OneShot, "APT:Notification"); + slot_data.parameter_event = + Kernel::Event::Create(Kernel::ResetType::OneShot, "APT:Parameter"); + } + HLE::Applets::Init(); +} + +AppletManager::~AppletManager() { + HLE::Applets::Shutdown(); +} + +} // namespace APT +} // namespace Service diff --git a/src/core/hle/service/apt/applet_manager.h b/src/core/hle/service/apt/applet_manager.h new file mode 100644 index 000000000..7c07b5627 --- /dev/null +++ b/src/core/hle/service/apt/applet_manager.h @@ -0,0 +1,178 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include "core/hle/kernel/event.h" +#include "core/hle/result.h" +#include "core/hle/service/fs/archive.h" + +namespace Service { +namespace APT { + +/// Signals used by APT functions +enum class SignalType : 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, +}; + +/// App Id's used by APT functions +enum class AppletId : u32 { + None = 0, + AnySystemApplet = 0x100, + HomeMenu = 0x101, + AlternateMenu = 0x103, + Camera = 0x110, + FriendList = 0x112, + GameNotes = 0x113, + InternetBrowser = 0x114, + InstructionManual = 0x115, + Notifications = 0x116, + Miiverse = 0x117, + MiiversePost = 0x118, + AmiiboSettings = 0x119, + AnySysLibraryApplet = 0x200, + SoftwareKeyboard1 = 0x201, + Ed1 = 0x202, + PnoteApp = 0x204, + SnoteApp = 0x205, + Error = 0x206, + Mint = 0x207, + Extrapad = 0x208, + Memolib = 0x209, + Application = 0x300, + Tiger = 0x301, + AnyLibraryApplet = 0x400, + SoftwareKeyboard2 = 0x401, + Ed2 = 0x402, + PnoteApp2 = 0x404, + SnoteApp2 = 0x405, + Error2 = 0x406, + Mint2 = 0x407, + Extrapad2 = 0x408, + Memolib2 = 0x409, +}; + +/// Holds information about the parameters used in Send/Glance/ReceiveParameter +struct MessageParameter { + AppletId sender_id = AppletId::None; + AppletId destination_id = AppletId::None; + SignalType signal = SignalType::None; + Kernel::SharedPtr object = nullptr; + std::vector buffer; +}; + +/// Holds information about the parameters used in StartLibraryApplet +struct AppletStartupParameter { + Kernel::SharedPtr object = nullptr; + std::vector buffer; +}; + +union AppletAttributes { + u32 raw; + + BitField<0, 3, u32> applet_pos; + BitField<29, 1, u32> is_home_menu; + + AppletAttributes() : raw(0) {} + AppletAttributes(u32 attributes) : raw(attributes) {} +}; + +class AppletManager : public std::enable_shared_from_this { +public: + AppletManager(); + ~AppletManager(); + + /** + * Clears any existing parameter and places a new one. This function is currently only used by + * HLE Applets and should be likely removed in the future + */ + void CancelAndSendParameter(const MessageParameter& parameter); + + ResultCode SendParameter(const MessageParameter& parameter); + ResultVal GlanceParameter(AppletId app_id); + ResultVal ReceiveParameter(AppletId app_id); + bool CancelParameter(bool check_sender, AppletId sender_appid, bool check_receiver, + AppletId receiver_appid); + + struct InitializeResult { + Kernel::SharedPtr notification_event; + Kernel::SharedPtr parameter_event; + }; + + ResultVal Initialize(AppletId app_id, AppletAttributes attributes); + ResultCode Enable(AppletAttributes attributes); + bool IsRegistered(AppletId app_id); + ResultCode PrepareToStartLibraryApplet(AppletId applet_id); + ResultCode PreloadLibraryApplet(AppletId applet_id); + ResultCode FinishPreloadingLibraryApplet(AppletId applet_id); + ResultCode StartLibraryApplet(AppletId applet_id, Kernel::SharedPtr object, + const std::vector& buffer); + + struct AppletInfo { + u64 title_id; + Service::FS::MediaType media_type; + bool registered; + bool loaded; + u32 attributes; + }; + + ResultVal GetAppletInfo(AppletId app_id); + +private: + /// Parameter data to be returned in the next call to Glance/ReceiveParameter. + /// TODO(Subv): Use std::optional once we migrate to C++17. + boost::optional next_parameter; + + static constexpr size_t NumAppletSlot = 4; + + enum class AppletSlot : u8 { + Application, + SystemApplet, + HomeMenu, + LibraryApplet, + + // An invalid tag + Error, + }; + + struct AppletSlotData { + AppletId applet_id; + AppletSlot slot; + bool registered; + bool loaded; + AppletAttributes attributes; + Kernel::SharedPtr notification_event; + Kernel::SharedPtr parameter_event; + }; + + // Holds data about the concurrently running applets in the system. + std::array applet_slots = {}; + + // This overload returns nullptr if no applet with the specified id has been started. + AppletSlotData* GetAppletSlotData(AppletId id); + AppletSlotData* GetAppletSlotData(AppletAttributes attributes); +}; + +} // namespace APT +} // namespace Service diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 21a29083a..c88e14560 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -2,18 +2,17 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include #include "common/common_paths.h" #include "common/file_util.h" #include "common/logging/log.h" #include "core/core.h" #include "core/file_sys/file_backend.h" #include "core/hle/applets/applet.h" -#include "core/hle/kernel/event.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/romfs.h" +#include "core/hle/service/apt/applet_manager.h" #include "core/hle/service/apt/apt.h" #include "core/hle/service/apt/apt_a.h" #include "core/hle/service/apt/apt_s.h" @@ -21,7 +20,6 @@ #include "core/hle/service/apt/bcfnt/bcfnt.h" #include "core/hle/service/cfg/cfg.h" #include "core/hle/service/fs/archive.h" -#include "core/hle/service/ns/ns.h" #include "core/hle/service/ptm/ptm.h" #include "core/hle/service/service.h" #include "core/hw/aes/ccm.h" @@ -44,251 +42,26 @@ static u8 unknown_ns_state_field; static ScreencapPostPermission screen_capture_post_permission; -/// Parameter data to be returned in the next call to Glance/ReceiveParameter. -/// TODO(Subv): Use std::optional once we migrate to C++17. -static boost::optional next_parameter; - -enum class AppletPos { Application = 0, Library = 1, System = 2, SysLibrary = 3, Resident = 4 }; - -static constexpr size_t NumAppletSlot = 4; - -enum class AppletSlot : u8 { - Application, - SystemApplet, - HomeMenu, - LibraryApplet, - - // An invalid tag - Error, -}; - -union AppletAttributes { - u32 raw; - - BitField<0, 3, u32> applet_pos; - BitField<29, 1, u32> is_home_menu; - - AppletAttributes() : raw(0) {} - AppletAttributes(u32 attributes) : raw(attributes) {} -}; - -struct AppletSlotData { - AppletId applet_id; - AppletSlot slot; - bool registered; - bool loaded; - AppletAttributes attributes; - Kernel::SharedPtr notification_event; - Kernel::SharedPtr parameter_event; -}; - -// Holds data about the concurrently running applets in the system. -static std::array applet_slots = {}; - -struct AppletTitleData { - // There are two possible applet ids for each applet. - std::array applet_ids; - - // There's a specific TitleId per region for each applet. - static constexpr size_t NumRegions = 7; - std::array title_ids; -}; - -static constexpr size_t NumApplets = 29; -static constexpr std::array applet_titleids = {{ - {AppletId::HomeMenu, AppletId::None, 0x4003000008202, 0x4003000008F02, 0x4003000009802, - 0x4003000008202, 0x400300000A102, 0x400300000A902, 0x400300000B102}, - {AppletId::AlternateMenu, AppletId::None, 0x4003000008102, 0x4003000008102, 0x4003000008102, - 0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102}, - {AppletId::Camera, AppletId::None, 0x4003000008402, 0x4003000009002, 0x4003000009902, - 0x4003000008402, 0x400300000A202, 0x400300000AA02, 0x400300000B202}, - {AppletId::FriendList, AppletId::None, 0x4003000008D02, 0x4003000009602, 0x4003000009F02, - 0x4003000008D02, 0x400300000A702, 0x400300000AF02, 0x400300000B702}, - {AppletId::GameNotes, AppletId::None, 0x4003000008702, 0x4003000009302, 0x4003000009C02, - 0x4003000008702, 0x400300000A502, 0x400300000AD02, 0x400300000B502}, - {AppletId::InternetBrowser, AppletId::None, 0x4003000008802, 0x4003000009402, 0x4003000009D02, - 0x4003000008802, 0x400300000A602, 0x400300000AE02, 0x400300000B602}, - {AppletId::InstructionManual, AppletId::None, 0x4003000008602, 0x4003000009202, 0x4003000009B02, - 0x4003000008602, 0x400300000A402, 0x400300000AC02, 0x400300000B402}, - {AppletId::Notifications, AppletId::None, 0x4003000008E02, 0x4003000009702, 0x400300000A002, - 0x4003000008E02, 0x400300000A802, 0x400300000B002, 0x400300000B802}, - {AppletId::Miiverse, AppletId::None, 0x400300000BC02, 0x400300000BD02, 0x400300000BE02, - 0x400300000BC02, 0x4003000009E02, 0x4003000009502, 0x400300000B902}, - // These values obtained from an older NS dump firmware 4.5 - {AppletId::MiiversePost, AppletId::None, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02, - 0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02}, - // {AppletId::MiiversePost, AppletId::None, 0x4003000008302, 0x4003000008B02, 0x400300000BA02, - // 0x4003000008302, 0x0, 0x0, 0x0}, - {AppletId::AmiiboSettings, AppletId::None, 0x4003000009502, 0x4003000009E02, 0x400300000B902, - 0x4003000009502, 0x0, 0x4003000008C02, 0x400300000BF02}, - {AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2, 0x400300000C002, 0x400300000C802, - 0x400300000D002, 0x400300000C002, 0x400300000D802, 0x400300000DE02, 0x400300000E402}, - {AppletId::Ed1, AppletId::Ed2, 0x400300000C102, 0x400300000C902, 0x400300000D102, - 0x400300000C102, 0x400300000D902, 0x400300000DF02, 0x400300000E502}, - {AppletId::PnoteApp, AppletId::PnoteApp2, 0x400300000C302, 0x400300000CB02, 0x400300000D302, - 0x400300000C302, 0x400300000DB02, 0x400300000E102, 0x400300000E702}, - {AppletId::SnoteApp, AppletId::SnoteApp2, 0x400300000C402, 0x400300000CC02, 0x400300000D402, - 0x400300000C402, 0x400300000DC02, 0x400300000E202, 0x400300000E802}, - {AppletId::Error, AppletId::Error2, 0x400300000C502, 0x400300000C502, 0x400300000C502, - 0x400300000C502, 0x400300000CF02, 0x400300000CF02, 0x400300000CF02}, - {AppletId::Mint, AppletId::Mint2, 0x400300000C602, 0x400300000CE02, 0x400300000D602, - 0x400300000C602, 0x400300000DD02, 0x400300000E302, 0x400300000E902}, - {AppletId::Extrapad, AppletId::Extrapad2, 0x400300000CD02, 0x400300000CD02, 0x400300000CD02, - 0x400300000CD02, 0x400300000D502, 0x400300000D502, 0x400300000D502}, - {AppletId::Memolib, AppletId::Memolib2, 0x400300000F602, 0x400300000F602, 0x400300000F602, - 0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602}, - // TODO(Subv): Fill in the rest of the titleids -}}; - -static u64 GetTitleIdForApplet(AppletId id) { - ASSERT_MSG(id != AppletId::None, "Invalid applet id"); - - auto itr = std::find_if(applet_titleids.begin(), applet_titleids.end(), - [id](const AppletTitleData& data) { - return data.applet_ids[0] == id || data.applet_ids[1] == id; - }); - - ASSERT_MSG(itr != applet_titleids.end(), "Unknown applet id 0x%03X", static_cast(id)); - - return itr->title_ids[CFG::GetRegionValue()]; -} - -// This overload returns nullptr if no applet with the specified id has been started. -static AppletSlotData* GetAppletSlotData(AppletId id) { - auto GetSlot = [](AppletSlot slot) -> AppletSlotData* { - return &applet_slots[static_cast(slot)]; - }; - - if (id == AppletId::Application) { - auto* slot = GetSlot(AppletSlot::Application); - if (slot->applet_id != AppletId::None) - return slot; - - return nullptr; - } - - if (id == AppletId::AnySystemApplet) { - auto* system_slot = GetSlot(AppletSlot::SystemApplet); - if (system_slot->applet_id != AppletId::None) - return system_slot; - - // The Home Menu is also a system applet, but it lives in its own slot to be able to run - // concurrently with other system applets. - auto* home_slot = GetSlot(AppletSlot::HomeMenu); - if (home_slot->applet_id != AppletId::None) - return home_slot; - - return nullptr; - } - - if (id == AppletId::AnyLibraryApplet || id == AppletId::AnySysLibraryApplet) { - auto* slot = GetSlot(AppletSlot::LibraryApplet); - if (slot->applet_id == AppletId::None) - return nullptr; - - u32 applet_pos = slot->attributes.applet_pos; - - if (id == AppletId::AnyLibraryApplet && applet_pos == static_cast(AppletPos::Library)) - return slot; - - if (id == AppletId::AnySysLibraryApplet && - applet_pos == static_cast(AppletPos::SysLibrary)) - return slot; - - return nullptr; - } - - if (id == AppletId::HomeMenu || id == AppletId::AlternateMenu) { - auto* slot = GetSlot(AppletSlot::HomeMenu); - if (slot->applet_id != AppletId::None) - return slot; - - return nullptr; - } - - for (auto& slot : applet_slots) { - if (slot.applet_id == id) - return &slot; - } - - return nullptr; -} - -static AppletSlotData* GetAppletSlotData(AppletAttributes attributes) { - // Mapping from AppletPos to AppletSlot - static constexpr std::array applet_position_slots = { - AppletSlot::Application, AppletSlot::LibraryApplet, AppletSlot::SystemApplet, - AppletSlot::LibraryApplet, AppletSlot::Error, AppletSlot::LibraryApplet}; - - u32 applet_pos = attributes.applet_pos; - if (applet_pos >= applet_position_slots.size()) - return nullptr; - - AppletSlot slot = applet_position_slots[applet_pos]; - - if (slot == AppletSlot::Error) - return nullptr; - - // The Home Menu is a system applet, however, it has its own applet slot so that it can run - // concurrently with other system applets. - if (slot == AppletSlot::SystemApplet && attributes.is_home_menu) - return &applet_slots[static_cast(AppletSlot::HomeMenu)]; - - return &applet_slots[static_cast(slot)]; -} - -void SendParameter(const MessageParameter& parameter) { - next_parameter = parameter; - // Signal the event to let the receiver know that a new parameter is ready to be read - auto* const slot_data = GetAppletSlotData(static_cast(parameter.destination_id)); - if (slot_data == nullptr) { - LOG_DEBUG(Service_APT, "No applet was registered with the id %03X", - parameter.destination_id); - return; - } - - slot_data->parameter_event->Signal(); -} +static std::shared_ptr applet_manager; void Initialize(Service::Interface* self) { IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x2, 2, 0); // 0x20080 - u32 app_id = rp.Pop(); + AppletId app_id = rp.PopEnum(); u32 attributes = rp.Pop(); - LOG_DEBUG(Service_APT, "called app_id=0x%08X, attributes=0x%08X", app_id, attributes); + LOG_DEBUG(Service_APT, "called app_id=0x%08X, attributes=0x%08X", static_cast(app_id), + attributes); - auto* const slot_data = GetAppletSlotData(attributes); - - // Note: The real NS service does not check if the attributes value is valid before accessing - // the data in the array - ASSERT_MSG(slot_data, "Invalid application attributes"); - - if (slot_data->registered) { + auto result = applet_manager->Initialize(app_id, attributes); + if (result.Failed()) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, - ErrorSummary::InvalidState, ErrorLevel::Status)); - return; - } - - slot_data->applet_id = static_cast(app_id); - slot_data->attributes.raw = attributes; - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); - rb.Push(RESULT_SUCCESS); - rb.PushCopyHandles(Kernel::g_handle_table.Create(slot_data->notification_event).Unwrap(), - Kernel::g_handle_table.Create(slot_data->parameter_event).Unwrap()); - - if (slot_data->applet_id == AppletId::Application || - slot_data->applet_id == AppletId::HomeMenu) { - // Initialize the APT parameter to wake up the application. - next_parameter.emplace(); - next_parameter->signal = static_cast(SignalType::Wakeup); - next_parameter->sender_id = static_cast(AppletId::None); - next_parameter->destination_id = app_id; - // Not signaling the parameter event will cause the application (or Home Menu) to hang - // during startup. In the real console, it is usually the Kernel and Home Menu who cause NS - // to signal the HomeMenu and Application parameter events, respectively. - slot_data->parameter_event->Signal(); + rb.Push(result.Code()); + } else { + auto events = std::move(result).Unwrap(); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); + rb.Push(RESULT_SUCCESS); + rb.PushCopyHandles(Kernel::g_handle_table.Create(events.notification_event).Unwrap(), + Kernel::g_handle_table.Create(events.parameter_event).Unwrap()); } } @@ -508,18 +281,7 @@ void Enable(Service::Interface* self) { LOG_DEBUG(Service_APT, "called attributes=0x%08X", attributes); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - - auto* const slot_data = GetAppletSlotData(attributes); - - if (!slot_data) { - rb.Push(ResultCode(ErrCodes::InvalidAppletSlot, ErrorModule::Applet, - ErrorSummary::InvalidState, ErrorLevel::Status)); - return; - } - - slot_data->registered = true; - - rb.Push(RESULT_SUCCESS); + rb.Push(applet_manager->Enable(attributes)); } void GetAppletManInfo(Service::Interface* self) { @@ -540,22 +302,7 @@ void IsRegistered(Service::Interface* self) { AppletId app_id = static_cast(rp.Pop()); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); // No error - - const auto* slot_data = GetAppletSlotData(app_id); - - // Check if an LLE applet was registered first, then fallback to HLE applets - bool is_registered = slot_data && slot_data->registered; - - if (!is_registered) { - if (app_id == AppletId::AnyLibraryApplet) { - is_registered = HLE::Applets::IsLibraryAppletRunning(); - } else if (auto applet = HLE::Applets::Applet::Get(app_id)) { - // The applet exists, set it as registered. - is_registered = true; - } - } - - rb.Push(is_registered); + rb.Push(applet_manager->IsRegistered(app_id)); LOG_DEBUG(Service_APT, "called app_id=0x%08X", static_cast(app_id)); } @@ -571,9 +318,9 @@ void InquireNotification(Service::Interface* self) { void SendParameter(Service::Interface* self) { IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xC, 4, 4); // 0xC0104 - u32 src_app_id = rp.Pop(); - u32 dst_app_id = rp.Pop(); - u32 signal_type = rp.Pop(); + AppletId src_app_id = rp.PopEnum(); + AppletId dst_app_id = rp.PopEnum(); + SignalType signal_type = rp.PopEnum(); u32 buffer_size = rp.Pop(); Kernel::Handle handle = rp.PopHandle(); size_t size; @@ -582,17 +329,11 @@ void SendParameter(Service::Interface* self) { LOG_DEBUG(Service_APT, "called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," "buffer_size=0x%08X, handle=0x%08X, size=0x%08zX, in_param_buffer_ptr=0x%08X", - src_app_id, dst_app_id, signal_type, buffer_size, handle, size, buffer); + static_cast(src_app_id), static_cast(dst_app_id), + static_cast(signal_type), buffer_size, handle, size, buffer); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - // A new parameter can not be sent if the previous one hasn't been consumed yet - if (next_parameter) { - rb.Push(ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet, - ErrorSummary::InvalidState, ErrorLevel::Status)); - return; - } - MessageParameter param; param.destination_id = dst_app_id; param.sender_id = src_app_id; @@ -601,19 +342,12 @@ void SendParameter(Service::Interface* self) { param.buffer.resize(buffer_size); Memory::ReadBlock(buffer, param.buffer.data(), param.buffer.size()); - SendParameter(param); - - // If the applet is running in HLE mode, use the HLE interface to communicate with it. - if (auto dest_applet = HLE::Applets::Applet::Get(static_cast(dst_app_id))) { - rb.Push(dest_applet->ReceiveParameter(param)); - } else { - rb.Push(RESULT_SUCCESS); - } + rb.Push(applet_manager->SendParameter(param)); } void ReceiveParameter(Service::Interface* self) { IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xD, 2, 0); // 0xD0080 - u32 app_id = rp.Pop(); + AppletId app_id = rp.PopEnum(); u32 buffer_size = rp.Pop(); size_t static_buff_size; @@ -624,27 +358,22 @@ void ReceiveParameter(Service::Interface* self) { "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", buffer_size, static_buff_size); - LOG_DEBUG(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); + LOG_DEBUG(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", static_cast(app_id), + buffer_size); - if (!next_parameter) { - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::Applet, - ErrorSummary::InvalidState, ErrorLevel::Status)); - return; - } + auto next_parameter = applet_manager->ReceiveParameter(app_id); - if (next_parameter->destination_id != app_id) { + if (next_parameter.Failed()) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, - ErrorLevel::Status)); + rb.Push(next_parameter.Code()); return; } IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); rb.Push(RESULT_SUCCESS); // No error - rb.Push(next_parameter->sender_id); - rb.Push(next_parameter->signal); // Signal type + rb.PushEnum(next_parameter->sender_id); + rb.PushEnum(next_parameter->signal); // Signal type ASSERT_MSG(next_parameter->buffer.size() <= buffer_size, "Input static buffer is too small !"); rb.Push(static_cast(next_parameter->buffer.size())); // Parameter buffer size @@ -655,14 +384,11 @@ void ReceiveParameter(Service::Interface* self) { rb.PushStaticBuffer(buffer, next_parameter->buffer.size(), 0); Memory::WriteBlock(buffer, next_parameter->buffer.data(), next_parameter->buffer.size()); - - // Clear the parameter - next_parameter = boost::none; } void GlanceParameter(Service::Interface* self) { IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xE, 2, 0); // 0xE0080 - u32 app_id = rp.Pop(); + AppletId app_id = rp.PopEnum(); u32 buffer_size = rp.Pop(); size_t static_buff_size; @@ -673,26 +399,21 @@ void GlanceParameter(Service::Interface* self) { "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", buffer_size, static_buff_size); - LOG_DEBUG(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); + LOG_DEBUG(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", static_cast(app_id), + buffer_size); - if (!next_parameter) { - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::Applet, - ErrorSummary::InvalidState, ErrorLevel::Status)); - return; - } + auto next_parameter = applet_manager->GlanceParameter(app_id); - if (next_parameter->destination_id != app_id) { + if (next_parameter.Failed()) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, - ErrorLevel::Status)); + rb.Push(next_parameter.Code()); return; } IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); rb.Push(RESULT_SUCCESS); // No error - rb.Push(next_parameter->sender_id); - rb.Push(next_parameter->signal); // Signal type + rb.PushEnum(next_parameter->sender_id); + rb.PushEnum(next_parameter->signal); // Signal type ASSERT_MSG(next_parameter->buffer.size() <= buffer_size, "Input static buffer is too small !"); rb.Push(static_cast(next_parameter->buffer.size())); // Parameter buffer size @@ -703,44 +424,26 @@ void GlanceParameter(Service::Interface* self) { rb.PushStaticBuffer(buffer, next_parameter->buffer.size(), 0); Memory::WriteBlock(buffer, next_parameter->buffer.data(), next_parameter->buffer.size()); - - // Note: The NS module always clears the DSPSleep and DSPWakeup signals even in GlanceParameter. - if (next_parameter->signal == static_cast(SignalType::DspSleep) || - next_parameter->signal == static_cast(SignalType::DspWakeup)) - next_parameter = boost::none; } void CancelParameter(Service::Interface* self) { IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xF, 4, 0); // 0xF0100 bool check_sender = rp.Pop(); - u32 sender_appid = rp.Pop(); + AppletId sender_appid = rp.PopEnum(); bool check_receiver = rp.Pop(); - u32 receiver_appid = rp.Pop(); - - bool cancellation_success = true; - - if (!next_parameter) { - cancellation_success = false; - } else { - if (check_sender && next_parameter->sender_id != sender_appid) - cancellation_success = false; - - if (check_receiver && next_parameter->destination_id != receiver_appid) - cancellation_success = false; - } - - if (cancellation_success) - next_parameter = boost::none; + AppletId receiver_appid = rp.PopEnum(); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); // No error - rb.Push(cancellation_success); + rb.Push(applet_manager->CancelParameter(check_sender, sender_appid, check_receiver, + receiver_appid)); LOG_DEBUG(Service_APT, "called check_sender=%u, sender_appid=0x%08X, " "check_receiver=%u, receiver_appid=0x%08X", - check_sender, sender_appid, check_receiver, receiver_appid); + check_sender, static_cast(sender_appid), check_receiver, + static_cast(receiver_appid)); } void PrepareToStartApplication(Service::Interface* self) { @@ -840,38 +543,7 @@ void PrepareToStartLibraryApplet(Service::Interface* self) { LOG_DEBUG(Service_APT, "called applet_id=%08X", static_cast(applet_id)); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - - // The real APT service returns an error if there's a pending APT parameter when this function - // is called. - if (next_parameter) { - rb.Push(ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet, - ErrorSummary::InvalidState, ErrorLevel::Status)); - return; - } - - const auto& slot = applet_slots[static_cast(AppletSlot::LibraryApplet)]; - - if (slot.registered) { - rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, - ErrorSummary::InvalidState, ErrorLevel::Status)); - return; - } - - auto process = NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id)); - if (process) { - rb.Push(RESULT_SUCCESS); - return; - } - - // If we weren't able to load the native applet title, try to fallback to an HLE implementation. - auto applet = HLE::Applets::Applet::Get(applet_id); - if (applet) { - LOG_WARNING(Service_APT, "applet has already been started id=%08X", - static_cast(applet_id)); - rb.Push(RESULT_SUCCESS); - } else { - rb.Push(HLE::Applets::Applet::Create(applet_id)); - } + rb.Push(applet_manager->PrepareToStartLibraryApplet(applet_id)); } void PrepareToStartNewestHomeMenu(Service::Interface* self) { @@ -895,42 +567,15 @@ void PreloadLibraryApplet(Service::Interface* self) { LOG_DEBUG(Service_APT, "called applet_id=%08X", static_cast(applet_id)); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - - const auto& slot = applet_slots[static_cast(AppletSlot::LibraryApplet)]; - - if (slot.registered) { - rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, - ErrorSummary::InvalidState, ErrorLevel::Status)); - return; - } - - auto process = NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id)); - if (process) { - rb.Push(RESULT_SUCCESS); - return; - } - - // If we weren't able to load the native applet title, try to fallback to an HLE implementation. - auto applet = HLE::Applets::Applet::Get(applet_id); - if (applet) { - LOG_WARNING(Service_APT, "applet has already been started id=%08X", - static_cast(applet_id)); - rb.Push(RESULT_SUCCESS); - } else { - rb.Push(HLE::Applets::Applet::Create(applet_id)); - } + rb.Push(applet_manager->PreloadLibraryApplet(applet_id)); } void FinishPreloadingLibraryApplet(Service::Interface* self) { IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x17, 1, 0); // 0x00170040 AppletId applet_id = static_cast(rp.Pop()); - // TODO(Subv): This function should fail depending on the applet preparation state. - auto& slot = applet_slots[static_cast(AppletSlot::LibraryApplet)]; - slot.loaded = true; - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(RESULT_SUCCESS); + rb.Push(applet_manager->FinishPreloadingLibraryApplet(applet_id)); LOG_WARNING(Service_APT, "(STUBBED) called applet_id=%03X", static_cast(applet_id)); } @@ -947,26 +592,11 @@ void StartLibraryApplet(Service::Interface* self) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - // Send the Wakeup signal to the applet - MessageParameter param; - param.destination_id = static_cast(applet_id); - param.sender_id = static_cast(AppletId::Application); - param.object = Kernel::g_handle_table.GetGeneric(handle); - param.signal = static_cast(SignalType::Wakeup); - param.buffer.resize(buffer_size); - Memory::ReadBlock(buffer_addr, param.buffer.data(), param.buffer.size()); - SendParameter(param); + std::vector buffer(buffer_size); + Memory::ReadBlock(buffer_addr, buffer.data(), buffer.size()); - // In case the applet is being HLEd, attempt to communicate with it. - if (auto applet = HLE::Applets::Applet::Get(applet_id)) { - AppletStartupParameter parameter; - parameter.object = Kernel::g_handle_table.GetGeneric(handle); - parameter.buffer.resize(buffer_size); - Memory::ReadBlock(buffer_addr, parameter.buffer.data(), parameter.buffer.size()); - rb.Push(applet->Start(parameter)); - } else { - rb.Push(RESULT_SUCCESS); - } + rb.Push(applet_manager->StartLibraryApplet(applet_id, Kernel::g_handle_table.GetGeneric(handle), + buffer)); } void CancelLibraryApplet(Service::Interface* self) { @@ -1006,48 +636,19 @@ void GetAppletInfo(Service::Interface* self) { LOG_DEBUG(Service_APT, "called appid=%u", static_cast(app_id)); - const auto* slot = GetAppletSlotData(app_id); - - if (slot == nullptr || !slot->registered) { - // See if there's an HLE applet and try to use it before erroring out. - auto hle_applet = HLE::Applets::Applet::Get(app_id); - if (hle_applet == nullptr) { - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, - ErrorSummary::NotFound, ErrorLevel::Status)); - return; - } - - // TODO(Subv): Get the title id for the current applet and write it in the response[2-3] + auto info = applet_manager->GetAppletInfo(app_id); + if (info.Failed()) { + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(info.Code()); + } else { IPC::RequestBuilder rb = rp.MakeBuilder(7, 0); rb.Push(RESULT_SUCCESS); - u64 title_id = 0; - rb.Push(title_id); - rb.Push(static_cast(Service::FS::MediaType::NAND)); - rb.Push(true); // Registered - rb.Push(true); // Loaded - rb.Push(0); // Applet Attributes - LOG_WARNING(Service_APT, "Using HLE applet info for applet %03X", static_cast(app_id)); - return; + rb.Push(info->title_id); + rb.Push(static_cast(info->media_type)); + rb.Push(info->registered); + rb.Push(info->loaded); + rb.Push(info->attributes); } - - if (app_id == AppletId::Application) { - // TODO(Subv): Implement this once Application launching is implemented - LOG_ERROR(Service_APT, "Unimplemented GetAppletInfo(Application)"); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, - ErrorLevel::Status)); - return; - } - - IPC::RequestBuilder rb = rp.MakeBuilder(7, 0); - rb.Push(RESULT_SUCCESS); - rb.Push(GetTitleIdForApplet(app_id)); - // Note: The NS service hardcodes this to NAND for all applets except the Application applet. - rb.Push(static_cast(Service::FS::MediaType::NAND)); - rb.Push(slot->registered); - rb.Push(slot->loaded); - rb.Push(slot->attributes.raw); } void GetStartupArgument(Service::Interface* self) { @@ -1213,7 +814,7 @@ void Init() { AddService(new APT_S_Interface); AddService(new APT_U_Interface); - HLE::Applets::Init(); + applet_manager = std::make_shared(); using Kernel::MemoryPermission; shared_font_mem = @@ -1227,19 +828,6 @@ void Init() { unknown_ns_state_field = 0; screen_capture_post_permission = ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value - - for (size_t slot = 0; slot < applet_slots.size(); ++slot) { - auto& slot_data = applet_slots[slot]; - slot_data.slot = static_cast(slot); - slot_data.applet_id = AppletId::None; - slot_data.attributes.raw = 0; - slot_data.registered = false; - slot_data.loaded = false; - slot_data.notification_event = - Kernel::Event::Create(Kernel::ResetType::OneShot, "APT:Notification"); - slot_data.parameter_event = - Kernel::Event::Create(Kernel::ResetType::OneShot, "APT:Parameter"); - } } void Shutdown() { @@ -1248,18 +836,7 @@ void Shutdown() { shared_font_relocated = false; lock = nullptr; - for (auto& slot : applet_slots) { - slot.registered = false; - slot.notification_event = nullptr; - slot.parameter_event = nullptr; - slot.loaded = false; - slot.attributes.raw = 0; - slot.applet_id = AppletId::None; - } - - next_parameter = boost::none; - - HLE::Applets::Shutdown(); + applet_manager = nullptr; } } // namespace APT diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index fa20450da..9e5e3d430 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -19,21 +19,6 @@ namespace APT { /// Each APT service can only have up to 2 sessions connected at the same time. static const u32 MaxAPTSessions = 2; -/// Holds information about the parameters used in Send/Glance/ReceiveParameter -struct MessageParameter { - u32 sender_id = 0; - u32 destination_id = 0; - u32 signal = 0; - Kernel::SharedPtr object = nullptr; - std::vector buffer; -}; - -/// Holds information about the parameters used in StartLibraryApplet -struct AppletStartupParameter { - Kernel::SharedPtr object = nullptr; - std::vector buffer; -}; - /// Used by the application to pass information about the current framebuffer to applets. struct CaptureBufferInfo { u32_le size; @@ -48,65 +33,6 @@ struct CaptureBufferInfo { }; static_assert(sizeof(CaptureBufferInfo) == 0x20, "CaptureBufferInfo struct has incorrect size"); -/// Signals used by APT functions -enum class SignalType : 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, -}; - -/// App Id's used by APT functions -enum class AppletId : u32 { - None = 0, - AnySystemApplet = 0x100, - HomeMenu = 0x101, - AlternateMenu = 0x103, - Camera = 0x110, - FriendList = 0x112, - GameNotes = 0x113, - InternetBrowser = 0x114, - InstructionManual = 0x115, - Notifications = 0x116, - Miiverse = 0x117, - MiiversePost = 0x118, - AmiiboSettings = 0x119, - AnySysLibraryApplet = 0x200, - SoftwareKeyboard1 = 0x201, - Ed1 = 0x202, - PnoteApp = 0x204, - SnoteApp = 0x205, - Error = 0x206, - Mint = 0x207, - Extrapad = 0x208, - Memolib = 0x209, - Application = 0x300, - Tiger = 0x301, - AnyLibraryApplet = 0x400, - SoftwareKeyboard2 = 0x401, - Ed2 = 0x402, - PnoteApp2 = 0x404, - SnoteApp2 = 0x405, - Error2 = 0x406, - Mint2 = 0x407, - Extrapad2 = 0x408, - Memolib2 = 0x409, -}; - enum class StartupArgumentType : u32 { OtherApp = 0, Restart = 1, @@ -120,16 +46,6 @@ enum class ScreencapPostPermission : u32 { DisableScreenshotPostingToMiiverse = 3 }; -namespace ErrCodes { -enum { - ParameterPresent = 2, - InvalidAppletSlot = 4, -}; -} // namespace ErrCodes - -/// Send a parameter to the currently-running application, which will read it via ReceiveParameter -void SendParameter(const MessageParameter& parameter); - /** * APT::Initialize service function * Service function that initializes the APT process for the running application diff --git a/src/core/hle/service/apt/errors.h b/src/core/hle/service/apt/errors.h new file mode 100644 index 000000000..9c6f32c17 --- /dev/null +++ b/src/core/hle/service/apt/errors.h @@ -0,0 +1,16 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service { +namespace APT { +namespace ErrCodes { +enum { + ParameterPresent = 2, + InvalidAppletSlot = 4, +}; +} // namespace ErrCodes +} // namespace APT +} // namespace Service diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h index 6fb171c1a..035d21a4c 100644 --- a/src/core/hle/service/ns/ns.h +++ b/src/core/hle/service/ns/ns.h @@ -5,6 +5,7 @@ #pragma once #include "core/hle/kernel/process.h" +#include "core/hle/service/fs/archive.h" #include "core/hle/service/service.h" namespace Service {