Files
KytyPS5/src/emulator.cpp
T
nmzikandGitHub 2f5396c6a5 Rework guest memory tracking/virtual address space/direct and flexible memory (#135)
* Rework guest memory tracking

* add unknwon flag

* Fix macOS guest address-space reservation
2026-07-31 03:07:17 +02:00

216 lines
6.2 KiB
C++

#include "emulator.h"
#include "common/abi.h"
#include "common/assert.h"
#include "common/commonSubsystem.h"
#include "common/emulatorConfig.h"
#include "common/file.h"
#include "common/logging/log.h"
#include "common/profiler.h"
#include "common/singleton.h"
#include "common/stringUtils.h"
#include "common/subsystems.h"
#include "common/systemInfo.h"
#include "common/threads.h"
#include "graphics/presentation/window.h"
#include "kernel/fileSystem.h"
#include "kernel/memory.h"
#include "kernel/pthread.h"
#include "libs/agc.h"
#include "libs/audio.h"
#include "libs/controller.h"
#include "libs/libs.h"
#include "libs/network.h"
#include "loader/runtimeLinker.h"
#include "loader/systemContent.h"
#include "loader/timer.h"
#include <cstdlib>
#include <filesystem>
namespace Emulator {
static void PrintSystemInfo() {
Common::SystemInfo info = Common::GetSystemInfo();
LOGF("ProcessorName = %s\n", info.ProcessorName.c_str());
}
static void KytyClose() {
auto* rt = Common::Singleton<Loader::RuntimeLinker>::Instance();
rt->Clear();
LOGF("done!\n");
Common::SubsystemsListSingleton::Instance()->ShutdownAll();
}
static void MountOrCreateDir(const std::filesystem::path& dir, const std::string& point) {
if (!Common::File::IsDirectoryExisting(dir)) {
Common::File::CreateDirectories(dir);
}
EXIT_NOT_IMPLEMENTED(!Common::File::IsDirectoryExisting(dir));
Libs::LibKernel::FileSystem::Mount(dir, point);
auto dir_text = Common::PathToString(dir);
LOGF("Mounted %s -> %s\n", point.c_str(), dir_text.c_str());
}
static void MountSandboxDirs() {
std::string title_id;
if (!Loader::SystemContentParamSfoGetString("TITLE_ID", &title_id) || title_id.empty()) {
title_id = "UNKNOWN";
}
MountOrCreateDir("_DownloadData/" + title_id, "/download0");
MountOrCreateDir("_TempData/" + title_id, "/temp0");
MountOrCreateDir("_TempData/" + title_id, "/temp");
}
static bool ClearDirectoryContents(const std::filesystem::path& dir) {
bool ok = true;
for (const auto& entry: Common::File::GetDirEntries(dir)) {
if (entry.name == "." || entry.name == "..") {
continue;
}
auto path = dir / entry.name;
if (entry.is_file) {
Common::File::RemoveReadonly(path);
ok = Common::File::DeleteFile(path) && ok;
} else {
ok = ClearDirectoryContents(path) && ok;
ok = Common::File::DeleteDirectory(path) && ok;
}
}
return ok;
}
static void ClearDebugTextureFolder() {
const std::string debug_texture_folder = "_Textures";
if (!Common::File::IsDirectoryExisting(debug_texture_folder)) {
Common::File::CreateDirectories(debug_texture_folder);
return;
}
if (!ClearDirectoryContents(debug_texture_folder)) {
LOGF_COLOR(Log::Color::BrightYellow, "TextureDump: failed to completely clear %s\n",
debug_texture_folder.c_str());
}
}
static void Init(const Config::ConfigOptions& cfg, const std::filesystem::path& param_json) {
EXIT_IF(!Common::Thread::IsMainThread());
auto* slist = Common::SubsystemsList::Instance();
auto* audio = Libs::Audio::AudioSubsystem::Instance();
auto* config = Config::ConfigSubsystem::Instance();
auto* controller = Libs::Controller::ControllerSubsystem::Instance();
auto* core = Common::CommonSubsystem::Instance();
auto* file_system = Libs::LibKernel::FileSystem::FileSystemSubsystem::Instance();
auto* graphics = Libs::Graphics::GraphicsSubsystem::Instance();
auto* log = Log::LogSubsystem::Instance();
auto* memory = Libs::LibKernel::Memory::MemorySubsystem::Instance();
auto* network = Libs::Network::NetworkSubsystem::Instance();
auto* profiler = Profiler::ProfilerSubsystem::Instance();
auto* pthread = Libs::LibKernel::PthreadSubsystem::Instance();
auto* timer = Loader::Timer::TimerSubsystem::Instance();
slist->Add(config, {core});
slist->InitAll(true);
Config::Load(cfg);
slist->Add(log, {core, config});
slist->InitAll(true);
if (Common::File::IsFileExisting(param_json)) {
Loader::SystemContentLoadParamSfo(param_json);
if (const auto flexible_memory_size = Loader::SystemContentGetFlexibleMemorySize();
flexible_memory_size != 0) {
Libs::LibKernel::Memory::SetFlexibleMemorySize(flexible_memory_size);
}
}
slist->Add(audio, {core, log, pthread, memory});
slist->Add(controller, {core, log, config});
slist->Add(file_system, {core, log, pthread});
slist->Add(graphics, {core, log, pthread, memory, config, profiler, controller});
slist->Add(memory, {core, log});
slist->Add(network, {core, log, pthread});
slist->Add(profiler, {core, config});
slist->Add(pthread, {core, log, timer});
slist->Add(timer, {core, log});
slist->InitAll(true);
}
static void LoadElf(const std::filesystem::path& elf, bool dbg_print_reloc = false,
const std::filesystem::path& save_name = {}) {
auto* rt = Common::Singleton<Loader::RuntimeLinker>::Instance();
auto* program = rt->LoadProgram(
Libs::LibKernel::FileSystem::GetRealFilename(Common::PathToGenericString(elf)));
if (dbg_print_reloc) {
program->dbg_print_reloc = true;
}
if (!save_name.empty()) {
rt->SaveProgram(program, Libs::LibKernel::FileSystem::GetRealFilename(
Common::PathToGenericString(save_name)));
}
}
static void Execute(const std::filesystem::path& game_patch) {
auto patch_path = game_patch;
Common::Thread guest_thread(
[](void* param) {
auto* rt = Common::Singleton<Loader::RuntimeLinker>::Instance();
rt->Execute(*static_cast<const std::filesystem::path*>(param));
},
&patch_path);
Libs::Graphics::WindowRun();
std::quick_exit(0);
}
void Run(const RunOptions& options) {
if (options.app0_dir.empty()) {
EXIT("app0 directory is required\n");
}
if (options.elf.empty()) {
EXIT("ELF is required\n");
}
const auto param_json = options.app0_dir / "sce_sys" / "param.json";
Init(options.config, param_json);
ClearDebugTextureFolder();
PrintSystemInfo();
int ok = atexit(KytyClose);
EXIT_NOT_IMPLEMENTED(ok != 0);
Libs::LibKernel::FileSystem::Mount(options.app0_dir, "/app0");
Libs::LibKernel::FileSystem::Mount(options.app0_dir, "/hostapp");
MountSandboxDirs();
auto* rt = Common::Singleton<Loader::RuntimeLinker>::Instance();
Libs::InitAll(rt->Symbols());
LoadElf(options.elf);
Execute(options.game_patch);
}
} // namespace Emulator