From c1c211f542e9d89be91ea8fda9d6918bec633d0b Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 9 Jun 2018 19:33:22 -0600 Subject: [PATCH] fs.mitm: Implement basic passthrough framework for input commands. --- stratosphere/fs_mitm/Makefile | 153 ++++++++++++++++ stratosphere/fs_mitm/fs_mitm.json | 77 ++++++++ stratosphere/fs_mitm/source/debug.cpp | 17 ++ stratosphere/fs_mitm/source/debug.hpp | 4 + stratosphere/fs_mitm/source/fsmitm_main.cpp | 104 +++++++++++ .../fs_mitm/source/fsmitm_service.cpp | 12 ++ .../fs_mitm/source/fsmitm_service.hpp | 9 + stratosphere/fs_mitm/source/mitm_server.hpp | 127 +++++++++++++ stratosphere/fs_mitm/source/mitm_session.hpp | 153 ++++++++++++++++ stratosphere/fs_mitm/source/sm_mitm.c | 173 ++++++++++++++++++ stratosphere/fs_mitm/source/sm_mitm.h | 22 +++ stratosphere/loader/source/ldr_main.cpp | 2 + stratosphere/sm/source/sm_registration.cpp | 2 + 13 files changed, 855 insertions(+) create mode 100644 stratosphere/fs_mitm/Makefile create mode 100644 stratosphere/fs_mitm/fs_mitm.json create mode 100644 stratosphere/fs_mitm/source/debug.cpp create mode 100644 stratosphere/fs_mitm/source/debug.hpp create mode 100644 stratosphere/fs_mitm/source/fsmitm_main.cpp create mode 100644 stratosphere/fs_mitm/source/fsmitm_service.cpp create mode 100644 stratosphere/fs_mitm/source/fsmitm_service.hpp create mode 100644 stratosphere/fs_mitm/source/mitm_server.hpp create mode 100644 stratosphere/fs_mitm/source/mitm_session.hpp create mode 100644 stratosphere/fs_mitm/source/sm_mitm.c create mode 100644 stratosphere/fs_mitm/source/sm_mitm.h diff --git a/stratosphere/fs_mitm/Makefile b/stratosphere/fs_mitm/Makefile new file mode 100644 index 000000000..41a6cf79f --- /dev/null +++ b/stratosphere/fs_mitm/Makefile @@ -0,0 +1,153 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITPRO)/libnx/switch_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +# EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm". +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := data +INCLUDES := include +EXEFS_SRC := exefs_src + +DEFINES := -DDISABLE_IPC + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE + +CFLAGS := -g -Wall -O2 -ffunction-sections \ + $(ARCH) $(DEFINES) + +CFLAGS += $(INCLUDE) -D__SWITCH__ + +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +LIBS := -lstratosphere -lnx + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) $(LIBNX) $(CURDIR)/../libstratosphere + + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +all: $(BUILD) + +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).kip $(TARGET).elf + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(OUTPUT).kip + +$(OUTPUT).kip : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/fs_mitm/fs_mitm.json b/stratosphere/fs_mitm/fs_mitm.json new file mode 100644 index 000000000..f4c4850f3 --- /dev/null +++ b/stratosphere/fs_mitm/fs_mitm.json @@ -0,0 +1,77 @@ +{ + "name" : "fs.mitm", + "title_id" : "0x010041544D530000", + "main_thread_stack_size" : "0x8000", + "main_thread_priority": 44, + "default_cpu_id": 3, + "process_category" : 1, + "kernel_capabilities" : { + "handle_table_size" : 256, + "syscalls": { + "svcSetHeapSize": "0x01", + "svcSetMemoryPermission": "0x02", + "svcSetMemoryAttribute": "0x03", + "svcMapMemory": "0x04", + "svcUnmapMemory": "0x05", + "svcQueryMemory": "0x06", + "svcExitProcess": "0x07", + "svcCreateThread": "0x08", + "svcStartThread": "0x09", + "svcExitThread": "0x0a", + "svcSleepThread": "0x0b", + "svcGetThreadPriority": "0x0c", + "svcSetThreadPriority": "0x0d", + "svcGetThreadCoreMask": "0x0e", + "svcSetThreadCoreMask": "0x0f", + "svcGetCurrentProcessorNumber": "0x10", + "svcSignalEvent": "0x11", + "svcClearEvent": "0x12", + "svcMapSharedMemory": "0x13", + "svcUnmapSharedMemory": "0x14", + "svcCreateTransferMemory": "0x15", + "svcCloseHandle": "0x16", + "svcResetSignal": "0x17", + "svcWaitSynchronization": "0x18", + "svcCancelSynchronization": "0x19", + "svcArbitrateLock": "0x1a", + "svcArbitrateUnlock": "0x1b", + "svcWaitProcessWideKeyAtomic": "0x1c", + "svcSignalProcessWideKey": "0x1d", + "svcGetSystemTick": "0x1e", + "svcConnectToNamedPort": "0x1f", + "svcSendSyncRequestLight": "0x20", + "svcSendSyncRequest": "0x21", + "svcSendSyncRequestWithUserBuffer": "0x22", + "svcSendAsyncRequestWithUserBuffer": "0x23", + "svcGetProcessId": "0x24", + "svcGetThreadId": "0x25", + "svcBreak": "0x26", + "svcOutputDebugString": "0x27", + "svcReturnFromException": "0x28", + "svcGetInfo": "0x29", + "svcWaitForAddress": "0x34", + "svcSignalToAddress": "0x35", + "svcCreateSession": "0x40", + "svcAcceptSession": "0x41", + "svcReplyAndReceiveLight": "0x42", + "svcReplyAndReceive": "0x43", + "svcReplyAndReceiveWithUserBuffer": "0x44", + "svcCreateEvent": "0x45", + "svcReadWriteRegister": "0x4E", + "svcCreateInterruptEvent": "0x53", + "svcQueryIoMapping": "0x55", + "svcCreateDeviceAddressSpace": "0x56", + "svcAttachDeviceAddressSpace": "0x57", + "svcDetachDeviceAddressSpace": "0x58", + "svcMapDeviceAddressSpaceAligned": "0x5a", + "svcUnmapDeviceAddressSpace": "0x5c", + "svcGetSystemInfo": "0x6f" + }, + "map" : { + "address" : "0x40000000", + "size" : "0x40000", + "is_ro" : false, + "is_io" : true + } + } +} \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/debug.cpp b/stratosphere/fs_mitm/source/debug.cpp new file mode 100644 index 000000000..972d39f9c --- /dev/null +++ b/stratosphere/fs_mitm/source/debug.cpp @@ -0,0 +1,17 @@ +#include +#include +#include "debug.hpp" + +static u64 g_num_logged = 0; + +#define MAX_LOGS U64_MAX + +void Reboot() { + while (1) { + /* ... */ + } +} + +void Log(const void *data, int size) { + /* ... */ +} \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/debug.hpp b/stratosphere/fs_mitm/source/debug.hpp new file mode 100644 index 000000000..b79a426eb --- /dev/null +++ b/stratosphere/fs_mitm/source/debug.hpp @@ -0,0 +1,4 @@ +#pragma once + +void Reboot(); +void Log(const void *data, int size); \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/fsmitm_main.cpp b/stratosphere/fs_mitm/source/fsmitm_main.cpp new file mode 100644 index 000000000..fcc8653b9 --- /dev/null +++ b/stratosphere/fs_mitm/source/fsmitm_main.cpp @@ -0,0 +1,104 @@ +#include +#include +#include +#include + +#include +#include + +#include "sm_mitm.h" + +#include "mitm_server.hpp" +#include "fsmitm_service.hpp" + +extern "C" { + extern u32 __start__; + + u32 __nx_applet_type = AppletType_None; + + #define INNER_HEAP_SIZE 0x1000000 + size_t nx_inner_heap_size = INNER_HEAP_SIZE; + char nx_inner_heap[INNER_HEAP_SIZE]; + + void __libnx_initheap(void); + void __appInit(void); + void __appExit(void); +} + + +void __libnx_initheap(void) { + void* addr = nx_inner_heap; + size_t size = nx_inner_heap_size; + + /* Newlib */ + extern char* fake_heap_start; + extern char* fake_heap_end; + + fake_heap_start = (char*)addr; + fake_heap_end = (char*)addr + size; +} + +void __appInit(void) { + Result rc; + + rc = smInitialize(); + if (R_FAILED(rc)) { + fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM)); + } + + rc = smMitMInitialize(); + if (R_FAILED(rc)) { + fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM)); + } + + rc = fsInitialize(); + if (R_FAILED(rc)) { + fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS)); + } + + rc = splInitialize(); + if (R_FAILED(rc)) { + fatalSimple(0xCAFE << 4 | 3); + } + + /* Check for exosphere API compatibility. */ + u64 exosphere_cfg; + if (R_SUCCEEDED(splGetConfig((SplConfigItem)65000, &exosphere_cfg))) { + /* MitM requires Atmosphere API 0.1. */ + u16 api_version = (exosphere_cfg >> 16) & 0xFFFF; + if (api_version < 0x0001) { + fatalSimple(0xCAFE << 4 | 0xFE); + } + } else { + fatalSimple(0xCAFE << 4 | 0xFF); + } + + splExit(); +} + +void __appExit(void) { + /* Cleanup services. */ + fsExit(); + smMitMExit(); + smExit(); +} + +int main(int argc, char **argv) +{ + consoleDebugInit(debugDevice_SVC); + + + /* TODO: What's a good timeout value to use here? */ + WaitableManager *server_manager = new WaitableManager(U64_MAX); + + /* Create fsp-srv mitm. */ + server_manager->add_waitable(new MitMServer("fsp-srv", 61)); + + /* Loop forever, servicing our services. */ + server_manager->process(); + + /* Cleanup. */ + delete server_manager; + return 0; +} + diff --git a/stratosphere/fs_mitm/source/fsmitm_service.cpp b/stratosphere/fs_mitm/source/fsmitm_service.cpp new file mode 100644 index 000000000..0567aeb4d --- /dev/null +++ b/stratosphere/fs_mitm/source/fsmitm_service.cpp @@ -0,0 +1,12 @@ +#include +#include "fsmitm_service.hpp" + +Result FsMitMService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) { + Result rc = 0xF601; + return rc; +} + +Result FsMitMService::handle_deferred() { + /* This service is never deferrable. */ + return 0; +} \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/fsmitm_service.hpp b/stratosphere/fs_mitm/source/fsmitm_service.hpp new file mode 100644 index 000000000..7f08c7b59 --- /dev/null +++ b/stratosphere/fs_mitm/source/fsmitm_service.hpp @@ -0,0 +1,9 @@ +#pragma once +#include +#include + +class FsMitMService : IServiceObject { + public: + virtual Result dispatch(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_server.hpp b/stratosphere/fs_mitm/source/mitm_server.hpp new file mode 100644 index 000000000..94cc55220 --- /dev/null +++ b/stratosphere/fs_mitm/source/mitm_server.hpp @@ -0,0 +1,127 @@ +#pragma once +#include +#include + +#include "sm_mitm.h" +#include "mitm_session.hpp" + +#include "debug.hpp" + +template +class MitMSession; + +template +class MitMServer final : public IWaitable { + 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; + 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; + } + 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. */ + } + } + + 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))) { + /* 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(); + } + } + } + + 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; + } +}; + + diff --git a/stratosphere/fs_mitm/source/mitm_session.hpp b/stratosphere/fs_mitm/source/mitm_session.hpp new file mode 100644 index 000000000..a11dcd846 --- /dev/null +++ b/stratosphere/fs_mitm/source/mitm_session.hpp @@ -0,0 +1,153 @@ +#pragma once +#include +#include + +#include "mitm_server.hpp" + +#include "debug.hpp" + + +template +class MitMServer; + +template +class MitMSession final : public IWaitable { + static_assert(std::is_base_of::value, "Service Objects must derive from IServiceObject"); + + 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!"); + public: + MitMSession(MitMServer *s, Handle s_h, Handle c_h, const char *srv) : server(s), server_handle(s_h), client_handle(c_h) { + this->service_object = new T(); + if (R_FAILED(smMitMGetService(&forward_service, srv))) { + /* TODO: Panic. */ + } + if (R_FAILED(ipcQueryPointerBufferSize(forward_service.handle, &pointer_buffer_size))) { + /* TODO: Panic. */ + } + this->pointer_buffer = new char[pointer_buffer_size]; + } + + ~MitMSession() override { + delete this->service_object; + 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); + 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); + + /* TODO: Close input copy handles that we don't need. */ + + if (R_SUCCEEDED(retval)) { + rawdata_start = (u32 *)r.Raw; + retval = 0xF601; + if (r.CommandType == IpcCommandType_Request || r.CommandType == IpcCommandType_RequestWithContext) { + retval = this->service_object->dispatch(r, c, rawdata_start[2], (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer)); + } + + /* 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); + + struct { + u64 magic; + u64 result; + } *resp = (decltype(resp))out_r.Raw; + + retval = resp->result; + } + } + } + + if (retval == 0xF601) { + /* Session close. */ + rc = retval; + } else { + 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]); + } + } + } + } + + return rc; + } +}; \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/sm_mitm.c b/stratosphere/fs_mitm/source/sm_mitm.c new file mode 100644 index 000000000..25d9ee838 --- /dev/null +++ b/stratosphere/fs_mitm/source/sm_mitm.c @@ -0,0 +1,173 @@ +#include +#include +#include "sm_mitm.h" + +static Handle g_smMitmHandle = INVALID_HANDLE; +static u64 g_refCnt; + +Result smMitMInitialize(void) { + atomicIncrement64(&g_refCnt); + + if (g_smMitmHandle != INVALID_HANDLE) + return 0; + + Result rc = svcConnectToNamedPort(&g_smMitmHandle, "sm:"); + + if (R_SUCCEEDED(rc)) { + IpcCommand c; + ipcInitialize(&c); + ipcSendPid(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 zero; + u64 reserved[2]; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 0; + raw->zero = 0; + + rc = ipcDispatch(g_smMitmHandle); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + } + } + + if (R_FAILED(rc)) + smExit(); + + return rc; +} + +void smMitMExit(void) { + if (atomicDecrement64(&g_refCnt) == 0) { + svcCloseHandle(g_smMitmHandle); + g_smMitmHandle = INVALID_HANDLE; + } +} + +Result smMitMGetService(Service* service_out, const char *name_str) +{ + u64 name = smEncodeName(name_str); + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 service_name; + u64 reserved[2]; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 1; + raw->service_name = name; + + Result rc = ipcDispatch(g_smMitmHandle); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + service_out->type = ServiceType_Normal; + service_out->handle = r.Handles[0]; + } + } + + return rc; +} + + +Result smMitMInstall(Handle *handle_out, const char *name) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 service_name; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65000; + raw->service_name = smEncodeName(name); + + Result rc = ipcDispatch(g_smMitmHandle); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + *handle_out = r.Handles[0]; + } + } + + return rc; +} + +Result smMitMUninstall(const char *name) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 service_name; + u64 reserved; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65001; + raw->service_name = smEncodeName(name); + + Result rc = ipcDispatch(g_smMitmHandle); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + } + + return rc; +} \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/sm_mitm.h b/stratosphere/fs_mitm/source/sm_mitm.h new file mode 100644 index 000000000..aa2cd6af1 --- /dev/null +++ b/stratosphere/fs_mitm/source/sm_mitm.h @@ -0,0 +1,22 @@ +/** + * @file sm_mitm.h + * @brief Service manager (sm) IPC wrapper for Atmosphere extensions. + * @author SciresM + * @copyright libnx Authors + */ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +Result smMitMInitialize(void); +void smMitMExit(void); +Result smMitMGetService(Service* service_out, const char *name); +Result smMitMInstall(Handle *handle_out, const char *name); +Result smMitMUninstall(const char *name); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/stratosphere/loader/source/ldr_main.cpp b/stratosphere/loader/source/ldr_main.cpp index f2075abe8..dc0c2f30e 100644 --- a/stratosphere/loader/source/ldr_main.cpp +++ b/stratosphere/loader/source/ldr_main.cpp @@ -75,6 +75,8 @@ void __appInit(void) { fatalSimple(0xCAFE << 4 | 0xFF); /* TODO: Does Loader need to know about target firmware/master key revision? If so, extract from exosphere_cfg. */ } + + splExit(); } void __appExit(void) { diff --git a/stratosphere/sm/source/sm_registration.cpp b/stratosphere/sm/source/sm_registration.cpp index f27dd5ee4..b6e4e3169 100644 --- a/stratosphere/sm/source/sm_registration.cpp +++ b/stratosphere/sm/source/sm_registration.cpp @@ -264,6 +264,8 @@ Result Registration::RegisterServiceForPid(u64 pid, u64 service, u64 max_session if (R_SUCCEEDED(rc)) { free_service->service_name = service; free_service->owner_pid = pid; + free_service->max_sessions = max_sessions; + free_service->is_light = is_light; } return rc;