kernel: Module loading

This commit is contained in:
raphaelthegreat 2024-06-04 22:03:18 +03:00
parent 611745170e
commit 48a158f18a
21 changed files with 155 additions and 41 deletions

View file

@ -52,7 +52,6 @@ std::string MntPoints::GetHostFile(const std::string& guest_file) {
if (find == 0) {
std::string npath = guest_file.substr(pair.guest_path.size(), guest_file.size() - 1);
std::replace(pair.host_path.begin(), pair.host_path.end(), '\\', '/');
fmt::print("GetHostFile: {}\n", pair.host_path + npath);
return pair.host_path + npath;
}
}

View file

@ -236,13 +236,42 @@ size_t PS4_SYSV_ABI sceKernelPread(int fd, void *buf, size_t count, uint64_t off
return file.ReadRaw<u8>(buf, count);
}
int PS4_SYSV_ABI Unknown1() {
return 0x81100004;
s32 PS4_SYSV_ABI sceKernelLoadStartModule(const char *moduleFileName, size_t args, const void *argp,
u32 flags, const void *pOpt, int *pRes) {
LOG_INFO(Lib_Kernel, "called filename = {}, args = {}", moduleFileName, args);
if (flags != 0) {
return 0x80020016;
}
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
const auto path = mnt->GetHostFile(moduleFileName);
// Load PRX module.
auto* linker = Common::Singleton<Core::Linker>::Instance();
u32 handle = linker->LoadModule(path);
auto* module = linker->GetModule(handle);
linker->Relocate(module);
// Retrieve and verify proc param according to libkernel.
const u64* param = module->GetProcParam<u64*>();
ASSERT_MSG(!param || param[0] >= 0x18, "Invalid module param size: {}", param[0]);
module->Start(args, argp, 0);
return handle;
}
s32 PS4_SYSV_ABI sceKernelDlsym(s32 handle, const char *symbol, void **addrp) {
auto* linker = Common::Singleton<Core::Linker>::Instance();
auto* module = linker->GetModule(handle);
*addrp = module->FindByName(symbol);
if (*addrp == nullptr) {
return 0x80020003;
}
return ORBIS_OK;
}
void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("fJgP+wqifno", "libSceDiscMap", 1, "libSceDiscMap", 1, 1, Unknown1);
// obj
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard);
// memory
@ -260,6 +289,8 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("IWIBBdTHit4", "libkernel", 1, "libkernel", 1, 1, sceKernelMapFlexibleMemory);
LIB_FUNCTION("rVjRvHJ0X6c", "libkernel", 1, "libkernel", 1, 1, sceKernelVirtualQuery);
LIB_FUNCTION("p5EcQeEeJAE", "libkernel", 1, "libkernel", 1, 1, _sceKernelRtldSetApplicationHeapAPI);
LIB_FUNCTION("wzvqT4UqKX8", "libkernel", 1, "libkernel", 1, 1, sceKernelLoadStartModule);
LIB_FUNCTION("LwG8g3niqwA", "libkernel", 1, "libkernel", 1, 1, sceKernelDlsym);
// equeue
LIB_FUNCTION("D0OdFMjp46I", "libkernel", 1, "libkernel", 1, 1, sceKernelCreateEqueue);

View file

