mirror of
https://github.com/wiiu-env/AromaBaseModule.git
synced 2025-04-21 15:51:24 +02:00
Compare commits
43 Commits
AromaBaseM
...
main
Author | SHA1 | Date | |
---|---|---|---|
![]() |
08ab912f9a | ||
![]() |
e67f5f9725 | ||
![]() |
c02aed1daa | ||
![]() |
df60ed4401 | ||
![]() |
2349cc1581 | ||
![]() |
db349f0178 | ||
![]() |
4ee72d785b | ||
![]() |
ed4edfc2db | ||
![]() |
2c5f1bb7e2 | ||
![]() |
68fbbf05d7 | ||
![]() |
e89efe1d31 | ||
![]() |
270cd1dabb | ||
![]() |
ca15b44a12 | ||
![]() |
ef42550673 | ||
![]() |
72ff59de95 | ||
![]() |
69a0e31081 | ||
![]() |
4fb8ca0713 | ||
![]() |
a5fb305b2f | ||
![]() |
efcbfefeca | ||
![]() |
7fc494df91 | ||
![]() |
52e9a80255 | ||
![]() |
07e2682f9b | ||
![]() |
1d00a414d2 | ||
![]() |
24013d147f | ||
![]() |
bd836ed3aa | ||
![]() |
e3a1c85c92 | ||
![]() |
4803d90ddf | ||
![]() |
15c0971aae | ||
![]() |
4b148f86f8 | ||
![]() |
032bdf5b11 | ||
![]() |
abfdc45068 | ||
![]() |
f93b998830 | ||
![]() |
5d6324dc6d | ||
![]() |
fa6c26e26c | ||
![]() |
769262a66c | ||
![]() |
74d1c74b94 | ||
![]() |
4a60df7af4 | ||
![]() |
451e9c8f76 | ||
![]() |
bfa09b1ccb | ||
![]() |
e33fe06ec5 | ||
![]() |
d101c899c4 | ||
![]() |
00af55ac1d | ||
![]() |
a18c2fce99 |
10
.github/dependabot.yml
vendored
Normal file
10
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
36
.github/workflows/ci.yml
vendored
36
.github/workflows/ci.yml
vendored
@ -9,15 +9,22 @@ jobs:
|
||||
clang-format:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: clang-format
|
||||
run: |
|
||||
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source
|
||||
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./source
|
||||
build-binary:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: clang-format
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: create version.h
|
||||
run: |
|
||||
git_hash=$(git rev-parse --short "$GITHUB_SHA")
|
||||
cat <<EOF > ./source/version.h
|
||||
#pragma once
|
||||
#define VERSION_EXTRA " (nightly-$git_hash)"
|
||||
EOF
|
||||
- name: build binary
|
||||
run: |
|
||||
docker build . -t builder
|
||||
@ -41,25 +48,12 @@ jobs:
|
||||
- name: zip artifact
|
||||
run: zip -r ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip *.wms
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
uses: "softprops/action-gh-release@v2"
|
||||
with:
|
||||
tag_name: ${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
|
||||
release_name: Nightly-${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
|
||||
draft: false
|
||||
prerelease: true
|
||||
body: |
|
||||
Not a stable release:
|
||||
${{ github.event.head_commit.message }}
|
||||
- name: Upload Release Asset
|
||||
id: upload-release-asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
|
||||
asset_path: ./${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip
|
||||
asset_name: ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip
|
||||
asset_content_type: application/zip
|
||||
generate_release_notes: true
|
||||
name: Nightly-${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
|
||||
files: |
|
||||
./${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip
|
15
.github/workflows/pr.yml
vendored
15
.github/workflows/pr.yml
vendored
@ -6,15 +6,15 @@ jobs:
|
||||
clang-format:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: clang-format
|
||||
run: |
|
||||
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source
|
||||
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./source
|
||||
check-build-with-logging:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: clang-format
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: build binary with logging
|
||||
run: |
|
||||
docker build . -t builder
|
||||
@ -25,7 +25,14 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: clang-format
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: create version.h
|
||||
run: |
|
||||
git_hash=$(git rev-parse --short "${{ github.event.pull_request.head.sha }}")
|
||||
cat <<EOF > ./source/version.h
|
||||
#pragma once
|
||||
#define VERSION_EXTRA " (nightly-$git_hash)"
|
||||
EOF
|
||||
- name: build binary
|
||||
run: |
|
||||
docker build . -t builder
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,3 +8,4 @@ build/
|
||||
cmake-build-debug/
|
||||
CMakeLists.txt
|
||||
*.wms
|
||||
*.zip
|
||||
|
@ -1,6 +1,7 @@
|
||||
FROM wiiuenv/devkitppc:20220806
|
||||
FROM ghcr.io/wiiu-env/devkitppc:20241128
|
||||
|
||||
COPY --from=wiiuenv/libfunctionpatcher:20220904 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/wiiumodulesystem:20220904 /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20230621 /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20250208 /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/libkernel:20230621 /artifacts $DEVKITPRO
|
||||
|
||||
WORKDIR project
|
||||
|
14
Makefile
14
Makefile
@ -41,7 +41,7 @@ CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
|
||||
CXXFLAGS := $(CFLAGS) -std=c++20
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/libfunctionpatcher.ld $(WUMSSPECS)
|
||||
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -Tfunctionpatcher.ld -T$(WUMS_ROOT)/share/libkernel.ld $(WUMSSPECS)
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
CXXFLAGS += -DDEBUG -g
|
||||
@ -53,7 +53,7 @@ CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||
CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||
endif
|
||||
|
||||
LIBS := -lwums -lwut -lfunctionpatcher
|
||||
LIBS := -lwums -lwut -lfunctionpatcher -lkernel
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level
|
||||
@ -79,6 +79,7 @@ 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)))
|
||||
DEFFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.def)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
@ -96,7 +97,7 @@ endif
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES_SRC := $(DEFFILES:.def=.o) $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
@ -114,7 +115,7 @@ all: $(BUILD)
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(shell [ ! -d $(BUILD) ] && mkdir -p $(BUILD))
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
@ -145,6 +146,11 @@ $(OFILES_SRC) : $(HFILES_BIN)
|
||||
#-------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
#---------------------------------------------------------------------------------
|
||||
%.o: %.def
|
||||
$(SILENTMSG) $(notdir $<)
|
||||
$(SILENTCMD)rplimportgen $< $*.s $*.ld $(ERROR_FILTER)
|
||||
$(SILENTCMD)$(CC) -x assembler-with-cpp $(ASFLAGS) -c $*.s -o $@ $(ERROR_FILTER)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
|
@ -34,4 +34,4 @@ docker run -it --rm -v ${PWD}:/project aromabasemodule-builder make clean
|
||||
|
||||
## Format the code via docker
|
||||
|
||||
`docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source -i`
|
||||
`docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./source -i`
|
@ -6,7 +6,8 @@
|
||||
void initApplicationEndsHook() {
|
||||
DEBUG_FUNCTION_LINE("Patch ApplicationEndsHook functions");
|
||||
for (uint32_t i = 0; i < applicationendshook_function_replacements_size; i++) {
|
||||
if (!FunctionPatcherPatchFunction(&applicationendshook_function_replacements[i], nullptr)) {
|
||||
bool wasPatched = false;
|
||||
if (FunctionPatcher_AddFunctionPatch(&applicationendshook_function_replacements[i], nullptr, &wasPatched) != FUNCTION_PATCHER_RESULT_SUCCESS || !wasPatched) {
|
||||
OSFatal("AromaBaseModule: Failed to patch ApplicationEndsHook function");
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
#include "applicationends_function_replacements.h"
|
||||
#include "globals.h"
|
||||
|
||||
#include <coreinit/dynload.h>
|
||||
#include <coreinit/interrupts.h>
|
||||
#include <coreinit/messagequeue.h>
|
||||
#include <coreinit/scheduler.h>
|
||||
#include <coreinit/title.h>
|
||||
#include <wums.h>
|
||||
|
||||
static uint32_t lastData0 = 0;
|
||||
@ -23,6 +25,34 @@ void CallHook(wums_hook_type_t type) {
|
||||
}
|
||||
}
|
||||
}
|
||||
void ZombiUFix() {
|
||||
/*
|
||||
* ZombiU doesn't exit properly. It just calls exit(0) after receiving the
|
||||
* request to exit. If exiting takes too long, other threads will run again
|
||||
* and crash for some reason. The (hacky) solution is to set the priority
|
||||
* of (some) ZombiU threads to something very high (=> low priority).
|
||||
*/
|
||||
if (OSGetTitleID() == 0x000500001010EF00 || // ZombiU EUR
|
||||
OSGetTitleID() == 0x000500001011A700 || // ZombiU EUR
|
||||
OSGetTitleID() == 0x000500001010DD00 || // ZombiU USA
|
||||
OSGetTitleID() == 0x0005000010112300 // ZombiU JPN
|
||||
) {
|
||||
auto *curThread = OSGetCurrentThread();
|
||||
__OSLockScheduler(curThread);
|
||||
int state = OSDisableInterrupts();
|
||||
OSThread *t = *((OSThread **) 0x100567F8);
|
||||
while (t) {
|
||||
if ((uint32_t) t > (uint32_t) curThread && (uint32_t) t < 0x20000000) {
|
||||
t->priority = 0x80;
|
||||
OSReport("Set priority to %d for thread %08X (%s) to prevent it from running/crashing\n", t->priority, t, t->name);
|
||||
}
|
||||
t = t->activeLink.next;
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(state);
|
||||
__OSUnlockScheduler(curThread);
|
||||
}
|
||||
}
|
||||
|
||||
DECL_FUNCTION(uint32_t, OSReceiveMessage, OSMessageQueue *queue, OSMessage *message, uint32_t flags) {
|
||||
uint32_t res = real_OSReceiveMessage(queue, message, flags);
|
||||
@ -30,7 +60,9 @@ DECL_FUNCTION(uint32_t, OSReceiveMessage, OSMessageQueue *queue, OSMessage *mess
|
||||
if (message != nullptr && res) {
|
||||
if (lastData0 != message->args[0]) {
|
||||
if (message->args[0] == 0xD1E0D1E0) {
|
||||
ZombiUFix();
|
||||
CallHook(WUMS_HOOK_APPLICATION_REQUESTS_EXIT);
|
||||
CallHook(WUMS_HOOK_ALL_APPLICATION_REQUESTS_EXIT_DONE);
|
||||
}
|
||||
}
|
||||
lastData0 = message->args[0];
|
||||
|
@ -4,8 +4,15 @@
|
||||
#include "logger.h"
|
||||
#include <malloc.h>
|
||||
|
||||
extern "C" FunctionPatcherStatus FPAddFunctionPatch(function_replacement_data_t *function_data, PatchedFunctionHandle *outHandle, bool *outHasBeenPatched);
|
||||
|
||||
void initDynload() {
|
||||
gRPLData = (LOADED_RPL *) malloc(sizeof(LOADED_RPL) * gModuleData->number_modules);
|
||||
gLoadedRPLData = (LOADED_RPL *) malloc(sizeof(LOADED_RPL) * gModuleData->number_modules);
|
||||
if (!gLoadedRPLData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate gLoadedRPLData");
|
||||
OSFatal("AromaBaseModule: Failed to allocate gLoadedRPLData");
|
||||
}
|
||||
gRPLData = (RPL_DATA *) malloc(sizeof(RPL_DATA) * gModuleData->number_modules);
|
||||
if (!gRPLData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate gRPLData");
|
||||
OSFatal("AromaBaseModule: Failed to allocate gRPLData");
|
||||
@ -13,7 +20,9 @@ void initDynload() {
|
||||
|
||||
DEBUG_FUNCTION_LINE("Patch functions for dynload patches");
|
||||
for (uint32_t i = 0; i < dynload_function_replacements_size; i++) {
|
||||
if (!FunctionPatcherPatchFunction(&dynload_function_replacements[i], nullptr)) {
|
||||
bool wasPatched = false;
|
||||
// We need to use FPAddFunctionPatch because we can't use libfunctionpatcher yet. This patch enables it though.
|
||||
if (FPAddFunctionPatch(&dynload_function_replacements[i], nullptr, &wasPatched) != FUNCTION_PATCHER_RESULT_SUCCESS || !wasPatched) {
|
||||
OSFatal("AromaBaseModule: Failed to patch function for dynload patches");
|
||||
}
|
||||
}
|
||||
|
@ -3,23 +3,47 @@
|
||||
#include "loader_defines.h"
|
||||
#include "logger.h"
|
||||
#include <coreinit/dynload.h>
|
||||
#include <coreinit/title.h>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <wums.h>
|
||||
|
||||
DECL_FUNCTION(void, OSDynLoad_Release, OSDynLoad_Module module) {
|
||||
if (((uint32_t) module & MODULE_MAGIC_MASK) == MODULE_MAGIC) {
|
||||
uint32_t moduleHandle = ((uint32_t) module) & MODULE_ID_MASK;
|
||||
if (moduleHandle >= gModuleData->number_modules) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Invalid module handle was encoded in OSDynLoad_Module %d (%08X)", moduleHandle, module);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
real_OSDynLoad_Release(module);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(OSDynLoad_Error, OSDynLoad_Acquire, char const *name, OSDynLoad_Module *outModule) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Looking for module %s", name);
|
||||
for (uint32_t i = 0; i < gModuleData->number_modules; i++) {
|
||||
if (strcmp(name, gModuleData->modules[i].module_export_name) == 0) {
|
||||
*outModule = (OSDynLoad_Module) (0x13370000 + i);
|
||||
*outModule = (OSDynLoad_Module) (MODULE_MAGIC | i);
|
||||
return OS_DYNLOAD_OK;
|
||||
}
|
||||
}
|
||||
|
||||
OSDynLoad_Error result = real_OSDynLoad_Acquire(name, outModule);
|
||||
if (result == OS_DYNLOAD_OK) {
|
||||
return OS_DYNLOAD_OK;
|
||||
if (name != nullptr && name[0] == '~') {
|
||||
char cpy[64] = {};
|
||||
snprintf(cpy, sizeof(cpy), "%s", name);
|
||||
char *curPtr = &cpy[1];
|
||||
while (*curPtr != '\0') {
|
||||
if (*curPtr == '/') {
|
||||
*curPtr = '|';
|
||||
}
|
||||
curPtr++;
|
||||
}
|
||||
return real_OSDynLoad_Acquire(cpy, outModule);
|
||||
}
|
||||
|
||||
OSDynLoad_Error result = real_OSDynLoad_Acquire(name, outModule);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -29,8 +53,8 @@ DECL_FUNCTION(OSDynLoad_Error, OSDynLoad_FindExport, OSDynLoad_Module module, BO
|
||||
return OS_DYNLOAD_OK;
|
||||
}
|
||||
|
||||
if (((uint32_t) module & 0xFFFF0000) == 0x13370000) {
|
||||
uint32_t moduleHandle = ((uint32_t) module) & 0x0000FFFF;
|
||||
if (((uint32_t) module & MODULE_MAGIC_MASK) == MODULE_MAGIC) {
|
||||
uint32_t moduleHandle = ((uint32_t) module) & MODULE_ID_MASK;
|
||||
if (moduleHandle >= gModuleData->number_modules) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Invalid module handle was encoded in OSDynLoad_Module %d (%08X)", moduleHandle, module);
|
||||
return result;
|
||||
@ -63,24 +87,28 @@ DECL_FUNCTION(LOADED_RPL *, LiFindRPLByName, char *name) {
|
||||
for (uint32_t i = 0; i < gModuleData->number_modules; i++) {
|
||||
auto *curModule = &gModuleData->modules[i];
|
||||
if (strcmp(name, curModule->module_export_name) == 0) {
|
||||
fileInfoBuffer.tlsModuleIndex = 0;
|
||||
gRPLData[i].fileInfoBuffer = &fileInfoBuffer; // will be copied to the LiImportTracking array
|
||||
gRPLData[i].loadStateFlags = 0x0;
|
||||
gRPLData[i].entrypoint = 0x1; //needs to be != 0;
|
||||
gRPLData[i].funcExports = (Export *) (FUNCTION_EXPORT_MASK + i);
|
||||
gRPLData[i].numFuncExports = 1;
|
||||
gRPLData[i].dataExports = (Export *) (DATA_EXPORT_MASK + i);
|
||||
gRPLData[i].numDataExports = 1;
|
||||
return &gRPLData[i];
|
||||
fileInfoBuffer.tlsModuleIndex = 0;
|
||||
gLoadedRPLData[i].fileInfoBuffer = &fileInfoBuffer; // will be copied to the LiImportTracking array
|
||||
gLoadedRPLData[i].loadStateFlags = 0x0;
|
||||
gLoadedRPLData[i].entrypoint = 0x1; //needs to be != 0;
|
||||
gLoadedRPLData[i].funcExports = (Export *) (FUNCTION_EXPORT_MAGIC + i);
|
||||
gLoadedRPLData[i].numFuncExports = 1;
|
||||
gLoadedRPLData[i].dataExports = (Export *) (DATA_EXPORT_MAGIC + i);
|
||||
gLoadedRPLData[i].numDataExports = 1;
|
||||
return &gLoadedRPLData[i];
|
||||
}
|
||||
}
|
||||
return real_LiFindRPLByName(name);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(uint32_t, __OSDynLoad_InternalAcquire, char *name, void *out, uint32_t u1, uint32_t u2, uint32_t u3) {
|
||||
DECL_FUNCTION(uint32_t, __OSDynLoad_InternalAcquire, char *name, RPL_DATA **out, uint32_t u1, uint32_t u2, uint32_t u3) {
|
||||
for (uint32_t i = 0; i < gModuleData->number_modules; i++) {
|
||||
auto *curModule = &gModuleData->modules[i];
|
||||
if (strcmp(name, curModule->module_export_name) == 0) {
|
||||
// OSDynLoad_IsModuleLoaded uses __OSDynLoad_InternalAcquire and expects out have a valid value.
|
||||
// It uses the "handle", so don't need to fill the whole struct.
|
||||
gRPLData[i].handle = MODULE_MAGIC | i;
|
||||
*out = &gRPLData[i];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -90,10 +118,10 @@ DECL_FUNCTION(uint32_t, __OSDynLoad_InternalAcquire, char *name, void *out, uint
|
||||
Export ourExportThing;
|
||||
|
||||
DECL_FUNCTION(Export *, LiBinSearchExport, Export *exports, int numExports, char *name) {
|
||||
auto isFunc = (((uint32_t) exports) & 0xFFFF0000) == FUNCTION_EXPORT_MASK;
|
||||
auto isData = (((uint32_t) exports) & 0xFFFF0000) == DATA_EXPORT_MASK;
|
||||
auto isFunc = (((uint32_t) exports) & EXPORT_MASK) == FUNCTION_EXPORT_MAGIC;
|
||||
auto isData = (((uint32_t) exports) & EXPORT_MASK) == DATA_EXPORT_MAGIC;
|
||||
if (isFunc || isData) {
|
||||
uint32_t moduleHandle = ((uint32_t) exports) & 0x0000FFFF;
|
||||
uint32_t moduleHandle = ((uint32_t) exports) & EXPORT_MAGIC_MASK;
|
||||
if (moduleHandle > gModuleData->number_modules) {
|
||||
DEBUG_FUNCTION_LINE_LOADER_ERR("Invalid module handle was encoded in Export %d (%08X)", moduleHandle, exports);
|
||||
return nullptr;
|
||||
@ -118,7 +146,7 @@ DECL_FUNCTION(Export *, LiBinSearchExport, Export *exports, int numExports, char
|
||||
|
||||
DECL_FUNCTION(int32_t, LiFixupRelocOneRPL, LOADED_RPL *rpl, void *imports, uint32_t unknown) {
|
||||
auto rplAddress = (uint32_t) rpl;
|
||||
if (rplAddress >= (uint32_t) &gRPLData[0] && rplAddress < (uint32_t) &gRPLData[gModuleData->number_modules]) {
|
||||
if (rplAddress >= (uint32_t) &gLoadedRPLData[0] && rplAddress < (uint32_t) &gLoadedRPLData[gModuleData->number_modules]) {
|
||||
// Skip if this is our fake RPL
|
||||
return 0;
|
||||
}
|
||||
@ -127,21 +155,35 @@ DECL_FUNCTION(int32_t, LiFixupRelocOneRPL, LOADED_RPL *rpl, void *imports, uint3
|
||||
|
||||
DECL_FUNCTION(int32_t, sCheckOne, LOADED_RPL *rpl) {
|
||||
auto rplAddress = (uint32_t) rpl;
|
||||
if (rplAddress >= (uint32_t) &gRPLData[0] && rplAddress < (uint32_t) &gRPLData[gModuleData->number_modules]) {
|
||||
if (rplAddress >= (uint32_t) &gLoadedRPLData[0] && rplAddress < (uint32_t) &gLoadedRPLData[gModuleData->number_modules]) {
|
||||
// Skip if this is our fake RPL
|
||||
return 0;
|
||||
}
|
||||
return real_sCheckOne(rpl);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(void, sACPLoadOnDone, void) {
|
||||
if (OSGetTitleID() == 0x0005000010140900L) { // オセロ (Othello)
|
||||
DEBUG_FUNCTION_LINE_INFO("Skip sACPLoadOnDone for オセロ (Othello) as it might slow down exiting.");
|
||||
// For some unknown reason unloading the nn_acp.rpl after playing Othello
|
||||
// takes 30-100 seconds when many plugins are loaded... We take the very hacky and lazy route
|
||||
// and just stop calling it and pray this won't break anything.
|
||||
return;
|
||||
}
|
||||
|
||||
return real_sACPLoadOnDone();
|
||||
}
|
||||
|
||||
function_replacement_data_t dynload_function_replacements[] = {
|
||||
REPLACE_FUNCTION_VIA_ADDRESS(__OSDynLoad_InternalAcquire, 0x32029054, 0x101C400 + 0x0cc54),
|
||||
REPLACE_FUNCTION_VIA_ADDRESS(sACPLoadOnDone, 0x3201C400 + 0x29de0, 0x101C400 + 0x29de0),
|
||||
REPLACE_FUNCTION_VIA_ADDRESS(__OSDynLoad_InternalAcquire, 0x3201C400 + 0x0cc54, 0x101C400 + 0x0cc54),
|
||||
REPLACE_FUNCTION_VIA_ADDRESS(LiFindRPLByName, 0x32004BC4, 0x01004bc4),
|
||||
REPLACE_FUNCTION_VIA_ADDRESS(LiBinSearchExport, 0x320002f8, 0x010002f8),
|
||||
REPLACE_FUNCTION_VIA_ADDRESS(sCheckOne, 0x32007294, 0x01007294),
|
||||
REPLACE_FUNCTION_VIA_ADDRESS(LiFixupRelocOneRPL, 0x320059f0, 0x010059f0),
|
||||
REPLACE_FUNCTION(OSDynLoad_Acquire, LIBRARY_COREINIT, OSDynLoad_Acquire),
|
||||
REPLACE_FUNCTION(OSDynLoad_FindExport, LIBRARY_COREINIT, OSDynLoad_FindExport),
|
||||
REPLACE_FUNCTION(OSDynLoad_Release, LIBRARY_COREINIT, OSDynLoad_Release),
|
||||
};
|
||||
|
||||
uint32_t dynload_function_replacements_size = sizeof(dynload_function_replacements) / sizeof(function_replacement_data_t);
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <wut.h>
|
||||
|
||||
// see https://github.com/decaf-emu/decaf-emu/tree/43366a34e7b55ab9d19b2444aeb0ccd46ac77dea/src/libdecaf/src/cafe/loader
|
||||
struct LiImportTracking {
|
||||
@ -35,5 +36,19 @@ struct LOADED_RPL {
|
||||
char u4[12];
|
||||
};
|
||||
|
||||
#define FUNCTION_EXPORT_MASK 0x13370000
|
||||
#define DATA_EXPORT_MASK 0x13380000
|
||||
// https://github.com/decaf-emu/decaf-emu/blob/6feb1be1db3938e6da2d4a65fc0a7a8599fc8dd6/src/libdecaf/src/cafe/libraries/coreinit/coreinit_dynload.cpp#L40
|
||||
struct RPL_DATA {
|
||||
uint32_t handle;
|
||||
WUT_UNKNOWN_BYTES(0x94 - 0x4);
|
||||
};
|
||||
WUT_CHECK_SIZE(RPL_DATA, 0x94);
|
||||
|
||||
|
||||
#define EXPORT_MASK 0xFFFF0000
|
||||
#define EXPORT_MAGIC_MASK 0x0000FFFF
|
||||
#define FUNCTION_EXPORT_MAGIC 0x88660000
|
||||
#define DATA_EXPORT_MAGIC 0x88550000
|
||||
|
||||
#define MODULE_MAGIC_MASK 0xFFFF0000
|
||||
#define MODULE_ID_MASK 0x0000FFFF
|
||||
#define MODULE_MAGIC 0x87650000
|
4
source/functionpatcher.def
Normal file
4
source/functionpatcher.def
Normal file
@ -0,0 +1,4 @@
|
||||
:NAME homebrew_functionpatcher
|
||||
|
||||
:TEXT
|
||||
FPAddFunctionPatch
|
@ -2,4 +2,5 @@
|
||||
|
||||
module_information_t *gModuleData __attribute__((section(".data"))) = NULL;
|
||||
int32_t gSDMountRefCount __attribute__((section(".data"))) = 0;
|
||||
LOADED_RPL *gRPLData __attribute__((section(".data"))) = nullptr;
|
||||
LOADED_RPL *gLoadedRPLData __attribute__((section(".data"))) = nullptr;
|
||||
RPL_DATA *gRPLData __attribute__((section(".data"))) = nullptr;
|
@ -1,6 +1,8 @@
|
||||
#include "dynload/loader_defines.h"
|
||||
#include <function_patcher/fpatching_defines.h>
|
||||
#include <wums.h>
|
||||
|
||||
extern module_information_t *gModuleData;
|
||||
extern int32_t gSDMountRefCount;
|
||||
extern LOADED_RPL *gRPLData;
|
||||
extern LOADED_RPL *gLoadedRPLData;
|
||||
extern RPL_DATA *gRPLData;
|
@ -41,6 +41,7 @@ extern "C" {
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "## WARN## ", "", FMT, ##ARGS)
|
||||
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS)
|
||||
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "## INFO## ", "", FMT, ##ARGS)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS);
|
||||
|
||||
@ -58,6 +59,7 @@ extern "C" {
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "## WARN## ", "\n", FMT, ##ARGS)
|
||||
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
|
||||
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "## INFO## ", "\n", FMT, ##ARGS)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, OSReport, "##ERROR## ", "\n", FMT, ##ARGS);
|
||||
|
||||
|
@ -5,10 +5,15 @@
|
||||
#include "patches/patches.h"
|
||||
#include "sdrefcount/refcount.h"
|
||||
#include "symbolnamepatcher/symbolname.h"
|
||||
#include "version.h"
|
||||
#include <function_patcher/function_patching.h>
|
||||
#include <wums.h>
|
||||
|
||||
WUMS_MODULE_EXPORT_NAME("homebrew_basemodule");
|
||||
WUMS_MODULE_SKIP_INIT_FINI();
|
||||
WUMS_DEPENDS_ON(homebrew_functionpatcher);
|
||||
|
||||
#define VERSION "v0.2.6"
|
||||
|
||||
WUMS_INITIALIZE(args) {
|
||||
initLogging();
|
||||
@ -20,15 +25,25 @@ WUMS_INITIALIZE(args) {
|
||||
OSFatal("AromaBaseModule: The module information struct version does not match.");
|
||||
}
|
||||
|
||||
// First init Dynload to have proper OSDynLoad support!
|
||||
initDynload();
|
||||
|
||||
// Now init the library so we can use it for the other patches.
|
||||
if (FunctionPatcher_InitLibrary() != FUNCTION_PATCHER_RESULT_SUCCESS) {
|
||||
OSFatal("homebrew_basemodule: FunctionPatcher_InitLibrary failed");
|
||||
}
|
||||
|
||||
initApplicationEndsHook();
|
||||
initSDRefCount();
|
||||
initSymbolNamePatcher();
|
||||
initDynload();
|
||||
|
||||
initCommonPatches();
|
||||
|
||||
deinitLogging();
|
||||
}
|
||||
|
||||
WUMS_APPLICATION_STARTS() {
|
||||
OSReport("Running AromaBaseModule " VERSION VERSION_EXTRA "\n");
|
||||
|
||||
commonPatchesStart();
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
#include "globals.h"
|
||||
#include "logger.h"
|
||||
#include "patches_replacements.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <cstdlib>
|
||||
#include <kernel/kernel.h>
|
||||
|
||||
// init is not called for this module. We need to make sure to init these values in initCommonPatches()
|
||||
uint32_t gHeapMask;
|
||||
@ -14,7 +16,6 @@ void initCommonPatches() {
|
||||
if (!dummy) {
|
||||
gHeapMask = 0x80000000;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("%08X", dummy);
|
||||
gHeapMask = (uint32_t) dummy & 0xF0000000;
|
||||
free(dummy);
|
||||
}
|
||||
@ -22,11 +23,20 @@ void initCommonPatches() {
|
||||
|
||||
DEBUG_FUNCTION_LINE("Do common patches");
|
||||
for (uint32_t i = 0; i < patches_function_replacements_size; i++) {
|
||||
if (!FunctionPatcherPatchFunction(&patches_function_replacements[i], nullptr)) {
|
||||
bool wasPatched = false;
|
||||
if (FunctionPatcher_AddFunctionPatch(&patches_function_replacements[i], nullptr, &wasPatched) != FUNCTION_PATCHER_RESULT_SUCCESS || !wasPatched) {
|
||||
OSFatal("AromaBaseModule: Failed apply common patches");
|
||||
}
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("Common patches finished");
|
||||
|
||||
// Patch loader.elf to spit out less warnings when loading .rpx built with wut
|
||||
KernelNOPAtPhysicalAddress(0x0100b770 - 0x01000000 + 0x32000000);
|
||||
KernelNOPAtPhysicalAddress(0x0100b800 - 0x01000000 + 0x32000000);
|
||||
KernelNOPAtPhysicalAddress(0x0100b7b8 - 0x01000000 + 0x32000000);
|
||||
ICInvalidateRange(reinterpret_cast<void *>(0x0100b770), 0x04);
|
||||
ICInvalidateRange(reinterpret_cast<void *>(0x0100b800), 0x04);
|
||||
ICInvalidateRange(reinterpret_cast<void *>(0x0100b7b8), 0x04);
|
||||
}
|
||||
|
||||
void commonPatchesStart() {
|
||||
|
@ -4,11 +4,19 @@
|
||||
#include "patches.h"
|
||||
#include <coreinit/filesystem_fsa.h>
|
||||
#include <coreinit/title.h>
|
||||
#include <sysapp/launch.h>
|
||||
|
||||
static inline bool IsInHardcodedHomebrewMemoryRegion(void *addr) {
|
||||
if ((uint32_t) addr >= 0x00800000 && (uint32_t) addr < 0x01000000) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSAddClient, FSClient *client, FSErrorFlag errorMask) {
|
||||
auto res = real_FSAddClient(client, errorMask);
|
||||
if (res == FS_STATUS_OK) {
|
||||
if (((uint32_t) client & 0xF0000000) != gHeapMask) {
|
||||
if (((uint32_t) client & 0xF0000000) != gHeapMask && !IsInHardcodedHomebrewMemoryRegion(client)) {
|
||||
gNonHomebrewFSClientCount++;
|
||||
}
|
||||
}
|
||||
@ -18,7 +26,7 @@ DECL_FUNCTION(FSStatus, FSAddClient, FSClient *client, FSErrorFlag errorMask) {
|
||||
DECL_FUNCTION(FSStatus, FSDelClient, FSClient *client, FSErrorFlag errorMask) {
|
||||
auto res = real_FSDelClient(client, errorMask);
|
||||
if (res == FS_STATUS_OK) {
|
||||
if (((uint32_t) client & 0xF0000000) != gHeapMask) {
|
||||
if (((uint32_t) client & 0xF0000000) != gHeapMask && !IsInHardcodedHomebrewMemoryRegion(client)) {
|
||||
gNonHomebrewFSClientCount--;
|
||||
}
|
||||
}
|
||||
@ -36,17 +44,37 @@ DECL_FUNCTION(uint32_t, FSGetClientNum) {
|
||||
titleID == 0x0005000010203200 || // Shantae: Half-Genie Hero EUR
|
||||
titleID == 0x00050000101A6100 || // Shantae: Risky's Revenge Director's Cut USA
|
||||
titleID == 0x00050000101A9600 || // Shantae: Risky's Revenge Director's Cut EUR
|
||||
titleID == 0x00050000101F7300 // Shantae: Risky's Revenge Director's Cut JPN
|
||||
titleID == 0x00050000101F7300 || // Shantae: Risky's Revenge Director's Cut JPN
|
||||
titleID == 0x000500001014E100 || // Adventure Time: Explore the Dungeon Because I Don't Know! EUR
|
||||
titleID == 0x0005000010144000 || // Adventure Time: Explore the Dungeon Because I Don't Know! USA
|
||||
titleID == 0x0005000010115D00 || // The Smurfs™ 2 EUR
|
||||
titleID == 0x0005000010113300 // The Smurfs™ 2 USA
|
||||
) {
|
||||
DEBUG_FUNCTION_LINE("Fake FSGetClientNum num to %d instead of %d", gNonHomebrewFSClientCount, real_FSGetClientNum());
|
||||
DEBUG_FUNCTION_LINE_INFO("Fake FSGetClientNum num to %d instead of %d", gNonHomebrewFSClientCount, real_FSGetClientNum());
|
||||
return gNonHomebrewFSClientCount;
|
||||
}
|
||||
return real_FSGetClientNum();
|
||||
}
|
||||
|
||||
DECL_FUNCTION(uint32_t, SYSReturnToCaller, void *args) {
|
||||
// Fix jumping back to the System Settings when exiting the System Transfer
|
||||
auto curTitleID = OSGetTitleID();
|
||||
if (curTitleID == 0x0005001010062000L || curTitleID == 0x0005001010062100L || curTitleID == 0x0005001010062200L) {
|
||||
SysAppSettingsArgs set_args{};
|
||||
// Jump directly to the Transfer Menu
|
||||
set_args.jumpTo = SYS_SETTINGS_JUMP_TO_SOFTWARE_TRANSFER;
|
||||
_SYSLaunchSettings(&set_args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return real_SYSReturnToCaller(args);
|
||||
}
|
||||
|
||||
function_replacement_data_t patches_function_replacements[] = {
|
||||
REPLACE_FUNCTION(FSAddClient, LIBRARY_COREINIT, FSAddClient),
|
||||
REPLACE_FUNCTION(FSDelClient, LIBRARY_COREINIT, FSDelClient),
|
||||
REPLACE_FUNCTION(FSGetClientNum, LIBRARY_COREINIT, FSGetClientNum),
|
||||
REPLACE_FUNCTION(SYSReturnToCaller, LIBRARY_SYSAPP, SYSReturnToCaller),
|
||||
};
|
||||
|
||||
uint32_t patches_function_replacements_size = sizeof(patches_function_replacements) / sizeof(function_replacement_data_t);
|
@ -21,7 +21,8 @@ void initSDRefCount() {
|
||||
|
||||
DEBUG_FUNCTION_LINE("Patch SDRefCount functions");
|
||||
for (uint32_t i = 0; i < sdrefcount_function_replacements_size; i++) {
|
||||
if (!FunctionPatcherPatchFunction(&sdrefcount_function_replacements[i], nullptr)) {
|
||||
bool wasPatched = false;
|
||||
if (FunctionPatcher_AddFunctionPatch(&sdrefcount_function_replacements[i], nullptr, &wasPatched) != FUNCTION_PATCHER_RESULT_SUCCESS || !wasPatched) {
|
||||
OSFatal("AromaBaseModule: Failed to patch function for sd ref counting");
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,305 @@
|
||||
#include "applicationendshook/applicationends_function_replacements.h"
|
||||
#include "globals.h"
|
||||
#include "logger.h"
|
||||
#include <coreinit/dynload.h>
|
||||
#include <coreinit/filesystem_fsa.h>
|
||||
#include <coreinit/interrupts.h>
|
||||
#include <coreinit/scheduler.h>
|
||||
#include <coreinit/title.h>
|
||||
#include <string_view>
|
||||
|
||||
uint64_t NWFPatchTitleList[] = {
|
||||
0x0005000010102900L, // Demaecan JPN
|
||||
0x0005000010102A00L, // YNN JPN
|
||||
0x0005000010102D00L, // Hulu USA
|
||||
0x0005000010102E00L, // Amazon Instant Video USA
|
||||
0x0005000010102F00L, // Amazon / LOVEFiLM EUR
|
||||
0x0005000010104C00L, // Hulu JPN
|
||||
0x0005000010105700L, // YouTube ALL
|
||||
0x000500001012D300L, // Wii Street U powered by Google JPN
|
||||
0x0005000010132000L, // Wii Street U powered by Google USA
|
||||
0x0005000010132100L, // Wii Street U powered by Google EUR
|
||||
0x0005000010136100L, // BANDAI CHANNEL JPN
|
||||
0x0005000010149300L, // Mario vs. Donkey Kong Tipping Stars USA
|
||||
0x0005000010154500L, // Togabito JPN
|
||||
0x0005000010154800L, // BBC iPlayer EUR
|
||||
0x0005000010157D00L, // GAIABREAKER JPN
|
||||
0x000500001016E200L, // XType Plus EUR
|
||||
0x000500001016E500L, // BLOK DROP U USA
|
||||
0x000500001016E600L, // ZaciSa's Last Stand USA
|
||||
0x0005000010170400L, // XType Plus USA
|
||||
0x0005000010172A00L, // Crunchyroll USA
|
||||
0x0005000010172B00L, // Crunchyroll EUR
|
||||
0x0005000010173000L, // Nintendo Game Seminar 2013 Student Works JPN
|
||||
0x0005000010173100L, // I've Got to Run! USA
|
||||
0x0005000010175700L, // BLOK DROP U EUR
|
||||
0x0005000010175F00L, // Death Match Love Comedy JPN
|
||||
0x0005000010176400L, // Pixel Paint USA
|
||||
0x0005000010178E00L, // Mario vs. Donkey Kong Tipping Stars EUR
|
||||
0x0005000010179200L, // Mario vs. Donkey Kong Tipping Stars JPN
|
||||
0x0005000010179300L, // Internal Invasion USA
|
||||
0x0005000010179500L, // Plenty of Fishies USA
|
||||
0x000500001017A800L, // GAIABREAKER USA
|
||||
0x000500001017A900L, // SUPER ROBO MOUSE USA
|
||||
0x000500001017AB00L, // GAIABREAKER EUR
|
||||
0x000500001017DB00L, // Dolphin Up USA
|
||||
0x000500001017E200L, // 3Souls EUR
|
||||
0x000500001017E700L, // 3Souls USA
|
||||
0x000500001017EB00L, // SDK Paint USA
|
||||
0x000500001017EC00L, // Guac' a Mole EUR
|
||||
0x0005000010182E00L, // GetClose USA
|
||||
0x0005000010183100L, // Snake Den USA
|
||||
0x0005000010183400L, // U Host USA
|
||||
0x0005000010185000L, // ブタメダル JPN
|
||||
0x0005000010185900L, // GolT Stadium EUR
|
||||
0x000500001018A400L, // POKER DICE SOLITAIRE FUTURE USA
|
||||
0x000500001018D700L, // SHUT THE BOX USA
|
||||
0x000500001018EE00L, // Don't Touch Anything Red USA
|
||||
0x000500001018F900L, // TOSS N GO USA
|
||||
0x000500001018FE00L, // Sense by Play.me EUR
|
||||
0x0005000010190400L, // Red Riding Hood USA
|
||||
0x0005000010193900L, // Flapp & Zegeta USA
|
||||
0x0005000010193D00L, // Tiny Galaxy USA
|
||||
0x0005000010193E00L, // Twisted Fusion USA
|
||||
0x0005000010195F00L, // Arrow Time U USA
|
||||
0x0005000010198700L, // Watchup USA
|
||||
0x000500001019A100L, // Shapes of Gray USA
|
||||
0x000500001019A300L, // SPIKEY WALLS USA
|
||||
0x000500001019A700L, // BLOK DROP X TWISTED FUSION USA
|
||||
0x000500001019A800L, // Citadale The Legends Trilogy USA
|
||||
0x000500001019AD00L, // Elliot Quest USA
|
||||
0x000500001019B900L, // SUPER ROBO MOUSE EUR
|
||||
0x000500001019BA00L, // BLOK DROP X TWISTED FUSION EUR
|
||||
0x00050000101A2400L, // Tested with robots ! EUR
|
||||
0x00050000101A2E00L, // XType+ JPN
|
||||
0x00050000101A3E00L, // Defense Dome USA
|
||||
0x00050000101A4400L, // Toon Tanks USA
|
||||
0x00050000101A9100L, // Rakuten TV JPN
|
||||
0x00050000101A9F00L, // Dot Arcade USA
|
||||
0x00050000101AA300L, // SDK Spriter USA
|
||||
0x00050000101AAC00L, // Red Riding Hood EUR
|
||||
0x00050000101ABB00L, // COLOR BOMBS USA
|
||||
0x00050000101ACB00L, // psyscrolr USA
|
||||
0x00050000101AEB00L, // SDK Paint EUR
|
||||
0x00050000101AEF00L, // Midnight USA
|
||||
0x00050000101AF400L, // PixlCross USA
|
||||
0x00050000101B4F00L, // Asteroid Quarry USA
|
||||
0x00050000101B5000L, // Drop It: Block Paradise! USA
|
||||
0x00050000101B5E00L, // SPLASHY DUCK EUR
|
||||
0x00050000101B5F00L, // TABLETOP GALLERY EUR
|
||||
0x00050000101B8400L, // Mortar Melon USA
|
||||
0x00050000101B9600L, // Super Destronaut USA
|
||||
0x00050000101B9700L, // SDK Spriter EUR
|
||||
0x00050000101BA100L, // Best way to motivate kids ManabiGet! JPN
|
||||
0x00050000101BA700L, // PENTAPUZZLE USA
|
||||
0x00050000101BB300L, // ZaciSa: Defense of the Crayon Dimension! EUR
|
||||
0x00050000101BB800L, // Elliot Quest EUR
|
||||
0x00050000101BC000L, // ドットペイント JPN
|
||||
0x00050000101BC400L, // Plenty of Fishies EUR
|
||||
0x00050000101BC500L, // Mortar Melon EUR
|
||||
0x00050000101BCA00L, // Napster EUR
|
||||
0x00050000101BCB00L, // Rhapsody USA
|
||||
0x00050000101BCF00L, // Word Search by POWGI USA
|
||||
0x00050000101C3900L, // Word Search by POWGI EUR
|
||||
0x00050000101C3C00L, // PictoParty EUR
|
||||
0x00050000101C4A00L, // Word Party EUR
|
||||
0x00050000101C5500L, // Word Party USA
|
||||
0x00050000101C5900L, // サイコロの森 3-in-1L, // JPN
|
||||
0x00050000101C6100L, // Mini Mario & Friends amiibo Challenge JPN
|
||||
0x00050000101C6200L, // Mini Mario & Friends amiibo Challenge USA
|
||||
0x00050000101C6300L, // Mini Mario & Friends amiibo Challenge EUR
|
||||
0x00050000101C6900L, // TABLETOP GALLERY USA
|
||||
0x00050000101C6B00L, // PEG SOLITAIRE USA
|
||||
0x00050000101C7200L, // Placards USA
|
||||
0x00050000101C7300L, // The Stonecutter USA
|
||||
0x00050000101C8E00L, // Drop It: Block Paradise! EUR
|
||||
0x00050000101CA300L, // Neon Battle USA
|
||||
0x00050000101CF900L, // Word Puzzles by POWGI EUR
|
||||
0x00050000101CFA00L, // Word Puzzles by POWGI USA
|
||||
0x00050000101CFD00L, // Near Earth Objects USA
|
||||
0x00050000101CFF00L, // Job the Leprechaun USA
|
||||
0x00050000101D1700L, // Booty Diver USA
|
||||
0x00050000101D1A00L, // Aenigma Os USA
|
||||
0x00050000101D2800L, // DON'T CRASH USA
|
||||
0x00050000101D2900L, // PIXEL SLIME U USA
|
||||
0x00050000101D2A00L, // Land it Rocket USA
|
||||
0x00050000101D6200L, // Test Your Mind USA
|
||||
0x00050000101D6700L, // Star Sky EUR
|
||||
0x00050000101D7300L, // Molly Maggot USA
|
||||
0x00050000101D7700L, // Explody Bomb USA
|
||||
0x00050000101D7800L, // Hold Your Fire USA
|
||||
0x00050000101D8A00L, // Star Sky USA
|
||||
0x00050000101D8B00L, // ヒラメキパズル テトグラム JPN
|
||||
0x00050000101D8C00L, // ブルームーン JPN
|
||||
0x00050000101D9C00L, // Funky Physics USA
|
||||
0x00050000101D9F00L, // Job the Leprechaun EUR
|
||||
0x00050000101DB100L, // PictoParty USA
|
||||
0x00050000101DD500L, // Elliot Quest JPN
|
||||
0x00050000101DEE00L, // AVOIDER USA
|
||||
0x00050000101DFA00L, // Draw 2 Survive USA
|
||||
0x00050000101DFD00L, // Snowball USA
|
||||
0x00050000101E2E00L, // Christmas Adventure of Rocket P. USA
|
||||
0x00050000101E3200L, // Jewel Quest USA
|
||||
0x00050000101E3300L, // Olympia Rising EUR
|
||||
0x00050000101E3400L, // Olympia Rising USA
|
||||
0x00050000101E5500L, // Escape From Flare Industries USA
|
||||
0x00050000101E7800L, // SKEASY USA
|
||||
0x00050000101E7900L, // SPLASHY DUCK USA
|
||||
0x00050000101E7C00L, // TAP TAP ARCADE EUR
|
||||
0x00050000101E7D00L, // TAP TAP ARCADE USA
|
||||
0x00050000101E7E00L, // TOUCH SELECTIONS EUR
|
||||
0x00050000101E7F00L, // TOUCH SELECTIONS USA
|
||||
0x00050000101E8800L, // COLOR BOMBS EUR
|
||||
0x00050000101E9700L, // U Host EUR
|
||||
0x00050000101EA900L, // Armored ACORNs Action Squirrel Squad USA
|
||||
0x00050000101EC600L, // Defense Dome EUR
|
||||
0x00050000101EF400L, // Demonic Karma Summoner USA
|
||||
0x00050000101F2700L, // Star Sky 2 EUR
|
||||
0x00050000101F3E00L, // Star Sky 2 USA
|
||||
0x00050000101F5900L, // PENTAPUZZLE EUR
|
||||
0x00050000101F5F00L, // Hot Rod Racer USA
|
||||
0x00050000101F6200L, // Adventure Party Cats and Caverns USA
|
||||
0x00050000101F6600L, // Gravity+ USA
|
||||
0x00050000101F6A00L, // Jewel Quest EUR
|
||||
0x00050000101F6B00L, // PIXEL SLIME U EUR
|
||||
0x00050000101F7400L, // Hot Rod Racer EUR
|
||||
0x00050000101F7500L, // Midnight 2 USA
|
||||
0x00050000101F7C00L, // TAP TAP ARCADE 2 USA
|
||||
0x00050000101F8100L, // Gravity+ EUR
|
||||
0x00050000101F8400L, // JACKPOT 777 EUR
|
||||
0x00050000101F8D00L, // TAP TAP ARCADE 2 EUR
|
||||
0x00050000101F9000L, // Citadale USA
|
||||
0x00050000101F9200L, // JACKPOT 777 USA
|
||||
0x00050000101F9400L, // SD2: Go Duck Yourself USA
|
||||
0x00050000101F9900L, // Aenigma Os EUR
|
||||
0x00050000101F9A00L, // Citadale EUR
|
||||
0x00050000101FAB00L, // Collateral Thinking USA
|
||||
0x00050000101FAC00L, // INVANOID USA
|
||||
0x00050000101FAD00L, // SHOOTY SPACE USA
|
||||
0x00050000101FAF00L, // Midnight 2 EUR
|
||||
0x00050000101FB000L, // SD2: Go Duck Yourself EUR
|
||||
0x00050000101FB400L, // Shadow Archer USA
|
||||
0x00050000101FC000L, // BLOC USA
|
||||
0x00050000101FCE00L, // Word Logic by POWGI USA
|
||||
0x00050000101FD200L, // SUPER ROBO MOUSE JPN
|
||||
0x00050000101FD300L, // BLOK DROP U JPN
|
||||
0x00050000101FE600L, // Amazon Video JPN
|
||||
0x00050000101FEC00L, // Toon Tanks EUR
|
||||
0x00050000101FF900L, // Test Your Mind EUR
|
||||
0x00050000101FFA00L, // Word Logic by POWGI EUR
|
||||
0x0005000010200200L, // Collateral Thinking EUR
|
||||
0x0005000010200700L, // Twisted Fusion EUR
|
||||
0x0005000010200E00L, // PANDA LOVE USA
|
||||
0x0005000010200F00L, // PANDA LOVE EUR
|
||||
0x0005000010201500L, // TITANS TOWER USA
|
||||
0x0005000010201600L, // TITANS TOWER EUR
|
||||
0x0005000010201800L, // SHOOTY SPACE EUR
|
||||
0x0005000010202100L, // Overworld Defender Remix USA
|
||||
0x0005000010202500L, // Alice in Wonderland USA
|
||||
0x0005000010202600L, // Laser Blaster USA
|
||||
0x0005000010202700L, // Rorrim USA
|
||||
0x0005000010202900L, // Amazon Video BETA JPN
|
||||
0x0005000010202A00L, // Amazon Video USA
|
||||
0x0005000010202B00L, // Laser Blaster EUR
|
||||
0x0005000010203600L, // Rorrim EUR
|
||||
0x0005000010203900L, // Alice in Wonderland EUR
|
||||
0x0005000010203D00L, // Space Hunted: The Lost Levels USA
|
||||
0x0005000010207600L, // Space Hunted USA
|
||||
0x0005000010207700L, // Y.A.S.G USA
|
||||
0x0005000010207B00L, // Shadow Archer EUR
|
||||
0x0005000010207C00L, // A.C.E. - Alien Cleanup Elite USA
|
||||
0x0005000010208E00L, // A.C.E. EUR
|
||||
0x0005000010209D00L, // Sudoku Party EUR
|
||||
0x0005000010209E00L, // Sudoku Party USA
|
||||
0x000500001020A100L, // Star Sky 2 JPN
|
||||
0x000500001020B800L, // Scribble EUR
|
||||
0x000500001020BB00L, // Scribble USA
|
||||
0x000500001020C700L, // BLOC EUR
|
||||
0x000500001020D100L, // Pic-a-Pix Colour EUR
|
||||
0x000500001020D700L, // Pic-a-Pix Color USA
|
||||
0x000500001020F500L, // Absolutely Unstoppable MineRun EUR
|
||||
0x000500001020FD00L, // Absolutely Unstoppable MineRun USA
|
||||
0x0005000010210300L, // Citadale The Legends Trilogy EUR
|
||||
0x0005000010210400L, // Space Hunted EUR
|
||||
0x0005000010210500L, // Y.A.S.G EUR
|
||||
0x0005000010210700L, // The Stonecutter EUR
|
||||
0x0005000010211000L, // Coqui The Game USA
|
||||
0x0005000010211400L, // Daikon Set USA
|
||||
0x0005000010211E00L, // A Drawing's Journey EUR
|
||||
0x0005000010212500L, // Armored ACORNs Action Squirrel Squad EUR
|
||||
0x0005000010213500L, // Super Ultra Star Shooter EUR
|
||||
0x0005000010213B00L, // Cubeshift USA
|
||||
0x0005000010213C00L, // Super Ultra Star Shooter USA
|
||||
0x0005000010215F00L, // Spellcaster's Assistant EUR
|
||||
0x0005000010216100L, // Spellcaster's Assistant USA
|
||||
0x0005000010216D00L, // Shadow Archery USA
|
||||
0x0005000010216E00L, // Shadow Archery EUR
|
||||
0x0005000010217C00L, // Sinister Assistant EUR
|
||||
0x0005000010217F00L, // Sinister Assistant USA
|
||||
0x0005000010219C00L, // Space Hunted: The Lost Levels EUR
|
||||
0x000500001021B200L, // Captain U USA
|
||||
0x000500001021C000L, // Seasonal Assistant USA
|
||||
0x000500001021C100L, // Seasonal Assistant EUR
|
||||
0x000500001021C600L, // Captain U EUR
|
||||
0x000500001021C900L, // Reversi 32 EUR
|
||||
0x000500021016E601L, // ZaciSa's Last Stand Demo USA
|
||||
0x000500021017E201L, // 3Souls (Demo) EUR
|
||||
0x000500021017E701L, // 3Souls (Demo) USA
|
||||
0x000500021017EB01L, // SDK Paint Demo USA
|
||||
0x00050002101A2E01L, // XType+ (体験版) JPN
|
||||
0x00050002101AA301L, // SDK Spriter DEMO USA
|
||||
0x00050002101AEB01L, // SDK Paint Demo EUR
|
||||
0x00050002101B9701L, // SDK Spriter DEMO EUR
|
||||
0x00050002101BB301L, // ZaciSa: Defense of the Crayon Dimension! Demo EUR
|
||||
0x00050002101BCF01L, // Word Search by POWGI (Demo) USA
|
||||
0x00050002101C3901L, // Word Search by POWGI (Demo) EUR
|
||||
0x00050002101C4A01L, // Word Party (Demo) EUR
|
||||
0x00050002101C5501L, // Word Party (Demo) USA
|
||||
0x00050002101C5901L, // サイコロの森 3-in-1(体験版) JPN
|
||||
0x00050002101CF901L, // Word Puzzles by POWGI (Demo) EUR
|
||||
0x00050002101CFA01L, // Word Puzzles by POWGI (Demo) USA
|
||||
0x00050002101D8B01L, // ヒラメキパズル テトグラム(体験版) JPN
|
||||
0x00050002101FCE01L, // Word Logic by POWGI (Demo) USA
|
||||
0x00050002101FFA01L, // Word Logic by POWGI (Demo) EUR
|
||||
0x000500021020D101L, // Pic-a-Pix Colour (Demo) EUR
|
||||
0x000500021020D701L, // Pic-a-Pix Color (Demo) USA
|
||||
};
|
||||
|
||||
void NWF_Fix() {
|
||||
auto titleID = OSGetTitleID();
|
||||
bool found = false;
|
||||
for (auto &tid : NWFPatchTitleList) {
|
||||
if (tid == titleID) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Title using \"LibPlatform::Input::GetInstance()\" detected!");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return;
|
||||
}
|
||||
// Some games using the NWF (like Dot Arcade) keep a thread called "PlatformInputAppStateListenerThread" running,
|
||||
// which will cause a DSI exception if the title is not closing fast enough.
|
||||
auto *curThread = OSGetCurrentThread();
|
||||
__OSLockScheduler(curThread);
|
||||
int state = OSDisableInterrupts();
|
||||
OSThread *t = *((OSThread **) 0x100567F8);
|
||||
while (t) {
|
||||
if (t->name != nullptr && std::string_view(t->name) == "PlatformInputAppStateListenerThread") {
|
||||
t->priority = 0x80;
|
||||
OSReport("Set priority to %d for thread \"%s\" (%08X) to prevent it from running/crashing\n", t->priority, t->name, t);
|
||||
}
|
||||
t = t->activeLink.next;
|
||||
}
|
||||
OSRestoreInterrupts(state);
|
||||
__OSUnlockScheduler(curThread);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(void, __PPCExit, uint32_t u1) {
|
||||
NWF_Fix();
|
||||
|
||||
CallHook(WUMS_HOOK_APPLICATION_ENDS);
|
||||
CallHook(WUMS_HOOK_ALL_APPLICATION_ENDS_DONE);
|
||||
CallHook(WUMS_HOOK_FINI_WUT_SOCKETS);
|
||||
CallHook(WUMS_HOOK_FINI_WUT_DEVOPTAB);
|
||||
if (gSDMountRefCount > 0) {
|
||||
@ -17,6 +311,14 @@ DECL_FUNCTION(void, __PPCExit, uint32_t u1) {
|
||||
}
|
||||
gSDMountRefCount = 0;
|
||||
}
|
||||
|
||||
if (gModuleData->number_acquired_rpls > 0) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Release RPLs acquired by modules");
|
||||
for (uint32_t i = 0; i < gModuleData->number_acquired_rpls; i++) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("OSDynLoad_Release(0x%08X)", gModuleData->acquired_rpls[i]);
|
||||
OSDynLoad_Release((void *) gModuleData->acquired_rpls[i]);
|
||||
}
|
||||
}
|
||||
real___PPCExit(u1);
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,8 @@
|
||||
void initSymbolNamePatcher() {
|
||||
DEBUG_FUNCTION_LINE("Patch SymbolNamePatcher functions");
|
||||
for (uint32_t i = 0; i < symbolname_function_replacements_size; i++) {
|
||||
if (!FunctionPatcherPatchFunction(&symbolname_function_replacements[i], nullptr)) {
|
||||
bool wasPatched = false;
|
||||
if (FunctionPatcher_AddFunctionPatch(&symbolname_function_replacements[i], nullptr, &wasPatched) != FUNCTION_PATCHER_RESULT_SUCCESS || !wasPatched) {
|
||||
OSFatal("AromaBaseModule: Failed to patch SymbolNamePatcher function");
|
||||
}
|
||||
}
|
||||
|
2
source/version.h
Normal file
2
source/version.h
Normal file
@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
#define VERSION_EXTRA ""
|
Loading…
x
Reference in New Issue
Block a user