mirror of
https://github.com/wiiu-env/WiiUPluginSystem.git
synced 2024-12-24 00:51:59 +01:00
[Loader] Added intial code for Memory mapping!
The loader will now map some (hopefully) unused memory into userland using the segement registers. Currently we can get ~ 65mb of extra memory. At the moment, none if this memory is used, at first it needs to be checked if it's really unused. Press MINUS in the plugin loader to map the memory, this can take a moment. Check the UDPLogger for the mapping information. When the memory was mapped, values will be written to the PHYSICAL memory addresses, and read from the effective addresses as an test..
This commit is contained in:
parent
60e49ea83f
commit
a839430ea0
@ -37,6 +37,8 @@ SOURCES := src/common \
|
||||
src/libelf \
|
||||
src/menu/content \
|
||||
src/menu \
|
||||
src/mymemory \
|
||||
src/mykernel \
|
||||
src/myutils \
|
||||
src/patcher \
|
||||
src/plugin \
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <utils/logger.h>
|
||||
#include "settings/CSettings.h"
|
||||
#include "myutils/TcpReceiver.h"
|
||||
#include "mymemory/memory_mapping.h"
|
||||
|
||||
Application *Application::applicationInstance = NULL;
|
||||
bool Application::exitApplication = false;
|
||||
@ -185,6 +186,11 @@ void Application::executeThread(void) {
|
||||
exitApplication = true;
|
||||
}
|
||||
|
||||
if(controller[i]->data.buttons_d & VPAD_BUTTON_MINUS) {
|
||||
exitCode = APPLICATION_CLOSE_APPLY_MEMORY;
|
||||
exitApplication = true;
|
||||
}
|
||||
|
||||
if(controller[i]->data.buttons_d & VPAD_BUTTON_HOME) {
|
||||
exitCode = APPLICATION_CLOSE_MIIMAKER;
|
||||
exitApplication = true;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <language/gettext.h>
|
||||
|
||||
#define APPLICATION_CLOSE_APPLY 1
|
||||
#define APPLICATION_CLOSE_APPLY_MEMORY 3
|
||||
#define APPLICATION_CLOSE_MIIMAKER 2
|
||||
|
||||
class Application : public CThread {
|
||||
|
@ -30,14 +30,17 @@
|
||||
#include <utils/function_patcher.h>
|
||||
#include <system/exception_handler.h>
|
||||
#include <system/memory.h>
|
||||
|
||||
#include <kernel/kernel_utils.h>
|
||||
#include <mykernel/kernel_utils.h>
|
||||
|
||||
#include "mymemory/memory_mapping.h"
|
||||
|
||||
#include "common/retain_vars.h"
|
||||
#include "common/common.h"
|
||||
#include "plugin/PluginLoader.h"
|
||||
#include "plugin/PluginInformation.h"
|
||||
|
||||
|
||||
#include <wups.h>
|
||||
#include <iosuhax.h>
|
||||
#include <fat.h>
|
||||
@ -56,16 +59,15 @@
|
||||
#include "settings/CSettings.h"
|
||||
|
||||
static void ApplyPatchesAndCallHookStartingApp();
|
||||
void CallHook(wups_loader_hook_type_t hook_type);
|
||||
static void RestorePatches();
|
||||
s32 isInMiiMakerHBL();
|
||||
|
||||
/* Entry point */
|
||||
extern "C" int Menu_Main(int argc, char **argv) {
|
||||
if(gAppStatus == 2) {
|
||||
//"No, we don't want to patch stuff again.");
|
||||
return EXIT_RELAUNCH_ON_LOAD;
|
||||
}
|
||||
|
||||
InitOSFunctionPointers();
|
||||
InitSocketFunctionPointers(); //For logging
|
||||
InitSysFunctionPointers();
|
||||
@ -80,14 +82,21 @@ extern "C" int Menu_Main(int argc, char **argv) {
|
||||
log_init();
|
||||
|
||||
DEBUG_FUNCTION_LINE("We have %d kb for plugins.\n",(PLUGIN_LOCATION_END_ADDRESS-getApplicationEndAddr())/1024);
|
||||
setup_os_exceptions();
|
||||
|
||||
DEBUG_FUNCTION_LINE("Wii U Plugin System Loader %s\n",APP_VERSION);
|
||||
|
||||
//setup_os_exceptions();
|
||||
|
||||
Init();
|
||||
|
||||
init_kernel_syscalls();
|
||||
wups_init_kernel_syscalls();
|
||||
|
||||
gGameTitleID = OSGetTitleID();
|
||||
|
||||
if(MemoryMapping::isMemoryMapped()) {
|
||||
DEBUG_FUNCTION_LINE("Mapping was already done.\n");
|
||||
MemoryMapping::readTestValuesFromMemory();
|
||||
}
|
||||
|
||||
s32 result = 0;
|
||||
|
||||
//Reset everything when were going back to the Mii Maker
|
||||
@ -95,7 +104,6 @@ extern "C" int Menu_Main(int argc, char **argv) {
|
||||
CallHook(WUPS_LOADER_HOOK_DEINIT_PLUGIN);
|
||||
// Restore patches as the patched functions could change.
|
||||
RestorePatches();
|
||||
|
||||
PluginLoader * pluginLoader = PluginLoader::getInstance();
|
||||
std::vector<PluginInformation *> pluginList = pluginLoader->getPluginInformation("sd:/wiiu/plugins/");
|
||||
pluginLoader->loadAndLinkPlugins(pluginList);
|
||||
@ -109,6 +117,8 @@ extern "C" int Menu_Main(int argc, char **argv) {
|
||||
DEBUG_FUNCTION_LINE("Start main application\n");
|
||||
result = Application::instance()->exec();
|
||||
DEBUG_FUNCTION_LINE("Main application stopped result: %d\n",result);
|
||||
|
||||
DEBUG_FUNCTION_LINE("Application::destroyInstance\n");
|
||||
Application::destroyInstance();
|
||||
|
||||
DEBUG_FUNCTION_LINE("Release memory\n");
|
||||
@ -117,28 +127,38 @@ extern "C" int Menu_Main(int argc, char **argv) {
|
||||
PluginLoader::destroyInstance();
|
||||
}
|
||||
|
||||
if(result == APPLICATION_CLOSE_APPLY_MEMORY){
|
||||
if(!MemoryMapping::isMemoryMapped()) {
|
||||
MemoryMapping::setupMemoryMapping();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!isInMiiMakerHBL()) {
|
||||
//CallHook(WUPS_LOADER_HOOK_STARTING_APPLICATION);
|
||||
DEBUG_FUNCTION_LINE("Apply patches.\n");
|
||||
ApplyPatchesAndCallHookStartingApp();
|
||||
return EXIT_RELAUNCH_ON_LOAD;
|
||||
}
|
||||
|
||||
if(result == APPLICATION_CLOSE_APPLY) {
|
||||
|
||||
if(result == APPLICATION_CLOSE_APPLY || result == APPLICATION_CLOSE_APPLY_MEMORY) {
|
||||
CallHook(WUPS_LOADER_HOOK_INIT_FS);
|
||||
CallHook(WUPS_LOADER_HOOK_INIT_OVERLAY);
|
||||
CallHook(WUPS_LOADER_HOOK_INIT_PLUGIN);
|
||||
DEBUG_FUNCTION_LINE("Loading the system menu.\n");
|
||||
DeInit();
|
||||
init_kernel_syscalls();
|
||||
SYSLaunchMenu();
|
||||
return EXIT_RELAUNCH_ON_LOAD;
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("Going back to the Homebrew Launcher\n");
|
||||
DEBUG_FUNCTION_LINE("Let's go to back to the Homebrew Launcher\n");
|
||||
DEBUG_FUNCTION_LINE("Restoring the patched functions\n");
|
||||
RestorePatches();
|
||||
DEBUG_FUNCTION_LINE("Calling the plugin deinit hook\n");
|
||||
CallHook(WUPS_LOADER_HOOK_DEINIT_PLUGIN);
|
||||
DEBUG_FUNCTION_LINE("Unmounting SD/USB devices\n");
|
||||
DeInit();
|
||||
DEBUG_FUNCTION_LINE("Bye bye!\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
33
loader/src/mykernel/kernel_defs.h
Normal file
33
loader/src/mykernel/kernel_defs.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef __WUPS_KERNEL_DEFS_H_
|
||||
#define __WUPS_KERNEL_DEFS_H_
|
||||
|
||||
#include <dynamic_libs/fs_functions.h>
|
||||
#include <dynamic_libs/os_types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct _sr_table_t
|
||||
{
|
||||
u32 value[16];
|
||||
u32 sdr1;
|
||||
} sr_table_t;
|
||||
|
||||
typedef struct _bat_t
|
||||
{
|
||||
u32 h;
|
||||
u32 l;
|
||||
} bat_t;
|
||||
|
||||
typedef struct _bat_table_t
|
||||
{
|
||||
bat_t bat[8];
|
||||
} bat_table_t;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __KERNEL_DEFS_H_
|
181
loader/src/mykernel/kernel_utils.c
Normal file
181
loader/src/mykernel/kernel_utils.c
Normal file
@ -0,0 +1,181 @@
|
||||
#include <dynamic_libs/os_defs.h>
|
||||
#include <dynamic_libs/os_functions.h>
|
||||
#include "kernel_defs.h"
|
||||
#include <kernel/syscalls.h>
|
||||
|
||||
static void KernelReadSRs(sr_table_t * table) {
|
||||
u32 i = 0;
|
||||
|
||||
// calculate PT_size ((end-start)*8/4096)*4 or (end-start)/128
|
||||
// Minimum page table size is 64Kbytes.
|
||||
|
||||
asm volatile("eieio; isync");
|
||||
|
||||
asm volatile("mfspr %0, 25" : "=r" (table->sdr1));
|
||||
|
||||
asm volatile("mfsr %0, 0" : "=r" (table->value[i]));
|
||||
i++;
|
||||
asm volatile("mfsr %0, 1" : "=r" (table->value[i]));
|
||||
i++;
|
||||
asm volatile("mfsr %0, 2" : "=r" (table->value[i]));
|
||||
i++;
|
||||
asm volatile("mfsr %0, 3" : "=r" (table->value[i]));
|
||||
i++;
|
||||
asm volatile("mfsr %0, 4" : "=r" (table->value[i]));
|
||||
i++;
|
||||
asm volatile("mfsr %0, 5" : "=r" (table->value[i]));
|
||||
i++;
|
||||
asm volatile("mfsr %0, 6" : "=r" (table->value[i]));
|
||||
i++;
|
||||
asm volatile("mfsr %0, 7" : "=r" (table->value[i]));
|
||||
i++;
|
||||
asm volatile("mfsr %0, 8" : "=r" (table->value[i]));
|
||||
i++;
|
||||
asm volatile("mfsr %0, 9" : "=r" (table->value[i]));
|
||||
i++;
|
||||
asm volatile("mfsr %0, 10" : "=r" (table->value[i]));
|
||||
i++;
|
||||
asm volatile("mfsr %0, 11" : "=r" (table->value[i]));
|
||||
i++;
|
||||
asm volatile("mfsr %0, 12" : "=r" (table->value[i]));
|
||||
i++;
|
||||
asm volatile("mfsr %0, 13" : "=r" (table->value[i]));
|
||||
i++;
|
||||
asm volatile("mfsr %0, 14" : "=r" (table->value[i]));
|
||||
i++;
|
||||
asm volatile("mfsr %0, 15" : "=r" (table->value[i]));
|
||||
i++;
|
||||
|
||||
asm volatile("eieio; isync");
|
||||
}
|
||||
|
||||
static void KernelWriteSRs(sr_table_t * table) {
|
||||
u32 i = 0;
|
||||
|
||||
|
||||
asm volatile("eieio; isync");
|
||||
|
||||
// Writing didn't work for all at once so we only write number 8.
|
||||
// TODO: fix this and change it if required.
|
||||
|
||||
/*asm volatile("mtsr 0, %0" : : "r" (table->value[i])); i++;
|
||||
asm volatile("mtsr 1, %0" : : "r" (table->value[i])); i++;
|
||||
asm volatile("mtsr 2, %0" : : "r" (table->value[i])); i++;
|
||||
asm volatile("mtsr 3, %0" : : "r" (table->value[i])); i++;
|
||||
asm volatile("mtsr 4, %0" : : "r" (table->value[i])); i++;
|
||||
asm volatile("mtsr 5, %0" : : "r" (table->value[i])); i++;*/
|
||||
//asm volatile("mtsr 6, %0" : : "r" (table->value[6])); i++;
|
||||
/*asm volatile("mtsr 7, %0" : : "r" (table->value[i])); i++;*/
|
||||
asm volatile("mtsr 8, %0" : : "r" (table->value[8])); i++;
|
||||
/*asm volatile("mtsr 9, %0" : : "r" (table->value[i])); i++;
|
||||
asm volatile("mtsr 10, %0" : : "r" (table->value[i])); i++;
|
||||
asm volatile("mtsr 11, %0" : : "r" (table->value[i])); i++;
|
||||
asm volatile("mtsr 12, %0" : : "r" (table->value[i])); i++;
|
||||
asm volatile("mtsr 13, %0" : : "r" (table->value[i])); i++;
|
||||
asm volatile("mtsr 14, %0" : : "r" (table->value[i])); i++;
|
||||
asm volatile("mtsr 15, %0" : : "r" (table->value[i])); i++;*/
|
||||
|
||||
|
||||
asm volatile("isync");
|
||||
}
|
||||
|
||||
void KernelReadPTE(u32* dest, u32 size) {
|
||||
u32 msr = 0;
|
||||
u32 oldmsr = 0;
|
||||
//TODO: Calculate from SDR1
|
||||
u32 addr_base = 0xFFE20000;
|
||||
asm volatile("mfmsr %0" : "=r" (msr));
|
||||
oldmsr = msr;
|
||||
msr &= ~0x10;
|
||||
for(int i = 0;i<size/0x04;i++){
|
||||
u32 value_read = 0;
|
||||
u32 addr = addr_base + (i*4);
|
||||
// Disable Data address translation
|
||||
asm volatile("mtmsr %0" : : "r" (msr));
|
||||
__asm __volatile("lwz %0,0(%1)" : "=r"(value_read) : "r"(addr));
|
||||
// Enable Data address translation
|
||||
asm volatile("mtmsr %0" : : "r" (oldmsr));
|
||||
dest[i] = value_read;
|
||||
}
|
||||
}
|
||||
|
||||
void KernelWritePTE(u32 * in_addr, u32 size) {
|
||||
u32 msr = 0;
|
||||
u32 oldmsr = 0;
|
||||
//TODO: Calculate from SDR1
|
||||
u32 addr_base = 0xFFE20000;
|
||||
asm volatile("mfmsr %0" : "=r" (msr));
|
||||
oldmsr = msr;
|
||||
msr &= ~0x10;
|
||||
for(int i = 0;i<size/0x04;i++){
|
||||
u32 addr = addr_base + (i*4);
|
||||
u32 value = in_addr[i];
|
||||
// Disable Data address translation
|
||||
asm volatile("mtmsr %0" : : "r" (msr));
|
||||
__asm __volatile("stw %0,0(%1)" : : "r"(value),"r"(addr));
|
||||
// Enable Data address translation
|
||||
asm volatile("mtmsr %0" : : "r" (oldmsr));
|
||||
}
|
||||
}
|
||||
|
||||
void KernelWriteWitoutDAT(u32 addr, u32 value) {
|
||||
u32 msr = 0;
|
||||
u32 oldmsr = 0;
|
||||
//TODO: Calculate from SDR1
|
||||
u32 addr_base = 0xFFE20000;
|
||||
asm volatile("mfmsr %0" : "=r" (msr));
|
||||
oldmsr = msr;
|
||||
msr &= ~0x10;
|
||||
// Disable Data address translation
|
||||
asm volatile("mtmsr %0" : : "r" (msr));
|
||||
__asm __volatile("stw %0,0(%1)" : : "r"(value),"r"(addr));
|
||||
// Enable Data address translation
|
||||
asm volatile("mtmsr %0" : : "r" (oldmsr));
|
||||
}
|
||||
|
||||
void SC0x0A_KernelWriteWitoutDAT(u32 addr,u32 value);
|
||||
|
||||
void wups_init_kernel_syscalls(){
|
||||
//! assign 1 so that this variable gets into the retained .data section
|
||||
static uint8_t ucSyscallsSetupRequired = 1;
|
||||
if(!ucSyscallsSetupRequired)
|
||||
return;
|
||||
|
||||
ucSyscallsSetupRequired = 0;
|
||||
|
||||
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x0A * 4)), (unsigned int)KernelWriteWitoutDAT);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x0A * 4)), (unsigned int)KernelWriteWitoutDAT);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x0A * 4)), (unsigned int)KernelWriteWitoutDAT);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x0A * 4)), (unsigned int)KernelWriteWitoutDAT);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x0A * 4)), (unsigned int)KernelWriteWitoutDAT);
|
||||
|
||||
// Override all writes to SR8 with nops.
|
||||
SC0x0A_KernelWriteWitoutDAT(0xFFF1D754,0x60000000);
|
||||
SC0x0A_KernelWriteWitoutDAT(0xFFF1D64C,0x60000000);
|
||||
SC0x0A_KernelWriteWitoutDAT(0xFFE00638,0x60000000);
|
||||
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x36 * 4)), (unsigned int)KernelReadSRs);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x36 * 4)), (unsigned int)KernelReadSRs);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x36 * 4)), (unsigned int)KernelReadSRs);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x36 * 4)), (unsigned int)KernelReadSRs);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x36 * 4)), (unsigned int)KernelReadSRs);
|
||||
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x37 * 4)), (unsigned int)KernelReadPTE);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x37 * 4)), (unsigned int)KernelReadPTE);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x37 * 4)), (unsigned int)KernelReadPTE);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x37 * 4)), (unsigned int)KernelReadPTE);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x37 * 4)), (unsigned int)KernelReadPTE);
|
||||
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x09 * 4)), (unsigned int)KernelWritePTE);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x09 * 4)), (unsigned int)KernelWritePTE);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x09 * 4)), (unsigned int)KernelWritePTE);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x09 * 4)), (unsigned int)KernelWritePTE);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x09 * 4)), (unsigned int)KernelWritePTE);
|
||||
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x0A * 4)), (unsigned int)KernelWriteSRs);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x0A * 4)), (unsigned int)KernelWriteSRs);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x0A * 4)), (unsigned int)KernelWriteSRs);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x0A * 4)), (unsigned int)KernelWriteSRs);
|
||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x0A * 4)), (unsigned int)KernelWriteSRs);
|
||||
}
|
14
loader/src/mykernel/kernel_utils.h
Normal file
14
loader/src/mykernel/kernel_utils.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef __WUPS_KERNEL_UTILS_H_
|
||||
#define __WUPS_KERNEL_UTILS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void wups_init_kernel_syscalls();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __WUPS_KERNEL_UTILS_H_
|
20
loader/src/mykernel/syscalls.h
Normal file
20
loader/src/mykernel/syscalls.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef __WUPS_SYSCALLS_H_
|
||||
#define __WUPS_SYSCALLS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "kernel_defs.h"
|
||||
|
||||
void SC0x0A_KernelWriteSRs(sr_table_t * table);
|
||||
void SC0x36_KernelReadSRs(sr_table_t * table);
|
||||
void SC0x37_KernelReadPTE(u32* dest, u32 size);
|
||||
void SC0x09_KernelWritePTE(u32* addr,u32 size);
|
||||
void KernelTest();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __WUPS_SYSCALLS_H_
|
30
loader/src/mykernel/syscalls_asm.s
Normal file
30
loader/src/mykernel/syscalls_asm.s
Normal file
@ -0,0 +1,30 @@
|
||||
.globl SC0x36_KernelReadSRs
|
||||
SC0x36_KernelReadSRs:
|
||||
li r0, 0x3600
|
||||
sc
|
||||
blr
|
||||
|
||||
.globl SC0x0A_KernelWriteSRs
|
||||
SC0x0A_KernelWriteSRs:
|
||||
li r0, 0x0A00
|
||||
sc
|
||||
blr
|
||||
|
||||
.globl SC0x0A_KernelWriteWitoutDAT
|
||||
SC0x0A_KernelWriteWitoutDAT:
|
||||
li r0, 0x0A00
|
||||
sc
|
||||
blr
|
||||
|
||||
.globl SC0x37_KernelReadPTE
|
||||
SC0x37_KernelReadPTE:
|
||||
li r0, 0x3700
|
||||
sc
|
||||
blr
|
||||
|
||||
.globl SC0x09_KernelWritePTE
|
||||
SC0x09_KernelWritePTE:
|
||||
li r0, 0x0900
|
||||
sc
|
||||
blr
|
||||
|
637
loader/src/mymemory/memory_mapping.cpp
Normal file
637
loader/src/mymemory/memory_mapping.cpp
Normal file
@ -0,0 +1,637 @@
|
||||
#include "memory_mapping.h"
|
||||
#include "mykernel/syscalls.h"
|
||||
#include "common/retain_vars.h"
|
||||
#include <kernel/syscalls.h>
|
||||
#include <utils/logger.h>
|
||||
#include <utils/utils.h>
|
||||
#include <system/CThread.h>
|
||||
#include <fs/FSUtils.h>
|
||||
#include <vector>
|
||||
#include <dynamic_libs/os_functions.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
void runOnAllCores(CThread::Callback callback, void *callbackArg, s32 iAttr = 0, s32 iPriority = 16, s32 iStackSize = 0x8000) {
|
||||
int aff[] = {CThread::eAttributeAffCore2,CThread::eAttributeAffCore1,CThread::eAttributeAffCore0};
|
||||
|
||||
for(u32 i = 0; i <(sizeof(aff)/sizeof(aff[0])); i++) {
|
||||
CThread * thread = CThread::create(callback, callbackArg, iAttr | aff[i],iPriority,iStackSize);
|
||||
thread->resumeThread();
|
||||
delete thread;
|
||||
}
|
||||
}
|
||||
|
||||
void writeSegmentRegister(CThread *thread, void *arg) {
|
||||
sr_table_t * table = (sr_table_t *) arg;
|
||||
u16 core = OSGetThreadAffinity(OSGetCurrentThread());
|
||||
DEBUG_FUNCTION_LINE("Writing segment register to core %d\n",core);
|
||||
|
||||
DCFlushRange(table,sizeof(sr_table_t));
|
||||
SC0x0A_KernelWriteSRs(table);
|
||||
}
|
||||
|
||||
void readAndPrintSegmentRegister(CThread *thread, void *arg) {
|
||||
u16 core = OSGetThreadAffinity(OSGetCurrentThread());
|
||||
DEBUG_FUNCTION_LINE("Reading segment register and page table from core %d\n",core);
|
||||
sr_table_t srTable;
|
||||
memset(&srTable,0,sizeof(srTable));
|
||||
|
||||
SC0x36_KernelReadSRs(&srTable);
|
||||
DCFlushRange(&srTable,sizeof(srTable));
|
||||
|
||||
for(int i = 0; i < 16; i++) {
|
||||
DEBUG_FUNCTION_LINE("[%d] SR[%d]=%08X\n",core,i,srTable.value[i]);
|
||||
}
|
||||
|
||||
u32 pageTable[0x8000];
|
||||
|
||||
memset(pageTable,0,sizeof(pageTable));
|
||||
DEBUG_FUNCTION_LINE("Reading pageTable now.\n");
|
||||
SC0x37_KernelReadPTE(pageTable,sizeof(pageTable));
|
||||
DCFlushRange(pageTable,sizeof(pageTable));
|
||||
|
||||
DEBUG_FUNCTION_LINE("Reading pageTable done\n");
|
||||
|
||||
MemoryMapping::printPageTableTranslation(srTable,pageTable);
|
||||
|
||||
DEBUG_FUNCTION_LINE("-----------------------------\n");
|
||||
}
|
||||
|
||||
bool MemoryMapping::isMemoryMapped() {
|
||||
sr_table_t srTable;
|
||||
memset(&srTable,0,sizeof(srTable));
|
||||
|
||||
SC0x36_KernelReadSRs(&srTable);
|
||||
if((srTable.value[MEMORY_START_BASE >> 28] & 0x00FFFFFF) == SEGMENT_UNIQUE_ID) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 MemoryMapping::getHeapAddress() {
|
||||
return MEMORY_START_PLUGIN_HEAP;
|
||||
}
|
||||
|
||||
u32 MemoryMapping::getHeapSize() {
|
||||
const memory_values_t * mem_vals = mem_mapping[2].physical_addresses;
|
||||
u32 ea_size = 0;
|
||||
for(u32 j = 0;; j++) {
|
||||
u32 pa_start_address = mem_vals[j].start_address;
|
||||
u32 pa_end_address = mem_vals[j].end_address;
|
||||
if(pa_end_address == 0 && pa_start_address == 0) {
|
||||
break;
|
||||
}
|
||||
ea_size += pa_end_address - pa_start_address;
|
||||
}
|
||||
return ea_size;
|
||||
}
|
||||
|
||||
void MemoryMapping::searchEmptyMemoryRegions() {
|
||||
DEBUG_FUNCTION_LINE("Searching for empty memory.\n");
|
||||
|
||||
for(int i = 0;; i++) {
|
||||
if(mem_mapping[i].physical_addresses == NULL) {
|
||||
break;
|
||||
}
|
||||
u32 ea_start_address = mem_mapping[i].effective_start_address;
|
||||
|
||||
const memory_values_t * mem_vals = mem_mapping[i].physical_addresses;
|
||||
|
||||
u32 ea_size = 0;
|
||||
for(u32 j = 0;; j++) {
|
||||
u32 pa_start_address = mem_vals[j].start_address;
|
||||
u32 pa_end_address = mem_vals[j].end_address;
|
||||
if(pa_end_address == 0 && pa_start_address == 0) {
|
||||
break;
|
||||
}
|
||||
ea_size += pa_end_address - pa_start_address;
|
||||
}
|
||||
|
||||
u32* flush_start = (u32*)ea_start_address;
|
||||
u32 flush_size = ea_size;
|
||||
|
||||
DEBUG_FUNCTION_LINE("Flushing %08X (%d kB) at %08X.\n",flush_size,flush_size/1024, flush_start);
|
||||
DCFlushRange(flush_start,flush_size);
|
||||
|
||||
DEBUG_FUNCTION_LINE("Searching in memory region %d. 0x%08X - 0x%08X. Size 0x%08X (%d KBytes).\n",i+1,ea_start_address,ea_start_address+ea_size,ea_size,ea_size/1024);
|
||||
bool success = true;
|
||||
u32 * memory_ptr = (u32*) ea_start_address;
|
||||
bool inFailRange = false;
|
||||
u32 startFailing = 0;
|
||||
u32 startGood = ea_start_address;
|
||||
for(u32 j=0; j < ea_size/4; j++) {
|
||||
if(memory_ptr[j] != 0) {
|
||||
success = false;
|
||||
if(!success && !inFailRange) {
|
||||
if((((u32)&memory_ptr[j])-(u32)startGood)/1024 > 512) {
|
||||
u32 start_addr = startGood & 0xFFFE0000;
|
||||
if(start_addr != startGood) {
|
||||
start_addr += 0x20000;
|
||||
}
|
||||
u32 end_addr = ((u32)&memory_ptr[j]) - MEMORY_START_BASE;
|
||||
end_addr = (end_addr & 0xFFFE0000);
|
||||
DEBUG_FUNCTION_LINE("+ Free between 0x%08X and 0x%08X size: %u kB\n",start_addr - MEMORY_START_BASE,end_addr,(((u32)end_addr)-((u32)startGood - MEMORY_START_BASE))/1024);
|
||||
}
|
||||
startFailing = (u32)&memory_ptr[j];
|
||||
inFailRange = true;
|
||||
startGood = 0;
|
||||
j = ((j & 0xFFFF8000) + 0x00008000)-1;
|
||||
}
|
||||
//break;
|
||||
} else {
|
||||
if(inFailRange) {
|
||||
//DEBUG_FUNCTION_LINE("- Error between 0x%08X and 0x%08X size: %u kB\n",startFailing,&memory_ptr[j],(((u32)&memory_ptr[j])-(u32)startFailing)/1024);
|
||||
startFailing = 0;
|
||||
startGood = (u32) &memory_ptr[j];
|
||||
inFailRange = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(startGood != 0 && (startGood != ea_start_address + ea_size)) {
|
||||
DEBUG_FUNCTION_LINE("+ Good between 0x%08X and 0x%08X size: %u kB\n",startGood - MEMORY_START_BASE,((u32)(ea_start_address + ea_size) - (u32)MEMORY_START_BASE),((u32)(ea_start_address + ea_size) - (u32)startGood)/1024);
|
||||
} else if(inFailRange) {
|
||||
DEBUG_FUNCTION_LINE("- Used between 0x%08X and 0x%08X size: %u kB\n",startFailing,ea_start_address + ea_size,((u32)(ea_start_address + ea_size) - (u32)startFailing)/1024);
|
||||
}
|
||||
if(success) {
|
||||
DEBUG_FUNCTION_LINE("Test %d was successful!\n",i+1);
|
||||
}
|
||||
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("All tests done.\n");
|
||||
}
|
||||
|
||||
void MemoryMapping::writeTestValuesToMemory() {
|
||||
//don't smash the stack.
|
||||
u32 chunk_size = 0x1000;
|
||||
u32 testBuffer[chunk_size];
|
||||
|
||||
for(int i = 0;; i++) {
|
||||
if(mem_mapping[i].physical_addresses == NULL) {
|
||||
break;
|
||||
}
|
||||
u32 cur_ea_start_address = mem_mapping[i].effective_start_address;
|
||||
|
||||
DEBUG_FUNCTION_LINE("Preparing memory test for region %d. Region start at effective address %08X.\n",i+1,cur_ea_start_address);
|
||||
|
||||
const memory_values_t * mem_vals = mem_mapping[i].physical_addresses;
|
||||
u32 counter = 0;
|
||||
for(u32 j = 0;; j++) {
|
||||
u32 pa_start_address = mem_vals[j].start_address;
|
||||
u32 pa_end_address = mem_vals[j].end_address;
|
||||
if(pa_end_address == 0 && pa_start_address == 0) {
|
||||
break;
|
||||
}
|
||||
u32 pa_size = pa_end_address - pa_start_address;
|
||||
DEBUG_FUNCTION_LINE("Writing region %d of mapping %d. From %08X to %08X Size: %d KBytes...\n",j+1,i+1,pa_start_address,pa_end_address,pa_size/1024);
|
||||
for(u32 k=0; k<=pa_size/4; k++) {
|
||||
if(k > 0 && (k % chunk_size) == 0) {
|
||||
DCFlushRange(&testBuffer,sizeof(testBuffer));
|
||||
DCInvalidateRange(&testBuffer,sizeof(testBuffer));
|
||||
u32 destination = pa_start_address + ((k*4) - sizeof(testBuffer));
|
||||
SC0x25_KernelCopyData(destination,(u32)OSEffectiveToPhysical(testBuffer),sizeof(testBuffer));
|
||||
//DEBUG_FUNCTION_LINE("Copy testBuffer into %08X\n",destination);
|
||||
}
|
||||
if(k != pa_size/4) {
|
||||
testBuffer[k % chunk_size] = counter++;
|
||||
}
|
||||
//DEBUG_FUNCTION_LINE("testBuffer[%d] = %d\n",i % chunk_size,i);
|
||||
}
|
||||
u32* flush_start = (u32*)cur_ea_start_address;
|
||||
u32 flush_size = pa_size;
|
||||
|
||||
cur_ea_start_address += pa_size;
|
||||
|
||||
DEBUG_FUNCTION_LINE("Flushing %08X (%d kB) at %08X to map memory.\n",flush_size,flush_size/1024, flush_start);
|
||||
DCFlushRange(flush_start,flush_size);
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("Done writing region %d\n",i+1);
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryMapping::readTestValuesFromMemory() {
|
||||
DEBUG_FUNCTION_LINE("Testing reading the written values.\n");
|
||||
|
||||
for(int i = 0;; i++) {
|
||||
if(mem_mapping[i].physical_addresses == NULL) {
|
||||
break;
|
||||
}
|
||||
u32 ea_start_address = mem_mapping[i].effective_start_address;
|
||||
|
||||
const memory_values_t * mem_vals = mem_mapping[i].physical_addresses;
|
||||
//u32 counter = 0;
|
||||
u32 ea_size = 0;
|
||||
for(u32 j = 0;; j++) {
|
||||
u32 pa_start_address = mem_vals[j].start_address;
|
||||
u32 pa_end_address = mem_vals[j].end_address;
|
||||
if(pa_end_address == 0 && pa_start_address == 0) {
|
||||
break;
|
||||
}
|
||||
ea_size += pa_end_address - pa_start_address;
|
||||
}
|
||||
|
||||
u32* flush_start = (u32*)ea_start_address;
|
||||
u32 flush_size = ea_size;
|
||||
|
||||
DEBUG_FUNCTION_LINE("Flushing %08X (%d kB) at %08X to map memory.\n",flush_size,flush_size/1024, flush_start);
|
||||
DCFlushRange(flush_start,flush_size);
|
||||
|
||||
DEBUG_FUNCTION_LINE("Testing memory region %d. 0x%08X - 0x%08X. Size 0x%08X (%d KBytes).\n",i+1,ea_start_address,ea_start_address+ea_size,ea_size,ea_size/1024);
|
||||
bool success = true;
|
||||
u32 * memory_ptr = (u32*) ea_start_address;
|
||||
bool inFailRange = false;
|
||||
u32 startFailing = 0;
|
||||
u32 startGood = ea_start_address;
|
||||
for(u32 j=0; j < ea_size/4; j++) {
|
||||
if(memory_ptr[j] != j) {
|
||||
success = false;
|
||||
if(!success && !inFailRange) {
|
||||
DEBUG_FUNCTION_LINE("+ Good between 0x%08X and 0x%08X size: %u kB\n",startGood,&memory_ptr[j],(((u32)&memory_ptr[j])-(u32)startGood)/1024);
|
||||
startFailing = (u32)&memory_ptr[j];
|
||||
inFailRange = true;
|
||||
startGood = 0;
|
||||
j = ((j & 0xFFFF8000) + 0x00008000)-1;
|
||||
}
|
||||
//break;
|
||||
} else {
|
||||
if(inFailRange) {
|
||||
DEBUG_FUNCTION_LINE("- Error between 0x%08X and 0x%08X size: %u kB\n",startFailing,&memory_ptr[j],(((u32)&memory_ptr[j])-(u32)startFailing)/1024);
|
||||
startFailing = 0;
|
||||
startGood = (u32) &memory_ptr[j];
|
||||
inFailRange = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(startGood != 0 && (startGood != ea_start_address + ea_size)) {
|
||||
DEBUG_FUNCTION_LINE("+ Good between 0x%08X and 0x%08X size: %u kB\n",startGood,ea_start_address + ea_size,((u32)(ea_start_address + ea_size) - (u32)startGood)/1024);
|
||||
} else if(inFailRange) {
|
||||
DEBUG_FUNCTION_LINE("- Error between 0x%08X and 0x%08X size: %u kB\n",startFailing,ea_start_address + ea_size,((u32)(ea_start_address + ea_size) - (u32)startFailing)/1024);
|
||||
}
|
||||
if(success) {
|
||||
DEBUG_FUNCTION_LINE("Test %d was successful!\n",i+1);
|
||||
}
|
||||
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("All tests done.\n");
|
||||
}
|
||||
|
||||
void MemoryMapping::memoryMappingForRegions(const memory_mapping_t * memory_mapping, sr_table_t SRTable, u32 * translation_table) {
|
||||
for(int i = 0; /* waiting for a break */; i++) {
|
||||
DEBUG_FUNCTION_LINE("In loop %d\n",i);
|
||||
if(memory_mapping[i].physical_addresses == NULL) {
|
||||
DEBUG_FUNCTION_LINE("break %d\n",i);
|
||||
break;
|
||||
}
|
||||
u32 cur_ea_start_address = memory_mapping[i].effective_start_address;
|
||||
|
||||
DEBUG_FUNCTION_LINE("Mapping area %d. effective address %08X...\n",i+1,cur_ea_start_address);
|
||||
const memory_values_t * mem_vals = memory_mapping[i].physical_addresses;
|
||||
|
||||
for(u32 j = 0;; j++) {
|
||||
DEBUG_FUNCTION_LINE("In inner loop %d\n",j);
|
||||
u32 pa_start_address = mem_vals[j].start_address;
|
||||
u32 pa_end_address = mem_vals[j].end_address;
|
||||
if(pa_end_address == 0 && pa_start_address == 0) {
|
||||
DEBUG_FUNCTION_LINE("inner break %d\n",j);
|
||||
// Break if entry was empty.
|
||||
break;
|
||||
}
|
||||
u32 pa_size = pa_end_address - pa_start_address;
|
||||
DEBUG_FUNCTION_LINE("Adding page table entry %d for mapping area %d. %08X-%08X => %08X-%08X...\n",j+1,i+1,cur_ea_start_address,memory_mapping[i].effective_start_address+pa_size,pa_start_address,pa_end_address);
|
||||
if(!mapMemory(pa_start_address,pa_end_address,cur_ea_start_address,SRTable,translation_table)) {
|
||||
log_print("error =(\n");
|
||||
DEBUG_FUNCTION_LINE("Failed to map memory.\n");
|
||||
//OSFatal("Failed to map memory.");
|
||||
return;
|
||||
break;
|
||||
}
|
||||
cur_ea_start_address += pa_size;
|
||||
log_print("done\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryMapping::setupMemoryMapping() {
|
||||
//runOnAllCores(readAndPrintSegmentRegister,NULL,0,16,0x20000);
|
||||
|
||||
sr_table_t srTableCpy;
|
||||
u32 pageTableCpy[0x8000];
|
||||
|
||||
SC0x36_KernelReadSRs(&srTableCpy);
|
||||
SC0x37_KernelReadPTE(pageTableCpy,sizeof(pageTableCpy));
|
||||
|
||||
DCFlushRange(&srTableCpy,sizeof(srTableCpy));
|
||||
DCFlushRange(pageTableCpy,sizeof(pageTableCpy));
|
||||
|
||||
for(int i = 0; i < 16; i++) {
|
||||
DEBUG_FUNCTION_LINE("SR[%d]=%08X\n",i,srTableCpy.value[i]);
|
||||
}
|
||||
|
||||
printPageTableTranslation(srTableCpy,pageTableCpy);
|
||||
|
||||
// According to
|
||||
// http://wiiubrew.org/wiki/Cafe_OS#Virtual_Memory_Map 0x80000000
|
||||
// is currently unmapped.
|
||||
// This is nice because it leads to SR[8] which also seems to be unused (was set to 0x30FFFFFF)
|
||||
// The content of the segment was chosen randomly.
|
||||
u32 segment_index = MEMORY_START_BASE >> 28;
|
||||
u32 segment_content = 0x20000000 | SEGMENT_UNIQUE_ID;
|
||||
|
||||
DEBUG_FUNCTION_LINE("Setting SR[%d] to %08X\n",segment_index,segment_content);
|
||||
srTableCpy.value[segment_index] = segment_content;
|
||||
DCFlushRange(&srTableCpy,sizeof(srTableCpy));
|
||||
|
||||
DEBUG_FUNCTION_LINE("Writing segment registers...\n",segment_index,segment_content);
|
||||
// Writing the segment registers to ALL cores.
|
||||
runOnAllCores(writeSegmentRegister,&srTableCpy);
|
||||
|
||||
memoryMappingForRegions(mem_mapping,srTableCpy,pageTableCpy);
|
||||
|
||||
//printPageTableTranslation(srTableCpy,pageTableCpy);
|
||||
|
||||
DEBUG_FUNCTION_LINE("Writing PageTable... ");
|
||||
DCFlushRange(pageTableCpy,sizeof(pageTableCpy));
|
||||
SC0x09_KernelWritePTE(pageTableCpy,sizeof(pageTableCpy));
|
||||
DCFlushRange(pageTableCpy,sizeof(pageTableCpy));
|
||||
log_print("done\n");
|
||||
|
||||
//printPageTableTranslation(srTableCpy,pageTableCpy);
|
||||
|
||||
runOnAllCores(readAndPrintSegmentRegister,NULL,0,16,0x80000);
|
||||
|
||||
searchEmptyMemoryRegions();
|
||||
|
||||
writeTestValuesToMemory();
|
||||
readTestValuesFromMemory();
|
||||
}
|
||||
|
||||
void MemoryMapping::printPageTableTranslation(sr_table_t srTable, u32 * translation_table) {
|
||||
u32 SDR1 = srTable.sdr1;
|
||||
//u32 pagemask = SDR1 & 0x1FF;
|
||||
//u32 hashmask = (pagemask << 10) | 0x3FF;
|
||||
uint32_t pagetbl = SDR1 & 0xFFFF0000;
|
||||
|
||||
u32 pageIndexShift = 32 - 15;
|
||||
u32 pageIndexMask = (1 << (28 - pageIndexShift)) - 1;
|
||||
//u32 byteOffsetMask = (1 << pageIndexShift) - 1;
|
||||
//u32 apiShift = 22 - pageIndexShift;
|
||||
|
||||
//FSUtils::saveBufferToFile("sd:/table.bin", pteTable,sizeof(pteTable));
|
||||
|
||||
pageInformation current;
|
||||
memset(¤t,0,sizeof(current));
|
||||
|
||||
std::vector<pageInformation> pageInfos;
|
||||
|
||||
DEBUG_FUNCTION_LINE("Page table (%08X):\n",pagetbl);
|
||||
|
||||
for(u32 segment = 0; segment < 16 ; segment++) {
|
||||
u32 sr = srTable.value[segment];
|
||||
if(sr >> 31) {
|
||||
DEBUG_FUNCTION_LINE("Direct access not supported\n");
|
||||
} else {
|
||||
u32 ks = (sr >> 30) & 1;
|
||||
u32 kp = (sr >> 29) & 1;
|
||||
u32 nx = (sr >> 28) & 1;
|
||||
u32 vsid = sr & 0xFFFFFF;
|
||||
|
||||
DEBUG_FUNCTION_LINE("ks %08X kp %08X nx %08X vsid %08X\n",ks,kp,nx,vsid);
|
||||
u32 pageSize = 1 << pageIndexShift;
|
||||
for(u32 addr = segment * 0x10000000; addr < (segment + 1) * 0x10000000; addr += pageSize) {
|
||||
uint32_t pageIndex = (addr >> pageIndexShift) & pageIndexMask;
|
||||
uint32_t primaryHash = (vsid & 0x7FFFF) ^ pageIndex;
|
||||
|
||||
uint32_t pageTable = SDR1 & 0xFFFF0000;
|
||||
uint32_t pageMask = SDR1 & 0x1FF;
|
||||
uint32_t maskedHash = primaryHash & ((pageMask << 10) | 0x3FF);
|
||||
uint32_t api = (addr >> 22) & 0x3F;
|
||||
|
||||
uint32_t pteaddr = pageTable | (maskedHash << 6);
|
||||
|
||||
//DEBUG_FUNCTION_LINE("pteAddr %08X\n",pteAddr);
|
||||
|
||||
bool found = false;
|
||||
for (int j = 0; j < 8; j++, pteaddr += 8) {
|
||||
uint32_t PTEH = 0;
|
||||
uint32_t PTEL = 0;
|
||||
|
||||
u32 pteh_index = (pteaddr-pagetbl) / 4;
|
||||
u32 ptel_index = pteh_index + 1;
|
||||
//DEBUG_FUNCTION_LINE("pteh_index %08X\n",pteh_index);
|
||||
//DEBUG_FUNCTION_LINE("ptel_index %08X\n",ptel_index);
|
||||
|
||||
PTEH = translation_table[pteh_index];
|
||||
PTEL = translation_table[ptel_index];
|
||||
|
||||
//if(!readPTE(pteaddr,&PTEH)) continue;
|
||||
//if(!readPTE(pteaddr+4,&PTEL)) continue;
|
||||
|
||||
//Check validity
|
||||
|
||||
if (!(PTEH >> 31)) {
|
||||
//printf("PTE is not valid \n");
|
||||
continue;
|
||||
}
|
||||
//DEBUG_FUNCTION_LINE("in\n");
|
||||
// the H bit indicated if the PTE was found using the second hash.
|
||||
if (((PTEH >> 6) & 1)) {
|
||||
//DEBUG_FUNCTION_LINE("Secondary hash is used\n",((PTEH >> 6) & 1));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the VSID matches, otherwise this is a PTE for another SR
|
||||
// This is the place where collision could happen.
|
||||
// Hopefully no collision happen and only the PTEs of the SR will match.
|
||||
if (((PTEH >> 7) & 0xFFFFFF) != vsid) {
|
||||
//DEBUG_FUNCTION_LINE("VSID mismatch\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check the API (Abbreviated Page Index)
|
||||
if ((PTEH & 0x3F) != api) {
|
||||
//DEBUG_FUNCTION_LINE("API mismatch\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t pp = PTEL & 3;
|
||||
uint32_t phys = PTEL & 0xFFFFF000;
|
||||
|
||||
//DEBUG_FUNCTION_LINE("%08X: %08X %08X \n",pteaddr-pagetbl,PTEH,PTEL);
|
||||
//DEBUG_FUNCTION_LINE("current.phys == phys - current.size ( %08X %08X)\n",current.phys, phys - current.size);
|
||||
|
||||
if( current.ks == ks &&
|
||||
current.kp == kp &&
|
||||
current.nx == nx &&
|
||||
current.pp == pp &&
|
||||
current.phys == phys - current.size
|
||||
) {
|
||||
current.size += pageSize;
|
||||
//DEBUG_FUNCTION_LINE("New size of %08X is %08X\n",current.addr,current.size);
|
||||
} else {
|
||||
if(current.addr != 0 && current.size != 0) {
|
||||
/*DEBUG_FUNCTION_LINE("Saving old block from %08X\n",current.addr);
|
||||
DEBUG_FUNCTION_LINE("ks %08X new %08X\n",current.ks,ks);
|
||||
DEBUG_FUNCTION_LINE("kp %08X new %08X\n",current.kp,kp);
|
||||
DEBUG_FUNCTION_LINE("nx %08X new %08X\n",current.nx,nx);
|
||||
DEBUG_FUNCTION_LINE("pp %08X new %08X\n",current.pp,pp);*/
|
||||
pageInfos.push_back(current);
|
||||
memset(¤t,0,sizeof(current));
|
||||
}
|
||||
//DEBUG_FUNCTION_LINE("Found new block at %08X\n",addr);
|
||||
current.addr = addr;
|
||||
current.size = pageSize;
|
||||
current.kp = kp;
|
||||
current.ks = ks;
|
||||
current.nx = nx;
|
||||
current.pp = pp;
|
||||
current.phys = phys;
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
|
||||
}
|
||||
if(!found) {
|
||||
if(current.addr != 0 && current.size != 0) {
|
||||
pageInfos.push_back(current);
|
||||
memset(¤t,0,sizeof(current));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *access1[] = {"read/write", "read/write", "read/write", "read only"};
|
||||
const char *access2[] = {"no access", "read only", "read/write", "read only"};
|
||||
|
||||
for(std::vector<pageInformation>::iterator it = pageInfos.begin(); it != pageInfos.end(); ++it) {
|
||||
pageInformation cur = *it;
|
||||
// TODO: print if it's executable
|
||||
DEBUG_FUNCTION_LINE("%08X %08X -> %08X %08X. user access %s. supervisor access %s. %s\n",cur.addr,cur.addr+cur.size,cur.phys,cur.phys+cur.size,cur.kp ? access2[cur.pp] : access1[cur.pp],
|
||||
cur.ks ? access2[cur.pp] : access1[cur.pp],cur.nx? " not executable " : " executable");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool MemoryMapping::mapMemory(uint32_t pa_start_address,uint32_t pa_end_address,uint32_t ea_start_address, sr_table_t SRTable, u32 * translation_table) {
|
||||
// Based on code from dimok. Thanks!
|
||||
|
||||
u32 pageIndexShift = 32 - 15;
|
||||
u32 pageIndexMask = (1 << (28 - pageIndexShift)) - 1;
|
||||
//u32 byteOffsetMask = (1 << pageIndexShift) - 1;
|
||||
//u32 apiShift = 22 - pageIndexShift;
|
||||
|
||||
// Information on page 5.
|
||||
// https://www.nxp.com/docs/en/application-note/AN2794.pdf
|
||||
uint32_t HTABORG = SRTable.sdr1 >> 16;
|
||||
uint32_t HTABMASK = SRTable.sdr1 & 0x1FF;
|
||||
|
||||
// Iterate to all possible pages. Each page is 1<<(pageIndexShift) big.
|
||||
|
||||
uint32_t pageSize = 1<<(pageIndexShift);
|
||||
for(u32 i = 0; i < pa_end_address - pa_start_address; i += pageSize) {
|
||||
// Calculate the current effective address.
|
||||
uint32_t ea_addr = ea_start_address + i;
|
||||
// Calculate the segement.
|
||||
uint32_t segment = SRTable.value[ea_addr >> 28];
|
||||
|
||||
// Unique ID from the segment which is the input for the hash function.
|
||||
// Change it to prevent collisions.
|
||||
uint32_t VSID = segment & 0x00FFFFFF;
|
||||
uint32_t V = 1;
|
||||
|
||||
//Indicated if second hash is used.
|
||||
uint32_t H = 0;
|
||||
|
||||
// Abbreviated Page Index
|
||||
|
||||
// Real page number
|
||||
uint32_t RPN = (pa_start_address + i) >> 12;
|
||||
uint32_t RC = 3;
|
||||
uint32_t WIMG = 0x02;
|
||||
uint32_t PP = 0x02;
|
||||
|
||||
uint32_t page_index = (ea_addr >> pageIndexShift) & pageIndexMask;
|
||||
uint32_t API = (ea_addr >> 22) & 0x3F;
|
||||
|
||||
uint32_t PTEH = (V << 31) | (VSID << 7) | (H << 6) | API;
|
||||
uint32_t PTEL = (RPN << 12) | (RC << 7) | (WIMG << 3) | PP;
|
||||
|
||||
|
||||
//unsigned long long virtual_address = ((unsigned long long)VSID << 28UL) | (page_index << pageIndexShift) | (ea_addr & 0xFFF);
|
||||
|
||||
uint32_t primary_hash = (VSID & 0x7FFFF);
|
||||
|
||||
uint32_t hashvalue1 = primary_hash ^ page_index;
|
||||
|
||||
// hashvalue 2 is the complement of the first hash.
|
||||
uint32_t hashvalue2 = ~hashvalue1;
|
||||
|
||||
//uint32_t pageMask = SRTable.sdr1 & 0x1FF;
|
||||
|
||||
// calculate the address of the PTE groups.
|
||||
// PTEs are saved in a group of 8 PTEs
|
||||
// When PTEGaddr1 is full (all 8 PTEs set), PTEGaddr2 is used.
|
||||
// Then H in PTEH needs to be set to 1.
|
||||
uint32_t PTEGaddr1 = (HTABORG << 16) | (((hashvalue1 >> 10) & HTABMASK) << 16) | ((hashvalue1 & 0x3FF) << 6);
|
||||
uint32_t PTEGaddr2 = (HTABORG << 16) | (((hashvalue2 >> 10) & HTABMASK) << 16) | ((hashvalue2 & 0x3FF) << 6);
|
||||
|
||||
//offset of the group inside the PTE Table.
|
||||
uint32_t PTEGoffset = PTEGaddr1 - (HTABORG << 16);
|
||||
|
||||
bool setSuccessfully = false;
|
||||
PTEGoffset += 7*8;
|
||||
// Lets iterate through the PTE group where out PTE should be saved.
|
||||
for(int j = 7; j>0; PTEGoffset -= 8) {
|
||||
int index = (PTEGoffset/4);
|
||||
|
||||
uint32_t pteh = translation_table[index];
|
||||
// Check if it's already taken. The first bit indicates if the PTE-slot inside
|
||||
// this group is already taken.
|
||||
if ((pteh == 0)) {
|
||||
// If we found a free slot, set the PTEH and PTEL value.
|
||||
DEBUG_FUNCTION_LINE("Used slot %d. PTEGaddr1 %08X addr %08X\n",j+1,PTEGaddr1 - (HTABORG << 16),PTEGoffset);
|
||||
translation_table[index] = PTEH;
|
||||
translation_table[index+1] = PTEL;
|
||||
setSuccessfully = true;
|
||||
break;
|
||||
} else {
|
||||
//printf("PTEGoffset %08X was taken\n",PTEGoffset);
|
||||
}
|
||||
j--;
|
||||
}
|
||||
// Check if we already found a slot.
|
||||
if(!setSuccessfully) {
|
||||
DEBUG_FUNCTION_LINE("-------------- Using second slot -----------------------\n");
|
||||
// We still have a chance to find a slot in the PTEGaddr2 using the complement of the hash.
|
||||
// We need to set the H flag in PTEH and use PTEGaddr2.
|
||||
// (Not well tested)
|
||||
H = 1;
|
||||
PTEH = (V << 31) | (VSID << 7) | (H << 6) | API;
|
||||
PTEGoffset = PTEGaddr2 - (HTABORG << 16);
|
||||
PTEGoffset += 7*8;
|
||||
// Same as before.
|
||||
for(int j = 7; j>0; PTEGoffset -= 8) {
|
||||
int index = (PTEGoffset/4);
|
||||
uint32_t pteh = translation_table[index];
|
||||
//Check if it's already taken.
|
||||
if ((pteh == 0)) {
|
||||
translation_table[index] = PTEH;
|
||||
translation_table[index+1] = PTEL;
|
||||
setSuccessfully = true;
|
||||
break;
|
||||
} else {
|
||||
//printf("PTEGoffset %08X was taken\n",PTEGoffset);
|
||||
}
|
||||
j--;
|
||||
}
|
||||
|
||||
if(!setSuccessfully) {
|
||||
// Fail if we couldn't find a free slot.
|
||||
DEBUG_FUNCTION_LINE("-------------- No more free PTE -----------------------\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
128
loader/src/mymemory/memory_mapping.h
Normal file
128
loader/src/mymemory/memory_mapping.h
Normal file
@ -0,0 +1,128 @@
|
||||
#ifndef __WUPS_MEMORY_MAPPING_H_
|
||||
#define __WUPS_MEMORY_MAPPING_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <dynamic_libs/os_types.h>
|
||||
#include "mykernel/kernel_defs.h"
|
||||
|
||||
typedef struct pageInformation_ {
|
||||
uint32_t addr;
|
||||
uint32_t size;
|
||||
uint32_t ks;
|
||||
uint32_t kp;
|
||||
uint32_t nx;
|
||||
uint32_t pp;
|
||||
uint32_t phys;
|
||||
} pageInformation;
|
||||
|
||||
typedef struct _memory_values_t {
|
||||
unsigned int start_address;
|
||||
unsigned int end_address;
|
||||
} memory_values_t;
|
||||
|
||||
typedef struct _memory_mapping_t {
|
||||
unsigned int effective_start_address;
|
||||
const memory_values_t* physical_addresses;
|
||||
} memory_mapping_t;
|
||||
|
||||
|
||||
#define SEGMENT_UNIQUE_ID 0x00AABBCC // Unique ID. Chosen arbitrary.
|
||||
|
||||
#define MEMORY_START_BASE 0x80000000 // At most: 128MB for plugins heap.
|
||||
#define MEMORY_START_PLUGIN_HEAP MEMORY_START_BASE + 0x08000000 // At most: 128MB for plugins heap.
|
||||
#define MEMORY_START_PLUGIN_SPACE MEMORY_START_BASE + 0x00800000 // At most: 120MB for plugins.
|
||||
#define MEMORY_START_PLUGIN_LOADER MEMORY_START_BASE + 0x00000000 // At most: 8MB for the plugin loader.
|
||||
|
||||
const memory_values_t mem_vals_loader[] = {
|
||||
{0x28000000 + 0x06620000 , 0x28000000 + 0x06E20000}, // 8MB 0x80000000 0x80800000 -> 0x2E700000 0x2EF00000
|
||||
{0,0}
|
||||
};
|
||||
|
||||
const memory_values_t mem_vals_plugins[] = {
|
||||
{0x28000000 + 0x06E20000 , 0x28000000 + 0x07E20000}, // 16MB 0x80800000 0x81800000 -> 0x2EF00000 0x2FF00000
|
||||
{0,0}
|
||||
};
|
||||
|
||||
// Values needs to be aligned to 0x20000 and size needs to be a multiple of 0x20000
|
||||
const memory_values_t mem_vals_heap[] = {
|
||||
// 5.5.2 EUR
|
||||
{0x28000000 + 0x000E0000, 0x28000000 + 0x00160000}, // size: 512 kB
|
||||
{0x28000000 + 0x003C0000, 0x28000000 + 0x004C0000}, // size: 1024 kB
|
||||
{0x28000000 + 0x00900000, 0x28000000 + 0x00B00000}, // size: 2048 kB
|
||||
{0x28000000 + 0x00E40000, 0x28000000 + 0x00EC0000}, // size: 512 kB
|
||||
{0x28000000 + 0x00EE0000, 0x28000000 + 0x00F60000}, // size: 512 kB
|
||||
{0x28000000 + 0x00FA0000, 0x28000000 + 0x01020000}, // size: 512 kB
|
||||
{0x28000000 + 0x01040000, 0x28000000 + 0x013C0000}, // size: 3584 kB
|
||||
{0x28000000 + 0x02060000, 0x28000000 + 0x021A0000}, // size: 1280 kB
|
||||
{0x28000000 + 0x02BC0000, 0x28000000 + 0x02CA0000}, // size: 896 kB
|
||||
{0x28000000 + 0x04B60000, 0x28000000 + 0x04B80000}, // size: 128 kB
|
||||
{0x28000000 + 0x053C0000, 0x28000000 + 0x05880000}, // size: 4864 kB
|
||||
{0x28000000 + 0x058E0000, 0x28000000 + 0x06000000}, // size: 7296 kB
|
||||
{0x28000000 + 0x07E20000, 0x28000000 + 0x07F80000}, // size: 1408 kB
|
||||
{0x28000000 + 0x080E0000, 0x28000000 + 0x08180000}, // size: 640 kB
|
||||
{0x28000000 + 0x083C0000, 0x28000000 + 0x084C0000}, // size: 1024 kB
|
||||
{0x28000000 + 0x086E0000, 0x28000000 + 0x08760000}, // size: 512 kB
|
||||
{0x28000000 + 0x08C20000, 0x28000000 + 0x08F20000}, // size: 3072 kB
|
||||
{0x28000000 + 0x09000000, 0x28000000 + 0x09E20000}, // size: 14464 kB
|
||||
|
||||
// Not usable on 5.5.2
|
||||
//
|
||||
// Used in notifications {0x28000000 + 0x01720000, 0x28000000 + 0x018A0000}, // size: 1536 kB
|
||||
// {0x28000000 + 0x03820000, 0x28000000 + 0x038C0000}, // size: 640 kB
|
||||
// {0x28000000 + 0x03920000, 0x28000000 + 0x039A0000}, // size: 512 kB
|
||||
// Used in notifications {0x28000000 + 0x04B80000, 0x28000000 + 0x051E0000}, // size: 6528 kB
|
||||
// {0x28000000 + 0x08F20000, 0x28000000 + 0x09000000}, // size: 896 kB
|
||||
|
||||
// Porting to other/newer firmware:
|
||||
// Map this to check for free regions.
|
||||
// Use MemoryMapper::testFreeMemory() to see regions with are 0x00000000;
|
||||
// Then map the promising regions, and do the write/read check.
|
||||
// Writing numbers into the area, open the home menu and all background apps an check if anything was
|
||||
// overridden.
|
||||
// {0x28000000 + 0x00000000, 0x28000000 + 0x0A000000}, //
|
||||
|
||||
{0,0}
|
||||
};
|
||||
|
||||
const memory_mapping_t mem_mapping[] = {
|
||||
{MEMORY_START_PLUGIN_LOADER, mem_vals_loader},
|
||||
{MEMORY_START_PLUGIN_SPACE, mem_vals_plugins},
|
||||
{MEMORY_START_PLUGIN_HEAP, mem_vals_heap},
|
||||
{0,NULL}
|
||||
};
|
||||
|
||||
class MemoryMapping {
|
||||
|
||||
public:
|
||||
static bool isMemoryMapped();
|
||||
|
||||
static void setupMemoryMapping();
|
||||
|
||||
static void printPageTableTranslation(sr_table_t srTable, u32 * translation_table);
|
||||
|
||||
static void writeTestValuesToMemory();
|
||||
|
||||
static void readTestValuesFromMemory();
|
||||
|
||||
static void searchEmptyMemoryRegions();
|
||||
|
||||
static u32 getHeapAddress();
|
||||
|
||||
static u32 getHeapSize();
|
||||
|
||||
private:
|
||||
|
||||
static void memoryMappingForRegions(const memory_mapping_t * memory_mapping, sr_table_t SRTable, u32 * translation_table);
|
||||
|
||||
static bool mapMemory(u32 pa_start_address,u32 pa_end_address,u32 ea_start_address, sr_table_t SRTable, u32 * translation_table);
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __KERNEL_DEFS_H_
|
@ -1,10 +1,12 @@
|
||||
#include <utils/logger.h>
|
||||
#include <utils/function_patcher.h>
|
||||
#include <dynamic_libs/vpad_functions.h>
|
||||
#include "common/retain_vars.h"
|
||||
#include "hooks_patcher.h"
|
||||
#include "myutils/overlay_helper.h"
|
||||
#include "main.h"
|
||||
#include "utils.h"
|
||||
#include "mymemory/memory_mapping.h"
|
||||
|
||||
DECL(void, __PPCExit, void) {
|
||||
// Only continue if we are in the "right" application.
|
||||
@ -54,12 +56,32 @@ DECL(void, GX2WaitForVsync, void) {
|
||||
real_GX2WaitForVsync();
|
||||
}
|
||||
|
||||
u8 vpadPressCooldown = 0xFF;
|
||||
DECL(int, VPADRead, int chan, VPADData *buffer, u32 buffer_size, s32 *error) {
|
||||
int result = real_VPADRead(chan, buffer, buffer_size, error);
|
||||
|
||||
if(result > 0 && (buffer[0].btns_h == (VPAD_BUTTON_PLUS | VPAD_BUTTON_R | VPAD_BUTTON_L)) && vpadPressCooldown == 0 && OSIsHomeButtonMenuEnabled()) {
|
||||
if(MemoryMapping::isMemoryMapped()) {
|
||||
MemoryMapping::readTestValuesFromMemory();
|
||||
}else{
|
||||
DEBUG_FUNCTION_LINE("Memory was not mapped. To test the memory please exit the plugin loader by pressing MINUS\n");
|
||||
}
|
||||
vpadPressCooldown = 0x3C;
|
||||
}
|
||||
if(vpadPressCooldown > 0) {
|
||||
vpadPressCooldown--;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
hooks_magic_t method_hooks_hooks[] __attribute__((section(".data"))) = {
|
||||
MAKE_MAGIC(__PPCExit, LIB_CORE_INIT, STATIC_FUNCTION),
|
||||
MAKE_MAGIC(ProcUIProcessMessages, LIB_PROC_UI, DYNAMIC_FUNCTION),
|
||||
MAKE_MAGIC(GX2SetTVBuffer, LIB_GX2, STATIC_FUNCTION),
|
||||
MAKE_MAGIC(GX2SetDRCBuffer, LIB_GX2, STATIC_FUNCTION),
|
||||
MAKE_MAGIC(GX2WaitForVsync, LIB_GX2, STATIC_FUNCTION),
|
||||
MAKE_MAGIC(VPADRead, LIB_VPAD, STATIC_FUNCTION),
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user