2020-08-23 12:59:52 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Copyright (C) 2018-2020 Maschell
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
****************************************************************************/
|
|
|
|
|
2021-09-18 12:10:58 +02:00
|
|
|
#include <cstdint>
|
2020-04-27 13:32:37 +02:00
|
|
|
#include <coreinit/cache.h>
|
|
|
|
#include <coreinit/dynload.h>
|
2020-10-19 00:22:25 +02:00
|
|
|
#include <coreinit/title.h>
|
2020-04-27 13:32:37 +02:00
|
|
|
#include <sysapp/launch.h>
|
|
|
|
#include <proc_ui/procui.h>
|
|
|
|
#include <coreinit/foreground.h>
|
2020-10-19 00:21:59 +02:00
|
|
|
#include <coreinit/screen.h>
|
2020-11-26 21:14:37 +01:00
|
|
|
#include <nn/act/client_cpp.h>
|
2020-04-27 13:32:37 +02:00
|
|
|
|
|
|
|
#include "ElfUtils.h"
|
|
|
|
#include "module/ModuleData.h"
|
|
|
|
#include "module/ModuleDataFactory.h"
|
|
|
|
#include "common/module_defines.h"
|
|
|
|
|
2020-05-28 20:53:27 +02:00
|
|
|
#include <whb/log.h>
|
|
|
|
#include <whb/log_udp.h>
|
2020-10-19 00:21:59 +02:00
|
|
|
#include <utils/StringTools.h>
|
2020-05-28 20:53:27 +02:00
|
|
|
|
2020-04-27 13:32:37 +02:00
|
|
|
#include "kernel.h"
|
|
|
|
#include "dynamic.h"
|
|
|
|
#include "utils/logger.h"
|
2021-01-01 20:01:28 +01:00
|
|
|
#include <malloc.h>
|
|
|
|
#include <coreinit/memexpheap.h>
|
2020-04-27 13:32:37 +02:00
|
|
|
|
2020-08-23 13:06:32 +02:00
|
|
|
bool doRelocation(const std::vector<RelocationData> &relocData, relocation_trampolin_entry_t *tramp_data, uint32_t tramp_length);
|
2020-04-27 13:32:37 +02:00
|
|
|
|
2020-10-19 00:21:59 +02:00
|
|
|
void SplashScreen(const char *message, int32_t durationInMs);
|
|
|
|
|
2021-12-30 15:26:23 +01:00
|
|
|
uint32_t do_start(int argc, char **argv);
|
2021-01-01 20:01:28 +01:00
|
|
|
|
2020-04-27 13:32:37 +02:00
|
|
|
bool CheckRunning() {
|
2020-08-23 10:44:14 +02:00
|
|
|
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;
|
2020-04-27 13:32:37 +02:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-05-28 20:53:27 +02:00
|
|
|
extern "C" void __init_wut();
|
|
|
|
extern "C" void __fini_wut();
|
|
|
|
|
2020-04-27 13:32:37 +02:00
|
|
|
extern "C" int _start(int argc, char **argv) {
|
|
|
|
doKernelSetup();
|
|
|
|
InitFunctionPointers();
|
2020-04-27 18:35:24 +02:00
|
|
|
doKernelSetup2();
|
2020-04-27 13:32:37 +02:00
|
|
|
|
2020-05-28 20:53:27 +02:00
|
|
|
__init_wut();
|
|
|
|
|
|
|
|
WHBLogUdpInit();
|
2020-04-27 13:32:37 +02:00
|
|
|
|
2021-01-01 20:01:28 +01:00
|
|
|
// Save last entry on mem2 heap to detect leaked memory
|
|
|
|
MEMHeapHandle mem2_heap_handle = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM2);
|
|
|
|
auto heap = (MEMExpHeap *) mem2_heap_handle;
|
|
|
|
MEMExpHeapBlock *memory_start = heap->usedList.tail;
|
|
|
|
|
2021-12-30 15:26:23 +01:00
|
|
|
uint32_t entrypoint = do_start(argc, argv);
|
|
|
|
|
2021-01-01 20:01:28 +01:00
|
|
|
// free leaked memory
|
|
|
|
if (memory_start) {
|
|
|
|
int leak_count = 0;
|
|
|
|
while (true) {
|
|
|
|
MEMExpHeapBlock *memory_end = heap->usedList.tail;
|
|
|
|
if (memory_end == memory_start) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
free(&memory_end[1]);
|
|
|
|
leak_count++;
|
|
|
|
}
|
|
|
|
DEBUG_FUNCTION_LINE("Freed %d leaked memory blocks", leak_count);
|
|
|
|
}
|
|
|
|
|
|
|
|
WHBLogUdpDeinit();
|
|
|
|
|
|
|
|
__fini_wut();
|
2021-12-30 15:26:23 +01:00
|
|
|
|
|
|
|
if (entrypoint > 0) {
|
2021-12-30 16:01:06 +01:00
|
|
|
return ((int (*)(int, char **)) entrypoint)(argc, argv);
|
2021-12-30 15:26:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
2021-01-01 20:01:28 +01:00
|
|
|
}
|
|
|
|
|
2021-12-30 15:26:23 +01:00
|
|
|
uint32_t do_start(int argc, char **argv) {
|
2020-10-19 00:15:44 +02:00
|
|
|
// If we load from our CustomRPXLoader the argv is set with "safe.rpx"
|
|
|
|
// in this case we don't want to do any ProcUi stuff on error, only on success
|
2021-01-01 20:00:50 +01:00
|
|
|
bool doProcUI = (argc >= 1 && std::string(argv[0]) != "safe.rpx");
|
2020-05-28 20:53:27 +02:00
|
|
|
|
2021-09-18 12:10:58 +02:00
|
|
|
auto *cfwLaunchedWithPtr = (uint64_t *) 0x00FFFFF8;
|
2020-10-19 00:22:25 +02:00
|
|
|
*cfwLaunchedWithPtr = OSGetTitleID();
|
|
|
|
|
2020-05-28 20:53:27 +02:00
|
|
|
uint32_t ApplicationMemoryEnd;
|
|
|
|
|
|
|
|
asm volatile("lis %0, __CODE_END@h; ori %0, %0, __CODE_END@l" : "=r" (ApplicationMemoryEnd));
|
|
|
|
|
|
|
|
ApplicationMemoryEnd = (ApplicationMemoryEnd + 0x100) & 0xFFFFFF00;
|
|
|
|
|
2021-09-18 12:10:58 +02:00
|
|
|
auto *gModuleData = (module_information_t *) ApplicationMemoryEnd;
|
2020-05-28 20:53:27 +02:00
|
|
|
|
|
|
|
uint32_t moduleDataStartAddress = ((uint32_t) gModuleData + sizeof(module_information_t));
|
|
|
|
moduleDataStartAddress = (moduleDataStartAddress + 0x10000) & 0xFFFF0000;
|
|
|
|
|
2020-10-19 00:21:59 +02:00
|
|
|
std::string filepath("fs:/vol/external01/wiiu/payload.rpx");
|
2021-01-01 20:01:28 +01:00
|
|
|
int result = 0;
|
2020-10-19 00:19:04 +02:00
|
|
|
// The module will be loaded to 0x00FFF000 - sizeof(payload.rpx)
|
2021-01-01 20:01:28 +01:00
|
|
|
std::optional<ModuleData> moduleData = ModuleDataFactory::load(filepath, 0x00FFF000, 0x00FFF000 - moduleDataStartAddress, gModuleData->trampolines, DYN_LINK_TRAMPOLIN_LIST_LENGTH);
|
2020-10-19 00:12:19 +02:00
|
|
|
if (moduleData) {
|
2020-05-28 20:53:27 +02:00
|
|
|
DEBUG_FUNCTION_LINE("Loaded module data");
|
2021-01-01 20:01:28 +01:00
|
|
|
std::vector<RelocationData> relocData = moduleData->getRelocationDataList();
|
2020-08-23 10:44:14 +02:00
|
|
|
if (!doRelocation(relocData, gModuleData->trampolines, DYN_LINK_TRAMPOLIN_LIST_LENGTH)) {
|
2020-05-28 20:53:27 +02:00
|
|
|
DEBUG_FUNCTION_LINE("relocations failed");
|
|
|
|
}
|
2020-08-23 10:44:14 +02:00
|
|
|
if (moduleData->getBSSAddr() != 0) {
|
2020-05-28 20:53:27 +02:00
|
|
|
DEBUG_FUNCTION_LINE("memset .bss %08X (%d)", moduleData->getBSSAddr(), moduleData->getBSSSize());
|
2020-08-23 10:44:14 +02:00
|
|
|
memset((void *) moduleData->getBSSAddr(), 0, moduleData->getBSSSize());
|
2020-05-28 20:53:27 +02:00
|
|
|
}
|
2020-08-23 10:44:14 +02:00
|
|
|
if (moduleData->getSBSSAddr() != 0) {
|
2020-05-28 20:53:27 +02:00
|
|
|
DEBUG_FUNCTION_LINE("memset .sbss %08X (%d)", moduleData->getSBSSAddr(), moduleData->getSBSSSize());
|
2020-08-23 10:44:14 +02:00
|
|
|
memset((void *) moduleData->getSBSSAddr(), 0, moduleData->getSBSSSize());
|
2020-04-27 13:32:37 +02:00
|
|
|
}
|
2020-08-23 10:44:14 +02:00
|
|
|
DCFlushRange((void *) 0x00800000, 0x00800000);
|
|
|
|
ICInvalidateRange((void *) 0x00800000, 0x00800000);
|
2021-01-01 20:01:28 +01:00
|
|
|
DEBUG_FUNCTION_LINE("Calling entrypoint at: %08X", moduleData->getEntrypoint());
|
2021-12-30 15:26:23 +01:00
|
|
|
return moduleData->getEntrypoint();
|
2020-04-27 13:32:37 +02:00
|
|
|
} else {
|
2020-10-19 00:16:45 +02:00
|
|
|
DEBUG_FUNCTION_LINE("Failed to load module, revert main_hook");
|
|
|
|
revertMainHook();
|
2020-10-19 00:21:59 +02:00
|
|
|
SplashScreen(StringTools::strfmt("Failed to load \"%s\"", filepath.c_str()).c_str(), 3000);
|
2021-12-30 15:26:23 +01:00
|
|
|
result = 0;
|
2020-04-27 13:32:37 +02:00
|
|
|
}
|
|
|
|
|
2020-10-19 00:15:44 +02:00
|
|
|
if (doProcUI) {
|
2020-11-26 21:14:37 +01:00
|
|
|
nn::act::Initialize();
|
|
|
|
nn::act::SlotNo slot = nn::act::GetSlotNo();
|
|
|
|
nn::act::SlotNo defaultSlot = nn::act::GetDefaultAccount();
|
|
|
|
nn::act::Finalize();
|
|
|
|
|
|
|
|
if (defaultSlot) {
|
|
|
|
//normal menu boot
|
|
|
|
SYSLaunchMenu();
|
|
|
|
} else {
|
|
|
|
//show mii select
|
|
|
|
_SYSLaunchMenuWithCheckingAccount(slot);
|
|
|
|
}
|
2020-10-19 00:15:44 +02:00
|
|
|
ProcUIInit(OSSavesDone_ReadyToRelease);
|
|
|
|
DEBUG_FUNCTION_LINE("In ProcUI loop");
|
|
|
|
while (CheckRunning()) {
|
|
|
|
// wait.
|
|
|
|
OSSleepTicks(OSMillisecondsToTicks(100));
|
|
|
|
}
|
|
|
|
ProcUIShutdown();
|
2020-04-27 13:32:37 +02:00
|
|
|
}
|
|
|
|
|
2021-01-01 20:01:28 +01:00
|
|
|
return result;
|
2020-04-27 13:32:37 +02:00
|
|
|
}
|
|
|
|
|
2020-08-23 13:06:32 +02:00
|
|
|
bool doRelocation(const std::vector<RelocationData> &relocData, relocation_trampolin_entry_t *tramp_data, uint32_t tramp_length) {
|
2021-09-23 18:30:08 +02:00
|
|
|
for (auto const &curReloc: relocData) {
|
|
|
|
const RelocationData &cur = curReloc;
|
2020-08-23 13:06:32 +02:00
|
|
|
std::string functionName = cur.getName();
|
|
|
|
std::string rplName = cur.getImportRPLInformation().getName();
|
|
|
|
int32_t isData = cur.getImportRPLInformation().isData();
|
2020-04-27 13:32:37 +02:00
|
|
|
OSDynLoad_Module rplHandle = 0;
|
|
|
|
OSDynLoad_Acquire(rplName.c_str(), &rplHandle);
|
|
|
|
|
|
|
|
uint32_t functionAddress = 0;
|
2020-08-23 10:44:14 +02:00
|
|
|
OSDynLoad_FindExport(rplHandle, isData, functionName.c_str(), (void **) &functionAddress);
|
|
|
|
if (functionAddress == 0) {
|
2020-04-27 13:32:37 +02:00
|
|
|
return false;
|
|
|
|
}
|
2020-08-23 13:06:32 +02:00
|
|
|
if (!ElfUtils::elfLinkOne(cur.getType(), cur.getOffset(), cur.getAddend(), (uint32_t) cur.getDestination(), functionAddress, tramp_data, tramp_length, RELOC_TYPE_IMPORT)) {
|
2020-05-28 20:53:27 +02:00
|
|
|
DEBUG_FUNCTION_LINE("Relocation failed");
|
2020-04-27 13:32:37 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DCFlushRange(tramp_data, tramp_length * sizeof(relocation_trampolin_entry_t));
|
|
|
|
ICInvalidateRange(tramp_data, tramp_length * sizeof(relocation_trampolin_entry_t));
|
|
|
|
return true;
|
|
|
|
}
|
2020-10-19 00:21:59 +02:00
|
|
|
|
|
|
|
void SplashScreen(const char *message, int32_t durationInMs) {
|
|
|
|
// Init screen and screen buffers
|
|
|
|
OSScreenInit();
|
2021-01-01 20:01:28 +01:00
|
|
|
uint32_t screen_buf0_size = OSScreenGetBufferSizeEx(SCREEN_TV);
|
|
|
|
uint32_t screen_buf1_size = OSScreenGetBufferSizeEx(SCREEN_DRC);
|
2021-09-18 12:10:58 +02:00
|
|
|
auto *screenBuffer = (uint8_t *) memalign(0x100, screen_buf0_size + screen_buf1_size);
|
2021-01-01 20:01:28 +01:00
|
|
|
OSScreenSetBufferEx(SCREEN_TV, (void *) screenBuffer);
|
|
|
|
OSScreenSetBufferEx(SCREEN_DRC, (void *) (screenBuffer + screen_buf0_size));
|
2020-10-19 00:21:59 +02:00
|
|
|
|
|
|
|
OSScreenEnableEx(SCREEN_TV, 1);
|
|
|
|
OSScreenEnableEx(SCREEN_DRC, 1);
|
|
|
|
|
|
|
|
// Clear screens
|
|
|
|
OSScreenClearBufferEx(SCREEN_TV, 0);
|
|
|
|
OSScreenClearBufferEx(SCREEN_DRC, 0);
|
|
|
|
|
|
|
|
OSScreenPutFontEx(SCREEN_TV, 0, 0, message);
|
|
|
|
OSScreenPutFontEx(SCREEN_DRC, 0, 0, message);
|
|
|
|
|
|
|
|
|
|
|
|
OSScreenFlipBuffersEx(SCREEN_TV);
|
|
|
|
OSScreenFlipBuffersEx(SCREEN_DRC);
|
|
|
|
|
|
|
|
OSSleepTicks(OSMillisecondsToTicks(durationInMs));
|
2021-01-01 20:01:28 +01:00
|
|
|
free(screenBuffer);
|
2020-10-19 00:21:59 +02:00
|
|
|
}
|