mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-22 20:06:40 +00:00
dmnt: pull in from ams.tma branch
This commit is contained in:
commit
89503049b3
9 changed files with 957 additions and 10 deletions
2
Makefile
2
Makefile
|
@ -54,6 +54,7 @@ dist: all
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000034
|
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000034
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032
|
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032
|
||||||
cp fusee/fusee-primary/fusee-primary.bin atmosphere-$(AMSVER)/atmosphere/reboot_payload.bin
|
cp fusee/fusee-primary/fusee-primary.bin atmosphere-$(AMSVER)/atmosphere/reboot_payload.bin
|
||||||
|
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/010000000000000D
|
||||||
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/atmosphere/fusee-secondary.bin
|
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/atmosphere/fusee-secondary.bin
|
||||||
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/sept/payload.bin
|
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/sept/payload.bin
|
||||||
cp sept/sept-primary/sept-primary.bin atmosphere-$(AMSVER)/sept/sept-primary.bin
|
cp sept/sept-primary/sept-primary.bin atmosphere-$(AMSVER)/sept/sept-primary.bin
|
||||||
|
@ -69,6 +70,7 @@ dist: all
|
||||||
cp troposphere/reboot_to_payload/reboot_to_payload.nro atmosphere-$(AMSVER)/switch/reboot_to_payload.nro
|
cp troposphere/reboot_to_payload/reboot_to_payload.nro atmosphere-$(AMSVER)/switch/reboot_to_payload.nro
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/flags
|
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/flags
|
||||||
touch atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/flags/boot2.flag
|
touch atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/flags/boot2.flag
|
||||||
|
cp stratosphere/dmnt/dmnt.nsp atmosphere-$(AMSVER)/atmosphere/titles/010000000000000D/exefs.nsp
|
||||||
cd atmosphere-$(AMSVER); zip -r ../atmosphere-$(AMSVER).zip ./*; cd ../;
|
cd atmosphere-$(AMSVER); zip -r ../atmosphere-$(AMSVER).zip ./*; cd ../;
|
||||||
rm -r atmosphere-$(AMSVER)
|
rm -r atmosphere-$(AMSVER)
|
||||||
mkdir out
|
mkdir out
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
MODULES := loader pm sm boot ams_mitm eclct.stub creport fatal
|
MODULES := loader pm sm boot ams_mitm eclct.stub creport fatal dmnt
|
||||||
|
|
||||||
SUBFOLDERS := libstratosphere $(MODULES)
|
SUBFOLDERS := libstratosphere $(MODULES)
|
||||||
|
|
||||||
|
|
166
stratosphere/dmnt/Makefile
Normal file
166
stratosphere/dmnt/Makefile
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITPRO)),)
|
||||||
|
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||||
|
endif
|
||||||
|
|
||||||
|
TOPDIR ?= $(CURDIR)
|
||||||
|
include $(DEVKITPRO)/libnx/switch_rules
|
||||||
|
|
||||||
|
AMSBRANCH := $(shell git symbolic-ref --short HEAD)
|
||||||
|
AMSREV := $(AMSBRANCH)-$(shell git rev-parse --short HEAD)
|
||||||
|
|
||||||
|
ifneq (, $(strip $(shell git status --porcelain 2>/dev/null)))
|
||||||
|
AMSREV := $(AMSREV)-dirty
|
||||||
|
endif
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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 ../../common/include
|
||||||
|
EXEFS_SRC := exefs_src
|
||||||
|
|
||||||
|
DEFINES := -DDISABLE_IPC -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\"
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
.PHONY: all
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all : $(OUTPUT).nsp
|
||||||
|
|
||||||
|
ifeq ($(strip $(APP_JSON)),)
|
||||||
|
$(OUTPUT).nsp : $(OUTPUT).nso
|
||||||
|
else
|
||||||
|
$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(OUTPUT).nso : $(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
|
||||||
|
#---------------------------------------------------------------------------------------
|
117
stratosphere/dmnt/dmnt.json
Normal file
117
stratosphere/dmnt/dmnt.json
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
{
|
||||||
|
"name": "dmnt",
|
||||||
|
"title_id": "0x010000000000000d",
|
||||||
|
"title_id_range_min": "0x010000000000000d",
|
||||||
|
"title_id_range_max": "0x010000000000000d",
|
||||||
|
"main_thread_stack_size": "0x00004000",
|
||||||
|
"main_thread_priority": 39,
|
||||||
|
"default_cpu_id": 3,
|
||||||
|
"process_category": 0,
|
||||||
|
"is_retail": true,
|
||||||
|
"pool_partition": 2,
|
||||||
|
"is_64_bit": true,
|
||||||
|
"address_space_type": 1,
|
||||||
|
"filesystem_access": {
|
||||||
|
"permissions": "0xFFFFFFFFFFFFFFFF"
|
||||||
|
},
|
||||||
|
"service_access": [
|
||||||
|
"pm:dmnt",
|
||||||
|
"ldr:dmnt",
|
||||||
|
"ro:dmnt",
|
||||||
|
"ns:dev",
|
||||||
|
"spl:",
|
||||||
|
"lr",
|
||||||
|
"htc",
|
||||||
|
"bsd:s",
|
||||||
|
"sfdnsres",
|
||||||
|
"bsdcfg",
|
||||||
|
"set",
|
||||||
|
"fsp-srv",
|
||||||
|
"fatal:u"
|
||||||
|
],
|
||||||
|
"service_host": [
|
||||||
|
"dmnt:-"
|
||||||
|
],
|
||||||
|
"kernel_capabilities": [{
|
||||||
|
"type": "kernel_flags",
|
||||||
|
"value": {
|
||||||
|
"highest_thread_priority": 63,
|
||||||
|
"lowest_thread_priority": 24,
|
||||||
|
"lowest_cpu_id": 0,
|
||||||
|
"highest_cpu_id": 3
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"type": "syscalls",
|
||||||
|
"value": {
|
||||||
|
"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",
|
||||||
|
"svcDebugActiveProcess": "0x60",
|
||||||
|
"svcBreakDebugProcess": "0x61",
|
||||||
|
"svcTerminateDebugProcess": "0x62",
|
||||||
|
"svcGetDebugEvent": "0x63",
|
||||||
|
"svcContinueDebugEvent": "0x64",
|
||||||
|
"svcGetProcessList": "0x65",
|
||||||
|
"svcGetThreadList": "0x66",
|
||||||
|
"svcGetDebugThreadContext": "0x67",
|
||||||
|
"svcSetDebugThreadContext": "0x68",
|
||||||
|
"svcQueryDebugProcessMemory": "0x69",
|
||||||
|
"svcReadDebugProcessMemory": "0x6a",
|
||||||
|
"svcWriteDebugProcessMemory": "0x6b",
|
||||||
|
"svcSetHardwareBreakPoint": "0x6c",
|
||||||
|
"svcGetDebugThreadParam": "0x6d"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"type": "min_kernel_version",
|
||||||
|
"value": "0x0030"
|
||||||
|
}, {
|
||||||
|
"type": "handle_table_size",
|
||||||
|
"value": 0
|
||||||
|
}]
|
||||||
|
}
|
140
stratosphere/dmnt/source/dmnt_main.cpp
Normal file
140
stratosphere/dmnt/source/dmnt_main.cpp
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#include <switch.h>
|
||||||
|
#include <atmosphere.h>
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
#include "dmnt_service.hpp"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
extern u32 __start__;
|
||||||
|
|
||||||
|
u32 __nx_applet_type = AppletType_None;
|
||||||
|
|
||||||
|
#define INNER_HEAP_SIZE 0x80000
|
||||||
|
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 = pmdmntInitialize();
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
fatalSimple(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ldrDmntInitialize();
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
fatalSimple(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (kernelAbove300()) {
|
||||||
|
rc = roDmntInitialize();
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
fatalSimple(rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
rc = nsdevInitialize();
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
fatalSimple(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = lrInitialize();
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
fatalSimple(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = setInitialize();
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
fatalSimple(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = fsInitialize();
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
fatalSimple(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = fsdevMountSdmc();
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
fatalSimple(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckAtmosphereVersion(CURRENT_ATMOSPHERE_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __appExit(void) {
|
||||||
|
/* Cleanup services. */
|
||||||
|
fsdevUnmountAll();
|
||||||
|
fsExit();
|
||||||
|
setExit();
|
||||||
|
lrExit();
|
||||||
|
nsdevExit();
|
||||||
|
/* if (kernelAbove300()) { roDmntExit(); } */
|
||||||
|
ldrDmntExit();
|
||||||
|
pmdmntExit();
|
||||||
|
smExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
consoleDebugInit(debugDevice_SVC);
|
||||||
|
|
||||||
|
/* Nintendo uses four threads. */
|
||||||
|
auto server_manager = new WaitableManager(4);
|
||||||
|
|
||||||
|
/* Create services. */
|
||||||
|
server_manager->AddWaitable(new ServiceServer<DebugMonitorService>("dmnt:-", 4));
|
||||||
|
|
||||||
|
/* Loop forever, servicing our services. */
|
||||||
|
server_manager->Process();
|
||||||
|
|
||||||
|
delete server_manager;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
150
stratosphere/dmnt/source/dmnt_service.hpp
Normal file
150
stratosphere/dmnt/source/dmnt_service.hpp
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
enum DmntCmd {
|
||||||
|
DebugMonitor_Cmd_BreakDebugProcess = 0,
|
||||||
|
DebugMonitor_Cmd_TerminateDebugProcess = 1,
|
||||||
|
DebugMonitor_Cmd_CloseHandle = 2,
|
||||||
|
DebugMonitor_Cmd_LoadImage = 3,
|
||||||
|
DebugMonitor_Cmd_GetProcessId = 4,
|
||||||
|
DebugMonitor_Cmd_GetProcessHandle = 5,
|
||||||
|
DebugMonitor_Cmd_WaitSynchronization = 6,
|
||||||
|
DebugMonitor_Cmd_GetDebugEvent = 7,
|
||||||
|
DebugMonitor_Cmd_GetProcessModuleInfo = 8,
|
||||||
|
DebugMonitor_Cmd_GetProcessList = 9,
|
||||||
|
DebugMonitor_Cmd_GetThreadList = 10,
|
||||||
|
DebugMonitor_Cmd_GetDebugThreadContext = 11,
|
||||||
|
DebugMonitor_Cmd_ContinueDebugEvent = 12,
|
||||||
|
DebugMonitor_Cmd_ReadDebugProcessMemory = 13,
|
||||||
|
DebugMonitor_Cmd_WriteDebugProcessMemory = 14,
|
||||||
|
DebugMonitor_Cmd_SetDebugThreadContext = 15,
|
||||||
|
DebugMonitor_Cmd_GetDebugThreadParam = 16,
|
||||||
|
DebugMonitor_Cmd_InitializeThreadInfo = 17,
|
||||||
|
DebugMonitor_Cmd_SetHardwareBreakPoint = 18,
|
||||||
|
DebugMonitor_Cmd_QueryDebugProcessMemory = 19,
|
||||||
|
DebugMonitor_Cmd_GetProcessMemoryDetails = 20,
|
||||||
|
DebugMonitor_Cmd_AttachByProgramId = 21,
|
||||||
|
DebugMonitor_Cmd_AttachOnLaunch = 22,
|
||||||
|
DebugMonitor_Cmd_GetDebugMonitorProcessId = 23,
|
||||||
|
DebugMonitor_Cmd_GetJitDebugProcessList = 25,
|
||||||
|
DebugMonitor_Cmd_CreateCoreDump = 26,
|
||||||
|
DebugMonitor_Cmd_GetAllDebugThreadInfo = 27,
|
||||||
|
DebugMonitor_Cmd_TargetIO_FileOpen = 29,
|
||||||
|
DebugMonitor_Cmd_TargetIO_FileClose = 30,
|
||||||
|
DebugMonitor_Cmd_TargetIO_FileRead = 31,
|
||||||
|
DebugMonitor_Cmd_TargetIO_FileWrite = 32,
|
||||||
|
DebugMonitor_Cmd_TargetIO_FileSetAttributes = 33,
|
||||||
|
DebugMonitor_Cmd_TargetIO_FileGetInformation = 34,
|
||||||
|
DebugMonitor_Cmd_TargetIO_FileSetTime = 35,
|
||||||
|
DebugMonitor_Cmd_TargetIO_FileSetSize = 36,
|
||||||
|
DebugMonitor_Cmd_TargetIO_FileDelete = 37,
|
||||||
|
DebugMonitor_Cmd_TargetIO_FileMove = 38,
|
||||||
|
DebugMonitor_Cmd_TargetIO_DirectoryCreate = 39,
|
||||||
|
DebugMonitor_Cmd_TargetIO_DirectoryDelete = 40,
|
||||||
|
DebugMonitor_Cmd_TargetIO_DirectoryRename = 41,
|
||||||
|
DebugMonitor_Cmd_TargetIO_DirectoryGetCount = 42,
|
||||||
|
DebugMonitor_Cmd_TargetIO_DirectoryOpen = 43,
|
||||||
|
DebugMonitor_Cmd_TargetIO_DirectoryGetNext = 44,
|
||||||
|
DebugMonitor_Cmd_TargetIO_DirectoryClose = 45,
|
||||||
|
DebugMonitor_Cmd_TargetIO_GetFreeSpace = 46,
|
||||||
|
DebugMonitor_Cmd_TargetIO_GetVolumeInformation = 47,
|
||||||
|
DebugMonitor_Cmd_InitiateCoreDump = 48,
|
||||||
|
DebugMonitor_Cmd_ContinueCoreDump = 49,
|
||||||
|
DebugMonitor_Cmd_AddTTYToCoreDump = 50,
|
||||||
|
DebugMonitor_Cmd_AddImageToCoreDump = 51,
|
||||||
|
DebugMonitor_Cmd_CloseCoreDump = 52,
|
||||||
|
DebugMonitor_Cmd_CancelAttach = 53,
|
||||||
|
};
|
||||||
|
|
||||||
|
class DebugMonitorService final : public IServiceObject {
|
||||||
|
private:
|
||||||
|
Result BreakDebugProcess(Handle debug_hnd);
|
||||||
|
Result TerminateDebugProcess(Handle debug_hnd);
|
||||||
|
Result CloseHandle(Handle debug_hnd);
|
||||||
|
Result GetProcessId(Out<u64> out_pid, Handle hnd);
|
||||||
|
Result GetProcessHandle(Out<Handle> out_hnd, u64 pid);
|
||||||
|
Result WaitSynchronization(Handle hnd, u64 ns);
|
||||||
|
|
||||||
|
Result TargetIO_FileOpen(OutBuffer<u64> out_hnd, InBuffer<char> path, int open_mode, u32 create_mode);
|
||||||
|
Result TargetIO_FileClose(InBuffer<u64> hnd);
|
||||||
|
Result TargetIO_FileRead(InBuffer<u64> hnd, OutBuffer<u8, BufferType_Type1> out_data, Out<u32> out_read, u64 offset);
|
||||||
|
Result TargetIO_FileWrite(InBuffer<u64> hnd, InBuffer<u8, BufferType_Type1> data, Out<u32> out_written, u64 offset);
|
||||||
|
Result TargetIO_FileSetAttributes(InBuffer<char> path, InBuffer<u8> attributes);
|
||||||
|
Result TargetIO_FileGetInformation(InBuffer<char> path, OutBuffer<u64> out_info, Out<int> is_directory);
|
||||||
|
Result TargetIO_FileSetTime(InBuffer<char> path, u64 create, u64 access, u64 modify);
|
||||||
|
Result TargetIO_FileSetSize(InBuffer<char> path, u64 size);
|
||||||
|
Result TargetIO_FileDelete(InBuffer<char> path);
|
||||||
|
Result TargetIO_FileMove(InBuffer<char> path0, InBuffer<char> path1);
|
||||||
|
public:
|
||||||
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
|
MakeServiceCommandMeta<DebugMonitor_Cmd_BreakDebugProcess, &DebugMonitorService::BreakDebugProcess>(),
|
||||||
|
MakeServiceCommandMeta<DebugMonitor_Cmd_TerminateDebugProcess, &DebugMonitorService::TerminateDebugProcess>(),
|
||||||
|
MakeServiceCommandMeta<DebugMonitor_Cmd_CloseHandle, &DebugMonitorService::CloseHandle>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_LoadImage, &DebugMonitorService::LoadImage>(),
|
||||||
|
MakeServiceCommandMeta<DebugMonitor_Cmd_GetProcessId, &DebugMonitorService::GetProcessId>(),
|
||||||
|
MakeServiceCommandMeta<DebugMonitor_Cmd_GetProcessHandle, &DebugMonitorService::GetProcessHandle>(),
|
||||||
|
MakeServiceCommandMeta<DebugMonitor_Cmd_WaitSynchronization, &DebugMonitorService::WaitSynchronization>(),
|
||||||
|
//MakeServiceCommandMeta<DebugMonitor_Cmd_GetDebugEvent, &DebugMonitorService::GetDebugEvent>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_GetProcessModuleInfo, &DebugMonitorService::GetProcessModuleInfo>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_GetProcessList, &DebugMonitorService::GetProcessList>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_GetThreadList, &DebugMonitorService::GetThreadList>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_GetDebugThreadContext, &DebugMonitorService::GetDebugThreadContext>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_ContinueDebugEvent, &DebugMonitorService::ContinueDebugEvent>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_ReadDebugProcessMemory, &DebugMonitorService::ReadDebugProcessMemory>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_WriteDebugProcessMemory, &DebugMonitorService::WriteDebugProcessMemory>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_SetDebugThreadContext, &DebugMonitorService::SetDebugThreadContext>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_GetDebugThreadParam, &DebugMonitorService::GetDebugThreadParam>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_InitializeThreadInfo, &DebugMonitorService::InitializeThreadInfo>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_SetHardwareBreakPoint, &DebugMonitorService::SetHardwareBreakPoint>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_QueryDebugProcessMemory, &DebugMonitorService::QueryDebugProcessMemory>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_GetProcessMemoryDetails, &DebugMonitorService::GetProcessMemoryDetails>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_AttachByProgramId, &DebugMonitorService::AttachByProgramId>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_AttachOnLaunch, &DebugMonitorService::AttachOnLaunch>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_GetDebugMonitorProcessId, &DebugMonitorService::GetDebugMonitorProcessId>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_GetJitDebugProcessList, &DebugMonitorService::GetJitDebugProcessList>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_CreateCoreDump, &DebugMonitorService::CreateCoreDump>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_GetAllDebugThreadInfo, &DebugMonitorService::GetAllDebugThreadInfo>(),
|
||||||
|
MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_FileOpen, &DebugMonitorService::TargetIO_FileOpen>(),
|
||||||
|
MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_FileClose, &DebugMonitorService::TargetIO_FileClose>(),
|
||||||
|
MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_FileRead, &DebugMonitorService::TargetIO_FileRead>(),
|
||||||
|
MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_FileWrite, &DebugMonitorService::TargetIO_FileWrite>(),
|
||||||
|
MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_FileSetAttributes, &DebugMonitorService::TargetIO_FileSetAttributes>(),
|
||||||
|
MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_FileGetInformation, &DebugMonitorService::TargetIO_FileGetInformation>(),
|
||||||
|
MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_FileSetTime, &DebugMonitorService::TargetIO_FileSetTime>(),
|
||||||
|
MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_FileSetSize, &DebugMonitorService::TargetIO_FileSetSize>(),
|
||||||
|
MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_FileDelete, &DebugMonitorService::TargetIO_FileDelete>(),
|
||||||
|
MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_FileMove, &DebugMonitorService::TargetIO_FileMove>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_DirectoryCreate, &DebugMonitorService::TargetIO_DirectoryCreate>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_DirectoryDelete, &DebugMonitorService::TargetIO_DirectoryDelete>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_DirectoryRename, &DebugMonitorService::TargetIO_DirectoryRename>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_DirectoryGetCount, &DebugMonitorService::TargetIO_DirectoryGetCount>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_DirectoryOpen, &DebugMonitorService::TargetIO_DirectoryOpen>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_DirectoryGetNext, &DebugMonitorService::TargetIO_DirectoryGetNext>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_DirectoryClose, &DebugMonitorService::TargetIO_DirectoryClose>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_GetFreeSpace, &DebugMonitorService::TargetIO_GetFreeSpace>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_TargetIO_GetVolumeInformation, &DebugMonitorService::TargetIO_GetVolumeInformation>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_InitiateCoreDump, &DebugMonitorService::InitiateCoreDump>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_ContinueCoreDump, &DebugMonitorService::ContinueCoreDump>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_AddTTYToCoreDump, &DebugMonitorService::AddTTYToCoreDump>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_AddImageToCoreDump, &DebugMonitorService::AddImageToCoreDump>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_CloseCoreDump, &DebugMonitorService::CloseCoreDump>(),
|
||||||
|
// MakeServiceCommandMeta<DebugMonitor_Cmd_CancelAttach, &DebugMonitorService::CancelAttach>(),
|
||||||
|
};
|
||||||
|
};
|
52
stratosphere/dmnt/source/dmnt_service_debug.cpp
Normal file
52
stratosphere/dmnt/source/dmnt_service_debug.cpp
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <switch.h>
|
||||||
|
#include "dmnt_service.hpp"
|
||||||
|
|
||||||
|
Result DebugMonitorService::BreakDebugProcess(Handle debug_hnd) {
|
||||||
|
/* Nintendo discards the output of this command, but we will return it. */
|
||||||
|
return svcBreakDebugProcess(debug_hnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DebugMonitorService::TerminateDebugProcess(Handle debug_hnd) {
|
||||||
|
/* Nintendo discards the output of this command, but we will return it. */
|
||||||
|
return svcTerminateDebugProcess(debug_hnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DebugMonitorService::CloseHandle(Handle debug_hnd) {
|
||||||
|
/* Nintendo discards the output of this command, but we will return it. */
|
||||||
|
/* This command is, entertainingly, also pretty unsafe in general... */
|
||||||
|
return svcCloseHandle(debug_hnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DebugMonitorService::GetProcessId(Out<u64> out_pid, Handle hnd) {
|
||||||
|
/* Nintendo discards the output of this command, but we will return it. */
|
||||||
|
return svcGetProcessId(out_pid.GetPointer(), hnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DebugMonitorService::GetProcessHandle(Out<Handle> out_hnd, u64 pid) {
|
||||||
|
Result rc = svcDebugActiveProcess(out_hnd.GetPointer(), pid);
|
||||||
|
if (rc == 0xF401) {
|
||||||
|
rc = 0x4B7;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DebugMonitorService::WaitSynchronization(Handle hnd, u64 ns) {
|
||||||
|
/* Nintendo discards the output of this command, but we will return it. */
|
||||||
|
return svcWaitSynchronizationSingle(hnd, ns);
|
||||||
|
}
|
299
stratosphere/dmnt/source/dmnt_service_target_io.cpp
Normal file
299
stratosphere/dmnt/source/dmnt_service_target_io.cpp
Normal file
|
@ -0,0 +1,299 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <switch.h>
|
||||||
|
#include "dmnt_service.hpp"
|
||||||
|
|
||||||
|
enum TIOCreateOption : u32 {
|
||||||
|
TIOCreateOption_CreateNew = 1,
|
||||||
|
TIOCreateOption_CreateAlways = 2,
|
||||||
|
TIOCreateOption_OpenExisting = 3,
|
||||||
|
TIOCreateOption_OpenAlways = 4,
|
||||||
|
TIOCreateOption_ResetSize = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Nintendo uses actual pointers as file handles. We'll add a layer of indirection... */
|
||||||
|
static bool g_sd_initialized = false;
|
||||||
|
static HosMutex g_sd_lock;
|
||||||
|
static FsFileSystem g_sd_fs;
|
||||||
|
|
||||||
|
static HosMutex g_file_handle_lock;
|
||||||
|
static u64 g_cur_fd = 0;
|
||||||
|
static std::unordered_map<u64, FsFile> g_file_handles;
|
||||||
|
|
||||||
|
static Result EnsureSdInitialized() {
|
||||||
|
std::scoped_lock<HosMutex> lk(g_sd_lock);
|
||||||
|
if (g_sd_initialized) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result rc = fsMountSdcard(&g_sd_fs);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
g_sd_initialized = true;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64 GetFileHandle(FsFile f) {
|
||||||
|
std::scoped_lock<HosMutex> lk(g_file_handle_lock);
|
||||||
|
|
||||||
|
u64 fd = g_cur_fd++;
|
||||||
|
g_file_handles[fd] = f;
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result GetFileByHandle(FsFile *out, u64 handle) {
|
||||||
|
std::scoped_lock<HosMutex> lk(g_file_handle_lock);
|
||||||
|
if (g_file_handles.find(handle) != g_file_handles.end()) {
|
||||||
|
*out = g_file_handles[handle];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0x2EE202;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result CloseFileByHandle(u64 handle) {
|
||||||
|
std::scoped_lock<HosMutex> lk(g_file_handle_lock);
|
||||||
|
if (g_file_handles.find(handle) != g_file_handles.end()) {
|
||||||
|
fsFileClose(&g_file_handles[handle]);
|
||||||
|
g_file_handles.erase(handle);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0x2EE202;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FixPath(char *dst, size_t dst_size, InBuffer<char> &path) {
|
||||||
|
dst[dst_size - 1] = 0;
|
||||||
|
strncpy(dst, "/", dst_size - 1);
|
||||||
|
|
||||||
|
const char *src = path.buffer;
|
||||||
|
size_t src_idx = 0;
|
||||||
|
size_t dst_idx = 1;
|
||||||
|
while (src_idx < path.num_elements && (src[src_idx] == '/' || src[src_idx] == '\\')) {
|
||||||
|
src_idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (src_idx < path.num_elements && dst_idx < dst_size - 1 && src[src_idx] != 0) {
|
||||||
|
if (src[src_idx] == '\\') {
|
||||||
|
dst[dst_idx] = '/';
|
||||||
|
} else {
|
||||||
|
dst[dst_idx] = src[src_idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
src_idx++;
|
||||||
|
dst_idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dst_idx < dst_size) {
|
||||||
|
dst[dst_idx] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DebugMonitorService::TargetIO_FileOpen(OutBuffer<u64> out_hnd, InBuffer<char> path, int open_mode, u32 create_mode) {
|
||||||
|
if (out_hnd.num_elements != 1) {
|
||||||
|
return 0xF601;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result rc = EnsureSdInitialized();
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
char fs_path[FS_MAX_PATH];
|
||||||
|
FixPath(fs_path, sizeof(fs_path), path);
|
||||||
|
|
||||||
|
if (create_mode == TIOCreateOption_CreateAlways) {
|
||||||
|
fsFsDeleteFile(&g_sd_fs, fs_path);
|
||||||
|
rc = fsFsCreateFile(&g_sd_fs, fs_path, 0, 0);
|
||||||
|
} else if (create_mode == TIOCreateOption_CreateNew) {
|
||||||
|
rc = fsFsCreateFile(&g_sd_fs, fs_path, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
FsFile f;
|
||||||
|
rc = fsFsOpenFile(&g_sd_fs, fs_path, open_mode, &f);
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
if (create_mode == TIOCreateOption_OpenAlways) {
|
||||||
|
fsFsCreateFile(&g_sd_fs, fs_path, 0, 0);
|
||||||
|
rc = fsFsOpenFile(&g_sd_fs, fs_path, open_mode, &f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
if (create_mode == TIOCreateOption_ResetSize) {
|
||||||
|
rc = fsFileSetSize(&f, 0);
|
||||||
|
}
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
out_hnd[0] = GetFileHandle(f);
|
||||||
|
} else {
|
||||||
|
fsFileClose(&f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DebugMonitorService::TargetIO_FileClose(InBuffer<u64> hnd) {
|
||||||
|
if (hnd.num_elements != 1) {
|
||||||
|
return 0xF601;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CloseFileByHandle(hnd[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DebugMonitorService::TargetIO_FileRead(InBuffer<u64> hnd, OutBuffer<u8, BufferType_Type1> out_data, Out<u32> out_read, u64 offset) {
|
||||||
|
if (hnd.num_elements != 1) {
|
||||||
|
return 0xF601;
|
||||||
|
}
|
||||||
|
|
||||||
|
FsFile f;
|
||||||
|
Result rc = GetFileByHandle(&f, hnd[0]);
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t read = 0;
|
||||||
|
rc = fsFileRead(&f, offset, out_data.buffer, out_data.num_elements, &read);
|
||||||
|
out_read.SetValue(static_cast<u32>(read));
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DebugMonitorService::TargetIO_FileWrite(InBuffer<u64> hnd, InBuffer<u8, BufferType_Type1> data, Out<u32> out_written, u64 offset) {
|
||||||
|
if (hnd.num_elements != 1) {
|
||||||
|
return 0xF601;
|
||||||
|
}
|
||||||
|
|
||||||
|
FsFile f;
|
||||||
|
Result rc = GetFileByHandle(&f, hnd[0]);
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = fsFileWrite(&f, offset, data.buffer, data.num_elements);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
out_written.SetValue(data.num_elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DebugMonitorService::TargetIO_FileSetAttributes(InBuffer<char> path, InBuffer<u8> attributes) {
|
||||||
|
/* I don't really know why this command exists, Horizon doesn't allow you to set any attributes. */
|
||||||
|
/* N just returns 0x0 unconditionally here. */
|
||||||
|
return 0x0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DebugMonitorService::TargetIO_FileGetInformation(InBuffer<char> path, OutBuffer<u64> out_info, Out<int> is_directory) {
|
||||||
|
if (out_info.num_elements != 4) {
|
||||||
|
return 0xF601;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result rc = EnsureSdInitialized();
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
char fs_path[FS_MAX_PATH];
|
||||||
|
FixPath(fs_path, sizeof(fs_path), path);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < out_info.num_elements; i++) {
|
||||||
|
out_info[i] = 0;
|
||||||
|
}
|
||||||
|
is_directory.SetValue(0);
|
||||||
|
|
||||||
|
FsFile f;
|
||||||
|
rc = fsFsOpenFile(&g_sd_fs, fs_path, FS_OPEN_READ, &f);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
ON_SCOPE_EXIT { fsFileClose(&f); };
|
||||||
|
|
||||||
|
/* N doesn't check this return code. */
|
||||||
|
fsFileGetSize(&f, &out_info[0]);
|
||||||
|
|
||||||
|
/* TODO: N does not call fsFsGetFileTimestampRaw here, but we possibly could. */
|
||||||
|
} else {
|
||||||
|
FsDir dir;
|
||||||
|
rc = fsFsOpenDirectory(&g_sd_fs, fs_path, FS_DIROPEN_FILE | FS_DIROPEN_DIRECTORY, &dir);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
fsDirClose(&dir);
|
||||||
|
is_directory.SetValue(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DebugMonitorService::TargetIO_FileSetTime(InBuffer<char> path, u64 create, u64 access, u64 modify) {
|
||||||
|
/* This is another function that doesn't really need to exist, because Horizon doesn't let you set anything. */
|
||||||
|
return 0x0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DebugMonitorService::TargetIO_FileSetSize(InBuffer<char> input, u64 size) {
|
||||||
|
/* Why does this function take in a path and not a file handle? */
|
||||||
|
|
||||||
|
/* We will try to be better than N, here. N only treats input as a path. */
|
||||||
|
if (input.num_elements == sizeof(u64)) {
|
||||||
|
FsFile f;
|
||||||
|
if (R_SUCCEEDED(GetFileByHandle(&f, reinterpret_cast<u64 *>(input.buffer)[0]))) {
|
||||||
|
return fsFileSetSize(&f, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result rc = EnsureSdInitialized();
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
char fs_path[FS_MAX_PATH];
|
||||||
|
FixPath(fs_path, sizeof(fs_path), input);
|
||||||
|
|
||||||
|
FsFile f;
|
||||||
|
rc = fsFsOpenFile(&g_sd_fs, fs_path, FS_OPEN_WRITE, &f);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
rc = fsFileSetSize(&f, size);
|
||||||
|
fsFileClose(&f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DebugMonitorService::TargetIO_FileDelete(InBuffer<char> path) {
|
||||||
|
Result rc = EnsureSdInitialized();
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
char fs_path[FS_MAX_PATH];
|
||||||
|
FixPath(fs_path, sizeof(fs_path), path);
|
||||||
|
|
||||||
|
return fsFsDeleteFile(&g_sd_fs, fs_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DebugMonitorService::TargetIO_FileMove(InBuffer<char> path0, InBuffer<char> path1) {
|
||||||
|
Result rc = EnsureSdInitialized();
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
char fs_path0[FS_MAX_PATH];
|
||||||
|
char fs_path1[FS_MAX_PATH];
|
||||||
|
FixPath(fs_path0, sizeof(fs_path0), path0);
|
||||||
|
FixPath(fs_path1, sizeof(fs_path1), path1);
|
||||||
|
|
||||||
|
return fsFsRenameFile(&g_sd_fs, fs_path0, fs_path1);
|
||||||
|
}
|
|
@ -41,6 +41,8 @@ static bool HasLaunchedTitle(Boot2KnownTitleId title_id) {
|
||||||
return std::find(g_boot2_titles.begin(), g_boot2_titles.end(), title_id) != g_boot2_titles.end();
|
return std::find(g_boot2_titles.begin(), g_boot2_titles.end(), title_id) != g_boot2_titles.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<Boot2KnownTitleId> g_launched_titles;
|
||||||
|
|
||||||
static bool IsHexadecimal(const char *str) {
|
static bool IsHexadecimal(const char *str) {
|
||||||
while (*str) {
|
while (*str) {
|
||||||
if (isxdigit(*str)) {
|
if (isxdigit(*str)) {
|
||||||
|
@ -52,8 +54,20 @@ static bool IsHexadecimal(const char *str) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool HasLaunchedTitle(Boot2KnownTitleId title_id) {
|
||||||
|
return std::find(g_launched_titles.begin(), g_launched_titles.end(), title_id) != g_launched_titles.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetLaunchedTitle(Boot2KnownTitleId title_id) {
|
||||||
|
g_launched_titles.push_back(title_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ClearLaunchedTitles() {
|
||||||
|
g_launched_titles.clear();
|
||||||
|
}
|
||||||
|
|
||||||
static void LaunchTitle(Boot2KnownTitleId title_id, FsStorageId storage_id, u32 launch_flags, u64 *pid) {
|
static void LaunchTitle(Boot2KnownTitleId title_id, FsStorageId storage_id, u32 launch_flags, u64 *pid) {
|
||||||
u64 local_pid;
|
u64 local_pid = 0;
|
||||||
|
|
||||||
/* Don't launch a title twice during boot2. */
|
/* Don't launch a title twice during boot2. */
|
||||||
if (HasLaunchedTitle(title_id)) {
|
if (HasLaunchedTitle(title_id)) {
|
||||||
|
@ -64,15 +78,15 @@ static void LaunchTitle(Boot2KnownTitleId title_id, FsStorageId storage_id, u32
|
||||||
switch (rc) {
|
switch (rc) {
|
||||||
case 0xCE01:
|
case 0xCE01:
|
||||||
/* Out of resource! */
|
/* Out of resource! */
|
||||||
/* TODO: Panic(). */
|
std::abort();
|
||||||
break;
|
break;
|
||||||
case 0xDE01:
|
case 0xDE01:
|
||||||
/* Out of memory! */
|
/* Out of memory! */
|
||||||
/* TODO: Panic(). */
|
std::abort();
|
||||||
break;
|
break;
|
||||||
case 0xD001:
|
case 0xD001:
|
||||||
/* Limit Reached! */
|
/* Limit Reached! */
|
||||||
/* TODO: Panic(). */
|
std::abort();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* We don't care about other issues. */
|
/* We don't care about other issues. */
|
||||||
|
@ -235,8 +249,9 @@ void EmbeddedBoot2::Main() {
|
||||||
|
|
||||||
/* Launch usb. */
|
/* Launch usb. */
|
||||||
LaunchTitle(Boot2KnownTitleId::usb, FsStorageId_NandSystem, 0, NULL);
|
LaunchTitle(Boot2KnownTitleId::usb, FsStorageId_NandSystem, 0, NULL);
|
||||||
/* Launch tma. */
|
|
||||||
LaunchTitle(Boot2KnownTitleId::tma, FsStorageId_NandSystem, 0, NULL);
|
/* Launch Atmosphere dmnt, using FsStorageId_None to force SD card boot. */
|
||||||
|
LaunchTitle(Boot2KnownTitleId::dmnt, FsStorageId_None, 0, NULL);
|
||||||
|
|
||||||
/* Launch default programs. */
|
/* Launch default programs. */
|
||||||
for (auto &launch_program : g_additional_launch_programs) {
|
for (auto &launch_program : g_additional_launch_programs) {
|
||||||
|
@ -251,7 +266,10 @@ void EmbeddedBoot2::Main() {
|
||||||
if (titles_dir != NULL) {
|
if (titles_dir != NULL) {
|
||||||
while ((ent = readdir(titles_dir)) != NULL) {
|
while ((ent = readdir(titles_dir)) != NULL) {
|
||||||
if (strlen(ent->d_name) == 0x10 && IsHexadecimal(ent->d_name)) {
|
if (strlen(ent->d_name) == 0x10 && IsHexadecimal(ent->d_name)) {
|
||||||
u64 title_id = strtoul(ent->d_name, NULL, 16);
|
Boot2KnownTitleId title_id = (Boot2KnownTitleId)strtoul(ent->d_name, NULL, 16);
|
||||||
|
if (HasLaunchedTitle(title_id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
char title_path[FS_MAX_PATH] = {0};
|
char title_path[FS_MAX_PATH] = {0};
|
||||||
strcpy(title_path, "sdmc:/atmosphere/titles/");
|
strcpy(title_path, "sdmc:/atmosphere/titles/");
|
||||||
strcat(title_path, ent->d_name);
|
strcat(title_path, ent->d_name);
|
||||||
|
@ -259,7 +277,7 @@ void EmbeddedBoot2::Main() {
|
||||||
FILE *f_flag = fopen(title_path, "rb");
|
FILE *f_flag = fopen(title_path, "rb");
|
||||||
if (f_flag != NULL) {
|
if (f_flag != NULL) {
|
||||||
fclose(f_flag);
|
fclose(f_flag);
|
||||||
LaunchTitle((Boot2KnownTitleId)title_id, FsStorageId_None, 0, NULL);
|
LaunchTitle(title_id, FsStorageId_None, 0, NULL);
|
||||||
} else {
|
} else {
|
||||||
/* TODO: Deprecate this in the future. */
|
/* TODO: Deprecate this in the future. */
|
||||||
memset(title_path, 0, FS_MAX_PATH);
|
memset(title_path, 0, FS_MAX_PATH);
|
||||||
|
@ -269,13 +287,16 @@ void EmbeddedBoot2::Main() {
|
||||||
f_flag = fopen(title_path, "rb");
|
f_flag = fopen(title_path, "rb");
|
||||||
if (f_flag != NULL) {
|
if (f_flag != NULL) {
|
||||||
fclose(f_flag);
|
fclose(f_flag);
|
||||||
LaunchTitle((Boot2KnownTitleId)title_id, FsStorageId_None, 0, NULL);
|
LaunchTitle(title_id, FsStorageId_None, 0, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closedir(titles_dir);
|
closedir(titles_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Free the memory used to track what boot2 launches. */
|
||||||
|
ClearLaunchedTitles();
|
||||||
|
|
||||||
/* We no longer need the SD card. */
|
/* We no longer need the SD card. */
|
||||||
fsdevUnmountAll();
|
fsdevUnmountAll();
|
||||||
|
|
Loading…
Reference in a new issue