add load exec

Co-authored-by: thenotsoquietninja44-collab <thenotsoquietninja44@gmail.com>
This commit is contained in:
nmzik 2026-10-11 09:04:29 +02:00
parent 6f3bebcb50
commit cb375ec35a
9 changed files with 99 additions and 22 deletions

View File

@ -182,4 +182,8 @@ const Keymap& GetKeymap() {
return g_config->keymap;
}
const std::vector<std::string>& GetGuestArguments() {
return g_config->guest_arguments;
}
} // namespace Config

View File

@ -83,6 +83,7 @@ struct ConfigOptions {
bool red_zone_protection_enabled = false;
#endif
Keymap keymap;
std::vector<std::string> guest_arguments;
};
void Load(const ConfigOptions& cfg);
@ -136,6 +137,7 @@ bool RedZoneProtectionEnabled();
#endif
const Keymap& GetKeymap();
const std::vector<std::string>& GetGuestArguments();
} // namespace Config

View File

@ -16,6 +16,7 @@ struct RunOptions {
};
void Run(const RunOptions& options);
int LoadExec(const char* path, const char* const argv[]);
} // namespace Emulator

View File

@ -54,11 +54,7 @@ struct CContext {
std::list<atexit_func_t> atexit;
};
struct InitEnvParams {
int argc;
uint32_t pad;
const char* argv[3];
};
using InitEnvParams = Loader::EntryParams;
static int g_argc = 0;
static const char* const* g_argv = nullptr;
@ -271,9 +267,7 @@ static KYTY_SYSV_ABI void init_env(const InitEnvParams* params) {
return;
}
constexpr int argv_capacity = static_cast<int>(sizeof(params->argv) / sizeof(params->argv[0]));
EXIT_NOT_IMPLEMENTED(params->argc < 0 || params->argc >= argv_capacity);
EXIT_NOT_IMPLEMENTED(params->argc < 0);
g_argc = params->argc;
g_argv = params->argv;

View File

