mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-30 11:40:32 +00:00
8f88d8fb4d
exitspawn, set_fork and salamander.
257 lines
6.6 KiB
C
257 lines
6.6 KiB
C
/* adapted from https://github.com/dimok789/homebrew_launcher */
|
|
|
|
/****************************************************************************
|
|
*
|
|
* Copyright (C) 2015 Dimok
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
****************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <malloc.h>
|
|
#include <string.h>
|
|
#include <wiiu/os.h>
|
|
|
|
#include "hbl.h"
|
|
|
|
#define MEM_AREA_TABLE ((s_mem_area*)(MEM_BASE + 0x1600))
|
|
#define ELF_DATA_ADDR (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x00))
|
|
#define ELF_DATA_SIZE (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x04))
|
|
#define RPX_MAX_SIZE (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x0C))
|
|
#define RPX_MAX_CODE_SIZE (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x10))
|
|
#define APP_BASE_MEM ((unsigned char*)(MEM_BASE + 0x2000))
|
|
|
|
typedef struct _s_mem_area
|
|
{
|
|
unsigned int address;
|
|
unsigned int size;
|
|
struct _s_mem_area *next;
|
|
} s_mem_area;
|
|
|
|
void SC0x25_KernelCopyData(unsigned int addr, unsigned int src, unsigned int len);
|
|
|
|
typedef struct _memory_values_t
|
|
{
|
|
unsigned int start_address;
|
|
unsigned int end_address;
|
|
} memory_values_t;
|
|
|
|
static const memory_values_t mem_vals_540[] =
|
|
{
|
|
{ 0x2E609EFC, 0x2FF82000 }, // 26083 kB
|
|
{ 0x29030800, 0x293F6000 }, // 3864 kB
|
|
{ 0x288EEC30, 0x28B06800 }, // 2144 kB
|
|
{ 0x2D3B966C, 0x2D894000 }, // 4971 kB
|
|
{ 0x2CB56370, 0x2D1EF000 }, // 6756 kB
|
|
{ 0x2D8AD3D8, 0x2E000000 }, // 7499 kB
|
|
{ 0x2970200C, 0x298B9800 }, // 1759 kB
|
|
{ 0x2A057B68, 0x2A1B9000 }, // 1414 kB
|
|
{ 0x2ABBCC4C, 0x2ACB9000 }, // 1010 kB
|
|
{0, 0}
|
|
};
|
|
|
|
static inline void memoryAddArea(int start, int end, int cur_index)
|
|
{
|
|
// Create and copy new memory area
|
|
s_mem_area * mem_area = MEM_AREA_TABLE;
|
|
mem_area[cur_index].address = start;
|
|
mem_area[cur_index].size = end - start;
|
|
mem_area[cur_index].next = 0;
|
|
|
|
// Fill pointer to this area in the previous area
|
|
if (cur_index > 0)
|
|
{
|
|
mem_area[cur_index - 1].next = &mem_area[cur_index];
|
|
}
|
|
}
|
|
void *getApplicationEndAddr(void)
|
|
{
|
|
extern u32 _end[];
|
|
if((u32)_end >= 0x01000000)
|
|
return APP_BASE_MEM;
|
|
return _end;
|
|
}
|
|
|
|
/* Create memory areas arrays */
|
|
static void memoryInitAreaTable(u32 args_size)
|
|
{
|
|
u32 ApplicationMemoryEnd = (u32)getApplicationEndAddr() + args_size;
|
|
|
|
// 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
|
|
memoryAddArea(ApplicationMemoryEnd + 0x30000000, 0x30000000 + 0x01E20000, 0);
|
|
|
|
const memory_values_t * mem_vals = mem_vals_540;
|
|
|
|
// Fill entries
|
|
int i = 0;
|
|
while (mem_vals[i].start_address)
|
|
{
|
|
memoryAddArea(mem_vals[i].start_address, mem_vals[i].end_address, i + 1);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
static int HomebrewCopyMemory(u8 *address, u32 bytes, u32 args_size)
|
|
{
|
|
args_size += 0x7;
|
|
args_size &= ~0x7;
|
|
if (args_size > 0x10000)
|
|
args_size = 0x10000;
|
|
|
|
memoryInitAreaTable(args_size);
|
|
|
|
RPX_MAX_SIZE = 0x40000000;
|
|
RPX_MAX_CODE_SIZE = 0x03000000;
|
|
|
|
// check if we load an RPX or an ELF
|
|
if (*(u16 *)&address[7] != 0xCAFE)
|
|
{
|
|
// assume ELF
|
|
printf("loading ELF file \n");
|
|
|
|
ELF_DATA_ADDR = (u32)getApplicationEndAddr() + args_size;
|
|
if (ELF_DATA_ADDR >= 0x01000000)
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
// RPX
|
|
printf("loading RPX file \n");
|
|
|
|
ELF_DATA_ADDR = MEM_AREA_TABLE->address;
|
|
}
|
|
|
|
//! if we load an ELF file
|
|
if (ELF_DATA_ADDR < 0x01000000)
|
|
{
|
|
|
|
if ((ELF_DATA_ADDR + bytes) > 0x01000000)
|
|
return -1;
|
|
|
|
memcpy((void *)ELF_DATA_ADDR, address, bytes);
|
|
ELF_DATA_SIZE = bytes;
|
|
}
|
|
else
|
|
{
|
|
DCFlushRange(address, bytes);
|
|
|
|
u32 done = 0;
|
|
u32 addressPhysical = (u32)OSEffectiveToPhysical(address);
|
|
|
|
s_mem_area *mem_map = MEM_AREA_TABLE;
|
|
u32 mapPosition = 0;
|
|
|
|
while ((done < bytes) && mem_map)
|
|
{
|
|
if (mapPosition >= mem_map->size)
|
|
{
|
|
mem_map = mem_map->next;
|
|
|
|
if (!mem_map)
|
|
return -1;
|
|
|
|
mapPosition = 0;
|
|
}
|
|
|
|
u32 blockSize = bytes - done;
|
|
|
|
if ((mapPosition + blockSize) > mem_map->size)
|
|
blockSize = mem_map->size - mapPosition;
|
|
|
|
SC0x25_KernelCopyData(mem_map->address + mapPosition, (addressPhysical + done), blockSize);
|
|
|
|
mapPosition += blockSize;
|
|
done += blockSize;
|
|
}
|
|
|
|
ELF_DATA_SIZE = done;
|
|
}
|
|
return bytes;
|
|
}
|
|
|
|
int HBL_loadToMemory(const char *filepath, u32 args_size)
|
|
{
|
|
if (!filepath || !*filepath)
|
|
return -1;
|
|
|
|
printf("Loading file %s\n", filepath);
|
|
|
|
FILE *fp = fopen(filepath, "rb");
|
|
|
|
if (!fp)
|
|
{
|
|
printf("failed to open file %s\n", filepath);
|
|
return -1;
|
|
}
|
|
|
|
u32 bytesRead = 0;
|
|
fseek(fp, 0, SEEK_END);
|
|
u32 fileSize = ftell(fp);
|
|
fseek(fp, 0, SEEK_SET);
|
|
|
|
|
|
unsigned char *buffer = (unsigned char *) memalign(0x40, (fileSize + 0x3F) & ~0x3F);
|
|
|
|
if (!buffer)
|
|
{
|
|
printf("Not enough memory\n");
|
|
return -1;
|
|
}
|
|
|
|
// Copy rpl in memory
|
|
while (bytesRead < fileSize)
|
|
{
|
|
printf("progress: %f \r", 100.0f * (f32)bytesRead / (f32)fileSize);
|
|
|
|
u32 blockSize = 0x8000;
|
|
|
|
if (blockSize > (fileSize - bytesRead))
|
|
blockSize = fileSize - bytesRead;
|
|
|
|
int ret = fread(buffer + bytesRead, 1, blockSize, fp);
|
|
|
|
if (ret <= 0)
|
|
{
|
|
printf("Failure on reading file %s\n", filepath);
|
|
break;
|
|
}
|
|
|
|
bytesRead += ret;
|
|
}
|
|
|
|
printf("progress: %f \n", 100.0f * (f32)bytesRead / (f32)fileSize);
|
|
|
|
if (bytesRead != fileSize)
|
|
{
|
|
free(buffer);
|
|
printf("File loading not finished for file %s, finished %i of %i bytes\n", filepath, bytesRead,
|
|
fileSize);
|
|
printf("File read failure");
|
|
return -1;
|
|
}
|
|
|
|
int ret = HomebrewCopyMemory(buffer, bytesRead, args_size);
|
|
|
|
free(buffer);
|
|
|
|
if (ret < 0)
|
|
{
|
|
printf("Not enough memory");
|
|
return -1;
|
|
}
|
|
|
|
return fileSize;
|
|
}
|