Skip to content

Commit a441616

Browse files
committed
(WiiU) Core loading support
This commit re-adds core loading support, now compatible with Tiramisu and Aroma; using a libmocha feature added in those CFWs. Note that this does NOT work under Haxchi FW, non-payload Mocha versions, etc. RetroArch now requires either Tiramisu or Aroma on Wii U. The overall strategy is to make the path of the core to be loaded relative to the SD card root, pass this off to Mocha, then switch titles to the wrapper title (usually Health and Safety). In order to pass arguments, sysapp is used, with a little extra logic (since sysapp passes a blob of arbitrary bytes) to emulate argc/argv.
1 parent 90bca94 commit a441616

File tree

2 files changed

+240
-4
lines changed

2 files changed

+240
-4
lines changed

Makefile.wiiu

+4-1
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,14 @@ OBJ += wiiu/system/exception_handler.o
4141
OBJ += wiiu/system/missing_libc_functions.o
4242

4343
ifeq ($(SALAMANDER_BUILD),1)
44-
DEFINES += -DRARCH_CONSOLE -DIS_SALAMANDER
44+
DEFINES += -DRARCH_CONSOLE -DIS_SALAMANDER -DHAVE_LIBMOCHA
45+
46+
INCDIRS += -Ideps/libmocha/include
4547

4648
OBJ += frontend/frontend_salamander.o
4749
OBJ += frontend/frontend_driver.o
4850
OBJ += frontend/drivers/platform_wiiu.o
51+
OBJ += deps/libmocha/source/utils.o
4952
OBJ += libretro-common/encodings/encoding_utf.o
5053
OBJ += libretro-common/compat/compat_strcasestr.o
5154
OBJ += libretro-common/compat/fopen_utf8.o

frontend/drivers/platform_wiiu.c

+236-3
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,11 @@
8484
*/
8585

8686
#ifndef IS_SALAMANDER
87+
static enum frontend_fork wiiu_fork_mode = FRONTEND_FORK_NONE;
8788
static bool have_libfat_usb = false;
8889
static bool have_libfat_sdcard = false;
8990
#endif
91+
static bool in_exec = false;
9092

9193
static bool exists(char *path)
9294
{
@@ -226,18 +228,154 @@ static int frontend_wiiu_parse_drive_list(void *data, bool load_content)
226228
return 0;
227229
}
228230

