libstratosphere/fs.mitm: Push WIP support for Domains. Not yet fully working.

This commit is contained in:
Michael Scire 2018-06-12 16:00:09 -06:00
parent d8c9399cff
commit 237ff0d1e7
47 changed files with 1053 additions and 882 deletions

View file

@ -3,6 +3,8 @@
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "fs_shim.h" #include "fs_shim.h"
#include "debug.hpp"
enum FsIStorageCmd { enum FsIStorageCmd {
FsIStorage_Cmd_Read = 0, FsIStorage_Cmd_Read = 0,
FsIStorage_Cmd_Write = 1, FsIStorage_Cmd_Write = 1,
@ -17,6 +19,9 @@ class IStorage {
virtual ~IStorage() { virtual ~IStorage() {
} }
virtual IStorage *Clone() = 0;
virtual Result Read(void *buffer, size_t size, u64 offset, u64 *out_read_size) = 0; virtual Result Read(void *buffer, size_t size, u64 offset, u64 *out_read_size) = 0;
virtual Result Write(void *buffer, size_t size, u64 offset) = 0; virtual Result Write(void *buffer, size_t size, u64 offset) = 0;
virtual Result Flush() = 0; virtual Result Flush() = 0;
@ -33,6 +38,10 @@ class IStorageInterface : public IServiceObject {
/* ... */ /* ... */
}; };
IStorageInterface *clone() override {
return new IStorageInterface(this->base_storage->Clone());
}
~IStorageInterface() { ~IStorageInterface() {
delete base_storage; delete base_storage;
}; };

View file

@ -1,6 +1,47 @@
#include <switch.h> #include <switch.h>
#include "fs_shim.h" #include "fs_shim.h"
/* Necessary evil. */
Result ipcCopyFromDomain(Handle session, u32 object_id, Service *out) {
u32* buf = (u32*)armGetTls();
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u32 object_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
buf[0] = IpcCommandType_Control;
raw->magic = SFCI_MAGIC;
raw->cmd_id = 1;
raw->object_id = object_id;
Result rc = ipcDispatch(session);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct ipcCopyFromDomainResponse {
u64 magic;
u64 result;
} *raw = (struct ipcCopyFromDomainResponse*)r.Raw;
rc = raw->result;
if (R_SUCCEEDED(rc)) {
serviceCreate(out, r.Handles[0]);
}
}
return rc;
}
/* Missing fsp-srv commands. */ /* Missing fsp-srv commands. */
Result fsOpenDataStorageByDataId(Service* s, FsStorageId storage_id, u64 data_id, FsStorage* out) { Result fsOpenDataStorageByDataId(Service* s, FsStorageId storage_id, u64 data_id, FsStorage* out) {
IpcCommand c; IpcCommand c;
@ -41,6 +82,47 @@ Result fsOpenDataStorageByDataId(Service* s, FsStorageId storage_id, u64 data_id
return rc; return rc;
} }
Result fsOpenDataStorageByDataIdFromDomain(Service* s, FsStorageId storage_id, u64 data_id, u32 *out_object_id) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
FsStorageId storage_id;
u64 data_id;
} *raw;
raw = ipcPrepareHeaderForDomain(&c, sizeof(*raw), s->object_id);
raw->magic = SFCI_MAGIC;
raw->cmd_id = 202;
raw->storage_id = storage_id;
raw->data_id = data_id;
Result rc = serviceIpcDispatch(s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParseForDomain(&r);
struct {
u64 magic;
u64 result;
u32 object_id;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*out_object_id = resp->object_id;
}
}
return rc;
}
/* Missing FS File commands. */ /* Missing FS File commands. */
Result fsFileOperateRange(FsFile* f, u32 op_id, u64 off, u64 len, FsRangeInfo *out) { Result fsFileOperateRange(FsFile* f, u32 op_id, u64 off, u64 len, FsRangeInfo *out) {
IpcCommand c; IpcCommand c;

View file

@ -16,8 +16,12 @@ typedef struct {
u32 flags[0x40/sizeof(u32)]; u32 flags[0x40/sizeof(u32)];
} FsRangeInfo; } FsRangeInfo;
/* Necessary evils. */
Result ipcCopyFromDomain(Handle session, u32 object_id, Service *out);
/* Missing fsp-srv commands. */ /* Missing fsp-srv commands. */
Result fsOpenDataStorageByDataId(Service* s, FsStorageId storage_id, u64 data_id, FsStorage* out); Result fsOpenDataStorageByDataId(Service* s, FsStorageId storage_id, u64 data_id, FsStorage* out);
Result fsOpenDataStorageByDataIdFromDomain(Service* s, FsStorageId storage_id, u64 data_id, u32 *out_object_id);
/* Missing FS File commands. */ /* Missing FS File commands. */
Result fsFileOperateRange(FsFile* f, u32 op_id, u64 off, u64 len, FsRangeInfo *out); Result fsFileOperateRange(FsFile* f, u32 op_id, u64 off, u64 len, FsRangeInfo *out);

View file

@ -12,6 +12,8 @@
#include "fsmitm_service.hpp" #include "fsmitm_service.hpp"
#include "fsmitm_worker.hpp" #include "fsmitm_worker.hpp"
#include "mitm_service.hpp"
extern "C" { extern "C" {
extern u32 __start__; extern u32 __start__;
@ -62,6 +64,11 @@ void __appInit(void) {
fatalSimple(0xCAFE << 4 | 3); fatalSimple(0xCAFE << 4 | 3);
} }
rc = pminfoInitialize();
if (R_FAILED(rc)) {
fatalSimple(0xCAFE << 4 | 4);
}
/* Check for exosphere API compatibility. */ /* Check for exosphere API compatibility. */
u64 exosphere_cfg; u64 exosphere_cfg;
if (R_SUCCEEDED(splGetConfig((SplConfigItem)65000, &exosphere_cfg))) { if (R_SUCCEEDED(splGetConfig((SplConfigItem)65000, &exosphere_cfg))) {
@ -74,7 +81,7 @@ void __appInit(void) {
fatalSimple(0xCAFE << 4 | 0xFF); fatalSimple(0xCAFE << 4 | 0xFF);
} }
splExit(); //splExit();
} }
void __appExit(void) { void __appExit(void) {
@ -100,7 +107,8 @@ int main(int argc, char **argv)
WaitableManager *server_manager = new WaitableManager(U64_MAX); WaitableManager *server_manager = new WaitableManager(U64_MAX);
/* Create fsp-srv mitm. */ /* Create fsp-srv mitm. */
server_manager->add_waitable(new MitMServer<FsMitMService>("fsp-srv", 61)); //server_manager->add_waitable(new MitMServer<FsMitMService>("fsp-srv", 61));
server_manager->add_waitable(new MitMServer<GenericMitMService>("fsp-srv", 61));
/* Loop forever, servicing our services. */ /* Loop forever, servicing our services. */
server_manager->process(); server_manager->process();

View file

@ -19,6 +19,10 @@ class RomFileStorage : public IROStorage {
fsFileClose(base_file); fsFileClose(base_file);
delete base_file; delete base_file;
}; };
RomFileStorage *Clone() override {
return new RomFileStorage(this->base_file);
};
protected: protected:
Result Read(void *buffer, size_t size, u64 offset, u64 *out_read_size) override { Result Read(void *buffer, size_t size, u64 offset, u64 *out_read_size) override {
size_t out_sz = 0; size_t out_sz = 0;
@ -52,6 +56,10 @@ class RomInterfaceStorage : public IROStorage {
fsStorageClose(base_storage); fsStorageClose(base_storage);
delete base_storage; delete base_storage;
}; };
RomInterfaceStorage *Clone() override {
return new RomInterfaceStorage(this->base_storage);
};
protected: protected:
Result Read(void *buffer, size_t size, u64 offset, u64 *out_read_size) override { Result Read(void *buffer, size_t size, u64 offset, u64 *out_read_size) override {
Result rc = fsStorageRead(this->base_storage, offset, buffer, size); Result rc = fsStorageRead(this->base_storage, offset, buffer, size);

View file

@ -17,32 +17,51 @@ Result FsMitMService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_i
this->process_id = r.Pid; this->process_id = r.Pid;
} }
break; break;
case FspSrv_Cmd_OpenDataStorageByDataId: /*case FspSrv_Cmd_OpenDataStorageByDataId:
rc = WrapIpcCommandImpl<&FsMitMService::open_data_storage_by_data_id>(this, r, out_c, pointer_buffer, pointer_buffer_size); rc = WrapIpcCommandImpl<&FsMitMService::open_data_storage_by_data_id>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break; break; */
} }
return rc; return rc;
} }
Result FsMitMService::postprocess(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) { void FsMitMService::postprocess(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
struct { struct {
u64 magic; u64 magic;
u64 result; u64 result;
} *resp = (decltype(resp))r.Raw; } *resp = (decltype(resp))r.Raw;
u64 *tls = (u64 *)armGetTls();
u64 backup_tls[0x100/sizeof(u64)];
for (unsigned int i = 0; i < sizeof(backup_tls)/sizeof(u64); i++) {
backup_tls[i] = tls[i];
}
Result rc = (Result)resp->result; Result rc = (Result)resp->result;
switch (cmd_id) { switch (cmd_id) {
case FspSrv_Cmd_SetCurrentProcess: case FspSrv_Cmd_SetCurrentProcess:
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
this->has_initialized = true; this->has_initialized = true;
if (R_FAILED(pminfoInitialize()) || R_FAILED(pminfoGetTitleId(&this->title_id, this->process_id))) { rc = pminfoGetTitleId(&this->title_id, this->process_id);
fatalSimple(0xCAFE << 8 | 0xFD); if (R_FAILED(rc)) {
if (rc == 0x20F) {
this->title_id = this->process_id;
rc = 0x0;
} else {
fatalSimple(rc);
}
} }
pminfoExit(); }
Log(&this->process_id, 8);
Log(&this->title_id, 8);
for (unsigned int i = 0; i < sizeof(backup_tls)/sizeof(u64); i++) {
tls[i] = backup_tls[i];
}
if (this->title_id >= 0x0100000000001000) {
Reboot();
} }
break; break;
} }
return rc; resp->result = rc;
} }
Result FsMitMService::handle_deferred() { Result FsMitMService::handle_deferred() {
@ -51,25 +70,37 @@ Result FsMitMService::handle_deferred() {
} }
/* Add redirection for System Data Archives to the SD card. */ /* Add redirection for System Data Archives to the SD card. */
std::tuple<Result, MovedHandle> FsMitMService::open_data_storage_by_data_id(FsStorageId storage_id, u64 data_id) { std::tuple<Result, OutSession<IStorageInterface>> FsMitMService::open_data_storage_by_data_id(u64 sid, u64 data_id) {
Handle out_h = 0; FsStorageId storage_id = (FsStorageId)sid;
IPCSession<IStorageInterface> *out_session = NULL;
FsStorage data_storage; FsStorage data_storage;
FsFile data_file; FsFile data_file;
Result rc = fsOpenDataStorageByDataId(this->forward_service, storage_id, data_id, &data_storage); u32 out_domain_id;
Result rc;
if (this->get_owner() == NULL) {
rc = fsOpenDataStorageByDataId(this->forward_service, storage_id, data_id, &data_storage);
} else {
rc = fsOpenDataStorageByDataIdFromDomain(this->forward_service, storage_id, data_id, &out_domain_id);
if (R_SUCCEEDED(rc)) {
rc = ipcCopyFromDomain(this->forward_service->handle, out_domain_id, &data_storage.s);
}
}
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IPCSession<IStorageInterface> *out_session = NULL;
char path[FS_MAX_PATH] = {0}; char path[FS_MAX_PATH] = {0};
/* TODO: Is there a sensible path that ends in ".romfs" we can use?" */ /* TODO: Is there a sensible path that ends in ".romfs" we can use?" */
snprintf(path, sizeof(path), "/atmosphere/titles/%016lx/romfs.bin", data_id); snprintf(path, sizeof(path), "/atmosphere/titles/%016lx/romfs.bin", data_id);
if (R_SUCCEEDED(Utils::OpenSdFile(path, FS_OPEN_READ, &data_file))) { if (R_SUCCEEDED(Utils::OpenSdFile(path, FS_OPEN_READ, &data_file))) {
fsStorageClose(&data_storage); fsStorageClose(&data_storage);
out_session = new IPCSession<IStorageInterface>(new IStorageInterface(new RomFileStorage(data_file))); out_session = new IPCSession<IStorageInterface>(new IStorageInterface(new RomFileStorage(data_file)));
} else { } else {
out_session = new IPCSession<IStorageInterface>(new IStorageInterface(new RomInterfaceStorage(data_storage))); out_session = new IPCSession<IStorageInterface>(new IStorageInterface(new RomInterfaceStorage(data_storage)));
} }
FsMitmWorker::AddWaitable(out_session); if (this->get_owner() == NULL) {
out_h = out_session->get_client_handle(); FsMitmWorker::AddWaitable(out_session);
}
} }
return {rc, out_h};
OutSession out_s = OutSession(out_session);
out_s.domain_id = out_domain_id;
return {rc, out_s};
} }

