diff --git a/sd_loader/src/entry.c b/sd_loader/src/entry.c index 26f777c..40b7d21 100644 --- a/sd_loader/src/entry.c +++ b/sd_loader/src/entry.c @@ -2,13 +2,12 @@ #include "elf_abi.h" #include "../../src/common/common.h" #include "../../src/common/os_defs.h" - -#define CODE_RW_BASE_OFFSET 0 -#define DATA_RW_BASE_OFFSET 0 +#include "fs_defs.h" +#include "kernel_defs.h" +#include "loader_defs.h" #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 { @@ -18,14 +17,434 @@ typedef struct _private_data_t 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, OSFatal, const char* msg); - EXPORT_DECL(void, DCFlushRange, const void *addr, u32 length); - EXPORT_DECL(void, ICInvalidateRange, const void *addr, u32 length); - EXPORT_DECL(int, __os_snprintf, char* s, int n, const char * format, ...); + EXPORT_DECL(unsigned int, OSEffectiveToPhysical, const void*); 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); } 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) { Elf32_Ehdr *ehdr; @@ -49,25 +468,19 @@ static unsigned int load_elf_image (private_data_t *private_data, unsigned char continue; if(phdrs[i].p_filesz > phdrs[i].p_memsz) - return 0; + continue; if(!phdrs[i].p_filesz) continue; 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); - private_data->memcpy ((void *) p_paddr, image, phdrs[i].p_filesz); - private_data->DCFlushRange((void*)p_paddr, phdrs[i].p_filesz); + + private_data->memcpy ((void *) p_paddr, image, phdrs[i].p_filesz); + DCFlushRange((void*)p_paddr, phdrs[i].p_filesz); 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 @@ -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') { 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') { 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; } @@ -112,11 +541,24 @@ static void loadFunctionPointers(private_data_t * private_data) OS_FIND_EXPORT(coreinit_handle, "memcpy", private_data->memcpy); OS_FIND_EXPORT(coreinit_handle, "memset", private_data->memset); OS_FIND_EXPORT(coreinit_handle, "OSFatal", private_data->OSFatal); - OS_FIND_EXPORT(coreinit_handle, "DCFlushRange", private_data->DCFlushRange); - OS_FIND_EXPORT(coreinit_handle, "ICInvalidateRange", private_data->ICInvalidateRange); - OS_FIND_EXPORT(coreinit_handle, "__os_snprintf", private_data->__os_snprintf); + OS_FIND_EXPORT(coreinit_handle, "DCFlushRange", DCFlushRange); + OS_FIND_EXPORT(coreinit_handle, "DCInvalidateRange", DCInvalidateRange); + 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, "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; OSDynLoad_Acquire("sysapp.rpl", &sysapp_handle); OS_FIND_EXPORT(sysapp_handle, "SYSRelaunchTitle", private_data->SYSRelaunchTitle); @@ -124,37 +566,87 @@ static void loadFunctionPointers(private_data_t * private_data) int _start(int argc, char **argv) { + private_data_t private_data; + + if(MAIN_ENTRY_ADDR != 0xC001C0DE) { - private_data_t private_data; loadFunctionPointers(&private_data); - if(ELF_DATA_ADDR != 0xDEADC0DE && ELF_DATA_SIZE > 0) + while(1) { - //! copy data to safe area before processing it - unsigned char * pElfBuffer = (unsigned char *)private_data.MEMAllocFromDefaultHeapEx(ELF_DATA_SIZE, 4); - if(pElfBuffer) + if(ELF_DATA_ADDR != 0xDEADC0DE && ELF_DATA_SIZE > 0) { - private_data.memcpy(pElfBuffer, (unsigned char*)ELF_DATA_ADDR, ELF_DATA_SIZE); - MAIN_ENTRY_ADDR = load_elf_image(&private_data, pElfBuffer); - private_data.MEMFreeToDefaultHeap(pElfBuffer); + //! copy data to safe area before processing it + unsigned char * pElfBuffer = (unsigned char *)private_data.MEMAllocFromDefaultHeapEx(ELF_DATA_SIZE, 4); + if(pElfBuffer) + { + private_data.memcpy(pElfBuffer, (unsigned char*)ELF_DATA_ADDR, ELF_DATA_SIZE); + MAIN_ENTRY_ADDR = load_elf_image(&private_data, pElfBuffer); + private_data.MEMFreeToDefaultHeap(pElfBuffer); + + } + ELF_DATA_ADDR = 0xDEADC0DE; + ELF_DATA_SIZE = 0; } - ELF_DATA_ADDR = 0xDEADC0DE; - ELF_DATA_SIZE = 0; - } - if((MAIN_ENTRY_ADDR != 0xDEADC0DE) && (MAIN_ENTRY_ADDR != 0)) - { - int returnVal = ((int (*)(int, char **))MAIN_ENTRY_ADDR)(argc, argv); - - //! exit to miimaker and restart application on re-enter of another application - if(returnVal != (int)EXIT_RELAUNCH_ON_LOAD) + if(MAIN_ENTRY_ADDR == 0xDEADC0DE || MAIN_ENTRY_ADDR == 0) { - MAIN_ENTRY_ADDR = 0xDEADC0DE; - private_data.SYSRelaunchTitle(0, 0); - private_data.exit(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); + //! exit to miimaker and restart application on re-enter of another application + if(returnVal == (int)EXIT_RELAUNCH_ON_LOAD) + { + break; + } + //! exit to homebrew launcher in all other cases + else + { + MAIN_ENTRY_ADDR = 0xDEADC0DE; + private_data.SYSRelaunchTitle(0, 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; } diff --git a/sd_loader/src/fs_defs.h b/sd_loader/src/fs_defs.h new file mode 100644 index 0000000..9edc5cb --- /dev/null +++ b/sd_loader/src/fs_defs.h @@ -0,0 +1,62 @@ +#ifndef FS_DEFS_H +#define FS_DEFS_H + +#include + +#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 */ + diff --git a/src/common/common.h b/src/common/common.h index 6bca5c2..dbbe02f 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -19,11 +19,15 @@ extern "C" { #define ELF_DATA_ADDR (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x00)) #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 OS_FIRMWARE (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x04)) #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)) #ifndef EXIT_SUCCESS diff --git a/src/fs/DirList.cpp b/src/fs/DirList.cpp index 5cbce8e..c37b504 100644 --- a/src/fs/DirList.cpp +++ b/src/fs/DirList.cpp @@ -42,9 +42,9 @@ DirList::DirList() 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(); } @@ -53,13 +53,13 @@ DirList::~DirList() 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; Flags = flags; Filter = filter; - Depth = depth; + Depth = maxDepth; std::string folderpath(folder); u32 length = folderpath.size(); @@ -78,7 +78,6 @@ bool DirList::LoadPath(const std::string & folder, const char *filter, u32 flags return InternalLoadPath(folderpath); } -#include "utils/logger.h" bool DirList::InternalLoadPath(std::string &folderpath) { if(folderpath.size() < 3) @@ -87,7 +86,6 @@ bool DirList::InternalLoadPath(std::string &folderpath) struct dirent *dirent = NULL; DIR *dir = NULL; - log_printf("open %s\n", folderpath.c_str()); dir = opendir(folderpath.c_str()); if (dir == NULL) return false; diff --git a/src/fs/DirList.h b/src/fs/DirList.h index b0f8c05..ea5c20c 100644 --- a/src/fs/DirList.h +++ b/src/fs/DirList.h @@ -45,11 +45,11 @@ public: //!\param path Path from where to load the filelist of all files //!\param filter A fileext that needs to be filtered //!\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 virtual ~DirList(); //! 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 //!\param list index const char * GetFilename(int index) const; diff --git a/src/gui/FreeTypeGX.cpp b/src/gui/FreeTypeGX.cpp index 3e89ef9..c35432d 100755 --- a/src/gui/FreeTypeGX.cpp +++ b/src/gui/FreeTypeGX.cpp @@ -28,7 +28,6 @@ using namespace std; #define ALIGN4(x) (((x) + 3) & ~3) -#include "utils/logger.h" /** * 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. */ -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) 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); 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; ++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 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 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 offsetTop = 2.0f * ((f32)y - 0.5f * (f32)texture->surface.height) * (f32)pVideo->getHeightScaleFactor(); + f32 offsetLeft = blurScale * ((f32)x + 0.5f * (f32)texture->surface.width) * (f32)pVideo->getWidthScaleFactor(); + f32 offsetTop = blurScale * ((f32)y - 0.5f * (f32)texture->surface.height) * (f32)pVideo->getHeightScaleFactor(); f32 widthScale = blurScale * (f32)texture->surface.width * pVideo->getWidthScaleFactor(); f32 heightScale = blurScale * (f32)texture->surface.height * pVideo->getHeightScaleFactor(); diff --git a/src/menu/HomebrewLaunchWindow.cpp b/src/menu/HomebrewLaunchWindow.cpp index 5dda83c..be22047 100644 --- a/src/menu/HomebrewLaunchWindow.cpp +++ b/src/menu/HomebrewLaunchWindow.cpp @@ -167,8 +167,6 @@ void HomebrewLaunchWindow::OnFileLoadFinish(GuiElement *element, const std::stri if(result > 0) { - ELF_DATA_ADDR = (u32)APP_BASE_MEM; - ELF_DATA_SIZE = result; Application::instance()->quit(EXIT_SUCCESS); } } @@ -179,7 +177,7 @@ void HomebrewLaunchWindow::OnLoadButtonClick(GuiButton *button, const GuiControl backBtn.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->effectFinished.connect(this, &HomebrewLaunchWindow::OnOpenEffectFinish); loader->asyncLoadFinished.connect(this, &HomebrewLaunchWindow::OnFileLoadFinish); diff --git a/src/menu/HomebrewMemory.cpp b/src/menu/HomebrewMemory.cpp index 7e6f429..4a4fafa 100644 --- a/src/menu/HomebrewMemory.cpp +++ b/src/menu/HomebrewMemory.cpp @@ -1,6 +1,7 @@ #include +#include +#include #include "common/common.h" -#include "dynamic_libs/os_functions.h" #include "system/memory_area_table.h" #include "utils/utils.h" #include "utils/logger.h" @@ -29,7 +30,7 @@ int HomebrewCopyMemory(u8 *address, u32 bytes) if(*(u16*)&address[7] != 0xCAFE) { // assume ELF - ELF_DATA_ADDR = getApplicationEndAddr(); + ELF_DATA_ADDR = (u32)APP_BASE_MEM; } else { diff --git a/src/menu/HomebrewWindow.cpp b/src/menu/HomebrewWindow.cpp index 50a9717..7601a68 100644 --- a/src/menu/HomebrewWindow.cpp +++ b/src/menu/HomebrewWindow.cpp @@ -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) , buttonLTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_L | GuiTrigger::BUTTON_LEFT, 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.serverReceiveFinished.connect(this, &HomebrewWindow::OnTcpReceiveFinish); @@ -52,7 +52,7 @@ HomebrewWindow::HomebrewWindow(int w, int h) currentLeftPosition = 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(); @@ -314,8 +314,6 @@ void HomebrewWindow::OnCloseTcpReceiverFinish(GuiElement *element) void HomebrewWindow::OnTcpReceiveStart(GuiElement *element, u32 ip) { - setState(STATE_DISABLED); - element->setEffect(EFFECT_FADE, 15, 255); element->effectFinished.connect(this, &HomebrewWindow::OnOpenEffectFinish); append(element); @@ -329,8 +327,7 @@ void HomebrewWindow::OnTcpReceiveFinish(GuiElement *element, u32 ip, int result) if(result > 0) { - ELF_DATA_ADDR = (u32)APP_BASE_MEM; - ELF_DATA_SIZE = result; + log_printf("Launching homebrew, loaded to address %08X size %08X\n", ELF_DATA_ADDR, ELF_DATA_SIZE); Application::instance()->quit(EXIT_SUCCESS); } } diff --git a/src/menu/TcpReceiver.cpp b/src/menu/TcpReceiver.cpp index e45946b..912a233 100644 --- a/src/menu/TcpReceiver.cpp +++ b/src/menu/TcpReceiver.cpp @@ -5,16 +5,16 @@ #include #include "TcpReceiver.h" +#include "HomebrewMemory.h" #include "fs/CFile.hpp" #include "utils/logger.h" #include "utils/StringTools.h" #include "utils/net.h" -TcpReceiver::TcpReceiver(unsigned char* loadAddr, int port) +TcpReceiver::TcpReceiver(int port) : GuiFrame(0, 0) , CThread(CThread::eAttributeAffCore0 | CThread::eAttributePinnedAff) , exitRequested(false) - , loadAddress(0) , serverPort(port) , serverSocket(-1) , progressWindow("Receiving file...") @@ -22,8 +22,6 @@ TcpReceiver::TcpReceiver(unsigned char* loadAddr, int port) width = progressWindow.getWidth(); height = progressWindow.getHeight(); append(&progressWindow); - - loadAddress = loadAddr; resumeThread(); } @@ -122,32 +120,30 @@ int TcpReceiver::loadToMemory(s32 clientSocket, u32 ipAddress) log_printf("transfer start\n"); - std::string strBuffer; - strBuffer.resize(0x1000); + unsigned char* loadAddress = (unsigned char*)memalign(0x40, fileSize); + if(!loadAddress) + { + progressWindow.setTitle("Not enough memory"); + sleep(1); + return NOT_ENOUGH_MEMORY; + } // Copy rpl in memory while(bytesRead < fileSize) { progressWindow.setProgress(100.0f * (f32)bytesRead / (f32)fileSize); - u32 blockSize = strBuffer.size(); + u32 blockSize = 0x1000; if(blockSize > (fileSize - bytesRead)) blockSize = fileSize - bytesRead; - if((u32)(loadAddress + bytesRead + blockSize) > 0x01000000) - { - log_printf("File ist too big\n"); - return NOT_ENOUGH_MEMORY; - } - - int ret = recv(clientSocket, &strBuffer[0], blockSize, 0); + int ret = recv(clientSocket, loadAddress + bytesRead, blockSize, 0); if(ret <= 0) { log_printf("Failure on reading file\n"); break; } - memcpy(loadAddress + bytesRead, &strBuffer[0], ret); bytesRead += ret; } @@ -155,13 +151,20 @@ int TcpReceiver::loadToMemory(s32 clientSocket, u32 ipAddress) if(bytesRead != fileSize) { + free(loadAddress); log_printf("File loading not finished, %i of %i bytes received\n", bytesRead, fileSize); + progressWindow.setTitle("Receive incomplete"); + sleep(1); return FILE_READ_ERROR; } + int res = -1; + // Do we need to unzip this thing? if (haxx[4] > 0 || haxx[5] > 4) { + unsigned char* inflatedData = NULL; + // We need to unzip... 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 // Section is compressed, inflate - std::string inflatedData; - inflatedData.resize(fileSizeUnc); + inflatedData = (unsigned char*)malloc(fileSizeUnc); + if(!inflatedData) + { + free(loadAddress); + progressWindow.setTitle("Not enough memory"); + sleep(1); + return NOT_ENOUGH_MEMORY; + } int ret = 0; z_stream s; @@ -182,7 +191,13 @@ int TcpReceiver::loadToMemory(s32 clientSocket, u32 ipAddress) ret = inflateInit(&s); if (ret != Z_OK) + { + free(loadAddress); + free(inflatedData); + progressWindow.setTitle("Uncompress failure"); + sleep(1); return FILE_READ_ERROR; + } s.avail_in = fileSize; s.next_in = (Bytef *)(&loadAddress[0]); @@ -192,34 +207,62 @@ int TcpReceiver::loadToMemory(s32 clientSocket, u32 ipAddress) ret = inflate(&s, Z_FINISH); if (ret != Z_OK && ret != Z_STREAM_END) + { + free(loadAddress); + free(inflatedData); + progressWindow.setTitle("Uncompress failure"); + sleep(1); return FILE_READ_ERROR; + } inflateEnd(&s); - - if(fileSizeUnc > (0x01000000 - (u32)loadAddress)) - return FILE_READ_ERROR; - - memcpy(loadAddress, &inflatedData[0], fileSizeUnc); fileSize = fileSizeUnc; } else { // Section is compressed, inflate - std::string inflatedData; - inflatedData.resize(fileSizeUnc); + inflatedData = (unsigned char*)malloc(fileSizeUnc); + if(!inflatedData) + { + free(loadAddress); + progressWindow.setTitle("Not enough memory"); + sleep(1); + return NOT_ENOUGH_MEMORY; + } uLongf f = fileSizeUnc; int result = uncompress((Bytef*)&inflatedData[0], &f, (Bytef*)loadAddress, fileSize); if(result != Z_OK) { log_printf("uncompress failed %i\n", result); + progressWindow.setTitle("Uncompress failure"); + sleep(1); return FILE_READ_ERROR; } fileSizeUnc = f; - memcpy(loadAddress, &inflatedData[0], 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; } diff --git a/src/menu/TcpReceiver.h b/src/menu/TcpReceiver.h index 8ab3649..a15567c 100644 --- a/src/menu/TcpReceiver.h +++ b/src/menu/TcpReceiver.h @@ -20,7 +20,7 @@ public: NOT_ENOUGH_MEMORY = -4, }; - TcpReceiver(unsigned char* loadAddr, int port); + TcpReceiver(int port); ~TcpReceiver(); sigslot::signal2 serverReceiveStart; diff --git a/src/sounds/Voice.h b/src/sounds/Voice.h index e499fc8..ceb4ad7 100644 --- a/src/sounds/Voice.h +++ b/src/sounds/Voice.h @@ -81,7 +81,7 @@ public: voiceBuffer.dataType = format; voiceBuffer.loopingEnabled = (nextBuffer == NULL) ? 0 : 1; voiceBuffer.currentOffset = 0; - voiceBuffer.endOffset = bufferSize >> 1; + voiceBuffer.endOffset = (bufferSize >> 1) - 1; voiceBuffer.loopOffset = ((nextBuffer - buffer) >> 1); nextBufferSize = nextBufSize; @@ -130,7 +130,7 @@ public: if(lastLoopCounter != loopCounter) { lastLoopCounter = loopCounter; - AXSetVoiceEndOffset(voice, voiceBuffer.loopOffset + (nextBufferSize >> 1)); + AXSetVoiceEndOffset(voice, voiceBuffer.loopOffset + (nextBufferSize >> 1) - 1); return true; } return false; diff --git a/src/system/memory_area_table.c b/src/system/memory_area_table.c index cc37fc3..76bcba8 100644 --- a/src/system/memory_area_table.c +++ b/src/system/memory_area_table.c @@ -16,7 +16,6 @@ ****************************************************************************/ #include #include -#include #include "common/common.h" #include "utils/utils.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 */ void memoryInitAreaTable() { - u32 ApplicationMemoryEnd = getApplicationEndAddr(); - if(ApplicationMemoryEnd >= 0x01000000) - ApplicationMemoryEnd = 0x00800000; + u32 ApplicationMemoryEnd = (u32)APP_BASE_MEM; // 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 diff --git a/src/utils/utils.h b/src/utils/utils.h index c460fa2..729e808 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -40,6 +40,8 @@ extern "C" { #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))) +void SC0x25_KernelCopyData(unsigned int addr, unsigned int src, unsigned int len); + #ifdef __cplusplus } #endif diff --git a/src/utils/utils_asm.S b/src/utils/utils_asm.S new file mode 100644 index 0000000..c92f838 --- /dev/null +++ b/src/utils/utils_asm.S @@ -0,0 +1,5 @@ + .globl SC0x25_KernelCopyData +SC0x25_KernelCopyData: + li r0, 0x2500 + sc + blr