mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-15 05:50:08 +00:00
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
@ -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) \
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user