View file

@ -2,6 +2,7 @@
#include <switch.h> #include <switch.h>
#include <stratosphere/iserviceobject.hpp> #include <stratosphere/iserviceobject.hpp>
#include "imitmserviceobject.hpp" #include "imitmserviceobject.hpp"
#include "fs_istorage.hpp"
enum FspSrvCmd { enum FspSrvCmd {
FspSrv_Cmd_SetCurrentProcess = 1, FspSrv_Cmd_SetCurrentProcess = 1,
@ -17,11 +18,25 @@ class FsMitMService : public IMitMServiceObject {
FsMitMService(Service *s) : IMitMServiceObject(s), has_initialized(false), process_id(0), title_id(0) { FsMitMService(Service *s) : IMitMServiceObject(s), has_initialized(false), process_id(0), title_id(0) {
/* ... */ /* ... */
} }
FsMitMService *clone() override {
auto new_srv = new FsMitMService((Service *)&this->forward_service);
this->clone_to(new_srv);
return new_srv;
}
void clone_to(void *o) override {
FsMitMService *other = (FsMitMService *)o;
other->has_initialized = has_initialized;
other->process_id = process_id;
other->title_id = title_id;
}
virtual Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size); virtual Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size);
virtual Result postprocess(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size); virtual void postprocess(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size);
virtual Result handle_deferred(); virtual Result handle_deferred();
protected: protected:
/* Overridden commands. */ /* Overridden commands. */
std::tuple<Result, MovedHandle> open_data_storage_by_data_id(FsStorageId storage_id, u64 data_id); std::tuple<Result, OutSession<IStorageInterface>> open_data_storage_by_data_id(u64 storage_id, u64 data_id);
}; };

View file

@ -2,6 +2,8 @@
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include <atomic> #include <atomic>
#include "sm_mitm.h"
#include "fsmitm_utils.hpp" #include "fsmitm_utils.hpp"
static FsFileSystem g_sd_filesystem; static FsFileSystem g_sd_filesystem;
@ -11,6 +13,17 @@ static Result EnsureInitialized() {
if (g_has_initialized) { if (g_has_initialized) {
return 0x0; return 0x0;
} }
static const char * const required_active_services[] = {"pcv", "gpio", "pinmux", "psc:c"};
for (unsigned int i = 0; i < sizeof(required_active_services) / sizeof(required_active_services[0]); i++) {
Result rc = smMitMUninstall(required_active_services[i]);
if (rc == 0xE15) {
return rc;
} else if (rc != 0x1015) {
return rc;
}
}
Result rc = fsMountSdcard(&g_sd_filesystem); Result rc = fsMountSdcard(&g_sd_filesystem);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
g_has_initialized = true; g_has_initialized = true;

View file

@ -3,35 +3,36 @@
#include "fsmitm_worker.hpp" #include "fsmitm_worker.hpp"
static SystemEvent *g_new_waitable_event = NULL; static SystemEvent *g_new_waitable_event = NULL;
static ChildWaitableHolder *g_child_holder = NULL;
static HosMutex g_new_waitable_mutex; static HosMutex g_new_waitable_mutex;
static IWaitable *g_new_waitable = NULL; static HosSemaphore g_sema_new_waitable_finish;
Result FsMitmWorker::AddWaitableInternal(Handle *handles, size_t num_handles, u64 timeout) { static WaitableManager *g_worker_waiter = NULL;
Result FsMitmWorker::AddWaitableCallback(Handle *handles, size_t num_handles, u64 timeout) {
svcClearEvent(handles[0]); svcClearEvent(handles[0]);
g_child_holder->add_child(g_new_waitable); g_sema_new_waitable_finish.Signal();
return 0; return 0;
} }
void FsMitmWorker::AddWaitable(IWaitable *waitable) { void FsMitmWorker::AddWaitable(IWaitable *waitable) {
g_worker_waiter->add_waitable(waitable);
g_new_waitable_mutex.Lock(); g_new_waitable_mutex.Lock();
g_new_waitable = waitable;
g_new_waitable_event->signal_event(); g_new_waitable_event->signal_event();
g_sema_new_waitable_finish.Wait();
g_new_waitable_mutex.Unlock(); g_new_waitable_mutex.Unlock();
} }
void FsMitmWorker::Main(void *arg) { void FsMitmWorker::Main(void *arg) {
/* Initialize waitable event. */ /* Initialize waitable event. */
g_new_waitable_event = new SystemEvent(&FsMitmWorker::AddWaitableInternal); g_new_waitable_event = new SystemEvent(&FsMitmWorker::AddWaitableCallback);
g_child_holder = new ChildWaitableHolder();
/* Make a new waitable manager. */ /* Make a new waitable manager. */
WaitableManager *worker_waiter = new WaitableManager(U64_MAX); g_worker_waiter = new WaitableManager(U64_MAX);
worker_waiter->add_waitable(g_new_waitable_event); g_worker_waiter->add_waitable(g_new_waitable_event);
/* Service processes. */ /* Service processes. */
worker_waiter->process(); g_worker_waiter->process();
delete worker_waiter; delete g_worker_waiter;
} }

View file

@ -4,7 +4,7 @@
class FsMitmWorker { class FsMitmWorker {
private: private:
static Result AddWaitableInternal(Handle *handles, size_t num_handles, u64 timeout); static Result AddWaitableCallback(Handle *handles, size_t num_handles, u64 timeout);
public: public:
static void Main(void *arg); static void Main(void *arg);
static void AddWaitable(IWaitable *waitable); static void AddWaitable(IWaitable *waitable);

View file

@ -10,9 +10,11 @@ class IMitMServiceObject : public IServiceObject {
IMitMServiceObject(Service *s) : forward_service(s) { IMitMServiceObject(Service *s) : forward_service(s) {
} }
virtual void clone_to(void *o) = 0;
protected: protected:
virtual ~IMitMServiceObject() { } virtual ~IMitMServiceObject() { }
virtual Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) = 0; virtual Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) = 0;
virtual Result postprocess(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) = 0; virtual void postprocess(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) = 0;
virtual Result handle_deferred() = 0; virtual Result handle_deferred() = 0;
}; };

View file

@ -11,116 +11,39 @@ template <typename T>
class MitMSession; class MitMSession;
template <typename T> template <typename T>
class MitMServer final : public IWaitable { class MitMServer final : public IServer<T> {
static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject"); static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject");
protected: private:
Handle port_handle;
unsigned int max_sessions;
unsigned int num_sessions;
MitMSession<T> **sessions;
char mitm_name[9]; char mitm_name[9];
public: public:
MitMServer(const char *service_name, unsigned int max_s) : max_sessions(max_s) { MitMServer(const char *service_name, unsigned int max_s, bool s_d = false) : IServer<T>(service_name, max_s, s_d) {
this->sessions = new MitMSession<T> *[this->max_sessions]; Handle tmp_hnd;
for (unsigned int i = 0; i < this->max_sessions; i++) { Result rc;
this->sessions[i] = NULL;
if (R_SUCCEEDED((rc = smGetServiceOriginal(&tmp_hnd, smEncodeName(service_name))))) {
svcCloseHandle(tmp_hnd);
} else {
fatalSimple(rc);
} }
this->num_sessions = 0;
strncpy(mitm_name, service_name, 8); strncpy(mitm_name, service_name, 8);
mitm_name[8] = '\x00'; mitm_name[8] = '\x00';
Result rc;
if (R_FAILED((rc = smMitMInstall(&this->port_handle, mitm_name)))) { if (R_FAILED((rc = smMitMInstall(&this->port_handle, mitm_name)))) {
/* TODO: Panic. */ fatalSimple(rc);
} }
} }
virtual ~MitMServer() { virtual ~MitMServer() {
for (unsigned int i = 0; i < this->max_sessions; i++) { if (this->port_handle) {
if (this->sessions[i]) { if (R_FAILED(smMitMUninstall(this->mitm_name))) {
delete this->sessions[i];
}
delete this->sessions;
}
if (port_handle) {
if (R_FAILED(smMitMUninstall(mitm_name))) {
/* TODO: Panic. */ /* TODO: Panic. */
} }
svcCloseHandle(port_handle); /* svcCloseHandle(port_handle); was called by ~IServer. */
}
}
/* IWaitable */
virtual unsigned int get_num_waitables() {
unsigned int n = 1;
for (unsigned int i = 0; i < this->max_sessions; i++) {
if (this->sessions[i]) {
n += this->sessions[i]->get_num_waitables();
}
}
return n;
}
virtual void get_waitables(IWaitable **dst) {
dst[0] = this;
unsigned int n = 0;
for (unsigned int i = 0; i < this->max_sessions; i++) {
if (this->sessions[i]) {
this->sessions[i]->get_waitables(&dst[1 + n]);
n += this->sessions[i]->get_num_waitables();
}
} }
} }
virtual void delete_child(IWaitable *child) { ISession<T> *get_new_session(Handle session_h) override {
unsigned int i; return new MitMSession<T>(this, session_h, 0, mitm_name);
for (i = 0; i < this->max_sessions; i++) {
if (this->sessions[i] == child) {
break;
}
}
if (i == this->max_sessions) {
/* TODO: Panic, because this isn't our child. */
} else {
delete this->sessions[i];
this->sessions[i] = NULL;
this->num_sessions--;
}
}
virtual Handle get_handle() {
return this->port_handle;
}
virtual void handle_deferred() {
/* TODO: Panic, because we can never defer a server. */
}
virtual Result handle_signaled(u64 timeout) {
/* If this server's port was signaled, accept a new session. */
Handle session_h;
svcAcceptSession(&session_h, this->port_handle);
if (this->num_sessions >= this->max_sessions) {
svcCloseHandle(session_h);
return 0x10601;
}
unsigned int i;
for (i = 0; i < this->max_sessions; i++) {
if (this->sessions[i] == NULL) {
break;
}
}
this->sessions[i] = new MitMSession<T>(this, session_h, 0, mitm_name);
this->sessions[i]->set_parent(this);
this->num_sessions++;
return 0;
} }
}; };

View file

@ -0,0 +1,16 @@
#include <switch.h>
#include "mitm_service.hpp"
#include "debug.hpp"
Result GenericMitMService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
return 0xF601;
}
void GenericMitMService::postprocess(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
}
Result GenericMitMService::handle_deferred() {
/* This service is never deferrable. */
return 0;
}

View file

@ -0,0 +1,27 @@
#pragma once
#include <switch.h>
#include <stratosphere/iserviceobject.hpp>
#include "imitmserviceobject.hpp"
#include "fs_istorage.hpp"
class GenericMitMService : public IMitMServiceObject {
public:
GenericMitMService(Service *s) : IMitMServiceObject(s) {
/* ... */
}
GenericMitMService *clone() override {
auto new_srv = new GenericMitMService((Service *)&this->forward_service);
this->clone_to(new_srv);
return new_srv;
}
void clone_to(void *o) override {
/* ... */
}
virtual Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size);
virtual void postprocess(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size);
virtual Result handle_deferred();
};

View file

