Merge pull request #3086 from Subv/swkbd_launch

HLE/APT: Allow launching native applets instead of HLE ones.
This commit is contained in:
Weiyi Wang 2017-12-03 11:38:29 +02:00 committed by GitHub
commit 2664042325
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 101 additions and 2 deletions

View file

@ -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) \

View file

@ -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

View file

@ -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"
@ -83,6 +84,41 @@ struct AppletSlotData {
// Holds data about the concurrently running applets in the system.
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.
static AppletSlotData* GetAppletSlotData(AppletId id) {
auto GetSlot = [](AppletSlot slot) -> AppletSlotData* {
@ -771,8 +807,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<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);
if (applet) {
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);
// 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);
if (applet) {
LOG_WARNING(Service_APT, "applet has already been started id=%08X",

View file

@ -2,12 +2,35 @@
// Licensed under GPLv2 or any later version
// 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_s.h"
#include "core/loader/loader.h"
namespace Service {
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) {
std::make_shared<NS_S>()->InstallAsService(service_manager);
}

View file

@ -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<Kernel::Process> LaunchTitle(FS::MediaType media_type, u64 title_id);
/// Registers all NS services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);