mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-18 01:46:47 +00:00
fs.mitm: Implement basic passthrough framework for input commands.
This commit is contained in:
parent
28d630a23e
commit
c1c211f542
13 changed files with 855 additions and 0 deletions
153
stratosphere/fs_mitm/Makefile
Normal file
153
stratosphere/fs_mitm/Makefile
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITPRO)),)
|
||||||
|
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/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
|
||||||
|
#---------------------------------------------------------------------------------------
|
77
stratosphere/fs_mitm/fs_mitm.json
Normal file
77
stratosphere/fs_mitm/fs_mitm.json
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
stratosphere/fs_mitm/source/debug.cpp
Normal file
17
stratosphere/fs_mitm/source/debug.cpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#include <switch.h>
|
||||||
|
#include <cstring>
|
||||||
|
#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) {
|
||||||
|
/* ... */
|
||||||
|
}
|
4
stratosphere/fs_mitm/source/debug.hpp
Normal file
4
stratosphere/fs_mitm/source/debug.hpp
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
void Reboot();
|
||||||
|
void Log(const void *data, int size);
|
104
stratosphere/fs_mitm/source/fsmitm_main.cpp
Normal file
104
stratosphere/fs_mitm/source/fsmitm_main.cpp
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#include <switch.h>
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
#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<FsMitMService>("fsp-srv", 61));
|
||||||
|
|
||||||
|
/* Loop forever, servicing our services. */
|
||||||
|
server_manager->process();
|
||||||
|
|
||||||
|
/* Cleanup. */
|
||||||
|
delete server_manager;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
12
stratosphere/fs_mitm/source/fsmitm_service.cpp
Normal file
12
stratosphere/fs_mitm/source/fsmitm_service.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include <switch.h>
|
||||||
|
#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;
|
||||||
|
}
|
9
stratosphere/fs_mitm/source/fsmitm_service.hpp
Normal file
9
stratosphere/fs_mitm/source/fsmitm_service.hpp
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
#include <stratosphere/iserviceobject.hpp>
|
||||||
|
|
||||||
|
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();
|
||||||
|
};
|
127
stratosphere/fs_mitm/source/mitm_server.hpp
Normal file
127
stratosphere/fs_mitm/source/mitm_server.hpp
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
#include "sm_mitm.h"
|
||||||
|
#include "mitm_session.hpp"
|
||||||
|
|
||||||
|
#include "debug.hpp"
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class MitMSession;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class MitMServer final : public IWaitable {
|
||||||
|
static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject");
|
||||||
|
protected:
|
||||||
|
Handle port_handle;
|
||||||
|
unsigned int max_sessions;
|
||||||
|
unsigned int num_sessions;
|
||||||
|
MitMSession<T> **sessions;
|
||||||
|
char mitm_name[9];
|
||||||
|
|
||||||
|
public:
|
||||||
|
MitMServer(const char *service_name, unsigned int max_s) : max_sessions(max_s) {
|
||||||
|
this->sessions = new MitMSession<T> *[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<T>(this, session_h, 0, mitm_name);
|
||||||
|
this->sessions[i]->set_parent(this);
|
||||||
|
this->num_sessions++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
153
stratosphere/fs_mitm/source/mitm_session.hpp
Normal file
153
stratosphere/fs_mitm/source/mitm_session.hpp
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
#include "mitm_server.hpp"
|
||||||
|
|
||||||
|
#include "debug.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class MitMServer;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class MitMSession final : public IWaitable {
|
||||||
|
static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject");
|
||||||
|
|
||||||
|
T *service_object;
|
||||||
|
MitMServer<T> *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<T>(MitMServer<T> *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;
|
||||||
|
}
|
||||||
|
};
|
173
stratosphere/fs_mitm/source/sm_mitm.c
Normal file
173
stratosphere/fs_mitm/source/sm_mitm.c
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
#include <switch.h>
|
||||||
|
#include <switch/arm/atomics.h>
|
||||||
|
#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;
|
||||||
|
}
|
22
stratosphere/fs_mitm/source/sm_mitm.h
Normal file
22
stratosphere/fs_mitm/source/sm_mitm.h
Normal file
|
@ -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 <switch.h>
|
||||||
|
|
||||||
|
#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
|
|
@ -75,6 +75,8 @@ void __appInit(void) {
|
||||||
fatalSimple(0xCAFE << 4 | 0xFF);
|
fatalSimple(0xCAFE << 4 | 0xFF);
|
||||||
/* TODO: Does Loader need to know about target firmware/master key revision? If so, extract from exosphere_cfg. */
|
/* TODO: Does Loader need to know about target firmware/master key revision? If so, extract from exosphere_cfg. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
splExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void __appExit(void) {
|
void __appExit(void) {
|
||||||
|
|
|
@ -264,6 +264,8 @@ Result Registration::RegisterServiceForPid(u64 pid, u64 service, u64 max_session
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
free_service->service_name = service;
|
free_service->service_name = service;
|
||||||
free_service->owner_pid = pid;
|
free_service->owner_pid = pid;
|
||||||
|
free_service->max_sessions = max_sessions;
|
||||||
|
free_service->is_light = is_light;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
|
Loading…
Reference in a new issue