loader: update for libstratosphere refactor

This commit is contained in:
Michael Scire 2018-10-29 22:33:56 -07:00 committed by SciresM
parent 8b71378920
commit c49cfbd6af
12 changed files with 150 additions and 272 deletions

View file

@ -56,6 +56,9 @@
"svcReplyAndReceiveLight" : "0x42", "svcReplyAndReceiveLight" : "0x42",
"svcReplyAndReceive" : "0x43", "svcReplyAndReceive" : "0x43",
"svcReplyAndReceiveWithUserBuffer" : "0x44", "svcReplyAndReceiveWithUserBuffer" : "0x44",
"svcCreateEvent": "0x45",
"svcReadWriteRegister" : "0x4E",
"svcQueryIoMapping": "0x55",
"svcSetProcessMemoryPermission" : "0x73", "svcSetProcessMemoryPermission" : "0x73",
"svcMapProcessMemory" : "0x74", "svcMapProcessMemory" : "0x74",
"svcUnmapProcessMemory" : "0x75", "svcUnmapProcessMemory" : "0x75",

View file

@ -22,42 +22,18 @@
#include "ldr_launch_queue.hpp" #include "ldr_launch_queue.hpp"
#include "ldr_registration.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 DebugMonitorService::AddTitleToLaunchQueue(u64 args_size, u64 tid, InPointer<char> args) {
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;
}
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)); 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))}; return LaunchQueue::Add(tid, args.pointer, std::min(args_size, args.num_elements));
} }
std::tuple<Result> DebugMonitorService::clear_launch_queue(u64 dat) { void DebugMonitorService::ClearLaunchQueue() {
fprintf(stderr, "Clear launch queue: %lx\n", dat); LaunchQueue::Clear();
LaunchQueue::clear();
return {0};
} }
std::tuple<Result, u32> DebugMonitorService::get_nso_info(u64 pid, OutPointerWithClientSize<Registration::NsoInfo> out) { Result DebugMonitorService::GetNsoInfo(Out<u32> count, OutPointerWithClientSize<Registration::NsoInfo> out, u64 pid) {
u32 out_num_nsos = 0; /* Zero out the output memory. */
std::fill(out.pointer, out.pointer + out.num_elements, (const Registration::NsoInfo){0}); std::fill(out.pointer, out.pointer + out.num_elements, (const Registration::NsoInfo){0});
/* Actually return the nso infos. */
Result rc = Registration::GetNsoInfosForProcessId(out.pointer, out.num_elements, pid, &out_num_nsos); return Registration::GetNsoInfosForProcessId(out.pointer, out.num_elements, pid, count.GetPointer());
return {rc, out_num_nsos};
} }

View file

@ -17,7 +17,7 @@
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include <stratosphere/iserviceobject.hpp> #include <stratosphere.hpp>
#include "ldr_registration.hpp" #include "ldr_registration.hpp"
enum DebugMonitorServiceCmd { enum DebugMonitorServiceCmd {
@ -27,20 +27,15 @@ enum DebugMonitorServiceCmd {
}; };
class DebugMonitorService final : public IServiceObject { 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();
}
private: private:
/* Actual commands. */ /* Actual commands. */
std::tuple<Result> add_title_to_launch_queue(u64 args_size, u64 tid, InPointer<char> args); Result AddTitleToLaunchQueue(u64 args_size, u64 tid, InPointer<char> args);
std::tuple<Result> clear_launch_queue(u64 dat); void ClearLaunchQueue();
std::tuple<Result, u32> get_nso_info(u64 pid, OutPointerWithClientSize<Registration::NsoInfo> out); 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

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

View file

@ -30,13 +30,13 @@ class LaunchQueue {
char args[LAUNCH_QUEUE_ARG_SIZE_MAX]; 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(u64 tid, const char *args, u64 arg_size);
static Result add_item(const LaunchItem *item); static Result AddItem(const LaunchItem *item);
static Result add_copy(u64 tid_base, u64 new_tid); static Result AddCopy(u64 tid_base, u64 new_tid);
static int get_index(u64 tid); static int GetIndex(u64 tid);
static int get_free_index(u64 tid); static int GetFreeIndex(u64 tid);
static bool contains(u64 tid); static bool Contains(u64 tid);
static void clear(); static void Clear();
}; };