@ -12,154 +12,208 @@ template <typename T>
class MitMServer; class MitMServer;
template <typename T> template <typename T>
class MitMSession final : public IWaitable { class MitMSession final : public ISession<T> {
static_assert(std::is_base_of<IMitMServiceObject, T>::value, "MitM Service Objects must derive from IMitMServiceObject"); static_assert(std::is_base_of<IMitMServiceObject, T>::value, "MitM Service Objects must derive from IMitMServiceObject");
T *service_object;
MitMServer<T> *server;
Handle server_handle;
Handle client_handle;
/* This will be for the actual session. */ /* This will be for the actual session. */
Service forward_service; Service forward_service;
IpcParsedCommand cur_out_r;
char *pointer_buffer; u32 mitm_domain_id;
size_t pointer_buffer_size;
static_assert(sizeof(pointer_buffer) <= POINTER_BUFFER_SIZE_MAX, "Incorrect Size for PointerBuffer!");
public: public:
MitMSession<T>(MitMServer<T> *s, Handle s_h, Handle c_h, const char *srv) : server(s), server_handle(s_h), client_handle(c_h) { MitMSession<T>(MitMServer<T> *s, Handle s_h, Handle c_h, const char *srv) : ISession<T>(s, s_h, c_h, NULL, 0), mitm_domain_id(0) {
this->server = s;
this->server_handle = s_h;
this->client_handle = c_h;
if (R_FAILED(smMitMGetService(&forward_service, srv))) { if (R_FAILED(smMitMGetService(&forward_service, srv))) {
/* TODO: Panic. */ /* TODO: Panic. */
} }
if (R_FAILED(ipcQueryPointerBufferSize(forward_service.handle, &pointer_buffer_size))) { if (R_FAILED(ipcQueryPointerBufferSize(forward_service.handle, &this->pointer_buffer_size))) {
/* TODO: Panic. */ /* TODO: Panic. */
} }
this->service_object = new T(&forward_service); this->service_object = new T(&forward_service);
this->pointer_buffer = new char[pointer_buffer_size]; this->pointer_buffer = new char[this->pointer_buffer_size];
}
MitMSession<T>(MitMServer<T> *s, Handle s_h, Handle c_h, Handle f_h, size_t pbs) : ISession<T>(s, s_h, c_h, NULL, 0), mitm_domain_id(0) {
this->server = s;
this->server_handle = s_h;
this->client_handle = c_h;
this->pointer_buffer_size = pbs;
this->forward_service = {.handle = f_h};
this->service_object = new T(&forward_service);
this->pointer_buffer = new char[this->pointer_buffer_size];
} }
~MitMSession() override { virtual ~MitMSession() {
delete this->service_object;
delete this->pointer_buffer;
serviceClose(&forward_service); serviceClose(&forward_service);
if (server_handle) {
svcCloseHandle(server_handle);
}
if (client_handle) {
svcCloseHandle(client_handle);
}
}
T *get_service_object() { return this->service_object; }
Handle get_server_handle() { return this->server_handle; }
Handle get_client_handle() { return this->client_handle; }
/* IWaitable */
unsigned int get_num_waitables() override {
return 1;
} }
void get_waitables(IWaitable **dst) override { Result handle_message(IpcParsedCommand &r) override {
dst[0] = this; IpcCommand c;
} ipcInitialize(&c);
u64 cmd_id = ((u32 *)r.Raw)[2];
void delete_child(IWaitable *child) override { Result retval = 0xF601;
/* TODO: Panic, because we can never have any children. */
} cur_out_r.NumHandles = 0;
Handle get_handle() override { Log(armGetTls(), 0x100);
return this->server_handle;
}
void handle_deferred() override {
/* TODO: Panic, because we can never be deferred. */
}
Result handle_signaled(u64 timeout) override {
Result rc;
int handle_index;
/* Prepare pointer buffer... */
IpcCommand c_for_reply;
ipcInitialize(&c_for_reply);
ipcAddRecvStatic(&c_for_reply, this->pointer_buffer, this->pointer_buffer_size, 0);
u32 *cmdbuf = (u32 *)armGetTls(); u32 *cmdbuf = (u32 *)armGetTls();
ipcPrepareHeader(&c_for_reply, 0); if (r.CommandType == IpcCommandType_Request || r.CommandType == IpcCommandType_RequestWithContext) {
IServiceObject *obj;
if (r.IsDomainMessage) {
if (R_SUCCEEDED(rc = svcReplyAndReceive(&handle_index, &this->server_handle, 1, 0, timeout))) { obj = this->get_domain_object(r.ThisObjectId);
if (handle_index != 0) { if (obj && r.MessageType == DomainMessageType_Close) {
/* TODO: Panic? */ this->delete_object(r.ThisObjectId);
} struct {
Log(armGetTls(), 0x100); u64 magic;
Result retval = 0; u64 result;
u32 *rawdata_start = cmdbuf; } *o_resp;
IpcParsedCommand r;
IpcCommand c;
IpcParsedCommand out_r;
out_r.NumHandles = 0;
ipcInitialize(&c);
retval = ipcParse(&r);
u64 cmd_id = U64_MAX;
/* TODO: Close input copy handles that we don't need. */
if (R_SUCCEEDED(retval)) {
rawdata_start = (u32 *)r.Raw;
cmd_id = rawdata_start[2];
retval = 0xF601;
if (r.CommandType == IpcCommandType_Request || r.CommandType == IpcCommandType_RequestWithContext) {
retval = this->service_object->dispatch(r, c, cmd_id, (u8 *)this->pointer_buffer, this->pointer_buffer_size);
if (R_SUCCEEDED(retval)) {
ipcParse(&out_r);
}
}
/* 0xF601 --> Dispatch onwards. */
if (retval == 0xF601) {
/* Patch PID Descriptor, if relevant. */
if (r.HasPid) {
/* [ctrl 0] [ctrl 1] [handle desc 0] [pid low] [pid high] */
cmdbuf[4] = 0xFFFE0000UL | (cmdbuf[4] & 0xFFFFUL);
}
Log(armGetTls(), 0x100);
retval = serviceIpcDispatch(&forward_service);
if (R_SUCCEEDED(retval)) {
ipcParse(&out_r);
o_resp = (decltype(o_resp)) ipcPrepareHeaderForDomain(&c, sizeof(*o_resp), 0);
*(DomainMessageHeader *)((uintptr_t)o_resp - sizeof(DomainMessageHeader)) = {0};
o_resp->magic = SFCO_MAGIC;
o_resp->result = 0x0;
Log(armGetTls(), 0x100);
Reboot();
return o_resp->result;
}
} else {
obj = this->service_object;
}
if (obj) {
retval = obj->dispatch(r, c, cmd_id, (u8 *)this->pointer_buffer, this->pointer_buffer_size);
if (R_SUCCEEDED(retval)) {
if (r.IsDomainMessage) {
ipcParseForDomain(&cur_out_r);
} else {
ipcParse(&cur_out_r);
}
return retval;
}
}
} else if (r.CommandType == IpcCommandType_Control || r.CommandType == IpcCommandType_ControlWithContext) {
/* Ipc Clone Current Object. */
retval = serviceIpcDispatch(&forward_service);
Log(armGetTls(), 0x100);
if (R_SUCCEEDED(retval)) {
ipcParse(&cur_out_r);
struct {
u64 magic;
u64 result;
} *resp = (decltype(resp))cur_out_r.Raw;
retval = resp->result;
if (false && (cmd_id == IpcCtrl_Cmd_CloneCurrentObject || cmd_id == IpcCtrl_Cmd_CloneCurrentObjectEx)) {
if (R_SUCCEEDED(retval)) {
Handle s_h;
Handle c_h;
Result rc;
if (R_FAILED((rc = svcCreateSession(&s_h, &c_h, 0, 0)))) {
fatalSimple(rc);
}
MitMSession<T> *new_sess = new MitMSession<T>((MitMServer<T> *)this->server, s_h, c_h, cur_out_r.Handles[0], this->pointer_buffer_size);
this->get_service_object()->clone_to(new_sess->get_service_object());
if (this->is_domain) {
new_sess->is_domain = true;
new_sess->mitm_domain_id = this->mitm_domain_id;
new_sess->forward_service.type = this->forward_service.type;
new_sess->forward_service.object_id = this->forward_service.object_id;
new_sess->set_object(new_sess->get_service_object(), new_sess->mitm_domain_id);
for (unsigned int i = 0; i < DOMAIN_ID_MAX; i++) {
if (i != new_sess->mitm_domain_id) {
IServiceObject *obj = this->get_domain_object(i);
if (obj) {
new_sess->set_object(obj->clone(), i);
}
}
}
}
this->get_manager()->add_waitable(new_sess);
ipcSendHandleMove(&c, c_h);
struct { struct {
u64 magic; u64 magic;
u64 result; u64 result;
} *resp = (decltype(resp))out_r.Raw; } *o_resp;
retval = resp->result; o_resp = (decltype(o_resp)) ipcPrepareHeader(&c, sizeof(*o_resp));
o_resp->magic = SFCO_MAGIC;
o_resp->result = 0x0;
} }
} }
} }
Log(armGetTls(), 0x100);
return retval;
}
/* 0xF601 --> Dispatch onwards. */
if (retval == 0xF601) {
/* Patch PID Descriptor, if relevant. */
if (r.HasPid) {
/* [ctrl 0] [ctrl 1] [handle desc 0] [pid low] [pid high] */
cmdbuf[4] = 0xFFFE0000UL | (cmdbuf[4] & 0xFFFFUL);
}
if (retval == 0xF601) { Log(armGetTls(), 0x100);
/* Session close. */ retval = serviceIpcDispatch(&forward_service);
rc = retval; if (R_SUCCEEDED(retval)) {
} else { if (r.IsDomainMessage) {
if (R_SUCCEEDED(rc)) { ipcParseForDomain(&cur_out_r);
ipcInitialize(&c); } else {
retval = this->service_object->postprocess(r, c, cmd_id, (u8 *)this->pointer_buffer, this->pointer_buffer_size); ipcParse(&cur_out_r);
}
Log(armGetTls(), 0x100);
rc = svcReplyAndReceive(&handle_index, &this->server_handle, 0, this->server_handle, 0);
/* Clean up copy handles. */
for (unsigned int i = 0; i < out_r.NumHandles; i++) {
if (out_r.WasHandleCopied[i]) {
svcCloseHandle(out_r.Handles[i]);
}
} }
struct {
u64 magic;
u64 result;
} *resp = (decltype(resp))cur_out_r.Raw;
retval = resp->result;
}
}
Log(armGetTls(), 0x100);
Log(&cmd_id, sizeof(u64));
u64 retval_for_log = retval;
Log(&retval_for_log, sizeof(u64));
if (R_FAILED(retval)) {
// Reboot();
}
return retval;
}
void postprocess(IpcParsedCommand &r, u64 cmd_id) override {
if (this->active_object == this->service_object && (r.CommandType == IpcCommandType_Request || r.CommandType == IpcCommandType_RequestWithContext)) {
IpcCommand c;
ipcInitialize(&c);
this->service_object->postprocess(cur_out_r, c, cmd_id, (u8 *)this->pointer_buffer, this->pointer_buffer_size);
} else if (r.CommandType == IpcCommandType_Control || r.CommandType == IpcCommandType_ControlWithContext) {
if (cmd_id == IpcCtrl_Cmd_ConvertCurrentObjectToDomain) {
return;
this->is_domain = true;
struct {
u64 magic;
u64 result;
u32 domain_id;
} *resp = (decltype(resp))cur_out_r.Raw;
Result rc;
if (R_FAILED((rc = this->set_object(this->service_object, resp->domain_id)))) {
fatalSimple(rc);
}
this->mitm_domain_id = resp->domain_id;
this->forward_service.type = ServiceType_Domain;
this->forward_service.object_id = resp->domain_id;
}
}
}
void cleanup() override {
/* Clean up copy handles. */
for (unsigned int i = 0; i < cur_out_r.NumHandles; i++) {
if (cur_out_r.WasHandleCopied[i]) {
svcCloseHandle(cur_out_r.Handles[i]);
} }
} }
return rc;
} }
}; };

View file

@ -1,5 +1,7 @@
#pragma once #pragma once
#include "stratosphere/ipc_templating.hpp"
#include "stratosphere/iwaitable.hpp" #include "stratosphere/iwaitable.hpp"
#include "stratosphere/iserviceobject.hpp" #include "stratosphere/iserviceobject.hpp"
#include "stratosphere/iserver.hpp" #include "stratosphere/iserver.hpp"
@ -8,12 +10,9 @@
#include "stratosphere/serviceserver.hpp" #include "stratosphere/serviceserver.hpp"
#include "stratosphere/managedportserver.hpp" #include "stratosphere/managedportserver.hpp"
#include "stratosphere/existingportserver.hpp" #include "stratosphere/existingportserver.hpp"
#include "stratosphere/childholder.hpp"
#include "stratosphere/ievent.hpp" #include "stratosphere/ievent.hpp"
#include "stratosphere/systemevent.hpp" #include "stratosphere/systemevent.hpp"
#include "stratosphere/hossynch.hpp" #include "stratosphere/hossynch.hpp"
#include "stratosphere/waitablemanager.hpp" #include "stratosphere/waitablemanager.hpp"
#include "stratosphere/ipc_templating.hpp"

