(WiiU) implement the missing requirement for core loading: exec,

exitspawn, set_fork and salamander.
This commit is contained in:
aliaspider 2017-01-25 19:52:31 +01:00
parent 0ba9faa8bd
commit 8f88d8fb4d
13 changed files with 761 additions and 137 deletions

View File

@ -14,6 +14,7 @@ OBJ += wiiu/system/exception_handler.o
OBJ += wiiu/fs/sd_fat_devoptab.o
OBJ += wiiu/fs/fs_utils.o
OBJ += wiiu/tex_shader.o
OBJ += wiiu/hbl.o
DEFINES :=

176
Makefile.wiiu.salamander Normal file
View File

@ -0,0 +1,176 @@
TARGET := retroarch_wiiu_salamander
BUILD_HBL_ELF = 1
BUILD_RPX = 1
DEBUG = 0
PC_DEVELOPMENT_IP_ADDRESS =
PC_DEVELOPMENT_TCP_PORT =
OBJ :=
OBJ += wiiu/system/memory.o
OBJ += wiiu/system/exception_handler.o
OBJ += wiiu/fs/sd_fat_devoptab.o
OBJ += wiiu/fs/fs_utils.o
OBJ += wiiu/hbl.o
OBJ += frontend/frontend_salamander.o
OBJ += frontend/frontend_driver.o
OBJ += frontend/drivers/platform_wiiu.o
OBJ += frontend/drivers/platform_null.o
OBJ += libretro-common/compat/compat_strcasestr.o
OBJ += libretro-common/file/file_path.o
OBJ += libretro-common/string/stdstring.o
OBJ += libretro-common/lists/string_list.o
OBJ += libretro-common/lists/dir_list.o
OBJ += libretro-common/file/retro_dirent.o
OBJ += libretro-common/compat/compat_strl.o
OBJ += libretro-common/file/config_file.o
OBJ += libretro-common/streams/file_stream.o
OBJ += libretro-common/file/retro_stat.o
OBJ += libretro-common/hash/rhash.o
OBJ += file_path_str.o
OBJ += verbosity.o
ifeq ($(strip $(DEVKITPPC)),)
$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=<path to>devkitPPC")
endif
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>devkitPRO")
endif
export PATH := $(PATH):$(DEVKITPPC)/bin
PREFIX := powerpc-eabi-
CC := $(PREFIX)gcc
CXX := $(PREFIX)g++
AS := $(PREFIX)as
AR := $(PREFIX)ar
OBJCOPY := $(PREFIX)objcopy
STRIP := $(PREFIX)strip
NM := $(PREFIX)nm
LD := $(CXX)
ELF2RPL := wiiu/wut/elf2rpl/elf2rpl
ifneq ($(findstring Linux,$(shell uname -a)),)
else ifneq ($(findstring Darwin,$(shell uname -a)),)
else
ELF2RPL := $(ELF2RPL).exe
endif
INCDIRS := -I. -Ideps/zlib -Ideps/7zip -Ilibretro-common/include -Iwiiu -Iwiiu/include -I$(DEVKITPRO)/portlibs/ppc/include
LIBDIRS := -L. -L$(DEVKITPRO)/portlibs/ppc/lib
CFLAGS := -mwup -mcpu=750 -meabi -mhard-float
LDFLAGS :=
ifeq ($(DEBUG), 1)
CFLAGS += -O0 -g
else
CFLAGS += -O3
endif
LDFLAGS := $(CFLAGS)
ASFLAGS := $(CFLAGS) -mregnames
CFLAGS += -ffast-math -Werror=implicit-function-declaration
#CFLAGS += -fomit-frame-pointer -mword-relocations
#CFLAGS += -Wall
#todo: remove -DWIIU and use the built-in macros instead (HW_WUP or __wiiu__).
CFLAGS += -DWIIU -DMSB_FIRST
CFLAGS += -DHAVE_MAIN
CFLAGS += -DRARCH_CONSOLE -DIS_SALAMANDER
ifneq ($(PC_DEVELOPMENT_IP_ADDRESS),)
CFLAGS += -DPC_DEVELOPMENT_IP_ADDRESS='"$(PC_DEVELOPMENT_IP_ADDRESS)"'
endif
ifneq ($(PC_DEVELOPMENT_TCP_PORT),)
CFLAGS += -DPC_DEVELOPMENT_TCP_PORT=$(PC_DEVELOPMENT_TCP_PORT)
endif
ifeq ($(WHOLE_ARCHIVE_LINK), 1)
WHOLE_START := -Wl,--whole-archive
WHOLE_END := -Wl,--no-whole-archive
endif
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
LDFLAGS += -Wl,--gc-sections
LIBS := $(WHOLE_START) -lretro_wiiu $(WHOLE_END) -lm -lfat -liosuhax
RPX_OBJ = wiiu/system/stubs_rpl.o
HBL_ELF_OBJ = wiiu/system/dynamic.o wiiu/system/stubs_elf.o
RPX_LDFLAGS := -pie -fPIE
RPX_LDFLAGS += -z common-page-size=64 -z max-page-size=64
RPX_LDFLAGS += -T wiiu/link_rpl.ld
RPX_LDFLAGS += -nostartfiles
HBL_ELF_LDFLAGS := -T wiiu/link_elf.ld
TARGETS :=
ifeq ($(BUILD_RPX), 1)
TARGETS += $(TARGET).rpx
endif
ifeq ($(BUILD_HBL_ELF), 1)
TARGETS += $(TARGET).elf
endif
DEPFLAGS = -MT $@ -MMD -MP -MF $*.Tdepend
POSTCOMPILE = mv -f $*.Tdepend $*.depend
all: $(TARGETS)
%.o: %.cpp
%.o: %.cpp %.depend
$(CXX) -c -o $@ $< $(CXXFLAGS) $(INCDIRS) $(DEPFLAGS)
$(POSTCOMPILE)
%.o: %.c
%.o: %.c %.depend
$(CC) -c -o $@ $< $(CFLAGS) $(INCDIRS) $(DEPFLAGS)
$(POSTCOMPILE)
%.o: %.S
%.o: %.S %.depend
$(CC) -c -o $@ $< $(ASFLAGS) $(INCDIRS) $(DEPFLAGS)
$(POSTCOMPILE)
%.o: %.s
%.o: %.s %.depend
$(CC) -c -o $@ $< $(ASFLAGS) $(INCDIRS) $(DEPFLAGS)
$(POSTCOMPILE)
%.a:
$(AR) -rc $@ $^
%.depend: ;
$(ELF2RPL):
$(MAKE) -C wiiu/wut/elf2rpl/
$(TARGET).elf: $(OBJ) $(HBL_ELF_OBJ) libretro_wiiu.a wiiu/link_elf.ld
$(LD) $(OBJ) $(HBL_ELF_OBJ) $(LDFLAGS) $(HBL_ELF_LDFLAGS) $(LIBDIRS) $(LIBS) -o $@
$(TARGET).rpx.elf: $(OBJ) $(RPX_OBJ) libretro_wiiu.a wiiu/link_elf.ld
$(LD) $(OBJ) $(RPX_OBJ) $(LDFLAGS) $(RPX_LDFLAGS) $(LIBDIRS) $(LIBS) -o $@
$(TARGET).rpx: $(TARGET).rpx.elf $(ELF2RPL)
-$(ELF2RPL) $(TARGET).rpx.elf $@
clean:
rm -f $(OBJ) $(RPX_OBJ) $(HBL_ELF_OBJ) $(TARGET).elf $(TARGET).rpx.elf $(TARGET).rpx
rm -f $(OBJ:.o=.depend) $(RPX_OBJ:.o=.depend) $(HBL_ELF_OBJ:.o=.depend)
.PHONY: clean all
.PRECIOUS: %.depend
-include $(OBJ:.o=.depend) $(RPX_OBJ:.o=.depend) $(HBL_ELF_OBJ:.o=.depend)

