mirror of
https://github.com/ITotalJustice/sys-patch.git
synced 2025-01-07 05:08:11 +01:00
add overlay, fix es 14.0.0-14.1.2 patches, fix b_patch, add logging
This commit is contained in:
parent
5d62cf2cdb
commit
7d2a332bdd
2
.github/workflows/build_depoly.yml
vendored
2
.github/workflows/build_depoly.yml
vendored
@ -9,6 +9,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout 🛎️
|
- name: Checkout 🛎️
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@master
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: make dist -j2
|
run: make dist -j2
|
||||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,6 +1,6 @@
|
|||||||
.vscode
|
|
||||||
build
|
build
|
||||||
Firmware
|
Firmware
|
||||||
|
firmware
|
||||||
420000000000000B
|
420000000000000B
|
||||||
*.txt
|
*.txt
|
||||||
*.elf
|
*.elf
|
||||||
@ -8,5 +8,9 @@ Firmware
|
|||||||
*.nso
|
*.nso
|
||||||
*.nsp
|
*.nsp
|
||||||
*.zip
|
*.zip
|
||||||
|
*.nacp
|
||||||
|
*.ovl
|
||||||
|
*.nca
|
||||||
out
|
out
|
||||||
ignoreme
|
ignoreme
|
||||||
|
.vscode/settings.json
|
||||||
|
4
.gitmodules
vendored
Normal file
4
.gitmodules
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[submodule "overlay/libtesla"]
|
||||||
|
path = overlay/libtesla
|
||||||
|
url = https://github.com/ITotalJustice/libtesla.git
|
||||||
|
branch = tj
|
20
.vscode/c_cpp_properties.json
vendored
Normal file
20
.vscode/c_cpp_properties.json
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "switch",
|
||||||
|
"includePath": [
|
||||||
|
"${default}",
|
||||||
|
"${workspaceFolder}/**",
|
||||||
|
"${DEVKITPRO}/libnx/include/",
|
||||||
|
"${DEVKITPRO}/portlibs/switch/include/",
|
||||||
|
"${workspaceFolder}/overlay/libtesla/include",
|
||||||
|
"${workspaceFolder}/common"
|
||||||
|
],
|
||||||
|
"defines": [],
|
||||||
|
"cStandard": "c17",
|
||||||
|
"cppStandard": "c++23",
|
||||||
|
"compilerPath": "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-gcc"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
236
Makefile
236
Makefile
@ -1,233 +1,23 @@
|
|||||||
#---------------------------------------------------------------------------------
|
MAKEFILES := sysmod overlay
|
||||||
.SUFFIXES:
|
TARGETS := $(foreach dir,$(MAKEFILES),$(CURDIR)/$(dir))
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
ifeq ($(strip $(DEVKITPRO)),)
|
all: $(TARGETS)
|
||||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
@mkdir -p out/
|
||||||
endif
|
@cp -R sysmod/out/* out/
|
||||||
|
@cp -R overlay/out/* out/
|
||||||
|
|
||||||
TOPDIR ?= $(CURDIR)
|
.PHONY: $(TARGETS)
|
||||||
include $(DEVKITPRO)/libnx/switch_rules
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
$(TARGETS):
|
||||||
# TARGET is the name of the output
|
@$(MAKE) -C $@
|
||||||
# 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
|
|
||||||
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
|
|
||||||
#
|
|
||||||
# NO_ICON: if set to anything, do not use icon.
|
|
||||||
# NO_NACP: if set to anything, no .nacp file is generated.
|
|
||||||
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
|
|
||||||
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
|
|
||||||
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
|
|
||||||
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
|
|
||||||
# ICON is the filename of the icon (.jpg), relative to the project folder.
|
|
||||||
# If not set, it attempts to use one of the following (in this order):
|
|
||||||
# - <Project name>.jpg
|
|
||||||
# - icon.jpg
|
|
||||||
# - <libnx folder>/default_icon.jpg
|
|
||||||
#
|
|
||||||
# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder.
|
|
||||||
# If not set, it attempts to use one of the following (in this order):
|
|
||||||
# - <Project name>.json
|
|
||||||
# - config.json
|
|
||||||
# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead
|
|
||||||
# of a homebrew executable (.nro). This is intended to be used for sysmodules.
|
|
||||||
# NACP building is skipped as well.
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
TARGET := sys-patch
|
|
||||||
BUILD := build
|
|
||||||
SOURCES := src src/minIni
|
|
||||||
DATA := data
|
|
||||||
INCLUDES := include
|
|
||||||
#ROMFS := romfs
|
|
||||||
|
|
||||||
# sys-patch
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# options for code generation
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
|
||||||
|
|
||||||
CFLAGS := -g -Wall -O2 -ffunction-sections \
|
|
||||||
$(ARCH) $(DEFINES)
|
|
||||||
|
|
||||||
CFLAGS += $(INCLUDE) -D__SWITCH__
|
|
||||||
|
|
||||||
CXXFLAGS := $(CFLAGS) -std=c++23 -fno-rtti -fno-exceptions
|
|
||||||
|
|
||||||
ASFLAGS := -g $(ARCH)
|
|
||||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
|
||||||
|
|
||||||
LIBS := -lnx
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# list of directories containing libraries, this must be the top level containing
|
|
||||||
# include and lib
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
LIBDIRS := $(PORTLIBS) $(LIBNX)
|
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# 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_BIN := $(addsuffix .o,$(BINFILES))
|
|
||||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
|
||||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
|
||||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
ifeq ($(strip $(ICON)),)
|
|
||||||
icons := $(wildcard *.jpg)
|
|
||||||
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
|
|
||||||
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
|
|
||||||
else
|
|
||||||
ifneq (,$(findstring icon.jpg,$(icons)))
|
|
||||||
export APP_ICON := $(TOPDIR)/icon.jpg
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
export APP_ICON := $(TOPDIR)/$(ICON)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(strip $(NO_ICON)),)
|
|
||||||
export NROFLAGS += --icon=$(APP_ICON)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(strip $(NO_NACP)),)
|
|
||||||
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifneq ($(APP_TITLEID),)
|
|
||||||
export NACPFLAGS += --titleid=$(APP_TITLEID)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifneq ($(ROMFS),)
|
|
||||||
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
.PHONY: $(BUILD) clean all
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
all: $(BUILD)
|
|
||||||
|
|
||||||
$(BUILD):
|
|
||||||
@[ -d $@ ] || mkdir -p $@
|
|
||||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
|
||||||
|
|
||||||
@rm -rf out/
|
|
||||||
@mkdir -p out/atmosphere/contents/420000000000000B/flags
|
|
||||||
@touch out/atmosphere/contents/420000000000000B/flags/boot2.flag
|
|
||||||
@cp $(CURDIR)/toolbox.json out/atmosphere/contents/420000000000000B/toolbox.json
|
|
||||||
@cp $(CURDIR)/$(TARGET).nsp out/atmosphere/contents/420000000000000B/exefs.nsp
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
clean:
|
clean:
|
||||||
@echo clean ...
|
@rm -rf out
|
||||||
ifeq ($(strip $(APP_JSON)),)
|
@for i in $(TARGETS); do $(MAKE) -C $$i clean || exit 1; done;
|
||||||
@rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
|
|
||||||
else
|
|
||||||
@rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf
|
|
||||||
endif
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
dist: all
|
dist: all
|
||||||
|
@for i in $(TARGETS); do $(MAKE) -C $$i dist || exit 1; done;
|
||||||
@echo making dist ...
|
@echo making dist ...
|
||||||
|
|
||||||
@rm -f sys-patch.zip
|
@rm -f sys-patch.zip
|
||||||
@cd out; zip -r ../sys-patch.zip ./*; cd ../
|
@cd out; zip -r ../sys-patch.zip ./*; cd ../
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
else
|
|
||||||
.PHONY: all
|
|
||||||
|
|
||||||
DEPENDS := $(OFILES:.o=.d)
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# main targets
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
ifeq ($(strip $(APP_JSON)),)
|
|
||||||
|
|
||||||
all : $(OUTPUT).nro
|
|
||||||
|
|
||||||
ifeq ($(strip $(NO_NACP)),)
|
|
||||||
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
|
|
||||||
else
|
|
||||||
$(OUTPUT).nro : $(OUTPUT).elf
|
|
||||||
endif
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
all : $(OUTPUT).nsp
|
|
||||||
|
|
||||||
$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm
|
|
||||||
|
|
||||||
$(OUTPUT).nso : $(OUTPUT).elf
|
|
||||||
|
|
||||||
endif
|
|
||||||
|
|
||||||
$(OUTPUT).elf : $(OFILES)
|
|
||||||
|
|
||||||
$(OFILES_SRC) : $(HFILES_BIN)
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# you need a rule like this for each extension you use as binary data
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
%.bin.o %_bin.h : %.bin
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
@echo $(notdir $<)
|
|
||||||
@$(bin2o)
|
|
||||||
|
|
||||||
-include $(DEPENDS)
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------------
|
|
||||||
endif
|
|
||||||
#---------------------------------------------------------------------------------------
|
|
||||||
|
24
README.md
24
README.md
@ -6,25 +6,41 @@ A script-like system module that patches fs, es and ldr on boot.
|
|||||||
|
|
||||||
## Config
|
## Config
|
||||||
|
|
||||||
sys-patch features a *very* simple config, only 2 options so far and they both do the same thing :p
|
sys-patch features a simple config. This can be manually editied or updated using the overlay.
|
||||||
|
|
||||||
this config file can be found in `/config/sys-patch/config.ini`, if the file does not exist, the file will be created when sys-patch is run.
|
the config file can be found in `/config/sys-patch/config.ini`, if the file does not exist, the file will be created when sys-patch is run.
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
[options]
|
[options]
|
||||||
patch_sysmmc=1 ; 1=(default) patch sysmmc, 0=don't patch sysmmc
|
patch_sysmmc=1 ; 1=(default) patch sysmmc, 0=don't patch sysmmc
|
||||||
patch_emummc=1 ; 1=(default) patch emummc, 0=don't patch emummc
|
patch_emummc=1 ; 1=(default) patch emummc, 0=don't patch emummc
|
||||||
|
logging=1 ; 1=(default) output /config/sys-patch/log.inim 0=no log
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Overlay
|
||||||
|
|
||||||
|
the overlay can be used to change the config options and to see what patches are applied (if any).
|
||||||
|
|
||||||
|
- Unpatched means the patch wasn't applied (likely not found).
|
||||||
|
- Patched (green) means it was patched by sys-patch.
|
||||||
|
- Patched (yellow) means it was already patched, likely by sigpatches or a custom atmosphere build.
|
||||||
|
|
||||||
|
<p float="left">
|
||||||
|
<img src="https://i.imgur.com/IlTkkYM.jpg" width="400" />
|
||||||
|
<img src="https://i.imgur.com/T4K5u5f.jpg" width="400" />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
### prerequisites
|
### prerequisites
|
||||||
- install devkitpro
|
- install devkitpro
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone https://github.com/ITotalJustice/sys-patch.git
|
git clone --recurse-submodules https://github.com/ITotalJustice/sys-patch.git
|
||||||
cd sys-patch
|
cd sys-patch
|
||||||
make
|
make
|
||||||
```
|
```
|
||||||
@ -77,7 +93,6 @@ This repo is mainly a proof of concept. I would love for someone to build upon t
|
|||||||
|
|
||||||
here are a few ideas that i have:
|
here are a few ideas that i have:
|
||||||
- option to load new patterns from file
|
- option to load new patterns from file
|
||||||
- make this into a service / overlay
|
|
||||||
- make homebrew frontend that can update this sysmod, apply patches, all without having to reboot
|
- make homebrew frontend that can update this sysmod, apply patches, all without having to reboot
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -97,3 +112,4 @@ software is built on the shoulders of giants. this tool wouldn't be possible wth
|
|||||||
- Switchbrew (libnx, switch-examples)
|
- Switchbrew (libnx, switch-examples)
|
||||||
- DevkitPro (toolchain)
|
- DevkitPro (toolchain)
|
||||||
- [minIni](https://github.com/compuphase/minIni)
|
- [minIni](https://github.com/compuphase/minIni)
|
||||||
|
- [libtesla](https://github.com/WerWolv/libtesla)
|
||||||
|
@ -46,7 +46,6 @@ bool ini_openrewrite(const char* filename, struct NxFile* nxfile) {
|
|||||||
|
|
||||||
bool ini_close(struct NxFile* nxfile) {
|
bool ini_close(struct NxFile* nxfile) {
|
||||||
fsFileClose(&nxfile->file);
|
fsFileClose(&nxfile->file);
|
||||||
fsFsCommit(&nxfile->system);
|
|
||||||
fsFsClose(&nxfile->system);
|
fsFsClose(&nxfile->system);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
@ -16,7 +16,6 @@ struct NxFile {
|
|||||||
#define INI_FILEPOS s64
|
#define INI_FILEPOS s64
|
||||||
#define INI_OPENREWRITE
|
#define INI_OPENREWRITE
|
||||||
#define INI_REMOVE
|
#define INI_REMOVE
|
||||||
#define INI_NOBROWSE
|
|
||||||
|
|
||||||
bool ini_openread(const char* filename, struct NxFile* nxfile);
|
bool ini_openread(const char* filename, struct NxFile* nxfile);
|
||||||
bool ini_openwrite(const char* filename, struct NxFile* nxfile);
|
bool ini_openwrite(const char* filename, struct NxFile* nxfile);
|
225
overlay/Makefile
Normal file
225
overlay/Makefile
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.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
|
||||||
|
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
|
||||||
|
#
|
||||||
|
# NO_ICON: if set to anything, do not use icon.
|
||||||
|
# NO_NACP: if set to anything, no .nacp file is generated.
|
||||||
|
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
|
||||||
|
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
|
||||||
|
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
|
||||||
|
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
|
||||||
|
# ICON is the filename of the icon (.jpg), relative to the project folder.
|
||||||
|
# If not set, it attempts to use one of the following (in this order):
|
||||||
|
# - <Project name>.jpg
|
||||||
|
# - icon.jpg
|
||||||
|
# - <libnx folder>/default_icon.jpg
|
||||||
|
#
|
||||||
|
# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder.
|
||||||
|
# If not set, it attempts to use one of the following (in this order):
|
||||||
|
# - <Project name>.json
|
||||||
|
# - config.json
|
||||||
|
# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead
|
||||||
|
# of a homebrew executable (.nro). This is intended to be used for sysmodules.
|
||||||
|
# NACP building is skipped as well.
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
APP_TITLE := sys-patch
|
||||||
|
APP_AUTHOR := TotalJustice
|
||||||
|
APP_VERSION := 1.2.0
|
||||||
|
|
||||||
|
TARGET := sys-patch-overlay
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := src ../common/minIni
|
||||||
|
DATA := data
|
||||||
|
INCLUDES := include ../common libtesla/include
|
||||||
|
|
||||||
|
NO_ICON := 1
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
||||||
|
|
||||||
|
CFLAGS := -g -Wall -O2 -ffunction-sections \
|
||||||
|
$(ARCH) $(DEFINES)
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE) -D__SWITCH__
|
||||||
|
|
||||||
|
CXXFLAGS := $(CFLAGS) -std=c++23 -fno-exceptions
|
||||||
|
|
||||||
|
ASFLAGS := -g $(ARCH)
|
||||||
|
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||||
|
|
||||||
|
LIBS := -lnx
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
# include and lib
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(PORTLIBS) $(LIBNX)
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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_BIN := $(addsuffix .o,$(BINFILES))
|
||||||
|
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||||
|
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||||
|
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ifeq ($(strip $(ICON)),)
|
||||||
|
icons := $(wildcard *.jpg)
|
||||||
|
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
|
||||||
|
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
|
||||||
|
else
|
||||||
|
ifneq (,$(findstring icon.jpg,$(icons)))
|
||||||
|
export APP_ICON := $(TOPDIR)/icon.jpg
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
export APP_ICON := $(TOPDIR)/$(ICON)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(strip $(NO_ICON)),)
|
||||||
|
export NROFLAGS += --icon=$(APP_ICON)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(strip $(NO_NACP)),)
|
||||||
|
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(APP_TITLEID),)
|
||||||
|
export NACPFLAGS += --titleid=$(APP_TITLEID)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(ROMFS),)
|
||||||
|
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean all
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all: $(BUILD)
|
||||||
|
|
||||||
|
|
||||||
|
$(BUILD):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
@mkdir -p out/switch/.overlays
|
||||||
|
@cp $(CURDIR)/$(TARGET).ovl out/switch/.overlays/
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) $(TARGET).ovl $(TARGET).nro $(TARGET).nacp $(TARGET).elf
|
||||||
|
@rm -rf out/
|
||||||
|
@rm -f sys-patch-overlay.zip
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ftp: all
|
||||||
|
@echo making dist ...
|
||||||
|
curl -T sys-patch-overlay.ovl ftp://192.168.200.71:5000/switch/.overlays/ --user tj:12345678
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
dist: all
|
||||||
|
@echo making dist ...
|
||||||
|
|
||||||
|
@rm -f sys-patch-overlay.zip
|
||||||
|
@cd out; zip -r ../sys-patch-overlay.zip ./*; cd ../
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
.PHONY: all
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all : $(OUTPUT).ovl
|
||||||
|
|
||||||
|
$(OUTPUT).ovl : $(OUTPUT).elf $(OUTPUT).nacp
|
||||||
|
@elf2nro $< $@ $(NROFLAGS)
|
||||||
|
@echo "built ... $(notdir $(OUTPUT).ovl)"
|
||||||
|
|
||||||
|
$(OUTPUT).elf : $(OFILES)
|
||||||
|
|
||||||
|
$(OFILES_SRC) : $(HFILES_BIN)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.bin.o %_bin.h : %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
1
overlay/libtesla
Submodule
1
overlay/libtesla
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 3d74aeb31f0f26cf222d406c7ea118a82cc8ee69
|
149
overlay/src/main.cpp
Normal file
149
overlay/src/main.cpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
#define TESLA_INIT_IMPL // If you have more than one file using the tesla header, only define this in the main one
|
||||||
|
#include <tesla.hpp> // The Tesla Header
|
||||||
|
#include <string_view>
|
||||||
|
#include "minIni/minIni.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto CONFIG_PATH = "/config/sys-patch/config.ini";
|
||||||
|
constexpr auto LOG_PATH = "/config/sys-patch/log.ini";
|
||||||
|
|
||||||
|
auto does_file_exist(const char* path) -> bool {
|
||||||
|
Result rc{};
|
||||||
|
FsFileSystem fs{};
|
||||||
|
FsFile file{};
|
||||||
|
char path_buf[FS_MAX_PATH]{};
|
||||||
|
|
||||||
|
if (R_FAILED(fsOpenSdCardFileSystem(&fs))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(path_buf, path);
|
||||||
|
rc = fsFsOpenFile(&fs, path_buf, FsOpenMode_Read, &file);
|
||||||
|
fsFileClose(&file);
|
||||||
|
fsFsClose(&fs);
|
||||||
|
return R_SUCCEEDED(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates a directory, non-recursive!
|
||||||
|
auto create_dir(const char* path) -> bool {
|
||||||
|
Result rc{};
|
||||||
|
FsFileSystem fs{};
|
||||||
|
char path_buf[FS_MAX_PATH]{};
|
||||||
|
|
||||||
|
if (R_FAILED(fsOpenSdCardFileSystem(&fs))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(path_buf, path);
|
||||||
|
rc = fsFsCreateDirectory(&fs, path_buf);
|
||||||
|
fsFsClose(&fs);
|
||||||
|
return R_SUCCEEDED(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ConfigEntry {
|
||||||
|
const char* const section;
|
||||||
|
const char* const key;
|
||||||
|
bool value;
|
||||||
|
|
||||||
|
ConfigEntry(const char* _section, const char* _key, bool default_value) :
|
||||||
|
section{_section}, key{_key}, value{default_value} {}
|
||||||
|
|
||||||
|
void load_value_from_ini() {
|
||||||
|
this->value = ini_getbool(this->section, this->key, this->value, CONFIG_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto create_list_item(const char* text) {
|
||||||
|
auto item = new tsl::elm::ToggleListItem(text, value);
|
||||||
|
item->setStateChangedListener([this](bool new_value){
|
||||||
|
this->value = new_value;
|
||||||
|
ini_putl(this->section, this->key, this->value, CONFIG_PATH);
|
||||||
|
});
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class GuiMain final : public tsl::Gui {
|
||||||
|
public:
|
||||||
|
GuiMain() { }
|
||||||
|
|
||||||
|
// Called when this Gui gets loaded to create the UI
|
||||||
|
// Allocate all elements on the heap. libtesla will make sure to clean them up when not needed anymore
|
||||||
|
tsl::elm::Element* createUI() override {
|
||||||
|
create_dir("/config/");
|
||||||
|
create_dir("/config/sys-patch/");
|
||||||
|
|
||||||
|
config_patch_sysmmc.load_value_from_ini();
|
||||||
|
config_patch_emummc.load_value_from_ini();
|
||||||
|
config_logging.load_value_from_ini();
|
||||||
|
|
||||||
|
auto frame = new tsl::elm::OverlayFrame("sys-patch", "v1.2.0");
|
||||||
|
auto list = new tsl::elm::List();
|
||||||
|
|
||||||
|
list->addItem(new tsl::elm::CategoryHeader("Options"));
|
||||||
|
list->addItem(config_patch_sysmmc.create_list_item("Patch SysMMC"));
|
||||||
|
list->addItem(config_patch_emummc.create_list_item("Patch EmuMMC"));
|
||||||
|
list->addItem(config_logging.create_list_item("Logging"));
|
||||||
|
|
||||||
|
if (does_file_exist(LOG_PATH)) {
|
||||||
|
struct CallbackUser {
|
||||||
|
tsl::elm::List* list;
|
||||||
|
std::string last_section;
|
||||||
|
} callback_userdata{list};
|
||||||
|
|
||||||
|
ini_browse([](const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, void *UserData){
|
||||||
|
auto user = (CallbackUser*)UserData;
|
||||||
|
if (!std::strcmp("Skipped", Value)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user->last_section != Section) {
|
||||||
|
user->last_section = Section;
|
||||||
|
user->list->addItem(new tsl::elm::CategoryHeader("Log: " + user->last_section));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define F(x) ((x) >> 4) // 8bit -> 4bit
|
||||||
|
constexpr tsl::Color colour_syspatch{F(0), F(255), F(200), F(255)};
|
||||||
|
constexpr tsl::Color colour_file{F(255), F(177), F(66), F(255)};
|
||||||
|
constexpr tsl::Color colour_unpatched{F(250), F(90), F(58), F(255)};
|
||||||
|
#undef F
|
||||||
|
|
||||||
|
std::string_view value{Value};
|
||||||
|
if (value.starts_with("Patched")) {
|
||||||
|
if (value.ends_with("(sys-patch)")) {
|
||||||
|
user->list->addItem(new tsl::elm::ListItem(Key, "Patched", colour_syspatch));
|
||||||
|
} else {
|
||||||
|
user->list->addItem(new tsl::elm::ListItem(Key, "Patched", colour_file));
|
||||||
|
}
|
||||||
|
} else if (value.starts_with("Unpatched")) {
|
||||||
|
user->list->addItem(new tsl::elm::ListItem(Key, Value, colour_unpatched));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}, &callback_userdata, LOG_PATH);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->setContent(list);
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigEntry config_patch_sysmmc{"options", "patch_sysmmc", true};
|
||||||
|
ConfigEntry config_patch_emummc{"options", "patch_emummc", true};
|
||||||
|
ConfigEntry config_logging{"options", "patch_logging", true};
|
||||||
|
};
|
||||||
|
|
||||||
|
// libtesla already initialized fs, hid, pl, pmdmnt, hid:sys and set:sys
|
||||||
|
class SysPatchOverlay final : public tsl::Overlay {
|
||||||
|
public:
|
||||||
|
std::unique_ptr<tsl::Gui> loadInitialGui() override {
|
||||||
|
return initially<GuiMain>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
return tsl::loop<SysPatchOverlay>(argc, argv);
|
||||||
|
}
|
236
sysmod/Makefile
Normal file
236
sysmod/Makefile
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.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
|
||||||
|
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
|
||||||
|
#
|
||||||
|
# NO_ICON: if set to anything, do not use icon.
|
||||||
|
# NO_NACP: if set to anything, no .nacp file is generated.
|
||||||
|
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
|
||||||
|
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
|
||||||
|
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
|
||||||
|
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
|
||||||
|
# ICON is the filename of the icon (.jpg), relative to the project folder.
|
||||||
|
# If not set, it attempts to use one of the following (in this order):
|
||||||
|
# - <Project name>.jpg
|
||||||
|
# - icon.jpg
|
||||||
|
# - <libnx folder>/default_icon.jpg
|
||||||
|
#
|
||||||
|
# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder.
|
||||||
|
# If not set, it attempts to use one of the following (in this order):
|
||||||
|
# - <Project name>.json
|
||||||
|
# - config.json
|
||||||
|
# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead
|
||||||
|
# of a homebrew executable (.nro). This is intended to be used for sysmodules.
|
||||||
|
# NACP building is skipped as well.
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
TARGET := sys-patch
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := src ../common/minIni
|
||||||
|
DATA := data
|
||||||
|
INCLUDES := include ../common
|
||||||
|
#ROMFS := romfs
|
||||||
|
|
||||||
|
# sys-patch
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
||||||
|
|
||||||
|
CFLAGS := -g -Wall -O2 -ffunction-sections \
|
||||||
|
$(ARCH) $(DEFINES)
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE) -D__SWITCH__
|
||||||
|
|
||||||
|
CXXFLAGS := $(CFLAGS) -std=c++23 -fno-rtti -fno-exceptions
|
||||||
|
|
||||||
|
ASFLAGS := -g $(ARCH)
|
||||||
|
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||||
|
|
||||||
|
LIBS := -lnx
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
# include and lib
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(PORTLIBS) $(LIBNX)
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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_BIN := $(addsuffix .o,$(BINFILES))
|
||||||
|
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||||
|
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||||
|
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ifeq ($(strip $(ICON)),)
|
||||||
|
icons := $(wildcard *.jpg)
|
||||||
|
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
|
||||||
|
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
|
||||||
|
else
|
||||||
|
ifneq (,$(findstring icon.jpg,$(icons)))
|
||||||
|
export APP_ICON := $(TOPDIR)/icon.jpg
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
export APP_ICON := $(TOPDIR)/$(ICON)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(strip $(NO_ICON)),)
|
||||||
|
export NROFLAGS += --icon=$(APP_ICON)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(strip $(NO_NACP)),)
|
||||||
|
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(APP_TITLEID),)
|
||||||
|
export NACPFLAGS += --titleid=$(APP_TITLEID)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(ROMFS),)
|
||||||
|
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean all
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all: $(BUILD)
|
||||||
|
|
||||||
|
$(BUILD):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
@rm -rf out/
|
||||||
|
@mkdir -p out/atmosphere/contents/420000000000000B/flags
|
||||||
|
@touch out/atmosphere/contents/420000000000000B/flags/boot2.flag
|
||||||
|
@cp $(CURDIR)/toolbox.json out/atmosphere/contents/420000000000000B/toolbox.json
|
||||||
|
@cp $(CURDIR)/$(TARGET).nsp out/atmosphere/contents/420000000000000B/exefs.nsp
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
ifeq ($(strip $(APP_JSON)),)
|
||||||
|
@rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
|
||||||
|
else
|
||||||
|
@rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf
|
||||||
|
endif
|
||||||
|
@rm -rf out/
|
||||||
|
@rm -f sys-patch.zip
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
dist: all
|
||||||
|
@echo making dist ...
|
||||||
|
|
||||||
|
@rm -f sys-patch-no-overlay.zip
|
||||||
|
@cd out; zip -r ../sys-patch-no-overlay.zip ./*; cd ../
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
.PHONY: all
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(APP_JSON)),)
|
||||||
|
|
||||||
|
all : $(OUTPUT).nro
|
||||||
|
|
||||||
|
ifeq ($(strip $(NO_NACP)),)
|
||||||
|
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
|
||||||
|
else
|
||||||
|
$(OUTPUT).nro : $(OUTPUT).elf
|
||||||
|
endif
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
all : $(OUTPUT).nsp
|
||||||
|
|
||||||
|
$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm
|
||||||
|
|
||||||
|
$(OUTPUT).nso : $(OUTPUT).elf
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(OUTPUT).elf : $(OFILES)
|
||||||
|
|
||||||
|
$(OFILES_SRC) : $(HFILES_BIN)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.bin.o %_bin.h : %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
@ -2,6 +2,7 @@
|
|||||||
#include <span>
|
#include <span>
|
||||||
#include <algorithm> // for min
|
#include <algorithm> // for min
|
||||||
#include <bit> // for byteswap
|
#include <bit> // for byteswap
|
||||||
|
#include <utility> // std::unreachable
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include "minIni/minIni.h"
|
#include "minIni/minIni.h"
|
||||||
|
|
||||||
@ -69,28 +70,39 @@ struct PatchData {
|
|||||||
u8 size;
|
u8 size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class PatchedResult {
|
||||||
|
NOT_FOUND,
|
||||||
|
SKIPPED,
|
||||||
|
PATCHED_FILE,
|
||||||
|
PATCHED_SYSPATCH,
|
||||||
|
FAILED_WRITE,
|
||||||
|
};
|
||||||
|
|
||||||
struct Patterns {
|
struct Patterns {
|
||||||
const char* patch_name; // name of patch
|
const char* patch_name; // name of patch
|
||||||
PatternData byte_pattern; // the pattern to search
|
const PatternData byte_pattern; // the pattern to search
|
||||||
|
|
||||||
s32 inst_offset; // instruction offset relative to byte pattern
|
const s32 inst_offset; // instruction offset relative to byte pattern
|
||||||
s32 patch_offset; // patch offset relative to inst_offset
|
const s32 patch_offset; // patch offset relative to inst_offset
|
||||||
|
|
||||||
bool (*cond)(u32 inst); // check condtion of the instruction
|
bool (*const cond)(u32 inst); // check condition of the instruction
|
||||||
PatchData (*patch)(u32 inst); // the patch data to be applied
|
PatchData (*const patch)(u32 inst); // the patch data to be applied
|
||||||
|
bool (*const applied)(u32 inst); // check to see if patch already applied
|
||||||
|
|
||||||
u32 min_fw_ver{FW_VER_ANY}; // set to FW_VER_ANY to ignore
|
const u32 min_fw_ver{FW_VER_ANY}; // set to FW_VER_ANY to ignore
|
||||||
u32 max_fw_ver{FW_VER_ANY}; // set to FW_VER_ANY to ignore
|
const u32 max_fw_ver{FW_VER_ANY}; // set to FW_VER_ANY to ignore
|
||||||
u32 min_ams_ver{FW_VER_ANY}; // set to FW_VER_ANY to ignore
|
const u32 min_ams_ver{FW_VER_ANY}; // set to FW_VER_ANY to ignore
|
||||||
u32 max_ams_ver{FW_VER_ANY}; // set to FW_VER_ANY to ignore
|
const u32 max_ams_ver{FW_VER_ANY}; // set to FW_VER_ANY to ignore
|
||||||
|
|
||||||
|
PatchedResult result{PatchedResult::NOT_FOUND};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PatchEntry {
|
struct PatchEntry {
|
||||||
const char* name; // name of the system title
|
const char* name; // name of the system title
|
||||||
u64 title_id; // title id of the system title
|
const u64 title_id; // title id of the system title
|
||||||
std::span<const Patterns> patterns; // list of patterns to find
|
const std::span<Patterns> patterns; // list of patterns to find
|
||||||
u32 min_fw_ver{FW_VER_ANY}; // set to FW_VER_ANY to ignore
|
const u32 min_fw_ver{FW_VER_ANY}; // set to FW_VER_ANY to ignore
|
||||||
u32 max_fw_ver{FW_VER_ANY}; // set to FW_VER_ANY to ignore
|
const u32 max_fw_ver{FW_VER_ANY}; // set to FW_VER_ANY to ignore
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr auto subi_cond(u32 inst) -> bool {
|
constexpr auto subi_cond(u32 inst) -> bool {
|
||||||
@ -122,15 +134,19 @@ constexpr auto subs_cond(u32 inst) -> bool {
|
|||||||
constexpr auto cbz_cond(u32 inst) -> bool {
|
constexpr auto cbz_cond(u32 inst) -> bool {
|
||||||
const auto type = inst >> 24;
|
const auto type = inst >> 24;
|
||||||
return type == 0x34 || type == 0xB4;
|
return type == 0x34 || type == 0xB4;
|
||||||
};
|
}
|
||||||
|
|
||||||
constexpr auto mov_cond(u32 inst) -> bool {
|
constexpr auto mov_cond(u32 inst) -> bool {
|
||||||
return ((inst >> 24) & 0x7F) == 0x52;
|
return ((inst >> 24) & 0x7F) == 0x52;
|
||||||
};
|
}
|
||||||
|
|
||||||
constexpr auto mov2_cond(u32 inst) -> bool {
|
constexpr auto mov2_cond(u32 inst) -> bool {
|
||||||
return (inst >> 24) == 0x2A;
|
if (hosversionBefore(15,0,0)) {
|
||||||
};
|
return (inst >> 24) == 0x92; // and x0, x19, #0xffffffff
|
||||||
|
} else {
|
||||||
|
return (inst >> 24) == 0x2A;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constexpr auto bne_cond(u32 inst) -> bool {
|
constexpr auto bne_cond(u32 inst) -> bool {
|
||||||
const auto type = inst >> 24;
|
const auto type = inst >> 24;
|
||||||
@ -138,58 +154,77 @@ constexpr auto bne_cond(u32 inst) -> bool {
|
|||||||
return type == 0x54 || cond == 0x0;
|
return type == 0x54 || cond == 0x0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// mov w0, wzr (w0 = 0)
|
|
||||||
constexpr auto ret0_patch(u32 inst) -> PatchData {
|
constexpr auto ret0_patch(u32 inst) -> PatchData {
|
||||||
return std::byteswap(0xE0031F2A);
|
return std::byteswap(0xE0031F2AU);
|
||||||
}
|
}
|
||||||
|
|
||||||
// nop
|
|
||||||
constexpr auto nop_patch(u32 inst) -> PatchData {
|
constexpr auto nop_patch(u32 inst) -> PatchData {
|
||||||
return std::byteswap(0x1F2003D5);
|
return std::byteswap(0x1F2003D5U);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr auto subs_patch(u32 inst) -> PatchData {
|
constexpr auto subs_patch(u32 inst) -> PatchData {
|
||||||
return subi_cond(inst) ? (u8)0x1 : (u8)0x0;
|
return subi_cond(inst) ? (u8)0x1 : (u8)0x0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// b offset
|
|
||||||
constexpr auto b_patch(u32 inst) -> PatchData {
|
constexpr auto b_patch(u32 inst) -> PatchData {
|
||||||
const auto opcode = 0x14;
|
const auto opcode = 0x14 << 24;
|
||||||
const auto offset = (inst >> 5) & 0x7FFFF;
|
const auto offset = (inst >> 5) & 0x7FFFF;
|
||||||
return opcode | offset;
|
return opcode | offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// mov x0, xzr (x0 = 0)
|
|
||||||
constexpr auto mov0_patch(u32 inst) -> PatchData {
|
constexpr auto mov0_patch(u32 inst) -> PatchData {
|
||||||
return std::byteswap(0xE0031FAA);
|
return std::byteswap(0xE0031FAAU);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Patterns fs_patterns[] = {
|
constexpr auto ret0_applied(u32 inst) -> bool {
|
||||||
{ "noacidsigchk1", "0xC8FE4739", -24, 0, bl_cond, ret0_patch },
|
return ret0_patch(inst).data == inst;
|
||||||
{ "noacidsigchk2", "0x0210911F000072", -5, 0, bl_cond, ret0_patch },
|
}
|
||||||
{ "noncasigchk_old", "0x1E42B9", -5, 0, tbz_cond, nop_patch },
|
|
||||||
{ "noncasigchk_new", "0x3E4479", -5, 0, tbz_cond, nop_patch },
|
constexpr auto nop_applied(u32 inst) -> bool {
|
||||||
{ "nocntchk_old", "0x081C00121F05007181000054", -4, 0, bl_cond, ret0_patch },
|
return nop_patch(inst).data == inst;
|
||||||
{ "nocntchk_new", "0x081C00121F05007141010054", -4, 0, bl_cond, ret0_patch },
|
}
|
||||||
|
|
||||||
|
constexpr auto subs_applied(u32 inst) -> bool {
|
||||||
|
const auto type_i = (inst >> 24) & 0xFF;
|
||||||
|
const auto imm = (inst >> 10) & 0xFFF;
|
||||||
|
const auto type_r = (inst >> 21) & 0x7F9;
|
||||||
|
const auto reg = (inst >> 16) & 0x1F;
|
||||||
|
return ((type_i == 0x71) && (imm == 0x1)) || ((type_r == 0x358) && (reg == 0x0));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto b_applied(u32 inst) -> bool {
|
||||||
|
return 0x14 == (inst >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto mov0_applied(u32 inst) -> bool {
|
||||||
|
return mov0_patch(inst).data == inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
constinit Patterns fs_patterns[] = {
|
||||||
|
{ "noacidsigchk1", "0xC8FE4739", -24, 0, bl_cond, ret0_patch, ret0_applied },
|
||||||
|
{ "noacidsigchk2", "0x0210911F000072", -5, 0, bl_cond, ret0_patch, ret0_applied },
|
||||||
|
{ "noncasigchk_old", "0x1E42B9", -5, 0, tbz_cond, nop_patch, nop_applied },
|
||||||
|
{ "noncasigchk_new", "0x3E4479", -5, 0, tbz_cond, nop_patch, nop_applied },
|
||||||
|
{ "nocntchk_old", "0x081C00121F05007181000054", -4, 0, bl_cond, ret0_patch, ret0_applied },
|
||||||
|
{ "nocntchk_new", "0x081C00121F05007141010054", -4, 0, bl_cond, ret0_patch, ret0_applied },
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr Patterns ldr_patterns[] = {
|
constinit Patterns ldr_patterns[] = {
|
||||||
{ "noacidsigchk", "0xFD7BC6A8C0035FD6", 16, 2, subs_cond, subs_patch },
|
{ "noacidsigchk", "0xFD7BC6A8C0035FD6", 16, 2, subs_cond, subs_patch, subs_applied },
|
||||||
};
|
};
|
||||||
|
|
||||||
// todo: make patch for fw 14.0.0 - 14.1.2
|
constinit Patterns es_patterns[] = {
|
||||||
constexpr Patterns es_patterns[] = {
|
{ "es1", "0x1F90013128928052", -4, 0, cbz_cond, b_patch, b_applied, FW_VER_ANY, MAKEHOSVERSION(13,2,1) },
|
||||||
{ "es", "0x1F90013128928052", -4, 0, cbz_cond, b_patch, FW_VER_ANY, MAKEHOSVERSION(13,2,1) },
|
{ "es2", "0xC07240F9E1930091", -4, 0, tbz_cond, nop_patch, nop_applied, FW_VER_ANY, MAKEHOSVERSION(10,2,0) },
|
||||||
{ "es", "0xC07240F9E1930091", -4, 0, tbz_cond, nop_patch, FW_VER_ANY, MAKEHOSVERSION(10,2,0) },
|
{ "es3", "0xF3031FAA02000014", -4, 0, bne_cond, nop_patch, nop_applied, FW_VER_ANY, MAKEHOSVERSION(10,2,0) },
|
||||||
{ "es", "0xF3031FAA02000014", -4, 0, bne_cond, nop_patch, FW_VER_ANY, MAKEHOSVERSION(10,2,0) },
|
{ "es4", "0xC0FDFF35A8C35838", -4, 0, mov_cond, nop_patch, nop_applied, MAKEHOSVERSION(11,0,0), MAKEHOSVERSION(13,2,1) },
|
||||||
{ "es", "0xC0FDFF35A8C35838", -4, 0, mov_cond, nop_patch, MAKEHOSVERSION(11,0,0), MAKEHOSVERSION(13,2,1) },
|
{ "es5", "0xE023009145EEFF97", -4, 0, cbz_cond, b_patch, b_applied, MAKEHOSVERSION(11,0,0), MAKEHOSVERSION(13,2,1) },
|
||||||
{ "es", "0xE023009145EEFF97", -4, 0, cbz_cond, b_patch, MAKEHOSVERSION(11,0,0), MAKEHOSVERSION(13,2,1) },
|
{ "es6", "0x.6300...0094A0..D1..FF97", 16, 0, mov2_cond, mov0_patch, mov0_applied, MAKEHOSVERSION(14,0,0) },
|
||||||
{ "es", "0x.6300...0094A0..D1..FF97", 16, 0, mov2_cond, mov0_patch, MAKEHOSVERSION(15,0,0) },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE: add system titles that you want to be patched to this table.
|
// NOTE: add system titles that you want to be patched to this table.
|
||||||
// a list of system titles can be found here https://switchbrew.org/wiki/Title_list
|
// a list of system titles can be found here https://switchbrew.org/wiki/Title_list
|
||||||
constexpr PatchEntry patches[] = {
|
constinit PatchEntry patches[] = {
|
||||||
{ "fs", 0x0100000000000000, fs_patterns },
|
{ "fs", 0x0100000000000000, fs_patterns },
|
||||||
// ldr needs to be patched in fw 10+
|
// ldr needs to be patched in fw 10+
|
||||||
{ "ldr", 0x0100000000000001, ldr_patterns, MAKEHOSVERSION(10,0,0) },
|
{ "ldr", 0x0100000000000001, ldr_patterns, MAKEHOSVERSION(10,0,0) },
|
||||||
@ -216,13 +251,19 @@ auto is_emummc() -> bool {
|
|||||||
return (paths.unk[0] != '\0') || (paths.nintendo[0] != '\0');
|
return (paths.unk[0] != '\0') || (paths.nintendo[0] != '\0');
|
||||||
}
|
}
|
||||||
|
|
||||||
auto patcher(Handle handle, std::span<const u8> data, u64 addr, std::span<const Patterns> patterns) -> bool {
|
auto patcher(Handle handle, std::span<const u8> data, u64 addr, std::span<Patterns> patterns) -> bool {
|
||||||
for (auto& p : patterns) {
|
for (auto& p : patterns) {
|
||||||
// skip if version isn't valid
|
// skip if version isn't valid
|
||||||
if ((p.min_fw_ver && p.min_fw_ver > FW_VERSION) ||
|
if ((p.min_fw_ver && p.min_fw_ver > FW_VERSION) ||
|
||||||
(p.max_fw_ver && p.max_fw_ver < FW_VERSION) ||
|
(p.max_fw_ver && p.max_fw_ver < FW_VERSION) ||
|
||||||
(p.min_ams_ver && p.min_ams_ver > AMS_VERSION) ||
|
(p.min_ams_ver && p.min_ams_ver > AMS_VERSION) ||
|
||||||
(p.max_ams_ver && p.max_ams_ver < AMS_VERSION)) {
|
(p.max_ams_ver && p.max_ams_ver < AMS_VERSION)) {
|
||||||
|
p.result = PatchedResult::SKIPPED;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip if already patched
|
||||||
|
if (p.result == PatchedResult::PATCHED_FILE || p.result == PatchedResult::PATCHED_SYSPATCH) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,11 +300,16 @@ auto patcher(Handle handle, std::span<const u8> data, u64 addr, std::span<const
|
|||||||
|
|
||||||
// todo: log failed writes, although this should in theory never fail
|
// todo: log failed writes, although this should in theory never fail
|
||||||
if (R_FAILED(svcWriteDebugProcessMemory(handle, &patch_data, patch_offset, patch_size))) {
|
if (R_FAILED(svcWriteDebugProcessMemory(handle, &patch_data, patch_offset, patch_size))) {
|
||||||
|
p.result = PatchedResult::FAILED_WRITE;
|
||||||
} else {
|
} else {
|
||||||
// todo: log that this was successful
|
p.result = PatchedResult::PATCHED_SYSPATCH;
|
||||||
}
|
}
|
||||||
|
// move onto next pattern
|
||||||
break; // move onto next pattern
|
break;
|
||||||
|
} else if (p.applied(inst)) {
|
||||||
|
// patch already applied by sigpatches
|
||||||
|
p.result = PatchedResult::PATCHED_FILE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -272,7 +318,7 @@ auto patcher(Handle handle, std::span<const u8> data, u64 addr, std::span<const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto apply_patch(const PatchEntry& patch) -> bool {
|
auto apply_patch(PatchEntry& patch) -> bool {
|
||||||
Handle handle{};
|
Handle handle{};
|
||||||
DebugEventInfo event_info{};
|
DebugEventInfo event_info{};
|
||||||
|
|
||||||
@ -283,6 +329,9 @@ auto apply_patch(const PatchEntry& patch) -> bool {
|
|||||||
// skip if version isn't valid
|
// skip if version isn't valid
|
||||||
if ((patch.min_fw_ver && patch.min_fw_ver > FW_VERSION) ||
|
if ((patch.min_fw_ver && patch.min_fw_ver > FW_VERSION) ||
|
||||||
(patch.max_fw_ver && patch.max_fw_ver < FW_VERSION)) {
|
(patch.max_fw_ver && patch.max_fw_ver < FW_VERSION)) {
|
||||||
|
for (auto& p : patch.patterns) {
|
||||||
|
p.result = PatchedResult::SKIPPED;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +367,7 @@ auto apply_patch(const PatchEntry& patch) -> bool {
|
|||||||
const auto actual_size = std::min(READ_BUFFER_SIZE, mem_info.size);
|
const auto actual_size = std::min(READ_BUFFER_SIZE, mem_info.size);
|
||||||
if (R_FAILED(svcReadDebugProcessMemory(buffer, handle, mem_info.addr + sz, actual_size))) {
|
if (R_FAILED(svcReadDebugProcessMemory(buffer, handle, mem_info.addr + sz, actual_size))) {
|
||||||
// todo: log failed reads!
|
// todo: log failed reads!
|
||||||
continue;
|
break;
|
||||||
} else {
|
} else {
|
||||||
patcher(handle, std::span{buffer, actual_size}, mem_info.addr + sz, patch.patterns);
|
patcher(handle, std::span{buffer, actual_size}, mem_info.addr + sz, patch.patterns);
|
||||||
}
|
}
|
||||||
@ -361,29 +410,59 @@ auto ini_load_or_write_default(const char* section, const char* key, long _defau
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto patch_result_to_str(PatchedResult result) -> const char* {
|
||||||
|
switch (result) {
|
||||||
|
case PatchedResult::NOT_FOUND: return "Unpatched";
|
||||||
|
case PatchedResult::SKIPPED: return "Skipped";
|
||||||
|
case PatchedResult::PATCHED_FILE: return "Patched (file)";
|
||||||
|
case PatchedResult::PATCHED_SYSPATCH: return "Patched (sys-patch)";
|
||||||
|
case PatchedResult::FAILED_WRITE: return "Failed (svcWriteDebugProcessMemory)";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
constexpr auto ini_path = "/config/sys-patch/config.ini";
|
||||||
|
constexpr auto log_path = "/config/sys-patch/log.ini";
|
||||||
|
|
||||||
create_dir("/config/");
|
create_dir("/config/");
|
||||||
create_dir("/config/sys-patch/");
|
create_dir("/config/sys-patch/");
|
||||||
|
ini_remove(log_path);
|
||||||
|
|
||||||
const auto ini_path = "/config/sys-patch/config.ini";
|
|
||||||
const auto patch_sysmmc = ini_load_or_write_default("options", "patch_sysmmc", 1, ini_path);
|
const auto patch_sysmmc = ini_load_or_write_default("options", "patch_sysmmc", 1, ini_path);
|
||||||
const auto patch_emummc = ini_load_or_write_default("options", "patch_emummc", 1, ini_path);
|
const auto patch_emummc = ini_load_or_write_default("options", "patch_emummc", 1, ini_path);
|
||||||
|
const auto enable_logging = ini_load_or_write_default("options", "enable_logging", 1, ini_path);
|
||||||
const auto emummc = is_emummc();
|
const auto emummc = is_emummc();
|
||||||
|
bool enable_patching = true;
|
||||||
|
|
||||||
// check if we should patch sysmmc
|
// check if we should patch sysmmc
|
||||||
if (!patch_sysmmc && !emummc) {
|
if (!patch_sysmmc && !emummc) {
|
||||||
return 0;
|
enable_patching = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if we should patch emummc
|
// check if we should patch emummc
|
||||||
if (!patch_emummc && emummc) {
|
if (!patch_emummc && emummc) {
|
||||||
return 0;
|
enable_patching = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& patch : patches) {
|
if (enable_patching) {
|
||||||
apply_patch(patch);
|
for (auto& patch : patches) {
|
||||||
|
apply_patch(patch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable_logging) {
|
||||||
|
for (auto& patch : patches) {
|
||||||
|
for (auto& p : patch.patterns) {
|
||||||
|
if (!enable_patching) {
|
||||||
|
p.result = PatchedResult::SKIPPED;
|
||||||
|
}
|
||||||
|
ini_puts(patch.name, p.patch_name, patch_result_to_str(p.result), log_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// note: sysmod exits here.
|
// note: sysmod exits here.
|
Loading…
Reference in New Issue
Block a user