Merge branch 'master' into npdmfixup
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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>(),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>(),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>(),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>(),
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user