View File

@ -198,7 +198,7 @@ static bool core_info_list_iterate(
fill_pathname_base_noext(info_path_base, contents->elems[i].data,
sizeof(info_path_base));
#if defined(RARCH_MOBILE) || (defined(RARCH_CONSOLE) && !defined(PSP) && !defined(_3DS) && !defined(VITA))
#if defined(RARCH_MOBILE) || (defined(RARCH_CONSOLE) && !defined(PSP) && !defined(_3DS) && !defined(VITA) && !defined(HW_WUP))
substr = strrchr(info_path_base, '_');
if (substr)
*substr = '\0';

View File

@ -22,7 +22,9 @@
#include <file/file_path.h>
#ifndef IS_SALAMANDER
#include <lists/file_list.h>
#endif
#include "../frontend_driver.h"
#include "../frontend.h"
@ -56,17 +58,20 @@
#include <iosuhax.h>
#include "wiiu_dbg.h"
#include "hbl.h"
#ifndef IS_SALAMANDER
#ifdef HAVE_MENU
#include "../../menu/menu_driver.h"
#endif
#endif
//#define WIIU_SD_PATH "/vol/external01/"
#define WIIU_SD_PATH "sd:/"
#define WIIU_USB_PATH "usb:/"
static enum frontend_fork wiiu_fork_mode = FRONTEND_FORK_NONE;
static const char* elf_path_cst = WIIU_SD_PATH "retroarch/retroarch.elf";
static const char *elf_path_cst = WIIU_SD_PATH "retroarch/retroarch.elf";
static void frontend_wiiu_get_environment_settings(int *argc, char *argv[],
void *args, void *params_data)
@ -139,7 +144,8 @@ enum frontend_architecture frontend_wiiu_get_architecture(void)
static int frontend_wiiu_parse_drive_list(void *data)
{
file_list_t *list = (file_list_t*)data;
#ifndef IS_SALAMANDER
file_list_t *list = (file_list_t *)data;
if (!list)
return -1;
@ -153,18 +159,125 @@ static int frontend_wiiu_parse_drive_list(void *data)
msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR,
MENU_SETTING_ACTION, 0, 0);
#endif
return 0;
}
frontend_ctx_driver_t frontend_ctx_wiiu = {
static void frontend_wiiu_exec(const char *path, bool should_load_game)
{
struct
{
u32 magic;
u32 argc;
char * argv[3];
char args[];
}*param = getApplicationEndAddr();
int len = 0;
param->argc = 0;
if(!path || !*path)
{
RARCH_LOG("No executable path provided, cannot Restart\n");
}
DEBUG_STR(path);
strcpy(param->args + len, elf_path_cst);
param->argv[param->argc] = param->args + len;
len += strlen(param->args + len) + 1;
param->argc++;
RARCH_LOG("Attempt to load core: [%s].\n", path);
#ifndef IS_SALAMANDER
if (should_load_game && !path_is_empty(RARCH_PATH_CONTENT))
{
strcpy(param->args + len, path_get(RARCH_PATH_CONTENT));
param->argv[param->argc] = param->args + len;
len += strlen(param->args + len) + 1;
param->argc++;
RARCH_LOG("content path: [%s].\n", path_get(RARCH_PATH_CONTENT));
}
#endif
param->argv[param->argc] = NULL;
{
if (HBL_loadToMemory(path, (u32)param->args - (u32)param + len) < 0)
RARCH_LOG("Failed to load core\n");
else
{
param->magic = ARGV_MAGIC;
ARGV_PTR = param;
DEBUG_VAR(param->argc);
DEBUG_VAR(param->argv);
}
}
}
#ifndef IS_SALAMANDER
static bool frontend_wiiu_set_fork(enum frontend_fork fork_mode)
{
switch (fork_mode)
{
case FRONTEND_FORK_CORE:
RARCH_LOG("FRONTEND_FORK_CORE\n");
wiiu_fork_mode = fork_mode;
break;
case FRONTEND_FORK_CORE_WITH_ARGS:
RARCH_LOG("FRONTEND_FORK_CORE_WITH_ARGS\n");
wiiu_fork_mode = fork_mode;
break;
case FRONTEND_FORK_RESTART:
RARCH_LOG("FRONTEND_FORK_RESTART\n");
/* NOTE: We don't implement Salamander, so just turn
* this into FRONTEND_FORK_CORE. */
wiiu_fork_mode = FRONTEND_FORK_CORE;
break;
case FRONTEND_FORK_NONE:
default:
return false;
}
return true;
}
#endif
static void frontend_wiiu_exitspawn(char *s, size_t len)
{
bool should_load_game = false;
#ifndef IS_SALAMANDER
if (wiiu_fork_mode == FRONTEND_FORK_NONE)
return;
switch (wiiu_fork_mode)
{
case FRONTEND_FORK_CORE_WITH_ARGS:
should_load_game = true;
break;
default:
break;
}
#endif
frontend_wiiu_exec(s, should_load_game);
}
frontend_ctx_driver_t frontend_ctx_wiiu =
{
frontend_wiiu_get_environment_settings,
frontend_wiiu_init,
frontend_wiiu_deinit,
NULL, /* exitspawn */
frontend_wiiu_exitspawn,
NULL, /* process_args */
NULL, /* exec */
frontend_wiiu_exec,
#ifdef IS_SALAMANDER
NULL, /* set_fork */
#else
frontend_wiiu_set_fork,
#endif
frontend_wiiu_shutdown,
NULL, /* get_name */
NULL, /* get_os */
@ -187,68 +300,74 @@ frontend_ctx_driver_t frontend_ctx_wiiu = {
static int log_socket = -1;
static volatile int log_lock = 0;
void log_init(const char * ipString, int port)
void log_init(const char *ipString, int port)
{
log_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (log_socket < 0)
return;
log_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in connect_addr;
memset(&connect_addr, 0, sizeof(connect_addr));
connect_addr.sin_family = AF_INET;
connect_addr.sin_port = port;
inet_aton(ipString, &connect_addr.sin_addr);
if (log_socket < 0)
return;
if(connect(log_socket, (struct sockaddr*)&connect_addr, sizeof(connect_addr)) < 0)
{
socketclose(log_socket);
log_socket = -1;
}
struct sockaddr_in connect_addr;
memset(&connect_addr, 0, sizeof(connect_addr));
connect_addr.sin_family = AF_INET;
connect_addr.sin_port = port;
inet_aton(ipString, &connect_addr.sin_addr);
if (connect(log_socket, (struct sockaddr *)&connect_addr, sizeof(connect_addr)) < 0)
{
socketclose(log_socket);
log_socket = -1;
}
}
void log_deinit(void)
{
if(log_socket >= 0)
{
socketclose(log_socket);
log_socket = -1;
}
if (log_socket >= 0)
{
socketclose(log_socket);
log_socket = -1;
}
}
static ssize_t log_write(struct _reent *r, void* fd, const char *ptr, size_t len)
static ssize_t log_write(struct _reent *r, void *fd, const char *ptr, size_t len)
{
if(log_socket < 0)
return len;
if (log_socket < 0)
return len;
while (log_lock)
OSSleepTicks(((248625000 / 4)) / 1000);
while(log_lock)
OSSleepTicks(((248625000/4)) / 1000);
log_lock = 1;
int ret;
while (len > 0) {
int block = len < 1400 ? len : 1400; // take max 1400 bytes per UDP packet
ret = send(log_socket, ptr, block, 0);
if(ret < 0)
break;
len -= ret;
ptr += ret;
while (len > 0)
{
int block = len < 1400 ? len : 1400; // take max 1400 bytes per UDP packet
ret = send(log_socket, ptr, block, 0);
if (ret < 0)
break;
len -= ret;
ptr += ret;
}
log_lock = 0;
return len;
}
void net_print(const char* str)
void net_print(const char *str)
{
log_write(NULL, 0, str, strlen(str));
}
void net_print_exp(const char* str)
void net_print_exp(const char *str)
{
send(log_socket, str, strlen(str), 0);
}
static devoptab_t dotab_stdout = {
static devoptab_t dotab_stdout =
{
"stdout_net", // device name
0, // size of file structure
NULL, // device open
@ -264,13 +383,12 @@ void SaveCallback()
}
int main(int argc, char **argv)
{
{
#if 1
setup_os_exceptions();
#else
InstallExceptionHandler();
#endif
ProcUIInit(&SaveCallback);
socket_lib_init();
@ -279,22 +397,46 @@ int main(int argc, char **argv)
devoptab_list[STD_OUT] = &dotab_stdout;
devoptab_list[STD_ERR] = &dotab_stdout;
#endif
#ifndef IS_SALAMANDER
VPADInit();
WPADEnableURCC(true);
WPADEnableWiiRemote(true);
KPADInit();
#endif
verbosity_enable();
printf("starting\n");
fflush(stdout);
DEBUG_VAR(ARGV_PTR);
if(ARGV_PTR && ((u32)ARGV_PTR < 0x01000000))
{
struct
{
u32 magic;
u32 argc;
char * argv[3];
}*param = ARGV_PTR;
if(param->magic == ARGV_MAGIC)
{
argc = param->argc;
argv = param->argv;
}
ARGV_PTR = NULL;
}
DEBUG_VAR(argc);
DEBUG_STR(argv[0]);
DEBUG_STR(argv[1]);
fflush(stdout);
#ifdef IS_SALAMANDER
int salamander_main(int, char **);
salamander_main(argc, argv);
#else
#if 1
#if 0
int argc_ = 2;
// char* argv_[] = {WIIU_SD_PATH "retroarch/retroarch.elf", WIIU_SD_PATH "rom.nes", NULL};
char* argv_[] = {WIIU_SD_PATH "retroarch/retroarch.elf", WIIU_SD_PATH "rom.sfc", NULL};
char *argv_[] = {WIIU_SD_PATH "retroarch/retroarch.elf", WIIU_SD_PATH "rom.sfc", NULL};
rarch_main(argc_, argv_, NULL);
#else
@ -306,14 +448,18 @@ int main(int argc, char **argv)
int ret = runloop_iterate(&sleep_ms);
if (ret == 1 && sleep_ms > 0)
retro_sleep(sleep_ms);
task_queue_ctl(TASK_QUEUE_CTL_WAIT, NULL);
if (ret == -1)
break;
retro_sleep(sleep_ms);
}while(1);
task_queue_ctl(TASK_QUEUE_CTL_WAIT, NULL);
if (ret == -1)
break;
}
while (1);
main_exit(NULL);
#endif
#endif
fflush(stdout);
fflush(stderr);
@ -322,6 +468,8 @@ int main(int argc, char **argv)
#if defined(PC_DEVELOPMENT_IP_ADDRESS) && defined(PC_DEVELOPMENT_TCP_PORT)
log_deinit();
#endif
/* returning non 0 here can prevent loading a different rpx/elf in the HBL environment */
return 0;
}
@ -340,7 +488,8 @@ void __init(void)
{
extern void(*__CTOR_LIST__[])(void);
void(**ctor)(void) = __CTOR_LIST__;
while(*ctor)
while (*ctor)
(*ctor++)();
}
@ -350,7 +499,8 @@ void __fini(void)
{
extern void(*__DTOR_LIST__[])(void);
void(**ctor)(void) = __DTOR_LIST__;
while(*ctor)
while (*ctor)
(*ctor++)();
}
@ -359,38 +509,80 @@ void __fini(void)
//just to be able to call async
void someFunc(void *arg)
{
(void)arg;
(void)arg;
}
static int mcp_hook_fd = -1;
int MCPHookOpen()
{
//take over mcp thread
mcp_hook_fd = IOS_Open("/dev/mcp", 0);
if(mcp_hook_fd < 0)
return -1;
IOS_IoctlAsync(mcp_hook_fd, 0x62, (void*)0, 0, (void*)0, 0, someFunc, (void*)0);
//let wupserver start up
retro_sleep(1000);
if(IOSUHAX_Open("/dev/mcp") < 0)
{
IOS_Close(mcp_hook_fd);
mcp_hook_fd = -1;
return -1;
}
return 0;
//take over mcp thread
mcp_hook_fd = IOS_Open("/dev/mcp", 0);
if (mcp_hook_fd < 0)
return -1;
IOS_IoctlAsync(mcp_hook_fd, 0x62, (void *)0, 0, (void *)0, 0, someFunc, (void *)0);
//let wupserver start up
retro_sleep(1000);
if (IOSUHAX_Open("/dev/mcp") < 0)
{
IOS_Close(mcp_hook_fd);
mcp_hook_fd = -1;
return -1;
}
return 0;
}
void MCPHookClose()
{
if(mcp_hook_fd < 0)
return;
//close down wupserver, return control to mcp
IOSUHAX_Close();
//wait for mcp to return
retro_sleep(1000);
IOS_Close(mcp_hook_fd);
mcp_hook_fd = -1;
if (mcp_hook_fd < 0)
return;
//close down wupserver, return control to mcp
IOSUHAX_Close();
//wait for mcp to return
retro_sleep(1000);
IOS_Close(mcp_hook_fd);
mcp_hook_fd = -1;
}
static int iosuhaxMount = 0;
static void fsdev_init(void)
{
iosuhaxMount = 0;
int res = IOSUHAX_Open(NULL);
if (res < 0)
res = MCPHookOpen();
if (res < 0)
mount_sd_fat("sd");
else
{
iosuhaxMount = 1;
fatInitDefault();
}
}
static void fsdev_exit(void)
{
if (iosuhaxMount)
{
fatUnmount("sd:");
fatUnmount("usb:");
if (mcp_hook_fd >= 0)
MCPHookClose();
else
IOSUHAX_Close();
}
else
unmount_sd_fat("sd");
}
/* HBL elf entry point */
@ -398,76 +590,29 @@ int __entry_menu(int argc, char **argv)
{
InitFunctionPointers();
memoryInitialize();
int iosuhaxMount = 0;
int res = IOSUHAX_Open(NULL);
if(res < 0)
res = MCPHookOpen();
if(res < 0)
mount_sd_fat("sd");
else
{
iosuhaxMount = 1;
fatInitDefault();
}
fsdev_init();
__init();
int ret = main(argc, argv);
__fini();
if(iosuhaxMount)
{
fatUnmount("sd:");
fatUnmount("usb:");
if(mcp_hook_fd >= 0)
MCPHookClose();
else
IOSUHAX_Close();
}
else
unmount_sd_fat("sd");
fsdev_exit();
memoryRelease();
return ret;
}
/* RPX entry point */
__attribute__((noreturn))
void _start(int argc, char **argv)
{
memoryInitialize();
int iosuhaxMount = 0;
int res = IOSUHAX_Open(NULL);
if(res < 0)
res = MCPHookOpen();
if(res < 0)
mount_sd_fat("sd");
else
{
iosuhaxMount = 1;
fatInitDefault();
}
fsdev_init();
__init();
int ret = main(argc, argv);
__fini();
if(iosuhaxMount)
{
fatUnmount("sd:");
fatUnmount("usb:");
if(mcp_hook_fd >= 0)
MCPHookClose();
else
IOSUHAX_Close();
}
else
unmount_sd_fat("sd");
fsdev_exit();
memoryRelease();
SYSRelaunchTitle(argc, argv);
exit(ret);
SYSRelaunchTitle(0, 0);
exit(0);
}

View File

@ -152,6 +152,9 @@ bool frontend_driver_get_core_extension(char *s, size_t len)
#elif defined(GEKKO)
strlcpy(s, "dol", len);
return true;
#elif defined(HW_WUP)
strlcpy(s, "rpx|elf", len);
return true;
#elif defined(__linux__)
strlcpy(s, "elf", len);
return true;

View File

@ -167,8 +167,11 @@ static void salamander_init(char *s, size_t len)
}
}
}
#ifdef HAVE_MAIN
int salamander_main(int argc, char *argv[])
#else
int main(int argc, char *argv[])
#endif
{
char libretro_path[PATH_MAX_LENGTH] = {0};
void *args = NULL;

256
wiiu/hbl.c Normal file
View File

@ -0,0 +1,256 @@
/* 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;
}

25
wiiu/hbl.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef __WIIU_HBL_LOADER_H__
#define __WIIU_HBL_LOADER_H__
#ifdef __cplusplus
extern "C" {
#endif
#ifndef MEM_BASE
#define MEM_BASE (0x00800000)
#endif
#define ARGV_PTR (*(void* volatile *)(MEM_BASE + 0x1300 + 0x80))
#define MAKE_MAGIC(c0, c1, c2, c3) (((c0) << 24) |((c1) << 16) |((c2) << 8) | c3)
#define ARGV_MAGIC MAKE_MAGIC('_', 'a', 'r', 'g')
int HBL_loadToMemory(const char *filepath, u32 args_size);
void* getApplicationEndAddr(void);
#ifdef __cplusplus
}
#endif
#endif // __WIIU_HBL_LOADER_H__

View File

@ -160,9 +160,6 @@ typedef struct FSMountSource
uint32_t __unknown[0xC0];
} FSMountSource;
FSStatus fsDevInit();
FSStatus fsDevExit();
void FSInit();
void FSShutdown();

View File

@ -170,6 +170,9 @@ SECTIONS {
} : hdr_data
__bss_end__ = .;
_end = .;
PROVIDE(end = .);
/* System stuff is for our elf2rpl converter to go through */
. = ORIGIN(system);

View File

@ -24,6 +24,7 @@ IMPORT(OSYieldThread);
IMPORT(OSGetSystemTime);
IMPORT(OSGetSystemTick);
IMPORT(OSGetSymbolName);
IMPORT(OSEffectiveToPhysical);
IMPORT(exit);
IMPORT(_Exit);
@ -168,6 +169,7 @@ IMPORT_END();
IMPORT_BEGIN(sysapp);
IMPORT(SYSRelaunchTitle);
IMPORT(SYSLaunchMenu);
IMPORT_END();

View File

@ -23,3 +23,9 @@
#include "imports.h"
.section ".text"
.globl SC0x25_KernelCopyData
SC0x25_KernelCopyData:
li r0, 0x2500
sc
blr

View File

@ -51,3 +51,10 @@
.long 3b
#include "imports.h"
.section ".text"
.globl SC0x25_KernelCopyData
SC0x25_KernelCopyData:
li r0, 0x2500
sc
blr