diff --git a/src/core/core.cpp b/src/core/core.cpp index c6eebade7..a74e7b430 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -589,7 +589,7 @@ void System::Reset() { // TODO: Properly implement the reset // Since the system is completely reinitialized, we'll have to store the deliver arg manually. - boost::optional deliver_arg; + boost::optional deliver_arg; if (auto apt = Service::APT::GetModule(*this)) { deliver_arg = apt->GetAppletManager()->ReceiveDeliverArg(); } diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp index ce82a64e5..08205b77d 100644 --- a/src/core/file_sys/archive_systemsavedata.cpp +++ b/src/core/file_sys/archive_systemsavedata.cpp @@ -60,7 +60,7 @@ ResultVal> ArchiveFactory_SystemSaveData::Open(c std::string fullpath = GetSystemSaveDataPath(base_path, path); if (!FileUtil::Exists(fullpath)) { // TODO(Subv): Check error code, this one is probably wrong - return ERR_NOT_FORMATTED; + return ERROR_NOT_FOUND; } auto archive = std::make_unique(fullpath); return MakeResult>(std::move(archive)); diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp index 6b73637ca..ab96cc2e2 100644 --- a/src/core/hle/applets/applet.cpp +++ b/src/core/hle/applets/applet.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "common/assert.h" #include "common/common_types.h" #include "core/core.h" @@ -42,24 +43,24 @@ static Core::TimingEventType* 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, - std::weak_ptr manager) { +ResultCode Applet::Create(Service::APT::AppletId id, Service::APT::AppletId parent, bool preload, + const std::shared_ptr& manager) { switch (id) { case Service::APT::AppletId::SoftwareKeyboard1: case Service::APT::AppletId::SoftwareKeyboard2: - applets[id] = std::make_shared(id, std::move(manager)); + applets[id] = std::make_shared(id, parent, preload, manager); break; case Service::APT::AppletId::Ed1: case Service::APT::AppletId::Ed2: - applets[id] = std::make_shared(id, std::move(manager)); + applets[id] = std::make_shared(id, parent, preload, manager); break; case Service::APT::AppletId::Error: case Service::APT::AppletId::Error2: - applets[id] = std::make_shared(id, std::move(manager)); + applets[id] = std::make_shared(id, parent, preload, manager); break; case Service::APT::AppletId::Mint: case Service::APT::AppletId::Mint2: - applets[id] = std::make_shared(id, std::move(manager)); + applets[id] = std::make_shared(id, parent, preload, manager); break; default: LOG_ERROR(Service_APT, "Could not create applet {}", id); @@ -68,6 +69,17 @@ ResultCode Applet::Create(Service::APT::AppletId id, ErrorSummary::NotSupported, ErrorLevel::Permanent); } + Service::APT::AppletAttributes attributes; + attributes.applet_pos.Assign(static_cast(Service::APT::AppletPos::AutoLibrary)); + attributes.is_home_menu.Assign(false); + const auto lock_handle_data = manager->GetLockHandle(attributes); + + manager->Initialize(id, lock_handle_data->corrected_attributes); + manager->Enable(lock_handle_data->corrected_attributes); + if (preload) { + manager->FinishPreloadingLibraryApplet(id); + } + return RESULT_SUCCESS; } @@ -80,8 +92,8 @@ std::shared_ptr Applet::Get(Service::APT::AppletId id) { /// Handles updating the current Applet every time it's called. static void AppletUpdateEvent(u64 applet_id, s64 cycles_late) { - Service::APT::AppletId id = static_cast(applet_id); - std::shared_ptr applet = Applet::Get(id); + const auto id = static_cast(applet_id); + const auto applet = Applet::Get(id); ASSERT_MSG(applet != nullptr, "Applet doesn't exist! applet_id={:08X}", id); applet->Update(); @@ -96,20 +108,28 @@ static void AppletUpdateEvent(u64 applet_id, s64 cycles_late) { } } -ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter) { - ResultCode result = StartImpl(parameter); - if (result.IsError()) - return result; - // Schedule the update event - Core::System::GetInstance().CoreTiming().ScheduleEvent( - usToCycles(applet_update_interval_us), applet_update_event, static_cast(id)); - return result; -} - bool Applet::IsRunning() const { return is_running; } +ResultCode Applet::ReceiveParameter(const Service::APT::MessageParameter& parameter) { + switch (parameter.signal) { + case Service::APT::SignalType::Wakeup: { + ResultCode result = Start(parameter); + if (!result.IsError()) { + // Schedule the update event + Core::System::GetInstance().CoreTiming().ScheduleEvent( + usToCycles(applet_update_interval_us), applet_update_event, static_cast(id)); + } + return result; + } + case Service::APT::SignalType::WakeupByCancel: + return Finalize(); + default: + return ReceiveParameterImpl(parameter); + } +} + void Applet::SendParameter(const Service::APT::MessageParameter& parameter) { if (auto locked = manager.lock()) { locked->CancelAndSendParameter(parameter); @@ -118,12 +138,15 @@ void Applet::SendParameter(const Service::APT::MessageParameter& parameter) { } } -bool IsLibraryAppletRunning() { - // Check the applets map for instances of any applet - for (auto itr = applets.begin(); itr != applets.end(); ++itr) - if (itr->second != nullptr) - return true; - return false; +void Applet::CloseApplet(std::shared_ptr object, const std::vector& buffer) { + if (auto locked = manager.lock()) { + locked->PrepareToCloseLibraryApplet(true, false, false); + locked->CloseLibraryApplet(std::move(object), buffer); + } else { + LOG_ERROR(Service_APT, "called after destructing applet manager"); + } + + is_running = false; } void Init() { diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h index 2ed410bdc..36f895be8 100644 --- a/src/core/hle/applets/applet.h +++ b/src/core/hle/applets/applet.h @@ -18,10 +18,12 @@ public: * Creates an instance of the Applet subclass identified by the parameter. * and stores it in a global map. * @param id Id of the applet to create. + * @param parent Id of the applet's parent. + * @param preload Whether the applet is being preloaded. * @returns ResultCode Whether the operation was successful or not. */ - static ResultCode Create(Service::APT::AppletId id, - std::weak_ptr manager); + static ResultCode Create(Service::APT::AppletId id, Service::APT::AppletId parent, bool preload, + const std::shared_ptr& manager); /** * Retrieves the Applet instance identified by the specified id. @@ -35,19 +37,12 @@ public: * @param parameter Parameter data to handle. * @returns ResultCode Whether the operation was successful or not. */ - virtual ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) = 0; - - /** - * Handles the Applet start event, triggered from the application. - * @param parameter Parameter data to handle. - * @returns ResultCode Whether the operation was successful or not. - */ - ResultCode Start(const Service::APT::AppletStartupParameter& parameter); + ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter); /** * Whether the applet is currently executing instead of the host application or not. */ - bool IsRunning() const; + [[nodiscard]] bool IsRunning() const; /** * Handles an update tick for the Applet, lets it update the screen, send commands, etc. @@ -55,31 +50,45 @@ public: virtual void Update() = 0; protected: - Applet(Service::APT::AppletId id, std::weak_ptr manager) - : id(id), manager(std::move(manager)) {} + Applet(Service::APT::AppletId id, Service::APT::AppletId parent, bool preload, + std::weak_ptr manager) + : id(id), parent(parent), preload(preload), manager(std::move(manager)) {} + + /** + * Handles a parameter from the application. + * @param parameter Parameter data to handle. + * @returns ResultCode Whether the operation was successful or not. + */ + virtual ResultCode ReceiveParameterImpl(const Service::APT::MessageParameter& parameter) = 0; /** * Handles the Applet start event, triggered from the application. * @param parameter Parameter data to handle. * @returns ResultCode Whether the operation was successful or not. */ - virtual ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) = 0; + virtual ResultCode Start(const Service::APT::MessageParameter& parameter) = 0; + + /** + * Sends the LibAppletClosing signal to the application, + * along with the relevant data buffers. + */ + virtual ResultCode Finalize() = 0; Service::APT::AppletId id; ///< Id of this Applet + Service::APT::AppletId parent; ///< Id of this Applet's parent + bool preload; ///< Whether the Applet is being preloaded. std::shared_ptr> heap_memory; ///< Heap memory for this Applet /// Whether this applet is currently running instead of the host application or not. bool is_running = false; void SendParameter(const Service::APT::MessageParameter& parameter); + void CloseApplet(std::shared_ptr object, const std::vector& buffer); private: std::weak_ptr manager; }; -/// Returns whether a library applet is currently running -bool IsLibraryAppletRunning(); - /// Initializes the HLE applets void Init(); diff --git a/src/core/hle/applets/erreula.cpp b/src/core/hle/applets/erreula.cpp index 5273f989e..69d6071d6 100644 --- a/src/core/hle/applets/erreula.cpp +++ b/src/core/hle/applets/erreula.cpp @@ -9,7 +9,7 @@ namespace HLE::Applets { -ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& parameter) { +ResultCode ErrEula::ReceiveParameterImpl(const Service::APT::MessageParameter& parameter) { if (parameter.signal != Service::APT::SignalType::Request) { LOG_ERROR(Service_APT, "unsupported signal {}", parameter.signal); UNIMPLEMENTED(); @@ -33,34 +33,33 @@ ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& param "ErrEula Memory"); // Send the response message with the newly created SharedMemory - Service::APT::MessageParameter result; - result.signal = Service::APT::SignalType::Response; - result.buffer.clear(); - result.destination_id = Service::APT::AppletId::Application; - result.sender_id = id; - result.object = framebuffer_memory; + SendParameter({ + .sender_id = id, + .destination_id = parent, + .signal = Service::APT::SignalType::Response, + .object = framebuffer_memory, + }); - SendParameter(result); return RESULT_SUCCESS; } -ResultCode ErrEula::StartImpl(const Service::APT::AppletStartupParameter& parameter) { +ResultCode ErrEula::Start(const Service::APT::MessageParameter& parameter) { is_running = true; + startup_param = parameter.buffer; // TODO(Subv): Set the expected fields in the response buffer before resending it to the // application. // TODO(Subv): Reverse the parameter format for the ErrEula applet - // Let the application know that we're closing - Service::APT::MessageParameter message; - message.buffer.resize(parameter.buffer.size()); - std::fill(message.buffer.begin(), message.buffer.end(), 0); - message.signal = Service::APT::SignalType::WakeupByExit; - message.destination_id = Service::APT::AppletId::Application; - message.sender_id = id; - SendParameter(message); + // Let the application know that we're closing. + Finalize(); + return RESULT_SUCCESS; +} - is_running = false; +ResultCode ErrEula::Finalize() { + std::vector buffer(startup_param.size()); + std::fill(buffer.begin(), buffer.end(), 0); + CloseApplet(nullptr, buffer); return RESULT_SUCCESS; } diff --git a/src/core/hle/applets/erreula.h b/src/core/hle/applets/erreula.h index c879c5e05..bdb169b13 100644 --- a/src/core/hle/applets/erreula.h +++ b/src/core/hle/applets/erreula.h @@ -11,11 +11,13 @@ namespace HLE::Applets { class ErrEula final : public Applet { public: - explicit ErrEula(Service::APT::AppletId id, std::weak_ptr manager) - : Applet(id, std::move(manager)) {} + explicit ErrEula(Service::APT::AppletId id, Service::APT::AppletId parent, bool preload, + std::weak_ptr manager) + : Applet(id, parent, preload, std::move(manager)) {} - ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; - ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; + ResultCode ReceiveParameterImpl(const Service::APT::MessageParameter& parameter) override; + ResultCode Start(const Service::APT::MessageParameter& parameter) override; + ResultCode Finalize() override; void Update() override; private: @@ -23,6 +25,9 @@ private: /// It holds the framebuffer info retrieved by the application with /// GSPGPU::ImportDisplayCaptureInfo std::shared_ptr framebuffer_memory; + + /// Parameter received by the applet on start. + std::vector startup_param; }; } // namespace HLE::Applets diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp index 3811df432..ca4a0878b 100644 --- a/src/core/hle/applets/mii_selector.cpp +++ b/src/core/hle/applets/mii_selector.cpp @@ -19,7 +19,7 @@ namespace HLE::Applets { -ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& parameter) { +ResultCode MiiSelector::ReceiveParameterImpl(const Service::APT::MessageParameter& parameter) { if (parameter.signal != Service::APT::SignalType::Request) { LOG_ERROR(Service_APT, "unsupported signal {}", parameter.signal); UNIMPLEMENTED(); @@ -42,18 +42,17 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p "MiiSelector Memory"); // Send the response message with the newly created SharedMemory - Service::APT::MessageParameter result; - result.signal = Service::APT::SignalType::Response; - result.buffer.clear(); - result.destination_id = Service::APT::AppletId::Application; - result.sender_id = id; - result.object = framebuffer_memory; + SendParameter({ + .sender_id = id, + .destination_id = parent, + .signal = Service::APT::SignalType::Response, + .object = framebuffer_memory, + }); - SendParameter(result); return RESULT_SUCCESS; } -ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& parameter) { +ResultCode MiiSelector::Start(const Service::APT::MessageParameter& parameter) { ASSERT_MSG(parameter.buffer.size() == sizeof(config), "The size of the parameter (MiiConfig) is wrong"); @@ -85,17 +84,11 @@ void MiiSelector::Update() { Finalize(); } -void MiiSelector::Finalize() { - // Let the application know that we're closing - Service::APT::MessageParameter message; - message.buffer.resize(sizeof(MiiResult)); - std::memcpy(message.buffer.data(), &result, message.buffer.size()); - message.signal = Service::APT::SignalType::WakeupByExit; - message.destination_id = Service::APT::AppletId::Application; - message.sender_id = id; - SendParameter(message); - - is_running = false; +ResultCode MiiSelector::Finalize() { + std::vector buffer(sizeof(MiiResult)); + std::memcpy(buffer.data(), &result, buffer.size()); + CloseApplet(nullptr, buffer); + return RESULT_SUCCESS; } MiiResult MiiSelector::GetStandardMiiResult() { diff --git a/src/core/hle/applets/mii_selector.h b/src/core/hle/applets/mii_selector.h index 0a8b8113c..50cf1bf4a 100644 --- a/src/core/hle/applets/mii_selector.h +++ b/src/core/hle/applets/mii_selector.h @@ -115,19 +115,15 @@ ASSERT_REG_POSITION(guest_mii_name, 0x6C); class MiiSelector final : public Applet { public: - MiiSelector(Service::APT::AppletId id, std::weak_ptr manager) - : Applet(id, std::move(manager)) {} + MiiSelector(Service::APT::AppletId id, Service::APT::AppletId parent, bool preload, + std::weak_ptr manager) + : Applet(id, parent, preload, std::move(manager)) {} - ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; - ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; + ResultCode ReceiveParameterImpl(const Service::APT::MessageParameter& parameter) override; + ResultCode Start(const Service::APT::MessageParameter& parameter) override; + ResultCode Finalize() override; void Update() override; - /** - * Sends the LibAppletClosing signal to the application, - * along with the relevant data buffers. - */ - void Finalize(); - static MiiResult GetStandardMiiResult(); private: diff --git a/src/core/hle/applets/mint.cpp b/src/core/hle/applets/mint.cpp index 3a98b97c5..0f62e4917 100644 --- a/src/core/hle/applets/mint.cpp +++ b/src/core/hle/applets/mint.cpp @@ -9,7 +9,7 @@ namespace HLE::Applets { -ResultCode Mint::ReceiveParameter(const Service::APT::MessageParameter& parameter) { +ResultCode Mint::ReceiveParameterImpl(const Service::APT::MessageParameter& parameter) { if (parameter.signal != Service::APT::SignalType::Request) { LOG_ERROR(Service_APT, "unsupported signal {}", parameter.signal); UNIMPLEMENTED(); @@ -33,34 +33,33 @@ ResultCode Mint::ReceiveParameter(const Service::APT::MessageParameter& paramete "Mint Memory"); // Send the response message with the newly created SharedMemory - Service::APT::MessageParameter result; - result.signal = Service::APT::SignalType::Response; - result.buffer.clear(); - result.destination_id = Service::APT::AppletId::Application; - result.sender_id = id; - result.object = framebuffer_memory; + SendParameter({ + .sender_id = id, + .destination_id = parent, + .signal = Service::APT::SignalType::Response, + .object = framebuffer_memory, + }); - SendParameter(result); return RESULT_SUCCESS; } -ResultCode Mint::StartImpl(const Service::APT::AppletStartupParameter& parameter) { +ResultCode Mint::Start(const Service::APT::MessageParameter& parameter) { is_running = true; + startup_param = parameter.buffer; // TODO(Subv): Set the expected fields in the response buffer before resending it to the // application. // TODO(Subv): Reverse the parameter format for the Mint applet // Let the application know that we're closing - Service::APT::MessageParameter message; - message.buffer.resize(parameter.buffer.size()); - std::fill(message.buffer.begin(), message.buffer.end(), 0); - message.signal = Service::APT::SignalType::WakeupByExit; - message.destination_id = Service::APT::AppletId::Application; - message.sender_id = id; - SendParameter(message); + Finalize(); + return RESULT_SUCCESS; +} - is_running = false; +ResultCode Mint::Finalize() { + std::vector buffer(startup_param.size()); + std::fill(buffer.begin(), buffer.end(), 0); + CloseApplet(nullptr, buffer); return RESULT_SUCCESS; } diff --git a/src/core/hle/applets/mint.h b/src/core/hle/applets/mint.h index cb250f1fa..4c2f8ffd6 100644 --- a/src/core/hle/applets/mint.h +++ b/src/core/hle/applets/mint.h @@ -11,11 +11,13 @@ namespace HLE::Applets { class Mint final : public Applet { public: - explicit Mint(Service::APT::AppletId id, std::weak_ptr manager) - : Applet(id, std::move(manager)) {} + explicit Mint(Service::APT::AppletId id, Service::APT::AppletId parent, bool preload, + std::weak_ptr manager) + : Applet(id, parent, preload, std::move(manager)) {} - ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; - ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; + ResultCode ReceiveParameterImpl(const Service::APT::MessageParameter& parameter) override; + ResultCode Start(const Service::APT::MessageParameter& parameter) override; + ResultCode Finalize() override; void Update() override; private: @@ -23,6 +25,9 @@ private: /// It holds the framebuffer info retrieved by the application with /// GSPGPU::ImportDisplayCaptureInfo std::shared_ptr framebuffer_memory; + + /// Parameter received by the applet on start. + std::vector startup_param; }; } // namespace HLE::Applets diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp index 0db78287e..f864eee80 100644 --- a/src/core/hle/applets/swkbd.cpp +++ b/src/core/hle/applets/swkbd.cpp @@ -21,7 +21,7 @@ namespace HLE::Applets { -ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) { +ResultCode SoftwareKeyboard::ReceiveParameterImpl(Service::APT::MessageParameter const& parameter) { switch (parameter.signal) { case Service::APT::SignalType::Request: { // The LibAppJustStarted message contains a buffer with the size of the framebuffer shared @@ -39,14 +39,13 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con "SoftwareKeyboard Memory"); // Send the response message with the newly created SharedMemory - Service::APT::MessageParameter result; - result.signal = Service::APT::SignalType::Response; - result.buffer.clear(); - result.destination_id = Service::APT::AppletId::Application; - result.sender_id = id; - result.object = framebuffer_memory; + SendParameter({ + .sender_id = id, + .destination_id = parent, + .signal = Service::APT::SignalType::Response, + .object = framebuffer_memory, + }); - SendParameter(result); return RESULT_SUCCESS; } @@ -92,7 +91,7 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con } } -ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter const& parameter) { +ResultCode SoftwareKeyboard::Start(Service::APT::MessageParameter const& parameter) { ASSERT_MSG(parameter.buffer.size() == sizeof(config), "The size of the parameter (SoftwareKeyboardConfig) is wrong"); @@ -151,14 +150,16 @@ void SoftwareKeyboard::Update() { config.text_offset = 0; if (config.filter_flags & HLE::Applets::SoftwareKeyboardFilter::Callback) { + std::vector buffer(sizeof(SoftwareKeyboardConfig)); + std::memcpy(buffer.data(), &config, buffer.size()); + // Send the message to invoke callback - Service::APT::MessageParameter message; - message.buffer.resize(sizeof(SoftwareKeyboardConfig)); - std::memcpy(message.buffer.data(), &config, message.buffer.size()); - message.signal = Service::APT::SignalType::Message; - message.destination_id = Service::APT::AppletId::Application; - message.sender_id = id; - SendParameter(message); + SendParameter({ + .sender_id = id, + .destination_id = parent, + .signal = Service::APT::SignalType::Message, + .buffer = buffer, + }); } else { Finalize(); } @@ -168,18 +169,12 @@ void SoftwareKeyboard::DrawScreenKeyboard() { // TODO(Subv): Draw the HLE keyboard, for now just do nothing } -void SoftwareKeyboard::Finalize() { - // Let the application know that we're closing - Service::APT::MessageParameter message; - message.buffer.resize(sizeof(SoftwareKeyboardConfig)); - std::memcpy(message.buffer.data(), &config, message.buffer.size()); - message.signal = Service::APT::SignalType::WakeupByExit; - message.destination_id = Service::APT::AppletId::Application; - message.sender_id = id; - SendParameter(message); - - is_running = false; +ResultCode SoftwareKeyboard::Finalize() { + std::vector buffer(sizeof(SoftwareKeyboardConfig)); + std::memcpy(buffer.data(), &config, buffer.size()); + CloseApplet(nullptr, buffer); text_memory = nullptr; + return RESULT_SUCCESS; } Frontend::KeyboardConfig SoftwareKeyboard::ToFrontendConfig( diff --git a/src/core/hle/applets/swkbd.h b/src/core/hle/applets/swkbd.h index e754496c9..663693ba6 100644 --- a/src/core/hle/applets/swkbd.h +++ b/src/core/hle/applets/swkbd.h @@ -175,11 +175,13 @@ static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config class SoftwareKeyboard final : public Applet { public: - SoftwareKeyboard(Service::APT::AppletId id, std::weak_ptr manager) - : Applet(id, std::move(manager)) {} + SoftwareKeyboard(Service::APT::AppletId id, Service::APT::AppletId parent, bool preload, + std::weak_ptr manager) + : Applet(id, parent, preload, std::move(manager)) {} - ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; - ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; + ResultCode ReceiveParameterImpl(const Service::APT::MessageParameter& parameter) override; + ResultCode Start(const Service::APT::MessageParameter& parameter) override; + ResultCode Finalize() override; void Update() override; /** @@ -187,12 +189,6 @@ public: */ void DrawScreenKeyboard(); - /** - * Sends the LibAppletClosing signal to the application, - * along with the relevant data buffers. - */ - void Finalize(); - private: Frontend::KeyboardConfig ToFrontendConfig(const SoftwareKeyboardConfig& config) const; diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index e3cfe37bd..6e8e25bea 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -208,6 +208,9 @@ void Process::Exit() { if (plgldr) { plgldr->OnProcessExit(*this, kernel); } + + // Clear the process's open handles. + handle_table.Clear(); } VAddr Process::GetLinearHeapAreaAddress() const { diff --git a/src/core/hle/service/ac/ac.cpp b/src/core/hle/service/ac/ac.cpp index 22f36a455..b7e610a05 100644 --- a/src/core/hle/service/ac/ac.cpp +++ b/src/core/hle/service/ac/ac.cpp @@ -36,6 +36,7 @@ void Module::Interface::ConnectAsync(Kernel::HLERequestContext& ctx) { rp.Skip(2, false); // ProcessId descriptor ac->connect_event = rp.PopObject(); + rp.Skip(2, false); // Buffer descriptor if (ac->connect_event) { ac->connect_event->SetName("AC:connect_event"); diff --git a/src/core/hle/service/apt/applet_manager.cpp b/src/core/hle/service/apt/applet_manager.cpp index 9ba7e8110..0bcbd2ecf 100644 --- a/src/core/hle/service/apt/applet_manager.cpp +++ b/src/core/hle/service/apt/applet_manager.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/settings.h" #include "core/core.h" #include "core/hle/applets/applet.h" #include "core/hle/service/am/am.h" @@ -14,8 +15,6 @@ SERVICE_CONSTRUCT_IMPL(Service::APT::AppletManager) namespace Service::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; @@ -23,6 +22,7 @@ struct AppletTitleData { // There's a specific TitleId per region for each applet. static constexpr std::size_t NumRegions = 7; std::array title_ids; + std::array n3ds_title_ids = {0, 0, 0, 0, 0, 0, 0}; }; static constexpr std::size_t NumApplets = 29; @@ -44,7 +44,8 @@ static constexpr std::array applet_titleids = {{ 0x400300000AD02, 0x400300000B502}}, {{AppletId::InternetBrowser, AppletId::None}, {0x4003000008802, 0x4003000009402, 0x4003000009D02, 0x4003000008802, 0x400300000A602, - 0x400300000AE02, 0x400300000B602}}, + 0x400300000AE02, 0x400300000B602}, + {0x4003020008802, 0x4003020009402, 0x4003020009D02, 0x4003020008802, 0, 0x400302000AE02, 0}}, {{AppletId::InstructionManual, AppletId::None}, {0x4003000008602, 0x4003000009202, 0x4003000009B02, 0x4003000008602, 0x400300000A402, 0x400300000AC02, 0x400300000B402}}, @@ -100,117 +101,139 @@ static u64 GetTitleIdForApplet(AppletId id, u32 region_value) { ASSERT_MSG(itr != applet_titleids.end(), "Unknown applet id 0x{:#05X}", id); + auto n3ds_title_id = itr->n3ds_title_ids[region_value]; + if (n3ds_title_id != 0 && Settings::values.is_new_3ds.GetValue()) { + return n3ds_title_id; + } return itr->title_ids[region_value]; } -AppletManager::AppletSlotData* AppletManager::GetAppletSlotData(AppletId id) { - auto GetSlot = [this](AppletSlot slot) -> AppletSlotData* { - return &applet_slots[static_cast(slot)]; - }; - +AppletManager::AppletSlot AppletManager::GetAppletSlotFromId(AppletId id) { if (id == AppletId::Application) { - auto* slot = GetSlot(AppletSlot::Application); - if (slot->applet_id != AppletId::None) - return slot; + if (GetAppletSlot(AppletSlot::Application)->applet_id != AppletId::None) + return AppletSlot::Application; - return nullptr; + return AppletSlot::Error; } if (id == AppletId::AnySystemApplet) { - auto* system_slot = GetSlot(AppletSlot::SystemApplet); - if (system_slot->applet_id != AppletId::None) - return system_slot; + if (GetAppletSlot(AppletSlot::SystemApplet)->applet_id != AppletId::None) + return AppletSlot::SystemApplet; // 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; + if (GetAppletSlot(AppletSlot::HomeMenu)->applet_id != AppletId::None) + return AppletSlot::HomeMenu; - return nullptr; + return AppletSlot::Error; } if (id == AppletId::AnyLibraryApplet || id == AppletId::AnySysLibraryApplet) { - auto* slot = GetSlot(AppletSlot::LibraryApplet); - if (slot->applet_id == AppletId::None) - return nullptr; + auto slot_data = GetAppletSlot(AppletSlot::LibraryApplet); + if (slot_data->applet_id == AppletId::None) + return AppletSlot::Error; - u32 applet_pos = slot->attributes.applet_pos; + auto applet_pos = static_cast(slot_data->attributes.applet_pos.Value()); + if ((id == AppletId::AnyLibraryApplet && applet_pos == AppletPos::Library) || + (id == AppletId::AnySysLibraryApplet && applet_pos == AppletPos::SysLibrary)) + return AppletSlot::LibraryApplet; - 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; + return AppletSlot::Error; } if (id == AppletId::HomeMenu || id == AppletId::AlternateMenu) { - auto* slot = GetSlot(AppletSlot::HomeMenu); - if (slot->applet_id != AppletId::None) - return slot; + if (GetAppletSlot(AppletSlot::HomeMenu)->applet_id != AppletId::None) + return AppletSlot::HomeMenu; - return nullptr; + return AppletSlot::Error; } - for (auto& slot : applet_slots) { - if (slot.applet_id == id) - return &slot; + for (std::size_t slot = 0; slot < applet_slots.size(); ++slot) { + if (applet_slots[slot].applet_id == id) { + return static_cast(slot); + } } - return nullptr; + return AppletSlot::Error; } -AppletManager::AppletSlotData* AppletManager::GetAppletSlotData(AppletAttributes attributes) { +AppletManager::AppletSlot AppletManager::GetAppletSlotFromAttributes(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; + auto applet_pos = attributes.applet_pos; if (applet_pos >= applet_position_slots.size()) - return nullptr; - - AppletSlot slot = applet_position_slots[applet_pos]; + return AppletSlot::Error; + auto slot = applet_position_slots[applet_pos]; if (slot == AppletSlot::Error) - return nullptr; + return AppletSlot::Error; // 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 AppletSlot::HomeMenu; - return &applet_slots[static_cast(slot)]; + return slot; +} + +AppletManager::AppletSlot AppletManager::GetAppletSlotFromPos(AppletPos pos) { + AppletId applet_id; + switch (pos) { + case AppletPos::Application: + applet_id = AppletId::Application; + break; + case AppletPos::Library: + applet_id = AppletId::AnyLibraryApplet; + break; + case AppletPos::System: + applet_id = AppletId::AnySystemApplet; + break; + case AppletPos::SysLibrary: + applet_id = AppletId::AnySysLibraryApplet; + break; + default: + return AppletSlot::Error; + } + return GetAppletSlotFromId(applet_id); } 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}", - parameter.destination_id); - return; - } + LOG_DEBUG( + Service_APT, "Sending parameter from {:03X} to {:03X} with signal {:08X} and size {:08X}", + parameter.sender_id, parameter.destination_id, parameter.signal, parameter.buffer.size()); - slot_data->parameter_event->Signal(); + // If the applet is being HLEd, send directly to the applet. + if (auto dest_applet = HLE::Applets::Applet::Get(parameter.destination_id)) { + dest_applet->ReceiveParameter(parameter); + } else { + // Otherwise, send the parameter the LLE way. + next_parameter = parameter; + + // Signal the event to let the receiver know that a new parameter is ready to be read + auto slot = GetAppletSlotFromId(parameter.destination_id); + if (slot != AppletSlot::Error) { + GetAppletSlot(slot)->parameter_event->Signal(); + } else { + LOG_DEBUG(Service_APT, "No applet was registered with ID {:03X}", + parameter.destination_id); + } + } } 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); + LOG_WARNING(Service_APT, "Parameter from {:03X} to {:03X} blocked by pending parameter.", + parameter.sender_id, parameter.destination_id); + return {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; - } + return RESULT_SUCCESS; } ResultVal AppletManager::GlanceParameter(AppletId app_id) { @@ -224,7 +247,7 @@ ResultVal AppletManager::GlanceParameter(AppletId app_id) { ErrorLevel::Status); } - MessageParameter parameter = *next_parameter; + auto parameter = *next_parameter; // Note: The NS module always clears the DSPSleep and DSPWakeup signals even in GlanceParameter. if (next_parameter->signal == SignalType::DspSleep || @@ -246,17 +269,9 @@ ResultVal AppletManager::ReceiveParameter(AppletId app_id) { 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; - } + auto cancellation_success = + next_parameter && (!check_sender || next_parameter->sender_id == sender_appid) && + (!check_receiver || next_parameter->destination_id == receiver_appid); if (cancellation_success) next_parameter = {}; @@ -264,43 +279,57 @@ bool AppletManager::CancelParameter(bool check_sender, AppletId sender_appid, bo return cancellation_success; } +ResultVal AppletManager::GetLockHandle( + AppletAttributes attributes) { + auto corrected_attributes = attributes; + if (attributes.applet_pos == static_cast(AppletPos::Library) || + attributes.applet_pos == static_cast(AppletPos::SysLibrary) || + attributes.applet_pos == static_cast(AppletPos::AutoLibrary)) { + auto corrected_pos = last_library_launcher_slot == AppletSlot::Application + ? AppletPos::Library + : AppletPos::SysLibrary; + corrected_attributes.applet_pos.Assign(static_cast(corrected_pos)); + LOG_DEBUG(Service_APT, "Corrected applet attributes from {:08X} to {:08X}", attributes.raw, + corrected_attributes.raw); + } + + return MakeResult({corrected_attributes, 0, lock}); +} + ResultVal AppletManager::Initialize(AppletId app_id, AppletAttributes attributes) { - auto* const slot_data = GetAppletSlotData(attributes); - + auto slot = GetAppletSlotFromAttributes(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"); + ASSERT_MSG(slot != AppletSlot::Error, "Invalid application attributes"); + auto slot_data = GetAppletSlot(slot); if (slot_data->registered) { + LOG_WARNING(Service_APT, "Applet attempted to register in occupied slot {:02X}", slot); return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, ErrorSummary::InvalidState, ErrorLevel::Status); } + LOG_DEBUG(Service_APT, "Initializing applet with ID {:03X} and attributes {:08X}.", app_id, + attributes.raw); slot_data->applet_id = static_cast(app_id); // Note: In the real console the title id of a given applet slot is set by the APT module when // calling StartApplication. slot_data->title_id = system.Kernel().GetCurrentProcess()->codeset->program_id; slot_data->attributes.raw = attributes.raw; - const auto* home_menu_slot = GetAppletSlotData(AppletId::HomeMenu); - // Applications need to receive a Wakeup signal to actually start up, this signal is usually - // sent by the Home Menu after starting the app by way of APT::WakeupApplication. In some cases - // such as when starting a game directly or the Home Menu itself, we have to send the signal - // ourselves since the Home Menu is not running yet. We detect if the Home Menu is running by - // checking if there's an applet registered in the HomeMenu slot. - if (slot_data->applet_id == AppletId::HomeMenu || - (slot_data->applet_id == AppletId::Application && !home_menu_slot)) { - // 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(); + // sent by the Home Menu after starting the app by way of APT::WakeupApplication. However, + // if nothing is running yet the signal should be sent by APT::Initialize itself. + if (active_slot == AppletSlot::Error) { + active_slot = slot; + + // Wake up the application. + SendParameter({ + .sender_id = AppletId::None, + .destination_id = app_id, + .signal = SignalType::Wakeup, + }); } return MakeResult( @@ -308,17 +337,23 @@ ResultVal AppletManager::Initialize(AppletId ap } ResultCode AppletManager::Enable(AppletAttributes attributes) { - auto* const slot_data = GetAppletSlotData(attributes); - - if (!slot_data) { - return ResultCode(ErrCodes::InvalidAppletSlot, ErrorModule::Applet, - ErrorSummary::InvalidState, ErrorLevel::Status); + auto slot = GetAppletSlotFromAttributes(attributes); + if (slot == AppletSlot::Error) { + LOG_WARNING(Service_APT, + "Attempted to register with attributes {:08X}, but could not find slot.", + attributes.raw); + return {ErrCodes::InvalidAppletSlot, ErrorModule::Applet, ErrorSummary::InvalidState, + ErrorLevel::Status}; } + LOG_DEBUG(Service_APT, "Registering applet with attributes {:08X}.", attributes.raw); + auto slot_data = GetAppletSlot(slot); slot_data->registered = true; // Send any outstanding parameters to the newly-registered application if (delayed_parameter && delayed_parameter->destination_id == slot_data->applet_id) { + // TODO: Real APT would loop trying to send the parameter until it succeeds, + // essentially waiting for existing parameters to be delivered. CancelAndSendParameter(*delayed_parameter); delayed_parameter.reset(); } @@ -327,42 +362,29 @@ ResultCode AppletManager::Enable(AppletAttributes attributes) { } 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; + auto slot = GetAppletSlotFromId(app_id); + return slot != AppletSlot::Error && GetAppletSlot(slot)->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); + return {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); + if (GetAppletSlot(AppletSlot::LibraryApplet)->registered) { + return {ErrorDescription::AlreadyExists, ErrorModule::Applet, ErrorSummary::InvalidState, + ErrorLevel::Status}; } + last_library_launcher_slot = active_slot; + last_prepared_library_applet = applet_id; + auto cfg = Service::CFG::GetModule(system); - u32 region_value = cfg->GetRegionValue(); auto process = - NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id, region_value)); + NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id, cfg->GetRegionValue())); if (process) { return RESULT_SUCCESS; } @@ -370,25 +392,27 @@ ResultCode AppletManager::PrepareToStartLibraryApplet(AppletId applet_id) { // 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}", applet_id); + LOG_WARNING(Service_APT, "applet has already been started id={:03X}", applet_id); return RESULT_SUCCESS; } else { - return HLE::Applets::Applet::Create(applet_id, shared_from_this()); + auto parent = GetAppletSlotId(last_library_launcher_slot); + LOG_DEBUG(Service_APT, "Creating HLE applet {:03X} with parent {:03X}", applet_id, parent); + return HLE::Applets::Applet::Create(applet_id, parent, false, 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); + if (GetAppletSlot(AppletSlot::LibraryApplet)->registered) { + return {ErrorDescription::AlreadyExists, ErrorModule::Applet, ErrorSummary::InvalidState, + ErrorLevel::Status}; } + last_library_launcher_slot = active_slot; + last_prepared_library_applet = applet_id; + auto cfg = Service::CFG::GetModule(system); - u32 region_value = cfg->GetRegionValue(); auto process = - NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id, region_value)); + NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id, cfg->GetRegionValue())); if (process) { return RESULT_SUCCESS; } @@ -399,44 +423,43 @@ ResultCode AppletManager::PreloadLibraryApplet(AppletId applet_id) { LOG_WARNING(Service_APT, "applet has already been started id={:08X}", applet_id); return RESULT_SUCCESS; } else { - return HLE::Applets::Applet::Create(applet_id, shared_from_this()); + auto parent = GetAppletSlotId(last_library_launcher_slot); + LOG_DEBUG(Service_APT, "Creating HLE applet {:03X} with parent {:03X}", applet_id, parent); + return HLE::Applets::Applet::Create(applet_id, parent, true, 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; + GetAppletSlot(AppletSlot::LibraryApplet)->loaded = true; return RESULT_SUCCESS; } ResultCode AppletManager::StartLibraryApplet(AppletId applet_id, std::shared_ptr 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); + active_slot = AppletSlot::LibraryApplet; - // 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; + auto send_res = SendParameter({ + .sender_id = GetAppletSlotId(last_library_launcher_slot), + .destination_id = applet_id, + .signal = SignalType::Wakeup, + .object = std::move(object), + .buffer = buffer, + }); + if (send_res.IsError()) { + active_slot = last_library_launcher_slot; + return send_res; } + + return RESULT_SUCCESS; } ResultCode AppletManager::PrepareToCloseLibraryApplet(bool not_pause, bool exiting, bool jump_home) { if (next_parameter) { - return ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet, - ErrorSummary::InvalidState, ErrorLevel::Status); + return {ErrCodes::ParameterPresent, ErrorModule::Applet, ErrorSummary::InvalidState, + ErrorLevel::Status}; } if (!not_pause) @@ -452,57 +475,151 @@ ResultCode AppletManager::PrepareToCloseLibraryApplet(bool not_pause, bool exiti } ResultCode AppletManager::CloseLibraryApplet(std::shared_ptr object, - std::vector buffer) { - auto& slot = applet_slots[static_cast(AppletSlot::LibraryApplet)]; + const std::vector& buffer) { + auto slot = GetAppletSlot(AppletSlot::LibraryApplet); + auto destination_id = GetAppletSlotId(last_library_launcher_slot); - MessageParameter param; - // TODO(Subv): The destination id should be the "current applet slot id", which changes - // constantly depending on what is going on in the system. Most of the time it is the running - // application, but it could be something else if a system applet is launched. - param.destination_id = AppletId::Application; - param.sender_id = slot.applet_id; - param.object = std::move(object); - param.signal = library_applet_closing_command; - param.buffer = std::move(buffer); + active_slot = last_library_launcher_slot; - ResultCode result = SendParameter(param); + MessageParameter param = { + .sender_id = slot->applet_id, + .destination_id = destination_id, + .signal = library_applet_closing_command, + .object = std::move(object), + .buffer = buffer, + }; if (library_applet_closing_command != SignalType::WakeupByPause) { - // TODO(Subv): Terminate the running applet title - slot.Reset(); + CancelAndSendParameter(param); + // TODO: Terminate the running applet title + slot->Reset(); + } else { + SendParameter(param); } - return result; + return RESULT_SUCCESS; +} + +ResultCode AppletManager::CancelLibraryApplet(bool app_exiting) { + if (next_parameter) { + return {ErrCodes::ParameterPresent, ErrorModule::Applet, ErrorSummary::InvalidState, + ErrorLevel::Status}; + } + + auto slot = GetAppletSlot(AppletSlot::LibraryApplet); + if (!slot->registered) { + return {ErrCodes::InvalidAppletSlot, ErrorModule::Applet, ErrorSummary::InvalidState, + ErrorLevel::Status}; + } + + return SendParameter({ + .sender_id = GetAppletSlotId(last_library_launcher_slot), + .destination_id = slot->applet_id, + .signal = SignalType::WakeupByCancel, + }); +} + +ResultCode AppletManager::PrepareToStartSystemApplet(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 {ErrCodes::ParameterPresent, ErrorModule::Applet, ErrorSummary::InvalidState, + ErrorLevel::Status}; + } + + last_system_launcher_slot = active_slot; + return RESULT_SUCCESS; +} + +ResultCode AppletManager::StartSystemApplet(AppletId applet_id, + std::shared_ptr object, + const std::vector& buffer) { + auto source_applet_id = AppletId::None; + if (last_system_launcher_slot != AppletSlot::Error) { + const auto slot_data = GetAppletSlot(last_system_launcher_slot); + source_applet_id = slot_data->applet_id; + + // If a system applet is launching another system applet, reset the slot to avoid conflicts. + // This is needed because system applets won't necessarily call CloseSystemApplet before + // exiting. + if (last_system_launcher_slot == AppletSlot::SystemApplet) { + slot_data->Reset(); + } + } + + // If a system applet is not already registered, it is started by APT. + const auto slot_id = + applet_id == AppletId::HomeMenu ? AppletSlot::HomeMenu : AppletSlot::SystemApplet; + if (!GetAppletSlot(slot_id)->registered) { + auto cfg = Service::CFG::GetModule(system); + auto process = NS::LaunchTitle(FS::MediaType::NAND, + GetTitleIdForApplet(applet_id, cfg->GetRegionValue())); + if (!process) { + // TODO: Find the right error code. + return {ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotSupported, + ErrorLevel::Permanent}; + } + } + + active_slot = slot_id; + + SendApplicationParameterAfterRegistration({ + .sender_id = source_applet_id, + .destination_id = applet_id, + .signal = SignalType::Wakeup, + .object = std::move(object), + .buffer = buffer, + }); + + return RESULT_SUCCESS; +} + +ResultCode AppletManager::PrepareToCloseSystemApplet() { + if (next_parameter) { + return {ErrCodes::ParameterPresent, ErrorModule::Applet, ErrorSummary::InvalidState, + ErrorLevel::Status}; + } + + return RESULT_SUCCESS; +} + +ResultCode AppletManager::CloseSystemApplet(std::shared_ptr object, + const std::vector& buffer) { + ASSERT_MSG(active_slot == AppletSlot::HomeMenu || active_slot == AppletSlot::SystemApplet, + "Attempting to close a system applet from a non-system applet."); + + auto slot = GetAppletSlot(active_slot); + + active_slot = last_system_launcher_slot; + + // TODO: Send a parameter to the application only if the application ordered the applet to + // close. + + // TODO: Terminate the running applet title + slot->Reset(); + + 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}", 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)"); + auto slot = GetAppletSlotFromId(app_id); + if (slot == AppletSlot::Error) { return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, ErrorLevel::Status); } - auto cfg = Service::CFG::GetModule(system); - ASSERT_MSG(cfg, "CFG Module missing!"); - u32 region_value = cfg->GetRegionValue(); - return MakeResult({GetTitleIdForApplet(app_id, region_value), - Service::FS::MediaType::NAND, slot->registered, slot->loaded, - slot->attributes.raw}); + auto slot_data = GetAppletSlot(slot); + if (!slot_data->registered) { + return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, + ErrorLevel::Status); + } + + // TODO: Basic heuristic to guess media type, needs proper implementation. + auto media_type = ((slot_data->title_id >> 32) & 0xFFFFFFFF) == 0x00040000 + ? Service::FS::MediaType::SDMC + : Service::FS::MediaType::NAND; + return MakeResult({slot_data->title_id, media_type, slot_data->registered, + slot_data->loaded, slot_data->attributes.raw}); } ResultCode AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType media_type, @@ -511,21 +628,18 @@ ResultCode AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType // for the Application slot is already in use. The way this is implemented in hardware is to // launch the Home Menu and tell it to launch our desired application. - // Save the title data to send it to the Home Menu when DoApplicationJump is called. - const auto& application_slot = applet_slots[static_cast(AppletSlot::Application)]; - ASSERT_MSG(flags != ApplicationJumpFlags::UseStoredParameters, "Unimplemented application jump flags 1"); - if (flags == ApplicationJumpFlags::UseCurrentParameters) { - title_id = application_slot.title_id; - } - - app_jump_parameters.current_title_id = application_slot.title_id; + // Save the title data to send it to the Home Menu when DoApplicationJump is called. + auto application_slot_data = GetAppletSlot(AppletSlot::Application); + app_jump_parameters.current_title_id = application_slot_data->title_id; // TODO(Subv): Retrieve the correct media type of the currently-running application. For now // just assume NAND. app_jump_parameters.current_media_type = FS::MediaType::NAND; - app_jump_parameters.next_title_id = title_id; + app_jump_parameters.next_title_id = flags == ApplicationJumpFlags::UseCurrentParameters + ? application_slot_data->title_id + : title_id; app_jump_parameters.next_media_type = media_type; app_jump_parameters.flags = flags; @@ -535,29 +649,29 @@ ResultCode AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType return RESULT_SUCCESS; } -ResultCode AppletManager::DoApplicationJump(DeliverArg arg) { +ResultCode AppletManager::DoApplicationJump(const DeliverArg& arg) { // Note: The real console uses the Home Menu to perform the application jump, it goes // OldApplication->Home Menu->NewApplication. We do not need to use the Home Menu to do this so // we launch the new application directly. In the real APT service, the Home Menu must be // running to do this, otherwise error 0xC8A0CFF0 is returned. - auto& application_slot = applet_slots[static_cast(AppletSlot::Application)]; - - if (app_jump_parameters.flags != ApplicationJumpFlags::UseCurrentParameters) { - // The source program ID is not updated when using flags 0x2. - arg.source_program_id = application_slot.title_id; - } - - application_slot.Reset(); + auto application_slot_data = GetAppletSlot(AppletSlot::Application); + auto title_id = application_slot_data->title_id; + application_slot_data->Reset(); // Set the delivery parameters. - deliver_arg = std::move(arg); + deliver_arg = arg; + if (app_jump_parameters.flags != ApplicationJumpFlags::UseCurrentParameters) { + // The source program ID is not updated when using flags 0x2. + deliver_arg->source_program_id = title_id; + } // TODO(Subv): Terminate the current Application. // Note: The real console sends signal 17 (WakeupToLaunchApplication) to the Home Menu, this // prompts it to call GetProgramIdOnApplicationJump and // PrepareToStartApplication/StartApplication on the title to launch. + active_slot = AppletSlot::Application; // Perform a soft-reset if we're trying to relaunch the same title. // TODO(Subv): Note that this reboots the entire emulated system, a better way would be to @@ -565,8 +679,8 @@ ResultCode AppletManager::DoApplicationJump(DeliverArg arg) { // installed titles since we have no way of getting the file path of an arbitrary game dump // based only on the title id. - std::string new_path = Service::AM::GetTitleContentPath(app_jump_parameters.next_media_type, - app_jump_parameters.next_title_id); + auto new_path = Service::AM::GetTitleContentPath(app_jump_parameters.next_media_type, + app_jump_parameters.next_title_id); if (new_path.empty() || !FileUtil::Exists(new_path)) { LOG_CRITICAL( Service_APT, @@ -594,16 +708,17 @@ ResultCode AppletManager::DoApplicationJump(DeliverArg arg) { } ResultCode AppletManager::PrepareToStartApplication(u64 title_id, FS::MediaType media_type) { - // TODO(Subv): This should check that the current applet is of System type and return 0xc8a0cc04 - // if not. + if (active_slot == AppletSlot::Error || + GetAppletSlot(active_slot)->attributes.applet_pos != static_cast(AppletPos::System)) { + return {ErrCodes::InvalidAppletSlot, ErrorModule::Applet, ErrorSummary::InvalidState, + ErrorLevel::Status}; + } // TODO(Subv): This should return 0xc8a0cff0 if the applet preparation state is already set - const auto& application_slot = applet_slots[static_cast(AppletSlot::Application)]; - - if (application_slot.registered) { - // TODO(Subv): Convert this to the enum constructor of ResultCode - return ResultCode(0xc8a0cffc); + if (GetAppletSlot(AppletSlot::Application)->registered) { + return {ErrorDescription::AlreadyExists, ErrorModule::Applet, ErrorSummary::InvalidState, + ErrorLevel::Status}; } ASSERT_MSG(!app_start_parameters, @@ -633,8 +748,10 @@ ResultCode AppletManager::StartApplication(const std::vector& parameter, // PM::LaunchTitle. We should research more about that. ASSERT_MSG(app_start_parameters, "Trying to start an application without preparing it first."); + active_slot = AppletSlot::Application; + // Launch the title directly. - const auto process = + auto process = NS::LaunchTitle(app_start_parameters->next_media_type, app_start_parameters->next_title_id); if (!process) { LOG_CRITICAL(Service_APT, "Failed to launch title during application start, exiting."); @@ -652,22 +769,20 @@ ResultCode AppletManager::StartApplication(const std::vector& parameter, ResultCode AppletManager::WakeupApplication() { // Send a Wakeup signal via the apt parameter to the application once it registers itself. - // The real APT service does this by spinwaiting on another thread until the application is + // The real APT service does this by spin waiting on another thread until the application is // registered. - MessageParameter wakeup_parameter{}; - wakeup_parameter.signal = SignalType::Wakeup; - wakeup_parameter.sender_id = AppletId::HomeMenu; - wakeup_parameter.destination_id = AppletId::Application; - SendApplicationParameterAfterRegistration(wakeup_parameter); + SendApplicationParameterAfterRegistration({.sender_id = AppletId::HomeMenu, + .destination_id = AppletId::Application, + .signal = SignalType::Wakeup}); return RESULT_SUCCESS; } void AppletManager::SendApplicationParameterAfterRegistration(const MessageParameter& parameter) { - const auto* slot = GetAppletSlotData(AppletId::Application); + auto slot = GetAppletSlotFromId(parameter.destination_id); // If the application is already registered, immediately send the parameter - if (slot && slot->registered) { + if (slot != AppletSlot::Error && GetAppletSlot(slot)->registered) { CancelAndSendParameter(parameter); return; } @@ -677,22 +792,20 @@ void AppletManager::SendApplicationParameterAfterRegistration(const MessageParam } void AppletManager::EnsureHomeMenuLoaded() { - const auto& system_slot = applet_slots[static_cast(AppletSlot::SystemApplet)]; // TODO(Subv): The real APT service sends signal 12 (WakeupByCancel) to the currently running // System applet, waits for it to finish, and then launches the Home Menu. - ASSERT_MSG(!system_slot.registered, "A system applet is already running"); + ASSERT_MSG(!GetAppletSlot(AppletSlot::SystemApplet)->registered, + "A system applet is already running"); - const auto& menu_slot = applet_slots[static_cast(AppletSlot::HomeMenu)]; - - if (menu_slot.registered) { + if (GetAppletSlot(AppletSlot::HomeMenu)->registered) { // The Home Menu is already running. return; } auto cfg = Service::CFG::GetModule(system); ASSERT_MSG(cfg, "CFG Module missing!"); - u32 region_value = cfg->GetRegionValue(); - u64 menu_title_id = GetTitleIdForApplet(AppletId::HomeMenu, region_value); + + auto menu_title_id = GetTitleIdForApplet(AppletId::HomeMenu, cfg->GetRegionValue()); auto process = NS::LaunchTitle(FS::MediaType::NAND, menu_title_id); if (!process) { LOG_WARNING(Service_APT, @@ -701,6 +814,7 @@ void AppletManager::EnsureHomeMenuLoaded() { } AppletManager::AppletManager(Core::System& system) : system(system) { + lock = system.Kernel().CreateMutex(false, "APT_U:Lock"); for (std::size_t slot = 0; slot < applet_slots.size(); ++slot) { auto& slot_data = applet_slots[slot]; slot_data.slot = static_cast(slot); diff --git a/src/core/hle/service/apt/applet_manager.h b/src/core/hle/service/apt/applet_manager.h index 78b6ed32c..b7a11500a 100644 --- a/src/core/hle/service/apt/applet_manager.h +++ b/src/core/hle/service/apt/applet_manager.h @@ -103,10 +103,13 @@ private: friend class boost::serialization::access; }; -/// Holds information about the parameters used in StartLibraryApplet -struct AppletStartupParameter { - std::shared_ptr object = nullptr; - std::vector buffer; +enum class AppletPos { + Application = 0, + Library = 1, + System = 2, + SysLibrary = 3, + Resident = 4, + AutoLibrary = 5 }; union AppletAttributes { @@ -125,6 +128,56 @@ enum class ApplicationJumpFlags : u8 { UseCurrentParameters = 2 }; +struct DeliverArg { + std::vector param; + std::vector hmac; + u64 source_program_id = std::numeric_limits::max(); + +private: + template + void serialize(Archive& ar, const unsigned int) { + ar& param; + ar& hmac; + ar& source_program_id; + } + friend class boost::serialization::access; +}; + +struct ApplicationJumpParameters { + u64 next_title_id; + FS::MediaType next_media_type; + ApplicationJumpFlags flags; + + u64 current_title_id; + FS::MediaType current_media_type; + +private: + template + void serialize(Archive& ar, const unsigned int file_version) { + ar& next_title_id; + ar& next_media_type; + if (file_version > 0) { + ar& flags; + } + ar& current_title_id; + ar& current_media_type; + } + friend class boost::serialization::access; +}; + +struct ApplicationStartParameters { + u64 next_title_id; + FS::MediaType next_media_type; + +private: + template + void serialize(Archive& ar, const unsigned int) { + ar& next_title_id; + ar& next_media_type; + } + friend class boost::serialization::access; +}; + class AppletManager : public std::enable_shared_from_this { public: explicit AppletManager(Core::System& system); @@ -142,41 +195,42 @@ public: bool CancelParameter(bool check_sender, AppletId sender_appid, bool check_receiver, AppletId receiver_appid); + struct GetLockHandleResult { + AppletAttributes corrected_attributes; + u32 state; + std::shared_ptr lock; + }; + ResultVal GetLockHandle(AppletAttributes attributes); + struct InitializeResult { std::shared_ptr notification_event; std::shared_ptr 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, std::shared_ptr object, const std::vector& buffer); ResultCode PrepareToCloseLibraryApplet(bool not_pause, bool exiting, bool jump_home); - ResultCode CloseLibraryApplet(std::shared_ptr object, std::vector buffer); + ResultCode CloseLibraryApplet(std::shared_ptr object, + const std::vector& buffer); + ResultCode CancelLibraryApplet(bool app_exiting); + + ResultCode PrepareToStartSystemApplet(AppletId applet_id); + ResultCode StartSystemApplet(AppletId applet_id, std::shared_ptr object, + const std::vector& buffer); + ResultCode PrepareToCloseSystemApplet(); + ResultCode CloseSystemApplet(std::shared_ptr object, + const std::vector& buffer); ResultCode PrepareToDoApplicationJump(u64 title_id, FS::MediaType media_type, ApplicationJumpFlags flags); - - struct DeliverArg { - std::vector param; - std::vector hmac; - u64 source_program_id = std::numeric_limits::max(); - - private: - template - void serialize(Archive& ar, const unsigned int) { - ar& param; - ar& hmac; - ar& source_program_id; - } - friend class boost::serialization::access; - }; - - ResultCode DoApplicationJump(DeliverArg arg); + ResultCode DoApplicationJump(const DeliverArg& arg); boost::optional ReceiveDeliverArg() const { return deliver_arg; @@ -197,49 +251,16 @@ public: bool loaded; u32 attributes; }; - ResultVal GetAppletInfo(AppletId app_id); - struct ApplicationJumpParameters { - u64 next_title_id; - FS::MediaType next_media_type; - ApplicationJumpFlags flags; - - u64 current_title_id; - FS::MediaType current_media_type; - - private: - template - void serialize(Archive& ar, const unsigned int file_version) { - ar& next_title_id; - ar& next_media_type; - if (file_version > 0) { - ar& flags; - } - ar& current_title_id; - ar& current_media_type; - } - friend class boost::serialization::access; - }; - ApplicationJumpParameters GetApplicationJumpParameters() const { return app_jump_parameters; } - struct ApplicationStartParameters { - u64 next_title_id; - FS::MediaType next_media_type; - - private: - template - void serialize(Archive& ar, const unsigned int) { - ar& next_title_id; - ar& next_media_type; - } - friend class boost::serialization::access; - }; - private: + /// APT lock retrieved via GetLockHandle. + std::shared_ptr lock; + /// Parameter data to be returned in the next call to Glance/ReceiveParameter. // NOTE: A bug in gcc prevents serializing std::optional boost::optional next_parameter; @@ -248,6 +269,10 @@ private: /// APT::Initialize. boost::optional delayed_parameter; + ApplicationJumpParameters app_jump_parameters{}; + boost::optional app_start_parameters{}; + boost::optional deliver_arg{}; + static constexpr std::size_t NumAppletSlot = 4; enum class AppletSlot : u8 { @@ -292,16 +317,28 @@ private: friend class boost::serialization::access; }; - ApplicationJumpParameters app_jump_parameters{}; - boost::optional app_start_parameters{}; - boost::optional deliver_arg{}; - // Holds data about the concurrently running applets in the system. std::array applet_slots = {}; + AppletSlot active_slot = AppletSlot::Error; - // This overload returns nullptr if no applet with the specified id has been started. - AppletSlotData* GetAppletSlotData(AppletId id); - AppletSlotData* GetAppletSlotData(AppletAttributes attributes); + AppletSlot last_library_launcher_slot = AppletSlot::Error; + SignalType library_applet_closing_command = SignalType::None; + AppletId last_prepared_library_applet = AppletId::None; + AppletSlot last_system_launcher_slot = AppletSlot::Error; + + Core::System& system; + + AppletSlotData* GetAppletSlot(AppletSlot slot) { + return &applet_slots[static_cast(slot)]; + } + + AppletId GetAppletSlotId(AppletSlot slot) { + return slot != AppletSlot::Error ? GetAppletSlot(slot)->applet_id : AppletId::None; + } + + AppletSlot GetAppletSlotFromId(AppletId id); + AppletSlot GetAppletSlotFromAttributes(AppletAttributes attributes); + AppletSlot GetAppletSlotFromPos(AppletPos pos); /// Checks if the Application slot has already been registered and sends the parameter to it, /// otherwise it queues for sending when the application registers itself with APT::Enable. @@ -309,12 +346,6 @@ private: void EnsureHomeMenuLoaded(); - // Command that will be sent to the application when a library applet calls CloseLibraryApplet. - SignalType library_applet_closing_command; - - Core::System& system; - -private: template void serialize(Archive& ar, const unsigned int file_version) { ar& next_parameter; @@ -323,6 +354,11 @@ private: ar& delayed_parameter; ar& app_start_parameters; ar& deliver_arg; + ar& active_slot; + ar& last_library_launcher_slot; + ar& last_prepared_library_applet; + ar& last_system_launcher_slot; + ar& lock; } ar& applet_slots; ar& library_applet_closing_command; @@ -332,7 +368,7 @@ private: } // namespace Service::APT -BOOST_CLASS_VERSION(Service::APT::AppletManager::ApplicationJumpParameters, 1) +BOOST_CLASS_VERSION(Service::APT::ApplicationJumpParameters, 1) BOOST_CLASS_VERSION(Service::APT::AppletManager, 1) SERVICE_CONSTRUCT(Service::APT::AppletManager) diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 1983622ae..bb0d19f7a 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -39,7 +39,6 @@ void Module::serialize(Archive& ar, const unsigned int file_version) { ar& shared_font_mem; ar& shared_font_loaded; ar& shared_font_relocated; - ar& lock; ar& cpu_percent; ar& unknown_ns_state_field; ar& screen_capture_buffer; @@ -63,8 +62,8 @@ std::shared_ptr Module::NSInterface::GetModule() const { void Module::NSInterface::SetWirelessRebootInfo(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x06, 1, 2); // 0x00060042 - u32 size = rp.Pop(); - auto buffer = rp.PopStaticBuffer(); + const auto size = rp.Pop(); + const auto buffer = rp.PopStaticBuffer(); apt->wireless_reboot_info = std::move(buffer); @@ -76,8 +75,8 @@ void Module::NSInterface::SetWirelessRebootInfo(Kernel::HLERequestContext& ctx) void Module::APTInterface::Initialize(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x2, 2, 0); // 0x20080 - AppletId app_id = rp.PopEnum(); - u32 attributes = rp.Pop(); + const auto app_id = rp.PopEnum(); + const auto attributes = rp.Pop(); LOG_DEBUG(Service_APT, "called app_id={:#010X}, attributes={:#010X}", app_id, attributes); @@ -86,10 +85,9 @@ void Module::APTInterface::Initialize(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(result.Code()); } else { - auto events = std::move(result).Unwrap(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(events.notification_event, events.parameter_event); + rb.PushCopyObjects(result->notification_event, result->parameter_event); } } @@ -148,9 +146,10 @@ static u32 DecompressLZ11(const u8* in, u8* out) { } bool Module::LoadSharedFont() { - u8 font_region_code; auto cfg = Service::CFG::GetModule(system); ASSERT_MSG(cfg, "CFG Module missing!"); + + u8 font_region_code; switch (cfg->GetRegionValue()) { case 4: // CHN font_region_code = 2; @@ -279,7 +278,7 @@ void Module::APTInterface::GetSharedFont(Kernel::HLERequestContext& ctx) { void Module::APTInterface::GetWirelessRebootInfo(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x45, 1, 0); // 0x00450040 - u32 size = rp.Pop(); + const auto size = rp.Pop(); LOG_WARNING(Service_APT, "called size={:08X}", size); @@ -290,9 +289,11 @@ void Module::APTInterface::GetWirelessRebootInfo(Kernel::HLERequestContext& ctx) void Module::APTInterface::NotifyToWait(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x43, 1, 0); // 0x430040 - u32 app_id = rp.Pop(); + const auto app_id = rp.Pop(); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); // No error + LOG_WARNING(Service_APT, "(STUBBED) app_id={}", app_id); } @@ -302,24 +303,26 @@ void Module::APTInterface::GetLockHandle(Kernel::HLERequestContext& ctx) { // Bits [0:2] are the applet type (System, Library, etc) // Bit 5 tells the application that there's a pending APT parameter, // this will cause the app to wait until parameter_event is signaled. - u32 applet_attributes = rp.Pop(); - IPC::RequestBuilder rb = rp.MakeBuilder(3, 2); - rb.Push(RESULT_SUCCESS); // No error + const auto attributes = rp.Pop(); - // TODO(Subv): The output attributes should have an AppletPos of either Library or System | - // Library (depending on the type of the last launched applet) if the input attributes' - // AppletPos has the Library bit set. + LOG_DEBUG(Service_APT, "called applet_attributes={:#010X}", attributes); - rb.Push(applet_attributes); // Applet Attributes, this value is passed to Enable. - rb.Push(0); // Least significant bit = power button state - rb.PushCopyObjects(apt->lock); - - LOG_WARNING(Service_APT, "(STUBBED) called applet_attributes={:#010X}", applet_attributes); + auto result = apt->applet_manager->GetLockHandle(attributes); + if (result.Failed()) { + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(result.Code()); + } else { + IPC::RequestBuilder rb = rp.MakeBuilder(3, 2); + rb.Push(RESULT_SUCCESS); + rb.PushRaw(result->corrected_attributes); + rb.Push(result->state); + rb.PushCopyObjects(result->lock); + } } void Module::APTInterface::Enable(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x3, 1, 0); // 0x30040 - u32 attributes = rp.Pop(); + const auto attributes = rp.Pop(); LOG_DEBUG(Service_APT, "called attributes={:#010X}", attributes); @@ -329,7 +332,8 @@ void Module::APTInterface::Enable(Kernel::HLERequestContext& ctx) { void Module::APTInterface::GetAppletManInfo(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x5, 1, 0); // 0x50040 - u32 unk = rp.Pop(); + const auto unk = rp.Pop(); + IPC::RequestBuilder rb = rp.MakeBuilder(5, 0); rb.Push(RESULT_SUCCESS); // No error rb.Push(0); @@ -342,7 +346,8 @@ void Module::APTInterface::GetAppletManInfo(Kernel::HLERequestContext& ctx) { void Module::APTInterface::IsRegistered(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x9, 1, 0); // 0x90040 - AppletId app_id = rp.PopEnum(); + const auto app_id = rp.PopEnum(); + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); // No error rb.Push(apt->applet_manager->IsRegistered(app_id)); @@ -352,21 +357,23 @@ void Module::APTInterface::IsRegistered(Kernel::HLERequestContext& ctx) { void Module::APTInterface::InquireNotification(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0xB, 1, 0); // 0xB0040 - u32 app_id = rp.Pop(); + const auto app_id = rp.Pop(); + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); // No error rb.Push(static_cast(SignalType::None)); // Signal type + LOG_WARNING(Service_APT, "(STUBBED) called app_id={:#010X}", app_id); } void Module::APTInterface::SendParameter(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0xC, 4, 4); // 0xC0104 - AppletId src_app_id = rp.PopEnum(); - AppletId dst_app_id = rp.PopEnum(); - SignalType signal_type = rp.PopEnum(); - u32 buffer_size = rp.Pop(); - std::shared_ptr object = rp.PopGenericObject(); - std::vector buffer = rp.PopStaticBuffer(); + const auto src_app_id = rp.PopEnum(); + const auto dst_app_id = rp.PopEnum(); + const auto signal_type = rp.PopEnum(); + const auto buffer_size = rp.Pop(); + const auto object = rp.PopGenericObject(); + const auto buffer = rp.PopStaticBuffer(); LOG_DEBUG(Service_APT, "called src_app_id={:#010X}, dst_app_id={:#010X}, signal_type={:#010X}," @@ -374,42 +381,39 @@ void Module::APTInterface::SendParameter(Kernel::HLERequestContext& ctx) { src_app_id, dst_app_id, signal_type, buffer_size); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - - MessageParameter param; - param.destination_id = dst_app_id; - param.sender_id = src_app_id; - param.object = std::move(object); - param.signal = signal_type; - param.buffer = std::move(buffer); - - rb.Push(apt->applet_manager->SendParameter(param)); + rb.Push(apt->applet_manager->SendParameter({ + .sender_id = src_app_id, + .destination_id = dst_app_id, + .signal = signal_type, + .object = object, + .buffer = buffer, + })); } void Module::APTInterface::ReceiveParameter(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0xD, 2, 0); // 0xD0080 const auto app_id = rp.PopEnum(); - const u32 buffer_size = rp.Pop(); + const auto buffer_size = rp.Pop(); LOG_DEBUG(Service_APT, "called app_id={:#010X}, buffer_size={:#010X}", app_id, buffer_size); auto next_parameter = apt->applet_manager->ReceiveParameter(app_id); - if (next_parameter.Failed()) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(next_parameter.Code()); - return; + } else { + const auto size = std::min(static_cast(next_parameter->buffer.size()), buffer_size); + next_parameter->buffer.resize( + buffer_size); // APT always push a buffer with the maximum size + + IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); + rb.Push(RESULT_SUCCESS); // No error + rb.PushEnum(next_parameter->sender_id); + rb.PushEnum(next_parameter->signal); // Signal type + rb.Push(size); // Parameter buffer size + rb.PushMoveObjects(next_parameter->object); + rb.PushStaticBuffer(std::move(next_parameter->buffer), 0); } - - IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); - - rb.Push(RESULT_SUCCESS); // No error - 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 - rb.PushMoveObjects(next_parameter->object); - next_parameter->buffer.resize(buffer_size); // APT always push a buffer with the maximum size - rb.PushStaticBuffer(std::move(next_parameter->buffer), 0); } void Module::APTInterface::GlanceParameter(Kernel::HLERequestContext& ctx) { @@ -420,42 +424,40 @@ void Module::APTInterface::GlanceParameter(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_APT, "called app_id={:#010X}, buffer_size={:#010X}", app_id, buffer_size); auto next_parameter = apt->applet_manager->GlanceParameter(app_id); - if (next_parameter.Failed()) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(next_parameter.Code()); - return; - } + } else { + const auto size = std::min(static_cast(next_parameter->buffer.size()), buffer_size); + next_parameter->buffer.resize( + buffer_size); // APT always push a buffer with the maximum size - IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); - rb.Push(RESULT_SUCCESS); // No error - 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 - rb.PushMoveObjects(next_parameter->object); - next_parameter->buffer.resize(buffer_size); // APT always push a buffer with the maximum size - rb.PushStaticBuffer(std::move(next_parameter->buffer), 0); + IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); + rb.Push(RESULT_SUCCESS); // No error + rb.PushEnum(next_parameter->sender_id); + rb.PushEnum(next_parameter->signal); // Signal type + rb.Push(size); // Parameter buffer size + rb.PushMoveObjects(next_parameter->object); + rb.PushStaticBuffer(std::move(next_parameter->buffer), 0); + } } void Module::APTInterface::CancelParameter(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0xF, 4, 0); // 0xF0100 + const auto check_sender = rp.Pop(); + const auto sender_appid = rp.PopEnum(); + const auto check_receiver = rp.Pop(); + const auto receiver_appid = rp.PopEnum(); - bool check_sender = rp.Pop(); - AppletId sender_appid = rp.PopEnum(); - bool check_receiver = rp.Pop(); - AppletId receiver_appid = rp.PopEnum(); + LOG_DEBUG( + Service_APT, + "called check_sender={}, sender_appid={:#010X}, check_receiver={}, receiver_appid={:#010X}", + check_sender, sender_appid, check_receiver, receiver_appid); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); - rb.Push(RESULT_SUCCESS); // No error rb.Push(apt->applet_manager->CancelParameter(check_sender, sender_appid, check_receiver, receiver_appid)); - - LOG_DEBUG(Service_APT, - "called check_sender={}, sender_appid={:#010X}, " - "check_receiver={}, receiver_appid={:#010X}", - check_sender, sender_appid, check_receiver, receiver_appid); } void Module::APTInterface::PrepareToDoApplicationJump(Kernel::HLERequestContext& ctx) { @@ -464,8 +466,8 @@ void Module::APTInterface::PrepareToDoApplicationJump(Kernel::HLERequestContext& u64 title_id = rp.Pop(); u8 media_type = rp.Pop(); - LOG_WARNING(Service_APT, "(STUBBED) called title_id={:016X}, media_type={:#01X}, flags={:#08X}", - title_id, media_type, flags); + LOG_INFO(Service_APT, "called title_id={:016X}, media_type={:#01X}, flags={:#08X}", title_id, + media_type, flags); ResultCode result = apt->applet_manager->PrepareToDoApplicationJump( title_id, static_cast(media_type), flags); @@ -476,32 +478,15 @@ void Module::APTInterface::PrepareToDoApplicationJump(Kernel::HLERequestContext& void Module::APTInterface::DoApplicationJump(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x32, 2, 4); // 0x00320084 - auto param_size = rp.Pop(); - auto hmac_size = rp.Pop(); - - constexpr u32 max_param_size{0x300}; - constexpr u32 max_hmac_size{0x20}; - if (param_size > max_param_size) { - LOG_ERROR(Service_APT, - "Param size is outside the valid range (capped to {:#010X}): param_size={:#010X}", - max_param_size, param_size); - param_size = max_param_size; - } - if (hmac_size > max_hmac_size) { - LOG_ERROR(Service_APT, - "HMAC size is outside the valid range (capped to {:#010X}): hmac_size={:#010X}", - max_hmac_size, hmac_size); - hmac_size = max_hmac_size; - } - - auto param = rp.PopStaticBuffer(); - auto hmac = rp.PopStaticBuffer(); + const auto param_size = rp.Pop(); + const auto hmac_size = rp.Pop(); + const auto param = rp.PopStaticBuffer(); + const auto hmac = rp.PopStaticBuffer(); LOG_INFO(Service_APT, "called param_size={:08X}, hmac_size={:08X}", param_size, hmac_size); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(apt->applet_manager->DoApplicationJump( - AppletManager::DeliverArg{std::move(param), std::move(hmac)})); + rb.Push(apt->applet_manager->DoApplicationJump(DeliverArg{param, hmac})); } void Module::APTInterface::GetProgramIdOnApplicationJump(Kernel::HLERequestContext& ctx) { @@ -509,7 +494,7 @@ void Module::APTInterface::GetProgramIdOnApplicationJump(Kernel::HLERequestConte LOG_DEBUG(Service_APT, "called"); - auto parameters = apt->applet_manager->GetApplicationJumpParameters(); + const auto parameters = apt->applet_manager->GetApplicationJumpParameters(); IPC::RequestBuilder rb = rp.MakeBuilder(7, 0); rb.Push(RESULT_SUCCESS); @@ -520,13 +505,13 @@ void Module::APTInterface::GetProgramIdOnApplicationJump(Kernel::HLERequestConte } void Module::APTInterface::ReceiveDeliverArg(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x35, 2, 4); // 0x00350080 + IPC::RequestParser rp(ctx, 0x35, 2, 0); // 0x00350080 const auto param_size = rp.Pop(); const auto hmac_size = rp.Pop(); LOG_DEBUG(Service_APT, "called param_size={:08X}, hmac_size={:08X}", param_size, hmac_size); - auto arg = apt->applet_manager->ReceiveDeliverArg().value_or(AppletManager::DeliverArg{}); + auto arg = apt->applet_manager->ReceiveDeliverArg().value_or(DeliverArg{}); arg.param.resize(param_size); arg.hmac.resize(std::min(hmac_size, 0x20)); @@ -540,40 +525,40 @@ void Module::APTInterface::ReceiveDeliverArg(Kernel::HLERequestContext& ctx) { void Module::APTInterface::PrepareToStartApplication(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x15, 5, 0); // 0x00150140 - const u64 title_id = rp.Pop(); - const auto media_type = rp.PopEnum(); + const auto title_id = rp.Pop(); + const auto media_type = static_cast(rp.Pop()); rp.Skip(1, false); // Padding - const u32 flags = rp.Pop(); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(apt->applet_manager->PrepareToStartApplication(title_id, media_type)); + const auto flags = rp.Pop(); LOG_INFO(Service_APT, "called title_id={:#010X} media_type={} flags={:#010X}", title_id, media_type, flags); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(apt->applet_manager->PrepareToStartApplication(title_id, media_type)); } void Module::APTInterface::StartApplication(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x1B, 3, 4); // 0x001B00C4 - const u32 parameter_size = rp.Pop(); - const u32 hmac_size = rp.Pop(); - const bool paused = rp.Pop(); - const std::vector parameter = rp.PopStaticBuffer(); - const std::vector hmac = rp.PopStaticBuffer(); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(apt->applet_manager->StartApplication(parameter, hmac, paused)); + const auto parameter_size = rp.Pop(); + const auto hmac_size = rp.Pop(); + const auto paused = rp.Pop(); + const auto parameter = rp.PopStaticBuffer(); + const auto hmac = rp.PopStaticBuffer(); LOG_INFO(Service_APT, "called parameter_size={:#010X}, hmac_size={:#010X}, paused={}", parameter_size, hmac_size, paused); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(apt->applet_manager->StartApplication(parameter, hmac, paused)); } void Module::APTInterface::WakeupApplication(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x1C, 0, 0); // 0x001C0000 + LOG_DEBUG(Service_APT, "called"); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(apt->applet_manager->WakeupApplication()); - - LOG_DEBUG(Service_APT, "called"); } void Module::APTInterface::AppletUtility(Kernel::HLERequestContext& ctx) { @@ -583,49 +568,49 @@ void Module::APTInterface::AppletUtility(Kernel::HLERequestContext& ctx) { const auto utility_command = rp.Pop(); const auto input_size = rp.Pop(); const auto output_size = rp.Pop(); - [[maybe_unused]] const std::vector input = rp.PopStaticBuffer(); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(RESULT_SUCCESS); // No error + [[maybe_unused]] const auto input = rp.PopStaticBuffer(); LOG_WARNING(Service_APT, "(STUBBED) called command={:#010X}, input_size={:#010X}, output_size={:#010X}", utility_command, input_size, output_size); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); // No error } void Module::APTInterface::SetAppCpuTimeLimit(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x4F, 2, 0); // 0x4F0080 - u32 value = rp.Pop(); - apt->cpu_percent = rp.Pop(); + const auto must_be_one = rp.Pop(); + const auto value = rp.Pop(); - if (value != 1) { - LOG_ERROR(Service_APT, "This value should be one, but is actually {}!", value); + LOG_WARNING(Service_APT, "(STUBBED) called, must_be_one={}, value={}", must_be_one, value); + if (must_be_one != 1) { + LOG_ERROR(Service_APT, "This value should be one, but is actually {}!", must_be_one); } + apt->cpu_percent = value; + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); // No error - - LOG_WARNING(Service_APT, "(STUBBED) called, cpu_percent={}, value={}", apt->cpu_percent, value); } void Module::APTInterface::GetAppCpuTimeLimit(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x50, 1, 0); // 0x500040 - u32 value = rp.Pop(); + const auto must_be_one = rp.Pop(); - if (value != 1) { - LOG_ERROR(Service_APT, "This value should be one, but is actually {}!", value); + LOG_WARNING(Service_APT, "(STUBBED) called, must_be_one={}", must_be_one); + if (must_be_one != 1) { + LOG_ERROR(Service_APT, "This value should be one, but is actually {}!", must_be_one); } IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); // No error rb.Push(apt->cpu_percent); - - LOG_WARNING(Service_APT, "(STUBBED) called, value={}", value); } void Module::APTInterface::PrepareToStartLibraryApplet(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x18, 1, 0); // 0x180040 - AppletId applet_id = rp.PopEnum(); + const auto applet_id = rp.PopEnum(); LOG_DEBUG(Service_APT, "called, applet_id={:08X}", applet_id); @@ -633,23 +618,33 @@ void Module::APTInterface::PrepareToStartLibraryApplet(Kernel::HLERequestContext rb.Push(apt->applet_manager->PrepareToStartLibraryApplet(applet_id)); } +void Module::APTInterface::PrepareToStartSystemApplet(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x19, 1, 0); // 0x190040 + const auto applet_id = rp.PopEnum(); + + LOG_DEBUG(Service_APT, "called, applet_id={:08X}", applet_id); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(apt->applet_manager->PrepareToStartSystemApplet(applet_id)); +} + void Module::APTInterface::PrepareToStartNewestHomeMenu(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x1A, 0, 0); // 0x1A0000 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + LOG_DEBUG(Service_APT, "called"); + // TODO(Subv): This command can only be called by a System Applet (return 0xC8A0CC04 otherwise). // This command must return an error when called, otherwise the Home Menu will try to reboot the // system. rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, ErrorSummary::InvalidState, ErrorLevel::Status)); - - LOG_DEBUG(Service_APT, "called"); } void Module::APTInterface::PreloadLibraryApplet(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x16, 1, 0); // 0x160040 - AppletId applet_id = rp.PopEnum(); + const auto applet_id = rp.PopEnum(); LOG_DEBUG(Service_APT, "called, applet_id={:08X}", applet_id); @@ -659,7 +654,7 @@ void Module::APTInterface::PreloadLibraryApplet(Kernel::HLERequestContext& ctx) void Module::APTInterface::FinishPreloadingLibraryApplet(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x17, 1, 0); // 0x00170040 - AppletId applet_id = rp.PopEnum(); + const auto applet_id = rp.PopEnum(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(apt->applet_manager->FinishPreloadingLibraryApplet(applet_id)); @@ -669,23 +664,35 @@ void Module::APTInterface::FinishPreloadingLibraryApplet(Kernel::HLERequestConte void Module::APTInterface::StartLibraryApplet(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x1E, 2, 4); // 0x1E0084 - AppletId applet_id = rp.PopEnum(); + const auto applet_id = rp.PopEnum(); + const auto buffer_size = rp.Pop(); + const auto object = rp.PopGenericObject(); + const auto buffer = rp.PopStaticBuffer(); - [[maybe_unused]] const std::size_t buffer_size = rp.Pop(); - std::shared_ptr object = rp.PopGenericObject(); - const std::vector buffer = rp.PopStaticBuffer(); - - LOG_DEBUG(Service_APT, "called, applet_id={:08X}", applet_id); + LOG_DEBUG(Service_APT, "called, applet_id={:08X}, size={:08X}", applet_id, buffer_size); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(apt->applet_manager->StartLibraryApplet(applet_id, std::move(object), buffer)); + rb.Push(apt->applet_manager->StartLibraryApplet(applet_id, object, buffer)); +} + +void Module::APTInterface::StartSystemApplet(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x1F, 2, 4); // 0x1F0084 + const auto applet_id = rp.PopEnum(); + const auto buffer_size = rp.Pop(); + const auto object = rp.PopGenericObject(); + const auto buffer = rp.PopStaticBuffer(); + + LOG_DEBUG(Service_APT, "called, applet_id={:08X}, size={:08X}", applet_id, buffer_size); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(apt->applet_manager->StartSystemApplet(applet_id, object, buffer)); } void Module::APTInterface::CloseApplication(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x27, 1, 4); - [[maybe_unused]] const u32 parameters_size = rp.Pop(); - [[maybe_unused]] const std::shared_ptr object = rp.PopGenericObject(); - [[maybe_unused]] const std::vector buffer = rp.PopStaticBuffer(); + [[maybe_unused]] const auto parameters_size = rp.Pop(); + [[maybe_unused]] const auto object = rp.PopGenericObject(); + [[maybe_unused]] const auto buffer = rp.PopStaticBuffer(); LOG_DEBUG(Service_APT, "called"); @@ -697,19 +704,19 @@ void Module::APTInterface::CloseApplication(Kernel::HLERequestContext& ctx) { void Module::APTInterface::CancelLibraryApplet(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x3B, 1, 0); // 0x003B0040 - bool exiting = rp.Pop(); + const auto app_exiting = rp.Pop(); + + LOG_DEBUG(Service_APT, "called app_exiting={}", app_exiting); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(1); // TODO: Find the return code meaning - - LOG_WARNING(Service_APT, "(STUBBED) called exiting={}", exiting); + rb.Push(apt->applet_manager->CancelLibraryApplet(app_exiting)); } void Module::APTInterface::PrepareToCloseLibraryApplet(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x25, 3, 0); // 0x002500C0 - bool not_pause = rp.Pop(); - bool exiting = rp.Pop(); - bool jump_to_home = rp.Pop(); + const auto not_pause = rp.Pop(); + const auto exiting = rp.Pop(); + const auto jump_to_home = rp.Pop(); LOG_DEBUG(Service_APT, "called not_pause={} exiting={} jump_to_home={}", not_pause, exiting, jump_to_home); @@ -718,32 +725,52 @@ void Module::APTInterface::PrepareToCloseLibraryApplet(Kernel::HLERequestContext rb.Push(apt->applet_manager->PrepareToCloseLibraryApplet(not_pause, exiting, jump_to_home)); } +void Module::APTInterface::PrepareToCloseSystemApplet(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x26, 0, 0); // 0x260000 + + LOG_DEBUG(Service_APT, "called"); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(apt->applet_manager->PrepareToCloseSystemApplet()); +} + void Module::APTInterface::CloseLibraryApplet(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x28, 1, 4); // 0x00280044 - u32 parameter_size = rp.Pop(); - auto object = rp.PopGenericObject(); - std::vector buffer = rp.PopStaticBuffer(); + const auto parameter_size = rp.Pop(); + const auto object = rp.PopGenericObject(); + const auto buffer = rp.PopStaticBuffer(); LOG_DEBUG(Service_APT, "called size={}", parameter_size); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(apt->applet_manager->CloseLibraryApplet(std::move(object), std::move(buffer))); + rb.Push(apt->applet_manager->CloseLibraryApplet(object, buffer)); +} + +void Module::APTInterface::CloseSystemApplet(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x29, 1, 4); // 0x00280044 + const auto parameter_size = rp.Pop(); + const auto object = rp.PopGenericObject(); + const auto buffer = rp.PopStaticBuffer(); + + LOG_DEBUG(Service_APT, "called size={}", parameter_size); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(apt->applet_manager->CloseSystemApplet(object, buffer)); } void Module::APTInterface::LoadSysMenuArg(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x36, 1, 0); // 0x00360040 const auto size = std::min(std::size_t{rp.Pop()}, SysMenuArgSize); - // This service function does not clear the buffer. + LOG_DEBUG(Service_APT, "called"); + // This service function does not clear the buffer. std::vector buffer(size); std::copy_n(apt->sys_menu_arg_buffer.cbegin(), size, buffer.begin()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); rb.Push(RESULT_SUCCESS); rb.PushStaticBuffer(std::move(buffer), 0); - - LOG_DEBUG(Service_APT, "called"); } void Module::APTInterface::StoreSysMenuArg(Kernel::HLERequestContext& ctx) { @@ -751,21 +778,24 @@ void Module::APTInterface::StoreSysMenuArg(Kernel::HLERequestContext& ctx) { const auto size = std::min(std::size_t{rp.Pop()}, SysMenuArgSize); const auto& buffer = rp.PopStaticBuffer(); + LOG_DEBUG(Service_APT, "called"); ASSERT_MSG(buffer.size() >= size, "Buffer too small to hold requested data"); std::copy_n(buffer.cbegin(), size, apt->sys_menu_arg_buffer.begin()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); - - LOG_DEBUG(Service_APT, "called"); } void Module::APTInterface::SendCaptureBufferInfo(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x40, 1, 2); // 0x00400042 - u32 size = rp.Pop(); + const auto size = rp.Pop(); + const auto buffer = rp.PopStaticBuffer(); + + LOG_DEBUG(Service_APT, "called"); + ASSERT(size == 0x20); - apt->screen_capture_buffer = rp.PopStaticBuffer(); + apt->screen_capture_buffer = buffer; IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); @@ -773,7 +803,10 @@ void Module::APTInterface::SendCaptureBufferInfo(Kernel::HLERequestContext& ctx) void Module::APTInterface::ReceiveCaptureBufferInfo(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x41, 1, 0); // 0x00410040 - u32 size = rp.Pop(); + const auto size = rp.Pop(); + + LOG_DEBUG(Service_APT, "called"); + ASSERT(size == 0x20); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); @@ -784,7 +817,9 @@ void Module::APTInterface::ReceiveCaptureBufferInfo(Kernel::HLERequestContext& c void Module::APTInterface::GetCaptureInfo(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x4A, 1, 0); // 0x004A0040 - const u32 size = rp.Pop(); + const auto size = rp.Pop(); + + LOG_DEBUG(Service_APT, "called"); ASSERT(size == 0x20); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); @@ -797,29 +832,31 @@ void Module::APTInterface::GetCaptureInfo(Kernel::HLERequestContext& ctx) { void Module::APTInterface::SetScreenCapPostPermission(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x55, 1, 0); // 0x00550040 + LOG_DEBUG(Service_APT, "called, screen_capture_post_permission={}", + apt->screen_capture_post_permission); + apt->screen_capture_post_permission = static_cast(rp.Pop() & 0xF); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); // No error - LOG_WARNING(Service_APT, "(STUBBED) called, screen_capture_post_permission={}", - apt->screen_capture_post_permission); } void Module::APTInterface::GetScreenCapPostPermission(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x56, 0, 0); // 0x00560000 + LOG_DEBUG(Service_APT, "(STUBBED) called, screen_capture_post_permission={}", + apt->screen_capture_post_permission); + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); // No error rb.Push(static_cast(apt->screen_capture_post_permission)); - LOG_WARNING(Service_APT, "(STUBBED) called, screen_capture_post_permission={}", - apt->screen_capture_post_permission); } void Module::APTInterface::GetAppletInfo(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x6, 1, 0); // 0x60040 - auto app_id = rp.PopEnum(); + const auto app_id = rp.PopEnum(); - LOG_DEBUG(Service_APT, "called, app_id={}", app_id); + LOG_DEBUG(Service_APT, "called, app_id={:08X}", app_id); auto info = apt->applet_manager->GetAppletInfo(app_id); if (info.Failed()) { @@ -838,20 +875,11 @@ void Module::APTInterface::GetAppletInfo(Kernel::HLERequestContext& ctx) { void Module::APTInterface::GetStartupArgument(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x51, 2, 0); // 0x00510080 - u32 parameter_size = rp.Pop(); - constexpr u32 max_parameter_size{0x1000}; + const auto parameter_size = rp.Pop(); const auto startup_argument_type = static_cast(rp.Pop()); - LOG_WARNING(Service_APT, "called, startup_argument_type={}, parameter_size={:#010X}", - startup_argument_type, parameter_size); - - if (parameter_size > max_parameter_size) { - LOG_ERROR(Service_APT, - "Parameter size is outside the valid range (capped to {:#010X}): " - "parameter_size={:#010X}", - max_parameter_size, parameter_size); - parameter_size = max_parameter_size; - } + LOG_INFO(Service_APT, "called, startup_argument_type={}, parameter_size={:#010X}", + startup_argument_type, parameter_size); std::vector param; bool exists = false; @@ -877,7 +905,8 @@ void Module::APTInterface::GetStartupArgument(Kernel::HLERequestContext& ctx) { } } - param.resize(parameter_size); + constexpr u32 max_parameter_size{0x1000}; + param.resize(std::min(parameter_size, max_parameter_size)); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); rb.Push(RESULT_SUCCESS); @@ -887,13 +916,17 @@ void Module::APTInterface::GetStartupArgument(Kernel::HLERequestContext& ctx) { void Module::APTInterface::Wrap(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x46, 4, 4); - const u32 output_size = rp.Pop(); - const u32 input_size = rp.Pop(); - const u32 nonce_offset = rp.Pop(); - u32 nonce_size = rp.Pop(); + const auto output_size = rp.Pop(); + const auto input_size = rp.Pop(); + const auto nonce_offset = rp.Pop(); + auto nonce_size = rp.Pop(); auto& input = rp.PopMappedBuffer(); - ASSERT(input.GetSize() == input_size); auto& output = rp.PopMappedBuffer(); + + LOG_DEBUG(Service_APT, "called, output_size={}, input_size={}, nonce_offset={}, nonce_size={}", + output_size, input_size, nonce_offset, nonce_size); + + ASSERT(input.GetSize() == input_size); ASSERT(output.GetSize() == output_size); // Note: real 3DS still returns SUCCESS when the sizes don't match. It seems that it doesn't @@ -901,9 +934,6 @@ void Module::APTInterface::Wrap(Kernel::HLERequestContext& ctx) { ASSERT_MSG(output_size == input_size + HW::AES::CCM_MAC_SIZE, "input_size ({}) doesn't match to output_size ({})", input_size, output_size); - LOG_DEBUG(Service_APT, "called, output_size={}, input_size={}, nonce_offset={}, nonce_size={}", - output_size, input_size, nonce_offset, nonce_size); - // Note: This weird nonce size modification is verified against real 3DS nonce_size = std::min(nonce_size & ~3, HW::AES::CCM_NONCE_SIZE); @@ -924,7 +954,6 @@ void Module::APTInterface::Wrap(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); rb.Push(RESULT_SUCCESS); - // Unmap buffer rb.PushMappedBuffer(input); rb.PushMappedBuffer(output); @@ -932,13 +961,17 @@ void Module::APTInterface::Wrap(Kernel::HLERequestContext& ctx) { void Module::APTInterface::Unwrap(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x47, 4, 4); - const u32 output_size = rp.Pop(); - const u32 input_size = rp.Pop(); - const u32 nonce_offset = rp.Pop(); - u32 nonce_size = rp.Pop(); + const auto output_size = rp.Pop(); + const auto input_size = rp.Pop(); + const auto nonce_offset = rp.Pop(); + auto nonce_size = rp.Pop(); auto& input = rp.PopMappedBuffer(); - ASSERT(input.GetSize() == input_size); auto& output = rp.PopMappedBuffer(); + + LOG_DEBUG(Service_APT, "called, output_size={}, input_size={}, nonce_offset={}, nonce_size={}", + output_size, input_size, nonce_offset, nonce_size); + + ASSERT(input.GetSize() == input_size); ASSERT(output.GetSize() == output_size); // Note: real 3DS still returns SUCCESS when the sizes don't match. It seems that it doesn't @@ -946,9 +979,6 @@ void Module::APTInterface::Unwrap(Kernel::HLERequestContext& ctx) { ASSERT_MSG(output_size == input_size - HW::AES::CCM_MAC_SIZE, "input_size ({}) doesn't match to output_size ({})", input_size, output_size); - LOG_DEBUG(Service_APT, "called, output_size={}, input_size={}, nonce_offset={}, nonce_size={}", - output_size, input_size, nonce_offset, nonce_size); - // Note: This weird nonce size modification is verified against real 3DS nonce_size = std::min(nonce_size & ~3, HW::AES::CCM_NONCE_SIZE); @@ -984,6 +1014,8 @@ void Module::APTInterface::Unwrap(Kernel::HLERequestContext& ctx) { void Module::APTInterface::CheckNew3DSApp(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x101, 0, 0); // 0x01010000 + LOG_WARNING(Service_APT, "(STUBBED) called"); + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); if (apt->unknown_ns_state_field) { rb.Push(RESULT_SUCCESS); @@ -991,41 +1023,39 @@ void Module::APTInterface::CheckNew3DSApp(Kernel::HLERequestContext& ctx) { } else { PTM::CheckNew3DS(rb); } - - LOG_WARNING(Service_APT, "(STUBBED) called"); } void Module::APTInterface::CheckNew3DS(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x102, 0, 0); // 0x01020000 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); - PTM::CheckNew3DS(rb); - LOG_WARNING(Service_APT, "(STUBBED) called"); + + PTM::CheckNew3DS(rb); } void Module::APTInterface::Unknown0x0103(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x103, 0, 0); // 0x01030000 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); + LOG_WARNING(Service_APT, "(STUBBED) called"); + rb.Push(RESULT_SUCCESS); rb.Push(Settings::values.is_new_3ds ? 2 : 1); - - LOG_WARNING(Service_APT, "(STUBBED) called"); } void Module::APTInterface::IsTitleAllowed(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x105, 4, 0); // 0x01050100 - const u64 program_id = rp.Pop(); - const auto media_type = rp.PopEnum(); + const auto program_id = rp.Pop(); + const auto media_type = static_cast(rp.Pop()); rp.Skip(1, false); // Padding + LOG_DEBUG(Service_APT, "called, title_id={:016X} media_type={}", program_id, media_type); + // We allow all titles to be launched, so this function is a no-op IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); rb.Push(true); - - LOG_DEBUG(Service_APT, "called, title_id={:016X} media_type={}", program_id, media_type); } Module::APTInterface::APTInterface(std::shared_ptr apt, const char* name, u32 max_session) @@ -1046,8 +1076,6 @@ Module::Module(Core::System& system) : system(system) { MemoryPermission::ReadWrite, MemoryPermission::Read, 0, Kernel::MemoryRegion::SYSTEM, "APT:SharedFont") .Unwrap(); - - lock = system.Kernel().CreateMutex(false, "APT_U:Lock"); } Module::~Module() {} diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index 78aa636a5..e831a7d77 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -416,6 +416,17 @@ public: */ void PrepareToStartLibraryApplet(Kernel::HLERequestContext& ctx); + /** + * APT::PrepareToStartSystemApplet service function + * Inputs: + * 0 : Command header [0x00190040] + * 1 : Id of the applet to start + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + */ + void PrepareToStartSystemApplet(Kernel::HLERequestContext& ctx); + /** * APT::PrepareToStartNewestHomeMenu service function * Inputs: @@ -464,6 +475,22 @@ public: */ void StartLibraryApplet(Kernel::HLERequestContext& ctx); + /** + * APT::StartSystemApplet service function + * Inputs: + * 0 : Command header [0x001F0084] + * 1 : Id of the applet to start + * 2 : Buffer size + * 3 : 0x0 + * 4 : Handle passed to the applet + * 5 : (Size << 14) | 2 + * 6 : Input buffer virtual address + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + */ + void StartSystemApplet(Kernel::HLERequestContext& ctx); + /** * APT::CloseApplication service function * Inputs: @@ -562,6 +589,16 @@ public: */ void PrepareToCloseLibraryApplet(Kernel::HLERequestContext& ctx); + /** + * APT::PrepareToCloseSystemApplet service function + * Inputs: + * 0 : Command header [0x00260000] + * Outputs: + * 0 : Header code + * 1 : Result code + */ + void PrepareToCloseSystemApplet(Kernel::HLERequestContext& ctx); + /** * APT::CloseLibraryApplet service function * Inputs: @@ -577,6 +614,21 @@ public: */ void CloseLibraryApplet(Kernel::HLERequestContext& ctx); + /** + * APT::CloseSystemApplet service function + * Inputs: + * 0 : Command header [0x00290044] + * 1 : Buffer size + * 2 : 0x0 + * 3 : Object handle + * 4 : (Size << 14) | 2 + * 5 : Input buffer virtual address + * Outputs: + * 0 : Header code + * 1 : Result code + */ + void CloseSystemApplet(Kernel::HLERequestContext& ctx); + /** * APT::LoadSysMenuArg service function * Inputs: @@ -744,8 +796,6 @@ private: bool shared_font_loaded = false; bool shared_font_relocated = false; - std::shared_ptr lock; - u32 cpu_percent = 0; ///< CPU time available to the running application // APT::CheckNew3DSApp will check this unknown_ns_state_field to determine processing mode diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp index 98bee76d4..091ccaf0e 100644 --- a/src/core/hle/service/apt/apt_a.cpp +++ b/src/core/hle/service/apt/apt_a.cpp @@ -32,25 +32,25 @@ APT_A::APT_A(std::shared_ptr apt) {0x00140040, nullptr, "SetPreparationState"}, {0x00150140, &APT_A::PrepareToStartApplication, "PrepareToStartApplication"}, {0x00160040, &APT_A::PreloadLibraryApplet, "PreloadLibraryApplet"}, - {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, + {0x00170040, &APT_A::FinishPreloadingLibraryApplet, "FinishPreloadingLibraryApplet"}, {0x00180040, &APT_A::PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"}, - {0x00190040, nullptr, "PrepareToStartSystemApplet"}, - {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, + {0x00190040, &APT_A::PrepareToStartSystemApplet, "PrepareToStartSystemApplet"}, + {0x001A0000, &APT_A::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"}, {0x001B00C4, &APT_A::StartApplication, "StartApplication"}, {0x001C0000, &APT_A::WakeupApplication, "WakeupApplication"}, {0x001D0000, nullptr, "CancelApplication"}, {0x001E0084, &APT_A::StartLibraryApplet, "StartLibraryApplet"}, - {0x001F0084, nullptr, "StartSystemApplet"}, + {0x001F0084, &APT_A::StartSystemApplet, "StartSystemApplet"}, {0x00200044, nullptr, "StartNewestHomeMenu"}, {0x00210000, nullptr, "OrderToCloseApplication"}, {0x00220040, nullptr, "PrepareToCloseApplication"}, {0x00230040, nullptr, "PrepareToJumpToApplication"}, {0x00240044, nullptr, "JumpToApplication"}, {0x002500C0, &APT_A::PrepareToCloseLibraryApplet, "PrepareToCloseLibraryApplet"}, - {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, + {0x00260000, &APT_A::PrepareToCloseSystemApplet, "PrepareToCloseSystemApplet"}, {0x00270044, &APT_A::CloseApplication, "CloseApplication"}, {0x00280044, &APT_A::CloseLibraryApplet, "CloseLibraryApplet"}, - {0x00290044, nullptr, "CloseSystemApplet"}, + {0x00290044, &APT_A::CloseSystemApplet, "CloseSystemApplet"}, {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, {0x002C0044, nullptr, "JumpToHomeMenu"}, @@ -63,8 +63,8 @@ APT_A::APT_A(std::shared_ptr apt) {0x00330000, &APT_A::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"}, {0x00340084, nullptr, "SendDeliverArg"}, {0x00350080, &APT_A::ReceiveDeliverArg, "ReceiveDeliverArg"}, - {0x00360040, nullptr, "LoadSysMenuArg"}, - {0x00370042, nullptr, "StoreSysMenuArg"}, + {0x00360040, &APT_A::LoadSysMenuArg, "LoadSysMenuArg"}, + {0x00370042, &APT_A::StoreSysMenuArg, "StoreSysMenuArg"}, {0x00380040, nullptr, "PreloadResidentApplet"}, {0x00390040, nullptr, "PrepareToStartResidentApplet"}, {0x003A0044, nullptr, "StartResidentApplet"}, @@ -83,7 +83,7 @@ APT_A::APT_A(std::shared_ptr apt) {0x00470104, &APT_A::Unwrap, "Unwrap"}, {0x00480100, nullptr, "GetProgramInfo"}, {0x00490180, nullptr, "Reboot"}, - {0x004A0040, nullptr, "GetCaptureInfo"}, + {0x004A0040, &APT_A::GetCaptureInfo, "GetCaptureInfo"}, {0x004B00C2, &APT_A::AppletUtility, "AppletUtility"}, {0x004C0000, nullptr, "SetFatalErrDispMode"}, {0x004D0080, nullptr, "GetAppletProgramInfo"}, diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp index 9cb6f1b0f..98ee8cb61 100644 --- a/src/core/hle/service/apt/apt_s.cpp +++ b/src/core/hle/service/apt/apt_s.cpp @@ -24,7 +24,7 @@ APT_S::APT_S(std::shared_ptr apt) {0x000C0104, &APT_S::SendParameter, "SendParameter"}, {0x000D0080, &APT_S::ReceiveParameter, "ReceiveParameter"}, {0x000E0080, &APT_S::GlanceParameter, "GlanceParameter"}, - {0x000F0100, nullptr, "CancelParameter"}, + {0x000F0100, &APT_S::CancelParameter, "CancelParameter"}, {0x001000C2, nullptr, "DebugFunc"}, {0x001100C0, nullptr, "MapProgramIdForDebug"}, {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"}, @@ -34,23 +34,23 @@ APT_S::APT_S(std::shared_ptr apt) {0x00160040, &APT_S::PreloadLibraryApplet, "PreloadLibraryApplet"}, {0x00170040, &APT_S::FinishPreloadingLibraryApplet, "FinishPreloadingLibraryApplet"}, {0x00180040, &APT_S::PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"}, - {0x00190040, nullptr, "PrepareToStartSystemApplet"}, + {0x00190040, &APT_S::PrepareToStartSystemApplet, "PrepareToStartSystemApplet"}, {0x001A0000, &APT_S::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"}, {0x001B00C4, &APT_S::StartApplication, "StartApplication"}, {0x001C0000, &APT_S::WakeupApplication, "WakeupApplication"}, {0x001D0000, nullptr, "CancelApplication"}, {0x001E0084, &APT_S::StartLibraryApplet, "StartLibraryApplet"}, - {0x001F0084, nullptr, "StartSystemApplet"}, + {0x001F0084, &APT_S::StartSystemApplet, "StartSystemApplet"}, {0x00200044, nullptr, "StartNewestHomeMenu"}, {0x00210000, nullptr, "OrderToCloseApplication"}, {0x00220040, nullptr, "PrepareToCloseApplication"}, {0x00230040, nullptr, "PrepareToJumpToApplication"}, {0x00240044, nullptr, "JumpToApplication"}, - {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"}, - {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, + {0x002500C0, &APT_S::PrepareToCloseLibraryApplet, "PrepareToCloseLibraryApplet"}, + {0x00260000, &APT_S::PrepareToCloseSystemApplet, "PrepareToCloseSystemApplet"}, {0x00270044, &APT_S::CloseApplication, "CloseApplication"}, - {0x00280044, nullptr, "CloseLibraryApplet"}, - {0x00290044, nullptr, "CloseSystemApplet"}, + {0x00280044, &APT_S::CloseLibraryApplet, "CloseLibraryApplet"}, + {0x00290044, &APT_S::CloseSystemApplet, "CloseSystemApplet"}, {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, {0x002C0044, nullptr, "JumpToHomeMenu"}, @@ -62,13 +62,13 @@ APT_S::APT_S(std::shared_ptr apt) {0x00320084, &APT_S::DoApplicationJump, "DoApplicationJump"}, {0x00330000, &APT_S::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"}, {0x00340084, nullptr, "SendDeliverArg"}, - {0x00350080, nullptr, "ReceiveDeliverArg"}, + {0x00350080, &APT_S::ReceiveDeliverArg, "ReceiveDeliverArg"}, {0x00360040, &APT_S::LoadSysMenuArg, "LoadSysMenuArg"}, {0x00370042, &APT_S::StoreSysMenuArg, "StoreSysMenuArg"}, {0x00380040, nullptr, "PreloadResidentApplet"}, {0x00390040, nullptr, "PrepareToStartResidentApplet"}, {0x003A0044, nullptr, "StartResidentApplet"}, - {0x003B0040, nullptr, "CancelLibraryApplet"}, + {0x003B0040, &APT_S::CancelLibraryApplet, "CancelLibraryApplet"}, {0x003C0042, nullptr, "SendDspSleep"}, {0x003D0042, nullptr, "SendDspWakeUp"}, {0x003E0080, nullptr, "ReplySleepQuery"}, diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp index da119a177..329187153 100644 --- a/src/core/hle/service/apt/apt_u.cpp +++ b/src/core/hle/service/apt/apt_u.cpp @@ -34,23 +34,23 @@ APT_U::APT_U(std::shared_ptr apt) {0x00160040, &APT_U::PreloadLibraryApplet, "PreloadLibraryApplet"}, {0x00170040, &APT_U::FinishPreloadingLibraryApplet, "FinishPreloadingLibraryApplet"}, {0x00180040, &APT_U::PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"}, - {0x00190040, nullptr, "PrepareToStartSystemApplet"}, - {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, + {0x00190040, &APT_U::PrepareToStartSystemApplet, "PrepareToStartSystemApplet"}, + {0x001A0000, &APT_U::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"}, {0x001B00C4, &APT_U::StartApplication, "StartApplication"}, {0x001C0000, &APT_U::WakeupApplication, "WakeupApplication"}, {0x001D0000, nullptr, "CancelApplication"}, {0x001E0084, &APT_U::StartLibraryApplet, "StartLibraryApplet"}, - {0x001F0084, nullptr, "StartSystemApplet"}, + {0x001F0084, &APT_U::StartSystemApplet, "StartSystemApplet"}, {0x00200044, nullptr, "StartNewestHomeMenu"}, {0x00210000, nullptr, "OrderToCloseApplication"}, {0x00220040, nullptr, "PrepareToCloseApplication"}, {0x00230040, nullptr, "PrepareToJumpToApplication"}, {0x00240044, nullptr, "JumpToApplication"}, {0x002500C0, &APT_U::PrepareToCloseLibraryApplet, "PrepareToCloseLibraryApplet"}, - {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, + {0x00260000, &APT_U::PrepareToCloseSystemApplet, "PrepareToCloseSystemApplet"}, {0x00270044, &APT_U::CloseApplication, "CloseApplication"}, {0x00280044, &APT_U::CloseLibraryApplet, "CloseLibraryApplet"}, - {0x00290044, nullptr, "CloseSystemApplet"}, + {0x00290044, &APT_U::CloseSystemApplet, "CloseSystemApplet"}, {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, {0x002C0044, nullptr, "JumpToHomeMenu"}, @@ -95,10 +95,13 @@ APT_U::APT_U(std::shared_ptr apt) {0x00530104, nullptr, "Unwrap1"}, {0x00550040, &APT_U::SetScreenCapPostPermission, "SetScreenCapPostPermission"}, {0x00560000, &APT_U::GetScreenCapPostPermission, "GetScreenCapPostPermission"}, + {0x00570044, nullptr, "WakeupApplication2"}, {0x00580002, nullptr, "GetProgramID"}, {0x01010000, &APT_U::CheckNew3DSApp, "CheckNew3DSApp"}, {0x01020000, &APT_U::CheckNew3DS, "CheckNew3DS"}, {0x01030000, &APT_U::Unknown0x0103, "Unknown0x0103"}, + {0x01040000, nullptr, "IsStandardMemoryLayout"}, + {0x01050100, &APT_U::IsTitleAllowed, "IsTitleAllowed"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index 3593a167c..94a46be4b 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -1388,7 +1388,7 @@ Module::Module(Core::System& system) : system(system) { auto archive_result = systemsavedata_factory.Open(archive_path, 0); // If the archive didn't exist, create the files inside - if (archive_result.Code() != FileSys::ERR_NOT_FORMATTED) { + if (archive_result.Code() != FileSys::ERROR_NOT_FOUND) { ASSERT_MSG(archive_result.Succeeded(), "Could not open the CECD SystemSaveData archive!"); cecd_system_save_data_archive = std::move(archive_result).Unwrap(); } else { diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index 14ab57f49..68ba0b64f 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp @@ -620,6 +620,11 @@ ResultCode Module::FormatConfig() { if (!res.IsSuccess()) return res; + u8 unknown_data = 0; + res = CreateConfigInfoBlk(Unknown_0x000E0000, sizeof(unknown_data), 0x2, &unknown_data); + if (!res.IsSuccess()) + return res; + res = CreateConfigInfoBlk(ConsoleModelBlockID, sizeof(CONSOLE_MODEL_OLD), 0xC, &CONSOLE_MODEL_OLD); if (!res.IsSuccess()) @@ -669,7 +674,7 @@ ResultCode Module::LoadConfigNANDSaveFile() { auto archive_result = systemsavedata_factory.Open(archive_path, 0); // If the archive didn't exist, create the files inside - if (archive_result.Code() == FileSys::ERR_NOT_FORMATTED) { + if (archive_result.Code() == FileSys::ERROR_NOT_FOUND) { // Format the archive to create the directories systemsavedata_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0); diff --git a/src/core/hle/service/frd/frd.cpp b/src/core/hle/service/frd/frd.cpp index 605fc9ab4..0784f9039 100644 --- a/src/core/hle/service/frd/frd.cpp +++ b/src/core/hle/service/frd/frd.cpp @@ -110,6 +110,7 @@ void Module::Interface::GetMyScreenName(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); rb.PushRaw(screen_name); + rb.Push(0); LOG_INFO(Service_FRD, "returning the username defined in cfg"); }