View file

@ -92,24 +92,31 @@ void __appExit(void) {
smExit(); 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) int main(int argc, char **argv)
{ {
consoleDebugInit(debugDevice_SVC); consoleDebugInit(debugDevice_SVC);
/* TODO: What's a good timeout value to use here? */ auto server_manager = new WaitableManager<LoaderServerOptions>(1);
auto server_manager = std::make_unique<WaitableManager>(U64_MAX);
/* Add services to manager. */ /* Add services to manager. */
server_manager->add_waitable(new ServiceServer<ProcessManagerService>("ldr:pm", 1)); server_manager->AddWaitable(new ServiceServer<ProcessManagerService>("ldr:pm", 1));
server_manager->add_waitable(new ServiceServer<ShellService>("ldr:shel", 3)); server_manager->AddWaitable(new ServiceServer<ShellService>("ldr:shel", 3));
server_manager->add_waitable(new ServiceServer<DebugMonitorService>("ldr:dmnt", 2)); server_manager->AddWaitable(new ServiceServer<DebugMonitorService>("ldr:dmnt", 2));
if (!kernelAbove300()) { if (GetRuntimeFirmwareVersion() < FirmwareVersion_300) {
/* On 1.0.0-2.3.0, Loader services ldr:ro instead of ro. */ /* 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. */ /* Loop forever, servicing our services. */
server_manager->process(); server_manager->Process();
delete server_manager;
return 0; return 0;
} }

View file

@ -22,68 +22,45 @@
#include "ldr_content_management.hpp" #include "ldr_content_management.hpp"
#include "ldr_npdm.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 ProcessManagerService::CreateProcess(Out<MovedHandle> proc_h, u64 flags, u64 index, CopiedHandle reslimit_h) {
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 rc; Result rc;
Registration::TidSid tid_sid; Registration::TidSid tid_sid;
LaunchQueue::LaunchItem *launch_item; LaunchQueue::LaunchItem *launch_item;
char nca_path[FS_MAX_PATH] = {0}; 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, %016lx, %08x);\n", flags, index, reslimit_h.handle);
rc = Registration::GetRegisteredTidSid(index, &tid_sid); rc = Registration::GetRegisteredTidSid(index, &tid_sid);
if (R_FAILED(rc)) { if (R_FAILED(rc)) {
return {rc, MovedHandle{process_h}}; return rc;
} }
if (tid_sid.storage_id != FsStorageId_None) { if (tid_sid.storage_id != FsStorageId_None) {
rc = ContentManagement::ResolveContentPathForTidSid(nca_path, &tid_sid); rc = ContentManagement::ResolveContentPathForTidSid(nca_path, &tid_sid);
if (R_FAILED(rc)) { 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)) { if (R_SUCCEEDED(rc)) {
ContentManagement::SetCreatedTitle(tid_sid.title_id); 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(Registration::TidSid tid_sid, OutPointerWithServerSize<ProcessManagerService::ProgramInfo, 0x1> out_program_info) {
Result rc; Result rc;
char nca_path[FS_MAX_PATH] = {0}; char nca_path[FS_MAX_PATH] = {0};
/* Zero output. */ /* Zero output. */
std::fill(out_program_info.pointer, out_program_info.pointer + out_program_info.num_elements, (const ProcessManagerService::ProgramInfo){0}); 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)) { if (R_FAILED(rc)) {
return {rc}; return {rc};
@ -100,31 +77,22 @@ std::tuple<Result> ProcessManagerService::get_program_info(Registration::TidSid
return {rc}; 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}; return {rc};
} }
std::tuple<Result, u64> ProcessManagerService::register_title(Registration::TidSid tid_sid) { Result ProcessManagerService::RegisterTitle(Out<u64> index, Registration::TidSid tid_sid) {
u64 out_index = 0; return Registration::RegisterTidSid(&tid_sid, index.GetPointer()) ? 0 : 0xE09;
if (Registration::RegisterTidSid(&tid_sid, &out_index)) {
return {0, out_index};
} else {
return {0xE09, out_index};
}
} }
std::tuple<Result> ProcessManagerService::unregister_title(u64 index) { Result ProcessManagerService::UnregisterTitle(u64 index) {
if (Registration::UnregisterIndex(index)) { return Registration::UnregisterIndex(index) ? 0 : 0x1009;
return {0};
} else {
return {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; NpdmUtils::NpdmInfo info;
Result rc; Result rc;
bool mounted_code = false; bool mounted_code = false;

View file

@ -16,7 +16,7 @@
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include <stratosphere/iserviceobject.hpp> #include <stratosphere.hpp>
#include "ldr_registration.hpp" #include "ldr_registration.hpp"
#include "ldr_process_creation.hpp" #include "ldr_process_creation.hpp"
@ -43,25 +43,20 @@ class ProcessManagerService final : public IServiceObject {
}; };
static_assert(sizeof(ProcessManagerService::ProgramInfo) == 0x400, "Incorrect ProgramInfo definition."); 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();
}
private: private:
/* Actual commands. */ /* Actual commands. */
std::tuple<Result, MovedHandle> create_process(u64 flags, u64 index, CopiedHandle reslimit_h); Result CreateProcess(Out<MovedHandle> proc_h, u64 flags, u64 index, CopiedHandle reslimit_h);
std::tuple<Result> get_program_info(Registration::TidSid tid_sid, OutPointerWithServerSize<ProcessManagerService::ProgramInfo, 0x1> out_program_info); Result GetProgramInfo(Registration::TidSid tid_sid, OutPointerWithServerSize<ProcessManagerService::ProgramInfo, 0x1> out_program_info);
std::tuple<Result, u64> register_title(Registration::TidSid tid_sid); Result RegisterTitle(Out<u64> index, Registration::TidSid tid_sid);
std::tuple<Result> unregister_title(u64 index); Result UnregisterTitle(u64 index);
/* Utilities */ /* 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_map.hpp"
#include "ldr_nro.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 RelocatableObjectsService::LoadNro(Out<u64> load_address, PidDescriptor pid_desc, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_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;
Registration::Process *target_proc = NULL; Registration::Process *target_proc = NULL;
if (!this->has_initialized || this->process_id != pid_desc.pid) { if (!this->has_initialized || this->process_id != pid_desc.pid) {
rc = 0xAE09; return 0xAE09;
goto LOAD_NRO_END;
} }
if (nro_address & 0xFFF) { if (nro_address & 0xFFF) {
rc = 0xA209; return 0xA209;
goto LOAD_NRO_END;
} }
if (nro_address + nro_size <= nro_address || !nro_size || (nro_size & 0xFFF)) { if (nro_address + nro_size <= nro_address || !nro_size || (nro_size & 0xFFF)) {
rc = 0xA409; return 0xA409;
goto LOAD_NRO_END;
} }
if (bss_size && bss_address + bss_size <= bss_address) { if (bss_size && bss_address + bss_size <= bss_address) {
rc = 0xA409; return 0xA409;
goto LOAD_NRO_END;
} }
/* Ensure no overflow for combined sizes. */ /* Ensure no overflow for combined sizes. */
if (U64_MAX - nro_size < bss_size) { if (U64_MAX - nro_size < bss_size) {
rc = 0xA409; return 0xA409;
goto LOAD_NRO_END;
} }
target_proc = Registration::GetProcessByProcessId(pid_desc.pid); target_proc = Registration::GetProcessByProcessId(pid_desc.pid);
if (target_proc == NULL || (target_proc->owner_ro_service != NULL && (RelocatableObjectsService *)(target_proc->owner_ro_service) != this)) { if (target_proc == NULL || (target_proc->owner_ro_service != NULL && (RelocatableObjectsService *)(target_proc->owner_ro_service) != this)) {
rc = 0xAC09; return 0xAC09;
goto LOAD_NRO_END;
} }
target_proc->owner_ro_service = this; target_proc->owner_ro_service = this;
rc = NroUtils::LoadNro(target_proc, this->process_handle, nro_address, nro_size, bss_address, bss_size, &out_address); return NroUtils::LoadNro(target_proc, this->process_handle, nro_address, nro_size, bss_address, bss_size, load_address.GetPointer());
LOAD_NRO_END:
return {rc, out_address};
} }
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; Registration::Process *target_proc = NULL;
if (!this->has_initialized || this->process_id != pid_desc.pid) { if (!this->has_initialized || this->process_id != pid_desc.pid) {
return 0xAE09; 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); 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 RelocatableObjectsService::LoadNrr(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size) {
Result rc; Result rc = 0;
Registration::Process *target_proc = NULL; Registration::Process *target_proc = NULL;
MappedCodeMemory nrr_info = {0}; 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) { if (!this->has_initialized || this->process_id != pid_desc.pid) {
rc = 0xAE09; rc = 0xAE09;
goto LOAD_NRR_END; return rc;
} }
if (nrr_address & 0xFFF) { if (nrr_address & 0xFFF) {
rc = 0xA209; rc = 0xA209;
goto LOAD_NRR_END; return rc;
} }
if (nrr_address + nrr_size <= nrr_address || !nrr_size || (nrr_size & 0xFFF)) { if (nrr_address + nrr_size <= nrr_address || !nrr_size || (nrr_size & 0xFFF)) {
rc = 0xA409; rc = 0xA409;
goto LOAD_NRR_END; return rc;
} }
target_proc = Registration::GetProcessByProcessId(pid_desc.pid); target_proc = Registration::GetProcessByProcessId(pid_desc.pid);
if (target_proc == NULL || (target_proc->owner_ro_service != NULL && (RelocatableObjectsService *)(target_proc->owner_ro_service) != this)) { if (target_proc == NULL || (target_proc->owner_ro_service != NULL && (RelocatableObjectsService *)(target_proc->owner_ro_service) != this)) {
rc = 0xAC09; rc = 0xAC09;
goto LOAD_NRR_END; return rc;
} }
target_proc->owner_ro_service = this; 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)))) { 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()))) { 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); 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); Registration::AddNrrInfo(target_proc->index, &nrr_info);
} }
LOAD_NRR_END: return rc;
if (R_FAILED(rc)) {
if (nrr_info.IsActive()) {
nrr_info.Close();
}
}
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; Registration::Process *target_proc = NULL;
if (!this->has_initialized || this->process_id != pid_desc.pid) { if (!this->has_initialized || this->process_id != pid_desc.pid) {
return 0xAE09; return 0xAE09;
@ -171,9 +133,8 @@ std::tuple<Result> RelocatableObjectsService::unload_nrr(PidDescriptor pid_desc,
return Registration::RemoveNrrInfo(target_proc->index, nrr_address); 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; u64 handle_pid;
Result rc = 0xAE09;
if (R_SUCCEEDED(svcGetProcessId(&handle_pid, process_h.handle)) && handle_pid == pid_desc.pid) { if (R_SUCCEEDED(svcGetProcessId(&handle_pid, process_h.handle)) && handle_pid == pid_desc.pid) {
if (this->has_initialized) { if (this->has_initialized) {
svcCloseHandle(this->process_handle); svcCloseHandle(this->process_handle);
@ -181,7 +142,7 @@ std::tuple<Result> RelocatableObjectsService::initialize(PidDescriptor pid_desc,
this->process_handle = process_h.handle; this->process_handle = process_h.handle;
this->process_id = handle_pid; this->process_id = handle_pid;
this->has_initialized = true; this->has_initialized = true;
rc = 0; return 0;
} }
return {rc}; return 0xAE09;
} }

View file

@ -17,7 +17,7 @@
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include <stratosphere/iserviceobject.hpp> #include <stratosphere.hpp>
#include "ldr_registration.hpp" #include "ldr_registration.hpp"
enum RoServiceCmd { enum RoServiceCmd {
@ -33,27 +33,26 @@ class RelocatableObjectsService final : public IServiceObject {
u64 process_id = U64_MAX; u64 process_id = U64_MAX;
bool has_initialized = false; bool has_initialized = false;
public: public:
~RelocatableObjectsService() { virtual ~RelocatableObjectsService() override {
Registration::CloseRoService(this, this->process_handle); Registration::CloseRoService(this, this->process_handle);
if (this->has_initialized) { if (this->has_initialized) {
svcCloseHandle(this->process_handle); 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: private:
/* Actual commands. */ /* Actual commands. */
std::tuple<Result, u64> load_nro(PidDescriptor pid_desc, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size); Result LoadNro(Out<u64> load_address, 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); Result UnloadNro(PidDescriptor pid_desc, u64 nro_address);
std::tuple<Result> load_nrr(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size); Result LoadNrr(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size);
std::tuple<Result> unload_nrr(PidDescriptor pid_desc, u64 nrr_address); Result UnloadNrr(PidDescriptor pid_desc, u64 nrr_address);
std::tuple<Result> initialize(PidDescriptor pid_desc, CopiedHandle process_h); 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

@ -20,49 +20,28 @@
#include "ldr_launch_queue.hpp" #include "ldr_launch_queue.hpp"
#include "ldr_content_management.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 ShellService::AddTitleToLaunchQueue(u64 args_size, u64 tid, InPointer<char> args) {
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;
case Shell_Cmd_AtmosphereSetExternalContentSource:
rc = WrapIpcCommandImpl<&ShellService::set_external_content_source>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
default:
break;
}
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)); 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))}; return LaunchQueue::Add(tid, args.pointer, std::min(args_size, args.num_elements));
} }
std::tuple<Result> ShellService::clear_launch_queue(u64 dat) { void ShellService::ClearLaunchQueue() {
fprintf(stderr, "Clear launch queue: %lx\n", dat); LaunchQueue::Clear();
LaunchQueue::clear();
return {0};
} }
/* SetExternalContentSource extension */ /* SetExternalContentSource extension */
std::tuple<Result, MovedHandle> ShellService::set_external_content_source(u64 tid) { Result ShellService::SetExternalContentSource(Out<MovedHandle> out, u64 tid) {
Handle server_h; Handle server_h;
Handle client_h; Handle client_h;
Result rc; Result rc;
if (R_FAILED(rc = svcCreateSession(&server_h, &client_h, 0, 0))) { if (R_FAILED(rc = svcCreateSession(&server_h, &client_h, 0, 0))) {
return {rc, 0}; return rc;
} }
Service service; Service service;
serviceCreate(&service, client_h); serviceCreate(&service, client_h);
ContentManagement::SetExternalContentSource(tid, FsFileSystem {service}); ContentManagement::SetExternalContentSource(tid, FsFileSystem {service});
return {0, server_h}; out.SetValue(server_h);
return 0;
} }

View file

@ -16,7 +16,7 @@
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include <stratosphere/iserviceobject.hpp> #include <stratosphere.hpp>
enum ShellServiceCmd { enum ShellServiceCmd {
Shell_Cmd_AddTitleToLaunchQueue = 0, Shell_Cmd_AddTitleToLaunchQueue = 0,
@ -26,22 +26,17 @@ enum ShellServiceCmd {
}; };
class ShellService final : public IServiceObject { 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: private:
/* Actual commands. */ /* Actual commands. */
std::tuple<Result> add_title_to_launch_queue(u64 args_size, u64 tid, InPointer<char> args); Result AddTitleToLaunchQueue(u64 args_size, u64 tid, InPointer<char> args);
std::tuple<Result> clear_launch_queue(u64 dat); void ClearLaunchQueue();
/* Atmosphere commands. */ /* Atmosphere commands. */
std::tuple<Result, MovedHandle> set_external_content_source(u64 tid); 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>(),
};
}; };