Merge branch 'master' into npdmfixup

This commit is contained in:
SciresM
2018-10-31 18:02:07 +09:00
committed by GitHub
235 changed files with 6301 additions and 9851 deletions

View File

@@ -21,7 +21,7 @@ TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := source
DATA := data
INCLUDES := include
INCLUDES := include ../../common/include
EXEFS_SRC := exefs_src
DEFINES := -DDISABLE_IPC

View File

@@ -13,60 +13,63 @@
{
"type": "syscalls",
"value": {
"svcSetHeapSize": "0x01",
"svcSetMemoryPermission": "0x02",
"svcSetMemoryAttribute": "0x03",
"svcMapMemory": "0x04",
"svcUnmapMemory": "0x05",
"svcQueryMemory": "0x06",
"svcExitProcess": "0x07",
"svcCreateThread": "0x08",
"svcStartThread": "0x09",
"svcExitThread": "0x0A",
"svcSleepThread": "0x0B",
"svcGetThreadPriority": "0x0C",
"svcSetThreadPriority": "0x0D",
"svcGetThreadCoreMask": "0x0E",
"svcSetThreadCoreMask": "0x0F",
"svcGetCurrentProcessorNumber": "0x10",
"svcSignalEvent": "0x11",
"svcClearEvent": "0x12",
"svcMapSharedMemory": "0x13",
"svcUnmapSharedMemory": "0x14",
"svcCreateTransferMemory": "0x15",
"svcCloseHandle": "0x16",
"svcResetSignal": "0x17",
"svcWaitSynchronization": "0x18",
"svcCancelSynchronization": "0x19",
"svcArbitrateLock": "0x1A",
"svcArbitrateUnlock": "0x1B",
"svcWaitProcessWideKeyAtomic": "0x1C",
"svcSignalProcessWideKey": "0x1D",
"svcGetSystemTick": "0x1E",
"svcConnectToNamedPort": "0x1F",
"svcSendSyncRequestLight": "0x20",
"svcSendSyncRequest": "0x21",
"svcSendSyncRequestWithUserBuffer": "0x22",
"svcSendAsyncRequestWithUserBuffer": "0x23",
"svcGetProcessId": "0x24",
"svcGetThreadId": "0x25",
"svcBreak": "0x26",
"svcOutputDebugString": "0x27",
"svcReturnFromException": "0x28",
"svcGetInfo": "0x29",
"svcWaitForAddress": "0x34",
"svcSignalToAddress": "0x35",
"svcCreateSession": "0x40",
"svcAcceptSession": "0x41",
"svcReplyAndReceiveLight": "0x42",
"svcReplyAndReceive": "0x43",
"svcReplyAndReceiveWithUserBuffer": "0x44",
"svcSetProcessMemoryPermission": "0x73",
"svcMapProcessMemory": "0x74",
"svcUnmapProcessMemory": "0x75",
"svcMapProcessCodeMemory": "0x77",
"svcUnmapProcessCodeMemory": "0x78",
"svcCreateProcess": "0x79"
"svcSetHeapSize" : "0x01",
"svcSetMemoryPermission" : "0x02",
"svcSetMemoryAttribute" : "0x03",
"svcMapMemory" : "0x04",
"svcUnmapMemory" : "0x05",
"svcQueryMemory" : "0x06",
"svcExitProcess" : "0x07",
"svcCreateThread" : "0x08",
"svcStartThread" : "0x09",
"svcExitThread" : "0x0A",
"svcSleepThread" : "0x0B",
"svcGetThreadPriority" : "0x0C",
"svcSetThreadPriority" : "0x0D",
"svcGetThreadCoreMask" : "0x0E",
"svcSetThreadCoreMask" : "0x0F",
"svcGetCurrentProcessorNumber" : "0x10",
"svcSignalEvent" : "0x11",
"svcClearEvent" : "0x12",
"svcMapSharedMemory" : "0x13",
"svcUnmapSharedMemory" : "0x14",
"svcCreateTransferMemory" : "0x15",
"svcCloseHandle" : "0x16",
"svcResetSignal" : "0x17",
"svcWaitSynchronization" : "0x18",
"svcCancelSynchronization" : "0x19",
"svcArbitrateLock" : "0x1A",
"svcArbitrateUnlock" : "0x1B",
"svcWaitProcessWideKeyAtomic" : "0x1C",
"svcSignalProcessWideKey" : "0x1D",
"svcGetSystemTick" : "0x1E",
"svcConnectToNamedPort" : "0x1F",
"svcSendSyncRequestLight" : "0x20",
"svcSendSyncRequest" : "0x21",
"svcSendSyncRequestWithUserBuffer" : "0x22",
"svcSendAsyncRequestWithUserBuffer" : "0x23",
"svcGetProcessId" : "0x24",
"svcGetThreadId" : "0x25",
"svcBreak" : "0x26",
"svcOutputDebugString" : "0x27",
"svcReturnFromException" : "0x28",
"svcGetInfo" : "0x29",
"svcWaitForAddress" : "0x34",
"svcSignalToAddress" : "0x35",
"svcCreateSession" : "0x40",
"svcAcceptSession" : "0x41",
"svcReplyAndReceiveLight" : "0x42",
"svcReplyAndReceive" : "0x43",
"svcReplyAndReceiveWithUserBuffer" : "0x44",
"svcCreateEvent" : "0x45",
"svcReadWriteRegister" : "0x4E",
"svcQueryIoMapping" : "0x55",
"svcSetProcessMemoryPermission" : "0x73",
"svcMapProcessMemory" : "0x74",
"svcUnmapProcessMemory" : "0x75",
"svcMapProcessCodeMemory" : "0x77",
"svcUnmapProcessCodeMemory" : "0x78",
"svcCreateProcess" : "0x79"
}
}
]

View File

