mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 18:53:28 +01:00
Implement standalone OVL (overlay) loading mode
* Allow to load OVL alone. * Add error checks in ppu_load_exec(), do not crash on error. * Fix crash on exit from standalone PRX mode, allow kernel explorer to work with it as well for the added OVL mode.
This commit is contained in:
parent
9077563dac
commit
82c86ed2f7
@ -431,6 +431,11 @@ void cpu_thread::operator()()
|
||||
|
||||
while (!g_fxo->get<cpu_profiler>())
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Can we have a little race, right? First thread is started concurrently with g_fxo->init()
|
||||
std::this_thread::sleep_for(1ms);
|
||||
}
|
||||
|
@ -786,6 +786,27 @@ static void ppu_check_patch_spu_images(const ppu_segment& seg)
|
||||
}
|
||||
}
|
||||
|
||||
void try_spawn_ppu_if_exclusive_program(const ppu_module& m)
|
||||
{
|
||||
// If only PRX/OVL has been loaded at Emu.BootGame(), launch a single PPU thread so its memory can be viewed
|
||||
if (Emu.IsReady() && g_fxo->get<ppu_module>()->segs.empty())
|
||||
{
|
||||
ppu_thread_params p
|
||||
{
|
||||
.stack_addr = vm::cast(vm::alloc(0x100000, vm::stack, 4096)),
|
||||
.stack_size = 0x100000,
|
||||
};
|
||||
|
||||
auto ppu = idm::make_ptr<named_thread<ppu_thread>>("PPU[0x1000000] Thread (test_thread)", p, "test_thread", 0);
|
||||
|
||||
ppu->cmd_push({ppu_cmd::initialize, 0});
|
||||
ppu->cia = m.funcs[0].addr;
|
||||
|
||||
// For kernel explorer
|
||||
g_fxo->init<lv2_memory_container>(4096);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::string& path)
|
||||
{
|
||||
// Create new PRX object
|
||||
@ -1080,18 +1101,7 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
|
||||
ppu_loader.success("PRX library hash: %s (<- %u)", hash, applied);
|
||||
|
||||
if (Emu.IsReady() && g_fxo->get<ppu_module>()->segs.empty())
|
||||
{
|
||||
// Special loading mode
|
||||
ppu_thread_params p{
|
||||
.stack_addr = vm::cast(vm::alloc(0x100000, vm::stack, 4096)),
|
||||
.stack_size = 0x100000,
|
||||
};
|
||||
|
||||
auto ppu = idm::make_ptr<named_thread<ppu_thread>>("PPU[0x1000000] Thread (test_thread)", p, "test_thread", 0);
|
||||
|
||||
ppu->cmd_push({ppu_cmd::initialize, 0});
|
||||
}
|
||||
try_spawn_ppu_if_exclusive_program(*prx);
|
||||
|
||||
return prx;
|
||||
}
|
||||
@ -1129,8 +1139,24 @@ void ppu_unload_prx(const lv2_prx& prx)
|
||||
}
|
||||
}
|
||||
|
||||
void ppu_load_exec(const ppu_exec_object& elf)
|
||||
bool ppu_load_exec(const ppu_exec_object& elf)
|
||||
{
|
||||
// Check if it is a standalone executable first
|
||||
for (const auto& prog : elf.progs)
|
||||
{
|
||||
if (prog.p_type == 0x1u /* LOAD */ && prog.p_memsz)
|
||||
{
|
||||
using addr_range = utils::address_range;
|
||||
|
||||
const addr_range r = addr_range::start_length(static_cast<u32>(prog.p_vaddr), static_cast<u32>(prog.p_memsz));
|
||||
|
||||
if ((prog.p_vaddr | prog.p_memsz) > UINT32_MAX || !r.valid() || !r.inside(addr_range::start_length(0x00000000, 0x30000000)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set for delayed initialization in ppu_initialize()
|
||||
const auto _main = g_fxo->get<ppu_module>();
|
||||
|
||||
@ -1153,6 +1179,27 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
sha1_context sha;
|
||||
sha1_starts(&sha);
|
||||
|
||||
struct on_fatal_error
|
||||
{
|
||||
ppu_module* _main;
|
||||
bool errored = true;
|
||||
|
||||
~on_fatal_error()
|
||||
{
|
||||
if (!errored)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Revert previous allocations on an error
|
||||
for (const auto& seg : _main->segs)
|
||||
{
|
||||
vm::dealloc(seg.addr);
|
||||
}
|
||||
}
|
||||
|
||||
} error_handler{_main};
|
||||
|
||||
// Allocate memory at fixed positions
|
||||
for (const auto& prog : elf.progs)
|
||||
{
|
||||
@ -1173,7 +1220,10 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
if (type == 0x1 /* LOAD */ && prog.p_memsz)
|
||||
{
|
||||
if (prog.bin.size() > size || prog.bin.size() != prog.p_filesz)
|
||||
fmt::throw_exception("Invalid binary size (0x%llx, memsz=0x%x)", prog.bin.size(), size);
|
||||
{
|
||||
ppu_loader.fatal("ppu_load_exec(): Invalid binary size (0x%llx, memsz=0x%x)", prog.bin.size(), size);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vm::falloc(addr, size, vm::main))
|
||||
{
|
||||
@ -1181,7 +1231,8 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
|
||||
if (!vm::falloc(addr, size))
|
||||
{
|
||||
fmt::throw_exception("vm::falloc() failed (addr=0x%x, memsz=0x%x)", addr, size);
|
||||
ppu_loader.fatal("ppu_load_exec(): vm::falloc() failed (addr=0x%x, memsz=0x%x)", addr, size);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1299,11 +1350,17 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
|
||||
case 0x00000007: // TLS
|
||||
{
|
||||
ppu_loader.notice("TLS info segment found: tls-image=*0x%x, image-size=0x%x, tls-size=0x%x", prog.p_vaddr, prog.p_filesz, prog.p_memsz);
|
||||
|
||||
if ((prog.p_vaddr | prog.p_filesz | prog.p_memsz) > UINT32_MAX)
|
||||
{
|
||||
ppu_loader.fatal("ppu_load_exec(): TLS segment is invalid!");
|
||||
return false;
|
||||
}
|
||||
|
||||
tls_vaddr = vm::cast(prog.p_vaddr);
|
||||
tls_fsize = ::narrow<u32>(prog.p_filesz);
|
||||
tls_vsize = ::narrow<u32>(prog.p_memsz);
|
||||
|
||||
ppu_loader.notice("TLS info segment found: tls-image=*0x%x, image-size=0x%x, tls-size=0x%x", tls_vaddr, tls_fsize, tls_vsize);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1388,7 +1445,8 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
|
||||
if (proc_prx_param.magic != 0x1b434cecu)
|
||||
{
|
||||
fmt::throw_exception("Bad magic! (0x%x)", proc_prx_param.magic);
|
||||
ppu_loader.fatal("ppu_load_exec(): Bad magic! (0x%x)", proc_prx_param.magic);
|
||||
return false;
|
||||
}
|
||||
|
||||
ppu_load_exports(link, proc_prx_param.libent_start, proc_prx_param.libent_end);
|
||||
@ -1647,6 +1705,9 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
ensure(vm::page_protect(addr, utils::align(size, 0x1000), 0, 0, vm::page_writable));
|
||||
}
|
||||
}
|
||||
|
||||
error_handler.errored = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_exec_object& elf, const std::string& path)
|
||||
@ -1875,5 +1936,8 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
|
||||
ovlm->path = path;
|
||||
|
||||
idm::import_existing<lv2_obj, lv2_overlay>(ovlm);
|
||||
|
||||
try_spawn_ppu_if_exclusive_program(*ovlm);
|
||||
|
||||
return {std::move(ovlm), {}};
|
||||
}
|
||||
|
@ -2089,7 +2089,7 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<lv2_
|
||||
std::vector<std::pair<std::string, u64>> file_queue;
|
||||
file_queue.reserve(2000);
|
||||
|
||||
// Find all .sprx files recursively (TODO: process .mself files)
|
||||
// Find all .sprx files recursively
|
||||
for (usz i = 0; i < dir_queue.size(); i++)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "Emu/Cell/lv2/sys_memory.h"
|
||||
#include "Emu/Cell/lv2/sys_sync.h"
|
||||
#include "Emu/Cell/lv2/sys_prx.h"
|
||||
#include "Emu/Cell/lv2/sys_overlay.h"
|
||||
#include "Emu/Cell/lv2/sys_rsx.h"
|
||||
#include "Emu/Cell/Modules/cellMsgDialog.h"
|
||||
|
||||
@ -64,13 +65,14 @@ std::string g_cfg_defaults;
|
||||
|
||||
atomic_t<u64> g_watchdog_hold_ctr{0};
|
||||
|
||||
extern void ppu_load_exec(const ppu_exec_object&);
|
||||
extern bool ppu_load_exec(const ppu_exec_object&);
|
||||
extern void spu_load_exec(const spu_exec_object&);
|
||||
extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<lv2_prx*>* loaded_prx);
|
||||
extern bool ppu_initialize(const ppu_module&, bool = false);
|
||||
extern void ppu_finalize(const ppu_module&);
|
||||
extern void ppu_unload_prx(const lv2_prx&);
|
||||
extern std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object&, const std::string&);
|
||||
extern std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_exec_object&, const std::string& path);
|
||||
|
||||
fs::file g_tty;
|
||||
atomic_t<s64> g_tty_size{0};
|
||||
@ -1570,15 +1572,30 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
|
||||
|
||||
g_fxo->init<ppu_module>();
|
||||
|
||||
ppu_load_exec(ppu_exec);
|
||||
if (ppu_load_exec(ppu_exec))
|
||||
{
|
||||
ConfigurePPUCache();
|
||||
|
||||
ConfigurePPUCache();
|
||||
g_fxo->init();
|
||||
Emu.GetCallbacks().init_gs_render();
|
||||
Emu.GetCallbacks().init_pad_handler(m_title_id);
|
||||
Emu.GetCallbacks().init_kb_handler();
|
||||
Emu.GetCallbacks().init_mouse_handler();
|
||||
}
|
||||
// Overlay (OVL) executable (only load it)
|
||||
else if (vm::map(0x3000'0000, 0x1000'0000, 0x200); !ppu_load_overlay(ppu_exec, m_path).first)
|
||||
{
|
||||
ppu_exec = fs::file{};
|
||||
}
|
||||
|
||||
g_fxo->init();
|
||||
Emu.GetCallbacks().init_gs_render();
|
||||
Emu.GetCallbacks().init_pad_handler(m_title_id);
|
||||
Emu.GetCallbacks().init_kb_handler();
|
||||
Emu.GetCallbacks().init_mouse_handler();
|
||||
if (ppu_exec != elf_error::ok)
|
||||
{
|
||||
Stop();
|
||||
|
||||
sys_log.error("Invalid or unsupported PPU executable format: %s", elf_path);
|
||||
|
||||
return game_boot_result::invalid_file_or_folder;
|
||||
}
|
||||
}
|
||||
else if (ppu_prx.open(elf_file) == elf_error::ok)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user