diff --git a/Makefile.wiiu b/Makefile.wiiu
index 182d2ddd33..89f12510cc 100644
--- a/Makefile.wiiu
+++ b/Makefile.wiiu
@@ -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 :=
 
diff --git a/Makefile.wiiu.salamander b/Makefile.wiiu.salamander
new file mode 100644
index 0000000000..66e406752d
--- /dev/null
+++ b/Makefile.wiiu.salamander
@@ -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)
+
diff --git a/core_info.c b/core_info.c
index b178441a5e..65aaea596b 100644
--- a/core_info.c
+++ b/core_info.c
@@ -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';
diff --git a/frontend/drivers/platform_wiiu.c b/frontend/drivers/platform_wiiu.c
index 28b9aaff5d..6121164e8e 100644
--- a/frontend/drivers/platform_wiiu.c
+++ b/frontend/drivers/platform_wiiu.c
@@ -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);
 }
diff --git a/frontend/frontend_driver.c b/frontend/frontend_driver.c
index d99005b887..d32480d71e 100644
--- a/frontend/frontend_driver.c
+++ b/frontend/frontend_driver.c
@@ -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;
diff --git a/frontend/frontend_salamander.c b/frontend/frontend_salamander.c
index 5a9a13a20e..d07921f198 100644
--- a/frontend/frontend_salamander.c
+++ b/frontend/frontend_salamander.c
@@ -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;
diff --git a/wiiu/hbl.c b/wiiu/hbl.c
new file mode 100644
index 0000000000..685cd42318
--- /dev/null
+++ b/wiiu/hbl.c
@@ -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;
+}
diff --git a/wiiu/hbl.h b/wiiu/hbl.h
new file mode 100644
index 0000000000..89cba6d735
--- /dev/null
+++ b/wiiu/hbl.h
@@ -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__
diff --git a/wiiu/include/wiiu/fs.h b/wiiu/include/wiiu/fs.h
index 77dca33247..0878f30f4f 100644
--- a/wiiu/include/wiiu/fs.h
+++ b/wiiu/include/wiiu/fs.h
@@ -160,9 +160,6 @@ typedef struct FSMountSource
    uint32_t __unknown[0xC0];
 } FSMountSource;
 
-FSStatus fsDevInit();
-FSStatus fsDevExit();
-
 void FSInit();
 void FSShutdown();
 
diff --git a/wiiu/link_rpl.ld b/wiiu/link_rpl.ld
index f2e0ac4e1d..2deb7293ff 100644
--- a/wiiu/link_rpl.ld
+++ b/wiiu/link_rpl.ld
@@ -170,6 +170,9 @@ SECTIONS {
    } : hdr_data
    __bss_end__ = .;
 
+   _end = .;
+   PROVIDE(end = .);
+
    /* System stuff is for our elf2rpl converter to go through */
    . = ORIGIN(system);
 
diff --git a/wiiu/system/imports.h b/wiiu/system/imports.h
index b6f6a9d8b1..a2dfe9be99 100644
--- a/wiiu/system/imports.h
+++ b/wiiu/system/imports.h
@@ -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();
 
diff --git a/wiiu/system/stubs_elf.S b/wiiu/system/stubs_elf.S
index 2fb57eb6b1..6c6b40dd01 100644
--- a/wiiu/system/stubs_elf.S
+++ b/wiiu/system/stubs_elf.S
@@ -23,3 +23,9 @@
 
 #include "imports.h"
 
+.section ".text"
+.globl SC0x25_KernelCopyData
+SC0x25_KernelCopyData:
+li r0, 0x2500
+sc
+blr
diff --git a/wiiu/system/stubs_rpl.S b/wiiu/system/stubs_rpl.S
index 9dffaec458..6bd4ffdea9 100644
--- a/wiiu/system/stubs_rpl.S
+++ b/wiiu/system/stubs_rpl.S
@@ -51,3 +51,10 @@
    .long 3b
 
 #include "imports.h"
+
+.section ".text"
+.globl SC0x25_KernelCopyData
+SC0x25_KernelCopyData:
+li r0, 0x2500
+sc
+blr