From 237ff0d1e7f226d5f51c3c17e306eaa844b10069 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 12 Jun 2018 16:00:09 -0600 Subject: [PATCH] libstratosphere/fs.mitm: Push WIP support for Domains. Not yet fully working. --- stratosphere/fs_mitm/source/fs_istorage.hpp | 9 + stratosphere/fs_mitm/source/fs_shim.c | 82 +++++ stratosphere/fs_mitm/source/fs_shim.h | 4 + stratosphere/fs_mitm/source/fsmitm_main.cpp | 12 +- .../fs_mitm/source/fsmitm_romstorage.hpp | 8 + .../fs_mitm/source/fsmitm_service.cpp | 63 +++- .../fs_mitm/source/fsmitm_service.hpp | 19 +- stratosphere/fs_mitm/source/fsmitm_utils.cpp | 13 + stratosphere/fs_mitm/source/fsmitm_worker.cpp | 23 +- stratosphere/fs_mitm/source/fsmitm_worker.hpp | 2 +- .../fs_mitm/source/imitmserviceobject.hpp | 4 +- stratosphere/fs_mitm/source/mitm_server.hpp | 109 +------ stratosphere/fs_mitm/source/mitm_service.cpp | 16 + stratosphere/fs_mitm/source/mitm_service.hpp | 27 ++ stratosphere/fs_mitm/source/mitm_session.hpp | 294 +++++++++++------- .../libstratosphere/include/stratosphere.hpp | 5 +- .../include/stratosphere/childholder.hpp | 76 ----- .../include/stratosphere/domainowner.hpp | 80 +++++ .../stratosphere/existingportserver.hpp | 6 +- .../include/stratosphere/ievent.hpp | 19 +- .../include/stratosphere/ipc_templating.hpp | 93 +++++- .../include/stratosphere/ipcsession.hpp | 193 +----------- .../include/stratosphere/iserver.hpp | 88 +----- .../include/stratosphere/iserviceobject.hpp | 18 +- .../include/stratosphere/isession.hpp | 288 +++++++++++++++++ .../include/stratosphere/iwaitable.hpp | 40 ++- .../stratosphere/managedportserver.hpp | 6 +- .../include/stratosphere/serviceserver.hpp | 6 +- .../include/stratosphere/servicesession.hpp | 195 +----------- .../include/stratosphere/waitablemanager.hpp | 12 +- .../stratosphere/waitablemanagerbase.hpp | 14 + .../source/waitablemanager.cpp | 66 ++-- .../loader/source/ldr_debug_monitor.cpp | 2 +- .../loader/source/ldr_debug_monitor.hpp | 2 +- stratosphere/loader/source/ldr_main.cpp | 4 +- stratosphere/loader/source/ldr_nso.cpp | 4 +- stratosphere/loader/source/ldr_nso.hpp | 2 +- .../loader/source/ldr_process_manager.cpp | 4 +- .../loader/source/ldr_process_manager.hpp | 2 +- stratosphere/loader/source/ldr_ro_service.cpp | 1 + stratosphere/loader/source/ldr_ro_service.hpp | 2 +- stratosphere/loader/source/ldr_shell.cpp | 1 + stratosphere/loader/source/ldr_shell.hpp | 2 +- stratosphere/sm/source/sm_manager_service.cpp | 1 + stratosphere/sm/source/sm_manager_service.hpp | 6 +- stratosphere/sm/source/sm_user_service.cpp | 2 +- stratosphere/sm/source/sm_user_service.hpp | 10 +- 47 files changed, 1053 insertions(+), 882 deletions(-) create mode 100644 stratosphere/fs_mitm/source/mitm_service.cpp create mode 100644 stratosphere/fs_mitm/source/mitm_service.hpp delete mode 100644 stratosphere/libstratosphere/include/stratosphere/childholder.hpp create mode 100644 stratosphere/libstratosphere/include/stratosphere/domainowner.hpp create mode 100644 stratosphere/libstratosphere/include/stratosphere/isession.hpp create mode 100644 stratosphere/libstratosphere/include/stratosphere/waitablemanagerbase.hpp diff --git a/stratosphere/fs_mitm/source/fs_istorage.hpp b/stratosphere/fs_mitm/source/fs_istorage.hpp index cb352ef97..124399e8a 100644 --- a/stratosphere/fs_mitm/source/fs_istorage.hpp +++ b/stratosphere/fs_mitm/source/fs_istorage.hpp @@ -3,6 +3,8 @@ #include #include "fs_shim.h" +#include "debug.hpp" + enum FsIStorageCmd { FsIStorage_Cmd_Read = 0, FsIStorage_Cmd_Write = 1, @@ -17,6 +19,9 @@ class IStorage { virtual ~IStorage() { } + + virtual IStorage *Clone() = 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 Flush() = 0; @@ -33,6 +38,10 @@ class IStorageInterface : public IServiceObject { /* ... */ }; + IStorageInterface *clone() override { + return new IStorageInterface(this->base_storage->Clone()); + } + ~IStorageInterface() { delete base_storage; }; diff --git a/stratosphere/fs_mitm/source/fs_shim.c b/stratosphere/fs_mitm/source/fs_shim.c index 179d3d73a..9af845521 100644 --- a/stratosphere/fs_mitm/source/fs_shim.c +++ b/stratosphere/fs_mitm/source/fs_shim.c @@ -1,6 +1,47 @@ #include #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. */ Result fsOpenDataStorageByDataId(Service* s, FsStorageId storage_id, u64 data_id, FsStorage* out) { IpcCommand c; @@ -41,6 +82,47 @@ Result fsOpenDataStorageByDataId(Service* s, FsStorageId storage_id, u64 data_id 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. */ Result fsFileOperateRange(FsFile* f, u32 op_id, u64 off, u64 len, FsRangeInfo *out) { IpcCommand c; diff --git a/stratosphere/fs_mitm/source/fs_shim.h b/stratosphere/fs_mitm/source/fs_shim.h index e50752b27..231807f38 100644 --- a/stratosphere/fs_mitm/source/fs_shim.h +++ b/stratosphere/fs_mitm/source/fs_shim.h @@ -16,8 +16,12 @@ typedef struct { u32 flags[0x40/sizeof(u32)]; } FsRangeInfo; +/* Necessary evils. */ +Result ipcCopyFromDomain(Handle session, u32 object_id, Service *out); + /* Missing fsp-srv commands. */ 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. */ Result fsFileOperateRange(FsFile* f, u32 op_id, u64 off, u64 len, FsRangeInfo *out); diff --git a/stratosphere/fs_mitm/source/fsmitm_main.cpp b/stratosphere/fs_mitm/source/fsmitm_main.cpp index 4f714f177..bb76ce7c6 100644 --- a/stratosphere/fs_mitm/source/fsmitm_main.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_main.cpp @@ -12,6 +12,8 @@ #include "fsmitm_service.hpp" #include "fsmitm_worker.hpp" +#include "mitm_service.hpp" + extern "C" { extern u32 __start__; @@ -62,6 +64,11 @@ void __appInit(void) { fatalSimple(0xCAFE << 4 | 3); } + rc = pminfoInitialize(); + if (R_FAILED(rc)) { + fatalSimple(0xCAFE << 4 | 4); + } + /* Check for exosphere API compatibility. */ u64 exosphere_cfg; if (R_SUCCEEDED(splGetConfig((SplConfigItem)65000, &exosphere_cfg))) { @@ -74,7 +81,7 @@ void __appInit(void) { fatalSimple(0xCAFE << 4 | 0xFF); } - splExit(); + //splExit(); } void __appExit(void) { @@ -100,7 +107,8 @@ int main(int argc, char **argv) WaitableManager *server_manager = new WaitableManager(U64_MAX); /* Create fsp-srv mitm. */ - server_manager->add_waitable(new MitMServer("fsp-srv", 61)); + //server_manager->add_waitable(new MitMServer("fsp-srv", 61)); + server_manager->add_waitable(new MitMServer("fsp-srv", 61)); /* Loop forever, servicing our services. */ server_manager->process(); diff --git a/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp b/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp index fab72816f..ffdee8c4e 100644 --- a/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp @@ -19,6 +19,10 @@ class RomFileStorage : public IROStorage { fsFileClose(base_file); delete base_file; }; + + RomFileStorage *Clone() override { + return new RomFileStorage(this->base_file); + }; protected: Result Read(void *buffer, size_t size, u64 offset, u64 *out_read_size) override { size_t out_sz = 0; @@ -52,6 +56,10 @@ class RomInterfaceStorage : public IROStorage { fsStorageClose(base_storage); delete base_storage; }; + + RomInterfaceStorage *Clone() override { + return new RomInterfaceStorage(this->base_storage); + }; protected: Result Read(void *buffer, size_t size, u64 offset, u64 *out_read_size) override { Result rc = fsStorageRead(this->base_storage, offset, buffer, size); diff --git a/stratosphere/fs_mitm/source/fsmitm_service.cpp b/stratosphere/fs_mitm/source/fsmitm_service.cpp index 26c1bcaa2..c7a5afbc4 100644 --- a/stratosphere/fs_mitm/source/fsmitm_service.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_service.cpp @@ -17,32 +17,51 @@ Result FsMitMService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_i this->process_id = r.Pid; } 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); - break; + break; */ } 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 { u64 magic; u64 result; } *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; switch (cmd_id) { case FspSrv_Cmd_SetCurrentProcess: if (R_SUCCEEDED(rc)) { this->has_initialized = true; - if (R_FAILED(pminfoInitialize()) || R_FAILED(pminfoGetTitleId(&this->title_id, this->process_id))) { - fatalSimple(0xCAFE << 8 | 0xFD); + rc = pminfoGetTitleId(&this->title_id, this->process_id); + 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; } - return rc; + resp->result = rc; } Result FsMitMService::handle_deferred() { @@ -51,25 +70,37 @@ Result FsMitMService::handle_deferred() { } /* Add redirection for System Data Archives to the SD card. */ -std::tuple FsMitMService::open_data_storage_by_data_id(FsStorageId storage_id, u64 data_id) { - Handle out_h = 0; +std::tuple> FsMitMService::open_data_storage_by_data_id(u64 sid, u64 data_id) { + FsStorageId storage_id = (FsStorageId)sid; + IPCSession *out_session = NULL; FsStorage data_storage; 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)) { - IPCSession *out_session = NULL; char path[FS_MAX_PATH] = {0}; /* TODO: Is there a sensible path that ends in ".romfs" we can use?" */ snprintf(path, sizeof(path), "/atmosphere/titles/%016lx/romfs.bin", data_id); if (R_SUCCEEDED(Utils::OpenSdFile(path, FS_OPEN_READ, &data_file))) { fsStorageClose(&data_storage); out_session = new IPCSession(new IStorageInterface(new RomFileStorage(data_file))); - } else { - + } else { out_session = new IPCSession(new IStorageInterface(new RomInterfaceStorage(data_storage))); } - FsMitmWorker::AddWaitable(out_session); - out_h = out_session->get_client_handle(); + if (this->get_owner() == NULL) { + 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}; } \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/fsmitm_service.hpp b/stratosphere/fs_mitm/source/fsmitm_service.hpp index 16a02c5fc..525a04301 100644 --- a/stratosphere/fs_mitm/source/fsmitm_service.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_service.hpp @@ -2,6 +2,7 @@ #include #include #include "imitmserviceobject.hpp" +#include "fs_istorage.hpp" enum FspSrvCmd { 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 *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 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(); protected: /* Overridden commands. */ - std::tuple open_data_storage_by_data_id(FsStorageId storage_id, u64 data_id); + std::tuple> open_data_storage_by_data_id(u64 storage_id, u64 data_id); }; \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/fsmitm_utils.cpp b/stratosphere/fs_mitm/source/fsmitm_utils.cpp index d87ee2599..c061a0d77 100644 --- a/stratosphere/fs_mitm/source/fsmitm_utils.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_utils.cpp @@ -2,6 +2,8 @@ #include #include +#include "sm_mitm.h" + #include "fsmitm_utils.hpp" static FsFileSystem g_sd_filesystem; @@ -11,6 +13,17 @@ static Result EnsureInitialized() { if (g_has_initialized) { 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); if (R_SUCCEEDED(rc)) { g_has_initialized = true; diff --git a/stratosphere/fs_mitm/source/fsmitm_worker.cpp b/stratosphere/fs_mitm/source/fsmitm_worker.cpp index 0dd4cdb2a..c2cf4d834 100644 --- a/stratosphere/fs_mitm/source/fsmitm_worker.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_worker.cpp @@ -3,35 +3,36 @@ #include "fsmitm_worker.hpp" static SystemEvent *g_new_waitable_event = NULL; -static ChildWaitableHolder *g_child_holder = NULL; 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]); - g_child_holder->add_child(g_new_waitable); + g_sema_new_waitable_finish.Signal(); return 0; } void FsMitmWorker::AddWaitable(IWaitable *waitable) { + g_worker_waiter->add_waitable(waitable); g_new_waitable_mutex.Lock(); - g_new_waitable = waitable; g_new_waitable_event->signal_event(); + g_sema_new_waitable_finish.Wait(); g_new_waitable_mutex.Unlock(); } void FsMitmWorker::Main(void *arg) { /* Initialize waitable event. */ - g_new_waitable_event = new SystemEvent(&FsMitmWorker::AddWaitableInternal); - g_child_holder = new ChildWaitableHolder(); + g_new_waitable_event = new SystemEvent(&FsMitmWorker::AddWaitableCallback); /* Make a new waitable manager. */ - WaitableManager *worker_waiter = new WaitableManager(U64_MAX); - worker_waiter->add_waitable(g_new_waitable_event); + g_worker_waiter = new WaitableManager(U64_MAX); + g_worker_waiter->add_waitable(g_new_waitable_event); /* Service processes. */ - worker_waiter->process(); + g_worker_waiter->process(); - delete worker_waiter; + delete g_worker_waiter; } diff --git a/stratosphere/fs_mitm/source/fsmitm_worker.hpp b/stratosphere/fs_mitm/source/fsmitm_worker.hpp index 4f7a48d6f..4a78e81e3 100644 --- a/stratosphere/fs_mitm/source/fsmitm_worker.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_worker.hpp @@ -4,7 +4,7 @@ class FsMitmWorker { private: - static Result AddWaitableInternal(Handle *handles, size_t num_handles, u64 timeout); + static Result AddWaitableCallback(Handle *handles, size_t num_handles, u64 timeout); public: static void Main(void *arg); static void AddWaitable(IWaitable *waitable); diff --git a/stratosphere/fs_mitm/source/imitmserviceobject.hpp b/stratosphere/fs_mitm/source/imitmserviceobject.hpp index 56c2b51c4..460853990 100644 --- a/stratosphere/fs_mitm/source/imitmserviceobject.hpp +++ b/stratosphere/fs_mitm/source/imitmserviceobject.hpp @@ -10,9 +10,11 @@ class IMitMServiceObject : public IServiceObject { IMitMServiceObject(Service *s) : forward_service(s) { } + + virtual void clone_to(void *o) = 0; protected: virtual ~IMitMServiceObject() { } 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; }; diff --git a/stratosphere/fs_mitm/source/mitm_server.hpp b/stratosphere/fs_mitm/source/mitm_server.hpp index 94cc55220..0945988d9 100644 --- a/stratosphere/fs_mitm/source/mitm_server.hpp +++ b/stratosphere/fs_mitm/source/mitm_server.hpp @@ -11,116 +11,39 @@ template class MitMSession; template -class MitMServer final : public IWaitable { +class MitMServer final : public IServer { static_assert(std::is_base_of::value, "Service Objects must derive from IServiceObject"); - protected: - Handle port_handle; - unsigned int max_sessions; - unsigned int num_sessions; - MitMSession **sessions; + private: char mitm_name[9]; public: - MitMServer(const char *service_name, unsigned int max_s) : max_sessions(max_s) { - this->sessions = new MitMSession *[this->max_sessions]; - for (unsigned int i = 0; i < this->max_sessions; i++) { - this->sessions[i] = NULL; + MitMServer(const char *service_name, unsigned int max_s, bool s_d = false) : IServer(service_name, max_s, s_d) { + Handle tmp_hnd; + Result rc; + + 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); mitm_name[8] = '\x00'; - Result rc; if (R_FAILED((rc = smMitMInstall(&this->port_handle, mitm_name)))) { - /* TODO: Panic. */ + fatalSimple(rc); } } virtual ~MitMServer() { - 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 (R_FAILED(smMitMUninstall(mitm_name))) { + if (this->port_handle) { + if (R_FAILED(smMitMUninstall(this->mitm_name))) { /* TODO: Panic. */ } - svcCloseHandle(port_handle); - } - } - - /* 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(); - } + /* svcCloseHandle(port_handle); was called by ~IServer. */ } } - 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() { - 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(this, session_h, 0, mitm_name); - this->sessions[i]->set_parent(this); - this->num_sessions++; - return 0; + ISession *get_new_session(Handle session_h) override { + return new MitMSession(this, session_h, 0, mitm_name); } }; diff --git a/stratosphere/fs_mitm/source/mitm_service.cpp b/stratosphere/fs_mitm/source/mitm_service.cpp new file mode 100644 index 000000000..3985ab233 --- /dev/null +++ b/stratosphere/fs_mitm/source/mitm_service.cpp @@ -0,0 +1,16 @@ +#include +#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; +} \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/mitm_service.hpp b/stratosphere/fs_mitm/source/mitm_service.hpp new file mode 100644 index 000000000..73c06ac9b --- /dev/null +++ b/stratosphere/fs_mitm/source/mitm_service.hpp @@ -0,0 +1,27 @@ +#pragma once +#include +#include +#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(); +}; \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/mitm_session.hpp b/stratosphere/fs_mitm/source/mitm_session.hpp index 0f2b36f09..8865c54a4 100644 --- a/stratosphere/fs_mitm/source/mitm_session.hpp +++ b/stratosphere/fs_mitm/source/mitm_session.hpp @@ -12,154 +12,208 @@ template class MitMServer; template -class MitMSession final : public IWaitable { +class MitMSession final : public ISession { static_assert(std::is_base_of::value, "MitM Service Objects must derive from IMitMServiceObject"); - T *service_object; - MitMServer *server; - Handle server_handle; - Handle client_handle; /* This will be for the actual session. */ Service forward_service; - - char *pointer_buffer; - size_t pointer_buffer_size; - - static_assert(sizeof(pointer_buffer) <= POINTER_BUFFER_SIZE_MAX, "Incorrect Size for PointerBuffer!"); + IpcParsedCommand cur_out_r; + u32 mitm_domain_id; + public: - MitMSession(MitMServer *s, Handle s_h, Handle c_h, const char *srv) : server(s), server_handle(s_h), client_handle(c_h) { + MitMSession(MitMServer *s, Handle s_h, Handle c_h, const char *srv) : ISession(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))) { /* 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. */ } 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(MitMServer *s, Handle s_h, Handle c_h, Handle f_h, size_t pbs) : ISession(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 { - delete this->service_object; - delete this->pointer_buffer; + virtual ~MitMSession() { 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 { - 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 { - /* 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); + Result handle_message(IpcParsedCommand &r) override { + IpcCommand c; + ipcInitialize(&c); + u64 cmd_id = ((u32 *)r.Raw)[2]; + Result retval = 0xF601; + + cur_out_r.NumHandles = 0; + + Log(armGetTls(), 0x100); + u32 *cmdbuf = (u32 *)armGetTls(); - ipcPrepareHeader(&c_for_reply, 0); - - - if (R_SUCCEEDED(rc = svcReplyAndReceive(&handle_index, &this->server_handle, 1, 0, timeout))) { - if (handle_index != 0) { - /* TODO: Panic? */ - } - Log(armGetTls(), 0x100); - Result retval = 0; - u32 *rawdata_start = cmdbuf; - - 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); + if (r.CommandType == IpcCommandType_Request || r.CommandType == IpcCommandType_RequestWithContext) { + IServiceObject *obj; + if (r.IsDomainMessage) { + obj = this->get_domain_object(r.ThisObjectId); + if (obj && r.MessageType == DomainMessageType_Close) { + this->delete_object(r.ThisObjectId); + struct { + u64 magic; + u64 result; + } *o_resp; + 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 *new_sess = new MitMSession((MitMServer *)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 { u64 magic; 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) { - /* Session close. */ - rc = retval; - } else { - if (R_SUCCEEDED(rc)) { - ipcInitialize(&c); - retval = this->service_object->postprocess(r, c, cmd_id, (u8 *)this->pointer_buffer, this->pointer_buffer_size); - } - 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]); - } + Log(armGetTls(), 0x100); + retval = serviceIpcDispatch(&forward_service); + if (R_SUCCEEDED(retval)) { + if (r.IsDomainMessage) { + ipcParseForDomain(&cur_out_r); + } else { + ipcParse(&cur_out_r); } + + 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; } }; \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere.hpp b/stratosphere/libstratosphere/include/stratosphere.hpp index 000a8b741..7d861a8ae 100644 --- a/stratosphere/libstratosphere/include/stratosphere.hpp +++ b/stratosphere/libstratosphere/include/stratosphere.hpp @@ -1,5 +1,7 @@ #pragma once +#include "stratosphere/ipc_templating.hpp" + #include "stratosphere/iwaitable.hpp" #include "stratosphere/iserviceobject.hpp" #include "stratosphere/iserver.hpp" @@ -8,12 +10,9 @@ #include "stratosphere/serviceserver.hpp" #include "stratosphere/managedportserver.hpp" #include "stratosphere/existingportserver.hpp" -#include "stratosphere/childholder.hpp" #include "stratosphere/ievent.hpp" #include "stratosphere/systemevent.hpp" #include "stratosphere/hossynch.hpp" #include "stratosphere/waitablemanager.hpp" - -#include "stratosphere/ipc_templating.hpp" \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/childholder.hpp b/stratosphere/libstratosphere/include/stratosphere/childholder.hpp deleted file mode 100644 index 428ccef69..000000000 --- a/stratosphere/libstratosphere/include/stratosphere/childholder.hpp +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once -#include -#include - -#include "iwaitable.hpp" - -class ChildWaitableHolder : public IWaitable { - protected: - std::vector 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; - } -}; \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/domainowner.hpp b/stratosphere/libstratosphere/include/stratosphere/domainowner.hpp new file mode 100644 index 000000000..bf7b560fb --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/domainowner.hpp @@ -0,0 +1,80 @@ +#pragma once +#include +#include + +#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; + } + } + } +}; \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/existingportserver.hpp b/stratosphere/libstratosphere/include/stratosphere/existingportserver.hpp index 4ec15b004..d026fb676 100644 --- a/stratosphere/libstratosphere/include/stratosphere/existingportserver.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/existingportserver.hpp @@ -5,7 +5,11 @@ template class ExistingPortServer : public IServer { public: - ExistingPortServer(Handle port_h, unsigned int max_s) : IServer(NULL, max_s) { + ExistingPortServer(Handle port_h, unsigned int max_s, bool s_d = false) : IServer(NULL, max_s, s_d) { this->port_handle = port_h; } + + ISession *get_new_session(Handle session_h) override { + return new ServiceSession(this, session_h, 0); + } }; \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/ievent.hpp b/stratosphere/libstratosphere/include/stratosphere/ievent.hpp index c30f11bb0..ae41a9125 100644 --- a/stratosphere/libstratosphere/include/stratosphere/ievent.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/ievent.hpp @@ -27,24 +27,7 @@ class IEvent : public IWaitable { virtual Result signal_event() = 0; - /* 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. */ - } - + /* IWaitable */ virtual Handle get_handle() { if (handles.size() > 0) { return this->handles[0]; diff --git a/stratosphere/libstratosphere/include/stratosphere/ipc_templating.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc_templating.hpp index e3cca2873..2ea9187ed 100644 --- a/stratosphere/libstratosphere/include/stratosphere/ipc_templating.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/ipc_templating.hpp @@ -6,6 +6,8 @@ #include "../boost/callable_traits.hpp" #include +#include "domainowner.hpp" + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-but-set-variable" @@ -88,6 +90,21 @@ struct CopiedHandle { CopiedHandle(Handle h) : handle(h) { } }; +/* Forward declarations. */ +template +class ISession; + +/* Represents an output ServiceObject. */ +struct OutSessionBase {}; + +template +struct OutSession : OutSessionBase { + ISession *session; + u32 domain_id; + + OutSession(ISession *s) : session(s), domain_id(DOMAIN_ID_MAX) { } +}; + /* Utilities. */ template class Template> struct is_specialization_of { @@ -117,9 +134,14 @@ struct is_ipc_handle { static const size_t value = (std::is_same::value || std::is_same::value) ? 1 : 0; }; +template +struct is_out_session { + static const bool value = std::is_base_of::value; +}; + template struct size_in_raw_data { - static const size_t value = (is_ipc_buffer::value || is_ipc_handle::value) ? 0 : ((sizeof(T) < sizeof(u32)) ? sizeof(u32) : (sizeof(T) + 3) & (~3)); + static const size_t value = (is_ipc_buffer::value || is_ipc_handle::value || is_out_session::value) ? 0 : ((sizeof(T) < sizeof(u32)) ? sizeof(u32) : (sizeof(T) + 3) & (~3)); }; template @@ -127,6 +149,11 @@ struct size_in_raw_data_for_arguments { static const size_t value = (size_in_raw_data::value + ... + 0); }; +template +struct num_out_sessions_in_arguments { + static const size_t value = ((is_out_session::value ? 1 : 0) + ... + 0); +}; + template struct size_in_raw_data_with_out_pointers { static const size_t value = is_specialization_of::value ? 2 : size_in_raw_data::value; @@ -293,6 +320,10 @@ struct Validator> { return 0xF601; } + if (((u32 *)r.Raw)[0] != SFCI_MAGIC) { + //return 0xF601; + } + size_t a_index = 0, b_index = num_inbuffers_in_arguments::value, x_index = 0, c_index = 0, h_index = 0; size_t cur_rawdata_index = 4; size_t cur_c_size_offset = 0x10 + size_in_raw_data_for_arguments::value + (0x10 - ((uintptr_t)r.Raw - (uintptr_t)r.RawWithoutPadding)); @@ -334,33 +365,55 @@ template struct Encoder; template -constexpr size_t GetAndUpdateOffsetIntoRawData(size_t& offset) { +constexpr size_t GetAndUpdateOffsetIntoRawData(DomainOwner *domain_owner, size_t& offset) { auto old = offset; if (old == 0) { offset += sizeof(u64); } else { - offset += size_in_raw_data::value; + if constexpr (is_out_session::value) { + if (domain_owner) { + offset += sizeof(u32); + } + } else { + offset += size_in_raw_data::value; + } } return old; } template -void EncodeValueIntoIpcMessageBeforePrepare(IpcCommand *c, T value) { +void EncodeValueIntoIpcMessageBeforePrepare(DomainOwner *domain_owner, IpcCommand *c, T &value) { if constexpr (std::is_same::value) { ipcSendHandleMove(c, value.handle); } else if constexpr (std::is_same::value) { ipcSendHandleCopy(c, value.handle); } else if constexpr (std::is_same::value) { ipcSendPid(c); + } else if constexpr (is_out_session::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 -void EncodeValueIntoIpcMessageAfterPrepare(u8 *cur_out, T value) { +void EncodeValueIntoIpcMessageAfterPrepare(DomainOwner *domain_owner, u8 *cur_out, T value) { if constexpr (is_ipc_handle::value || std::is_same::value) { /* Do nothing. */ + } else if constexpr (is_out_session::value) { + if (domain_owner) { + *((u32 *)cur_out) = value.domain_id; + } } else { *((T *)(cur_out)) = value; } @@ -370,7 +423,7 @@ template struct Encoder> { IpcCommand &out_command; - auto operator()(Args... args) { + auto operator()(DomainOwner *domain_owner, Args... args) { static_assert(sizeof...(Args) > 0, "IpcCommandImpls must return std::tuple"); size_t offset = 0; @@ -378,19 +431,26 @@ struct Encoder> { std::fill(tls, tls + 0x100, 0x00); - ((EncodeValueIntoIpcMessageBeforePrepare(&out_command, args)), ...); + ((EncodeValueIntoIpcMessageBeforePrepare(domain_owner, &out_command, args)), ...); /* Remove the extra space resulting from first Result type. */ struct { u64 magic; u64 result; - } *raw = (decltype(raw))ipcPrepareHeader(&out_command, sizeof(*raw) + size_in_raw_data_for_arguments::value - sizeof(Result)); + } *raw; + if (domain_owner == NULL) { + raw = (decltype(raw))ipcPrepareHeader(&out_command, sizeof(*raw) + size_in_raw_data_for_arguments::value - sizeof(Result)); + } else { + raw = (decltype(raw))ipcPrepareHeaderForDomain(&out_command, sizeof(*raw) + size_in_raw_data_for_arguments::value + (num_out_sessions_in_arguments::value * sizeof(u32)) - sizeof(Result), 0); + *((DomainMessageHeader *)((uintptr_t)raw - sizeof(DomainMessageHeader))) = {0}; + } + raw->magic = SFCO_MAGIC; u8 *raw_data = (u8 *)&raw->result; - ((EncodeValueIntoIpcMessageAfterPrepare(raw_data + GetAndUpdateOffsetIntoRawData(offset), args)), ...); + ((EncodeValueIntoIpcMessageAfterPrepare(domain_owner, raw_data + GetAndUpdateOffsetIntoRawData(domain_owner, offset), args)), ...); Result rc = raw->result; @@ -424,7 +484,9 @@ Result WrapDeferredIpcCommandImpl(Class *this_ptr, Args... args) { auto tuple_args = std::make_tuple(args...); auto result = std::apply( [=](auto&&... a) { return (this_ptr->*IpcCommandImpl)(a...); }, tuple_args); - return std::apply(Encoder{out_command}, result); + DomainOwner *down = NULL; + + return std::apply(Encoder{out_command}, std::tuple_cat(std::make_tuple(down), result)); } template @@ -446,8 +508,12 @@ Result WrapIpcCommandImpl(Class *this_ptr, IpcParsedCommand& r, IpcCommand &out_ auto args = Decoder::Decode(r, out_command, pointer_buffer); 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{out_command}, result); + return std::apply(Encoder{out_command}, std::tuple_cat(std::make_tuple(down), result)); } template @@ -468,8 +534,11 @@ Result WrapStaticIpcCommandImpl(IpcParsedCommand& r, IpcCommand &out_command, u8 auto args = Decoder::Decode(r, out_command, pointer_buffer); auto result = std::apply(IpcCommandImpl, args); + DomainOwner *down = NULL; - return std::apply(Encoder{out_command}, result); + return std::apply(Encoder{out_command}, std::tuple_cat(std::make_tuple(down), result)); } #pragma GCC diagnostic pop + +#include "isession.hpp" diff --git a/stratosphere/libstratosphere/include/stratosphere/ipcsession.hpp b/stratosphere/libstratosphere/include/stratosphere/ipcsession.hpp index ef95238ce..5cabd6a1c 100644 --- a/stratosphere/libstratosphere/include/stratosphere/ipcsession.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/ipcsession.hpp @@ -5,200 +5,31 @@ #include "ipc_templating.hpp" #include "iserviceobject.hpp" #include "iwaitable.hpp" -#include "servicesession.hpp" +#include "isession.hpp" template -class IPCSession final : public IWaitable { +class IPCSession final : public ISession { static_assert(std::is_base_of::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: - IPCSession(size_t pbs = 0x400) : pointer_buffer_size(pbs) { + IPCSession(size_t pbs = 0x400) : ISession(NULL, 0, 0, 0) { 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); } 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 *so, size_t pbs = 0x400) : service_object(so), pointer_buffer_size(pbs) { + IPCSession(T *so, size_t pbs = 0x400) : ISession(NULL, 0, 0, so, 0) { 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); } - this->pointer_buffer = new char[pointer_buffer_size]; - } - - ~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 ConvertCurrentObjectToDomain() { - /* TODO */ - return {0xF601}; - } - std::tuple CopyFromCurrentDomain() { - /* TODO */ - return {0xF601}; - } - std::tuple CloneCurrentObject() { - /* TODO */ - return {0xF601}; - } - std::tuple QueryPointerBufferSize() { - return {0x0, (u32)this->pointer_buffer_size}; - } - std::tuple 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; + this->pointer_buffer_size = pbs; + this->pointer_buffer = new char[this->pointer_buffer_size]; + this->is_domain = false; } }; diff --git a/stratosphere/libstratosphere/include/stratosphere/iserver.hpp b/stratosphere/libstratosphere/include/stratosphere/iserver.hpp index 66cb1e7aa..24ff1ee67 100644 --- a/stratosphere/libstratosphere/include/stratosphere/iserver.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/iserver.hpp @@ -4,10 +4,10 @@ #include "iserviceobject.hpp" #include "iwaitable.hpp" -#include "servicesession.hpp" +#include "isession.hpp" template -class ServiceSession; +class ISession; template class IServer : public IWaitable { @@ -15,71 +15,22 @@ class IServer : public IWaitable { protected: Handle port_handle; unsigned int max_sessions; - unsigned int num_sessions; - ServiceSession **sessions; + bool supports_domains; public: - IServer(const char *service_name, unsigned int max_s) : max_sessions(max_s) { - this->sessions = new ServiceSession *[this->max_sessions]; - for (unsigned int i = 0; i < this->max_sessions; i++) { - this->sessions[i] = NULL; - } - this->num_sessions = 0; + IServer(const char *service_name, unsigned int max_s, bool s_d = false) : max_sessions(max_s), supports_domains(s_d) { + } - virtual ~IServer() { - for (unsigned int i = 0; i < this->max_sessions; i++) { - if (this->sessions[i]) { - delete this->sessions[i]; - } - - delete this->sessions; - } - + virtual ~IServer() { if (port_handle) { svcCloseHandle(port_handle); } } + + virtual ISession *get_new_session(Handle session_h) = 0; - /* 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--; - } - } - + /* IWaitable */ virtual Handle get_handle() { return this->port_handle; } @@ -92,23 +43,12 @@ class IServer : public IWaitable { 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); + Result rc = svcAcceptSession(&session_h, this->port_handle); + if (R_FAILED(rc)) { + return rc; + } - 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 ServiceSession(this, session_h, 0); - this->sessions[i]->set_parent(this); - this->num_sessions++; + this->get_manager()->add_waitable(this->get_new_session(session_h)); return 0; } }; \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/iserviceobject.hpp b/stratosphere/libstratosphere/include/stratosphere/iserviceobject.hpp index 9b569722d..965fc59c0 100644 --- a/stratosphere/libstratosphere/include/stratosphere/iserviceobject.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/iserviceobject.hpp @@ -1,11 +1,25 @@ #pragma once #include -#include "ipc_templating.hpp" +template +class ISession; + +class DomainOwner; class IServiceObject { - protected: + private: + DomainOwner *owner = NULL; + public: 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; + protected: virtual Result handle_deferred() = 0; }; + +#include "domainowner.hpp" diff --git a/stratosphere/libstratosphere/include/stratosphere/isession.hpp b/stratosphere/libstratosphere/include/stratosphere/isession.hpp new file mode 100644 index 000000000..de33692eb --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/isession.hpp @@ -0,0 +1,288 @@ +#pragma once +#include +#include + +#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 +class IServer; + +class IServiceObject; + +template +class ISession : public IWaitable, public DomainOwner { + static_assert(std::is_base_of::value, "Service Objects must derive from IServiceObject"); + protected: + T *service_object; + IServer *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(IServer *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(IServer *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 ConvertCurrentObjectToDomain() { + /* TODO */ + return {0xF601}; + } + std::tuple CopyFromCurrentDomain() { + /* TODO */ + return {0xF601}; + } + std::tuple CloneCurrentObject() { + /* TODO */ + return {0xF601}; + } + std::tuple QueryPointerBufferSize() { + return {0x0, (u32)this->pointer_buffer_size}; + } + std::tuple CloneCurrentObjectEx() { + /* TODO */ + return {0xF601}; + } +}; diff --git a/stratosphere/libstratosphere/include/stratosphere/iwaitable.hpp b/stratosphere/libstratosphere/include/stratosphere/iwaitable.hpp index ded313965..4a81f3c40 100644 --- a/stratosphere/libstratosphere/include/stratosphere/iwaitable.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/iwaitable.hpp @@ -2,38 +2,34 @@ #include +#include "waitablemanagerbase.hpp" + +class WaitableManager; + class IWaitable { - u64 wait_priority = 0; - bool is_deferred = false; - IWaitable *parent_waitable; + private: + u64 wait_priority = 0; + bool is_deferred = false; + WaitableManagerBase *manager; public: 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 Handle get_handle() = 0; virtual Result handle_signaled(u64 timeout) = 0; - - bool has_parent() { - return this->parent_waitable != NULL; + + WaitableManager *get_manager() { + return (WaitableManager *)this->manager; } - void set_parent(IWaitable *p) { - if (has_parent()) { - /* TODO: Panic? */ - } - this->parent_waitable = p; - } - - IWaitable *get_parent() { - return this->parent_waitable; + void set_manager(WaitableManagerBase *m) { + this->manager = m; } void update_priority() { - static u64 g_cur_priority = 0; - this->wait_priority = g_cur_priority++; + if (manager) { + this->wait_priority = this->manager->get_priority(); + } } bool get_deferred() { @@ -47,4 +43,6 @@ class IWaitable { static bool compare(IWaitable *a, IWaitable *b) { return (a->wait_priority < b->wait_priority) && !a->is_deferred; } -}; \ No newline at end of file +}; + +#include "waitablemanager.hpp" \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/managedportserver.hpp b/stratosphere/libstratosphere/include/stratosphere/managedportserver.hpp index af86db42b..83ed7df5c 100644 --- a/stratosphere/libstratosphere/include/stratosphere/managedportserver.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/managedportserver.hpp @@ -5,9 +5,13 @@ template class ManagedPortServer : public IServer { public: - ManagedPortServer(const char *service_name, unsigned int max_s) : IServer(service_name, max_s) { + ManagedPortServer(const char *service_name, unsigned int max_s, bool s_d = false) : IServer(service_name, max_s, s_d) { if (R_FAILED(svcManageNamedPort(&this->port_handle, service_name, this->max_sessions))) { /* TODO: panic */ } } + + ISession *get_new_session(Handle session_h) override { + return new ServiceSession(this, session_h, 0); + } }; \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/serviceserver.hpp b/stratosphere/libstratosphere/include/stratosphere/serviceserver.hpp index 289518225..e73388670 100644 --- a/stratosphere/libstratosphere/include/stratosphere/serviceserver.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/serviceserver.hpp @@ -5,9 +5,13 @@ template class ServiceServer : public IServer { public: - ServiceServer(const char *service_name, unsigned int max_s) : IServer(service_name, max_s) { + ServiceServer(const char *service_name, unsigned int max_s, bool s_d = false) : IServer(service_name, max_s, s_d) { if (R_FAILED(smRegisterService(&this->port_handle, service_name, false, this->max_sessions))) { /* TODO: Panic. */ } } + + ISession *get_new_session(Handle session_h) override { + return new ServiceSession(this, session_h, 0); + } }; \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/servicesession.hpp b/stratosphere/libstratosphere/include/stratosphere/servicesession.hpp index 1b397701e..da64e8d6b 100644 --- a/stratosphere/libstratosphere/include/stratosphere/servicesession.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/servicesession.hpp @@ -6,200 +6,15 @@ #include "iserviceobject.hpp" #include "iwaitable.hpp" #include "iserver.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) - +#include "isession.hpp" template -class IServer; - -template -class ServiceSession final : public IWaitable { +class ServiceSession final : public ISession { static_assert(std::is_base_of::value, "Service Objects must derive from IServiceObject"); - - T *service_object; - IServer *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: - ServiceSession(IServer *s, Handle s_h, Handle c_h) : server(s), server_handle(s_h), client_handle(c_h) { - this->service_object = new T(); + ServiceSession(IServer *s, Handle s_h, Handle c_h, size_t pbs = 0x400) : ISession(s, s_h, c_h, pbs) { + /* ... */ } - ~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 ConvertCurrentObjectToDomain() { - /* TODO */ - return {0xF601}; - } - std::tuple CopyFromCurrentDomain() { - /* TODO */ - return {0xF601}; - } - std::tuple CloneCurrentObject() { - /* TODO */ - return {0xF601}; - } - std::tuple QueryPointerBufferSize() { - return {0x0, (u32)sizeof(this->pointer_buffer)}; - } - std::tuple 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; - } }; diff --git a/stratosphere/libstratosphere/include/stratosphere/waitablemanager.hpp b/stratosphere/libstratosphere/include/stratosphere/waitablemanager.hpp index 407c7c248..ebefa548a 100644 --- a/stratosphere/libstratosphere/include/stratosphere/waitablemanager.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/waitablemanager.hpp @@ -2,15 +2,22 @@ #include #include +#include "waitablemanagerbase.hpp" #include "iwaitable.hpp" +#include "hossynch.hpp" -class WaitableManager { +class IWaitable; + +class WaitableManager : public WaitableManagerBase { + std::vector to_add_waitables; std::vector waitables; u64 timeout; + HosMutex lock; + std::atomic_bool has_new_items; private: void process_internal(bool break_on_timeout); public: - WaitableManager(u64 t) : waitables(0), timeout(t) { } + WaitableManager(u64 t) : waitables(0), timeout(t), has_new_items(false) { } ~WaitableManager() { /* This should call the destructor for every waitable. */ for (auto & waitable : waitables) { @@ -19,7 +26,6 @@ class WaitableManager { waitables.clear(); } - unsigned int get_num_signalable(); void add_waitable(IWaitable *waitable); void process(); void process_until_timeout(); diff --git a/stratosphere/libstratosphere/include/stratosphere/waitablemanagerbase.hpp b/stratosphere/libstratosphere/include/stratosphere/waitablemanagerbase.hpp new file mode 100644 index 000000000..f294b8fd9 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/waitablemanagerbase.hpp @@ -0,0 +1,14 @@ +#pragma once +#include +#include +#include + +class WaitableManagerBase { + std::atomic cur_priority; + public: + WaitableManagerBase() : cur_priority(0) { } + + u64 get_priority() { + return std::atomic_fetch_add(&cur_priority, (u64)1); + } +}; \ No newline at end of file diff --git a/stratosphere/libstratosphere/source/waitablemanager.cpp b/stratosphere/libstratosphere/source/waitablemanager.cpp index eb2727307..fee21cb4b 100644 --- a/stratosphere/libstratosphere/source/waitablemanager.cpp +++ b/stratosphere/libstratosphere/source/waitablemanager.cpp @@ -4,56 +4,51 @@ #include - -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) { - 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) { - std::vector signalables; std::vector handles; int handle_index = 0; Result rc; while (1) { - /* Create vector of signalable items. */ - signalables.resize(this->get_num_signalable(), NULL); - unsigned int n = 0; - for (auto & waitable : this->waitables) { - waitable->get_waitables(signalables.data() + n); - n += waitable->get_num_waitables(); + /* Add new items, if relevant. */ + if (this->has_new_items) { + this->lock.Lock(); + this->waitables.insert(this->waitables.end(), this->to_add_waitables.begin(), this->to_add_waitables.end()); + this->to_add_waitables.clear(); + this->has_new_items = false; + this->lock.Unlock(); } - - /* Sort signalables by priority. */ - std::sort(signalables.begin(), signalables.end(), IWaitable::compare); + + /* Sort waitables by priority. */ + std::sort(this->waitables.begin(), this->waitables.end(), IWaitable::compare); /* Copy out handles. */ - handles.resize(signalables.size()); - std::transform(signalables.begin(), signalables.end(), handles.begin(), [](IWaitable *w) { return w->get_handle(); }); + handles.resize(this->waitables.size()); + 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)) { /* Handle a signaled waitable. */ /* 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++) { - signalables[i]->update_priority(); + this->waitables[i]->update_priority(); } } else if (rc == 0xEA01) { /* Timeout. */ - for (auto & waitable : signalables) { + for (auto & waitable : this->waitables) { waitable->update_priority(); } if (break_on_timeout) { @@ -69,26 +64,21 @@ void WaitableManager::process_internal(bool break_on_timeout) { /* Close the handle. */ svcCloseHandle(handles[handle_index]); + IWaitable *to_delete = this->waitables[handle_index]; + /* 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. */ - if (signalables[handle_index]->has_parent()) { - 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()); - + delete to_delete; + for (int i = 0; i < handle_index; i++) { - signalables[i]->update_priority(); + this->waitables[i]->update_priority(); } } /* Do deferred callback for each waitable. */ - for (auto & waitable : signalables) { + for (auto & waitable : this->waitables) { if (waitable->get_deferred()) { waitable->handle_deferred(); } diff --git a/stratosphere/loader/source/ldr_debug_monitor.cpp b/stratosphere/loader/source/ldr_debug_monitor.cpp index 26088a173..722e19118 100644 --- a/stratosphere/loader/source/ldr_debug_monitor.cpp +++ b/stratosphere/loader/source/ldr_debug_monitor.cpp @@ -1,7 +1,7 @@ #include #include #include - +#include #include "ldr_debug_monitor.hpp" #include "ldr_launch_queue.hpp" #include "ldr_registration.hpp" diff --git a/stratosphere/loader/source/ldr_debug_monitor.hpp b/stratosphere/loader/source/ldr_debug_monitor.hpp index 5ca07936e..3d6a23f6f 100644 --- a/stratosphere/loader/source/ldr_debug_monitor.hpp +++ b/stratosphere/loader/source/ldr_debug_monitor.hpp @@ -10,7 +10,7 @@ enum DebugMonitorServiceCmd { Dmnt_Cmd_GetNsoInfo = 2 }; -class DebugMonitorService final : 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 { diff --git a/stratosphere/loader/source/ldr_main.cpp b/stratosphere/loader/source/ldr_main.cpp index dc0c2f30e..e1633cb66 100644 --- a/stratosphere/loader/source/ldr_main.cpp +++ b/stratosphere/loader/source/ldr_main.cpp @@ -72,11 +72,11 @@ void __appInit(void) { /* Check for exosphere API compatibility. */ u64 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. */ } - splExit(); + //splExit(); } void __appExit(void) { diff --git a/stratosphere/loader/source/ldr_nso.cpp b/stratosphere/loader/source/ldr_nso.cpp index a533e2bcc..cf58656b9 100644 --- a/stratosphere/loader/source/ldr_nso.cpp +++ b/stratosphere/loader/source/ldr_nso.cpp @@ -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 check_hash = ((g_nso_headers[index].flags >> (segment + 3)) & 1) != 0; 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; } 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); return rc; } diff --git a/stratosphere/loader/source/ldr_nso.hpp b/stratosphere/loader/source/ldr_nso.hpp index 7ab733f54..242839249 100644 --- a/stratosphere/loader/source/ldr_nso.hpp +++ b/stratosphere/loader/source/ldr_nso.hpp @@ -92,6 +92,6 @@ class NsoUtils { static Result ValidateNsoLoadSet(); 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); }; \ No newline at end of file diff --git a/stratosphere/loader/source/ldr_process_manager.cpp b/stratosphere/loader/source/ldr_process_manager.cpp index be3a434a8..2ea5bd03b 100644 --- a/stratosphere/loader/source/ldr_process_manager.cpp +++ b/stratosphere/loader/source/ldr_process_manager.cpp @@ -1,4 +1,5 @@ #include +#include #include "ldr_process_manager.hpp" #include "ldr_registration.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 rc = 0xF601; - + switch ((ProcessManagerServiceCmd)cmd_id) { case Pm_Cmd_CreateProcess: 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: break; } - return rc; } diff --git a/stratosphere/loader/source/ldr_process_manager.hpp b/stratosphere/loader/source/ldr_process_manager.hpp index 62d939870..efdd4ab7b 100644 --- a/stratosphere/loader/source/ldr_process_manager.hpp +++ b/stratosphere/loader/source/ldr_process_manager.hpp @@ -12,7 +12,7 @@ enum ProcessManagerServiceCmd { Pm_Cmd_UnregisterTitle = 3 }; -class ProcessManagerService final : IServiceObject { +class ProcessManagerService final : public IServiceObject { struct ProgramInfo { u8 main_thread_priority; u8 default_cpu_id; diff --git a/stratosphere/loader/source/ldr_ro_service.cpp b/stratosphere/loader/source/ldr_ro_service.cpp index 941899712..402bb9cc6 100644 --- a/stratosphere/loader/source/ldr_ro_service.cpp +++ b/stratosphere/loader/source/ldr_ro_service.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "ldr_ro_service.hpp" #include "ldr_registration.hpp" diff --git a/stratosphere/loader/source/ldr_ro_service.hpp b/stratosphere/loader/source/ldr_ro_service.hpp index 8b952bfbe..c5c640553 100644 --- a/stratosphere/loader/source/ldr_ro_service.hpp +++ b/stratosphere/loader/source/ldr_ro_service.hpp @@ -12,7 +12,7 @@ enum RoServiceCmd { Ro_Cmd_Initialize = 4, }; -class RelocatableObjectsService final : IServiceObject { +class RelocatableObjectsService final : public IServiceObject { Handle process_handle; u64 process_id; bool has_initialized; diff --git a/stratosphere/loader/source/ldr_shell.cpp b/stratosphere/loader/source/ldr_shell.cpp index 50c9f44ae..d28fecd07 100644 --- a/stratosphere/loader/source/ldr_shell.cpp +++ b/stratosphere/loader/source/ldr_shell.cpp @@ -1,4 +1,5 @@ #include +#include #include "ldr_shell.hpp" #include "ldr_launch_queue.hpp" diff --git a/stratosphere/loader/source/ldr_shell.hpp b/stratosphere/loader/source/ldr_shell.hpp index 9eda9ee48..e5e27eec9 100644 --- a/stratosphere/loader/source/ldr_shell.hpp +++ b/stratosphere/loader/source/ldr_shell.hpp @@ -7,7 +7,7 @@ enum ShellServiceCmd { Shell_Cmd_ClearLaunchQueue = 1 }; -class ShellService final : 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 { diff --git a/stratosphere/sm/source/sm_manager_service.cpp b/stratosphere/sm/source/sm_manager_service.cpp index 446b917bb..0e6a46801 100644 --- a/stratosphere/sm/source/sm_manager_service.cpp +++ b/stratosphere/sm/source/sm_manager_service.cpp @@ -1,4 +1,5 @@ #include +#include #include "sm_manager_service.hpp" #include "sm_registration.hpp" diff --git a/stratosphere/sm/source/sm_manager_service.hpp b/stratosphere/sm/source/sm_manager_service.hpp index 7346bc08d..1022ecd0b 100644 --- a/stratosphere/sm/source/sm_manager_service.hpp +++ b/stratosphere/sm/source/sm_manager_service.hpp @@ -7,11 +7,15 @@ enum ManagerServiceCmd { Manager_Cmd_UnregisterProcess = 1 }; -class ManagerService final : IServiceObject { +class ManagerService 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; + ManagerService *clone() override { + return new ManagerService(); + } + private: /* Actual commands. */ std::tuple register_process(u64 pid, InBuffer acid_sac, InBuffer aci0_sac); diff --git a/stratosphere/sm/source/sm_user_service.cpp b/stratosphere/sm/source/sm_user_service.cpp index 4c1bce24a..69e0e5699 100644 --- a/stratosphere/sm/source/sm_user_service.cpp +++ b/stratosphere/sm/source/sm_user_service.cpp @@ -4,7 +4,7 @@ #include "sm_registration.hpp" 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) { case User_Cmd_Initialize: rc = WrapIpcCommandImpl<&UserService::initialize>(this, r, out_c, pointer_buffer, pointer_buffer_size); diff --git a/stratosphere/sm/source/sm_user_service.hpp b/stratosphere/sm/source/sm_user_service.hpp index d8c54a08a..94f39b0ad 100644 --- a/stratosphere/sm/source/sm_user_service.hpp +++ b/stratosphere/sm/source/sm_user_service.hpp @@ -12,7 +12,7 @@ enum UserServiceCmd { User_Cmd_AtmosphereUninstallMitm = 65001 }; -class UserService final : IServiceObject { +class UserService final : public IServiceObject { u64 pid; bool has_initialized; 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 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: /* Actual commands. */ std::tuple initialize(PidDescriptor pid);