View file

@ -1,76 +0,0 @@
#pragma once
#include <switch.h>
#include <vector>
#include "iwaitable.hpp"
class ChildWaitableHolder : public IWaitable {
protected:
std::vector<IWaitable *> children;
public:
/* Implicit constructor. */
void add_child(IWaitable *child) {
this->children.push_back(child);
}
virtual ~ChildWaitableHolder() {
for (unsigned int i = 0; i < this->children.size(); i++) {
delete this->children[i];
}
this->children.clear();
}
/* IWaitable */
virtual unsigned int get_num_waitables() {
unsigned int n = 0;
for (unsigned int i = 0; i < this->children.size(); i++) {
if (this->children[i]) {
n += this->children[i]->get_num_waitables();
}
}
return n;
}
virtual void get_waitables(IWaitable **dst) {
unsigned int n = 0;
for (unsigned int i = 0; i < this->children.size(); i++) {
if (this->children[i]) {
this->children[i]->get_waitables(&dst[n]);
n += this->children[i]->get_num_waitables();
}
}
}
virtual void delete_child(IWaitable *child) {
unsigned int i;
for (i = 0; i < this->children.size(); i++) {
if (this->children[i] == child) {
break;
}
}
if (i == this->children.size()) {
/* TODO: Panic, because this isn't our child. */
} else {
delete this->children[i];
this->children.erase(this->children.begin() + i);
}
}
virtual Handle get_handle() {
/* We don't have a handle. */
return 0;
}
virtual void handle_deferred() {
/* TODO: Panic, because we can never defer a server. */
}
virtual Result handle_signaled(u64 timeout) {
/* TODO: Panic, because we can never be signalled. */
return 0;
}
};

View file

@ -0,0 +1,80 @@
#pragma once
#include <switch.h>
#include <type_traits>
#include "iserviceobject.hpp"
#define DOMAIN_ID_MAX 0x200
class IServiceObject;
class DomainOwner {
private:
IServiceObject *domain_objects[DOMAIN_ID_MAX];
public:
DomainOwner() {
for (unsigned int i = 0; i < DOMAIN_ID_MAX; i++) {
domain_objects[i] = NULL;
}
}
virtual ~DomainOwner() {
for (unsigned int i = 0; i < DOMAIN_ID_MAX; i++) {
this->delete_object(i);
}
}
IServiceObject *get_domain_object(unsigned int i) {
if (i < DOMAIN_ID_MAX) {
return domain_objects[i];
}
return NULL;
}
Result reserve_object(IServiceObject *object, unsigned int *out_i) {
for (unsigned int i = 4; i < DOMAIN_ID_MAX; i++) {
if (domain_objects[i] == NULL) {
domain_objects[i] = object;
object->set_owner(this);
*out_i = i;
return 0;
}
}
return 0x1900B;
}
Result set_object(IServiceObject *object, unsigned int i) {
if (domain_objects[i] == NULL) {
domain_objects[i] = object;
object->set_owner(this);
return 0;
}
return 0x1900B;
}
unsigned int get_object_id(IServiceObject *object) {
for (unsigned int i = 0; i < DOMAIN_ID_MAX; i++) {
if (domain_objects[i] == object) {
return i;
}
}
return DOMAIN_ID_MAX;
}
void delete_object(unsigned int i) {
if (domain_objects[i]) {
delete domain_objects[i];
domain_objects[i] = NULL;
}
}
void delete_object(IServiceObject *object) {
for (unsigned int i = 0; i < DOMAIN_ID_MAX; i++) {
if (domain_objects[i] == object) {
delete domain_objects[i];
domain_objects[i] = NULL;
break;
}
}
}
};

View file

@ -5,7 +5,11 @@
template <typename T> template <typename T>
class ExistingPortServer : public IServer<T> { class ExistingPortServer : public IServer<T> {
public: public:
ExistingPortServer(Handle port_h, unsigned int max_s) : IServer<T>(NULL, max_s) { ExistingPortServer(Handle port_h, unsigned int max_s, bool s_d = false) : IServer<T>(NULL, max_s, s_d) {
this->port_handle = port_h; this->port_handle = port_h;
} }
ISession<T> *get_new_session(Handle session_h) override {
return new ServiceSession<T>(this, session_h, 0);
}
}; };

View file