@ -4,6 +4,7 @@
#include "common/emulatorConfig.h"
#include "common/logging/log.h"
#include "common/stringUtils.h"
#include "emulator.h"
#include "graphics/presentation/systemOverlay.h"
#include "libs/dialog.h"
#include "libs/errno.h"
@ -99,6 +100,11 @@ static int KYTY_SYSV_ABI SystemServiceHideSplashScreen() {
return OK;
}
int KYTY_SYSV_ABI SystemServiceLoadExec(const char* path, const char* const argv[]) {
PRINT_NAME();
return Emulator::LoadExec(path, argv);
}
static int KYTY_SYSV_ABI SystemServiceParamGetInt(int param_id, int* value) {
PRINT_NAME();
@ -559,6 +565,7 @@ LIB_DEFINE(InitSystemGesture_1) {
} // namespace SystemGesture
LIB_DEFINE(InitSystemService_1) {
LIB_FUNC("JoBqSQt1yyA", SystemService::SystemServiceLoadExec);
LIB_FUNC("Vo5V8KAwCmk", SystemService::SystemServiceHideSplashScreen);
LIB_FUNC("fZo48un7LK4", SystemService::SystemServiceParamGetInt);
LIB_FUNC("SsC-m-S9JTA", SystemService::SystemServiceParamGetString);

63
src/loader/loadExec.cpp Normal file
View File

@ -0,0 +1,63 @@
#include "emulator.h"
#include "common/file.h"
#include "common/logging/log.h"
#include "kernel/fileSystem.h"
#include "libs/errno.h"
#include <cerrno>
#include <cstring>
#include <fstream>
#include <string_view>
#include <vector>
#if KYTY_PLATFORM == KYTY_PLATFORM_LINUX
#include <linux/close_range.h>
#include <unistd.h>
#endif
namespace Emulator {
int LoadExec(const char* path, const char* const argv[]) {
using namespace Libs::SystemService;
if (path == nullptr || !std::string_view(path).starts_with("/app0/") ||
!Common::File::IsFileExisting(Libs::LibKernel::FileSystem::GetRealFilename(path))) {
return SYSTEM_SERVICE_ERROR_PARAMETER;
}
#if KYTY_PLATFORM == KYTY_PLATFORM_LINUX
std::ifstream command("/proc/self/cmdline", std::ios::binary);
std::vector<std::string> arguments;
for (std::string argument; std::getline(command, argument, '\0') && argument != "--guest-exec";) {
arguments.push_back(std::move(argument));
}
if (arguments.empty()) {
return SYSTEM_SERVICE_ERROR_INTERNAL;
}
arguments.insert(arguments.end(), {"--guest-exec", path});
size_t bytes = 0;
for (size_t i = 0; argv != nullptr && argv[i] != nullptr; ++i) {
const auto size = strnlen(argv[i], 4096 - bytes) + 1;
if (size > 4096 - bytes) {
return SYSTEM_SERVICE_ERROR_PARAMETER;
}
bytes += size;
arguments.emplace_back(argv[i]);
}
std::vector<char*> host_argv;
for (auto& argument: arguments) {
host_argv.push_back(argument.data());
}
host_argv.push_back(nullptr);
LOGF("LoadExec: %s\n", path);
Log::Flush();
if (close_range(3, ~0u, CLOSE_RANGE_UNSHARE | CLOSE_RANGE_CLOEXEC) == 0) {
execvp(host_argv[0], host_argv.data());
}
LOGF("LoadExec failed: %s\n", std::strerror(errno));
return SYSTEM_SERVICE_ERROR_INTERNAL;
#else
return SYSTEM_SERVICE_ERROR_UNAVAILABLE;
#endif
}
} // namespace Emulator

View File

@ -25,6 +25,7 @@
#include <algorithm>
#include <atomic>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
@ -88,16 +89,6 @@ ThreadLocalStorage::~ThreadLocalStorage() {
}
}
#pragma pack(1)
struct EntryParams {
int argc;
uint32_t pad;
const char* argv[3];
};
#pragma pack()
using atexit_func_t = KYTY_SYSV_ABI void (*)();
using entry_func_t = KYTY_SYSV_ABI void (*)(EntryParams* params, atexit_func_t atexit_func);
using module_ini_fini_func_t = KYTY_SYSV_ABI int (*)(size_t args, const void* argp,
@ -1283,11 +1274,16 @@ void RuntimeLinker::Execute(const std::filesystem::path& game_patch) {
LOGF_COLOR(Log::Color::BrightYellow, "---\n--- Execute: %s\n---\n", "Main");
if (auto entry = GetEntry(); entry != 0) {
const auto& arguments = Config::GetGuestArguments();
const auto params_size = offsetof(EntryParams, argv) +
(arguments.size() + 2) * sizeof(const char*);
auto* params = reinterpret_cast<EntryParams*>(
(reinterpret_cast<uintptr_t>(main_stack_top) - 0x100u) & ~static_cast<uintptr_t>(0x0f));
std::memset(params, 0, sizeof(EntryParams));
params->argc = 1;
params->argv[0] = "KytyEmu";
(reinterpret_cast<uintptr_t>(main_stack_top) - params_size - 0x100u) &
~static_cast<uintptr_t>(0x0f));
std::memset(params, 0, params_size);
for (const auto& argument: arguments) {
params->argv[params->argc++] = argument.c_str();
}
LOGF("stack_addr = %" PRIx64 "\n", reinterpret_cast<uint64_t>(params));

View File

@ -14,6 +14,12 @@
namespace Loader {
struct EntryParams {
int argc;
uint32_t pad;
const char* argv[1];
};
class Elf64;
struct Elf64_Sym;
struct Elf64_Rela;

View File

@ -300,6 +300,10 @@ static bool ParseArgs(int argc, char* argv[], RunOptions& options, bool& show_he
value.c_str());
return false;
}
} else if (arg == "--guest-exec") {
options.elf = Common::PathFromUtf8(Common::FixFilenameSlash(value));
options.config.guest_arguments.assign(argv + i + 1, argv + argc);
break;
} else if (arg == "--game-patch") {
if (!options.game_patch.empty()) {
::printf("--game-patch can only be specified once\n");