mirror of
https://github.com/kamb205/KB-RPCS3.git
synced 2026-10-17 21:00:50 +02:00
120 lines
3.6 KiB
C
120 lines
3.6 KiB
C
/*
|
|
* RPCS3 PS5 game tile launcher: the eboot of each PS3 game's own tile on the PS5 home screen.
|
|
* Reads the game to boot from /app0/rpcs3-launch.txt (a path under RPCS3's data folder, as the RPCS3 PS5
|
|
* library lists it) and has RPCS3 PS5 (PPSA99303) started with it.
|
|
* A title may not start another title (only a system process may: SceLncService refuses with 0x8094000f),
|
|
* so the tile sends the one-shot payload rpcs3ps5-launch.elf (tools/launcher/launch.c; its copy is in the
|
|
* tile) to the ELF loader, with "<user>|<path>" written after the marker in its request buffer, and ends.
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
#include <arpa/inet.h>
|
|
#include <netinet/in.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/socket.h>
|
|
#include <unistd.h>
|
|
|
|
#define LOADER_PORT 9021
|
|
#define MARKER "RPCS3PS5-LAUNCH-REQUEST:"
|
|
|
|
int sceUserServiceInitialize(void *params);
|
|
int sceUserServiceGetForegroundUser(int32_t *user_id);
|
|
int sceKernelDebugOutText(int channel, const char *text);
|
|
int sceSystemServiceLoadExec(const char *path, const char *const *argv);
|
|
int sceKernelUsleep(unsigned int microseconds);
|
|
|
|
// A title ends by asking the shell to close it: exit() is refused (SIGSYS) and reported as a crash
|
|
// ("something went wrong"). The CRT calls this after main returns.
|
|
void catchReturnFromMain(int status)
|
|
{
|
|
(void)status;
|
|
sceSystemServiceLoadExec("exit", NULL);
|
|
for (;;)
|
|
sceKernelUsleep(100000);
|
|
}
|
|
|
|
static void say(const char *text)
|
|
{
|
|
char line[900];
|
|
snprintf(line, sizeof(line), "[RPCS3 tile] %s\n", text);
|
|
sceKernelDebugOutText(0, line);
|
|
}
|
|
|
|
static int send_all(int s, const void *data, size_t size)
|
|
{
|
|
const char *p = data;
|
|
while (size) {
|
|
const ssize_t n = send(s, p, size, 0);
|
|
if (n <= 0)
|
|
return -1;
|
|
p += n;
|
|
size -= (size_t)n;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// The launch payload, with the request written in, to the ELF loader
|
|
static int send_launch(const char *request)
|
|
{
|
|
FILE *f = fopen("/app0/rpcs3ps5-launch.elf", "rb");
|
|
if (!f)
|
|
return -1;
|
|
fseek(f, 0, SEEK_END);
|
|
const long size = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
char *elf = malloc((size_t)size);
|
|
const int ok = elf && fread(elf, 1, (size_t)size, f) == (size_t)size;
|
|
fclose(f);
|
|
char *slot = NULL;
|
|
for (long i = 0; ok && i + (long)sizeof(MARKER) < size && !slot; i++)
|
|
if (!memcmp(elf + i, MARKER, sizeof(MARKER) - 1))
|
|
slot = elf + i + sizeof(MARKER) - 1;
|
|
// the buffer is 1024 bytes including the marker
|
|
if (!slot || strlen(request) + 1 > 1024 - (sizeof(MARKER) - 1)) {
|
|
free(elf);
|
|
return -2;
|
|
}
|
|
memcpy(slot, request, strlen(request) + 1);
|
|
|
|
const int s = socket(AF_INET, SOCK_STREAM, 0);
|
|
struct sockaddr_in a;
|
|
memset(&a, 0, sizeof(a));
|
|
a.sin_family = AF_INET;
|
|
a.sin_port = htons(LOADER_PORT);
|
|
a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
|
int r = -3;
|
|
if (s >= 0 && !connect(s, (struct sockaddr *)&a, sizeof(a)))
|
|
r = send_all(s, elf, (size_t)size) ? -4 : 0;
|
|
if (s >= 0)
|
|
close(s);
|
|
free(elf);
|
|
return r;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
(void)argc;
|
|
(void)argv;
|
|
char game[700] = {0};
|
|
FILE *f = fopen("/app0/rpcs3-launch.txt", "r");
|
|
if (!f || !fgets(game, sizeof(game), f)) {
|
|
say("no /app0/rpcs3-launch.txt");
|
|
return 0;
|
|
}
|
|
fclose(f);
|
|
game[strcspn(game, "\r\n")] = 0;
|
|
|
|
int32_t user = -1;
|
|
sceUserServiceInitialize(NULL);
|
|
sceUserServiceGetForegroundUser(&user);
|
|
|
|
char request[800], msg[900];
|
|
snprintf(request, sizeof(request), "%d|%s", (int)user, game);
|
|
const int r = send_launch(request);
|
|
snprintf(msg, sizeof(msg), "launch payload for RPCS3 PS5 '%s' (user %d) sent: %d", game, (int)user, r);
|
|
say(msg);
|
|
return 0; // the payload starts RPCS3 PS5 once this tile has ended
|
|
}
|