mirror of
https://github.com/wiiu-env/homebrew_launcher.git
synced 2025-02-22 07:07:09 +01:00
rebase
This commit is contained in:
parent
0daa72d497
commit
a2297bdb43
@ -2,12 +2,11 @@
|
|||||||
#include "elf_abi.h"
|
#include "elf_abi.h"
|
||||||
#include "../../src/common/common.h"
|
#include "../../src/common/common.h"
|
||||||
#include "../../src/common/os_defs.h"
|
#include "../../src/common/os_defs.h"
|
||||||
|
#include "fs_defs.h"
|
||||||
#define CODE_RW_BASE_OFFSET 0
|
#include "kernel_defs.h"
|
||||||
#define DATA_RW_BASE_OFFSET 0
|
#include "loader_defs.h"
|
||||||
|
|
||||||
#define EXPORT_DECL(res, func, ...) res (* func)(__VA_ARGS__);
|
#define EXPORT_DECL(res, func, ...) res (* func)(__VA_ARGS__);
|
||||||
|
|
||||||
#define OS_FIND_EXPORT(handle, funcName, func) OSDynLoad_FindExport(handle, 0, funcName, &func)
|
#define OS_FIND_EXPORT(handle, funcName, func) OSDynLoad_FindExport(handle, 0, funcName, &func)
|
||||||
|
|
||||||
typedef struct _private_data_t
|
typedef struct _private_data_t
|
||||||
@ -18,14 +17,434 @@ typedef struct _private_data_t
|
|||||||
EXPORT_DECL(void*, memcpy, void *p1, const void *p2, unsigned int s);
|
EXPORT_DECL(void*, memcpy, void *p1, const void *p2, unsigned int s);
|
||||||
EXPORT_DECL(void*, memset, void *p1, int val, unsigned int s);
|
EXPORT_DECL(void*, memset, void *p1, int val, unsigned int s);
|
||||||
EXPORT_DECL(void, OSFatal, const char* msg);
|
EXPORT_DECL(void, OSFatal, const char* msg);
|
||||||
EXPORT_DECL(void, DCFlushRange, const void *addr, u32 length);
|
EXPORT_DECL(unsigned int, OSEffectiveToPhysical, const void*);
|
||||||
EXPORT_DECL(void, ICInvalidateRange, const void *addr, u32 length);
|
|
||||||
EXPORT_DECL(int, __os_snprintf, char* s, int n, const char * format, ...);
|
|
||||||
EXPORT_DECL(void, exit, int);
|
EXPORT_DECL(void, exit, int);
|
||||||
|
|
||||||
|
EXPORT_DECL(int, FSInit, void);
|
||||||
|
EXPORT_DECL(int, FSAddClientEx, void *pClient, int unk_zero_param, int errHandling);
|
||||||
|
EXPORT_DECL(int, FSDelClient, void *pClient);
|
||||||
|
EXPORT_DECL(void, FSInitCmdBlock, void *pCmd);
|
||||||
|
EXPORT_DECL(int, FSGetMountSource, void *pClient, void *pCmd, int type, void *source, int errHandling);
|
||||||
|
EXPORT_DECL(int, FSMount, void *pClient, void *pCmd, void *source, const char *target, uint32_t bytes, int errHandling);
|
||||||
|
EXPORT_DECL(int, FSUnmount, void *pClient, void *pCmd, const char *target, int errHandling);
|
||||||
|
EXPORT_DECL(int, FSOpenFile, void *pClient, void *pCmd, const char *path, const char *mode, int *fd, int errHandling);
|
||||||
|
EXPORT_DECL(int, FSGetStatFile, void *pClient, void *pCmd, int fd, void *buffer, int error);
|
||||||
|
EXPORT_DECL(int, FSReadFile, void *pClient, void *pCmd, void *buffer, int size, int count, int fd, int flag, int errHandling);
|
||||||
|
EXPORT_DECL(int, FSCloseFile, void *pClient, void *pCmd, int fd, int errHandling);
|
||||||
|
|
||||||
EXPORT_DECL(int, SYSRelaunchTitle, int argc, char** argv);
|
EXPORT_DECL(int, SYSRelaunchTitle, int argc, char** argv);
|
||||||
} private_data_t;
|
} private_data_t;
|
||||||
|
|
||||||
|
static void (*DCFlushRange)(void *addr, unsigned int size);
|
||||||
|
static void (*DCInvalidateRange)(void *addr, unsigned int size);
|
||||||
|
static void (*ICInvalidateRange)(void *addr, unsigned int size);
|
||||||
|
static unsigned int hook_LiWaitOneChunk;
|
||||||
|
static unsigned int addrphys_LiWaitOneChunk;
|
||||||
|
|
||||||
|
extern void SC0x25_KernelCopyData(unsigned int addr, unsigned int src, unsigned int len);
|
||||||
|
extern void my_PrepareTitle_hook(void);
|
||||||
|
|
||||||
|
/* Write a 32-bit word with kernel permissions */
|
||||||
|
static void __attribute__ ((noinline)) kern_write(void *addr, uint32_t value)
|
||||||
|
{
|
||||||
|
asm volatile (
|
||||||
|
"li 3,1\n"
|
||||||
|
"li 4,0\n"
|
||||||
|
"mr 5,%1\n"
|
||||||
|
"li 6,0\n"
|
||||||
|
"li 7,0\n"
|
||||||
|
"lis 8,1\n"
|
||||||
|
"mr 9,%0\n"
|
||||||
|
"mr %1,1\n"
|
||||||
|
"li 0,0x3500\n"
|
||||||
|
"sc\n"
|
||||||
|
"nop\n"
|
||||||
|
"mr 1,%1\n"
|
||||||
|
:
|
||||||
|
: "r"(addr), "r"(value)
|
||||||
|
: "memory", "ctr", "lr", "0", "3", "4", "5", "6", "7", "8", "9", "10",
|
||||||
|
"11", "12"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void KernelCopyData(unsigned int addr, unsigned int src, unsigned int len)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Setup a DBAT access with cache inhibited to write through and read directly from memory
|
||||||
|
*/
|
||||||
|
unsigned int dbatu0, dbatl0, dbatu1, dbatl1;
|
||||||
|
// save the original DBAT value
|
||||||
|
asm volatile("mfdbatu %0, 0" : "=r" (dbatu0));
|
||||||
|
asm volatile("mfdbatl %0, 0" : "=r" (dbatl0));
|
||||||
|
asm volatile("mfdbatu %0, 1" : "=r" (dbatu1));
|
||||||
|
asm volatile("mfdbatl %0, 1" : "=r" (dbatl1));
|
||||||
|
|
||||||
|
unsigned int target_dbatu0 = 0;
|
||||||
|
unsigned int target_dbatl0 = 0;
|
||||||
|
unsigned int target_dbatu1 = 0;
|
||||||
|
unsigned int target_dbatl1 = 0;
|
||||||
|
|
||||||
|
unsigned int *dst_p = (unsigned int*)addr;
|
||||||
|
unsigned int *src_p = (unsigned int*)src;
|
||||||
|
|
||||||
|
// we only need DBAT modification for addresses out of our own DBAT range
|
||||||
|
// as our own DBAT is available everywhere for user and supervisor
|
||||||
|
// since our own DBAT is on DBAT5 position we don't collide here
|
||||||
|
if(addr < 0x00800000 || addr >= 0x01000000)
|
||||||
|
{
|
||||||
|
target_dbatu0 = (addr & 0x00F00000) | 0xC0000000 | 0x1F;
|
||||||
|
target_dbatl0 = (addr & 0xFFF00000) | 0x32;
|
||||||
|
asm volatile("mtdbatu 0, %0" : : "r" (target_dbatu0));
|
||||||
|
asm volatile("mtdbatl 0, %0" : : "r" (target_dbatl0));
|
||||||
|
dst_p = (unsigned int*)((addr & 0xFFFFFF) | 0xC0000000);
|
||||||
|
}
|
||||||
|
if(src < 0x00800000 || src >= 0x01000000)
|
||||||
|
{
|
||||||
|
target_dbatu1 = (src & 0x00F00000) | 0xB0000000 | 0x1F;
|
||||||
|
target_dbatl1 = (src & 0xFFF00000) | 0x32;
|
||||||
|
|
||||||
|
asm volatile("mtdbatu 1, %0" : : "r" (target_dbatu1));
|
||||||
|
asm volatile("mtdbatl 1, %0" : : "r" (target_dbatl1));
|
||||||
|
src_p = (unsigned int*)((src & 0xFFFFFF) | 0xB0000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
asm volatile("eieio; isync");
|
||||||
|
|
||||||
|
unsigned int i;
|
||||||
|
for(i = 0; i < len; i += 4)
|
||||||
|
{
|
||||||
|
// if we are on the edge to next chunk
|
||||||
|
if((target_dbatu0 != 0) && (((unsigned int)dst_p & 0x00F00000) != (target_dbatu0 & 0x00F00000)))
|
||||||
|
{
|
||||||
|
target_dbatu0 = ((addr + i) & 0x00F00000) | 0xC0000000 | 0x1F;
|
||||||
|
target_dbatl0 = ((addr + i) & 0xFFF00000) | 0x32;
|
||||||
|
dst_p = (unsigned int*)(((addr + i) & 0xFFFFFF) | 0xC0000000);
|
||||||
|
|
||||||
|
asm volatile("eieio; isync");
|
||||||
|
asm volatile("mtdbatu 0, %0" : : "r" (target_dbatu0));
|
||||||
|
asm volatile("mtdbatl 0, %0" : : "r" (target_dbatl0));
|
||||||
|
asm volatile("eieio; isync");
|
||||||
|
}
|
||||||
|
if((target_dbatu1 != 0) && (((unsigned int)src_p & 0x00F00000) != (target_dbatu1 & 0x00F00000)))
|
||||||
|
{
|
||||||
|
target_dbatu1 = ((src + i) & 0x00F00000) | 0xB0000000 | 0x1F;
|
||||||
|
target_dbatl1 = ((src + i) & 0xFFF00000) | 0x32;
|
||||||
|
src_p = (unsigned int*)(((src + i) & 0xFFFFFF) | 0xB0000000);
|
||||||
|
|
||||||
|
asm volatile("eieio; isync");
|
||||||
|
asm volatile("mtdbatu 1, %0" : : "r" (target_dbatu1));
|
||||||
|
asm volatile("mtdbatl 1, %0" : : "r" (target_dbatl1));
|
||||||
|
asm volatile("eieio; isync");
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst_p = *src_p;
|
||||||
|
|
||||||
|
++dst_p;
|
||||||
|
++src_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Restore original DBAT value
|
||||||
|
*/
|
||||||
|
asm volatile("eieio; isync");
|
||||||
|
asm volatile("mtdbatu 0, %0" : : "r" (dbatu0));
|
||||||
|
asm volatile("mtdbatl 0, %0" : : "r" (dbatl0));
|
||||||
|
asm volatile("mtdbatu 1, %0" : : "r" (dbatu1));
|
||||||
|
asm volatile("mtdbatl 1, %0" : : "r" (dbatl1));
|
||||||
|
asm volatile("eieio; isync");
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function is called every time after LiBounceOneChunk.
|
||||||
|
// It waits for the asynchronous call of LiLoadAsync for the IOSU to fill data to the RPX/RPL address
|
||||||
|
// and return the still remaining bytes to load.
|
||||||
|
// We override it and replace the loaded date from LiLoadAsync with our data and our remaining bytes to load.
|
||||||
|
static int LiWaitOneChunk(unsigned int * iRemainingBytes, const char *filename, int fileType)
|
||||||
|
{
|
||||||
|
unsigned int result;
|
||||||
|
register int core_id;
|
||||||
|
int remaining_bytes = 0;
|
||||||
|
|
||||||
|
int sgFileOffset;
|
||||||
|
int sgBufferNumber;
|
||||||
|
int *sgBounceError;
|
||||||
|
int *sgGotBytes;
|
||||||
|
int *sgTotalBytes;
|
||||||
|
int *sgIsLoadingBuffer;
|
||||||
|
int *sgFinishedLoadingBuffer;
|
||||||
|
|
||||||
|
// get the current core
|
||||||
|
asm volatile("mfspr %0, 0x3EF" : "=r" (core_id));
|
||||||
|
|
||||||
|
// get the offset of per core global variable for dynload initialized (just a simple address + (core_id * 4))
|
||||||
|
unsigned int gDynloadInitialized = *(volatile unsigned int*)(OS_SPECIFICS->addr_gDynloadInitialized + (core_id << 2));
|
||||||
|
|
||||||
|
// Comment (Dimok):
|
||||||
|
// time measurement at this position for logger -> we don't need it right now except maybe for debugging
|
||||||
|
//unsigned long long systemTime1 = Loader_GetSystemTime();
|
||||||
|
|
||||||
|
if(OS_FIRMWARE == 550)
|
||||||
|
{
|
||||||
|
// pointer to global variables of the loader
|
||||||
|
loader_globals_550_t *loader_globals = (loader_globals_550_t*)(0xEFE19E80);
|
||||||
|
|
||||||
|
sgBufferNumber = loader_globals->sgBufferNumber;
|
||||||
|
sgFileOffset = loader_globals->sgFileOffset;
|
||||||
|
sgBounceError = &loader_globals->sgBounceError;
|
||||||
|
sgGotBytes = &loader_globals->sgGotBytes;
|
||||||
|
sgTotalBytes = &loader_globals->sgTotalBytes;
|
||||||
|
sgFinishedLoadingBuffer = &loader_globals->sgFinishedLoadingBuffer;
|
||||||
|
// not available on 5.5.x
|
||||||
|
sgIsLoadingBuffer = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// pointer to global variables of the loader
|
||||||
|
loader_globals_t *loader_globals = (loader_globals_t*)(OS_SPECIFICS->addr_sgIsLoadingBuffer);
|
||||||
|
|
||||||
|
sgBufferNumber = loader_globals->sgBufferNumber;
|
||||||
|
sgFileOffset = loader_globals->sgFileOffset;
|
||||||
|
sgBounceError = &loader_globals->sgBounceError;
|
||||||
|
sgGotBytes = &loader_globals->sgGotBytes;
|
||||||
|
sgIsLoadingBuffer = &loader_globals->sgIsLoadingBuffer;
|
||||||
|
// not available on < 5.5.x
|
||||||
|
sgTotalBytes = NULL;
|
||||||
|
sgFinishedLoadingBuffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the data loading was started in LiBounceOneChunk() and here it waits for IOSU to finish copy the data
|
||||||
|
if(gDynloadInitialized != 0) {
|
||||||
|
result = OS_SPECIFICS->LiWaitIopCompleteWithInterrupts(0x2160EC0, &remaining_bytes);
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = OS_SPECIFICS->LiWaitIopComplete(0x2160EC0, &remaining_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comment (Dimok):
|
||||||
|
// time measurement at this position for logger -> we don't need it right now except maybe for debugging
|
||||||
|
//unsigned long long systemTime2 = Loader_GetSystemTime();
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Start of our function intrusion:
|
||||||
|
// After IOSU is done writing the data into the 0xF6000000/0xF6400000 address,
|
||||||
|
// we overwrite it with our data before setting the global flag for IsLoadingBuffer to 0
|
||||||
|
// Do this only if we are in the game that was launched by our method
|
||||||
|
s_mem_area *mem_area = MEM_AREA_TABLE;
|
||||||
|
if((ELF_DATA_ADDR == mem_area->address) && (fileType == 0))
|
||||||
|
{
|
||||||
|
unsigned int load_address = (sgBufferNumber == 1) ? 0xF6000000 : (0xF6000000 + 0x00400000);
|
||||||
|
unsigned int load_addressPhys = (sgBufferNumber == 1) ? 0x1B000000 : (0x1B000000 + 0x00400000); // virtual 0xF6000000 and 0xF6400000
|
||||||
|
|
||||||
|
remaining_bytes = ELF_DATA_SIZE - sgFileOffset;
|
||||||
|
if (remaining_bytes > 0x400000)
|
||||||
|
// truncate size
|
||||||
|
remaining_bytes = 0x400000;
|
||||||
|
|
||||||
|
DCFlushRange((void*)load_address, remaining_bytes);
|
||||||
|
|
||||||
|
u32 rpxBlockPos = 0;
|
||||||
|
u32 done = 0;
|
||||||
|
u32 mapOffset = 0;
|
||||||
|
|
||||||
|
while((done < (u32)sgFileOffset) && mem_area)
|
||||||
|
{
|
||||||
|
if((done + mem_area->size) > (u32)sgFileOffset)
|
||||||
|
{
|
||||||
|
mapOffset = sgFileOffset - done;
|
||||||
|
done = sgFileOffset;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
done += mem_area->size;
|
||||||
|
mem_area = mem_area->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while((done < ELF_DATA_SIZE) && (rpxBlockPos < 0x400000) && mem_area)
|
||||||
|
{
|
||||||
|
u32 address = mem_area->address + mapOffset;
|
||||||
|
u32 blockSize = ELF_DATA_SIZE - done;
|
||||||
|
|
||||||
|
if(blockSize > (0x400000 - rpxBlockPos))
|
||||||
|
{
|
||||||
|
blockSize = 0x400000 - rpxBlockPos;
|
||||||
|
}
|
||||||
|
if((mapOffset + blockSize) >= mem_area->size)
|
||||||
|
{
|
||||||
|
blockSize = mem_area->size - mapOffset;
|
||||||
|
mem_area = mem_area->next;
|
||||||
|
mapOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SC0x25_KernelCopyData(load_addressPhys + rpxBlockPos, address, blockSize);
|
||||||
|
done += blockSize;
|
||||||
|
rpxBlockPos += blockSize;
|
||||||
|
mapOffset += blockSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
DCInvalidateRange((void*)load_address, remaining_bytes);
|
||||||
|
|
||||||
|
if((u32)(sgFileOffset + remaining_bytes) == ELF_DATA_SIZE)
|
||||||
|
{
|
||||||
|
ELF_DATA_ADDR = 0xDEADC0DE;
|
||||||
|
ELF_DATA_SIZE = 0;
|
||||||
|
MAIN_ENTRY_ADDR = 0xC001C0DE;
|
||||||
|
}
|
||||||
|
// set result to 0 -> "everything OK"
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// end of our little intrusion into this function
|
||||||
|
//------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// set the result to the global bounce error variable
|
||||||
|
if(sgBounceError) {
|
||||||
|
*sgBounceError = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// disable global flag that buffer is still loaded by IOSU
|
||||||
|
if(sgFinishedLoadingBuffer)
|
||||||
|
{
|
||||||
|
unsigned int zeroBitCount = 0;
|
||||||
|
asm volatile("cntlzw %0, %0" : "=r" (zeroBitCount) : "r"(*sgFinishedLoadingBuffer));
|
||||||
|
*sgFinishedLoadingBuffer = zeroBitCount >> 5;
|
||||||
|
}
|
||||||
|
else if(sgIsLoadingBuffer)
|
||||||
|
{
|
||||||
|
*sgIsLoadingBuffer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check result for errors
|
||||||
|
if(result == 0)
|
||||||
|
{
|
||||||
|
// the remaining size is set globally and in stack variable only
|
||||||
|
// if a pointer was passed to this function
|
||||||
|
if(iRemainingBytes) {
|
||||||
|
if(sgGotBytes) {
|
||||||
|
*sgGotBytes = remaining_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
*iRemainingBytes = remaining_bytes;
|
||||||
|
|
||||||
|
// on 5.5.x a new variable for total loaded bytes was added
|
||||||
|
if(sgTotalBytes) {
|
||||||
|
*sgTotalBytes += remaining_bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Comment (Dimok):
|
||||||
|
// calculate time difference and print it on logging how long the wait for asynchronous data load took
|
||||||
|
// something like (systemTime2 - systemTime1) * constant / bus speed, did not look deeper into it as we don't need that crap
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Comment (Dimok):
|
||||||
|
// a lot of error handling here. depending on error code sometimes calls Loader_Panic() -> we don't make errors so we can skip that part ;-P
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void my_PrepareTitle(CosAppXmlInfo *xmlKernelInfo)
|
||||||
|
{
|
||||||
|
if(ELF_DATA_ADDR == MEM_AREA_TABLE->address)
|
||||||
|
{
|
||||||
|
xmlKernelInfo->max_size = RPX_MAX_SIZE;
|
||||||
|
xmlKernelInfo->max_codesize = RPX_MAX_CODE_SIZE;
|
||||||
|
//! setup our hook to LiWaitOneChunk for RPX loading
|
||||||
|
hook_LiWaitOneChunk = ((u32)LiWaitOneChunk) | 0x48000002;
|
||||||
|
KernelCopyData(addrphys_LiWaitOneChunk, (u32) &hook_LiWaitOneChunk, 4);
|
||||||
|
asm volatile("icbi 0, %0" : : "r" (OS_SPECIFICS->addr_LiWaitOneChunk & ~31));
|
||||||
|
}
|
||||||
|
else if((MAIN_ENTRY_ADDR == 0xC001C0DE) && (*(u32*)xmlKernelInfo->rpx_name == 0x66666c5f)) // ffl_
|
||||||
|
{
|
||||||
|
//! restore original LiWaitOneChunk instruction as our RPX is done
|
||||||
|
MAIN_ENTRY_ADDR = 0xDEADC0DE;
|
||||||
|
KernelCopyData(addrphys_LiWaitOneChunk, (u32)&OS_SPECIFICS->orig_LiWaitOneChunkInstr, 4);
|
||||||
|
asm volatile("icbi 0, %0" : : "r" (OS_SPECIFICS->addr_LiWaitOneChunk & ~31));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int LoadFileToMem(private_data_t *private_data, const char *filepath, unsigned char **fileOut, unsigned int * sizeOut)
|
||||||
|
{
|
||||||
|
int iFd = -1;
|
||||||
|
void *pClient = private_data->MEMAllocFromDefaultHeapEx(FS_CLIENT_SIZE, 4);
|
||||||
|
if(!pClient)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
void *pCmd = private_data->MEMAllocFromDefaultHeapEx(FS_CMD_BLOCK_SIZE, 4);
|
||||||
|
if(!pCmd)
|
||||||
|
{
|
||||||
|
private_data->MEMFreeToDefaultHeap(pClient);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int success = 0;
|
||||||
|
private_data->FSInit();
|
||||||
|
private_data->FSInitCmdBlock(pCmd);
|
||||||
|
private_data->FSAddClientEx(pClient, 0, -1);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
char tempPath[FS_MOUNT_SOURCE_SIZE];
|
||||||
|
char mountPath[FS_MAX_MOUNTPATH_SIZE];
|
||||||
|
|
||||||
|
int status = private_data->FSGetMountSource(pClient, pCmd, 0, tempPath, -1);
|
||||||
|
if (status != 0) {
|
||||||
|
private_data->OSFatal("FSGetMountSource failed.");
|
||||||
|
}
|
||||||
|
status = private_data->FSMount(pClient, pCmd, tempPath, mountPath, FS_MAX_MOUNTPATH_SIZE, -1);
|
||||||
|
if(status != 0) {
|
||||||
|
private_data->OSFatal("SD mount failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
status = private_data->FSOpenFile(pClient, pCmd, filepath, "r", &iFd, -1);
|
||||||
|
if(status != 0) {
|
||||||
|
private_data->OSFatal("FSOpenFile failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
FSStat stat;
|
||||||
|
stat.size = 0;
|
||||||
|
|
||||||
|
void *pBuffer = NULL;
|
||||||
|
|
||||||
|
private_data->FSGetStatFile(pClient, pCmd, iFd, &stat, -1);
|
||||||
|
|
||||||
|
if(stat.size > 0)
|
||||||
|
pBuffer = private_data->MEMAllocFromDefaultHeapEx((stat.size + 0x3F) & ~0x3F, 0x40);
|
||||||
|
else
|
||||||
|
private_data->OSFatal("ELF file empty.");
|
||||||
|
|
||||||
|
unsigned int done = 0;
|
||||||
|
|
||||||
|
while(done < stat.size)
|
||||||
|
{
|
||||||
|
int readBytes = private_data->FSReadFile(pClient, pCmd, pBuffer + done, 1, stat.size - done, iFd, 0, -1);
|
||||||
|
if(readBytes <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
done += readBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(done != stat.size)
|
||||||
|
{
|
||||||
|
private_data->MEMFreeToDefaultHeap(pBuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*fileOut = (unsigned char*)pBuffer;
|
||||||
|
*sizeOut = stat.size;
|
||||||
|
success = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private_data->FSCloseFile(pClient, pCmd, iFd, -1);
|
||||||
|
private_data->FSUnmount(pClient, pCmd, mountPath, -1);
|
||||||
|
}
|
||||||
|
while(0);
|
||||||
|
|
||||||
|
private_data->FSDelClient(pClient);
|
||||||
|
private_data->MEMFreeToDefaultHeap(pClient);
|
||||||
|
private_data->MEMFreeToDefaultHeap(pCmd);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned int load_elf_image (private_data_t *private_data, unsigned char *elfstart)
|
static unsigned int load_elf_image (private_data_t *private_data, unsigned char *elfstart)
|
||||||
{
|
{
|
||||||
Elf32_Ehdr *ehdr;
|
Elf32_Ehdr *ehdr;
|
||||||
@ -49,25 +468,19 @@ static unsigned int load_elf_image (private_data_t *private_data, unsigned char
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(phdrs[i].p_filesz > phdrs[i].p_memsz)
|
if(phdrs[i].p_filesz > phdrs[i].p_memsz)
|
||||||
return 0;
|
continue;
|
||||||
|
|
||||||
if(!phdrs[i].p_filesz)
|
if(!phdrs[i].p_filesz)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
unsigned int p_paddr = phdrs[i].p_paddr;
|
unsigned int p_paddr = phdrs[i].p_paddr;
|
||||||
|
|
||||||
// use correct offset address for executables and data access
|
|
||||||
if(phdrs[i].p_flags & PF_X)
|
|
||||||
p_paddr += CODE_RW_BASE_OFFSET;
|
|
||||||
else
|
|
||||||
p_paddr += DATA_RW_BASE_OFFSET;
|
|
||||||
|
|
||||||
image = (unsigned char *) (elfstart + phdrs[i].p_offset);
|
image = (unsigned char *) (elfstart + phdrs[i].p_offset);
|
||||||
|
|
||||||
private_data->memcpy ((void *) p_paddr, image, phdrs[i].p_filesz);
|
private_data->memcpy ((void *) p_paddr, image, phdrs[i].p_filesz);
|
||||||
private_data->DCFlushRange((void*)p_paddr, phdrs[i].p_filesz);
|
DCFlushRange((void*)p_paddr, phdrs[i].p_filesz);
|
||||||
|
|
||||||
if(phdrs[i].p_flags & PF_X)
|
if(phdrs[i].p_flags & PF_X)
|
||||||
private_data->ICInvalidateRange ((void *) phdrs[i].p_paddr, phdrs[i].p_memsz);
|
ICInvalidateRange ((void *) p_paddr, phdrs[i].p_memsz);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! clear BSS
|
//! clear BSS
|
||||||
@ -78,15 +491,31 @@ static unsigned int load_elf_image (private_data_t *private_data, unsigned char
|
|||||||
if(section_name[0] == '.' && section_name[1] == 'b' && section_name[2] == 's' && section_name[3] == 's')
|
if(section_name[0] == '.' && section_name[1] == 'b' && section_name[2] == 's' && section_name[3] == 's')
|
||||||
{
|
{
|
||||||
private_data->memset((void*)shdr[i].sh_addr, 0, shdr[i].sh_size);
|
private_data->memset((void*)shdr[i].sh_addr, 0, shdr[i].sh_size);
|
||||||
private_data->DCFlushRange((void*)shdr[i].sh_addr, shdr[i].sh_size);
|
DCFlushRange((void*)shdr[i].sh_addr, shdr[i].sh_size);
|
||||||
}
|
}
|
||||||
else if(section_name[0] == '.' && section_name[1] == 's' && section_name[2] == 'b' && section_name[3] == 's' && section_name[4] == 's')
|
else if(section_name[0] == '.' && section_name[1] == 's' && section_name[2] == 'b' && section_name[3] == 's' && section_name[4] == 's')
|
||||||
{
|
{
|
||||||
private_data->memset((void*)shdr[i].sh_addr, 0, shdr[i].sh_size);
|
private_data->memset((void*)shdr[i].sh_addr, 0, shdr[i].sh_size);
|
||||||
private_data->DCFlushRange((void*)shdr[i].sh_addr, shdr[i].sh_size);
|
DCFlushRange((void*)shdr[i].sh_addr, shdr[i].sh_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! setup hooks
|
||||||
|
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x25 * 4)), (unsigned int)KernelCopyData);
|
||||||
|
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x25 * 4)), (unsigned int)KernelCopyData);
|
||||||
|
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x25 * 4)), (unsigned int)KernelCopyData);
|
||||||
|
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x25 * 4)), (unsigned int)KernelCopyData);
|
||||||
|
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x25 * 4)), (unsigned int)KernelCopyData);
|
||||||
|
|
||||||
|
//! store physical address for later use
|
||||||
|
addrphys_LiWaitOneChunk = private_data->OSEffectiveToPhysical((void*)OS_SPECIFICS->addr_LiWaitOneChunk);
|
||||||
|
|
||||||
|
u32 addr_my_PrepareTitle_hook = ((u32)my_PrepareTitle_hook) | 0x48000003;
|
||||||
|
DCFlushRange(&addr_my_PrepareTitle_hook, 4);
|
||||||
|
|
||||||
|
//! create our copy syscall
|
||||||
|
SC0x25_KernelCopyData(OS_SPECIFICS->addr_PrepareTitle_hook, private_data->OSEffectiveToPhysical(&addr_my_PrepareTitle_hook), 4);
|
||||||
|
|
||||||
return ehdr->e_entry;
|
return ehdr->e_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,22 +541,39 @@ static void loadFunctionPointers(private_data_t * private_data)
|
|||||||
OS_FIND_EXPORT(coreinit_handle, "memcpy", private_data->memcpy);
|
OS_FIND_EXPORT(coreinit_handle, "memcpy", private_data->memcpy);
|
||||||
OS_FIND_EXPORT(coreinit_handle, "memset", private_data->memset);
|
OS_FIND_EXPORT(coreinit_handle, "memset", private_data->memset);
|
||||||
OS_FIND_EXPORT(coreinit_handle, "OSFatal", private_data->OSFatal);
|
OS_FIND_EXPORT(coreinit_handle, "OSFatal", private_data->OSFatal);
|
||||||
OS_FIND_EXPORT(coreinit_handle, "DCFlushRange", private_data->DCFlushRange);
|
OS_FIND_EXPORT(coreinit_handle, "DCFlushRange", DCFlushRange);
|
||||||
OS_FIND_EXPORT(coreinit_handle, "ICInvalidateRange", private_data->ICInvalidateRange);
|
OS_FIND_EXPORT(coreinit_handle, "DCInvalidateRange", DCInvalidateRange);
|
||||||
OS_FIND_EXPORT(coreinit_handle, "__os_snprintf", private_data->__os_snprintf);
|
OS_FIND_EXPORT(coreinit_handle, "ICInvalidateRange", ICInvalidateRange);
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, "OSEffectiveToPhysical", private_data->OSEffectiveToPhysical);
|
||||||
OS_FIND_EXPORT(coreinit_handle, "exit", private_data->exit);
|
OS_FIND_EXPORT(coreinit_handle, "exit", private_data->exit);
|
||||||
|
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, "FSInit", private_data->FSInit);
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, "FSAddClientEx", private_data->FSAddClientEx);
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, "FSDelClient", private_data->FSDelClient);
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, "FSInitCmdBlock", private_data->FSInitCmdBlock);
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, "FSGetMountSource", private_data->FSGetMountSource);
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, "FSMount", private_data->FSMount);
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, "FSUnmount", private_data->FSUnmount);
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, "FSOpenFile", private_data->FSOpenFile);
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, "FSGetStatFile", private_data->FSGetStatFile);
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, "FSReadFile", private_data->FSReadFile);
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, "FSCloseFile", private_data->FSCloseFile);
|
||||||
|
|
||||||
unsigned int sysapp_handle;
|
unsigned int sysapp_handle;
|
||||||
OSDynLoad_Acquire("sysapp.rpl", &sysapp_handle);
|
OSDynLoad_Acquire("sysapp.rpl", &sysapp_handle);
|
||||||
OS_FIND_EXPORT(sysapp_handle, "SYSRelaunchTitle", private_data->SYSRelaunchTitle);
|
OS_FIND_EXPORT(sysapp_handle, "SYSRelaunchTitle", private_data->SYSRelaunchTitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
int _start(int argc, char **argv)
|
int _start(int argc, char **argv)
|
||||||
{
|
|
||||||
{
|
{
|
||||||
private_data_t private_data;
|
private_data_t private_data;
|
||||||
|
|
||||||
|
if(MAIN_ENTRY_ADDR != 0xC001C0DE)
|
||||||
|
{
|
||||||
loadFunctionPointers(&private_data);
|
loadFunctionPointers(&private_data);
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
if(ELF_DATA_ADDR != 0xDEADC0DE && ELF_DATA_SIZE > 0)
|
if(ELF_DATA_ADDR != 0xDEADC0DE && ELF_DATA_SIZE > 0)
|
||||||
{
|
{
|
||||||
//! copy data to safe area before processing it
|
//! copy data to safe area before processing it
|
||||||
@ -137,24 +583,70 @@ int _start(int argc, char **argv)
|
|||||||
private_data.memcpy(pElfBuffer, (unsigned char*)ELF_DATA_ADDR, ELF_DATA_SIZE);
|
private_data.memcpy(pElfBuffer, (unsigned char*)ELF_DATA_ADDR, ELF_DATA_SIZE);
|
||||||
MAIN_ENTRY_ADDR = load_elf_image(&private_data, pElfBuffer);
|
MAIN_ENTRY_ADDR = load_elf_image(&private_data, pElfBuffer);
|
||||||
private_data.MEMFreeToDefaultHeap(pElfBuffer);
|
private_data.MEMFreeToDefaultHeap(pElfBuffer);
|
||||||
|
|
||||||
}
|
}
|
||||||
ELF_DATA_ADDR = 0xDEADC0DE;
|
ELF_DATA_ADDR = 0xDEADC0DE;
|
||||||
ELF_DATA_SIZE = 0;
|
ELF_DATA_SIZE = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((MAIN_ENTRY_ADDR != 0xDEADC0DE) && (MAIN_ENTRY_ADDR != 0))
|
if(MAIN_ENTRY_ADDR == 0xDEADC0DE || MAIN_ENTRY_ADDR == 0)
|
||||||
|
{
|
||||||
|
if(HBL_CHANNEL)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned char *pElfBuffer = NULL;
|
||||||
|
unsigned int uiElfSize = 0;
|
||||||
|
|
||||||
|
LoadFileToMem(&private_data, CAFE_OS_SD_PATH WIIU_PATH "/apps/homebrew_launcher/homebrew_launcher.elf", &pElfBuffer, &uiElfSize);
|
||||||
|
|
||||||
|
if(!pElfBuffer)
|
||||||
|
{
|
||||||
|
private_data.OSFatal("Failed to load homebrew_launcher.elf");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MAIN_ENTRY_ADDR = load_elf_image(&private_data, pElfBuffer);
|
||||||
|
if(MAIN_ENTRY_ADDR == 0)
|
||||||
|
{
|
||||||
|
private_data.OSFatal("Failed to load homebrew_launcher.elf");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
private_data.MEMFreeToDefaultHeap(pElfBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
int returnVal = ((int (*)(int, char **))MAIN_ENTRY_ADDR)(argc, argv);
|
int returnVal = ((int (*)(int, char **))MAIN_ENTRY_ADDR)(argc, argv);
|
||||||
|
|
||||||
//! exit to miimaker and restart application on re-enter of another application
|
//! exit to miimaker and restart application on re-enter of another application
|
||||||
if(returnVal != (int)EXIT_RELAUNCH_ON_LOAD)
|
if(returnVal == (int)EXIT_RELAUNCH_ON_LOAD)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//! exit to homebrew launcher in all other cases
|
||||||
|
else
|
||||||
{
|
{
|
||||||
MAIN_ENTRY_ADDR = 0xDEADC0DE;
|
MAIN_ENTRY_ADDR = 0xDEADC0DE;
|
||||||
private_data.SYSRelaunchTitle(0, 0);
|
private_data.SYSRelaunchTitle(0, 0);
|
||||||
private_data.exit(0);
|
private_data.exit(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ( (int (*)(int, char **))(*(unsigned int*)OS_SPECIFICS->addr_OSTitle_main_entry) )(argc, argv);
|
int ret = ( (int (*)(int, char **))(*(unsigned int*)OS_SPECIFICS->addr_OSTitle_main_entry) )(argc, argv);
|
||||||
|
|
||||||
|
//! if an application returns and was an RPX launch then launch HBL again
|
||||||
|
if(MAIN_ENTRY_ADDR == 0xC001C0DE)
|
||||||
|
{
|
||||||
|
private_data.SYSRelaunchTitle(0, 0);
|
||||||
|
private_data.exit(0);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
62
sd_loader/src/fs_defs.h
Normal file
62
sd_loader/src/fs_defs.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#ifndef FS_DEFS_H
|
||||||
|
#define FS_DEFS_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* FS defines and types */
|
||||||
|
#define FS_MAX_LOCALPATH_SIZE 511
|
||||||
|
#define FS_MAX_MOUNTPATH_SIZE 128
|
||||||
|
#define FS_MAX_FULLPATH_SIZE (FS_MAX_LOCALPATH_SIZE + FS_MAX_MOUNTPATH_SIZE)
|
||||||
|
#define FS_MAX_ARGPATH_SIZE FS_MAX_FULLPATH_SIZE
|
||||||
|
|
||||||
|
#define FS_STATUS_OK 0
|
||||||
|
#define FS_RET_UNSUPPORTED_CMD 0x0400
|
||||||
|
#define FS_RET_NO_ERROR 0x0000
|
||||||
|
#define FS_RET_ALL_ERROR (unsigned int)(-1)
|
||||||
|
|
||||||
|
#define FS_STAT_FLAG_IS_DIRECTORY 0x80000000
|
||||||
|
|
||||||
|
/* max length of file/dir name */
|
||||||
|
#define FS_MAX_ENTNAME_SIZE 256
|
||||||
|
|
||||||
|
#define FS_SOURCETYPE_EXTERNAL 0
|
||||||
|
#define FS_SOURCETYPE_HFIO 1
|
||||||
|
#define FS_SOURCETYPE_HFIO 1
|
||||||
|
|
||||||
|
#define FS_MOUNT_SOURCE_SIZE 0x300
|
||||||
|
#define FS_CLIENT_SIZE 0x1700
|
||||||
|
#define FS_CMD_BLOCK_SIZE 0xA80
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t flag;
|
||||||
|
uint32_t permission;
|
||||||
|
uint32_t owner_id;
|
||||||
|
uint32_t group_id;
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t alloc_size;
|
||||||
|
uint64_t quota_size;
|
||||||
|
uint32_t ent_id;
|
||||||
|
uint64_t ctime;
|
||||||
|
uint64_t mtime;
|
||||||
|
uint8_t attributes[48];
|
||||||
|
} __attribute__((packed)) FSStat;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
FSStat stat;
|
||||||
|
char name[FS_MAX_ENTNAME_SIZE];
|
||||||
|
} FSDirEntry;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* FS_DEFS_H */
|
||||||
|
|
@ -19,11 +19,15 @@ extern "C" {
|
|||||||
|
|
||||||
#define ELF_DATA_ADDR (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x00))
|
#define ELF_DATA_ADDR (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x00))
|
||||||
#define ELF_DATA_SIZE (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x04))
|
#define ELF_DATA_SIZE (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x04))
|
||||||
|
#define HBL_CHANNEL (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x08))
|
||||||
|
#define RPX_MAX_SIZE (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x0C))
|
||||||
|
#define RPX_MAX_CODE_SIZE (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x10))
|
||||||
#define MAIN_ENTRY_ADDR (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x00))
|
#define MAIN_ENTRY_ADDR (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x00))
|
||||||
#define OS_FIRMWARE (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x04))
|
#define OS_FIRMWARE (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x04))
|
||||||
|
|
||||||
#define OS_SPECIFICS ((OsSpecifics*)(MEM_BASE + 0x1500))
|
#define OS_SPECIFICS ((OsSpecifics*)(MEM_BASE + 0x1500))
|
||||||
|
|
||||||
|
#define MEM_AREA_TABLE ((s_mem_area*)(MEM_BASE + 0x1600))
|
||||||
#define APP_BASE_MEM ((unsigned char*)(MEM_BASE + 0x2000))
|
#define APP_BASE_MEM ((unsigned char*)(MEM_BASE + 0x2000))
|
||||||
|
|
||||||
#ifndef EXIT_SUCCESS
|
#ifndef EXIT_SUCCESS
|
||||||
|
@ -42,9 +42,9 @@ DirList::DirList()
|
|||||||
Depth = 0;
|
Depth = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DirList::DirList(const std::string & path, const char *filter, u32 flags, u32 depth)
|
DirList::DirList(const std::string & path, const char *filter, u32 flags, u32 maxDepth)
|
||||||
{
|
{
|
||||||
this->LoadPath(path, filter, flags, depth);
|
this->LoadPath(path, filter, flags, maxDepth);
|
||||||
this->SortList();
|
this->SortList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,13 +53,13 @@ DirList::~DirList()
|
|||||||
ClearList();
|
ClearList();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DirList::LoadPath(const std::string & folder, const char *filter, u32 flags, u32 depth)
|
bool DirList::LoadPath(const std::string & folder, const char *filter, u32 flags, u32 maxDepth)
|
||||||
{
|
{
|
||||||
if(folder.empty()) return false;
|
if(folder.empty()) return false;
|
||||||
|
|
||||||
Flags = flags;
|
Flags = flags;
|
||||||
Filter = filter;
|
Filter = filter;
|
||||||
Depth = depth;
|
Depth = maxDepth;
|
||||||
|
|
||||||
std::string folderpath(folder);
|
std::string folderpath(folder);
|
||||||
u32 length = folderpath.size();
|
u32 length = folderpath.size();
|
||||||
@ -78,7 +78,6 @@ bool DirList::LoadPath(const std::string & folder, const char *filter, u32 flags
|
|||||||
return InternalLoadPath(folderpath);
|
return InternalLoadPath(folderpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "utils/logger.h"
|
|
||||||
bool DirList::InternalLoadPath(std::string &folderpath)
|
bool DirList::InternalLoadPath(std::string &folderpath)
|
||||||
{
|
{
|
||||||
if(folderpath.size() < 3)
|
if(folderpath.size() < 3)
|
||||||
@ -87,7 +86,6 @@ bool DirList::InternalLoadPath(std::string &folderpath)
|
|||||||
struct dirent *dirent = NULL;
|
struct dirent *dirent = NULL;
|
||||||
DIR *dir = NULL;
|
DIR *dir = NULL;
|
||||||
|
|
||||||
log_printf("open %s\n", folderpath.c_str());
|
|
||||||
dir = opendir(folderpath.c_str());
|
dir = opendir(folderpath.c_str());
|
||||||
if (dir == NULL)
|
if (dir == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
@ -45,11 +45,11 @@ public:
|
|||||||
//!\param path Path from where to load the filelist of all files
|
//!\param path Path from where to load the filelist of all files
|
||||||
//!\param filter A fileext that needs to be filtered
|
//!\param filter A fileext that needs to be filtered
|
||||||
//!\param flags search/filter flags from the enum
|
//!\param flags search/filter flags from the enum
|
||||||
DirList(const std::string & path, const char *filter = NULL, u32 flags = Files | Dirs, u32 depth = 0xffffffff);
|
DirList(const std::string & path, const char *filter = NULL, u32 flags = Files | Dirs, u32 maxDepth = 0xffffffff);
|
||||||
//!Destructor
|
//!Destructor
|
||||||
virtual ~DirList();
|
virtual ~DirList();
|
||||||
//! Load all the files from a directory
|
//! Load all the files from a directory
|
||||||
bool LoadPath(const std::string & path, const char *filter = NULL, u32 flags = Files | Dirs, u32 depth = 0xffffffff);
|
bool LoadPath(const std::string & path, const char *filter = NULL, u32 flags = Files | Dirs, u32 maxDepth = 0xffffffff);
|
||||||
//! Get a filename of the list
|
//! Get a filename of the list
|
||||||
//!\param list index
|
//!\param list index
|
||||||
const char * GetFilename(int index) const;
|
const char * GetFilename(int index) const;
|
||||||
|
@ -28,7 +28,6 @@ using namespace std;
|
|||||||
|
|
||||||
#define ALIGN4(x) (((x) + 3) & ~3)
|
#define ALIGN4(x) (((x) + 3) & ~3)
|
||||||
|
|
||||||
#include "utils/logger.h"
|
|
||||||
/**
|
/**
|
||||||
* Default constructor for the FreeTypeGX class for WiiXplorer.
|
* Default constructor for the FreeTypeGX class for WiiXplorer.
|
||||||
*/
|
*/
|
||||||
@ -370,7 +369,7 @@ int16_t FreeTypeGX::getStyleOffsetHeight(int16_t format, uint16_t pixelSize)
|
|||||||
* @return The number of characters printed.
|
* @return The number of characters printed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint16_t FreeTypeGX::drawText(CVideo *video, int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, const glm::vec4 & color, uint16_t textStyle, uint16_t textWidth, const float &textBlur, const float &colorBlurIntensity, const glm::vec4 & blurColor)
|
uint16_t FreeTypeGX::drawText(CVideo *video, int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, const glm::vec4 & color, uint16_t textStyle, uint16_t textWidth, const float &textBlur, const float & colorBlurIntensity, const glm::vec4 & blurColor, const float & internalRenderingScale)
|
||||||
{
|
{
|
||||||
if (!text)
|
if (!text)
|
||||||
return 0;
|
return 0;
|
||||||
@ -401,9 +400,9 @@ uint16_t FreeTypeGX::drawText(CVideo *video, int16_t x, int16_t y, int16_t z, co
|
|||||||
{
|
{
|
||||||
FT_Get_Kerning(ftFace, fontData[pixelSize].ftgxCharMap[text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta);
|
FT_Get_Kerning(ftFace, fontData[pixelSize].ftgxCharMap[text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta);
|
||||||
x_pos += (pairDelta.x >> 6);
|
x_pos += (pairDelta.x >> 6);
|
||||||
}
|
|
||||||
|
|
||||||
copyTextureToFramebuffer(video, glyphData->texture, x_pos + glyphData->renderOffsetX + x_offset, y + glyphData->renderOffsetY - y_offset, z, color, textBlur, colorBlurIntensity, blurColor);
|
}
|
||||||
|
copyTextureToFramebuffer(video, glyphData->texture,x_pos + glyphData->renderOffsetX + x_offset, y + glyphData->renderOffsetY - y_offset, z, color, textBlur, colorBlurIntensity, blurColor,internalRenderingScale);
|
||||||
|
|
||||||
x_pos += glyphData->glyphAdvanceX;
|
x_pos += glyphData->glyphAdvanceX;
|
||||||
++printed;
|
++printed;
|
||||||
@ -548,13 +547,13 @@ void FreeTypeGX::getOffset(const wchar_t *text, int16_t pixelSize, uint16_t widt
|
|||||||
* @param screenY The screen Y coordinate at which to output the rendered texture.
|
* @param screenY The screen Y coordinate at which to output the rendered texture.
|
||||||
* @param color Color to apply to the texture.
|
* @param color Color to apply to the texture.
|
||||||
*/
|
*/
|
||||||
void FreeTypeGX::copyTextureToFramebuffer(CVideo *pVideo, GX2Texture *texture, int16_t x, int16_t y, int16_t z, const glm::vec4 & color, const float & defaultBlur, const float & blurIntensity, const glm::vec4 & blurColor)
|
void FreeTypeGX::copyTextureToFramebuffer(CVideo *pVideo, GX2Texture *texture, int16_t x, int16_t y, int16_t z, const glm::vec4 & color, const float & defaultBlur, const float & blurIntensity, const glm::vec4 & blurColor, const float & internalRenderingScale)
|
||||||
{
|
{
|
||||||
static const f32 imageAngle = 0.0f;
|
static const f32 imageAngle = 0.0f;
|
||||||
static const f32 blurScale = 2.0f;
|
static const f32 blurScale = (2.0f/ (internalRenderingScale));
|
||||||
|
|
||||||
f32 offsetLeft = 2.0f * ((f32)x + 0.5f * (f32)texture->surface.width) * (f32)pVideo->getWidthScaleFactor();
|
f32 offsetLeft = blurScale * ((f32)x + 0.5f * (f32)texture->surface.width) * (f32)pVideo->getWidthScaleFactor();
|
||||||
f32 offsetTop = 2.0f * ((f32)y - 0.5f * (f32)texture->surface.height) * (f32)pVideo->getHeightScaleFactor();
|
f32 offsetTop = blurScale * ((f32)y - 0.5f * (f32)texture->surface.height) * (f32)pVideo->getHeightScaleFactor();
|
||||||
|
|
||||||
f32 widthScale = blurScale * (f32)texture->surface.width * pVideo->getWidthScaleFactor();
|
f32 widthScale = blurScale * (f32)texture->surface.width * pVideo->getWidthScaleFactor();
|
||||||
f32 heightScale = blurScale * (f32)texture->surface.height * pVideo->getHeightScaleFactor();
|
f32 heightScale = blurScale * (f32)texture->surface.height * pVideo->getHeightScaleFactor();
|
||||||
|
@ -167,8 +167,6 @@ void HomebrewLaunchWindow::OnFileLoadFinish(GuiElement *element, const std::stri
|
|||||||
|
|
||||||
if(result > 0)
|
if(result > 0)
|
||||||
{
|
{
|
||||||
ELF_DATA_ADDR = (u32)APP_BASE_MEM;
|
|
||||||
ELF_DATA_SIZE = result;
|
|
||||||
Application::instance()->quit(EXIT_SUCCESS);
|
Application::instance()->quit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,7 +177,7 @@ void HomebrewLaunchWindow::OnLoadButtonClick(GuiButton *button, const GuiControl
|
|||||||
backBtn.setState(GuiElement::STATE_DISABLED);
|
backBtn.setState(GuiElement::STATE_DISABLED);
|
||||||
loadBtn.setState(GuiElement::STATE_DISABLED);
|
loadBtn.setState(GuiElement::STATE_DISABLED);
|
||||||
|
|
||||||
HomebrewLoader * loader = HomebrewLoader::loadToMemoryAsync(homebrewLaunchPath, APP_BASE_MEM);
|
HomebrewLoader * loader = HomebrewLoader::loadToMemoryAsync(homebrewLaunchPath);
|
||||||
loader->setEffect(EFFECT_FADE, 15, 255);
|
loader->setEffect(EFFECT_FADE, 15, 255);
|
||||||
loader->effectFinished.connect(this, &HomebrewLaunchWindow::OnOpenEffectFinish);
|
loader->effectFinished.connect(this, &HomebrewLaunchWindow::OnOpenEffectFinish);
|
||||||
loader->asyncLoadFinished.connect(this, &HomebrewLaunchWindow::OnFileLoadFinish);
|
loader->asyncLoadFinished.connect(this, &HomebrewLaunchWindow::OnFileLoadFinish);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <coreinit/cache.h>
|
||||||
|
#include <coreinit/memory.h>
|
||||||
#include "common/common.h"
|
#include "common/common.h"
|
||||||
#include "dynamic_libs/os_functions.h"
|
|
||||||
#include "system/memory_area_table.h"
|
#include "system/memory_area_table.h"
|
||||||
#include "utils/utils.h"
|
#include "utils/utils.h"
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
@ -29,7 +30,7 @@ int HomebrewCopyMemory(u8 *address, u32 bytes)
|
|||||||
if(*(u16*)&address[7] != 0xCAFE)
|
if(*(u16*)&address[7] != 0xCAFE)
|
||||||
{
|
{
|
||||||
// assume ELF
|
// assume ELF
|
||||||
ELF_DATA_ADDR = getApplicationEndAddr();
|
ELF_DATA_ADDR = (u32)APP_BASE_MEM;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -43,7 +43,7 @@ HomebrewWindow::HomebrewWindow(int w, int h)
|
|||||||
, wpadTouchTrigger(GuiTrigger::CHANNEL_2 | GuiTrigger::CHANNEL_3 | GuiTrigger::CHANNEL_4 | GuiTrigger::CHANNEL_5, GuiTrigger::BUTTON_A)
|
, wpadTouchTrigger(GuiTrigger::CHANNEL_2 | GuiTrigger::CHANNEL_3 | GuiTrigger::CHANNEL_4 | GuiTrigger::CHANNEL_5, GuiTrigger::BUTTON_A)
|
||||||
, buttonLTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_L | GuiTrigger::BUTTON_LEFT, true)
|
, buttonLTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_L | GuiTrigger::BUTTON_LEFT, true)
|
||||||
, buttonRTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_R | GuiTrigger::BUTTON_RIGHT, true)
|
, buttonRTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_R | GuiTrigger::BUTTON_RIGHT, true)
|
||||||
, tcpReceiver(APP_BASE_MEM, DEFAULT_WIILOAD_PORT)
|
, tcpReceiver(DEFAULT_WIILOAD_PORT)
|
||||||
{
|
{
|
||||||
tcpReceiver.serverReceiveStart.connect(this, &HomebrewWindow::OnTcpReceiveStart);
|
tcpReceiver.serverReceiveStart.connect(this, &HomebrewWindow::OnTcpReceiveStart);
|
||||||
tcpReceiver.serverReceiveFinished.connect(this, &HomebrewWindow::OnTcpReceiveFinish);
|
tcpReceiver.serverReceiveFinished.connect(this, &HomebrewWindow::OnTcpReceiveFinish);
|
||||||
@ -52,7 +52,7 @@ HomebrewWindow::HomebrewWindow(int w, int h)
|
|||||||
currentLeftPosition = 0;
|
currentLeftPosition = 0;
|
||||||
listOffset = 0;
|
listOffset = 0;
|
||||||
|
|
||||||
DirList dirList("fs:/vol/external01/wiiu/apps", ".elf", DirList::Files | DirList::CheckSubfolders, 1);
|
DirList dirList("fs:/vol/external01/wiiu/apps", ".elf,.rpx", DirList::Files | DirList::CheckSubfolders, 1);
|
||||||
|
|
||||||
dirList.SortList();
|
dirList.SortList();
|
||||||
|
|
||||||
@ -314,8 +314,6 @@ void HomebrewWindow::OnCloseTcpReceiverFinish(GuiElement *element)
|
|||||||
|
|
||||||
void HomebrewWindow::OnTcpReceiveStart(GuiElement *element, u32 ip)
|
void HomebrewWindow::OnTcpReceiveStart(GuiElement *element, u32 ip)
|
||||||
{
|
{
|
||||||
setState(STATE_DISABLED);
|
|
||||||
|
|
||||||
element->setEffect(EFFECT_FADE, 15, 255);
|
element->setEffect(EFFECT_FADE, 15, 255);
|
||||||
element->effectFinished.connect(this, &HomebrewWindow::OnOpenEffectFinish);
|
element->effectFinished.connect(this, &HomebrewWindow::OnOpenEffectFinish);
|
||||||
append(element);
|
append(element);
|
||||||
@ -329,8 +327,7 @@ void HomebrewWindow::OnTcpReceiveFinish(GuiElement *element, u32 ip, int result)
|
|||||||
|
|
||||||
if(result > 0)
|
if(result > 0)
|
||||||
{
|
{
|
||||||
ELF_DATA_ADDR = (u32)APP_BASE_MEM;
|
log_printf("Launching homebrew, loaded to address %08X size %08X\n", ELF_DATA_ADDR, ELF_DATA_SIZE);
|
||||||
ELF_DATA_SIZE = result;
|
|
||||||
Application::instance()->quit(EXIT_SUCCESS);
|
Application::instance()->quit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,16 +5,16 @@
|
|||||||
#include <nsysnet/socket.h>
|
#include <nsysnet/socket.h>
|
||||||
|
|
||||||
#include "TcpReceiver.h"
|
#include "TcpReceiver.h"
|
||||||
|
#include "HomebrewMemory.h"
|
||||||
#include "fs/CFile.hpp"
|
#include "fs/CFile.hpp"
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
#include "utils/StringTools.h"
|
#include "utils/StringTools.h"
|
||||||
#include "utils/net.h"
|
#include "utils/net.h"
|
||||||
|
|
||||||
TcpReceiver::TcpReceiver(unsigned char* loadAddr, int port)
|
TcpReceiver::TcpReceiver(int port)
|
||||||
: GuiFrame(0, 0)
|
: GuiFrame(0, 0)
|
||||||
, CThread(CThread::eAttributeAffCore0 | CThread::eAttributePinnedAff)
|
, CThread(CThread::eAttributeAffCore0 | CThread::eAttributePinnedAff)
|
||||||
, exitRequested(false)
|
, exitRequested(false)
|
||||||
, loadAddress(0)
|
|
||||||
, serverPort(port)
|
, serverPort(port)
|
||||||
, serverSocket(-1)
|
, serverSocket(-1)
|
||||||
, progressWindow("Receiving file...")
|
, progressWindow("Receiving file...")
|
||||||
@ -22,8 +22,6 @@ TcpReceiver::TcpReceiver(unsigned char* loadAddr, int port)
|
|||||||
width = progressWindow.getWidth();
|
width = progressWindow.getWidth();
|
||||||
height = progressWindow.getHeight();
|
height = progressWindow.getHeight();
|
||||||
append(&progressWindow);
|
append(&progressWindow);
|
||||||
|
|
||||||
loadAddress = loadAddr;
|
|
||||||
resumeThread();
|
resumeThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,32 +120,30 @@ int TcpReceiver::loadToMemory(s32 clientSocket, u32 ipAddress)
|
|||||||
|
|
||||||
log_printf("transfer start\n");
|
log_printf("transfer start\n");
|
||||||
|
|
||||||
std::string strBuffer;
|
unsigned char* loadAddress = (unsigned char*)memalign(0x40, fileSize);
|
||||||
strBuffer.resize(0x1000);
|
if(!loadAddress)
|
||||||
|
{
|
||||||
|
progressWindow.setTitle("Not enough memory");
|
||||||
|
sleep(1);
|
||||||
|
return NOT_ENOUGH_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
// Copy rpl in memory
|
// Copy rpl in memory
|
||||||
while(bytesRead < fileSize)
|
while(bytesRead < fileSize)
|
||||||
{
|
{
|
||||||
progressWindow.setProgress(100.0f * (f32)bytesRead / (f32)fileSize);
|
progressWindow.setProgress(100.0f * (f32)bytesRead / (f32)fileSize);
|
||||||
|
|
||||||
u32 blockSize = strBuffer.size();
|
u32 blockSize = 0x1000;
|
||||||
if(blockSize > (fileSize - bytesRead))
|
if(blockSize > (fileSize - bytesRead))
|
||||||
blockSize = fileSize - bytesRead;
|
blockSize = fileSize - bytesRead;
|
||||||
|
|
||||||
if((u32)(loadAddress + bytesRead + blockSize) > 0x01000000)
|
int ret = recv(clientSocket, loadAddress + bytesRead, blockSize, 0);
|
||||||
{
|
|
||||||
log_printf("File ist too big\n");
|
|
||||||
return NOT_ENOUGH_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ret = recv(clientSocket, &strBuffer[0], blockSize, 0);
|
|
||||||
if(ret <= 0)
|
if(ret <= 0)
|
||||||
{
|
{
|
||||||
log_printf("Failure on reading file\n");
|
log_printf("Failure on reading file\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(loadAddress + bytesRead, &strBuffer[0], ret);
|
|
||||||
bytesRead += ret;
|
bytesRead += ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,13 +151,20 @@ int TcpReceiver::loadToMemory(s32 clientSocket, u32 ipAddress)
|
|||||||
|
|
||||||
if(bytesRead != fileSize)
|
if(bytesRead != fileSize)
|
||||||
{
|
{
|
||||||
|
free(loadAddress);
|
||||||
log_printf("File loading not finished, %i of %i bytes received\n", bytesRead, fileSize);
|
log_printf("File loading not finished, %i of %i bytes received\n", bytesRead, fileSize);
|
||||||
|
progressWindow.setTitle("Receive incomplete");
|
||||||
|
sleep(1);
|
||||||
return FILE_READ_ERROR;
|
return FILE_READ_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int res = -1;
|
||||||
|
|
||||||
// Do we need to unzip this thing?
|
// Do we need to unzip this thing?
|
||||||
if (haxx[4] > 0 || haxx[5] > 4)
|
if (haxx[4] > 0 || haxx[5] > 4)
|
||||||
{
|
{
|
||||||
|
unsigned char* inflatedData = NULL;
|
||||||
|
|
||||||
// We need to unzip...
|
// We need to unzip...
|
||||||
if (loadAddress[0] == 'P' && loadAddress[1] == 'K' && loadAddress[2] == 0x03 && loadAddress[3] == 0x04)
|
if (loadAddress[0] == 'P' && loadAddress[1] == 'K' && loadAddress[2] == 0x03 && loadAddress[3] == 0x04)
|
||||||
{
|
{
|
||||||
@ -169,8 +172,14 @@ int TcpReceiver::loadToMemory(s32 clientSocket, u32 ipAddress)
|
|||||||
//! mhmm this is incorrect, it has to parse the zip
|
//! mhmm this is incorrect, it has to parse the zip
|
||||||
|
|
||||||
// Section is compressed, inflate
|
// Section is compressed, inflate
|
||||||
std::string inflatedData;
|
inflatedData = (unsigned char*)malloc(fileSizeUnc);
|
||||||
inflatedData.resize(fileSizeUnc);
|
if(!inflatedData)
|
||||||
|
{
|
||||||
|
free(loadAddress);
|
||||||
|
progressWindow.setTitle("Not enough memory");
|
||||||
|
sleep(1);
|
||||||
|
return NOT_ENOUGH_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
z_stream s;
|
z_stream s;
|
||||||
@ -182,7 +191,13 @@ int TcpReceiver::loadToMemory(s32 clientSocket, u32 ipAddress)
|
|||||||
|
|
||||||
ret = inflateInit(&s);
|
ret = inflateInit(&s);
|
||||||
if (ret != Z_OK)
|
if (ret != Z_OK)
|
||||||
|
{
|
||||||
|
free(loadAddress);
|
||||||
|
free(inflatedData);
|
||||||
|
progressWindow.setTitle("Uncompress failure");
|
||||||
|
sleep(1);
|
||||||
return FILE_READ_ERROR;
|
return FILE_READ_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
s.avail_in = fileSize;
|
s.avail_in = fileSize;
|
||||||
s.next_in = (Bytef *)(&loadAddress[0]);
|
s.next_in = (Bytef *)(&loadAddress[0]);
|
||||||
@ -192,34 +207,62 @@ int TcpReceiver::loadToMemory(s32 clientSocket, u32 ipAddress)
|
|||||||
|
|
||||||
ret = inflate(&s, Z_FINISH);
|
ret = inflate(&s, Z_FINISH);
|
||||||
if (ret != Z_OK && ret != Z_STREAM_END)
|
if (ret != Z_OK && ret != Z_STREAM_END)
|
||||||
|
{
|
||||||
|
free(loadAddress);
|
||||||
|
free(inflatedData);
|
||||||
|
progressWindow.setTitle("Uncompress failure");
|
||||||
|
sleep(1);
|
||||||
return FILE_READ_ERROR;
|
return FILE_READ_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
inflateEnd(&s);
|
inflateEnd(&s);
|
||||||
|
|
||||||
if(fileSizeUnc > (0x01000000 - (u32)loadAddress))
|
|
||||||
return FILE_READ_ERROR;
|
|
||||||
|
|
||||||
memcpy(loadAddress, &inflatedData[0], fileSizeUnc);
|
|
||||||
fileSize = fileSizeUnc;
|
fileSize = fileSizeUnc;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Section is compressed, inflate
|
// Section is compressed, inflate
|
||||||
std::string inflatedData;
|
inflatedData = (unsigned char*)malloc(fileSizeUnc);
|
||||||
inflatedData.resize(fileSizeUnc);
|
if(!inflatedData)
|
||||||
|
{
|
||||||
|
free(loadAddress);
|
||||||
|
progressWindow.setTitle("Not enough memory");
|
||||||
|
sleep(1);
|
||||||
|
return NOT_ENOUGH_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
uLongf f = fileSizeUnc;
|
uLongf f = fileSizeUnc;
|
||||||
int result = uncompress((Bytef*)&inflatedData[0], &f, (Bytef*)loadAddress, fileSize);
|
int result = uncompress((Bytef*)&inflatedData[0], &f, (Bytef*)loadAddress, fileSize);
|
||||||
if(result != Z_OK)
|
if(result != Z_OK)
|
||||||
{
|
{
|
||||||
log_printf("uncompress failed %i\n", result);
|
log_printf("uncompress failed %i\n", result);
|
||||||
|
progressWindow.setTitle("Uncompress failure");
|
||||||
|
sleep(1);
|
||||||
return FILE_READ_ERROR;
|
return FILE_READ_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
fileSizeUnc = f;
|
fileSizeUnc = f;
|
||||||
memcpy(loadAddress, &inflatedData[0], fileSizeUnc);
|
|
||||||
fileSize = fileSizeUnc;
|
fileSize = fileSizeUnc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(loadAddress);
|
||||||
|
|
||||||
|
HomebrewInitMemory();
|
||||||
|
res = HomebrewCopyMemory(inflatedData, fileSize);
|
||||||
|
free(inflatedData);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HomebrewInitMemory();
|
||||||
|
res = HomebrewCopyMemory(loadAddress, fileSize);
|
||||||
|
free(loadAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
progressWindow.setTitle("Not enough memory");
|
||||||
|
sleep(1);
|
||||||
|
return NOT_ENOUGH_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
return fileSize;
|
return fileSize;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ public:
|
|||||||
NOT_ENOUGH_MEMORY = -4,
|
NOT_ENOUGH_MEMORY = -4,
|
||||||
};
|
};
|
||||||
|
|
||||||
TcpReceiver(unsigned char* loadAddr, int port);
|
TcpReceiver(int port);
|
||||||
~TcpReceiver();
|
~TcpReceiver();
|
||||||
|
|
||||||
sigslot::signal2<GuiElement *, u32> serverReceiveStart;
|
sigslot::signal2<GuiElement *, u32> serverReceiveStart;
|
||||||
|
@ -81,7 +81,7 @@ public:
|
|||||||
voiceBuffer.dataType = format;
|
voiceBuffer.dataType = format;
|
||||||
voiceBuffer.loopingEnabled = (nextBuffer == NULL) ? 0 : 1;
|
voiceBuffer.loopingEnabled = (nextBuffer == NULL) ? 0 : 1;
|
||||||
voiceBuffer.currentOffset = 0;
|
voiceBuffer.currentOffset = 0;
|
||||||
voiceBuffer.endOffset = bufferSize >> 1;
|
voiceBuffer.endOffset = (bufferSize >> 1) - 1;
|
||||||
voiceBuffer.loopOffset = ((nextBuffer - buffer) >> 1);
|
voiceBuffer.loopOffset = ((nextBuffer - buffer) >> 1);
|
||||||
nextBufferSize = nextBufSize;
|
nextBufferSize = nextBufSize;
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ public:
|
|||||||
if(lastLoopCounter != loopCounter)
|
if(lastLoopCounter != loopCounter)
|
||||||
{
|
{
|
||||||
lastLoopCounter = loopCounter;
|
lastLoopCounter = loopCounter;
|
||||||
AXSetVoiceEndOffset(voice, voiceBuffer.loopOffset + (nextBufferSize >> 1));
|
AXSetVoiceEndOffset(voice, voiceBuffer.loopOffset + (nextBufferSize >> 1) - 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <gctypes.h>
|
|
||||||
#include "common/common.h"
|
#include "common/common.h"
|
||||||
#include "utils/utils.h"
|
#include "utils/utils.h"
|
||||||
#include "memory_area_table.h"
|
#include "memory_area_table.h"
|
||||||
@ -352,9 +351,7 @@ static inline void memoryAddArea(int start, int end, int cur_index)
|
|||||||
/* Create memory areas arrays */
|
/* Create memory areas arrays */
|
||||||
void memoryInitAreaTable()
|
void memoryInitAreaTable()
|
||||||
{
|
{
|
||||||
u32 ApplicationMemoryEnd = getApplicationEndAddr();
|
u32 ApplicationMemoryEnd = (u32)APP_BASE_MEM;
|
||||||
if(ApplicationMemoryEnd >= 0x01000000)
|
|
||||||
ApplicationMemoryEnd = 0x00800000;
|
|
||||||
|
|
||||||
// This one seems to be available on every firmware and therefore its our code area but also our main RPX area behind our code
|
// This one seems to be available on every firmware and therefore its our code area but also our main RPX area behind our code
|
||||||
// 22876 kB - our application // ok
|
// 22876 kB - our application // ok
|
||||||
|
@ -40,6 +40,8 @@ extern "C" {
|
|||||||
#define le32(i) ((((u32)le16((i) & 0xFFFF)) << 16) | ((u32)le16(((i) & 0xFFFF0000) >> 16)))
|
#define le32(i) ((((u32)le16((i) & 0xFFFF)) << 16) | ((u32)le16(((i) & 0xFFFF0000) >> 16)))
|
||||||
#define le64(i) ((((u64)le32((i) & 0xFFFFFFFFLL)) << 32) | ((u64)le32(((i) & 0xFFFFFFFF00000000LL) >> 32)))
|
#define le64(i) ((((u64)le32((i) & 0xFFFFFFFFLL)) << 32) | ((u64)le32(((i) & 0xFFFFFFFF00000000LL) >> 32)))
|
||||||
|
|
||||||
|
void SC0x25_KernelCopyData(unsigned int addr, unsigned int src, unsigned int len);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
5
src/utils/utils_asm.S
Normal file
5
src/utils/utils_asm.S
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.globl SC0x25_KernelCopyData
|
||||||
|
SC0x25_KernelCopyData:
|
||||||
|
li r0, 0x2500
|
||||||
|
sc
|
||||||
|
blr
|
Loading…
x
Reference in New Issue
Block a user