@ -94,23 +94,22 @@ void Linker::Execute() {
}
}
Module* Linker::LoadModule(const std::filesystem::path& elf_name) {
s32 Linker::LoadModule(const std::filesystem::path& elf_name) {
std::scoped_lock lk{mutex};
if (!std::filesystem::exists(elf_name)) {
LOG_ERROR(Core_Linker, "Provided file {} does not exist", elf_name.string());
return nullptr;
return -1;
}
auto module = std::make_unique<Module>(elf_name);
if (!module->IsValid()) {
LOG_ERROR(Core_Linker, "Provided file {} is not valid ELF file", elf_name.string());
return nullptr;
return -1;
}
if (!module->IsSharedLib()) {
main_proc_param_addr = module->GetProcParam();
}
return m_modules.emplace_back(std::move(module)).get();
m_modules.emplace_back(std::move(module));
return m_modules.size() - 1;
}
void Linker::Relocate(Module* module) {

View file

@ -3,6 +3,7 @@
#pragma once
#include <mutex>
#include <vector>
#include "core/module.h"
@ -29,7 +30,11 @@ public:
}
VAddr GetProcParam() const {
return main_proc_param_addr;
return m_modules[0]->GetProcParam();
}
Module* GetModule(s32 index) const {
return m_modules.at(index).get();
}
void SetHeapApiFunc(void* func) {
@ -39,7 +44,7 @@ public:
void* TlsGetAddr(u64 module_index, u64 offset);
void InitTlsForThread(bool is_primary = false);
Module* LoadModule(const std::filesystem::path& elf_name);
s32 LoadModule(const std::filesystem::path& elf_name);
void Relocate(Module* module);
void Resolve(const std::string& name, Loader::SymbolType type,
@ -49,15 +54,14 @@ public:
private:
const Module* FindExportedModule(const ModuleInfo& m, const LibraryInfo& l);
void InitTls();
std::mutex mutex;
u32 dtv_generation_counter{1};
size_t static_tls_size{};
size_t max_tls_index{};
HeapApiFunc heap_api_func{};
std::vector<std::unique_ptr<Module>> m_modules;
Loader::SymbolsResolver m_hle_symbols{};
VAddr main_proc_param_addr{};
};
} // namespace Core

View file

@ -11,7 +11,7 @@
namespace Core::Loader {
void SymbolsResolver::AddSymbol(const SymbolResolver& s, u64 virtual_addr) {
m_symbols.emplace_back(GenerateName(s), virtual_addr);
m_symbols.emplace_back(GenerateName(s), s.nidName, virtual_addr);
}
std::string SymbolsResolver::GenerateName(const SymbolResolver& s) {

View file

@ -6,6 +6,7 @@
#include <filesystem>
#include <string>
#include <vector>
#include <span>
#include "common/types.h"
namespace Core::Loader {
@ -20,6 +21,7 @@ enum class SymbolType {
struct SymbolRecord {
std::string name;
std::string nid_name;
u64 virtual_address;
};
@ -42,6 +44,10 @@ public:
void AddSymbol(const SymbolResolver& s, u64 virtual_addr);
const SymbolRecord* FindSymbol(const SymbolResolver& s) const;
std::span<const SymbolRecord> GetSymbols() const {
return m_symbols;
}
size_t GetSize() const noexcept {
return m_symbols.size();
}

View file

@ -240,7 +240,7 @@ MemoryManager::VMAHandle MemoryManager::MergeAdjacent(VMAHandle iter) {
}
void MemoryManager::MapVulkanMemory(VAddr addr, size_t size) {
return;
//return;
const vk::Device device = instance->GetDevice();
const auto memory_props = instance->GetPhysicalDevice().getMemoryProperties();
void* host_pointer = reinterpret_cast<void*>(addr);
@ -312,7 +312,7 @@ void MemoryManager::MapVulkanMemory(VAddr addr, size_t size) {
}
void MemoryManager::UnmapVulkanMemory(VAddr addr, size_t size) {
return;
//return;
const auto it = mapped_memories.find(addr);
ASSERT(it != mapped_memories.end() && it->second.buffer_size == size);
mapped_memories.erase(it);

View file

@ -349,6 +349,7 @@ void Module::LoadSymbols() {
const auto aeronid = AeroLib::FindByNid(ids.at(0).c_str());
const auto nid_name = aeronid ? aeronid->name : "UNK";
LOG_INFO(Core_Linker, "NidName {}", nid_name);
Loader::SymbolResolver sym_r{};
sym_r.name = ids.at(0);

View file

@ -119,8 +119,18 @@ public:
return elf.IsSharedLib();
}
VAddr GetProcParam() const noexcept {
return proc_param_virtual_addr;
void* FindByName(std::string_view name) {
const auto symbols = export_sym.GetSymbols();
const auto it = std::ranges::find(symbols, name, &Loader::SymbolRecord::nid_name);
if (it != symbols.end()) {
return reinterpret_cast<void*>(it->virtual_address);
}
return nullptr;
}
template <typename T = VAddr>
const T GetProcParam() const noexcept {
return reinterpret_cast<T>(proc_param_virtual_addr);
}
std::span<const ModuleInfo> GetImportModules() const {

View file

@ -247,4 +247,12 @@ void Translator::S_BFE_U32(const GcnInst& inst) {
ir.SetScc(ir.INotEqual(result, ir.Imm32(0)));
}
void Translator::S_LSHL_B32(const GcnInst& inst) {
const IR::U32 src0{GetSrc(inst.src[0])};
const IR::U32 src1{GetSrc(inst.src[1])};
const IR::U32 result = ir.ShiftLeftLogical(src0, ir.BitwiseAnd(src1, ir.Imm32(0x1F)));
SetDst(inst.dst[0], result);
ir.SetScc(ir.INotEqual(result, ir.Imm32(0)));
}
} // namespace Shader::Gcn

View file

@ -371,6 +371,9 @@ void Translate(IR::Block* block, std::span<const GcnInst> inst_list, Info& info)
case Opcode::S_CMP_EQ_U32:
translator.S_CMP(ConditionOp::EQ, false, inst);
break;
case Opcode::S_LSHL_B32:
translator.S_LSHL_B32(inst);
break;
case Opcode::V_CNDMASK_B32:
translator.V_CNDMASK_B32(inst);
break;
@ -527,6 +530,9 @@ void Translate(IR::Block* block, std::span<const GcnInst> inst_list, Info& info)
case Opcode::S_BFE_U32:
translator.S_BFE_U32(inst);
break;
case Opcode::V_RNDNE_F32:
translator.V_RNDNE_F32(inst);
break;
case Opcode::S_NOP:
case Opcode::S_CBRANCH_EXECZ:
case Opcode::S_CBRANCH_SCC0:

View file

@ -48,6 +48,7 @@ public:
void S_CSELECT_B32(const GcnInst& inst);
void S_CSELECT_B64(const GcnInst& inst);
void S_BFE_U32(const GcnInst& inst);
void S_LSHL_B32(const GcnInst& inst);
// Scalar Memory
void S_LOAD_DWORD(int num_dwords, const GcnInst& inst);
@ -102,6 +103,7 @@ public:
void V_LSHR_B32(const GcnInst& inst);
void V_ASHRREV_I32(const GcnInst& inst);
void V_MAD_U32_U24(const GcnInst& inst);
void V_RNDNE_F32(const GcnInst& inst);
// Vector Memory
void BUFFER_LOAD_FORMAT(u32 num_dwords, bool is_typed, const GcnInst& inst);

View file

@ -367,4 +367,9 @@ void Translator::V_MAD_U32_U24(const GcnInst& inst) {
V_MAD_I32_I24(inst);
}
void Translator::V_RNDNE_F32(const GcnInst& inst) {
const IR::F32 src0{GetSrc(inst.src[0], true)};
SetDst(inst.dst[0], ir.FPRoundEven(src0));
}
} // namespace Shader::Gcn

View file

@ -31,7 +31,7 @@ void Translator::IMAGE_GET_RESINFO(const GcnInst& inst) {
void Translator::IMAGE_SAMPLE(const GcnInst& inst) {
const auto& mimg = inst.control.mimg;
ASSERT(!mimg.da);
//ASSERT(!mimg.da);
IR::VectorReg addr_reg{inst.src[0].code};
IR::VectorReg dest_reg{inst.dst[0].code};

View file

@ -252,6 +252,16 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
}
break;
}
case PM4ItOpcode::DrawIndexOffset2: {
const auto* draw_index_off = reinterpret_cast<const PM4CmdDrawIndexOffset2*>(header);
regs.max_index_size = draw_index_off->max_size;
regs.num_indices = draw_index_off->index_count;
regs.draw_initiator = draw_index_off->draw_initiator;
if (rasterizer) {
rasterizer->Draw(true, draw_index_off->index_offset);
}
break;
}
case PM4ItOpcode::DrawIndexAuto: {
const auto* draw_index = reinterpret_cast<const PM4CmdDrawIndexAuto*>(header);
regs.num_indices = draw_index->index_count;
@ -272,6 +282,17 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
}
break;
}
case PM4ItOpcode::NumInstances: {
const auto* num_instances = reinterpret_cast<const PM4CmdDrawNumInstances*>(header);
regs.num_instances.num_instances = num_instances->num_instances;
break;
}
case PM4ItOpcode::IndexBase: {
const auto* index_base = reinterpret_cast<const PM4CmdDrawIndexBase*>(header);
regs.index_base_address.base_addr_lo = index_base->addr_lo;
regs.index_base_address.base_addr_hi.Assign(index_base->addr_hi);
break;
}
case PM4ItOpcode::EventWrite: {
// const auto* event = reinterpret_cast<const PM4CmdEventWrite*>(header);
break;

View file

@ -548,4 +548,15 @@ struct PM4CmdDispatchDirect {
u32 dispatch_initiator; ///< Dispatch Initiator Register
};
struct PM4CmdDrawNumInstances {
PM4Type3Header header;
u32 num_instances;
};
struct PM4CmdDrawIndexBase {
PM4Type3Header header;
u32 addr_lo;
u32 addr_hi;
};
} // namespace AmdGpu

View file

@ -309,6 +309,12 @@ vk::Format SurfaceFormat(AmdGpu::DataFormat data_format, AmdGpu::NumberFormat nu
if (data_format == AmdGpu::DataFormat::FormatBc3 && num_format == AmdGpu::NumberFormat::Srgb) {
return vk::Format::eBc3SrgbBlock;
}
if (data_format == AmdGpu::DataFormat::Format16_16_16_16 && num_format == AmdGpu::NumberFormat::Sint) {
return vk::Format::eR16G16B16A16Sint;
}
if (data_format == AmdGpu::DataFormat::FormatBc7 && num_format == AmdGpu::NumberFormat::Srgb) {
return vk::Format::eBc7SrgbBlock;
}
UNREACHABLE();
}

View file

@ -81,8 +81,17 @@ ComputePipeline::ComputePipeline(const Instance& instance_, Scheduler& scheduler
ComputePipeline::~ComputePipeline() = default;
void ComputePipeline::BindResources(Core::MemoryManager* memory,
void ComputePipeline::BindResources(Core::MemoryManager* memory, StreamBuffer& staging,
VideoCore::TextureCache& texture_cache) const {
static constexpr u64 MinUniformAlignment = 64;
const auto map_staging = [&](auto src, size_t size) {
const auto [data, offset, _] = staging.Map(size, MinUniformAlignment);
std::memcpy(data, reinterpret_cast<const void*>(src), size);
staging.Commit(size);
return offset;
};
// Bind resource buffers and textures.
boost::container::static_vector<vk::DescriptorBufferInfo, 4> buffer_infos;
boost::container::static_vector<vk::DescriptorImageInfo, 8> image_infos;
@ -94,8 +103,9 @@ void ComputePipeline::BindResources(Core::MemoryManager* memory,
const u32 size = vsharp.GetSize();
const VAddr addr = vsharp.base_address.Value();
texture_cache.OnCpuWrite(addr);
const auto [vk_buffer, offset] = memory->GetVulkanBuffer(addr);
buffer_infos.emplace_back(vk_buffer, offset, size);
const u32 offset = map_staging(addr, size);
//const auto [vk_buffer, offset] = memory->GetVulkanBuffer(addr);
buffer_infos.emplace_back(staging.Handle(), offset, size);
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding++,

View file

@ -31,7 +31,8 @@ public:
return *pipeline;
}
void BindResources(Core::MemoryManager* memory, VideoCore::TextureCache& texture_cache) const;
void BindResources(Core::MemoryManager* memory, StreamBuffer& staging,
VideoCore::TextureCache& texture_cache) const;
private:
const Instance& instance;

View file

@ -32,16 +32,15 @@ Rasterizer::Rasterizer(const Instance& instance_, Scheduler& scheduler_,
Rasterizer::~Rasterizer() = default;
void Rasterizer::Draw(bool is_indexed) {
void Rasterizer::Draw(bool is_indexed, u32 index_offset) {
const auto cmdbuf = scheduler.CommandBuffer();
const auto& regs = liverpool->regs;
const u32 num_indices = SetupIndexBuffer(is_indexed);
const u32 num_indices = SetupIndexBuffer(is_indexed, index_offset);
const GraphicsPipeline* pipeline = pipeline_cache.GetGraphicsPipeline();
pipeline->BindResources(memory, vertex_index_buffer, texture_cache);
boost::container::static_vector<vk::RenderingAttachmentInfo, Liverpool::NumColorBuffers>
color_attachments{};
const std::array color = {0.5f, 0.5f, 0.5f, 1.f};
for (auto col_buf_id = 0u; col_buf_id < Liverpool::NumColorBuffers; ++col_buf_id) {
const auto& col_buf = regs.color_buffers[col_buf_id];
if (!col_buf) {
@ -54,12 +53,10 @@ void Rasterizer::Draw(bool is_indexed) {
color_attachments.push_back({
.imageView = *image_view.image_view,
.imageLayout = vk::ImageLayout::eGeneral,
.loadOp = compute_done ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad,
.loadOp = vk::AttachmentLoadOp::eLoad,
.storeOp = vk::AttachmentStoreOp::eStore,
.clearValue = vk::ClearValue{color},
});
}
compute_done = false;
// TODO: Don't restart renderpass every draw
const auto& scissor = regs.screen_scissor;
@ -88,18 +85,16 @@ void Rasterizer::Draw(bool is_indexed) {
}
void Rasterizer::DispatchDirect() {
compute_done = true;
return;
const auto cmdbuf = scheduler.CommandBuffer();
const auto& cs_program = liverpool->regs.cs_program;
const ComputePipeline* pipeline = pipeline_cache.GetComputePipeline();
pipeline->BindResources(memory, texture_cache);
pipeline->BindResources(memory, vertex_index_buffer, texture_cache);
cmdbuf.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline->Handle());
cmdbuf.dispatch(cs_program.dim_x, cs_program.dim_y, cs_program.dim_z);
}
u32 Rasterizer::SetupIndexBuffer(bool& is_indexed) {
u32 Rasterizer::SetupIndexBuffer(bool& is_indexed, u32 index_offset) {
// Emulate QuadList primitive type with CPU made index buffer.
const auto& regs = liverpool->regs;
if (liverpool->regs.primitive_type == Liverpool::PrimitiveType::QuadList) {
@ -135,7 +130,7 @@ u32 Rasterizer::SetupIndexBuffer(bool& is_indexed) {
// Bind index buffer.
const auto cmdbuf = scheduler.CommandBuffer();
cmdbuf.bindIndexBuffer(vertex_index_buffer.Handle(), offset, index_type);
cmdbuf.bindIndexBuffer(vertex_index_buffer.Handle(), offset + index_offset * index_size, index_type);
return regs.num_indices;
}

View file

@ -29,12 +29,12 @@ public:
VideoCore::TextureCache& texture_cache, AmdGpu::Liverpool* liverpool);
~Rasterizer();
void Draw(bool is_indexed);
void Draw(bool is_indexed, u32 index_offset = 0);
void DispatchDirect();
private:
u32 SetupIndexBuffer(bool& is_indexed);
u32 SetupIndexBuffer(bool& is_indexed, u32 index_offset);
void MapMemory(VAddr addr, size_t size);
void UpdateDynamicState(const GraphicsPipeline& pipeline);
@ -49,7 +49,6 @@ private:
Core::MemoryManager* memory;
PipelineCache pipeline_cache;
StreamBuffer vertex_index_buffer;
bool compute_done{};
};
} // namespace Vulkan