Merge pull request #3086 from Subv/swkbd_launch
HLE/APT: Allow launching native applets instead of HLE ones.
This commit is contained in:
commit
2664042325
5 changed files with 101 additions and 2 deletions
|
@ -47,6 +47,7 @@ namespace Log {
|
||||||
SUB(Service, NDM) \
|
SUB(Service, NDM) \
|
||||||
SUB(Service, NFC) \
|
SUB(Service, NFC) \
|
||||||
SUB(Service, NIM) \
|
SUB(Service, NIM) \
|
||||||
|
SUB(Service, NS) \
|
||||||
SUB(Service, NWM) \
|
SUB(Service, NWM) \
|
||||||
SUB(Service, CAM) \
|
SUB(Service, CAM) \
|
||||||
SUB(Service, CECD) \
|
SUB(Service, CECD) \
|
||||||
|
|
|
@ -64,6 +64,7 @@ enum class Class : ClassType {
|
||||||
Service_NDM, ///< The NDM (Network daemon manager) service
|
Service_NDM, ///< The NDM (Network daemon manager) service
|
||||||
Service_NFC, ///< The NFC service
|
Service_NFC, ///< The NFC service
|
||||||
Service_NIM, ///< The NIM (Network interface manager) 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_NWM, ///< The NWM (Network wlan manager) service
|
||||||
Service_CAM, ///< The CAM (Camera) service
|
Service_CAM, ///< The CAM (Camera) service
|
||||||
Service_CECD, ///< The CECD (StreetPass) service
|
Service_CECD, ///< The CECD (StreetPass) service
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "core/hle/service/apt/bcfnt/bcfnt.h"
|
#include "core/hle/service/apt/bcfnt/bcfnt.h"
|
||||||
#include "core/hle/service/cfg/cfg.h"
|
#include "core/hle/service/cfg/cfg.h"
|
||||||
#include "core/hle/service/fs/archive.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/ptm/ptm.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
#include "core/hw/aes/ccm.h"
|
#include "core/hw/aes/ccm.h"
|
||||||
|
@ -83,6 +84,41 @@ struct AppletSlotData {
|
||||||
// Holds data about the concurrently running applets in the system.
|
// Holds data about the concurrently running applets in the system.
|
||||||
static std::array<AppletSlotData, NumAppletSlot> applet_slots = {};
|
static std::array<AppletSlotData, NumAppletSlot> applet_slots = {};
|
||||||
|
|
||||||
|
struct AppletTitleData {
|
||||||
|
// There are two possible applet ids for each applet.
|
||||||
|
std::array<AppletId, 2> applet_ids;
|
||||||
|
|
||||||
|
// There's a specific TitleId per region for each applet.
|
||||||
|
static constexpr size_t NumRegions = 7;
|
||||||
|
std::array<u64, NumRegions> title_ids;
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr size_t NumApplets = 29;
|
||||||
|
static constexpr std::array<AppletTitleData, NumApplets> 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},
|
||||||
|
{AppletId::Ed1, AppletId::Ed2, 0x400300000C102, 0x400300000C902, 0x400300000D102,
|
||||||
|
0x400300000C102, 0x400300000D902, 0x400300000DF02, 0x400300000E502},
|
||||||
|
// 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.
|
// This overload returns nullptr if no applet with the specified id has been started.
|
||||||
static AppletSlotData* GetAppletSlotData(AppletId id) {
|
static AppletSlotData* GetAppletSlotData(AppletId id) {
|
||||||
auto GetSlot = [](AppletSlot slot) -> AppletSlotData* {
|
auto GetSlot = [](AppletSlot slot) -> AppletSlotData* {
|
||||||
|
@ -771,8 +807,29 @@ void PrepareToStartLibraryApplet(Service::Interface* self) {
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
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<size_t>(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);
|
auto applet = HLE::Applets::Applet::Get(applet_id);
|
||||||
if (applet) {
|
if (applet) {
|
||||||
LOG_WARNING(Service_APT, "applet has already been started id=%08X",
|
LOG_WARNING(Service_APT, "applet has already been started id=%08X",
|
||||||
|
@ -805,8 +862,21 @@ void PreloadLibraryApplet(Service::Interface* self) {
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
|
|
||||||
// TODO(Subv): Launch the requested applet application.
|
const auto& slot = applet_slots[static_cast<size_t>(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);
|
auto applet = HLE::Applets::Applet::Get(applet_id);
|
||||||
if (applet) {
|
if (applet) {
|
||||||
LOG_WARNING(Service_APT, "applet has already been started id=%08X",
|
LOG_WARNING(Service_APT, "applet has already been started id=%08X",
|
||||||
|
|
|
@ -2,12 +2,35 @@
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <cinttypes>
|
||||||
|
#include "core/hle/service/am/am.h"
|
||||||
#include "core/hle/service/ns/ns.h"
|
#include "core/hle/service/ns/ns.h"
|
||||||
#include "core/hle/service/ns/ns_s.h"
|
#include "core/hle/service/ns/ns_s.h"
|
||||||
|
#include "core/loader/loader.h"
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
namespace NS {
|
namespace NS {
|
||||||
|
|
||||||
|
Kernel::SharedPtr<Kernel::Process> 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<Kernel::Process> 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) {
|
void InstallInterfaces(SM::ServiceManager& service_manager) {
|
||||||
std::make_shared<NS_S>()->InstallAsService(service_manager);
|
std::make_shared<NS_S>()->InstallAsService(service_manager);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,15 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
namespace NS {
|
namespace NS {
|
||||||
|
|
||||||
|
/// Loads and launches the title identified by title_id in the specified media type.
|
||||||
|
Kernel::SharedPtr<Kernel::Process> LaunchTitle(FS::MediaType media_type, u64 title_id);
|
||||||
|
|
||||||
/// Registers all NS services with the specified service manager.
|
/// Registers all NS services with the specified service manager.
|
||||||
void InstallInterfaces(SM::ServiceManager& service_manager);
|
void InstallInterfaces(SM::ServiceManager& service_manager);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue