Skip to content

Commit 4a9b09a

Browse files
Initial version
1 parent 62ee193 commit 4a9b09a

11 files changed

+803
-0
lines changed

.clang-format

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Generated from CLion C/C++ Code Style settings
2+
BasedOnStyle: LLVM
3+
AccessModifierOffset: -4
4+
AlignAfterOpenBracket: Align
5+
AlignConsecutiveAssignments: Consecutive
6+
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
7+
AlignOperands: Align
8+
AllowAllArgumentsOnNextLine: false
9+
AllowAllConstructorInitializersOnNextLine: false
10+
AllowAllParametersOfDeclarationOnNextLine: false
11+
AllowShortBlocksOnASingleLine: Always
12+
AllowShortCaseLabelsOnASingleLine: false
13+
AllowShortFunctionsOnASingleLine: All
14+
AllowShortIfStatementsOnASingleLine: Always
15+
AllowShortLambdasOnASingleLine: All
16+
AllowShortLoopsOnASingleLine: true
17+
AlwaysBreakAfterReturnType: None
18+
AlwaysBreakTemplateDeclarations: Yes
19+
BreakBeforeBraces: Custom
20+
BraceWrapping:
21+
AfterCaseLabel: false
22+
AfterClass: false
23+
AfterControlStatement: Never
24+
AfterEnum: false
25+
AfterFunction: false
26+
AfterNamespace: false
27+
AfterUnion: false
28+
BeforeCatch: false
29+
BeforeElse: false
30+
IndentBraces: false
31+
SplitEmptyFunction: false
32+
SplitEmptyRecord: true
33+
BreakBeforeBinaryOperators: None
34+
BreakBeforeTernaryOperators: true
35+
BreakConstructorInitializers: BeforeColon
36+
BreakInheritanceList: BeforeColon
37+
ColumnLimit: 0
38+
CompactNamespaces: false
39+
ContinuationIndentWidth: 8
40+
IndentCaseLabels: true
41+
IndentPPDirectives: None
42+
IndentWidth: 4
43+
KeepEmptyLinesAtTheStartOfBlocks: true
44+
MaxEmptyLinesToKeep: 2
45+
NamespaceIndentation: All
46+
ObjCSpaceAfterProperty: false
47+
ObjCSpaceBeforeProtocolList: true
48+
PointerAlignment: Right
49+
ReflowComments: false
50+
SpaceAfterCStyleCast: true
51+
SpaceAfterLogicalNot: false
52+
SpaceAfterTemplateKeyword: false
53+
SpaceBeforeAssignmentOperators: true
54+
SpaceBeforeCpp11BracedList: false
55+
SpaceBeforeCtorInitializerColon: true
56+
SpaceBeforeInheritanceColon: true
57+
SpaceBeforeParens: ControlStatements
58+
SpaceBeforeRangeBasedForLoopColon: true
59+
SpaceInEmptyParentheses: false
60+
SpacesBeforeTrailingComments: 1
61+
SpacesInAngles: false
62+
SpacesInCStyleCastParentheses: false
63+
SpacesInContainerLiterals: false
64+
SpacesInParentheses: false
65+
SpacesInSquareBrackets: false
66+
TabWidth: 4
67+
UseTab: Never

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
# Prerequisites
22
*.d
3+
*.lst
4+
*.map
35

46
# Compiled Object files
57
*.slo
68
*.lo
79
*.o
810
*.obj
11+
*.elf
12+
*.wps
913

1014
# Precompiled Headers
1115
*.gch

Dockerfile

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
FROM ghcr.io/wiiu-env/devkitppc:20230218
2+
3+
COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:20230215 /artifacts $DEVKITPRO
4+
5+
WORKDIR project

Makefile

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
#-------------------------------------------------------------------------------
2+
.SUFFIXES:
3+
#-------------------------------------------------------------------------------
4+
5+
ifeq ($(strip $(DEVKITPRO)),)
6+
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
7+
endif
8+
9+
TOPDIR ?= $(CURDIR)
10+
11+
include $(DEVKITPRO)/wups/share/wups_rules
12+
13+
WUT_ROOT := $(DEVKITPRO)/wut
14+
WUMS_ROOT := $(DEVKITPRO)/wums
15+
16+
#-------------------------------------------------------------------------------
17+
# TARGET is the name of the output
18+
# BUILD is the directory where object files & intermediate files will be placed
19+
# SOURCES is a list of directories containing source code
20+
# DATA is a list of directories containing data files
21+
# INCLUDES is a list of directories containing header files
22+
#-------------------------------------------------------------------------------
23+
TARGET := CodePatchPlugin
24+
BUILD := build
25+
SOURCES := src src/utils
26+
DATA := data
27+
INCLUDES := src
28+
29+
#-------------------------------------------------------------------------------
30+
# options for code generation
31+
#-------------------------------------------------------------------------------
32+
CFLAGS := -g -Wall -O2 -ffunction-sections \
33+
$(MACHDEP)
34+
35+
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__
36+
37+
CXXFLAGS := $(CFLAGS)
38+
39+
ASFLAGS := -g $(ARCH)
40+
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) $(WUPSSPECS)
41+
42+
LIBS := -lwups -lwut -lwums -lnotifications
43+
44+
#-------------------------------------------------------------------------------
45+
# list of directories containing libraries, this must be the top level
46+
# containing include and lib
47+
#-------------------------------------------------------------------------------
48+
LIBDIRS := $(PORTLIBS) $(WUPS_ROOT) $(WUT_ROOT) $(WUMS_ROOT)
49+
50+
#-------------------------------------------------------------------------------
51+
# no real need to edit anything past this point unless you need to add additional
52+
# rules for different file extensions
53+
#-------------------------------------------------------------------------------
54+
ifneq ($(BUILD),$(notdir $(CURDIR)))
55+
#-------------------------------------------------------------------------------
56+
57+
export OUTPUT := $(CURDIR)/$(TARGET)
58+
export TOPDIR := $(CURDIR)
59+
60+
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
61+
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
62+
63+
export DEPSDIR := $(CURDIR)/$(BUILD)
64+
65+
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
66+
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
67+
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
68+
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
69+
70+
#-------------------------------------------------------------------------------
71+
# use CXX for linking C++ projects, CC for standard C
72+
#-------------------------------------------------------------------------------
73+
ifeq ($(strip $(CPPFILES)),)
74+
#-------------------------------------------------------------------------------
75+
export LD := $(CC)
76+
#-------------------------------------------------------------------------------
77+
else
78+
#-------------------------------------------------------------------------------
79+
export LD := $(CXX)
80+
#-------------------------------------------------------------------------------
81+
endif
82+
#-------------------------------------------------------------------------------
83+
84+
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
85+
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
86+
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
87+
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
88+
89+
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
90+
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
91+
-I$(CURDIR)/$(BUILD)
92+
93+
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
94+
95+
.PHONY: $(BUILD) clean all
96+
97+
#-------------------------------------------------------------------------------
98+
all: $(BUILD)
99+
100+
$(BUILD):
101+
@[ -d $@ ] || mkdir -p $@
102+
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
103+
104+
#-------------------------------------------------------------------------------
105+
clean:
106+
@echo clean ...
107+
@rm -fr $(BUILD) $(TARGET).wps $(TARGET).elf
108+
109+
#-------------------------------------------------------------------------------
110+
else
111+
.PHONY: all
112+
113+
DEPENDS := $(OFILES:.o=.d)
114+
115+
#-------------------------------------------------------------------------------
116+
# main targets
117+
#-------------------------------------------------------------------------------
118+
all : $(OUTPUT).wps
119+
120+
$(OUTPUT).wps : $(OUTPUT).elf
121+
$(OUTPUT).elf : $(OFILES)
122+
123+
$(OFILES_SRC) : $(HFILES_BIN)
124+
125+
#-------------------------------------------------------------------------------
126+
# you need a rule like this for each extension you use as binary data
127+
#-------------------------------------------------------------------------------
128+
%.bin.o %_bin.h : %.bin
129+
#-------------------------------------------------------------------------------
130+
@echo $(notdir $<)
131+
@$(bin2o)
132+
133+
-include $(DEPENDS)
134+
135+
#-------------------------------------------------------------------------------
136+
endif
137+
#-------------------------------------------------------------------------------

README.md

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Code Patch Plugin
2+
This plugin loads user-provided code patches (stored in the [hax format](#hax-files)) and dynamically applies them to the current application. It supports WUPS and Aroma (alternative environment to Tiramisu) and was inspired by [CafeLoader](https://github.com/aboood40091/CafeLoader). The application's executable file remains untouched by the plugin.
3+
4+
Code Patch will load all `.hax` files in a folder and apply all patches found therein. Unlike CafeLoader, you do not need to compile a project in order to create patches.
5+
6+
*Currently, only `.hax` files are supported. The addr/code `.bin` files and network loading features that CafeLoader has may be included in a future version.*
7+
8+
---
9+
10+
**Note**: New/additional instructions or routines are not supported. Only instruction replacements are allowed.
11+
12+
**Note**: Code Patch will not run on system applications or applets.
13+
14+
---
15+
16+
## Installation
17+
Be sure you fully installed and configured Tiramisu and Aroma on your Wii U.
18+
19+
1. Copy `CodePatchPlugin.wps` into `/fs/vol/external01/wiiu/environments/aroma/plugins`.
20+
2. Create a folder in `/fs/vol/external01/wiiu/` called `codepatches`.
21+
22+
## Usage
23+
For each application you wish to apply patches, create a folder with the base title ID in the path `/fs/vol/external01/wiiu/codepatches/[title ID]`, where `[title ID]` is the base title ID, and place `.hax` files in there.
24+
25+
Patching can be enabled/disabled globally via the WUPS config menu (press L, DPAD Down and Minus on the GamePad, Pro Controller or Classic Controller).
26+
27+
When loading and applying patches, the plugin will display messages in the top left. These too can be enabled/disabled in the WUPS config menu.
28+
29+
I tested on a 32 GB US model running 5.5.5. This plugin will work on all 5.5.X versions that Tiramisu supports.
30+
31+
## hax files
32+
A `.hax` file is a format that contains individual code replacements with corresponding addresses. Since the Wii U's CPU is big-endian, `.hax` files must also be. I did not invent this format; I use it since CafeLoader used it.
33+
34+
For reference, here is a breakdown of the format.
35+
36+
**Offset**|**Type**|**Description**
37+
:-----:|:-----:|:-----:
38+
0|uint16|number of patches
39+
2|Patch|patches
40+
41+
#### Patch
42+
**Offset**|**Type**|**Description**
43+
:-----:|:-----:|:-----:
44+
0|uint16|size of code (should be 4)
45+
2|uint32|address (for BotW, this value minus 0xA900000 = original address)
46+
6|uint32|code
47+
48+
### Python script
49+
I included a Python script that converts an `.txt` file to a `.hax` file. Using this is not required. Before running the script, install `keystone` from pip.
50+
51+
Run the script like so: `python txt_to_hax.py [txt file]`. The resulting `.hax` file will appear in the same directory with the same name as the `.hax` file.
52+
53+
The input file must have patches in this format, seperated by newlines. Any line not in this format will be ignored. Lines beginning with `;` are treated as comments and are also ignored.
54+
```
55+
[address in hex starting with 0x] = [PPC instruction]
56+
```
57+
58+
## Building
59+
To build, you need:
60+
61+
- [Wii U Plugin System](https://github.com/Maschell/WiiUPluginSystem)
62+
- [Wii U Module System](https://github.com/wiiu-env/WiiUModuleSystem)
63+
- [NotificationModule](https://github.com/wiiu-env/NotificationModule)
64+
- [wut](https://github.com/devkitpro/wut)
65+
66+
Install them with their dependencies in this order according to their READMEs. After, compile the plugin using `make` (with no logging) or `make DEBUG=1` (with logging).
67+
68+
## Buildflags
69+
70+
### Logging
71+
Building via `make` only logs errors (via OSReport). To enable logging via the [LoggingModule](https://github.com/wiiu-env/LoggingModule) set `DEBUG` to `1` or `VERBOSE`.
72+
73+
`make` Logs errors only (via OSReport).
74+
`make DEBUG=1` Enables information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule).
75+
`make DEBUG=VERBOSE` Enables verbose information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule).
76+
77+
If the [LoggingModule](https://github.com/wiiu-env/LoggingModule) is not present, it will fallback to UDP (port 4405) and [CafeOS](https://github.com/wiiu-env/USBSerialLoggingModule) logging. You can use `udplogserver` (/opt/devkitpro/tools/bin/udplogserver) to view logs.

src/kernel.hpp

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// https://github.com/wiiu-env/EnvironmentLoader
2+
#pragma once
3+
#include <coreinit/cache.h>
4+
#include <coreinit/memorymap.h>
5+
#include <whb/log.h>
6+
#include <whb/log_udp.h>
7+
#include <wums.h>
8+
9+
extern "C" void SCKernelCopyData(uint32_t dst, uint32_t src, uint32_t len);
10+
extern "C" void SC_KernelCopyData(uint32_t addr, uint32_t src, uint32_t len);
11+
12+
#define KERN_SYSCALL_TBL_1 0xFFE84C70 //Unknown
13+
#define KERN_SYSCALL_TBL_2 0xFFE85070 //Games
14+
#define KERN_SYSCALL_TBL_3 0xFFE85470 //Loader
15+
#define KERN_SYSCALL_TBL_4 0xFFEAAA60 //Home menu
16+
#define KERN_SYSCALL_TBL_5 0xFFEAAE60 //Browser
17+
18+
/* Write a 32-bit word with kernel permissions */
19+
void __attribute__((noinline)) kern_write(void *addr, uint32_t value) {
20+
asm volatile(
21+
"li 3,1\n"
22+
"li 4,0\n"
23+
"mr 5,%1\n"
24+
"li 6,0\n"
25+
"li 7,0\n"
26+
"lis 8,1\n"
27+
"mr 9,%0\n"
28+
"mr %1,1\n"
29+
"li 0,0x3500\n"
30+
"sc\n"
31+
"nop\n"
32+
"mr 1,%1\n"
33+
:
34+
: "r"(addr), "r"(value)
35+
: "memory", "ctr", "lr", "0", "3", "4", "5", "6", "7", "8", "9", "10",
36+
"11", "12");
37+
}
38+
39+
// https://github.com/wiiu-env/payload_loader
40+
/* Read a 32-bit word with kernel permissions */
41+
uint32_t __attribute__ ((noinline)) kern_read(const void *addr) {
42+
uint32_t result;
43+
asm volatile (
44+
"li 3,1\n"
45+
"li 4,0\n"
46+
"li 5,0\n"
47+
"li 6,0\n"
48+
"li 7,0\n"
49+
"lis 8,1\n"
50+
"mr 9,%1\n"
51+
"li 0,0x3400\n"
52+
"mr %0,1\n"
53+
"sc\n"
54+
"nop\n"
55+
"mr 1,%0\n"
56+
"mr %0,3\n"
57+
: "=r"(result)
58+
: "b"(addr)
59+
: "memory", "ctr", "lr", "0", "3", "4", "5", "6", "7", "8", "9", "10",
60+
"11", "12"
61+
);
62+
63+
return result;
64+
}
65+
66+
void KernelWriteU32(uint32_t addr, uint32_t value) {
67+
kern_write((void *) (KERN_SYSCALL_TBL_2 + (0x25 * 4)), (unsigned int) SCKernelCopyData);
68+
69+
ICInvalidateRange(&value, 4);
70+
DCFlushRange(&value, 4);
71+
72+
auto dst = (uint32_t) OSEffectiveToPhysical(addr);
73+
auto src = (uint32_t) OSEffectiveToPhysical((uint32_t) &value);
74+
75+
SC_KernelCopyData(dst, src, 4);
76+
77+
DCFlushRange((void *) addr, 4);
78+
ICInvalidateRange((void *) addr, 4);
79+
}
80+
81+
// uint32_t KernelReadU32(uint32_t addr) {
82+
// uint32_t value = kern_read((void *) OSEffectiveToPhysical(addr));
83+
// return value;
84+
// }

0 commit comments

Comments
 (0)