Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PPU LLVM: Precompile all executable (PRX, MSELF, overlay) code at startup #9680

Merged
merged 2 commits into from Jan 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
42 changes: 36 additions & 6 deletions rpcs3/Emu/Cell/PPUModule.cpp
Expand Up @@ -3,6 +3,7 @@

#include "Utilities/bin_patch.h"
#include "Utilities/StrUtil.h"
#include "Utilities/address_range.h"
#include "Crypto/sha1.h"
#include "Crypto/unself.h"
#include "Loader/ELF.h"
Expand Down Expand Up @@ -30,7 +31,7 @@ extern std::string ppu_get_function_name(const std::string& _module, u32 fnid);
extern std::string ppu_get_variable_name(const std::string& _module, u32 vnid);
extern void ppu_register_range(u32 addr, u32 size);
extern void ppu_register_function_at(u32 addr, u32 size, ppu_function_t ptr);
extern void ppu_initialize(const ppu_module& info);
extern bool ppu_initialize(const ppu_module& info, bool = false);
extern void ppu_initialize();

extern void sys_initialize_tls(ppu_thread&, u64, u32, u32, u32);
Expand Down Expand Up @@ -1648,17 +1649,34 @@ void ppu_load_exec(const ppu_exec_object& elf)
}
}

std::shared_ptr<lv2_overlay> ppu_load_overlay(const ppu_exec_object& elf, const std::string& path)
std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_exec_object& elf, const std::string& path)
{
const auto ovlm = idm::make_ptr<lv2_obj, lv2_overlay>();

// Access linkage information object
const auto link = g_fxo->get<ppu_linkage_info>();

// Executable hash
sha1_context sha;
sha1_starts(&sha);

// Check if it is an overlay 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(::narrow<u32>(prog.p_vaddr), ::narrow<u32>(prog.p_memsz));

if (!r.valid() || !r.inside(addr_range::start_length(0x30000000, 0x10000000)))
{
// TODO: Check error and if there's a better way to error check
return {nullptr, CELL_ENOEXEC};
}
}
}

const auto ovlm = std::make_shared<lv2_overlay>();

// Allocate memory at fixed positions
for (const auto& prog : elf.progs)
{
Expand All @@ -1682,7 +1700,18 @@ std::shared_ptr<lv2_overlay> ppu_load_overlay(const ppu_exec_object& elf, const
fmt::throw_exception("Invalid binary size (0x%llx, memsz=0x%x)", prog.bin.size(), size);

if (!vm::get(vm::any, 0x30000000)->falloc(addr, size))
fmt::throw_exception("vm::falloc() failed (addr=0x%x, memsz=0x%x)", addr, size);
{
ppu_loader.error("ppu_load_overlay(): vm::falloc() failed (addr=0x%x, memsz=0x%x)", addr, size);

// Revert previous allocations
for (const auto& seg : ovlm->segs)
{
ensure(vm::dealloc(seg.addr));
}

// TODO: Check error code, maybe disallow more than one overlay instance completely
return {nullptr, CELL_EBUSY};
}

// Copy segment data, hash it
std::memcpy(vm::base(addr), prog.bin.data(), prog.bin.size());
Expand Down Expand Up @@ -1845,5 +1874,6 @@ std::shared_ptr<lv2_overlay> ppu_load_overlay(const ppu_exec_object& elf, const
ovlm->name = path.substr(path.find_last_of('/') + 1);
ovlm->path = path;

return ovlm;
idm::import_existing<lv2_obj, lv2_overlay>(ovlm);
return {std::move(ovlm), {}};
}