231+
static void frontend_wiiu_exec(const char *path, bool should_load_content)
232+
{
233+
/* goal: make one big buffer with all the argv's, seperated by NUL. we can
234+
* then pass this thru sysapp! */
235+
char *argv_buf;
236+
size_t n, argv_len = strlen(path) + 1; /* argv[0] plus null */
237+
238+
#ifndef IS_SALAMANDER
239+
const char *content = path_get(RARCH_PATH_CONTENT);
240+
const char *content_args[2] = {content, NULL};
241+
#ifdef HAVE_NETWORKING
242+
const char *netplay_args[NETPLAY_FORK_MAX_ARGS];
243+
#endif
244+
#endif
245+
/* args will select between content_args, netplay_args, or no args (default) */
246+
const char **args = NULL;
247+
248+
/* and some other stuff (C89) */
249+
MochaRPXLoadInfo load_info = {0};
250+
MochaUtilsStatus ret;
251+
SYSStandardArgsIn std_args = {0};
252+
253+
#ifndef IS_SALAMANDER
254+
if (should_load_content)
255+
{
256+
#ifdef HAVE_NETWORKING
257+
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_GET_FORK_ARGS,
258+
(void *) netplay_args))
259+
{
260+
const char **cur_arg = netplay_args;
261+
262+
do
263+
argv_len += strnlen(*cur_arg, PATH_MAX_LENGTH) + 1;
264+
while (*(++cur_arg));
265+
266+
args = netplay_args;
267+
} else
268+
#endif
269+
if (!string_is_empty(content))
270+
{
271+
argv_len += strnlen(content, PATH_MAX_LENGTH) + 1;
272+
args = content_args;
273+
}
274+
}
275+
#endif
276+
277+
argv_buf = malloc(argv_len);
278+
argv_buf[0] = '\0';
279+
280+
n = strlcpy(argv_buf, path, argv_len);
281+
n++; /* leave room for the NUL */
282+
if (args)
283+
{
284+
const char **cur_arg = args;
285+
do
286+
{
287+
n += strlcpy(argv_buf + n, *cur_arg, argv_len - n);
288+
n++;
289+
} while (*(++cur_arg));
290+
}
291+
292+
if (string_starts_with(path, "fs:/vol/external01/"))
293+
path_relative_to(load_info.path, path, "fs:/vol/external01/", sizeof(load_info.path));
294+
else if (string_starts_with(path, "sd:/"))
295+
path_relative_to(load_info.path, path, "sd:/", sizeof(load_info.path));
296+
else goto cleanup; /* bail if not on the SD card */
297+
298+
/* Mocha might not be init'd (Salamander) */
299+
if (Mocha_InitLibrary() != MOCHA_RESULT_SUCCESS)
300+
goto cleanup;
301+
302+
load_info.target = LOAD_RPX_TARGET_SD_CARD;
303+
ret = Mocha_PrepareRPXLaunch(&load_info);
304+
if (ret != MOCHA_RESULT_SUCCESS)
305+
goto cleanup;
306+
307+
std_args.argString = argv_buf;
308+
std_args.size = argv_len;
309+
ret = Mocha_LaunchHomebrewWrapperEx(&std_args);
310+
if (ret != MOCHA_RESULT_SUCCESS)
311+
{
312+
MochaRPXLoadInfo load_info_revert;
313+
load_info_revert.target = LOAD_RPX_TARGET_EXTRA_REVERT_PREPARE;
314+
Mocha_PrepareRPXLaunch(&load_info_revert);
315+
goto cleanup;
316+
}
317+
318+
in_exec = true;
319+
320+
cleanup:
321+
free(argv_buf);
322+
argv_buf = NULL;
323+
}
324+
325+
static void frontend_wiiu_exitspawn(char *s, size_t len, char *args)
326+
{
327+
bool should_load_content = false;
328+
#ifndef IS_SALAMANDER
329+
if (wiiu_fork_mode == FRONTEND_FORK_NONE)
330+
return;
331+
332+
switch (wiiu_fork_mode)
333+
{
334+
case FRONTEND_FORK_CORE_WITH_ARGS:
335+
should_load_content = true;
336+
break;
337+
default:
338+
break;
339+
}
340+
#endif
341+
frontend_wiiu_exec(s, should_load_content);
342+
}
343+
344+
#ifndef IS_SALAMANDER
345+
static bool frontend_wiiu_set_fork(enum frontend_fork fork_mode)
346+
{
347+
switch (fork_mode)
348+
{
349+
case FRONTEND_FORK_CORE:
350+
case FRONTEND_FORK_CORE_WITH_ARGS:
351+
wiiu_fork_mode = fork_mode;
352+
break;
353+
case FRONTEND_FORK_RESTART:
354+
/* NOTE: We don't implement Salamander, so just turn
355+
* this into FRONTEND_FORK_CORE. */
356+
wiiu_fork_mode = FRONTEND_FORK_CORE;
357+
break;
358+
case FRONTEND_FORK_NONE:
359+
default:
360+
return false;
361+
}
362+
363+
return true;
364+
}
365+
#endif
366+
229367
frontend_ctx_driver_t frontend_ctx_wiiu =
230368
{
231369
frontend_wiiu_get_env_settings,
232370
frontend_wiiu_init,
233371
frontend_wiiu_deinit,
234-
NULL, /* exitspawn */
372+
frontend_wiiu_exitspawn,
235373
NULL, /* process_args */
236-
NULL, /* exec */
374+
frontend_wiiu_exec,
237375
#ifdef IS_SALAMANDER
238376
NULL, /* set_fork */
239377
#else
240-
NULL, /* set_fork */
378+
frontend_wiiu_set_fork,
241379
#endif
242380
frontend_wiiu_shutdown,
243381
NULL, /* get_name */
@@ -272,6 +410,7 @@ frontend_ctx_driver_t frontend_ctx_wiiu =
272410
/* main() and its supporting functions */
273411

274412
static void main_setup(void);
413+
static void get_arguments(int *argc, char ***argv);
275414
#ifndef IS_SALAMANDER
276415
static void main_loop(void);
277416
#endif
@@ -291,6 +430,7 @@ int main(int argc, char **argv)
291430
{
292431
proc_setup();
293432
main_setup();
433+
get_arguments(&argc, &argv);
294434

295435
#ifdef IS_SALAMANDER
296436
int salamander_main(int argc, char **argv);
@@ -328,9 +468,31 @@ static void main_teardown(void)
328468
memoryRelease();
329469
}
330470

471+
// https://github.com/devkitPro/wut/blob/7d9fa9e416bffbcd747f1a8e5701fd6342f9bc3d/libraries/libwhb/src/proc.c
472+
473+
#define HBL_TITLE_ID (0x0005000013374842)
474+
#define MII_MAKER_JPN_TITLE_ID (0x000500101004A000)
475+
#define MII_MAKER_USA_TITLE_ID (0x000500101004A100)
476+
#define MII_MAKER_EUR_TITLE_ID (0x000500101004A200)
477+
478+
static bool in_hbl = false;
331479
static bool in_aroma = false;
480+
332481
static void proc_setup(void)
333482
{
483+
uint64_t titleID = OSGetTitleID();
484+
485+
// Homebrew Launcher does not like the standard ProcUI application loop, sad!
486+
if (titleID == HBL_TITLE_ID ||
487+
titleID == MII_MAKER_JPN_TITLE_ID ||
488+
titleID == MII_MAKER_USA_TITLE_ID ||
489+
titleID == MII_MAKER_EUR_TITLE_ID)
490+
{
491+
// Important: OSEnableHomeButtonMenu must come before ProcUIInitEx.
492+
OSEnableHomeButtonMenu(FALSE);
493+
in_hbl = TRUE;
494+
}
495+
334496
/* Detect Aroma explicitly (it's possible to run under H&S while using Tiramisu) */
335497
OSDynLoad_Module rpxModule;
336498
if (OSDynLoad_Acquire("homebrew_rpx_loader", &rpxModule) == OS_DYNLOAD_OK)
@@ -344,6 +506,29 @@ static void proc_setup(void)
344506

345507
static void proc_exit(void)
346508
{
509+
/* If we're doing a normal exit while running under HBL, we must SYSRelaunchTitle.
510+
* If we're in an exec (i.e. launching mocha homebrew wrapper) we must *not* do that. yay! */
511+
if (in_hbl && !in_exec)
512+
SYSRelaunchTitle(0, NULL);
513+
514+
/* Similar deal for Aroma, but exit to menu. */
515+
if (!in_hbl && !in_exec)
516+
SYSLaunchMenu();
517+
518+
/* Now just tell the OS that we really are ok to exit */
519+
if (!ProcUIInShutdown())
520+
{
521+
for (;;)
522+
{
523+
ProcUIStatus status;
524+
status = ProcUIProcessMessages(TRUE);
525+
if (status == PROCUI_STATUS_EXITING)
526+
break;
527+
else if (status == PROCUI_STATUS_RELEASE_FOREGROUND)
528+
ProcUIDrawDoneRelease();
529+
}
530+
}
531+
347532
ProcUIShutdown();
348533
}
349534

@@ -352,6 +537,54 @@ static void proc_save_callback(void)
352537
OSSavesDone_ReadyToRelease();
353538
}
354539

540+
static void sysapp_arg_cb(SYSDeserializeArg *arg, void *usr)
541+
{
542+
SYSStandardArgs *std_args = (SYSStandardArgs *) usr;
543+
544+
if (_SYSDeserializeStandardArg(arg, std_args))
545+
return;
546+
547+
if (strcmp(arg->argName, "sys:pack") == 0)
548+
{
549+
// Recurse
550+
SYSDeserializeSysArgsFromBlock(arg->data, arg->size, sysapp_arg_cb, usr);
551+
return;
552+
}
553+
}
554+
555+
static void get_arguments(int *argc, char ***argv)
556+
{
557+
#ifdef HAVE_NETWORKING
558+
static char *_argv[1 + NETPLAY_FORK_MAX_ARGS];
559+
#else
560+
static char* _argv[2];
561+
#endif
562+
int _argc = 0;
563+
SYSStandardArgs std_args = {0};
564+
565+
/* we could do something more rich with the content path and things here -
566+
* but since there's not a great way to actually pass that info along to RA,
567+
* just emulate argc/argv */
568+
SYSDeserializeSysArgs(sysapp_arg_cb, &std_args);
569+
570+
char *argv_buf = std_args.anchorData;
571+
size_t argv_len = std_args.anchorSize;
572+
if (!argv_buf || argv_len == 0)
573+
return;
574+
575+
size_t n = 0;
576+
while (n < argv_len && _argc < ARRAY_SIZE(_argv))
577+
{
578+
char *s = argv_buf + n;
579+
_argv[_argc++] = s;
580+
n += strlen(s);
581+
n++; /* skip the null */
582+
}
583+
584+
*argc = _argc;
585+
*argv = _argv;
586+
}
587+
355588
#ifndef IS_SALAMANDER
356589
static bool swap_is_pending(void *start_time)
357590
{

0 commit comments

Comments
 (0)