From ccd0710e5b8a599ed2403a2bcd1bf28931fd7b75 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 6 Nov 2017 14:51:57 -0500 Subject: [PATCH 1/5] Logging: Add a Service_NS log class for the NS service. --- src/common/logging/backend.cpp | 1 + src/common/logging/log.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 4b83eeb28..0bc611649 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -47,6 +47,7 @@ namespace Log { SUB(Service, NDM) \ SUB(Service, NFC) \ SUB(Service, NIM) \ + SUB(Service, NS) \ SUB(Service, NWM) \ SUB(Service, CAM) \ SUB(Service, CECD) \ diff --git a/src/common/logging/log.h b/src/common/logging/log.h index fe4dfed69..f36642c38 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h @@ -64,6 +64,7 @@ enum class Class : ClassType { Service_NDM, ///< The NDM (Network daemon manager) service Service_NFC, ///< The NFC service Service_NIM, ///< The NIM (Network interface manager) service + Service_NS, ///< The NS (Nintendo User Interface Shell) service Service_NWM, ///< The NWM (Network wlan manager) service Service_CAM, ///< The CAM (Camera) service Service_CECD, ///< The CECD (StreetPass) service From 191565a1b8e8edfdd468f5c77cdbad4520287ff1 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 6 Nov 2017 15:12:15 -0500 Subject: [PATCH 2/5] HLE/NS: Added a function to launch titles installed to the virtual NAND/SD card. It uses AM::GetTitleContentPath to retrieve the path of the program to launch. --- src/core/hle/service/ns/ns.cpp | 23 +++++++++++++++++++++++ src/core/hle/service/ns/ns.h | 4 ++++ 2 files changed, 27 insertions(+) diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 9e19c38bf..9616cc8f6 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp @@ -2,12 +2,35 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include +#include "core/hle/service/am/am.h" #include "core/hle/service/ns/ns.h" #include "core/hle/service/ns/ns_s.h" +#include "core/loader/loader.h" namespace Service { namespace NS { +Kernel::SharedPtr LaunchTitle(FS::MediaType media_type, u64 title_id) { + std::string path = AM::GetTitleContentPath(media_type, title_id); + auto loader = Loader::GetLoader(path); + + if (!loader) { + LOG_WARNING(Service_NS, "Could not find .app for title 0x%016" PRIx64, title_id); + return nullptr; + } + + Kernel::SharedPtr process; + Loader::ResultStatus result = loader->Load(process); + + if (result != Loader::ResultStatus::Success) { + LOG_WARNING(Service_NS, "Error loading .app for title 0x%016" PRIx64, title_id); + return nullptr; + } + + return process; +} + void InstallInterfaces(SM::ServiceManager& service_manager) { std::make_shared()->InstallAsService(service_manager); } diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h index c3d67d98c..6fb171c1a 100644 --- a/src/core/hle/service/ns/ns.h +++ b/src/core/hle/service/ns/ns.h @@ -4,11 +4,15 @@ #pragma once +#include "core/hle/kernel/process.h" #include "core/hle/service/service.h" namespace Service { namespace NS { +/// Loads and launches the title identified by title_id in the specified media type. +Kernel::SharedPtr LaunchTitle(FS::MediaType media_type, u64 title_id); + /// Registers all NS services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); From ecb1c6d2a1645526fc68d35930841217ee7b3ffa Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 6 Nov 2017 16:14:06 -0500 Subject: [PATCH 3/5] HLE/APT: Added a function to retrieve the titleid of an applet based on the current system region. The table was taken from the real APT service, but is incomplete due to the sheer amount of data it contains. There's 29 applets with 7 possible titleids. This table should be filled as needed. --- src/core/hle/service/apt/apt.cpp | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index e82a32868..668ef6037 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -83,6 +83,39 @@ struct AppletSlotData { // Holds data about the concurrently running applets in the system. static std::array applet_slots = {}; +struct AppletTitleData { + // There are two possible applet ids for each applet. + std::array applet_ids; + + // There's a specific TitleId per region for each applet. + static constexpr size_t NumRegions = 7; + std::array title_ids; +}; + +static constexpr size_t NumApplets = 29; +static constexpr std::array applet_titleids = {{ + {AppletId::HomeMenu, AppletId::None, 0x4003000008202, 0x4003000008F02, 0x4003000009802, + 0x4003000008202, 0x400300000A102, 0x400300000A902, 0x400300000B102}, + {AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2, 0x400300000C002, 0x400300000C802, + 0x400300000D002, 0x400300000C002, 0x400300000D802, 0x400300000DE02, 0x400300000E402}, + {AppletId::Error, AppletId::Error2, 0x400300000C502, 0x400300000C502, 0x400300000C502, + 0x400300000C502, 0x400300000CF02, 0x400300000CF02, 0x400300000CF02}, + // TODO(Subv): Fill in the rest of the titleids +}}; + +static u64 GetTitleIdForApplet(AppletId id) { + ASSERT_MSG(id != AppletId::None, "Invalid applet id"); + + auto itr = std::find_if(applet_titleids.begin(), applet_titleids.end(), + [id](const AppletTitleData& data) { + return data.applet_ids[0] == id || data.applet_ids[1] == id; + }); + + ASSERT_MSG(itr != applet_titleids.end(), "Unknown applet id"); + + return itr->title_ids[CFG::GetRegionValue()]; +} + // This overload returns nullptr if no applet with the specified id has been started. static AppletSlotData* GetAppletSlotData(AppletId id) { auto GetSlot = [](AppletSlot slot) -> AppletSlotData* { From d1de6b88640e37e52bac098ecb25524cb8720c16 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 6 Nov 2017 16:16:07 -0500 Subject: [PATCH 4/5] HLE/APT: Try to launch a native applet in PrepareToStartLibraryApplet and PreloadLibraryApplet before falling back to HLE applets. With this commit, you can run native applets if they are in the correct folder of your virtual NAND. Trying to exit the applet will currently cause an invalid read loop due to svcExitProcess not being implemented. --- src/core/hle/service/apt/apt.cpp | 39 ++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 668ef6037..5f2ad6423 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -21,6 +21,7 @@ #include "core/hle/service/apt/bcfnt/bcfnt.h" #include "core/hle/service/cfg/cfg.h" #include "core/hle/service/fs/archive.h" +#include "core/hle/service/ns/ns.h" #include "core/hle/service/ptm/ptm.h" #include "core/hle/service/service.h" #include "core/hw/aes/ccm.h" @@ -804,8 +805,29 @@ void PrepareToStartLibraryApplet(Service::Interface* self) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - // TODO(Subv): Launch the requested applet application. + // The real APT service returns an error if there's a pending APT parameter when this function + // is called. + if (next_parameter) { + rb.Push(ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + const auto& slot = applet_slots[static_cast(AppletSlot::LibraryApplet)]; + + if (slot.registered) { + rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + + auto process = NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id)); + if (process) { + rb.Push(RESULT_SUCCESS); + return; + } + + // If we weren't able to load the native applet title, try to fallback to an HLE implementation. auto applet = HLE::Applets::Applet::Get(applet_id); if (applet) { LOG_WARNING(Service_APT, "applet has already been started id=%08X", @@ -838,8 +860,21 @@ void PreloadLibraryApplet(Service::Interface* self) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - // TODO(Subv): Launch the requested applet application. + const auto& slot = applet_slots[static_cast(AppletSlot::LibraryApplet)]; + if (slot.registered) { + rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + + auto process = NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id)); + if (process) { + rb.Push(RESULT_SUCCESS); + return; + } + + // If we weren't able to load the native applet title, try to fallback to an HLE implementation. auto applet = HLE::Applets::Applet::Get(applet_id); if (applet) { LOG_WARNING(Service_APT, "applet has already been started id=%08X", From 1be31e271aa4f4eb1feb9bb53cae51b37ba14f16 Mon Sep 17 00:00:00 2001 From: Subv Date: Tue, 28 Nov 2017 09:10:19 -0500 Subject: [PATCH 5/5] NS/Applets: Added the MiiSelector applet to the list of native applet ids. --- src/core/hle/service/apt/apt.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 5f2ad6423..062278f87 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -101,6 +101,8 @@ static constexpr std::array applet_titleids = {{ 0x400300000D002, 0x400300000C002, 0x400300000D802, 0x400300000DE02, 0x400300000E402}, {AppletId::Error, AppletId::Error2, 0x400300000C502, 0x400300000C502, 0x400300000C502, 0x400300000C502, 0x400300000CF02, 0x400300000CF02, 0x400300000CF02}, + {AppletId::Ed1, AppletId::Ed2, 0x400300000C102, 0x400300000C902, 0x400300000D102, + 0x400300000C102, 0x400300000D902, 0x400300000DF02, 0x400300000E502}, // TODO(Subv): Fill in the rest of the titleids }};