@ -27,24 +27,7 @@ class IEvent : public IWaitable {
virtual Result signal_event() = 0; virtual Result signal_event() = 0;
/* IWaitable */ /* IWaitable */
virtual unsigned int get_num_waitables() {
if (handles.size() > 0) {
return 1;
}
return 0;
}
virtual void get_waitables(IWaitable **dst) {
if (handles.size() > 0) {
dst[0] = this;
}
}
virtual void delete_child(IWaitable *child) {
/* TODO: Panic, an event can never be a parent. */
}
virtual Handle get_handle() { virtual Handle get_handle() {
if (handles.size() > 0) { if (handles.size() > 0) {
return this->handles[0]; return this->handles[0];

View file

@ -6,6 +6,8 @@
#include "../boost/callable_traits.hpp" #include "../boost/callable_traits.hpp"
#include <type_traits> #include <type_traits>
#include "domainowner.hpp"
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
@ -88,6 +90,21 @@ struct CopiedHandle {
CopiedHandle(Handle h) : handle(h) { } CopiedHandle(Handle h) : handle(h) { }
}; };
/* Forward declarations. */
template <typename T>
class ISession;
/* Represents an output ServiceObject. */
struct OutSessionBase {};
template <typename T>
struct OutSession : OutSessionBase {
ISession<T> *session;
u32 domain_id;
OutSession(ISession<T> *s) : session(s), domain_id(DOMAIN_ID_MAX) { }
};
/* Utilities. */ /* Utilities. */
template <typename T, template <typename...> class Template> template <typename T, template <typename...> class Template>
struct is_specialization_of { struct is_specialization_of {
@ -117,9 +134,14 @@ struct is_ipc_handle {
static const size_t value = (std::is_same<T, MovedHandle>::value || std::is_same<T, CopiedHandle>::value) ? 1 : 0; static const size_t value = (std::is_same<T, MovedHandle>::value || std::is_same<T, CopiedHandle>::value) ? 1 : 0;
}; };
template <typename T>
struct is_out_session {
static const bool value = std::is_base_of<OutSessionBase, T>::value;
};
template <typename T> template <typename T>
struct size_in_raw_data { struct size_in_raw_data {
static const size_t value = (is_ipc_buffer<T>::value || is_ipc_handle<T>::value) ? 0 : ((sizeof(T) < sizeof(u32)) ? sizeof(u32) : (sizeof(T) + 3) & (~3)); static const size_t value = (is_ipc_buffer<T>::value || is_ipc_handle<T>::value || is_out_session<T>::value) ? 0 : ((sizeof(T) < sizeof(u32)) ? sizeof(u32) : (sizeof(T) + 3) & (~3));
}; };
template <typename ...Args> template <typename ...Args>
@ -127,6 +149,11 @@ struct size_in_raw_data_for_arguments {
static const size_t value = (size_in_raw_data<Args>::value + ... + 0); static const size_t value = (size_in_raw_data<Args>::value + ... + 0);
}; };
template <typename ...Args>
struct num_out_sessions_in_arguments {
static const size_t value = ((is_out_session<Args>::value ? 1 : 0) + ... + 0);
};
template <typename T> template <typename T>
struct size_in_raw_data_with_out_pointers { struct size_in_raw_data_with_out_pointers {
static const size_t value = is_specialization_of<T, OutPointerWithClientSize>::value ? 2 : size_in_raw_data<T>::value; static const size_t value = is_specialization_of<T, OutPointerWithClientSize>::value ? 2 : size_in_raw_data<T>::value;
@ -293,6 +320,10 @@ struct Validator<std::tuple<Args...>> {
return 0xF601; return 0xF601;
} }
if (((u32 *)r.Raw)[0] != SFCI_MAGIC) {
//return 0xF601;
}
size_t a_index = 0, b_index = num_inbuffers_in_arguments<Args ...>::value, x_index = 0, c_index = 0, h_index = 0; size_t a_index = 0, b_index = num_inbuffers_in_arguments<Args ...>::value, x_index = 0, c_index = 0, h_index = 0;
size_t cur_rawdata_index = 4; size_t cur_rawdata_index = 4;
size_t cur_c_size_offset = 0x10 + size_in_raw_data_for_arguments<Args... >::value + (0x10 - ((uintptr_t)r.Raw - (uintptr_t)r.RawWithoutPadding)); size_t cur_c_size_offset = 0x10 + size_in_raw_data_for_arguments<Args... >::value + (0x10 - ((uintptr_t)r.Raw - (uintptr_t)r.RawWithoutPadding));
@ -334,33 +365,55 @@ template<typename ArgsTuple>
struct Encoder; struct Encoder;
template<typename T> template<typename T>
constexpr size_t GetAndUpdateOffsetIntoRawData(size_t& offset) { constexpr size_t GetAndUpdateOffsetIntoRawData(DomainOwner *domain_owner, size_t& offset) {
auto old = offset; auto old = offset;
if (old == 0) { if (old == 0) {
offset += sizeof(u64); offset += sizeof(u64);
} else { } else {
offset += size_in_raw_data<T>::value; if constexpr (is_out_session<T>::value) {
if (domain_owner) {
offset += sizeof(u32);
}
} else {
offset += size_in_raw_data<T>::value;
}
} }
return old; return old;
} }
template<typename T> template<typename T>
void EncodeValueIntoIpcMessageBeforePrepare(IpcCommand *c, T value) { void EncodeValueIntoIpcMessageBeforePrepare(DomainOwner *domain_owner, IpcCommand *c, T &value) {
if constexpr (std::is_same<T, MovedHandle>::value) { if constexpr (std::is_same<T, MovedHandle>::value) {
ipcSendHandleMove(c, value.handle); ipcSendHandleMove(c, value.handle);
} else if constexpr (std::is_same<T, CopiedHandle>::value) { } else if constexpr (std::is_same<T, CopiedHandle>::value) {
ipcSendHandleCopy(c, value.handle); ipcSendHandleCopy(c, value.handle);
} else if constexpr (std::is_same<T, PidDescriptor>::value) { } else if constexpr (std::is_same<T, PidDescriptor>::value) {
ipcSendPid(c); ipcSendPid(c);
} else if constexpr (is_out_session<T>::value) {
if (domain_owner && value.session) {
/* TODO: Check error... */
if (value.domain_id != DOMAIN_ID_MAX) {
domain_owner->set_object(value.session->get_service_object(), value.domain_id);
} else {
domain_owner->reserve_object(value.session->get_service_object(), &value.domain_id);
}
value.session->close_handles();
} else {
ipcSendHandleMove(c, value.session ? value.session->get_client_handle() : 0x0);
}
} }
} }
template<typename T> template<typename T>
void EncodeValueIntoIpcMessageAfterPrepare(u8 *cur_out, T value) { void EncodeValueIntoIpcMessageAfterPrepare(DomainOwner *domain_owner, u8 *cur_out, T value) {
if constexpr (is_ipc_handle<T>::value || std::is_same<T, PidDescriptor>::value) { if constexpr (is_ipc_handle<T>::value || std::is_same<T, PidDescriptor>::value) {
/* Do nothing. */ /* Do nothing. */
} else if constexpr (is_out_session<T>::value) {
if (domain_owner) {
*((u32 *)cur_out) = value.domain_id;
}
} else { } else {
*((T *)(cur_out)) = value; *((T *)(cur_out)) = value;
} }
@ -370,7 +423,7 @@ template<typename... Args>
struct Encoder<std::tuple<Args...>> { struct Encoder<std::tuple<Args...>> {
IpcCommand &out_command; IpcCommand &out_command;
auto operator()(Args... args) { auto operator()(DomainOwner *domain_owner, Args... args) {
static_assert(sizeof...(Args) > 0, "IpcCommandImpls must return std::tuple<Result, ...>"); static_assert(sizeof...(Args) > 0, "IpcCommandImpls must return std::tuple<Result, ...>");
size_t offset = 0; size_t offset = 0;
@ -378,19 +431,26 @@ struct Encoder<std::tuple<Args...>> {
std::fill(tls, tls + 0x100, 0x00); std::fill(tls, tls + 0x100, 0x00);
((EncodeValueIntoIpcMessageBeforePrepare<Args>(&out_command, args)), ...); ((EncodeValueIntoIpcMessageBeforePrepare<Args>(domain_owner, &out_command, args)), ...);
/* Remove the extra space resulting from first Result type. */ /* Remove the extra space resulting from first Result type. */
struct { struct {
u64 magic; u64 magic;
u64 result; u64 result;
} *raw = (decltype(raw))ipcPrepareHeader(&out_command, sizeof(*raw) + size_in_raw_data_for_arguments<Args... >::value - sizeof(Result)); } *raw;
if (domain_owner == NULL) {
raw = (decltype(raw))ipcPrepareHeader(&out_command, sizeof(*raw) + size_in_raw_data_for_arguments<Args... >::value - sizeof(Result));
} else {
raw = (decltype(raw))ipcPrepareHeaderForDomain(&out_command, sizeof(*raw) + size_in_raw_data_for_arguments<Args... >::value + (num_out_sessions_in_arguments<Args... >::value * sizeof(u32)) - sizeof(Result), 0);
*((DomainMessageHeader *)((uintptr_t)raw - sizeof(DomainMessageHeader))) = {0};
}
raw->magic = SFCO_MAGIC; raw->magic = SFCO_MAGIC;
u8 *raw_data = (u8 *)&raw->result; u8 *raw_data = (u8 *)&raw->result;
((EncodeValueIntoIpcMessageAfterPrepare<Args>(raw_data + GetAndUpdateOffsetIntoRawData<Args>(offset), args)), ...); ((EncodeValueIntoIpcMessageAfterPrepare<Args>(domain_owner, raw_data + GetAndUpdateOffsetIntoRawData<Args>(domain_owner, offset), args)), ...);
Result rc = raw->result; Result rc = raw->result;
@ -424,7 +484,9 @@ Result WrapDeferredIpcCommandImpl(Class *this_ptr, Args... args) {
auto tuple_args = std::make_tuple(args...); auto tuple_args = std::make_tuple(args...);
auto result = std::apply( [=](auto&&... a) { return (this_ptr->*IpcCommandImpl)(a...); }, tuple_args); auto result = std::apply( [=](auto&&... a) { return (this_ptr->*IpcCommandImpl)(a...); }, tuple_args);
return std::apply(Encoder<OutArgs>{out_command}, result); DomainOwner *down = NULL;
return std::apply(Encoder<OutArgs>{out_command}, std::tuple_cat(std::make_tuple(down), result));
} }
template<auto IpcCommandImpl, typename Class> template<auto IpcCommandImpl, typename Class>
@ -446,8 +508,12 @@ Result WrapIpcCommandImpl(Class *this_ptr, IpcParsedCommand& r, IpcCommand &out_
auto args = Decoder<OutArgs, InArgsWithoutThis>::Decode(r, out_command, pointer_buffer); auto args = Decoder<OutArgs, InArgsWithoutThis>::Decode(r, out_command, pointer_buffer);
auto result = std::apply( [=](auto&&... args) { return (this_ptr->*IpcCommandImpl)(args...); }, args); auto result = std::apply( [=](auto&&... args) { return (this_ptr->*IpcCommandImpl)(args...); }, args);
DomainOwner *down = NULL;
if (r.IsDomainMessage) {
down = this_ptr->get_owner();
}
return std::apply(Encoder<OutArgs>{out_command}, result); return std::apply(Encoder<OutArgs>{out_command}, std::tuple_cat(std::make_tuple(down), result));
} }
template<auto IpcCommandImpl> template<auto IpcCommandImpl>
@ -468,8 +534,11 @@ Result WrapStaticIpcCommandImpl(IpcParsedCommand& r, IpcCommand &out_command, u8
auto args = Decoder<OutArgs, InArgs>::Decode(r, out_command, pointer_buffer); auto args = Decoder<OutArgs, InArgs>::Decode(r, out_command, pointer_buffer);
auto result = std::apply(IpcCommandImpl, args); auto result = std::apply(IpcCommandImpl, args);
DomainOwner *down = NULL;
return std::apply(Encoder<OutArgs>{out_command}, result); return std::apply(Encoder<OutArgs>{out_command}, std::tuple_cat(std::make_tuple(down), result));
} }
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#include "isession.hpp"

View file

@ -5,200 +5,31 @@
#include "ipc_templating.hpp" #include "ipc_templating.hpp"
#include "iserviceobject.hpp" #include "iserviceobject.hpp"
#include "iwaitable.hpp" #include "iwaitable.hpp"
#include "servicesession.hpp" #include "isession.hpp"
template <typename T> template <typename T>
class IPCSession final : public IWaitable { class IPCSession final : public ISession<T> {
static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject"); static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject");
T *service_object;
Handle server_handle;
Handle client_handle;
char *pointer_buffer;
size_t pointer_buffer_size;
static_assert(sizeof(pointer_buffer) <= POINTER_BUFFER_SIZE_MAX, "Incorrect Size for PointerBuffer!");
public: public:
IPCSession<T>(size_t pbs = 0x400) : pointer_buffer_size(pbs) { IPCSession<T>(size_t pbs = 0x400) : ISession<T>(NULL, 0, 0, 0) {
Result rc; Result rc;
if (R_FAILED((rc = svcCreateSession(&server_handle, &client_handle, 0, 0)))) { if (R_FAILED((rc = svcCreateSession(&this->server_handle, &this->client_handle, 0, 0)))) {
fatalSimple(rc); fatalSimple(rc);
} }
this->service_object = new T(); this->service_object = new T();
this->pointer_buffer = new char[pointer_buffer_size]; this->pointer_buffer_size = pbs;
this->pointer_buffer = new char[this->pointer_buffer_size];
this->is_domain = false;
} }
IPCSession<T>(T *so, size_t pbs = 0x400) : service_object(so), pointer_buffer_size(pbs) { IPCSession<T>(T *so, size_t pbs = 0x400) : ISession<T>(NULL, 0, 0, so, 0) {
Result rc; Result rc;
if (R_FAILED((rc = svcCreateSession(&server_handle, &client_handle, 0, 0)))) { if (R_FAILED((rc = svcCreateSession(&this->server_handle, &this->client_handle, 0, 0)))) {
fatalSimple(rc); fatalSimple(rc);
} }
this->pointer_buffer = new char[pointer_buffer_size]; this->pointer_buffer_size = pbs;
} this->pointer_buffer = new char[this->pointer_buffer_size];
this->is_domain = false;
~IPCSession() override {
delete this->service_object;
delete this->pointer_buffer;
if (server_handle) {
svcCloseHandle(server_handle);
}
if (client_handle) {
svcCloseHandle(client_handle);
}
}
T *get_service_object() { return this->service_object; }
Handle get_server_handle() { return this->server_handle; }
Handle get_client_handle() { return this->client_handle; }
/* IWaitable */
unsigned int get_num_waitables() override {
return 1;
}
void get_waitables(IWaitable **dst) override {
dst[0] = this;
}
void delete_child(IWaitable *child) override {
/* TODO: Panic, because we can never have any children. */
}
Handle get_handle() override {
return this->server_handle;
}
void handle_deferred() override {
Result rc = this->service_object->handle_deferred();
int handle_index;
if (rc != RESULT_DEFER_SESSION) {
this->set_deferred(false);
if (rc == 0xF601) {
svcCloseHandle(this->get_handle());
} else {
rc = svcReplyAndReceive(&handle_index, &this->server_handle, 0, this->server_handle, 0);
}
}
}
Result handle_signaled(u64 timeout) override {
Result rc;
int handle_index;
/* Prepare pointer buffer... */
IpcCommand c_for_reply;
ipcInitialize(&c_for_reply);
ipcAddRecvStatic(&c_for_reply, this->pointer_buffer, this->pointer_buffer_size, 0);
ipcPrepareHeader(&c_for_reply, 0);
if (R_SUCCEEDED(rc = svcReplyAndReceive(&handle_index, &this->server_handle, 1, 0, timeout))) {
if (handle_index != 0) {
/* TODO: Panic? */
}
u32 *cmdbuf = (u32 *)armGetTls();
Result retval = 0;
u32 *rawdata_start = cmdbuf;
IpcParsedCommand r;
IpcCommand c;
ipcInitialize(&c);
retval = ipcParse(&r);
if (R_SUCCEEDED(retval)) {
rawdata_start = (u32 *)r.Raw;
switch (r.CommandType) {
case IpcCommandType_Close:
/* TODO: This should close the session and clean up its resources. */
retval = 0xF601;
break;
case IpcCommandType_LegacyControl:
/* TODO: What does this allow one to do? */
retval = 0xF601;
break;
case IpcCommandType_LegacyRequest:
/* TODO: What does this allow one to do? */
retval = 0xF601;
break;
case IpcCommandType_Request:
case IpcCommandType_RequestWithContext:
retval = this->service_object->dispatch(r, c, rawdata_start[2], (u8 *)this->pointer_buffer, this->pointer_buffer_size);
break;
case IpcCommandType_Control:
case IpcCommandType_ControlWithContext:
retval = this->dispatch_control_command(r, c, rawdata_start[2]);
break;
case IpcCommandType_Invalid:
default:
retval = 0xF601;
break;
}
}
if (retval == RESULT_DEFER_SESSION) {
/* Session defer. */
this->set_deferred(true);
rc = retval;
} else if (retval == 0xF601) {
/* Session close. */
rc = retval;
} else {
rc = svcReplyAndReceive(&handle_index, &this->server_handle, 0, this->server_handle, 0);
}
}
return rc;
}
/* Control commands. */
std::tuple<Result> ConvertCurrentObjectToDomain() {
/* TODO */
return {0xF601};
}
std::tuple<Result> CopyFromCurrentDomain() {
/* TODO */
return {0xF601};
}
std::tuple<Result> CloneCurrentObject() {
/* TODO */
return {0xF601};
}
std::tuple<Result, u32> QueryPointerBufferSize() {
return {0x0, (u32)this->pointer_buffer_size};
}
std::tuple<Result> CloneCurrentObjectEx() {
/* TODO */
return {0xF601};
}
Result dispatch_control_command(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id) {
Result rc = 0xF601;
/* TODO: Implement. */
switch ((IpcControlCommand)cmd_id) {
case IpcCtrl_Cmd_ConvertCurrentObjectToDomain:
rc = WrapIpcCommandImpl<&IPCSession::ConvertCurrentObjectToDomain>(this, r, out_c, (u8 *)this->pointer_buffer, this->pointer_buffer_size);
break;
case IpcCtrl_Cmd_CopyFromCurrentDomain:
rc = WrapIpcCommandImpl<&IPCSession::CopyFromCurrentDomain>(this, r, out_c, (u8 *)this->pointer_buffer, this->pointer_buffer_size);
break;
case IpcCtrl_Cmd_CloneCurrentObject:
rc = WrapIpcCommandImpl<&IPCSession::CloneCurrentObject>(this, r, out_c, (u8 *)this->pointer_buffer, this->pointer_buffer_size);
break;
case IpcCtrl_Cmd_QueryPointerBufferSize:
rc = WrapIpcCommandImpl<&IPCSession::QueryPointerBufferSize>(this, r, out_c, (u8 *)this->pointer_buffer, this->pointer_buffer_size);
break;
case IpcCtrl_Cmd_CloneCurrentObjectEx:
rc = WrapIpcCommandImpl<&IPCSession::CloneCurrentObjectEx>(this, r, out_c, (u8 *)this->pointer_buffer, this->pointer_buffer_size);
break;
default:
break;
}
return rc;
} }
}; };

View file

@ -4,10 +4,10 @@
#include "iserviceobject.hpp" #include "iserviceobject.hpp"
#include "iwaitable.hpp" #include "iwaitable.hpp"
#include "servicesession.hpp" #include "isession.hpp"
template <typename T> template <typename T>
class ServiceSession; class ISession;
template <typename T> template <typename T>
class IServer : public IWaitable { class IServer : public IWaitable {
@ -15,71 +15,22 @@ class IServer : public IWaitable {
protected: protected:
Handle port_handle; Handle port_handle;
unsigned int max_sessions; unsigned int max_sessions;
unsigned int num_sessions; bool supports_domains;
ServiceSession<T> **sessions;
public: public:
IServer(const char *service_name, unsigned int max_s) : max_sessions(max_s) { IServer(const char *service_name, unsigned int max_s, bool s_d = false) : max_sessions(max_s), supports_domains(s_d) {
this->sessions = new ServiceSession<T> *[this->max_sessions];
for (unsigned int i = 0; i < this->max_sessions; i++) {
this->sessions[i] = NULL;
}
this->num_sessions = 0;
} }
virtual ~IServer() { virtual ~IServer() {
for (unsigned int i = 0; i < this->max_sessions; i++) {
if (this->sessions[i]) {
delete this->sessions[i];
}
delete this->sessions;
}
if (port_handle) { if (port_handle) {
svcCloseHandle(port_handle); svcCloseHandle(port_handle);
} }
} }
virtual ISession<T> *get_new_session(Handle session_h) = 0;
/* IWaitable */ /* IWaitable */
virtual unsigned int get_num_waitables() {
unsigned int n = 1;
for (unsigned int i = 0; i < this->max_sessions; i++) {
if (this->sessions[i]) {
n += this->sessions[i]->get_num_waitables();
}
}
return n;
}
virtual void get_waitables(IWaitable **dst) {
dst[0] = this;
unsigned int n = 0;
for (unsigned int i = 0; i < this->max_sessions; i++) {
if (this->sessions[i]) {
this->sessions[i]->get_waitables(&dst[1 + n]);
n += this->sessions[i]->get_num_waitables();
}
}
}
virtual void delete_child(IWaitable *child) {
unsigned int i;
for (i = 0; i < this->max_sessions; i++) {
if (this->sessions[i] == child) {
break;
}
}
if (i == this->max_sessions) {
/* TODO: Panic, because this isn't our child. */
} else {
delete this->sessions[i];
this->sessions[i] = NULL;
this->num_sessions--;
}
}
virtual Handle get_handle() { virtual Handle get_handle() {
return this->port_handle; return this->port_handle;
} }
@ -92,23 +43,12 @@ class IServer : public IWaitable {
virtual Result handle_signaled(u64 timeout) { virtual Result handle_signaled(u64 timeout) {
/* If this server's port was signaled, accept a new session. */ /* If this server's port was signaled, accept a new session. */
Handle session_h; Handle session_h;
svcAcceptSession(&session_h, this->port_handle); Result rc = svcAcceptSession(&session_h, this->port_handle);
if (R_FAILED(rc)) {
return rc;
}
if (this->num_sessions >= this->max_sessions) { this->get_manager()->add_waitable(this->get_new_session(session_h));
svcCloseHandle(session_h);
return 0x10601;
}
unsigned int i;
for (i = 0; i < this->max_sessions; i++) {
if (this->sessions[i] == NULL) {
break;
}
}
this->sessions[i] = new ServiceSession<T>(this, session_h, 0);
this->sessions[i]->set_parent(this);
this->num_sessions++;
return 0; return 0;
} }
}; };

View file

@ -1,11 +1,25 @@
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include "ipc_templating.hpp" template <typename T>
class ISession;
class DomainOwner;
class IServiceObject { class IServiceObject {
protected: private:
DomainOwner *owner = NULL;
public:
virtual ~IServiceObject() { } virtual ~IServiceObject() { }
virtual IServiceObject *clone() = 0;
bool is_domain() { return this->owner != NULL; }
DomainOwner *get_owner() { return this->owner; }
void set_owner(DomainOwner *owner) { this->owner = owner; }
virtual Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) = 0; virtual Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) = 0;
protected:
virtual Result handle_deferred() = 0; virtual Result handle_deferred() = 0;
}; };
#include "domainowner.hpp"

View file

@ -0,0 +1,288 @@
#pragma once
#include <switch.h>
#include <type_traits>
#include "ipc_templating.hpp"
#include "iserviceobject.hpp"
#include "iwaitable.hpp"
#include "iserver.hpp"
#include "domainowner.hpp"
enum IpcControlCommand {
IpcCtrl_Cmd_ConvertCurrentObjectToDomain = 0,
IpcCtrl_Cmd_CopyFromCurrentDomain = 1,
IpcCtrl_Cmd_CloneCurrentObject = 2,
IpcCtrl_Cmd_QueryPointerBufferSize = 3,
IpcCtrl_Cmd_CloneCurrentObjectEx = 4
};
#define POINTER_BUFFER_SIZE_MAX 0xFFFF
#define RESULT_DEFER_SESSION (0x6580A)
template <typename T>
class IServer;
class IServiceObject;
template <typename T>
class ISession : public IWaitable, public DomainOwner {
static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject");
protected:
T *service_object;
IServer<T> *server;
Handle server_handle;
Handle client_handle;
char *pointer_buffer;
size_t pointer_buffer_size;
bool is_domain;
IServiceObject *active_object;
static_assert(sizeof(pointer_buffer) <= POINTER_BUFFER_SIZE_MAX, "Incorrect Size for PointerBuffer!");
public:
ISession<T>(IServer<T> *s, Handle s_h, Handle c_h, size_t pbs = 0x400) : server(s), server_handle(s_h), client_handle(c_h), pointer_buffer_size(pbs) {
this->service_object = new T();
if (this->pointer_buffer_size) {
this->pointer_buffer = new char[this->pointer_buffer_size];
}
this->is_domain = false;
this->active_object = NULL;
}
ISession<T>(IServer<T> *s, Handle s_h, Handle c_h, T *so, size_t pbs = 0x400) : service_object(so), server(s), server_handle(s_h), client_handle(c_h), pointer_buffer_size(pbs) {
if (this->pointer_buffer_size) {
this->pointer_buffer = new char[this->pointer_buffer_size];
}
this->is_domain = false;
this->active_object = NULL;
}
~ISession() override {
delete this->pointer_buffer;
if (this->service_object && !this->is_domain) {
//delete this->service_object;
}
if (server_handle) {
svcCloseHandle(server_handle);
}
if (client_handle) {
svcCloseHandle(client_handle);
}
}
void close_handles() {
if (server_handle) {
svcCloseHandle(server_handle);
server_handle = 0;
}
if (client_handle) {
svcCloseHandle(client_handle);
client_handle = 0;
}
}
T *get_service_object() { return this->service_object; }
Handle get_server_handle() { return this->server_handle; }
Handle get_client_handle() { return this->client_handle; }
DomainOwner *get_owner() { return is_domain ? this : NULL; }
/* IWaitable */
Handle get_handle() override {
return this->server_handle;
}
void handle_deferred() override {
Result rc = this->service_object->handle_deferred();
int handle_index;
if (rc != RESULT_DEFER_SESSION) {
this->set_deferred(false);
if (rc == 0xF601) {
svcCloseHandle(this->get_handle());
} else {
rc = svcReplyAndReceive(&handle_index, &this->server_handle, 0, this->server_handle, 0);
}
}
}
virtual Result handle_message(IpcParsedCommand &r) {
Result retval = 0xF601;
IpcCommand c;
ipcInitialize(&c);
if (r.IsDomainMessage && this->active_object == NULL) {
return 0xF601;
}
if (r.IsDomainMessage && r.MessageType == DomainMessageType_Close) {
this->delete_object(this->active_object);
this->active_object = NULL;
struct {
u64 magic;
u64 result;
} *raw = (decltype(raw))ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCO_MAGIC;
raw->result = 0x0;
return 0x0;
}
u64 cmd_id = ((u32 *)r.Raw)[2];
switch (r.CommandType) {
case IpcCommandType_Close:
/* TODO: This should close the session and clean up its resources. */
retval = 0xF601;
break;
case IpcCommandType_LegacyControl:
/* TODO: What does this allow one to do? */
retval = 0xF601;
break;
case IpcCommandType_LegacyRequest:
/* TODO: What does this allow one to do? */
retval = 0xF601;
break;
case IpcCommandType_Request:
case IpcCommandType_RequestWithContext:
retval = this->active_object->dispatch(r, c, cmd_id, (u8 *)this->pointer_buffer, this->pointer_buffer_size);
break;
case IpcCommandType_Control:
case IpcCommandType_ControlWithContext:
retval = this->dispatch_control_command(r, c, cmd_id);
break;
case IpcCommandType_Invalid:
default:
retval = 0xF601;
break;
}
return retval;
}
virtual void postprocess(IpcParsedCommand &r, u64 cmd_id) {
/* ... */
(void)(r);
(void)(cmd_id);
}
virtual void cleanup() {
/* ... */
}
Result handle_signaled(u64 timeout) override {
Result rc;
int handle_index;
/* Prepare pointer buffer... */
IpcCommand c_for_reply;
ipcInitialize(&c_for_reply);
ipcAddRecvStatic(&c_for_reply, this->pointer_buffer, this->pointer_buffer_size, 0);
ipcPrepareHeader(&c_for_reply, 0);
if (R_SUCCEEDED(rc = svcReplyAndReceive(&handle_index, &this->server_handle, 1, 0, timeout))) {
if (handle_index != 0) {
/* TODO: Panic? */
}
IpcParsedCommand r;
u64 cmd_id;
Result retval = ipcParse(&r);
if (R_SUCCEEDED(retval)) {
if (this->is_domain && (r.CommandType == IpcCommandType_Request || r.CommandType == IpcCommandType_RequestWithContext)) {
retval = ipcParseForDomain(&r);
if (!r.IsDomainMessage || r.ThisObjectId >= DOMAIN_ID_MAX) {
retval = 0xF601;
} else {
this->active_object = this->get_domain_object(r.ThisObjectId);
}
} else {
this->active_object = this->service_object;
}
}
if (R_SUCCEEDED(retval)) {
cmd_id = ((u32 *)r.Raw)[2];
}
if (R_SUCCEEDED(retval)) {
retval = this->handle_message(r);
}
if (retval == RESULT_DEFER_SESSION) {
/* Session defer. */
this->active_object = NULL;
this->set_deferred(true);
rc = retval;
} else if (retval == 0xF601) {
/* Session close. */
this->active_object = NULL;
rc = retval;
} else {
if (R_SUCCEEDED(retval)) {
this->postprocess(r, cmd_id);
}
this->active_object = NULL;
rc = svcReplyAndReceive(&handle_index, &this->server_handle, 0, this->server_handle, 0);
this->cleanup();
}
}
return rc;
}
Result dispatch_control_command(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id) {
Result rc = 0xF601;
/* TODO: Implement. */
switch ((IpcControlCommand)cmd_id) {
case IpcCtrl_Cmd_ConvertCurrentObjectToDomain:
rc = WrapIpcCommandImpl<&ISession::ConvertCurrentObjectToDomain>(this, r, out_c, (u8 *)this->pointer_buffer, this->pointer_buffer_size);
break;
case IpcCtrl_Cmd_CopyFromCurrentDomain:
rc = WrapIpcCommandImpl<&ISession::CopyFromCurrentDomain>(this, r, out_c, (u8 *)this->pointer_buffer, this->pointer_buffer_size);
break;
case IpcCtrl_Cmd_CloneCurrentObject:
rc = WrapIpcCommandImpl<&ISession::CloneCurrentObject>(this, r, out_c, (u8 *)this->pointer_buffer, this->pointer_buffer_size);
break;
case IpcCtrl_Cmd_QueryPointerBufferSize:
rc = WrapIpcCommandImpl<&ISession::QueryPointerBufferSize>(this, r, out_c, (u8 *)this->pointer_buffer, this->pointer_buffer_size);
break;
case IpcCtrl_Cmd_CloneCurrentObjectEx:
rc = WrapIpcCommandImpl<&ISession::CloneCurrentObjectEx>(this, r, out_c, (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer));
break;
default:
break;
}
return rc;
}
/* Control commands. */
std::tuple<Result> ConvertCurrentObjectToDomain() {
/* TODO */
return {0xF601};
}
std::tuple<Result> CopyFromCurrentDomain() {
/* TODO */
return {0xF601};
}
std::tuple<Result> CloneCurrentObject() {
/* TODO */
return {0xF601};
}
std::tuple<Result, u32> QueryPointerBufferSize() {
return {0x0, (u32)this->pointer_buffer_size};
}
std::tuple<Result> CloneCurrentObjectEx() {
/* TODO */
return {0xF601};
}
};

View file

@ -2,38 +2,34 @@
#include <switch.h> #include <switch.h>
#include "waitablemanagerbase.hpp"
class WaitableManager;
class IWaitable { class IWaitable {
u64 wait_priority = 0; private:
bool is_deferred = false; u64 wait_priority = 0;
IWaitable *parent_waitable; bool is_deferred = false;
WaitableManagerBase *manager;
public: public:
virtual ~IWaitable() { } virtual ~IWaitable() { }
virtual unsigned int get_num_waitables() = 0;
virtual void get_waitables(IWaitable **dst) = 0;
virtual void delete_child(IWaitable *child) = 0;
virtual void handle_deferred() = 0; virtual void handle_deferred() = 0;
virtual Handle get_handle() = 0; virtual Handle get_handle() = 0;
virtual Result handle_signaled(u64 timeout) = 0; virtual Result handle_signaled(u64 timeout) = 0;
bool has_parent() { WaitableManager *get_manager() {
return this->parent_waitable != NULL; return (WaitableManager *)this->manager;
} }
void set_parent(IWaitable *p) { void set_manager(WaitableManagerBase *m) {
if (has_parent()) { this->manager = m;
/* TODO: Panic? */
}
this->parent_waitable = p;
}
IWaitable *get_parent() {
return this->parent_waitable;
} }
void update_priority() { void update_priority() {
static u64 g_cur_priority = 0; if (manager) {
this->wait_priority = g_cur_priority++; this->wait_priority = this->manager->get_priority();
}
} }
bool get_deferred() { bool get_deferred() {
@ -47,4 +43,6 @@ class IWaitable {
static bool compare(IWaitable *a, IWaitable *b) { static bool compare(IWaitable *a, IWaitable *b) {
return (a->wait_priority < b->wait_priority) && !a->is_deferred; return (a->wait_priority < b->wait_priority) && !a->is_deferred;
} }
}; };
#include "waitablemanager.hpp"

View file

@ -5,9 +5,13 @@
template <typename T> template <typename T>
class ManagedPortServer : public IServer<T> { class ManagedPortServer : public IServer<T> {
public: public:
ManagedPortServer(const char *service_name, unsigned int max_s) : IServer<T>(service_name, max_s) { ManagedPortServer(const char *service_name, unsigned int max_s, bool s_d = false) : IServer<T>(service_name, max_s, s_d) {
if (R_FAILED(svcManageNamedPort(&this->port_handle, service_name, this->max_sessions))) { if (R_FAILED(svcManageNamedPort(&this->port_handle, service_name, this->max_sessions))) {
/* TODO: panic */ /* TODO: panic */
} }
} }
ISession<T> *get_new_session(Handle session_h) override {
return new ServiceSession<T>(this, session_h, 0);
}
}; };

View file

@ -5,9 +5,13 @@
template <typename T> template <typename T>
class ServiceServer : public IServer<T> { class ServiceServer : public IServer<T> {
public: public:
ServiceServer(const char *service_name, unsigned int max_s) : IServer<T>(service_name, max_s) { ServiceServer(const char *service_name, unsigned int max_s, bool s_d = false) : IServer<T>(service_name, max_s, s_d) {
if (R_FAILED(smRegisterService(&this->port_handle, service_name, false, this->max_sessions))) { if (R_FAILED(smRegisterService(&this->port_handle, service_name, false, this->max_sessions))) {
/* TODO: Panic. */ /* TODO: Panic. */
} }
} }
ISession<T> *get_new_session(Handle session_h) override {
return new ServiceSession<T>(this, session_h, 0);
}
}; };

View file

@ -6,200 +6,15 @@
#include "iserviceobject.hpp" #include "iserviceobject.hpp"
#include "iwaitable.hpp" #include "iwaitable.hpp"
#include "iserver.hpp" #include "iserver.hpp"
#include "isession.hpp"
enum IpcControlCommand {
IpcCtrl_Cmd_ConvertCurrentObjectToDomain = 0,
IpcCtrl_Cmd_CopyFromCurrentDomain = 1,
IpcCtrl_Cmd_CloneCurrentObject = 2,
IpcCtrl_Cmd_QueryPointerBufferSize = 3,
IpcCtrl_Cmd_CloneCurrentObjectEx = 4
};
#define POINTER_BUFFER_SIZE_MAX 0xFFFF
#define RESULT_DEFER_SESSION (0x6580A)
template <typename T> template <typename T>
class IServer; class ServiceSession final : public ISession<T> {
template <typename T>
class ServiceSession final : public IWaitable {
static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject"); static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject");
T *service_object;
IServer<T> *server;
Handle server_handle;
Handle client_handle;
char pointer_buffer[0x400];
static_assert(sizeof(pointer_buffer) <= POINTER_BUFFER_SIZE_MAX, "Incorrect Size for PointerBuffer!");
public: public:
ServiceSession<T>(IServer<T> *s, Handle s_h, Handle c_h) : server(s), server_handle(s_h), client_handle(c_h) { ServiceSession<T>(IServer<T> *s, Handle s_h, Handle c_h, size_t pbs = 0x400) : ISession<T>(s, s_h, c_h, pbs) {
this->service_object = new T(); /* ... */
} }
~ServiceSession() override {
delete this->service_object;
if (server_handle) {
svcCloseHandle(server_handle);
}
if (client_handle) {
svcCloseHandle(client_handle);
}
}
T *get_service_object() { return this->service_object; }
Handle get_server_handle() { return this->server_handle; }
Handle get_client_handle() { return this->client_handle; }
/* IWaitable */
unsigned int get_num_waitables() override {
return 1;
}
void get_waitables(IWaitable **dst) override {
dst[0] = this;
}
void delete_child(IWaitable *child) override {
/* TODO: Panic, because we can never have any children. */
}
Handle get_handle() override {
return this->server_handle;
}
void handle_deferred() override {
Result rc = this->service_object->handle_deferred();
int handle_index;
if (rc != RESULT_DEFER_SESSION) {
this->set_deferred(false);
if (rc == 0xF601) {
svcCloseHandle(this->get_handle());
} else {
rc = svcReplyAndReceive(&handle_index, &this->server_handle, 0, this->server_handle, 0);
}
}
}
Result handle_signaled(u64 timeout) override {
Result rc;
int handle_index;
/* Prepare pointer buffer... */
IpcCommand c_for_reply;
ipcInitialize(&c_for_reply);
ipcAddRecvStatic(&c_for_reply, this->pointer_buffer, sizeof(this->pointer_buffer), 0);
ipcPrepareHeader(&c_for_reply, 0);
if (R_SUCCEEDED(rc = svcReplyAndReceive(&handle_index, &this->server_handle, 1, 0, timeout))) {
if (handle_index != 0) {
/* TODO: Panic? */
}
u32 *cmdbuf = (u32 *)armGetTls();
Result retval = 0;
u32 *rawdata_start = cmdbuf;
IpcParsedCommand r;
IpcCommand c;
ipcInitialize(&c);
retval = ipcParse(&r);
if (R_SUCCEEDED(retval)) {
rawdata_start = (u32 *)r.Raw;
switch (r.CommandType) {
case IpcCommandType_Close:
/* TODO: This should close the session and clean up its resources. */
retval = 0xF601;
break;
case IpcCommandType_LegacyControl:
/* TODO: What does this allow one to do? */
retval = 0xF601;
break;
case IpcCommandType_LegacyRequest:
/* TODO: What does this allow one to do? */
retval = 0xF601;
break;
case IpcCommandType_Request:
case IpcCommandType_RequestWithContext:
retval = this->service_object->dispatch(r, c, rawdata_start[2], (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer));
break;
case IpcCommandType_Control:
case IpcCommandType_ControlWithContext:
retval = this->dispatch_control_command(r, c, rawdata_start[2]);
break;
case IpcCommandType_Invalid:
default:
retval = 0xF601;
break;
}
}
if (retval == RESULT_DEFER_SESSION) {
/* Session defer. */
this->set_deferred(true);
rc = retval;
} else if (retval == 0xF601) {
/* Session close. */
rc = retval;
} else {
rc = svcReplyAndReceive(&handle_index, &this->server_handle, 0, this->server_handle, 0);
}
}
return rc;
}
/* Control commands. */
std::tuple<Result> ConvertCurrentObjectToDomain() {
/* TODO */
return {0xF601};
}
std::tuple<Result> CopyFromCurrentDomain() {
/* TODO */
return {0xF601};
}
std::tuple<Result> CloneCurrentObject() {
/* TODO */
return {0xF601};
}
std::tuple<Result, u32> QueryPointerBufferSize() {
return {0x0, (u32)sizeof(this->pointer_buffer)};
}
std::tuple<Result> CloneCurrentObjectEx() {
/* TODO */
return {0xF601};
}
Result dispatch_control_command(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id) {
Result rc = 0xF601;
/* TODO: Implement. */
switch ((IpcControlCommand)cmd_id) {
case IpcCtrl_Cmd_ConvertCurrentObjectToDomain:
rc = WrapIpcCommandImpl<&ServiceSession::ConvertCurrentObjectToDomain>(this, r, out_c, (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer));
break;
case IpcCtrl_Cmd_CopyFromCurrentDomain:
rc = WrapIpcCommandImpl<&ServiceSession::CopyFromCurrentDomain>(this, r, out_c, (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer));
break;
case IpcCtrl_Cmd_CloneCurrentObject:
rc = WrapIpcCommandImpl<&ServiceSession::CloneCurrentObject>(this, r, out_c, (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer));
break;
case IpcCtrl_Cmd_QueryPointerBufferSize:
rc = WrapIpcCommandImpl<&ServiceSession::QueryPointerBufferSize>(this, r, out_c, (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer));
break;
case IpcCtrl_Cmd_CloneCurrentObjectEx:
rc = WrapIpcCommandImpl<&ServiceSession::CloneCurrentObjectEx>(this, r, out_c, (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer));
break;
default:
break;
}
return rc;
}
}; };

View file

@ -2,15 +2,22 @@
#include <switch.h> #include <switch.h>
#include <vector> #include <vector>
#include "waitablemanagerbase.hpp"
#include "iwaitable.hpp" #include "iwaitable.hpp"
#include "hossynch.hpp"
class WaitableManager { class IWaitable;
class WaitableManager : public WaitableManagerBase {
std::vector<IWaitable *> to_add_waitables;
std::vector<IWaitable *> waitables; std::vector<IWaitable *> waitables;
u64 timeout; u64 timeout;
HosMutex lock;
std::atomic_bool has_new_items;
private: private:
void process_internal(bool break_on_timeout); void process_internal(bool break_on_timeout);
public: public:
WaitableManager(u64 t) : waitables(0), timeout(t) { } WaitableManager(u64 t) : waitables(0), timeout(t), has_new_items(false) { }
~WaitableManager() { ~WaitableManager() {
/* This should call the destructor for every waitable. */ /* This should call the destructor for every waitable. */
for (auto & waitable : waitables) { for (auto & waitable : waitables) {
@ -19,7 +26,6 @@ class WaitableManager {
waitables.clear(); waitables.clear();
} }
unsigned int get_num_signalable();
void add_waitable(IWaitable *waitable); void add_waitable(IWaitable *waitable);
void process(); void process();
void process_until_timeout(); void process_until_timeout();

View file

@ -0,0 +1,14 @@
#pragma once
#include <switch.h>
#include <atomic>
#include <vector>
class WaitableManagerBase {
std::atomic<u64> cur_priority;
public:
WaitableManagerBase() : cur_priority(0) { }
u64 get_priority() {
return std::atomic_fetch_add(&cur_priority, (u64)1);
}
};

View file

@ -4,56 +4,51 @@
#include <stratosphere/waitablemanager.hpp> #include <stratosphere/waitablemanager.hpp>
unsigned int WaitableManager::get_num_signalable() {
unsigned int n = 0;
for (auto & waitable : this->waitables) {
n += waitable->get_num_waitables();
}
return n;
}
void WaitableManager::add_waitable(IWaitable *waitable) { void WaitableManager::add_waitable(IWaitable *waitable) {
this->waitables.push_back(waitable); this->lock.Lock();
this->to_add_waitables.push_back(waitable);
waitable->set_manager(this);
this->has_new_items = true;
this->lock.Unlock();
} }
void WaitableManager::process_internal(bool break_on_timeout) { void WaitableManager::process_internal(bool break_on_timeout) {
std::vector<IWaitable *> signalables;
std::vector<Handle> handles; std::vector<Handle> handles;
int handle_index = 0; int handle_index = 0;
Result rc; Result rc;
while (1) { while (1) {
/* Create vector of signalable items. */ /* Add new items, if relevant. */
signalables.resize(this->get_num_signalable(), NULL); if (this->has_new_items) {
unsigned int n = 0; this->lock.Lock();
for (auto & waitable : this->waitables) { this->waitables.insert(this->waitables.end(), this->to_add_waitables.begin(), this->to_add_waitables.end());
waitable->get_waitables(signalables.data() + n); this->to_add_waitables.clear();
n += waitable->get_num_waitables(); this->has_new_items = false;
this->lock.Unlock();
} }
/* Sort signalables by priority. */ /* Sort waitables by priority. */
std::sort(signalables.begin(), signalables.end(), IWaitable::compare); std::sort(this->waitables.begin(), this->waitables.end(), IWaitable::compare);
/* Copy out handles. */ /* Copy out handles. */
handles.resize(signalables.size()); handles.resize(this->waitables.size());
std::transform(signalables.begin(), signalables.end(), handles.begin(), [](IWaitable *w) { return w->get_handle(); }); std::transform(this->waitables.begin(), this->waitables.end(), handles.begin(), [](IWaitable *w) { return w->get_handle(); });
rc = svcWaitSynchronization(&handle_index, handles.data(), signalables.size(), this->timeout); rc = svcWaitSynchronization(&handle_index, handles.data(), this->waitables.size(), this->timeout);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
/* Handle a signaled waitable. */ /* Handle a signaled waitable. */
/* TODO: What timeout should be passed here? */ /* TODO: What timeout should be passed here? */
rc = signalables[handle_index]->handle_signaled(0); rc = this->waitables[handle_index]->handle_signaled(0);
for (int i = 0; i < handle_index; i++) { for (int i = 0; i < handle_index; i++) {
signalables[i]->update_priority(); this->waitables[i]->update_priority();
} }
} else if (rc == 0xEA01) { } else if (rc == 0xEA01) {
/* Timeout. */ /* Timeout. */
for (auto & waitable : signalables) { for (auto & waitable : this->waitables) {
waitable->update_priority(); waitable->update_priority();
} }
if (break_on_timeout) { if (break_on_timeout) {
@ -69,26 +64,21 @@ void WaitableManager::process_internal(bool break_on_timeout) {
/* Close the handle. */ /* Close the handle. */
svcCloseHandle(handles[handle_index]); svcCloseHandle(handles[handle_index]);
IWaitable *to_delete = this->waitables[handle_index];
/* If relevant, remove from waitables. */ /* If relevant, remove from waitables. */
this->waitables.erase(std::remove(this->waitables.begin(), this->waitables.end(), signalables[handle_index]), this->waitables.end()); this->waitables.erase(this->waitables.begin() + handle_index);
/* Delete it. */ /* Delete it. */
if (signalables[handle_index]->has_parent()) { delete to_delete;
signalables[handle_index]->get_parent()->delete_child(signalables[handle_index]);
} else {
delete signalables[handle_index];
}
/* If relevant, remove from signalables. */
signalables.erase(std::remove(signalables.begin(), signalables.end(), signalables[handle_index]), signalables.end());
for (int i = 0; i < handle_index; i++) { for (int i = 0; i < handle_index; i++) {
signalables[i]->update_priority(); this->waitables[i]->update_priority();
} }
} }
/* Do deferred callback for each waitable. */ /* Do deferred callback for each waitable. */
for (auto & waitable : signalables) { for (auto & waitable : this->waitables) {
if (waitable->get_deferred()) { if (waitable->get_deferred()) {
waitable->handle_deferred(); waitable->handle_deferred();
} }

View file

@ -1,7 +1,7 @@
#include <switch.h> #include <switch.h>
#include <cstdio> #include <cstdio>
#include <algorithm> #include <algorithm>
#include <stratosphere.hpp>
#include "ldr_debug_monitor.hpp" #include "ldr_debug_monitor.hpp"
#include "ldr_launch_queue.hpp" #include "ldr_launch_queue.hpp"
#include "ldr_registration.hpp" #include "ldr_registration.hpp"

View file

@ -10,7 +10,7 @@ enum DebugMonitorServiceCmd {
Dmnt_Cmd_GetNsoInfo = 2 Dmnt_Cmd_GetNsoInfo = 2
}; };
class DebugMonitorService final : IServiceObject { class DebugMonitorService final : public IServiceObject {
public: public:
Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override; Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override;
Result handle_deferred() override { Result handle_deferred() override {

View file

@ -72,11 +72,11 @@ void __appInit(void) {
/* Check for exosphere API compatibility. */ /* Check for exosphere API compatibility. */
u64 exosphere_cfg; u64 exosphere_cfg;
if (R_FAILED(splGetConfig((SplConfigItem)65000, &exosphere_cfg))) { if (R_FAILED(splGetConfig((SplConfigItem)65000, &exosphere_cfg))) {
fatalSimple(0xCAFE << 4 | 0xFF); //fatalSimple(0xCAFE << 4 | 0xFF);
/* TODO: Does Loader need to know about target firmware/master key revision? If so, extract from exosphere_cfg. */ /* TODO: Does Loader need to know about target firmware/master key revision? If so, extract from exosphere_cfg. */
} }
splExit(); //splExit();
} }
void __appExit(void) { void __appExit(void) {

View file

@ -198,7 +198,7 @@ Result NsoUtils::CalculateNsoLoadExtents(u32 addspace_type, u32 args_size, NsoLo
} }
Result NsoUtils::LoadNsoSegment(unsigned int index, unsigned int segment, FILE *f_nso, u8 *map_base, u8 *map_end) { Result NsoUtils::LoadNsoSegment(u64 title_id, unsigned int index, unsigned int segment, FILE *f_nso, u8 *map_base, u8 *map_end) {
bool is_compressed = ((g_nso_headers[index].flags >> segment) & 1) != 0; bool is_compressed = ((g_nso_headers[index].flags >> segment) & 1) != 0;
bool check_hash = ((g_nso_headers[index].flags >> (segment + 3)) & 1) != 0; bool check_hash = ((g_nso_headers[index].flags >> (segment + 3)) & 1) != 0;
size_t out_size = g_nso_headers[index].segments[segment].decomp_size; size_t out_size = g_nso_headers[index].segments[segment].decomp_size;
@ -259,7 +259,7 @@ Result NsoUtils::LoadNsosIntoProcessMemory(Handle process_h, u64 title_id, NsoLo
return 0xA09; return 0xA09;
} }
for (unsigned int seg = 0; seg < 3; seg++) { for (unsigned int seg = 0; seg < 3; seg++) {
if (R_FAILED((rc = LoadNsoSegment(i, seg, f_nso, map_base, map_base + extents->nso_sizes[i])))) { if (R_FAILED((rc = LoadNsoSegment(title_id, i, seg, f_nso, map_base, map_base + extents->nso_sizes[i])))) {
fclose(f_nso); fclose(f_nso);
return rc; return rc;
} }

View file

@ -92,6 +92,6 @@ class NsoUtils {
static Result ValidateNsoLoadSet(); static Result ValidateNsoLoadSet();
static Result CalculateNsoLoadExtents(u32 addspace_type, u32 args_size, NsoLoadExtents *extents); static Result CalculateNsoLoadExtents(u32 addspace_type, u32 args_size, NsoLoadExtents *extents);
static Result LoadNsoSegment(unsigned int index, unsigned int segment, FILE *f_nso, u8 *map_base, u8 *map_end); static Result LoadNsoSegment(u64 title_id, unsigned int index, unsigned int segment, FILE *f_nso, u8 *map_base, u8 *map_end);
static Result LoadNsosIntoProcessMemory(Handle process_h, u64 title_id, NsoLoadExtents *extents, u8 *args, u32 args_size); static Result LoadNsosIntoProcessMemory(Handle process_h, u64 title_id, NsoLoadExtents *extents, u8 *args, u32 args_size);
}; };

View file

@ -1,4 +1,5 @@
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp>
#include "ldr_process_manager.hpp" #include "ldr_process_manager.hpp"
#include "ldr_registration.hpp" #include "ldr_registration.hpp"
#include "ldr_launch_queue.hpp" #include "ldr_launch_queue.hpp"
@ -7,7 +8,7 @@
Result ProcessManagerService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) { Result ProcessManagerService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
Result rc = 0xF601; Result rc = 0xF601;
switch ((ProcessManagerServiceCmd)cmd_id) { switch ((ProcessManagerServiceCmd)cmd_id) {
case Pm_Cmd_CreateProcess: case Pm_Cmd_CreateProcess:
rc = WrapIpcCommandImpl<&ProcessManagerService::create_process>(this, r, out_c, pointer_buffer, pointer_buffer_size); rc = WrapIpcCommandImpl<&ProcessManagerService::create_process>(this, r, out_c, pointer_buffer, pointer_buffer_size);
@ -24,7 +25,6 @@ Result ProcessManagerService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u
default: default:
break; break;
} }
return rc; return rc;
} }

View file

@ -12,7 +12,7 @@ enum ProcessManagerServiceCmd {
Pm_Cmd_UnregisterTitle = 3 Pm_Cmd_UnregisterTitle = 3
}; };
class ProcessManagerService final : IServiceObject { class ProcessManagerService final : public IServiceObject {
struct ProgramInfo { struct ProgramInfo {
u8 main_thread_priority; u8 main_thread_priority;
u8 default_cpu_id; u8 default_cpu_id;

View file

@ -1,6 +1,7 @@
#include <switch.h> #include <switch.h>
#include <cstdio> #include <cstdio>
#include <algorithm> #include <algorithm>
#include <stratosphere.hpp>
#include "ldr_ro_service.hpp" #include "ldr_ro_service.hpp"
#include "ldr_registration.hpp" #include "ldr_registration.hpp"

View file

@ -12,7 +12,7 @@ enum RoServiceCmd {
Ro_Cmd_Initialize = 4, Ro_Cmd_Initialize = 4,
}; };
class RelocatableObjectsService final : IServiceObject { class RelocatableObjectsService final : public IServiceObject {
Handle process_handle; Handle process_handle;
u64 process_id; u64 process_id;
bool has_initialized; bool has_initialized;

View file

@ -1,4 +1,5 @@
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp>
#include "ldr_shell.hpp" #include "ldr_shell.hpp"
#include "ldr_launch_queue.hpp" #include "ldr_launch_queue.hpp"

View file

@ -7,7 +7,7 @@ enum ShellServiceCmd {
Shell_Cmd_ClearLaunchQueue = 1 Shell_Cmd_ClearLaunchQueue = 1
}; };
class ShellService final : IServiceObject { class ShellService final : public IServiceObject {
public: public:
Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override; Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override;
Result handle_deferred() override { Result handle_deferred() override {

View file

@ -1,4 +1,5 @@
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp>
#include "sm_manager_service.hpp" #include "sm_manager_service.hpp"
#include "sm_registration.hpp" #include "sm_registration.hpp"

View file

@ -7,11 +7,15 @@ enum ManagerServiceCmd {
Manager_Cmd_UnregisterProcess = 1 Manager_Cmd_UnregisterProcess = 1
}; };
class ManagerService final : IServiceObject { class ManagerService final : public IServiceObject {
public: public:
Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override; Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override;
Result handle_deferred() override; Result handle_deferred() override;
ManagerService *clone() override {
return new ManagerService();
}
private: private:
/* Actual commands. */ /* Actual commands. */
std::tuple<Result> register_process(u64 pid, InBuffer<u8> acid_sac, InBuffer<u8> aci0_sac); std::tuple<Result> register_process(u64 pid, InBuffer<u8> acid_sac, InBuffer<u8> aci0_sac);

View file

@ -4,7 +4,7 @@
#include "sm_registration.hpp" #include "sm_registration.hpp"
Result UserService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) { Result UserService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
Result rc = 0xF601; Result rc = 0xF601;
switch ((UserServiceCmd)cmd_id) { switch ((UserServiceCmd)cmd_id) {
case User_Cmd_Initialize: case User_Cmd_Initialize:
rc = WrapIpcCommandImpl<&UserService::initialize>(this, r, out_c, pointer_buffer, pointer_buffer_size); rc = WrapIpcCommandImpl<&UserService::initialize>(this, r, out_c, pointer_buffer, pointer_buffer_size);

View file

@ -12,7 +12,7 @@ enum UserServiceCmd {
User_Cmd_AtmosphereUninstallMitm = 65001 User_Cmd_AtmosphereUninstallMitm = 65001
}; };
class UserService final : IServiceObject { class UserService final : public IServiceObject {
u64 pid; u64 pid;
bool has_initialized; bool has_initialized;
u64 deferred_service; u64 deferred_service;
@ -22,6 +22,14 @@ class UserService final : IServiceObject {
Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override; Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override;
Result handle_deferred() override; Result handle_deferred() override;
UserService *clone() override {
auto new_srv = new UserService();
new_srv->pid = pid;
new_srv->has_initialized = has_initialized;
new_srv->deferred_service = deferred_service;
return new_srv;
}
private: private:
/* Actual commands. */ /* Actual commands. */
std::tuple<Result> initialize(PidDescriptor pid); std::tuple<Result> initialize(PidDescriptor pid);