dmnt: pull in from ams.tma branch

This commit is contained in:
Michael Scire 2019-02-27 01:44:47 -08:00
commit 89503049b3
9 changed files with 957 additions and 10 deletions

View file

@ -54,6 +54,7 @@ dist: all
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000034
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032
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)/sept/payload.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
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/flags
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 ../;
rm -r atmosphere-$(AMSVER)
mkdir out

View file

@ -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)

166
stratosphere/dmnt/Makefile Normal file
View 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
View 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
}]
}

View 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;
}

View 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>(),
};
};

View 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);
}

View 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);
}

View file

@ -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();
}
static std::vector<Boot2KnownTitleId> g_launched_titles;
static bool IsHexadecimal(const char *str) {
while (*str) {
if (isxdigit(*str)) {
@ -52,8 +54,20 @@ static bool IsHexadecimal(const char *str) {
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) {
u64 local_pid;
u64 local_pid = 0;
/* Don't launch a title twice during boot2. */
if (HasLaunchedTitle(title_id)) {
@ -64,15 +78,15 @@ static void LaunchTitle(Boot2KnownTitleId title_id, FsStorageId storage_id, u32
switch (rc) {
case 0xCE01:
/* Out of resource! */
/* TODO: Panic(). */
std::abort();
break;
case 0xDE01:
/* Out of memory! */
/* TODO: Panic(). */
std::abort();
break;
case 0xD001:
/* Limit Reached! */
/* TODO: Panic(). */
std::abort();
break;
default:
/* We don't care about other issues. */
@ -235,8 +249,9 @@ void EmbeddedBoot2::Main() {
/* Launch usb. */
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. */
for (auto &launch_program : g_additional_launch_programs) {
@ -251,7 +266,10 @@ void EmbeddedBoot2::Main() {
if (titles_dir != NULL) {
while ((ent = readdir(titles_dir)) != NULL) {
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};
strcpy(title_path, "sdmc:/atmosphere/titles/");
strcat(title_path, ent->d_name);
@ -259,7 +277,7 @@ void EmbeddedBoot2::Main() {
FILE *f_flag = fopen(title_path, "rb");
if (f_flag != NULL) {
fclose(f_flag);
LaunchTitle((Boot2KnownTitleId)title_id, FsStorageId_None, 0, NULL);
LaunchTitle(title_id, FsStorageId_None, 0, NULL);
} else {
/* TODO: Deprecate this in the future. */
memset(title_path, 0, FS_MAX_PATH);
@ -269,13 +287,16 @@ void EmbeddedBoot2::Main() {
f_flag = fopen(title_path, "rb");
if (f_flag != NULL) {
fclose(f_flag);
LaunchTitle((Boot2KnownTitleId)title_id, FsStorageId_None, 0, NULL);
LaunchTitle(title_id, FsStorageId_None, 0, NULL);
}
}
}
}
closedir(titles_dir);
}
/* Free the memory used to track what boot2 launches. */
ClearLaunchedTitles();
/* We no longer need the SD card. */
fsdevUnmountAll();