@@ -19,11 +19,12 @@
#include <strings.h>
#include <vector>
#include <algorithm>
#include <map>
#include "ldr_registration.hpp"
#include "ldr_content_management.hpp"
#include "ldr_hid.hpp"
#include "ldr_npdm.hpp"
#include "ini.h"
@@ -40,6 +41,12 @@ static u64 g_override_key_combination = KEY_R;
static bool g_override_by_default = true;
static u64 g_override_hbl_tid = 0x010000000000100D;
/* Static buffer for loader.ini contents at runtime. */
static char g_config_ini_data[0x800];
/* SetExternalContentSource extension */
static std::map<u64, ContentManagement::ExternalContentSource> g_external_content_sources;
Result ContentManagement::MountCode(u64 tid, FsStorageId sid) {
char path[FS_MAX_PATH] = {0};
Result rc;
@@ -49,7 +56,11 @@ Result ContentManagement::MountCode(u64 tid, FsStorageId sid) {
TryMountSdCard();
}
if (ShouldOverrideContents() && R_SUCCEEDED(MountCodeNspOnSd(tid))) {
if (g_has_initialized_fs_dev) {
RefreshConfigurationData();
}
if (ShouldOverrideContents(tid) && R_SUCCEEDED(MountCodeNspOnSd(tid))) {
return 0x0;
}
@@ -92,7 +103,7 @@ Result ContentManagement::UnmountCode() {
void ContentManagement::TryMountHblNspOnSd() {
char path[FS_MAX_PATH+1] = {0};
char path[FS_MAX_PATH + 1] = {0};
strncpy(path, g_hbl_sd_path, FS_MAX_PATH);
for (unsigned int i = 0; i < FS_MAX_PATH && path[i] != '\x00'; i++) {
if (path[i] == '\\') {
@@ -259,24 +270,17 @@ static int LoaderIniHandler(void *user, const char *section, const char *name, c
return 1;
}
void ContentManagement::LoadConfiguration(FILE *config) {
void ContentManagement::RefreshConfigurationData() {
FILE *config = fopen("sdmc:/atmosphere/loader.ini", "r");
if (config == NULL) {
return;
}
char *config_str = new char[0x800];
if (config_str != NULL) {
/* Read in string. */
std::fill(config_str, config_str + FS_MAX_PATH, 0);
fread(config_str, 1, 0x7FF, config);
config_str[strlen(config_str)] = 0x0;
ini_parse_string(config_str, LoaderIniHandler, NULL);
delete[] config_str;
}
std::fill(g_config_ini_data, g_config_ini_data + 0x800, 0);
fread(g_config_ini_data, 1, 0x7FF, config);
fclose(config);
ini_parse_string(g_config_ini_data, LoaderIniHandler, NULL);
}
void ContentManagement::TryMountSdCard() {
@@ -293,7 +297,6 @@ void ContentManagement::TryMountSdCard() {
}
if (R_SUCCEEDED(fsdevMountSdmc())) {
ContentManagement::LoadConfiguration(fopen("sdmc:/atmosphere/loader.ini", "r"));
g_has_initialized_fs_dev = true;
}
}
@@ -303,7 +306,7 @@ bool ContentManagement::ShouldReplaceWithHBL(u64 tid) {
return g_mounted_hbl_nsp && tid == g_override_hbl_tid;
}
bool ContentManagement::ShouldOverrideContents() {
bool ContentManagement::ShouldOverrideContents(u64 tid) {
if (HasCreatedTitle(0x0100000000001000)) {
u64 kDown = 0;
bool keys_triggered = (R_SUCCEEDED(HidManagement::GetKeysDown(&kDown)) && ((kDown & g_override_key_combination) != 0));
@@ -312,4 +315,55 @@ bool ContentManagement::ShouldOverrideContents() {
/* Always redirect before qlaunch. */
return g_has_initialized_fs_dev;
}
}
}
/* SetExternalContentSource extension */
ContentManagement::ExternalContentSource *ContentManagement::GetExternalContentSource(u64 tid) {
auto i = g_external_content_sources.find(tid);
if (i == g_external_content_sources.end()) {
return nullptr;
} else {
return &i->second;
}
}
Result ContentManagement::SetExternalContentSource(u64 tid, FsFileSystem filesystem) {
if (g_external_content_sources.size() >= 16) {
return 0x409; /* LAUNCH_QUEUE_FULL */
}
/* Remove any existing ECS for this title. */
ClearExternalContentSource(tid);
char mountpoint[32];
ExternalContentSource::GenerateMountpointName(tid, mountpoint, sizeof(mountpoint));
if (fsdevMountDevice(mountpoint, filesystem) == -1) {
return 0x7802; /* specified mount name already exists */
}
g_external_content_sources.emplace(
std::piecewise_construct,
std::make_tuple(tid),
std::make_tuple(tid, mountpoint));
return 0;
}
void ContentManagement::ClearExternalContentSource(u64 tid) {
auto i = g_external_content_sources.find(tid);
if (i != g_external_content_sources.end()) {
g_external_content_sources.erase(i);
}
}
void ContentManagement::ExternalContentSource::GenerateMountpointName(u64 tid, char *out, size_t max_length) {
snprintf(out, max_length, "ecs-%016lx", tid);
}
ContentManagement::ExternalContentSource::ExternalContentSource(u64 tid, const char *mountpoint) : tid(tid) {
strncpy(this->mountpoint, mountpoint, sizeof(this->mountpoint));
NpdmUtils::InvalidateCache(tid);
}
ContentManagement::ExternalContentSource::~ExternalContentSource() {
fsdevUnmountDevice(mountpoint);
}

View File

@@ -34,9 +34,29 @@ class ContentManagement {
static bool HasCreatedTitle(u64 tid);
static void SetCreatedTitle(u64 tid);
static void LoadConfiguration(FILE *config);
static void RefreshConfigurationData();
static void TryMountSdCard();
static bool ShouldReplaceWithHBL(u64 tid);
static bool ShouldOverrideContents();
static bool ShouldOverrideContents(u64 tid);
/* SetExternalContentSource extension */
class ExternalContentSource {
public:
static void GenerateMountpointName(u64 tid, char *out, size_t max_length);
ExternalContentSource(u64 tid, const char *mountpoint);
~ExternalContentSource();
ExternalContentSource(const ExternalContentSource &other) = delete;
ExternalContentSource(ExternalContentSource &&other) = delete;
ExternalContentSource &operator=(const ExternalContentSource &other) = delete;
ExternalContentSource &operator=(ExternalContentSource &&other) = delete;
const u64 tid;
char mountpoint[32];
};
static ExternalContentSource *GetExternalContentSource(u64 tid); /* returns nullptr if no ECS is set */
static Result SetExternalContentSource(u64 tid, FsFileSystem filesystem); /* takes ownership of filesystem */
static void ClearExternalContentSource(u64 tid);
};

View File

@@ -22,42 +22,18 @@
#include "ldr_launch_queue.hpp"
#include "ldr_registration.hpp"
Result DebugMonitorService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
Result rc = 0xF601;
switch ((DebugMonitorServiceCmd)cmd_id) {
case Dmnt_Cmd_AddTitleToLaunchQueue:
rc = WrapIpcCommandImpl<&DebugMonitorService::add_title_to_launch_queue>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
case Dmnt_Cmd_ClearLaunchQueue:
rc = WrapIpcCommandImpl<&DebugMonitorService::clear_launch_queue>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
case Dmnt_Cmd_GetNsoInfo:
rc = WrapIpcCommandImpl<&DebugMonitorService::get_nso_info>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
default:
break;
}
return rc;
Result DebugMonitorService::AddTitleToLaunchQueue(u64 tid, InPointer<char> args, u32 args_size) {
if (args.num_elements < args_size) args_size = args.num_elements;
return LaunchQueue::Add(tid, args.pointer, args_size);
}
std::tuple<Result> DebugMonitorService::add_title_to_launch_queue(u64 args_size, u64 tid, InPointer<char> args) {
fprintf(stderr, "Add to launch queue: %p, %zX\n", args.pointer, std::min(args_size, args.num_elements));
return {LaunchQueue::add(tid, args.pointer, std::min(args_size, args.num_elements))};
void DebugMonitorService::ClearLaunchQueue() {
LaunchQueue::Clear();
}
std::tuple<Result> DebugMonitorService::clear_launch_queue(u64 dat) {
fprintf(stderr, "Clear launch queue: %lx\n", dat);
LaunchQueue::clear();
return {0};
}
std::tuple<Result, u32> DebugMonitorService::get_nso_info(u64 pid, OutPointerWithClientSize<Registration::NsoInfo> out) {
u32 out_num_nsos = 0;
Result DebugMonitorService::GetNsoInfo(Out<u32> count, OutPointerWithClientSize<Registration::NsoInfo> out, u64 pid) {
/* Zero out the output memory. */
std::fill(out.pointer, out.pointer + out.num_elements, (const Registration::NsoInfo){0});
Result rc = Registration::GetNsoInfosForProcessId(out.pointer, out.num_elements, pid, &out_num_nsos);
return {rc, out_num_nsos};
/* Actually return the nso infos. */
return Registration::GetNsoInfosForProcessId(out.pointer, out.num_elements, pid, count.GetPointer());
}

View File

@@ -17,7 +17,7 @@
#pragma once
#include <switch.h>
#include <stratosphere/iserviceobject.hpp>
#include <stratosphere.hpp>
#include "ldr_registration.hpp"
enum DebugMonitorServiceCmd {
@@ -26,21 +26,16 @@ enum DebugMonitorServiceCmd {
Dmnt_Cmd_GetNsoInfo = 2
};
class DebugMonitorService final : public IServiceObject {
public:
Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override;
Result handle_deferred() override {
/* This service will never defer. */
return 0;
}
DebugMonitorService *clone() override {
return new DebugMonitorService();
}
class DebugMonitorService final : public IServiceObject {
private:
/* Actual commands. */
std::tuple<Result> add_title_to_launch_queue(u64 args_size, u64 tid, InPointer<char> args);
std::tuple<Result> clear_launch_queue(u64 dat);
std::tuple<Result, u32> get_nso_info(u64 pid, OutPointerWithClientSize<Registration::NsoInfo> out);
Result AddTitleToLaunchQueue(u64 tid, InPointer<char> args, u32 args_size);
void ClearLaunchQueue();
Result GetNsoInfo(Out<u32> count, OutPointerWithClientSize<Registration::NsoInfo> out, u64 pid);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MakeServiceCommandMeta<Dmnt_Cmd_AddTitleToLaunchQueue, &DebugMonitorService::AddTitleToLaunchQueue>(),
MakeServiceCommandMeta<Dmnt_Cmd_ClearLaunchQueue, &DebugMonitorService::ClearLaunchQueue>(),
MakeServiceCommandMeta<Dmnt_Cmd_GetNsoInfo, &DebugMonitorService::GetNsoInfo>(),
};
};

View File

@@ -20,8 +20,6 @@
#include "ldr_content_management.hpp"
#include "ldr_hid.hpp"
static bool g_has_opened_hid_session = false;
Result HidManagement::GetKeysDown(u64 *keys) {
if (!ContentManagement::HasCreatedTitle(0x0100000000000013) || R_FAILED(hidInitialize())) {
return MAKERESULT(Module_Libnx, LibnxError_InitFail_HID);

View File

@@ -23,12 +23,12 @@
static std::array<LaunchQueue::LaunchItem, LAUNCH_QUEUE_SIZE> g_launch_queue = {0};
Result LaunchQueue::add(u64 tid, const char *args, u64 arg_size) {
Result LaunchQueue::Add(u64 tid, const char *args, u64 arg_size) {
if(arg_size > LAUNCH_QUEUE_ARG_SIZE_MAX) {
return 0x209;
}
int idx = get_free_index(tid);
int idx = GetFreeIndex(tid);
if(idx == LAUNCH_QUEUE_FULL)
return 0x409;
@@ -39,22 +39,22 @@ Result LaunchQueue::add(u64 tid, const char *args, u64 arg_size) {
return 0x0;
}
Result LaunchQueue::add_copy(u64 tid_base, u64 tid) {
int idx = get_index(tid_base);
Result LaunchQueue::AddCopy(u64 tid_base, u64 tid) {
int idx = GetIndex(tid_base);
if (idx == LAUNCH_QUEUE_FULL) {
return 0x0;
}
return add(tid, g_launch_queue[idx].args, g_launch_queue[idx].arg_size);
return Add(tid, g_launch_queue[idx].args, g_launch_queue[idx].arg_size);
}
Result LaunchQueue::add_item(const LaunchItem *item) {
Result LaunchQueue::AddItem(const LaunchItem *item) {
if(item->arg_size > LAUNCH_QUEUE_ARG_SIZE_MAX) {
return 0x209;
}
int idx = get_free_index(item->tid);
int idx = GetFreeIndex(item->tid);
if(idx == LAUNCH_QUEUE_FULL)
return 0x409;
@@ -62,7 +62,7 @@ Result LaunchQueue::add_item(const LaunchItem *item) {
return 0x0;
}
int LaunchQueue::get_index(u64 tid) {
int LaunchQueue::GetIndex(u64 tid) {
auto it = std::find_if(g_launch_queue.begin(), g_launch_queue.end(), member_equals_fn(&LaunchQueue::LaunchItem::tid, tid));
if (it == g_launch_queue.end()) {
return LAUNCH_QUEUE_FULL;
@@ -70,7 +70,7 @@ int LaunchQueue::get_index(u64 tid) {
return std::distance(g_launch_queue.begin(), it);
}
int LaunchQueue::get_free_index(u64 tid) {
int LaunchQueue::GetFreeIndex(u64 tid) {
for(unsigned int i = 0; i < LAUNCH_QUEUE_SIZE; i++) {
if(g_launch_queue[i].tid == tid || g_launch_queue[i].tid == 0x0) {
return i;
@@ -79,19 +79,19 @@ int LaunchQueue::get_free_index(u64 tid) {
return LAUNCH_QUEUE_FULL;
}
bool LaunchQueue::contains(u64 tid) {
return get_index(tid) != LAUNCH_QUEUE_FULL;
bool LaunchQueue::Contains(u64 tid) {
return GetIndex(tid) != LAUNCH_QUEUE_FULL;
}
void LaunchQueue::clear() {
void LaunchQueue::Clear() {
for (unsigned int i = 0; i < LAUNCH_QUEUE_SIZE; i++) {
g_launch_queue[i].tid = 0;
}
}
LaunchQueue::LaunchItem *LaunchQueue::get_item(u64 tid) {
int idx = get_index(tid);
LaunchQueue::LaunchItem *LaunchQueue::GetItem(u64 tid) {
int idx = GetIndex(tid);
if (idx == LAUNCH_QUEUE_FULL) {
return NULL;
}

View File

@@ -30,13 +30,13 @@ class LaunchQueue {
char args[LAUNCH_QUEUE_ARG_SIZE_MAX];
};
static LaunchQueue::LaunchItem *get_item(u64 tid);
static LaunchQueue::LaunchItem *GetItem(u64 tid);
static Result add(u64 tid, const char *args, u64 arg_size);
static Result add_item(const LaunchItem *item);
static Result add_copy(u64 tid_base, u64 new_tid);
static int get_index(u64 tid);
static int get_free_index(u64 tid);
static bool contains(u64 tid);
static void clear();
static Result Add(u64 tid, const char *args, u64 arg_size);
static Result AddItem(const LaunchItem *item);
static Result AddCopy(u64 tid_base, u64 new_tid);
static int GetIndex(u64 tid);
static int GetFreeIndex(u64 tid);
static bool Contains(u64 tid);
static void Clear();
};

View File

@@ -80,19 +80,7 @@ void __appInit(void) {
fatalSimple(0xCAFE << 4 | 2);
}
rc = splInitialize();
if (R_FAILED(rc)) {
fatalSimple(0xCAFE << 4 | 3);
}
/* Check for exosphere API compatibility. */
u64 exosphere_cfg;
if (R_FAILED(splGetConfig((SplConfigItem)65000, &exosphere_cfg))) {
//fatalSimple(0xCAFE << 4 | 0xFF);
/* TODO: Does Loader need to know about target firmware/master key revision? If so, extract from exosphere_cfg. */
}
//splExit();
CheckAtmosphereVersion();
}
void __appExit(void) {
@@ -104,24 +92,31 @@ void __appExit(void) {
smExit();
}
struct LoaderServerOptions {
static constexpr size_t PointerBufferSize = 0x400;
static constexpr size_t MaxDomains = 0;
static constexpr size_t MaxDomainObjects = 0;
};
int main(int argc, char **argv)
{
consoleDebugInit(debugDevice_SVC);
auto server_manager = new WaitableManager<LoaderServerOptions>(1);
/* TODO: What's a good timeout value to use here? */
auto server_manager = std::make_unique<WaitableManager>(U64_MAX);
/* Add services to manager. */
server_manager->add_waitable(new ServiceServer<ProcessManagerService>("ldr:pm", 1));
server_manager->add_waitable(new ServiceServer<ShellService>("ldr:shel", 3));
server_manager->add_waitable(new ServiceServer<DebugMonitorService>("ldr:dmnt", 2));
if (!kernelAbove300()) {
server_manager->AddWaitable(new ServiceServer<ProcessManagerService>("ldr:pm", 1));
server_manager->AddWaitable(new ServiceServer<ShellService>("ldr:shel", 3));
server_manager->AddWaitable(new ServiceServer<DebugMonitorService>("ldr:dmnt", 2));
if (GetRuntimeFirmwareVersion() < FirmwareVersion_300) {
/* On 1.0.0-2.3.0, Loader services ldr:ro instead of ro. */
server_manager->add_waitable(new ServiceServer<RelocatableObjectsService>("ldr:ro", 0x20));
server_manager->AddWaitable(new ServiceServer<RelocatableObjectsService>("ldr:ro", 0x20));
}
/* Loop forever, servicing our services. */
server_manager->process();
server_manager->Process();
delete server_manager;
return 0;
}

View File

@@ -33,6 +33,12 @@ Result NpdmUtils::LoadNpdmFromCache(u64 tid, NpdmInfo *out) {
return 0;
}
FILE *NpdmUtils::OpenNpdmFromECS(ContentManagement::ExternalContentSource *ecs) {
std::fill(g_npdm_path, g_npdm_path + FS_MAX_PATH, 0);
snprintf(g_npdm_path, FS_MAX_PATH, "%s:/main.npdm", ecs->mountpoint);
return fopen(g_npdm_path, "rb");
}
FILE *NpdmUtils::OpenNpdmFromHBL() {
std::fill(g_npdm_path, g_npdm_path + FS_MAX_PATH, 0);
snprintf(g_npdm_path, FS_MAX_PATH, "hbl:/main.npdm");
@@ -53,7 +59,12 @@ FILE *NpdmUtils::OpenNpdmFromSdCard(u64 title_id) {
FILE *NpdmUtils::OpenNpdm(u64 title_id) {
if (ContentManagement::ShouldOverrideContents()) {
ContentManagement::ExternalContentSource *ecs = nullptr;
if ((ecs = ContentManagement::GetExternalContentSource(title_id)) != nullptr) {
return OpenNpdmFromECS(ecs);
}
if (ContentManagement::ShouldOverrideContents(title_id)) {
if (ContentManagement::ShouldReplaceWithHBL(title_id)) {
return OpenNpdmFromHBL();
}
@@ -182,7 +193,7 @@ Result NpdmUtils::LoadNpdm(u64 tid, NpdmInfo *out) {
info->acid->title_id_range_max = tid;
info->aci0->title_id = tid;
if (ContentManagement::ShouldOverrideContents() && ContentManagement::ShouldReplaceWithHBL(tid)
if (ContentManagement::ShouldOverrideContents(tid) && ContentManagement::ShouldReplaceWithHBL(tid)
&& R_SUCCEEDED(LoadNpdmInternal(OpenNpdmFromExeFS(), &g_original_npdm_cache))) {
NpdmInfo *original_info = &g_original_npdm_cache.info;
/* Fix pool partition. */
@@ -190,7 +201,7 @@ Result NpdmUtils::LoadNpdm(u64 tid, NpdmInfo *out) {
info->acid->flags = (info->acid->flags & 0xFFFFFFC3) | (original_info->acid->flags & 0x0000003C);
}
/* Fix application type. */
const u32 original_application_type = GetApplicationType((u32 *)original_info->aci0_kac, original_info->aci0->kac_size/sizeof(u32)) & 7;
const u32 original_application_type = GetApplicationTypeRaw((u32 *)original_info->aci0_kac, original_info->aci0->kac_size/sizeof(u32)) & 7;
u32 *caps = (u32 *)info->aci0_kac;
for (unsigned int i = 0; i < info->aci0->kac_size/sizeof(u32); i++) {
if ((caps[i] & 0x3FFF) == 0x1FFF) {
@@ -489,4 +500,21 @@ u32 NpdmUtils::GetApplicationType(u32 *caps, size_t num_caps) {
}
}
return application_type;
}
}
/* Like GetApplicationType, except this returns the raw kac descriptor value. */
u32 NpdmUtils::GetApplicationTypeRaw(u32 *caps, size_t num_caps) {
u32 application_type = 0;
for (unsigned int i = 0; i < num_caps; i++) {
if ((caps[i] & 0x3FFF) == 0x1FFF) {
return (caps[i] >> 14) & 7;
}
}
return application_type;
}
void NpdmUtils::InvalidateCache(u64 tid) {
if (g_npdm_cache.info.title_id == tid) {
g_npdm_cache.info = (const NpdmUtils::NpdmInfo){0};
}
}

View File

@@ -19,6 +19,7 @@
#include <cstdio>
#include "ldr_registration.hpp"
#include "ldr_content_management.hpp" /* for ExternalContentSource */
#define MAGIC_META 0x4154454D
#define MAGIC_ACI0 0x30494341
@@ -96,17 +97,20 @@ class NpdmUtils {
static_assert(sizeof(NpdmAci0) == 0x40, "Incorrectly defined NpdmAci0!");
static u32 GetApplicationType(u32 *caps, size_t num_caps);
static u32 GetApplicationTypeRaw(u32 *caps, size_t num_caps);
static Result ValidateCapabilityAgainstRestrictions(u32 *restrict_caps, size_t num_restrict_caps, u32 *&cur_cap, size_t &caps_remaining);
static Result ValidateCapabilities(u32 *acid_caps, size_t num_acid_caps, u32 *aci0_caps, size_t num_aci0_caps);
static FILE *OpenNpdmFromECS(ContentManagement::ExternalContentSource *ecs);
static FILE *OpenNpdmFromHBL();
static FILE *OpenNpdmFromExeFS();
static FILE *OpenNpdmFromSdCard(u64 tid);
static FILE *OpenNpdm(u64 tid);
static Result LoadNpdm(u64 tid, NpdmInfo *out);
static Result LoadNpdmFromCache(u64 tid, NpdmInfo *out);
static void InvalidateCache(u64 tid);
private:
static Result LoadNpdmInternal(FILE *f_npdm, NpdmCache *cache);
};
};

View File

@@ -31,6 +31,12 @@ static bool g_nso_present[NSO_NUM_MAX] = {0};
static char g_nso_path[FS_MAX_PATH] = {0};
FILE *NsoUtils::OpenNsoFromECS(unsigned int index, ContentManagement::ExternalContentSource *ecs) {
std::fill(g_nso_path, g_nso_path + FS_MAX_PATH, 0);
snprintf(g_nso_path, FS_MAX_PATH, "%s:/%s", ecs->mountpoint, NsoUtils::GetNsoFileName(index));
return fopen(g_nso_path, "rb");
}
FILE *NsoUtils::OpenNsoFromHBL(unsigned int index) {
std::fill(g_nso_path, g_nso_path + FS_MAX_PATH, 0);
snprintf(g_nso_path, FS_MAX_PATH, "hbl:/%s", NsoUtils::GetNsoFileName(index));
@@ -61,7 +67,12 @@ bool NsoUtils::CheckNsoStubbed(unsigned int index, u64 title_id) {
}
FILE *NsoUtils::OpenNso(unsigned int index, u64 title_id) {
if (ContentManagement::ShouldOverrideContents()) {
ContentManagement::ExternalContentSource *ecs = nullptr;
if ((ecs = ContentManagement::GetExternalContentSource(title_id)) != nullptr) {
return OpenNsoFromECS(index, ecs);
}
if (ContentManagement::ShouldOverrideContents(title_id)) {
if (ContentManagement::ShouldReplaceWithHBL(title_id)) {
return OpenNsoFromHBL(index);
}

View File

@@ -18,6 +18,8 @@
#include <switch.h>
#include <cstdio>
#include "ldr_content_management.hpp" /* for ExternalContentSource */
#define MAGIC_NSO0 0x304F534E
#define NSO_NUM_MAX 13
@@ -96,7 +98,8 @@ class NsoUtils {
return "?";
}
}
static FILE *OpenNsoFromECS(unsigned int index, ContentManagement::ExternalContentSource *ecs);
static FILE *OpenNsoFromHBL(unsigned int index);
static FILE *OpenNsoFromExeFS(unsigned int index);
static FILE *OpenNsoFromSdCard(unsigned int index, u64 title_id);

View File

@@ -215,6 +215,8 @@ Result ProcessCreation::CreateProcess(Handle *out_process_h, u64 index, char *nc
rc = 0;
CREATE_PROCESS_END:
/* ECS is a one-shot operation. */
ContentManagement::ClearExternalContentSource(target_process->tid_sid.title_id);
if (mounted_code) {
if (R_SUCCEEDED(rc) && target_process->tid_sid.storage_id != FsStorageId_None) {
rc = ContentManagement::UnmountCode();

View File

@@ -22,68 +22,45 @@
#include "ldr_content_management.hpp"
#include "ldr_npdm.hpp"
Result ProcessManagerService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
Result rc = 0xF601;
switch ((ProcessManagerServiceCmd)cmd_id) {
case Pm_Cmd_CreateProcess:
rc = WrapIpcCommandImpl<&ProcessManagerService::create_process>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
case Pm_Cmd_GetProgramInfo:
rc = WrapIpcCommandImpl<&ProcessManagerService::get_program_info>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
case Pm_Cmd_RegisterTitle:
rc = WrapIpcCommandImpl<&ProcessManagerService::register_title>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
case Pm_Cmd_UnregisterTitle:
rc = WrapIpcCommandImpl<&ProcessManagerService::unregister_title>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
default:
break;
}
return rc;
}
std::tuple<Result, MovedHandle> ProcessManagerService::create_process(u64 flags, u64 index, CopiedHandle reslimit_h) {
Result ProcessManagerService::CreateProcess(Out<MovedHandle> proc_h, u64 index, u32 flags, CopiedHandle reslimit_h) {
Result rc;
Registration::TidSid tid_sid;
LaunchQueue::LaunchItem *launch_item;
char nca_path[FS_MAX_PATH] = {0};
Handle process_h = 0;
fprintf(stderr, "CreateProcess(%016lx, %016lx, %08x);\n", flags, index, reslimit_h.handle);
fprintf(stderr, "CreateProcess(%016lx, %08x, %08x);\n", index, flags, reslimit_h.handle);
rc = Registration::GetRegisteredTidSid(index, &tid_sid);
if (R_FAILED(rc)) {
return {rc, MovedHandle{process_h}};
return rc;
}
if (tid_sid.storage_id != FsStorageId_None) {
rc = ContentManagement::ResolveContentPathForTidSid(nca_path, &tid_sid);
if (R_FAILED(rc)) {
return {rc, MovedHandle{process_h}};
return rc;
}
}
launch_item = LaunchQueue::get_item(tid_sid.title_id);
launch_item = LaunchQueue::GetItem(tid_sid.title_id);
rc = ProcessCreation::CreateProcess(&process_h, index, nca_path, launch_item, flags, reslimit_h.handle);
rc = ProcessCreation::CreateProcess(proc_h.GetHandlePointer(), index, nca_path, launch_item, flags, reslimit_h.handle);
if (R_SUCCEEDED(rc)) {
ContentManagement::SetCreatedTitle(tid_sid.title_id);
}
return {rc, MovedHandle{process_h}};
return rc;
}
std::tuple<Result> ProcessManagerService::get_program_info(Registration::TidSid tid_sid, OutPointerWithServerSize<ProcessManagerService::ProgramInfo, 0x1> out_program_info) {
Result ProcessManagerService::GetProgramInfo(OutPointerWithServerSize<ProcessManagerService::ProgramInfo, 0x1> out_program_info, Registration::TidSid tid_sid) {
Result rc;
char nca_path[FS_MAX_PATH] = {0};
/* Zero output. */
std::fill(out_program_info.pointer, out_program_info.pointer + out_program_info.num_elements, (const ProcessManagerService::ProgramInfo){0});
rc = populate_program_info_buffer(out_program_info.pointer, &tid_sid);
rc = PopulateProgramInfoBuffer(out_program_info.pointer, &tid_sid);
if (R_FAILED(rc)) {
return {rc};
@@ -100,31 +77,22 @@ std::tuple<Result> ProcessManagerService::get_program_info(Registration::TidSid
return {rc};
}
rc = LaunchQueue::add_copy(tid_sid.title_id, out_program_info.pointer->title_id);
rc = LaunchQueue::AddCopy(tid_sid.title_id, out_program_info.pointer->title_id);
}
return {rc};
}
std::tuple<Result, u64> ProcessManagerService::register_title(Registration::TidSid tid_sid) {
u64 out_index = 0;
if (Registration::RegisterTidSid(&tid_sid, &out_index)) {
return {0, out_index};
} else {
return {0xE09, out_index};
}
Result ProcessManagerService::RegisterTitle(Out<u64> index, Registration::TidSid tid_sid) {
return Registration::RegisterTidSid(&tid_sid, index.GetPointer()) ? 0 : 0xE09;
}
std::tuple<Result> ProcessManagerService::unregister_title(u64 index) {
if (Registration::UnregisterIndex(index)) {
return {0};
} else {
return {0x1009};
}
Result ProcessManagerService::UnregisterTitle(u64 index) {
return Registration::UnregisterIndex(index) ? 0 : 0x1009;
}
Result ProcessManagerService::populate_program_info_buffer(ProcessManagerService::ProgramInfo *out, Registration::TidSid *tid_sid) {
Result ProcessManagerService::PopulateProgramInfoBuffer(ProcessManagerService::ProgramInfo *out, Registration::TidSid *tid_sid) {
NpdmUtils::NpdmInfo info;
Result rc;
bool mounted_code = false;

View File

@@ -16,7 +16,7 @@
#pragma once
#include <switch.h>
#include <stratosphere/iserviceobject.hpp>
#include <stratosphere.hpp>
#include "ldr_registration.hpp"
#include "ldr_process_creation.hpp"
@@ -42,26 +42,21 @@ class ProcessManagerService final : public IServiceObject {
u8 ac_buffer[0x3E0];
};
static_assert(sizeof(ProcessManagerService::ProgramInfo) == 0x400, "Incorrect ProgramInfo definition.");
public:
Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override;
Result handle_deferred() override {
/* This service will never defer. */
return 0;
}
ProcessManagerService *clone() override {
return new ProcessManagerService();
}
static_assert(sizeof(ProcessManagerService::ProgramInfo) == 0x400, "Incorrect ProgramInfo definition.");
private:
/* Actual commands. */
std::tuple<Result, MovedHandle> create_process(u64 flags, u64 index, CopiedHandle reslimit_h);
std::tuple<Result> get_program_info(Registration::TidSid tid_sid, OutPointerWithServerSize<ProcessManagerService::ProgramInfo, 0x1> out_program_info);
std::tuple<Result, u64> register_title(Registration::TidSid tid_sid);
std::tuple<Result> unregister_title(u64 index);
Result CreateProcess(Out<MovedHandle> proc_h, u64 index, u32 flags, CopiedHandle reslimit_h);
Result GetProgramInfo(OutPointerWithServerSize<ProcessManagerService::ProgramInfo, 0x1> out_program_info, Registration::TidSid tid_sid);
Result RegisterTitle(Out<u64> index, Registration::TidSid tid_sid);
Result UnregisterTitle(u64 index);
/* Utilities */
Result populate_program_info_buffer(ProcessManagerService::ProgramInfo *out, Registration::TidSid *tid_sid);
Result PopulateProgramInfoBuffer(ProcessManagerService::ProgramInfo *out, Registration::TidSid *tid_sid);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MakeServiceCommandMeta<Pm_Cmd_CreateProcess, &ProcessManagerService::CreateProcess>(),
MakeServiceCommandMeta<Pm_Cmd_GetProgramInfo, &ProcessManagerService::GetProgramInfo>(),
MakeServiceCommandMeta<Pm_Cmd_RegisterTitle, &ProcessManagerService::RegisterTitle>(),
MakeServiceCommandMeta<Pm_Cmd_UnregisterTitle, &ProcessManagerService::UnregisterTitle>(),
};
};

View File

@@ -24,71 +24,34 @@
#include "ldr_map.hpp"
#include "ldr_nro.hpp"
Result RelocatableObjectsService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
Result rc = 0xF601;
switch ((RoServiceCmd)cmd_id) {
case Ro_Cmd_LoadNro:
rc = WrapIpcCommandImpl<&RelocatableObjectsService::load_nro>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
case Ro_Cmd_UnloadNro:
rc = WrapIpcCommandImpl<&RelocatableObjectsService::unload_nro>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
case Ro_Cmd_LoadNrr:
rc = WrapIpcCommandImpl<&RelocatableObjectsService::load_nrr>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
case Ro_Cmd_UnloadNrr:
rc = WrapIpcCommandImpl<&RelocatableObjectsService::unload_nrr>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
case Ro_Cmd_Initialize:
rc = WrapIpcCommandImpl<&RelocatableObjectsService::initialize>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
default:
break;
}
return rc;
}
std::tuple<Result, u64> RelocatableObjectsService::load_nro(PidDescriptor pid_desc, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) {
Result rc;
u64 out_address = 0;
Result RelocatableObjectsService::LoadNro(Out<u64> load_address, PidDescriptor pid_desc, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) {
Registration::Process *target_proc = NULL;
if (!this->has_initialized || this->process_id != pid_desc.pid) {
rc = 0xAE09;
goto LOAD_NRO_END;
return 0xAE09;
}
if (nro_address & 0xFFF) {
rc = 0xA209;
goto LOAD_NRO_END;
return 0xA209;
}
if (nro_address + nro_size <= nro_address || !nro_size || (nro_size & 0xFFF)) {
rc = 0xA409;
goto LOAD_NRO_END;
return 0xA409;
}
if (bss_size && bss_address + bss_size <= bss_address) {
rc = 0xA409;
goto LOAD_NRO_END;
return 0xA409;
}
/* Ensure no overflow for combined sizes. */
if (U64_MAX - nro_size < bss_size) {
rc = 0xA409;
goto LOAD_NRO_END;
return 0xA409;
}
target_proc = Registration::GetProcessByProcessId(pid_desc.pid);
if (target_proc == NULL || (target_proc->owner_ro_service != NULL && (RelocatableObjectsService *)(target_proc->owner_ro_service) != this)) {
rc = 0xAC09;
goto LOAD_NRO_END;
return 0xAC09;
}
target_proc->owner_ro_service = this;
rc = NroUtils::LoadNro(target_proc, this->process_handle, nro_address, nro_size, bss_address, bss_size, &out_address);
LOAD_NRO_END:
return {rc, out_address};
return NroUtils::LoadNro(target_proc, this->process_handle, nro_address, nro_size, bss_address, bss_size, load_address.GetPointer());
}
std::tuple<Result> RelocatableObjectsService::unload_nro(PidDescriptor pid_desc, u64 nro_address) {
Result RelocatableObjectsService::UnloadNro(PidDescriptor pid_desc, u64 nro_address) {
Registration::Process *target_proc = NULL;
if (!this->has_initialized || this->process_id != pid_desc.pid) {
return 0xAE09;
@@ -106,37 +69,42 @@ std::tuple<Result> RelocatableObjectsService::unload_nro(PidDescriptor pid_desc,
return Registration::RemoveNroInfo(target_proc->index, this->process_handle, nro_address);
}
std::tuple<Result> RelocatableObjectsService::load_nrr(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size) {
Result rc;
Result RelocatableObjectsService::LoadNrr(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size) {
Result rc = 0;
Registration::Process *target_proc = NULL;
MappedCodeMemory nrr_info = {0};
ON_SCOPE_EXIT {
if (R_FAILED(rc) && nrr_info.IsActive()) {
nrr_info.Close();
}
};
if (!this->has_initialized || this->process_id != pid_desc.pid) {
rc = 0xAE09;
goto LOAD_NRR_END;
return rc;
}
if (nrr_address & 0xFFF) {
rc = 0xA209;
goto LOAD_NRR_END;
return rc;
}
if (nrr_address + nrr_size <= nrr_address || !nrr_size || (nrr_size & 0xFFF)) {
rc = 0xA409;
goto LOAD_NRR_END;
return rc;
}
target_proc = Registration::GetProcessByProcessId(pid_desc.pid);
if (target_proc == NULL || (target_proc->owner_ro_service != NULL && (RelocatableObjectsService *)(target_proc->owner_ro_service) != this)) {
rc = 0xAC09;
goto LOAD_NRR_END;
return rc;
}
target_proc->owner_ro_service = this;
if (R_FAILED((rc = nrr_info.Open(this->process_handle, target_proc->is_64_bit_addspace, nrr_address, nrr_size)))) {
goto LOAD_NRR_END;
return rc;
}
if (R_FAILED((rc = nrr_info.Map()))) {
goto LOAD_NRR_END;
return rc;
}
rc = NroUtils::ValidateNrrHeader((NroUtils::NrrHeader *)nrr_info.mapped_address, nrr_size, target_proc->title_id);
@@ -144,16 +112,10 @@ std::tuple<Result> RelocatableObjectsService::load_nrr(PidDescriptor pid_desc, u
Registration::AddNrrInfo(target_proc->index, &nrr_info);
}
LOAD_NRR_END:
if (R_FAILED(rc)) {
if (nrr_info.IsActive()) {
nrr_info.Close();
}
}
return {rc};
return rc;
}
std::tuple<Result> RelocatableObjectsService::unload_nrr(PidDescriptor pid_desc, u64 nrr_address) {
Result RelocatableObjectsService::UnloadNrr(PidDescriptor pid_desc, u64 nrr_address) {
Registration::Process *target_proc = NULL;
if (!this->has_initialized || this->process_id != pid_desc.pid) {
return 0xAE09;
@@ -171,9 +133,8 @@ std::tuple<Result> RelocatableObjectsService::unload_nrr(PidDescriptor pid_desc,
return Registration::RemoveNrrInfo(target_proc->index, nrr_address);
}
std::tuple<Result> RelocatableObjectsService::initialize(PidDescriptor pid_desc, CopiedHandle process_h) {
Result RelocatableObjectsService::Initialize(PidDescriptor pid_desc, CopiedHandle process_h) {
u64 handle_pid;
Result rc = 0xAE09;
if (R_SUCCEEDED(svcGetProcessId(&handle_pid, process_h.handle)) && handle_pid == pid_desc.pid) {
if (this->has_initialized) {
svcCloseHandle(this->process_handle);
@@ -181,7 +142,7 @@ std::tuple<Result> RelocatableObjectsService::initialize(PidDescriptor pid_desc,
this->process_handle = process_h.handle;
this->process_id = handle_pid;
this->has_initialized = true;
rc = 0;
return 0;
}
return {rc};
return 0xAE09;
}

View File

@@ -17,7 +17,7 @@
#pragma once
#include <switch.h>
#include <stratosphere/iserviceobject.hpp>
#include <stratosphere.hpp>
#include "ldr_registration.hpp"
enum RoServiceCmd {
@@ -33,27 +33,26 @@ class RelocatableObjectsService final : public IServiceObject {
u64 process_id = U64_MAX;
bool has_initialized = false;
public:
~RelocatableObjectsService() {
virtual ~RelocatableObjectsService() override {
Registration::CloseRoService(this, this->process_handle);
if (this->has_initialized) {
svcCloseHandle(this->process_handle);
}
}
Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override;
Result handle_deferred() override {
/* This service will never defer. */
return 0;
}
RelocatableObjectsService *clone() override {
return new RelocatableObjectsService(*this);
}
private:
/* Actual commands. */
std::tuple<Result, u64> load_nro(PidDescriptor pid_desc, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size);
std::tuple<Result> unload_nro(PidDescriptor pid_desc, u64 nro_address);
std::tuple<Result> load_nrr(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size);
std::tuple<Result> unload_nrr(PidDescriptor pid_desc, u64 nrr_address);
std::tuple<Result> initialize(PidDescriptor pid_desc, CopiedHandle process_h);
Result LoadNro(Out<u64> load_address, PidDescriptor pid_desc, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size);
Result UnloadNro(PidDescriptor pid_desc, u64 nro_address);
Result LoadNrr(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size);
Result UnloadNrr(PidDescriptor pid_desc, u64 nrr_address);
Result Initialize(PidDescriptor pid_desc, CopiedHandle process_h);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MakeServiceCommandMeta<Ro_Cmd_LoadNro, &RelocatableObjectsService::LoadNro>(),
MakeServiceCommandMeta<Ro_Cmd_UnloadNro, &RelocatableObjectsService::UnloadNro>(),
MakeServiceCommandMeta<Ro_Cmd_LoadNrr, &RelocatableObjectsService::LoadNrr>(),
MakeServiceCommandMeta<Ro_Cmd_UnloadNrr, &RelocatableObjectsService::UnloadNrr>(),
MakeServiceCommandMeta<Ro_Cmd_Initialize, &RelocatableObjectsService::Initialize>(),
};
};

View File

@@ -18,31 +18,30 @@
#include <stratosphere.hpp>
#include "ldr_shell.hpp"
#include "ldr_launch_queue.hpp"
#include "ldr_content_management.hpp"
Result ShellService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
Result rc = 0xF601;
switch ((ShellServiceCmd)cmd_id) {
case Shell_Cmd_AddTitleToLaunchQueue:
rc = WrapIpcCommandImpl<&ShellService::add_title_to_launch_queue>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
case Shell_Cmd_ClearLaunchQueue:
rc = WrapIpcCommandImpl<&ShellService::clear_launch_queue>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
default:
break;
Result ShellService::AddTitleToLaunchQueue(u64 tid, InPointer<char> args, u32 args_size) {
if (args.num_elements < args_size) args_size = args.num_elements;
return LaunchQueue::Add(tid, args.pointer, args_size);
}
void ShellService::ClearLaunchQueue() {
LaunchQueue::Clear();
}
/* SetExternalContentSource extension */
Result ShellService::SetExternalContentSource(Out<MovedHandle> out, u64 tid) {
Handle server_h;
Handle client_h;
Result rc;
if (R_FAILED(rc = svcCreateSession(&server_h, &client_h, 0, 0))) {
return rc;
}
return rc;
}
std::tuple<Result> ShellService::add_title_to_launch_queue(u64 args_size, u64 tid, InPointer<char> args) {
fprintf(stderr, "Add to launch queue: %p, %zX\n", args.pointer, std::min(args_size, args.num_elements));
return {LaunchQueue::add(tid, args.pointer, std::min(args_size, args.num_elements))};
}
std::tuple<Result> ShellService::clear_launch_queue(u64 dat) {
fprintf(stderr, "Clear launch queue: %lx\n", dat);
LaunchQueue::clear();
return {0};
Service service;
serviceCreate(&service, client_h);
ContentManagement::SetExternalContentSource(tid, FsFileSystem {service});
out.SetValue(server_h);
return 0;
}

View File

@@ -16,27 +16,27 @@
#pragma once
#include <switch.h>
#include <stratosphere/iserviceobject.hpp>
#include <stratosphere.hpp>
enum ShellServiceCmd {
Shell_Cmd_AddTitleToLaunchQueue = 0,
Shell_Cmd_ClearLaunchQueue = 1
Shell_Cmd_ClearLaunchQueue = 1,
Shell_Cmd_AtmosphereSetExternalContentSource = 65000,
};
class ShellService final : public IServiceObject {
public:
Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override;
Result handle_deferred() override {
/* This service will never defer. */
return 0;
}
ShellService *clone() override {
return new ShellService();
}
private:
/* Actual commands. */
std::tuple<Result> add_title_to_launch_queue(u64 args_size, u64 tid, InPointer<char> args);
std::tuple<Result> clear_launch_queue(u64 dat);
Result AddTitleToLaunchQueue(u64 tid, InPointer<char> args, u32 args_size);
void ClearLaunchQueue();
/* Atmosphere commands. */
Result SetExternalContentSource(Out<MovedHandle> out, u64 tid);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MakeServiceCommandMeta<Shell_Cmd_AddTitleToLaunchQueue, &ShellService::AddTitleToLaunchQueue>(),
MakeServiceCommandMeta<Shell_Cmd_ClearLaunchQueue, &ShellService::ClearLaunchQueue>(),
MakeServiceCommandMeta<Shell_Cmd_AtmosphereSetExternalContentSource, &ShellService::SetExternalContentSource>(),
};
};