diff --git a/Makefile b/Makefile index 976d523..57a5067 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ WUMS_ROOT := $(DEVKITPRO)/wums # DATA is a list of directories containing data files # INCLUDES is a list of directories containing header files #------------------------------------------------------------------------------- -TARGET := payload +TARGET := 10_wums_loader BUILD := build SOURCES := source \ source/elfio\ @@ -39,7 +39,7 @@ CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ CXXFLAGS := $(CFLAGS) -std=c++20 ASFLAGS := -g $(ARCH) -LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) +LDFLAGS = -g $(ARCH) $(RPXSPECS) --entry=_start -Wl,-Map,$(notdir $*.map) LIBS := -lwut -lz diff --git a/README.md b/README.md index 29c8659..137216c 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,12 @@ -# Setup payload -This is a payload that should be run with [CustomRPXLoader](https://github.com/wiiu-env/CustomRPXLoader). +# Wii U Module System Loader +This is a payload that should be run with [EnvironmentLoader](https://github.com/wiiu-env/EnvironmentLoader). ## Usage -Put the `payload.rpx` in the `sd:/wiiu/` folder of your sd card and use the `CustomRPXLoader` to run this setup payload. +Put the `10_wums_loader.rpx` in the `fs:/vol/external01/wiiu/environments/[ENVIRONMENT]/modules/setup` folder of your sd card and use the `EnvironmentLoader` to run this setup payload. -Put modules (in form of `.wms` files) that should be used a main()-hook into `sd:/wiiu/modules/` and one time modules into `sd:/wiiu/modules/setup`. -- Make sure not to call `exit` in the modules (by using the WiiUModuleSystem) -- The one time setups will be run in the order of their ordered filenames. +Put modules (in form of `.wms` files) that should be used a main()-hook into `fs:/vol/external01/wiiu/environments/[ENVIRONMENT]/modules/`. -The area between `0x00800000` and whereever this setup is loaded, will be used. +The area between `0x00800000` and whereever this loader is loaded, will be used. ## Building Make you to have [wut](https://github.com/devkitPro/wut/) and [WiiUModuleSystem](https://github.com/wiiu-env/WiiUModuleSystem) installed and use the following command for build: @@ -22,13 +20,13 @@ It's possible to use a docker image for building. This way you don't need anythi ``` # Build docker image (only needed once) -docker build . -t setuppayload-builder +docker build . -t wumsloader-builder # make -docker run -it --rm -v ${PWD}:/project setuppayload-builder make +docker run -it --rm -v ${PWD}:/project wumsloader-builder make # make clean -docker run -it --rm -v ${PWD}:/project setuppayload-builder make clean +docker run -it --rm -v ${PWD}:/project wumsloader-builder make clean ``` diff --git a/source/crt.c b/source/crt.c new file mode 100644 index 0000000..2fcd925 --- /dev/null +++ b/source/crt.c @@ -0,0 +1,36 @@ +void __init_wut_malloc(); + +void __init_wut_newlib(); + +void __init_wut_stdcpp(); + +void __init_wut_devoptab(); + +void __attribute__((weak)) __init_wut_socket(); + +void __fini_wut_malloc(); + +void __fini_wut_newlib(); + +void __fini_wut_stdcpp(); + +void __fini_wut_devoptab(); + +void __attribute__((weak)) __fini_wut_socket(); + +void __attribute__((weak)) +__init_wut_() { + __init_wut_malloc(); + __init_wut_newlib(); + __init_wut_stdcpp(); + __init_wut_devoptab(); + if (&__init_wut_socket) __init_wut_socket(); +} + +void __attribute__((weak)) +__fini_wut_() { + __fini_wut_devoptab(); + __fini_wut_stdcpp(); + __fini_wut_newlib(); + __fini_wut_malloc(); +} diff --git a/source/crt0.s b/source/crt0.s new file mode 100644 index 0000000..318de30 --- /dev/null +++ b/source/crt0.s @@ -0,0 +1,29 @@ +.extern main +.extern exit +.extern __init_wut_ +.extern __fini_wut_ + +.global _start +_start: + stwu 1, -0x28(1) + mflr 0 + stw 0, 0x2C(1) + stw 31, 0x24(1) + or 31, 1, 1 + stw 3, 0x18(31) + stw 4, 0x1C(31) + bl __init_wut_ + lwz 4, 0x1C(31) + lwz 3, 0x18(31) + bl main + or 9, 3, 3 + stw 9, 0x8(31) + bl __fini_wut_ + lwz 9, 0x8(31) + or 3, 9, 9 + addi 11, 31, 0x28 + lwz 0, 0x4(11) + mtlr 0 + lwz 31, -0x4(11) + or 1, 11, 11 + blr \ No newline at end of file diff --git a/source/main.cpp b/source/main.cpp index 32589e4..227ce15 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,17 +1,11 @@ #include #include -#include #include -#include -#include #include -#include #include #include #include -#include -#include #include "fs/DirList.h" #include "module/ModuleDataPersistence.h" @@ -20,106 +14,33 @@ #include "kernel.h" #include "globals.h" -bool CheckRunning() { - switch (ProcUIProcessMessages(true)) { - case PROCUI_STATUS_EXITING: { - return false; - } - case PROCUI_STATUS_RELEASE_FOREGROUND: { - ProcUIDrawDoneRelease(); - break; - } - case PROCUI_STATUS_IN_FOREGROUND: { - break; - } - case PROCUI_STATUS_IN_BACKGROUND: - default: - break; - } - return true; -} - extern "C" uint32_t textStart(); -extern "C" void _SYSLaunchMenuWithCheckingAccount(nn::act::SlotNo slot); - -bool doRelocation(std::vector> &relocData, relocation_trampolin_entry_t *tramp_data, uint32_t tramp_length) { - for (auto const &curReloc: relocData) { - std::string functionName = curReloc->getName(); - std::string rplName = curReloc->getImportRPLInformation()->getName(); - int32_t isData = curReloc->getImportRPLInformation()->isData(); - OSDynLoad_Module rplHandle = nullptr; - - if (OSDynLoad_IsModuleLoaded(rplName.c_str(), &rplHandle) != OS_DYNLOAD_OK) { - // only acquire if not already loaded. - OSDynLoad_Acquire(rplName.c_str(), &rplHandle); - } - - uint32_t functionAddress = 0; - OSDynLoad_FindExport(rplHandle, isData, functionName.c_str(), (void **) &functionAddress); - if (functionAddress == 0) { - return false; - } - if (!ElfUtils::elfLinkOne(curReloc->getType(), curReloc->getOffset(), curReloc->getAddend(), (uint32_t) curReloc->getDestination(), functionAddress, tramp_data, tramp_length, - RELOC_TYPE_IMPORT)) { - DEBUG_FUNCTION_LINE("Relocation failed\n"); - return false; - } - } - - DCFlushRange(tramp_data, tramp_length * sizeof(relocation_trampolin_entry_t)); - ICInvalidateRange(tramp_data, tramp_length * sizeof(relocation_trampolin_entry_t)); - return true; -} - int main(int argc, char **argv) { if (!WHBLogModuleInit()) { WHBLogCafeInit(); WHBLogUdpInit(); } - // 0x100 because before the .text section is a .init section - // Currently the size of the .init is ~ 0x24 bytes. We substract 0x100 to be safe. - uint32_t textSectionStart = textStart() - 0x1000; - - DirList setupModules("fs:/vol/external01/wiiu/modules/setup", ".rpx", DirList::Files, 1); - setupModules.SortList(); - - for (int i = 0; i < setupModules.GetFilecount(); i++) { - uint32_t destination_address = ((uint32_t) gModuleData + (sizeof(module_information_t) + 0x0000FFFF)) & 0xFFFF0000; - memset((void *) gModuleData, 0, sizeof(module_information_t)); - DEBUG_FUNCTION_LINE("Trying to run %s", setupModules.GetFilepath(i)); - auto moduleData = ModuleDataFactory::load(setupModules.GetFilepath(i), &destination_address, textSectionStart - destination_address, gModuleData->trampolines, - DYN_LINK_TRAMPOLIN_LIST_LENGTH); - if (!moduleData) { - DEBUG_FUNCTION_LINE("Failed to load %s", setupModules.GetFilepath(i)); - continue; - } - DEBUG_FUNCTION_LINE("Loaded module data"); - auto relocData = moduleData.value()->getRelocationDataList(); - if (!doRelocation(relocData, gModuleData->trampolines, DYN_LINK_TRAMPOLIN_LIST_LENGTH)) { - DEBUG_FUNCTION_LINE("relocations failed\n"); - } - - DCFlushRange((void *) moduleData.value()->getStartAddress(), moduleData.value()->getEndAddress() - moduleData.value()->getStartAddress()); - ICInvalidateRange((void *) moduleData.value()->getStartAddress(), moduleData.value()->getEndAddress() - moduleData.value()->getStartAddress()); - DEBUG_FUNCTION_LINE("Calling entrypoint @%08X", moduleData.value()->getEntrypoint()); - ((int (*)(int, char **)) moduleData.value()->getEntrypoint())(argc, argv); - DEBUG_FUNCTION_LINE("Back from module"); - } + // We subtract 0x100 to be safe. + uint32_t textSectionStart = textStart() - 0x100; memset((void *) gModuleData, 0, sizeof(module_information_t)); gModuleData->version = MODULE_INFORMATION_VERSION; - DirList modules("fs:/vol/external01/wiiu/modules", ".wms", DirList::Files, 1); + std::string basePath = "fs:/vol/external01/wiiu"; + if (argc >= 1) { + basePath = argv[0]; + } + + DirList modules(basePath + "/modules", ".wms", DirList::Files, 1); modules.SortList(); uint32_t destination_address = ((uint32_t) gModuleData + (sizeof(module_information_t) + 0x0000FFFF)) & 0xFFFF0000; for (int i = 0; i < modules.GetFilecount(); i++) { DEBUG_FUNCTION_LINE("Loading module %s", modules.GetFilepath(i)); - auto moduleData = ModuleDataFactory::load(modules.GetFilepath(i), &destination_address, MEMORY_REGION_USABLE_END - destination_address, gModuleData->trampolines, + auto moduleData = ModuleDataFactory::load(modules.GetFilepath(i), &destination_address, textSectionStart - destination_address, gModuleData->trampolines, DYN_LINK_TRAMPOLIN_LIST_LENGTH); - if (moduleData) { DEBUG_FUNCTION_LINE("Successfully loaded %s", modules.GetFilepath(i)); ModuleDataPersistence::saveModuleData(gModuleData, moduleData.value()); @@ -132,8 +53,6 @@ int main(int argc, char **argv) { WHBLogUdpDeinit(); - ProcUIInit(OSSavesDone_ReadyToRelease); - nn::act::Initialize(); nn::act::SlotNo slot = nn::act::GetSlotNo(); nn::act::SlotNo defaultSlot = nn::act::GetDefaultAccount(); @@ -144,11 +63,5 @@ int main(int argc, char **argv) { } else { //show mii select _SYSLaunchMenuWithCheckingAccount(slot); } - while (CheckRunning()) { - // wait. - OSSleepTicks(OSMillisecondsToTicks(100)); - } - ProcUIShutdown(); - return 0; } diff --git a/source/pc.s b/source/pc.s index 1a8a70f..baa1a0f 100644 --- a/source/pc.s +++ b/source/pc.s @@ -1,4 +1,4 @@ -.section ".text" +.section ".crt0" .global textStart textStart: mflr 4;