mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-07-08 18:16:21 +00:00
core: Reorganize
This commit is contained in:
parent
89cf4dbfcb
commit
369d92fa56
73 changed files with 724 additions and 572 deletions
|
@ -1,22 +0,0 @@
|
|||
#pragma once
|
||||
constexpr int SCE_OK = 0;
|
||||
|
||||
constexpr int SCE_KERNEL_ERROR_EBADF = 0x80020009;
|
||||
constexpr int SCE_KERNEL_ERROR_ENOMEM = 0x8002000c; // Insufficient memory
|
||||
constexpr int SCE_KERNEL_ERROR_EFAULT = 0x8002000e; // Invalid address pointer
|
||||
constexpr int SCE_KERNEL_ERROR_EINVAL = 0x80020016; // null or invalid states
|
||||
constexpr int SCE_KERNEL_ERROR_EAGAIN = 0x80020023; // Memory cannot be allocated
|
||||
constexpr int SCE_KERNEL_ERROR_ENAMETOOLONG = 0x8002003f; // character strings exceeds valid size
|
||||
|
||||
// videoOut
|
||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_VALUE = 0x80290001; // invalid argument
|
||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_ADDRESS = 0x80290002; // invalid addresses
|
||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_TILING_MODE = 0x80290007; // invalid tiling mode
|
||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_ASPECT_RATIO = 0x80290008; // invalid aspect ration
|
||||
constexpr int SCE_VIDEO_OUT_ERROR_RESOURCE_BUSY = 0x80290009; // already opened
|
||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_INDEX = 0x8029000A; // invalid buffer index
|
||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_HANDLE = 0x8029000B; // invalid handle
|
||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE = 0x8029000C; // Invalid event queue
|
||||
constexpr int SCE_VIDEO_OUT_ERROR_SLOT_OCCUPIED = 0x80290010; // slot already used
|
||||
constexpr int SCE_VIDEO_OUT_ERROR_FLIP_QUEUE_FULL = 0x80290012; // flip queue is full
|
||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_OPTION = 0x8029001A; // Invalid buffer attribute option
|
|
@ -1,8 +1,6 @@
|
|||
#include "video_out_ctx.h"
|
||||
|
||||
#include <core/PS4/HLE/LibKernel.h>
|
||||
#include "common/debug.h"
|
||||
#include <core/hle/libraries/libkernel/time_management.h>
|
||||
#include "core/PS4/HLE/Graphics/Objects/video_out_ctx.h"
|
||||
#include "core/hle/libraries/libkernel/time_management.h"
|
||||
|
||||
namespace HLE::Graphics::Objects {
|
||||
|
||||
|
@ -12,6 +10,7 @@ void VideoOutCtx::Init(u32 width, u32 height) {
|
|||
m_video_out_ctx.m_resolution.paneWidth = width;
|
||||
m_video_out_ctx.m_resolution.paneHeight = height;
|
||||
}
|
||||
|
||||
int VideoOutCtx::Open() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
|
@ -112,7 +111,7 @@ bool FlipQueue::flip(u32 micros) {
|
|||
std::scoped_lock cfg_lock{request->cfg->m_mutex};
|
||||
for (auto& flip_eq : request->cfg->m_flip_evtEq) {
|
||||
if (flip_eq != nullptr) {
|
||||
flip_eq->triggerEvent(SCE_VIDEO_OUT_EVENT_FLIP, HLE::Kernel::Objects::EVFILT_VIDEO_OUT, reinterpret_cast<void*>(request->flip_arg));
|
||||
flip_eq->triggerEvent(SCE_VIDEO_OUT_EVENT_FLIP, Core::Kernel::EVFILT_VIDEO_OUT, reinterpret_cast<void*>(request->flip_arg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,4 +130,4 @@ bool FlipQueue::flip(u32 micros) {
|
|||
return true;
|
||||
}
|
||||
|
||||
}; // namespace HLE::Graphics::Objects
|
||||
} // namespace HLE::Graphics::Objects
|
||||
|
|
|
@ -24,7 +24,7 @@ struct VideoConfigInternal {
|
|||
bool isOpened = false;
|
||||
SceVideoOutFlipStatus m_flip_status;
|
||||
SceVideoOutVblankStatus m_vblank_status;
|
||||
std::vector<HLE::Libs::LibKernel::EventQueues::SceKernelEqueue> m_flip_evtEq;
|
||||
std::vector<Core::Kernel::SceKernelEqueue> m_flip_evtEq;
|
||||
int m_flip_rate = 0;
|
||||
VideoOutBufferInfo buffers[16];
|
||||
std::vector<VideoOutBufferSetInternal> buffers_sets;
|
||||
|
@ -78,4 +78,5 @@ class VideoOutCtx {
|
|||
FlipQueue m_flip_queue;
|
||||
HLE::Libs::Graphics::GraphicCtx* m_graphic_ctx = nullptr;
|
||||
};
|
||||
}; // namespace HLE::Graphics::Objects
|
||||
|
||||
} // namespace HLE::Graphics::Objects
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
#include "video_out.h"
|
||||
|
||||
#include <core/PS4/GPU/gpu_memory.h>
|
||||
#include <core/PS4/GPU/video_out_buffer.h>
|
||||
#include <core/PS4/HLE/ErrorCodes.h>
|
||||
#include <core/PS4/HLE/LibSceGnmDriver.h>
|
||||
#include <core/PS4/HLE/Libs.h>
|
||||
#include <core/PS4/HLE/UserManagement/UsrMngCodes.h>
|
||||
#include <Util/config.h>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <magic_enum.hpp>
|
||||
#include "common/log.h"
|
||||
#include "common/debug.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include <magic_enum.hpp>
|
||||
#include <string>
|
||||
|
||||
#include "core/loader/symbols_resolver.h"
|
||||
#include "core/PS4/HLE/Graphics/video_out.h"
|
||||
#include "core/PS4/GPU/gpu_memory.h"
|
||||
#include "core/PS4/GPU/video_out_buffer.h"
|
||||
#include "core/hle/error_codes.h"
|
||||
#include "core/hle/libraries/libscegnmdriver/libscegnmdriver.h"
|
||||
#include "core/hle/libraries/libs.h"
|
||||
#include "core/hle/libraries/libuserservice/usr_mng_codes.h"
|
||||
#include "Util/config.h"
|
||||
#include "Objects/video_out_ctx.h"
|
||||
#include "common/singleton.h"
|
||||
#include "emulator.h"
|
||||
|
@ -60,7 +58,7 @@ void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(SceVideoOutBufferAttribute* attr
|
|||
LOG_INFO_IF(log_file_videoout, "height = {}\n", height);
|
||||
LOG_INFO_IF(log_file_videoout, "pitchInPixel = {}\n", pitchInPixel);
|
||||
|
||||
memset(attribute, 0, sizeof(SceVideoOutBufferAttribute));
|
||||
std::memset(attribute, 0, sizeof(SceVideoOutBufferAttribute));
|
||||
|
||||
attribute->pixelFormat = pixelFormat;
|
||||
attribute->tilingMode = tilingMode;
|
||||
|
@ -71,21 +69,23 @@ void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(SceVideoOutBufferAttribute* attr
|
|||
attribute->option = SCE_VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_NONE;
|
||||
}
|
||||
|
||||
static void flip_reset_event_func(HLE::Kernel::Objects::EqueueEvent* event) {
|
||||
static void flip_reset_event_func(Core::Kernel::EqueueEvent* event) {
|
||||
event->isTriggered = false;
|
||||
event->event.fflags = 0;
|
||||
event->event.data = 0;
|
||||
}
|
||||
static void flip_trigger_event_func(HLE::Kernel::Objects::EqueueEvent* event, void* trigger_data) {
|
||||
|
||||
static void flip_trigger_event_func(Core::Kernel::EqueueEvent* event, void* trigger_data) {
|
||||
event->isTriggered = true;
|
||||
event->event.fflags++;
|
||||
event->event.data = reinterpret_cast<intptr_t>(trigger_data);
|
||||
}
|
||||
static void flip_delete_event_func(LibKernel::EventQueues::SceKernelEqueue eq, HLE::Kernel::Objects::EqueueEvent* event) {
|
||||
|
||||
static void flip_delete_event_func(Core::Kernel::SceKernelEqueue eq, Core::Kernel::EqueueEvent* event) {
|
||||
BREAKPOINT(); // TODO
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(LibKernel::EventQueues::SceKernelEqueue eq, s32 handle, void* udata) {
|
||||
s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Core::Kernel::SceKernelEqueue eq, s32 handle, void* udata) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
||||
|
||||
|
@ -100,10 +100,10 @@ s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(LibKernel::EventQueues::SceKernelEqueue
|
|||
return SCE_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
|
||||
}
|
||||
|
||||
HLE::Kernel::Objects::EqueueEvent event;
|
||||
Core::Kernel::EqueueEvent event{};
|
||||
event.isTriggered = false;
|
||||
event.event.ident = SCE_VIDEO_OUT_EVENT_FLIP;
|
||||
event.event.filter = HLE::Kernel::Objects::EVFILT_VIDEO_OUT;
|
||||
event.event.filter = Core::Kernel::EVFILT_VIDEO_OUT;
|
||||
event.event.udata = udata;
|
||||
event.event.fflags = 0;
|
||||
event.event.data = 0;
|
||||
|
@ -213,18 +213,21 @@ s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* co
|
|||
|
||||
return registration_index;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutSetFlipRate(s32 handle, s32 rate) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
||||
videoOut->getCtx(handle)->m_flip_rate = rate;
|
||||
return SCE_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutIsFlipPending(s32 handle) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
||||
s32 pending = videoOut->getCtx(handle)->m_flip_status.flipPendingNum;
|
||||
return pending;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutSubmitFlip(s32 handle, s32 bufferIndex, s32 flipMode, s64 flipArg) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
||||
|
@ -249,9 +252,10 @@ s32 PS4_SYSV_ABI sceVideoOutSubmitFlip(s32 handle, s32 bufferIndex, s32 flipMode
|
|||
LOG_TRACE_IF(log_file_videoout, "sceVideoOutSubmitFlip flip queue is full\n");
|
||||
return SCE_VIDEO_OUT_ERROR_FLIP_QUEUE_FULL;
|
||||
}
|
||||
HLE::Libs::LibSceGnmDriver::sceGnmFlushGarlic(); // hackish should be done that neccesary for niko's homebrew
|
||||
Core::Libraries::LibSceGnmDriver::sceGnmFlushGarlic(); // hackish should be done that neccesary for niko's homebrew
|
||||
return SCE_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutGetFlipStatus(s32 handle, SceVideoOutFlipStatus* status) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
||||
|
@ -268,12 +272,14 @@ s32 PS4_SYSV_ABI sceVideoOutGetFlipStatus(s32 handle, SceVideoOutFlipStatus* sta
|
|||
LOG_INFO_IF(log_file_videoout, "currentBuffer = {}\n", status->currentBuffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutGetResolutionStatus(s32 handle, SceVideoOutResolutionStatus* status) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
||||
*status = videoOut->getCtx(handle)->m_resolution;
|
||||
return SCE_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutOpen(SceUserServiceUserId userId, s32 busType, s32 index, const void* param) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
if (userId != SCE_USER_SERVICE_USER_ID_SYSTEM && userId != 0) {
|
||||
|
@ -299,14 +305,20 @@ s32 PS4_SYSV_ABI sceVideoOutOpen(SceUserServiceUserId userId, s32 busType, s32 i
|
|||
|
||||
return handle;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutClose(s32 handle) {
|
||||
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
||||
videoOut->Close(handle);
|
||||
return SCE_OK;
|
||||
}
|
||||
s32 PS4_SYSV_ABI sceVideoOutUnregisterBuffers(s32 handle, s32 attributeIndex) { BREAKPOINT(); }
|
||||
|
||||
void videoOutRegisterLib(SymbolsResolver* sym) {
|
||||
s32 PS4_SYSV_ABI sceVideoOutUnregisterBuffers(s32 handle, s32 attributeIndex) {
|
||||
BREAKPOINT();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void videoOutRegisterLib(Core::Loader::SymbolsResolver* sym) {
|
||||
using namespace Core;
|
||||
LIB_FUNCTION("SbU3dwp80lQ", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutGetFlipStatus);
|
||||
LIB_FUNCTION("U46NwOiJpys", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutSubmitFlip);
|
||||
LIB_FUNCTION("w3BY+tAEiQY", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutRegisterBuffers);
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
#pragma once
|
||||
#include <core/PS4/HLE/Kernel/event_queues.h>
|
||||
#include <core/PS4/Loader/SymbolsResolver.h>
|
||||
|
||||
#include <string>
|
||||
#include "core/hle/kernel/event_queues.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
|
||||
namespace HLE::Libs::Graphics::VideoOut {
|
||||
|
||||
|
@ -95,12 +98,12 @@ struct VideoOutBufferSetInternal {
|
|||
|
||||
void videoOutInit(u32 width, u32 height);
|
||||
std::string getPixelFormatString(s32 format);
|
||||
void videoOutRegisterLib(SymbolsResolver* sym);
|
||||
void videoOutRegisterLib(Core::Loader::SymbolsResolver* sym);
|
||||
bool videoOutFlip(u32 micros);
|
||||
|
||||
void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(SceVideoOutBufferAttribute* attribute, u32 pixelFormat, u32 tilingMode, u32 aspectRatio, u32 width,
|
||||
u32 height, u32 pitchInPixel);
|
||||
s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(LibKernel::EventQueues::SceKernelEqueue eq, s32 handle, void* udata);
|
||||
s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Core::Kernel::SceKernelEqueue eq, s32 handle, void* udata);
|
||||
s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* const* addresses, s32 bufferNum,
|
||||
const SceVideoOutBufferAttribute* attribute);
|
||||
s32 PS4_SYSV_ABI sceVideoOutSetFlipRate(s32 handle, s32 rate);
|
||||
|
@ -110,4 +113,5 @@ s32 PS4_SYSV_ABI sceVideoOutGetFlipStatus(s32 handle, SceVideoOutFlipStatus* sta
|
|||
s32 PS4_SYSV_ABI sceVideoOutGetResolutionStatus(s32 handle, SceVideoOutResolutionStatus* status);
|
||||
s32 PS4_SYSV_ABI sceVideoOutOpen(SceUserServiceUserId userId, s32 busType, s32 index, const void* param);
|
||||
s32 PS4_SYSV_ABI sceVideoOutClose(s32 handle);
|
||||
} // namespace HLE::Libs::Graphics::VideoOut
|
||||
|
||||
} // namespace HLE::Libs::Graphics::VideoOut
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
#include "event_queue.h"
|
||||
|
||||
#include <Lib/Timer.h>
|
||||
|
||||
#include "common/debug.h"
|
||||
|
||||
namespace HLE::Kernel::Objects {
|
||||
EqueueInternal::~EqueueInternal() {}
|
||||
|
||||
int EqueueInternal::addEvent(const EqueueEvent& event) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
if (m_events.size() > 0) {
|
||||
BREAKPOINT();
|
||||
}
|
||||
// TODO check if event is already exists and return it. Currently we just add in m_events array
|
||||
m_events.push_back(event);
|
||||
|
||||
if (event.isTriggered) {
|
||||
BREAKPOINT(); // we don't support that either yet
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EqueueInternal::waitForEvents(SceKernelEvent* ev, int num, u32 micros) {
|
||||
std::unique_lock lock{m_mutex};
|
||||
|
||||
u32 timeElapsed = 0;
|
||||
Lib::Timer t;
|
||||
t.Start();
|
||||
|
||||
for (;;) {
|
||||
int ret = getTriggeredEvents(ev, num);
|
||||
|
||||
if (ret > 0 || (timeElapsed >= micros && micros != 0)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (micros == 0) {
|
||||
m_cond.wait(lock);
|
||||
} else {
|
||||
m_cond.wait_for(lock, std::chrono::microseconds(micros - timeElapsed));
|
||||
}
|
||||
|
||||
timeElapsed = static_cast<uint32_t>(t.GetTimeSec() * 1000000.0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool EqueueInternal::triggerEvent(u64 ident, s16 filter, void* trigger_data) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
if (m_events.size() > 1) {
|
||||
BREAKPOINT(); // we currently support one event
|
||||
}
|
||||
auto& event = m_events[0];
|
||||
|
||||
if (event.filter.trigger_event_func != nullptr) {
|
||||
event.filter.trigger_event_func(&event, trigger_data);
|
||||
} else {
|
||||
event.isTriggered = true;
|
||||
}
|
||||
|
||||
m_cond.notify_one();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int EqueueInternal::getTriggeredEvents(SceKernelEvent* ev, int num) {
|
||||
int ret = 0;
|
||||
|
||||
if (m_events.size() > 1) {
|
||||
BREAKPOINT(); // we currently support one event
|
||||
}
|
||||
auto& event = m_events[0];
|
||||
|
||||
if (event.isTriggered) {
|
||||
ev[ret++] = event.event;
|
||||
|
||||
if (event.filter.reset_event_func != nullptr) {
|
||||
event.filter.reset_event_func(&event);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
}; // namespace HLE::Kernel::Objects
|
|
@ -1,79 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace HLE::Kernel::Objects {
|
||||
|
||||
constexpr s16 EVFILT_READ = -1;
|
||||
constexpr s16 EVFILT_WRITE = -2;
|
||||
constexpr s16 EVFILT_AIO = -3; // attached to aio requests
|
||||
constexpr s16 EVFILT_VNODE = -4; // attached to vnodes
|
||||
constexpr s16 EVFILT_PROC = -5; // attached to struct proc
|
||||
constexpr s16 EVFILT_SIGNAL = -6; // attached to struct proc
|
||||
constexpr s16 EVFILT_TIMER = -7; // timers
|
||||
constexpr s16 EVFILT_FS = -9; // filesystem events
|
||||
constexpr s16 EVFILT_LIO = -10; // attached to lio requests
|
||||
constexpr s16 EVFILT_USER = -11; // User events
|
||||
constexpr s16 EVFILT_POLLING = -12;
|
||||
constexpr s16 EVFILT_VIDEO_OUT = -13;
|
||||
constexpr s16 EVFILT_GRAPHICS_CORE = -14;
|
||||
constexpr s16 EVFILT_HRTIMER = -15;
|
||||
constexpr s16 EVFILT_UVD_TRAP = -16;
|
||||
constexpr s16 EVFILT_VCE_TRAP = -17;
|
||||
constexpr s16 EVFILT_SDMA_TRAP = -18;
|
||||
constexpr s16 EVFILT_REG_EV = -19;
|
||||
constexpr s16 EVFILT_GPU_EXCEPTION = -20;
|
||||
constexpr s16 EVFILT_GPU_SYSTEM_EXCEPTION = -21;
|
||||
constexpr s16 EVFILT_GPU_DBGGC_EV = -22;
|
||||
constexpr s16 EVFILT_SYSCOUNT = 22;
|
||||
|
||||
class EqueueInternal;
|
||||
struct EqueueEvent;
|
||||
|
||||
using SceKernelEqueue = Kernel::Objects::EqueueInternal*;
|
||||
|
||||
using TriggerFunc = void (*)(EqueueEvent* event, void* trigger_data);
|
||||
using ResetFunc = void (*)(EqueueEvent* event);
|
||||
using DeleteFunc = void (*)(SceKernelEqueue eq, EqueueEvent* event);
|
||||
|
||||
struct SceKernelEvent {
|
||||
u64 ident = 0; /* identifier for this event */
|
||||
s16 filter = 0; /* filter for event */
|
||||
u16 flags = 0;
|
||||
u32 fflags = 0;
|
||||
s64 data = 0;
|
||||
void* udata = nullptr; /* opaque user data identifier */
|
||||
};
|
||||
|
||||
struct Filter {
|
||||
void* data = nullptr;
|
||||
TriggerFunc trigger_event_func = nullptr;
|
||||
ResetFunc reset_event_func = nullptr;
|
||||
DeleteFunc delete_event_func = nullptr;
|
||||
};
|
||||
|
||||
struct EqueueEvent {
|
||||
bool isTriggered = false;
|
||||
SceKernelEvent event;
|
||||
Filter filter;
|
||||
};
|
||||
|
||||
class EqueueInternal {
|
||||
public:
|
||||
EqueueInternal() = default;
|
||||
virtual ~EqueueInternal();
|
||||
void setName(const std::string& m_name) { this->m_name = m_name; }
|
||||
int addEvent(const EqueueEvent& event);
|
||||
int waitForEvents(SceKernelEvent* ev, int num, u32 micros);
|
||||
bool triggerEvent(u64 ident, s16 filter, void* trigger_data);
|
||||
int getTriggeredEvents(SceKernelEvent* ev, int num);
|
||||
private:
|
||||
std::string m_name;
|
||||
std::mutex m_mutex;
|
||||
std::vector<EqueueEvent> m_events;
|
||||
std::condition_variable m_cond;
|
||||
};
|
||||
}; // namespace HLE::Kernel::Objects
|
|
@ -1,62 +0,0 @@
|
|||
#include "physical_memory.h"
|
||||
|
||||
namespace HLE::Kernel::Objects {
|
||||
|
||||
static u64 AlignUp(u64 pos, u64 align) { return (align != 0 ? (pos + (align - 1)) & ~(align - 1) : pos); }
|
||||
|
||||
bool PhysicalMemory::Alloc(u64 searchStart, u64 searchEnd, u64 len, u64 alignment, u64* physAddrOut, int memoryType) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
u64 find_free_pos = 0;
|
||||
|
||||
// iterate through allocated blocked and find the next free position
|
||||
for (const auto& block : m_allocatedBlocks) {
|
||||
u64 n = block.start_addr + block.size;
|
||||
if (n > find_free_pos) {
|
||||
find_free_pos = n;
|
||||
}
|
||||
}
|
||||
|
||||
// align free position
|
||||
find_free_pos = AlignUp(find_free_pos, alignment);
|
||||
|
||||
// if the new position is between searchStart - searchEnd , allocate a new block
|
||||
if (find_free_pos >= searchStart && find_free_pos + len <= searchEnd) {
|
||||
AllocatedBlock block{};
|
||||
block.size = len;
|
||||
block.start_addr = find_free_pos;
|
||||
block.memoryType = memoryType;
|
||||
block.gpu_mode = GPU::MemoryMode::NoAccess;
|
||||
block.map_size = 0;
|
||||
block.map_virtual_addr = 0;
|
||||
block.prot = 0;
|
||||
block.cpu_mode = VirtualMemory::MemoryMode::NoAccess;
|
||||
|
||||
m_allocatedBlocks.push_back(block);
|
||||
|
||||
*physAddrOut = find_free_pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
bool PhysicalMemory::Map(u64 virtual_addr, u64 phys_addr, u64 len, int prot, VirtualMemory::MemoryMode cpu_mode, GPU::MemoryMode gpu_mode) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
for (auto& b : m_allocatedBlocks) {
|
||||
if (phys_addr >= b.start_addr && phys_addr < b.start_addr + b.size) {
|
||||
if (b.map_virtual_addr != 0 || b.map_size != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
b.map_virtual_addr = virtual_addr;
|
||||
b.map_size = len;
|
||||
b.prot = prot;
|
||||
b.cpu_mode = cpu_mode;
|
||||
b.gpu_mode = gpu_mode;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace HLE::Kernel::Objects
|
|
@ -1,34 +0,0 @@
|
|||
#pragma once
|
||||
#include "common/types.h"
|
||||
#include <core/virtual_memory.h>
|
||||
#include <core/PS4/GPU/gpu_memory.h>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
namespace HLE::Kernel::Objects {
|
||||
|
||||
class PhysicalMemory {
|
||||
public:
|
||||
struct AllocatedBlock {
|
||||
u64 start_addr;
|
||||
u64 size;
|
||||
int memoryType;
|
||||
u64 map_virtual_addr;
|
||||
u64 map_size;
|
||||
int prot;
|
||||
VirtualMemory::MemoryMode cpu_mode;
|
||||
GPU::MemoryMode gpu_mode;
|
||||
};
|
||||
PhysicalMemory() {}
|
||||
virtual ~PhysicalMemory() {}
|
||||
|
||||
public:
|
||||
bool Alloc(u64 searchStart, u64 searchEnd, u64 len, u64 alignment, u64* physAddrOut, int memoryType);
|
||||
bool Map(u64 virtual_addr, u64 phys_addr, u64 len, int prot, VirtualMemory::MemoryMode cpu_mode, GPU::MemoryMode gpu_mode);
|
||||
|
||||
private:
|
||||
std::vector<AllocatedBlock> m_allocatedBlocks;
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
} // namespace HLE::Kernel::Objects
|
|
@ -1,125 +0,0 @@
|
|||
#include "ThreadManagement.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
|
||||
#include "../ErrorCodes.h"
|
||||
|
||||
namespace HLE::Libs::LibKernel::ThreadManagement {
|
||||
|
||||
thread_local PthreadInternal* g_pthread_self = nullptr;
|
||||
PThreadCxt* g_pthread_cxt = nullptr;
|
||||
|
||||
void Pthread_Init_Self_MainThread() {
|
||||
g_pthread_self = new PthreadInternal{};
|
||||
scePthreadAttrInit(&g_pthread_self->attr);
|
||||
g_pthread_self->pth = pthread_self();
|
||||
g_pthread_self->name = "Main_Thread";
|
||||
}
|
||||
|
||||
int scePthreadAttrInit(ScePthreadAttr* attr) {
|
||||
*attr = new PthreadAttrInternal{};
|
||||
|
||||
int result = pthread_attr_init(&(*attr)->pth_attr);
|
||||
|
||||
(*attr)->affinity = 0x7f;
|
||||
(*attr)->guard_size = 0x1000;
|
||||
|
||||
SceKernelSchedParam param{};
|
||||
param.sched_priority = 700;
|
||||
|
||||
result = (result == 0 ? scePthreadAttrSetinheritsched(attr, 4) : result);
|
||||
result = (result == 0 ? scePthreadAttrSetschedparam(attr, ¶m) : result);
|
||||
result = (result == 0 ? scePthreadAttrSetschedpolicy(attr, SCHED_OTHER) : result);
|
||||
result = (result == 0 ? scePthreadAttrSetdetachstate(attr, PTHREAD_CREATE_JOINABLE) : result);
|
||||
|
||||
switch (result) {
|
||||
case 0: return SCE_OK;
|
||||
case ENOMEM: return SCE_KERNEL_ERROR_ENOMEM;
|
||||
default: return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int scePthreadAttrSetdetachstate(ScePthreadAttr* attr, int detachstate) {
|
||||
if (attr == nullptr || *attr == nullptr) {
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
int pstate = PTHREAD_CREATE_JOINABLE;
|
||||
switch (detachstate) {
|
||||
case 0: pstate = PTHREAD_CREATE_JOINABLE; break;
|
||||
case 1: pstate = PTHREAD_CREATE_DETACHED; break;
|
||||
default: BREAKPOINT(); // unknown state
|
||||
}
|
||||
|
||||
int result = pthread_attr_setdetachstate(&(*attr)->pth_attr, pstate);
|
||||
|
||||
(*attr)->detached = (pstate == PTHREAD_CREATE_DETACHED);
|
||||
|
||||
if (result == 0) {
|
||||
return SCE_OK;
|
||||
}
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
int scePthreadAttrSetinheritsched(ScePthreadAttr* attr, int inheritSched) {
|
||||
if (attr == nullptr || *attr == nullptr) {
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
int pinherit_sched = PTHREAD_INHERIT_SCHED;
|
||||
switch (inheritSched) {
|
||||
case 0: pinherit_sched = PTHREAD_EXPLICIT_SCHED; break;
|
||||
case 4: pinherit_sched = PTHREAD_INHERIT_SCHED; break;
|
||||
default: BREAKPOINT(); // unknown inheritSched
|
||||
}
|
||||
|
||||
int result = pthread_attr_setinheritsched(&(*attr)->pth_attr, pinherit_sched);
|
||||
|
||||
if (result == 0) {
|
||||
return SCE_OK;
|
||||
}
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
int scePthreadAttrSetschedparam(ScePthreadAttr* attr, const SceKernelSchedParam* param) {
|
||||
if (param == nullptr || attr == nullptr || *attr == nullptr) {
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
SceKernelSchedParam pparam{};
|
||||
if (param->sched_priority <= 478) {
|
||||
pparam.sched_priority = +2;
|
||||
} else if (param->sched_priority >= 733) {
|
||||
pparam.sched_priority = -2;
|
||||
} else {
|
||||
pparam.sched_priority = 0;
|
||||
}
|
||||
|
||||
int result = pthread_attr_setschedparam(&(*attr)->pth_attr, &pparam);
|
||||
|
||||
if (result == 0) {
|
||||
return SCE_OK;
|
||||
}
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
int scePthreadAttrSetschedpolicy(ScePthreadAttr* attr, int policy) {
|
||||
if (attr == nullptr || *attr == nullptr) {
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
if (policy != SCHED_OTHER) {
|
||||
BREAKPOINT(); // invest if policy is other and if winpthreadlibrary support it
|
||||
}
|
||||
|
||||
(*attr)->policy = policy;
|
||||
|
||||
int result = pthread_attr_setschedpolicy(&(*attr)->pth_attr, policy);
|
||||
|
||||
if (result == 0) {
|
||||
return SCE_OK;
|
||||
}
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
}; // namespace HLE::Libs::LibKernel::ThreadManagement
|
|
@ -1,42 +0,0 @@
|
|||
#pragma once
|
||||
#define _TIMESPEC_DEFINED
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include "common/types.h"
|
||||
#include <string>
|
||||
|
||||
namespace HLE::Libs::LibKernel::ThreadManagement {
|
||||
|
||||
struct PthreadAttrInternal;
|
||||
|
||||
using SceKernelSchedParam = ::sched_param;
|
||||
using ScePthreadAttr = PthreadAttrInternal*;
|
||||
|
||||
struct PthreadInternal {
|
||||
u08 reserved[4096];
|
||||
std::string name;
|
||||
pthread_t pth;
|
||||
ScePthreadAttr attr;
|
||||
};
|
||||
struct PthreadAttrInternal {
|
||||
u08 reserved[64];
|
||||
u64 affinity;
|
||||
size_t guard_size;
|
||||
int policy;
|
||||
bool detached;
|
||||
pthread_attr_t pth_attr;
|
||||
};
|
||||
|
||||
class PThreadCxt {};
|
||||
|
||||
void Pthread_Init_Self_MainThread();
|
||||
|
||||
//HLE FUNCTIONS
|
||||
int scePthreadAttrInit(ScePthreadAttr* attr);
|
||||
int scePthreadAttrSetdetachstate(ScePthreadAttr* attr, int detachstate);
|
||||
int scePthreadAttrSetinheritsched(ScePthreadAttr* attr, int inheritSched);
|
||||
int scePthreadAttrSetschedparam(ScePthreadAttr* attr, const SceKernelSchedParam* param);
|
||||
int scePthreadAttrSetschedpolicy(ScePthreadAttr* attr, int policy);
|
||||
|
||||
} // namespace HLE::Libs::LibKernel::ThreadManagement
|
|
@ -1,13 +0,0 @@
|
|||
#include "cpu_management.h"
|
||||
#include "Util/config.h"
|
||||
#include "common/log.h"
|
||||
#include <core/PS4/HLE/Libs.h>
|
||||
|
||||
namespace HLE::Libs::LibKernel::CPUManagement {
|
||||
int PS4_SYSV_ABI sceKernelIsNeoMode() {
|
||||
PRINT_FUNCTION_NAME();
|
||||
bool isNeo = Config::isNeoMode();
|
||||
return isNeo ? 1 : 0;
|
||||
}
|
||||
|
||||
}; // namespace HLE::Libs::LibKernel::CPUManagement
|
|
@ -1,6 +0,0 @@
|
|||
#pragma once
|
||||
#include "common/types.h"
|
||||
|
||||
namespace HLE::Libs::LibKernel::CPUManagement {
|
||||
int PS4_SYSV_ABI sceKernelIsNeoMode();
|
||||
};
|
|
@ -1,66 +0,0 @@
|
|||
#include "event_queues.h"
|
||||
|
||||
#include <core/PS4/HLE/ErrorCodes.h>
|
||||
#include <core/PS4/HLE/Libs.h>
|
||||
#include "common/log.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
namespace HLE::Libs::LibKernel::EventQueues {
|
||||
constexpr bool log_file_equeues = true; // disable it to disable logging
|
||||
|
||||
int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
|
||||
if (eq == nullptr) {
|
||||
LOG_TRACE_IF(log_file_equeues, "sceKernelCreateEqueue returned SCE_KERNEL_ERROR_EINVAL eq invalid\n");
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (name == nullptr) {
|
||||
LOG_TRACE_IF(log_file_equeues, "sceKernelCreateEqueue returned SCE_KERNEL_ERROR_EFAULT name invalid\n");
|
||||
return SCE_KERNEL_ERROR_EFAULT;
|
||||
}
|
||||
if (name == NULL) {
|
||||
LOG_TRACE_IF(log_file_equeues, "sceKernelCreateEqueue returned SCE_KERNEL_ERROR_EINVAL name is null\n");
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
if (strlen(name) > 31) { // max is 32 including null terminator
|
||||
LOG_TRACE_IF(log_file_equeues, "sceKernelCreateEqueue returned SCE_KERNEL_ERROR_ENAMETOOLONG name size exceeds 32 bytes\n");
|
||||
return SCE_KERNEL_ERROR_ENAMETOOLONG;
|
||||
}
|
||||
*eq = new Kernel::Objects::EqueueInternal;
|
||||
|
||||
(*eq)->setName(std::string(name));
|
||||
|
||||
LOG_INFO_IF(log_file_equeues, "sceKernelCreateEqueue created with name \"{}\"\n", name);
|
||||
return SCE_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, HLE::Kernel::Objects::SceKernelEvent* ev, int num, int* out, SceKernelUseconds* timo) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
|
||||
if (eq == nullptr) {
|
||||
return SCE_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
if (ev == nullptr) {
|
||||
return SCE_KERNEL_ERROR_EFAULT;
|
||||
}
|
||||
|
||||
if (num < 1) {
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (timo == nullptr) { // wait until an event arrives without timing out
|
||||
*out = eq->waitForEvents(ev, num, 0);
|
||||
}
|
||||
if (timo != nullptr) {
|
||||
if (*timo == 0) {//only events that have already arrived at the time of this function call can be received
|
||||
BREAKPOINT();
|
||||
} else { // wait until an event arrives with timing out
|
||||
BREAKPOINT();
|
||||
}
|
||||
}
|
||||
return SCE_OK;
|
||||
}
|
||||
|
||||
}; // namespace HLE::Libs::LibKernel::EventQueues
|
|
@ -1,12 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "Objects/event_queue.h"
|
||||
|
||||
namespace HLE::Libs::LibKernel::EventQueues {
|
||||
using SceKernelUseconds = u32;
|
||||
using SceKernelEqueue = Kernel::Objects::EqueueInternal*;
|
||||
|
||||
int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name);
|
||||
int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, HLE::Kernel::Objects::SceKernelEvent* ev, int num, int* out, SceKernelUseconds *timo);
|
||||
|
||||
}; // namespace HLE::Libs::LibKernel::EventQueues
|
|
@ -1,129 +0,0 @@
|
|||
#include "memory_management.h"
|
||||
|
||||
#include <core/PS4/GPU/gpu_memory.h>
|
||||
#include <core/virtual_memory.h>
|
||||
#include "common/log.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
#include <bit>
|
||||
#include <magic_enum.hpp>
|
||||
|
||||
#include "common/singleton.h"
|
||||
#include "../ErrorCodes.h"
|
||||
#include "../Libs.h"
|
||||
#include "Objects/physical_memory.h"
|
||||
|
||||
namespace HLE::Libs::LibKernel::MemoryManagement {
|
||||
|
||||
constexpr bool log_file_memory = true; // disable it to disable logging
|
||||
|
||||
bool isPowerOfTwo(u64 n) { return std::popcount(n) == 1; }
|
||||
|
||||
bool is16KBAligned(u64 n) { return ((n % (16ull * 1024) == 0)); }
|
||||
|
||||
u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize() {
|
||||
PRINT_FUNCTION_NAME();
|
||||
return SCE_KERNEL_MAIN_DMEM_SIZE;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len, u64 alignment, int memoryType, s64* physAddrOut) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
|
||||
if (searchStart < 0 || searchEnd <= searchStart) {
|
||||
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EINVAL searchStart,searchEnd invalid\n");
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
bool isInRange = (searchStart < len && searchEnd > len);
|
||||
if (len <= 0 || !is16KBAligned(len) || !isInRange) {
|
||||
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EINVAL memory range invalid\n");
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if ((alignment != 0 || is16KBAligned(alignment)) && !isPowerOfTwo(alignment)) {
|
||||
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EINVAL alignment invalid\n");
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (physAddrOut == nullptr) {
|
||||
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EINVAL physAddrOut is null\n");
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
auto memtype = magic_enum::enum_cast<MemoryTypes>(memoryType);
|
||||
|
||||
LOG_INFO_IF(log_file_memory, "search_start = {:#x}\n", searchStart);
|
||||
LOG_INFO_IF(log_file_memory, "search_end = {:#x}\n", searchEnd);
|
||||
LOG_INFO_IF(log_file_memory, "len = {:#x}\n", len);
|
||||
LOG_INFO_IF(log_file_memory, "alignment = {:#x}\n", alignment);
|
||||
LOG_INFO_IF(log_file_memory, "memory_type = {}\n", magic_enum::enum_name(memtype.value()));
|
||||
|
||||
u64 physical_addr = 0;
|
||||
auto* physical_memory = Common::Singleton<HLE::Kernel::Objects::PhysicalMemory>::Instance();
|
||||
if (!physical_memory->Alloc(searchStart, searchEnd, len, alignment, &physical_addr, memoryType)) {
|
||||
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EAGAIN can't allocate physical memory\n");
|
||||
return SCE_KERNEL_ERROR_EAGAIN;
|
||||
}
|
||||
*physAddrOut = static_cast<s64>(physical_addr);
|
||||
LOG_INFO_IF(true, "physAddrOut = {:#x}\n", physical_addr);
|
||||
return SCE_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags, s64 directMemoryStart, u64 alignment) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
if (len == 0 || !is16KBAligned(len)) {
|
||||
LOG_TRACE_IF(log_file_memory, "sceKernelMapDirectMemory returned SCE_KERNEL_ERROR_EINVAL len invalid\n");
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (!is16KBAligned(directMemoryStart)) {
|
||||
LOG_TRACE_IF(log_file_memory, "sceKernelMapDirectMemory returned SCE_KERNEL_ERROR_EINVAL directMemoryStart invalid\n");
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (alignment != 0) {
|
||||
if ((!isPowerOfTwo(alignment) && !is16KBAligned(alignment))) {
|
||||
LOG_TRACE_IF(log_file_memory, "sceKernelMapDirectMemory returned SCE_KERNEL_ERROR_EINVAL alignment invalid\n");
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO_IF(log_file_memory, "len = {:#x}\n", len);
|
||||
LOG_INFO_IF(log_file_memory, "prot = {:#x}\n", prot);
|
||||
LOG_INFO_IF(log_file_memory, "flags = {:#x}\n", flags);
|
||||
LOG_INFO_IF(log_file_memory, "directMemoryStart = {:#x}\n", directMemoryStart);
|
||||
LOG_INFO_IF(log_file_memory, "alignment = {:#x}\n", alignment);
|
||||
|
||||
VirtualMemory::MemoryMode cpu_mode = VirtualMemory::MemoryMode::NoAccess;
|
||||
GPU::MemoryMode gpu_mode = GPU::MemoryMode::NoAccess;
|
||||
|
||||
switch (prot) {
|
||||
case 0x32:
|
||||
case 0x33: // SCE_KERNEL_PROT_CPU_READ|SCE_KERNEL_PROT_CPU_WRITE|SCE_KERNEL_PROT_GPU_READ|SCE_KERNEL_PROT_GPU_ALL
|
||||
cpu_mode = VirtualMemory::MemoryMode::ReadWrite;
|
||||
gpu_mode = GPU::MemoryMode::ReadWrite;
|
||||
break;
|
||||
default: BREAKPOINT();
|
||||
}
|
||||
|
||||
auto in_addr = reinterpret_cast<u64>(*addr);
|
||||
u64 out_addr = 0;
|
||||
|
||||
if (flags == 0) {
|
||||
out_addr = VirtualMemory::memory_alloc_aligned(in_addr, len, cpu_mode, alignment);
|
||||
}
|
||||
LOG_INFO_IF(log_file_memory, "in_addr = {:#x}\n", in_addr);
|
||||
LOG_INFO_IF(log_file_memory, "out_addr = {:#x}\n", out_addr);
|
||||
|
||||
*addr = reinterpret_cast<void*>(out_addr); // return out_addr to first functions parameter
|
||||
|
||||
if (out_addr == 0) {
|
||||
return SCE_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
|
||||
auto* physical_memory = Common::Singleton<HLE::Kernel::Objects::PhysicalMemory>::Instance();
|
||||
if (!physical_memory->Map(out_addr, directMemoryStart, len, prot, cpu_mode, gpu_mode)) {
|
||||
BREAKPOINT();
|
||||
}
|
||||
|
||||
if (gpu_mode != GPU::MemoryMode::NoAccess) {
|
||||
GPU::memorySetAllocArea(out_addr, len);
|
||||
}
|
||||
return SCE_OK;
|
||||
}
|
||||
|
||||
} // namespace HLE::Libs::LibKernel::MemoryManagement
|
|
@ -1,36 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
// constants
|
||||
|
||||
constexpr u64 SCE_KERNEL_MAIN_DMEM_SIZE = 5376_MB; // ~ 6GB
|
||||
|
||||
namespace HLE::Libs::LibKernel::MemoryManagement {
|
||||
|
||||
// memory types
|
||||
|
||||
enum MemoryTypes : u32 {
|
||||
SCE_KERNEL_WB_ONION = 0, // write - back mode (Onion bus)
|
||||
SCE_KERNEL_WC_GARLIC = 3, // write - combining mode (Garlic bus)
|
||||
SCE_KERNEL_WB_GARLIC = 10 // write - back mode (Garlic bus)
|
||||
};
|
||||
|
||||
enum MemoryFlags : u32 {
|
||||
SCE_KERNEL_MAP_FIXED = 0x0010, // Fixed
|
||||
SCE_KERNEL_MAP_NO_OVERWRITE = 0x0080,
|
||||
SCE_KERNEL_MAP_NO_COALESCE = 0x400000
|
||||
};
|
||||
enum MemoryProtection : u32 {
|
||||
SCE_KERNEL_PROT_CPU_READ = 0x01, // Permit reads from the CPU
|
||||
SCE_KERNEL_PROT_CPU_RW = 0x02, // Permit reads/writes from the CPU
|
||||
SCE_KERNEL_PROT_CPU_WRITE = 0x02, // Permit reads/writes from the CPU (same)
|
||||
SCE_KERNEL_PROT_GPU_READ = 0x10, // Permit reads from the GPU
|
||||
SCE_KERNEL_PROT_GPU_WRITE = 0x20, // Permit writes from the GPU
|
||||
SCE_KERNEL_PROT_GPU_RW = 0x30 // Permit reads/writes from the GPU
|
||||
};
|
||||
|
||||
u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize();
|
||||
int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len, u64 alignment, int memoryType, s64* physAddrOut);
|
||||
int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags, s64 directMemoryStart, u64 alignment);
|
||||
}; // namespace HLE::Libs::LibKernel::MemoryManagement
|
|
@ -1,49 +0,0 @@
|
|||
#include "LibKernel.h"
|
||||
|
||||
#include "common/log.h"
|
||||
#include "common/debug.h"
|
||||
#include <windows.h>
|
||||
|
||||
#include "common/singleton.h"
|
||||
#include "../Loader/Elf.h"
|
||||
#include "Kernel/Objects/physical_memory.h"
|
||||
#include "Kernel/cpu_management.h"
|
||||
#include "Kernel/event_queues.h"
|
||||
#include "Kernel/memory_management.h"
|
||||
#include "Libs.h"
|
||||
#include "core/hle/libraries/libkernel/file_system.h"
|
||||
#include "core/hle/libraries/libkernel/time_management.h"
|
||||
|
||||
namespace HLE::Libs::LibKernel {
|
||||
|
||||
static u64 g_stack_chk_guard = 0xDEADBEEF54321ABC; // dummy return
|
||||
|
||||
int32_t PS4_SYSV_ABI sceKernelReleaseDirectMemory(off_t start, size_t len) {
|
||||
BREAKPOINT();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PS4_SYSV_ABI void stack_chk_fail() { BREAKPOINT(); }
|
||||
|
||||
int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len) { BREAKPOINT(); }
|
||||
void LibKernel_Register(SymbolsResolver* sym) {
|
||||
// obj
|
||||
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &HLE::Libs::LibKernel::g_stack_chk_guard);
|
||||
// memory
|
||||
LIB_FUNCTION("rTXw65xmLIA", "libkernel", 1, "libkernel", 1, 1, MemoryManagement::sceKernelAllocateDirectMemory);
|
||||
LIB_FUNCTION("pO96TwzOm5E", "libkernel", 1, "libkernel", 1, 1, MemoryManagement::sceKernelGetDirectMemorySize);
|
||||
LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, MemoryManagement::sceKernelMapDirectMemory);
|
||||
LIB_FUNCTION("MBuItvba6z8", "libkernel", 1, "libkernel", 1, 1, sceKernelReleaseDirectMemory);
|
||||
LIB_FUNCTION("cQke9UuBQOk", "libkernel", 1, "libkernel", 1, 1, sceKernelMunmap);
|
||||
// equeue
|
||||
LIB_FUNCTION("D0OdFMjp46I", "libkernel", 1, "libkernel", 1, 1, EventQueues::sceKernelCreateEqueue);
|
||||
LIB_FUNCTION("fzyMKs9kim0", "libkernel", 1, "libkernel", 1, 1, EventQueues::sceKernelWaitEqueue);
|
||||
// misc
|
||||
LIB_FUNCTION("WslcK1FQcGI", "libkernel", 1, "libkernel", 1, 1, CPUManagement::sceKernelIsNeoMode);
|
||||
LIB_FUNCTION("Ou3iL1abvng", "libkernel", 1, "libkernel", 1, 1, stack_chk_fail);
|
||||
|
||||
Core::Libraries::LibKernel::fileSystemSymbolsRegister(sym);
|
||||
Core::Libraries::LibKernel::timeSymbolsRegister(sym);
|
||||
}
|
||||
|
||||
}; // namespace HLE::Libs::LibKernel
|
|
@ -1,10 +0,0 @@
|
|||
#include "../Loader/SymbolsResolver.h"
|
||||
|
||||
namespace HLE::Libs::LibKernel {
|
||||
|
||||
void LibKernel_Register(SymbolsResolver* sym);
|
||||
|
||||
// functions
|
||||
|
||||
int32_t PS4_SYSV_ABI sceKernelReleaseDirectMemory(off_t start, size_t len);
|
||||
}; // namespace HLE::Libs::LibKernel
|
|
@ -1,27 +0,0 @@
|
|||
#include "LibSceGnmDriver.h"
|
||||
#include "Libs.h"
|
||||
#include "../Loader/Elf.h"
|
||||
#include "common/log.h"
|
||||
#include "common/debug.h"
|
||||
#include <core/PS4/GPU/gpu_memory.h>
|
||||
#include <emulator.h>
|
||||
|
||||
namespace HLE::Libs::LibSceGnmDriver {
|
||||
|
||||
int32_t sceGnmSubmitDone()
|
||||
{
|
||||
PRINT_DUMMY_FUNCTION_NAME();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceGnmFlushGarlic() { PRINT_FUNCTION_NAME();
|
||||
GPU::flushGarlic(Emu::getGraphicCtx());
|
||||
}
|
||||
|
||||
void LibSceGnmDriver_Register(SymbolsResolver* sym)
|
||||
{
|
||||
LIB_FUNCTION("yvZ73uQUqrk", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmSubmitDone);
|
||||
LIB_FUNCTION("iBt3Oe00Kvc", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmFlushGarlic);
|
||||
}
|
||||
|
||||
};
|
|
@ -1,9 +0,0 @@
|
|||
#pragma once
|
||||
#include "../Loader/SymbolsResolver.h"
|
||||
|
||||
namespace HLE::Libs::LibSceGnmDriver {
|
||||
|
||||
void LibSceGnmDriver_Register(SymbolsResolver* sym);
|
||||
int32_t sceGnmSubmitDone();
|
||||
void sceGnmFlushGarlic();
|
||||
}; // namespace HLE::Libs::LibSceGnmDriver
|
|
@ -1,23 +0,0 @@
|
|||
#include "Libs.h"
|
||||
|
||||
#include "LibKernel.h"
|
||||
#include "LibSceGnmDriver.h"
|
||||
#include <core/PS4/HLE/Graphics/video_out.h>
|
||||
#include "core/hle/libraries/libuserservice/user_service.h"
|
||||
#include "core/hle/libraries/libpad/pad.h"
|
||||
#include <core/hle/libraries/libsystemservice/system_service.h>
|
||||
#include "core/hle/libraries/libc/libc.h"
|
||||
|
||||
namespace HLE::Libs {
|
||||
|
||||
void Init_HLE_Libs(SymbolsResolver *sym) {
|
||||
|
||||
LibKernel::LibKernel_Register(sym);
|
||||
Graphics::VideoOut::videoOutRegisterLib(sym);
|
||||
LibSceGnmDriver::LibSceGnmDriver_Register(sym);
|
||||
Core::Libraries::LibUserService::userServiceSymbolsRegister(sym);
|
||||
Core::Libraries::LibPad::padSymbolsRegister(sym);
|
||||
Core::Libraries::LibSystemService::systemServiceSymbolsRegister(sym);
|
||||
Core::Libraries::LibC::libcSymbolsRegister(sym);
|
||||
}
|
||||
} // namespace HLE::Libs
|
|
@ -1,43 +0,0 @@
|
|||
#pragma once
|
||||
#include "../Loader/SymbolsResolver.h"
|
||||
#include <core/PS4/Loader/Elf.h>
|
||||
|
||||
#define LIB_FUNCTION(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \
|
||||
{\
|
||||
SymbolRes sr{}; \
|
||||
sr.name = nid; \
|
||||
sr.library = lib; \
|
||||
sr.library_version = libversion;\
|
||||
sr.module = mod;\
|
||||
sr.module_version_major = moduleVersionMajor;\
|
||||
sr.module_version_minor = moduleVersionMinor;\
|
||||
sr.type = STT_FUN;\
|
||||
auto func = reinterpret_cast<u64>(function);\
|
||||
sym->AddSymbol(sr, func);\
|
||||
}
|
||||
|
||||
#define LIB_OBJ(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \
|
||||
{ \
|
||||
SymbolRes sr{}; \
|
||||
sr.name = nid; \
|
||||
sr.library = lib; \
|
||||
sr.library_version = libversion; \
|
||||
sr.module = mod; \
|
||||
sr.module_version_major = moduleVersionMajor; \
|
||||
sr.module_version_minor = moduleVersionMinor; \
|
||||
sr.type = STT_OBJECT; \
|
||||
auto func = reinterpret_cast<u64>(function); \
|
||||
sym->AddSymbol(sr, func); \
|
||||
}
|
||||
|
||||
#define PRINT_FUNCTION_NAME() \
|
||||
{ \
|
||||
LOG_INFO_IF(true, "{}()\n", __func__); \
|
||||
}
|
||||
|
||||
#define PRINT_DUMMY_FUNCTION_NAME() \
|
||||
{ LOG_WARN_IF(true, "dummy {}()\n", __func__); }
|
||||
|
||||
namespace HLE::Libs {
|
||||
void Init_HLE_Libs(SymbolsResolver* sym);
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
//constants
|
||||
|
||||
constexpr int SCE_USER_SERVICE_MAX_LOGIN_USERS = 4; //max users logged in at once
|
||||
constexpr int SCE_USER_SERVICE_MAX_USER_NAME_LENGTH = 16;//Max length for user name
|
||||
|
||||
constexpr int SCE_USER_SERVICE_USER_ID_INVALID = -1;//invalid user ID
|
||||
constexpr int SCE_USER_SERVICE_USER_ID_SYSTEM = 255; //generic id for device
|
||||
constexpr int SCE_USER_SERVICE_USER_ID_EVERYONE = 254; // generic id for user (mostly used in common dialogs)
|
||||
|
||||
|
|
@ -1,664 +0,0 @@
|
|||
#include "Linker.h"
|
||||
#include "../virtual_memory.h"
|
||||
#include "common/log.h"
|
||||
#include <fmt/core.h>
|
||||
#include <Zydis/Zydis.h>
|
||||
#include "common/string_util.h"
|
||||
#include "Util/aerolib.h"
|
||||
#include "Loader/SymbolsResolver.h"
|
||||
#include "HLE/Kernel/ThreadManagement.h"
|
||||
#include "Stubs.h"
|
||||
|
||||
constexpr bool debug_loader = true;
|
||||
|
||||
static u64 g_load_addr = SYSTEM_RESERVED + CODE_BASE_OFFSET;
|
||||
|
||||
static u64 get_aligned_size(const elf_program_header& phdr)
|
||||
{
|
||||
return (phdr.p_align != 0 ? (phdr.p_memsz + (phdr.p_align - 1)) & ~(phdr.p_align - 1) : phdr.p_memsz);
|
||||
}
|
||||
|
||||
static u64 calculate_base_size(const elf_header& ehdr, std::span<const elf_program_header> phdr)
|
||||
{
|
||||
u64 base_size = 0;
|
||||
for (u16 i = 0; i < ehdr.e_phnum; i++)
|
||||
{
|
||||
if (phdr[i].p_memsz != 0 && (phdr[i].p_type == PT_LOAD || phdr[i].p_type == PT_SCE_RELRO))
|
||||
{
|
||||
u64 last_addr = phdr[i].p_vaddr + get_aligned_size(phdr[i]);
|
||||
if (last_addr > base_size)
|
||||
{
|
||||
base_size = last_addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return base_size;
|
||||
}
|
||||
|
||||
static std::string encodeId(u64 nVal)
|
||||
{
|
||||
std::string enc;
|
||||
const char pCodes[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
|
||||
if (nVal < 0x40u)
|
||||
{
|
||||
enc += pCodes[nVal];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nVal < 0x1000u)
|
||||
{
|
||||
enc += pCodes[static_cast<u16>(nVal >> 6u) & 0x3fu];
|
||||
enc += pCodes[nVal & 0x3fu];
|
||||
}
|
||||
else
|
||||
{
|
||||
enc += pCodes[static_cast<u16>(nVal >> 12u) & 0x3fu];
|
||||
enc += pCodes[static_cast<u16>(nVal >> 6u) & 0x3fu];
|
||||
enc += pCodes[nVal & 0x3fu];
|
||||
}
|
||||
}
|
||||
return enc;
|
||||
}
|
||||
|
||||
Linker::Linker() = default;
|
||||
|
||||
Linker::~Linker() = default;
|
||||
|
||||
Module* Linker::LoadModule(const std::string& elf_name)
|
||||
{
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
auto& m = m_modules.emplace_back();
|
||||
m.linker = this;
|
||||
m.elf.Open(elf_name);
|
||||
|
||||
if (m.elf.isElfFile()) {
|
||||
LoadModuleToMemory(&m);
|
||||
LoadDynamicInfo(&m);
|
||||
LoadSymbols(&m);
|
||||
Relocate(&m);
|
||||
} else {
|
||||
m_modules.pop_back();
|
||||
return nullptr; // It is not a valid elf file //TODO check it why!
|
||||
}
|
||||
|
||||
return &m;
|
||||
}
|
||||
|
||||
Module* Linker::FindModule(/*u32 id*/)
|
||||
{
|
||||
// TODO atm we only have 1 module so we don't need to iterate on vector
|
||||
if (m_modules.empty()) [[unlikely]] {
|
||||
return nullptr;
|
||||
}
|
||||
return &m_modules[0];
|
||||
}
|
||||
|
||||
void Linker::LoadModuleToMemory(Module* m)
|
||||
{
|
||||
//get elf header, program header
|
||||
const auto elf_header = m->elf.GetElfHeader();
|
||||
const auto elf_pheader = m->elf.GetProgramHeader();
|
||||
|
||||
u64 base_size = calculate_base_size(elf_header, elf_pheader);
|
||||
m->aligned_base_size = (base_size & ~(static_cast<u64>(0x1000) - 1)) + 0x1000;//align base size to 0x1000 block size (TODO is that the default block size or it can be changed?
|
||||
|
||||
m->base_virtual_addr = VirtualMemory::memory_alloc(g_load_addr, m->aligned_base_size, VirtualMemory::MemoryMode::ExecuteReadWrite);
|
||||
|
||||
LOG_INFO_IF(debug_loader, "====Load Module to Memory ========\n");
|
||||
LOG_INFO_IF(debug_loader, "base_virtual_addr ......: {:#018x}\n", m->base_virtual_addr);
|
||||
LOG_INFO_IF(debug_loader, "base_size ..............: {:#018x}\n", base_size);
|
||||
LOG_INFO_IF(debug_loader, "aligned_base_size ......: {:#018x}\n", m->aligned_base_size);
|
||||
|
||||
for (u16 i = 0; i < elf_header.e_phnum; i++)
|
||||
{
|
||||
switch (elf_pheader[i].p_type)
|
||||
{
|
||||
case PT_LOAD:
|
||||
case PT_SCE_RELRO:
|
||||
if (elf_pheader[i].p_memsz != 0)
|
||||
{
|
||||
u64 segment_addr = elf_pheader[i].p_vaddr + m->base_virtual_addr;
|
||||
u64 segment_file_size = elf_pheader[i].p_filesz;
|
||||
u64 segment_memory_size = get_aligned_size(elf_pheader[i]);
|
||||
auto segment_mode = m->elf.ElfPheaderFlagsStr(elf_pheader[i].p_flags);
|
||||
LOG_INFO_IF(debug_loader, "program header = [{}] type = {}\n",i,m->elf.ElfPheaderTypeStr(elf_pheader[i].p_type));
|
||||
LOG_INFO_IF(debug_loader, "segment_addr ..........: {:#018x}\n", segment_addr);
|
||||
LOG_INFO_IF(debug_loader, "segment_file_size .....: {}\n", segment_file_size);
|
||||
LOG_INFO_IF(debug_loader, "segment_memory_size ...: {}\n", segment_memory_size);
|
||||
LOG_INFO_IF(debug_loader, "segment_mode ..........: {}\n", segment_mode);
|
||||
|
||||
m->elf.LoadSegment(segment_addr, elf_pheader[i].p_offset, segment_file_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR_IF(debug_loader, "p_memsz==0 in type {}\n", m->elf.ElfPheaderTypeStr(elf_pheader[i].p_type));
|
||||
}
|
||||
break;
|
||||
case PT_DYNAMIC:
|
||||
if (elf_pheader[i].p_filesz != 0)
|
||||
{
|
||||
m->m_dynamic.resize(elf_pheader[i].p_filesz);
|
||||
m->elf.LoadSegment(reinterpret_cast<u64>(m->m_dynamic.data()), elf_pheader[i].p_offset, elf_pheader[i].p_filesz);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR_IF(debug_loader, "p_filesz==0 in type {}\n", m->elf.ElfPheaderTypeStr(elf_pheader[i].p_type));
|
||||
}
|
||||
break;
|
||||
case PT_SCE_DYNLIBDATA:
|
||||
if (elf_pheader[i].p_filesz != 0)
|
||||
{
|
||||
m->m_dynamic_data.resize(elf_pheader[i].p_filesz);
|
||||
m->elf.LoadSegment(reinterpret_cast<u64>(m->m_dynamic_data.data()), elf_pheader[i].p_offset, elf_pheader[i].p_filesz);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR_IF(debug_loader, "p_filesz==0 in type {}\n", m->elf.ElfPheaderTypeStr(elf_pheader[i].p_type));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR_IF(debug_loader, "Unimplemented type {}\n", m->elf.ElfPheaderTypeStr(elf_pheader[i].p_type));
|
||||
}
|
||||
}
|
||||
LOG_INFO_IF(debug_loader, "program entry addr ..........: {:#018x}\n", m->elf.GetElfEntry() + m->base_virtual_addr);
|
||||
|
||||
auto* rt1 = reinterpret_cast<uint8_t*>(m->elf.GetElfEntry() + m->base_virtual_addr);
|
||||
ZyanU64 runtime_address = m->elf.GetElfEntry() + m->base_virtual_addr;
|
||||
|
||||
// Loop over the instructions in our buffer.
|
||||
ZyanUSize offset = 0;
|
||||
ZydisDisassembledInstruction instruction;
|
||||
while (ZYAN_SUCCESS(ZydisDisassembleIntel(
|
||||
/* machine_mode: */ ZYDIS_MACHINE_MODE_LONG_64,
|
||||
/* runtime_address: */ runtime_address,
|
||||
/* buffer: */ rt1 + offset,
|
||||
/* length: */ sizeof(rt1) - offset,
|
||||
/* instruction: */ &instruction
|
||||
))) {
|
||||
fmt::print("{:#x}" PRIX64 " {}\n", runtime_address, instruction.text);
|
||||
offset += instruction.info.length;
|
||||
runtime_address += instruction.info.length;
|
||||
}
|
||||
}
|
||||
|
||||
void Linker::LoadDynamicInfo(Module* m)
|
||||
{
|
||||
for (const auto* dyn = reinterpret_cast<elf_dynamic*>(m->m_dynamic.data()); dyn->d_tag != DT_NULL; dyn++)
|
||||
{
|
||||
switch (dyn->d_tag)
|
||||
{
|
||||
case DT_SCE_HASH: //Offset of the hash table.
|
||||
m->dynamic_info.hash_table = reinterpret_cast<void*>(m->m_dynamic_data.data() + dyn->d_un.d_ptr);
|
||||
break;
|
||||
case DT_SCE_HASHSZ: //Size of the hash table
|
||||
m->dynamic_info.hash_table_size = dyn->d_un.d_val;
|
||||
break;
|
||||
case DT_SCE_STRTAB://Offset of the string table.
|
||||
m->dynamic_info.str_table = reinterpret_cast<char*>(m->m_dynamic_data.data() + dyn->d_un.d_ptr);
|
||||
break;
|
||||
case DT_SCE_STRSZ: //Size of the string table.
|
||||
m->dynamic_info.str_table_size = dyn->d_un.d_val;
|
||||
break;
|
||||
case DT_SCE_SYMTAB://Offset of the symbol table.
|
||||
m->dynamic_info.symbol_table = reinterpret_cast<elf_symbol*>(m->m_dynamic_data.data() + dyn->d_un.d_ptr);
|
||||
break;
|
||||
case DT_SCE_SYMTABSZ://Size of the symbol table.
|
||||
m->dynamic_info.symbol_table_total_size = dyn->d_un.d_val;
|
||||
break;
|
||||
case DT_INIT:
|
||||
m->dynamic_info.init_virtual_addr = dyn->d_un.d_ptr;
|
||||
break;
|
||||
case DT_FINI:
|
||||
m->dynamic_info.fini_virtual_addr = dyn->d_un.d_ptr;
|
||||
break;
|
||||
case DT_SCE_PLTGOT: //Offset of the global offset table.
|
||||
m->dynamic_info.pltgot_virtual_addr = dyn->d_un.d_ptr;
|
||||
break;
|
||||
case DT_SCE_JMPREL: //Offset of the table containing jump slots.
|
||||
m->dynamic_info.jmp_relocation_table = reinterpret_cast<elf_relocation*>(m->m_dynamic_data.data() + dyn->d_un.d_ptr);
|
||||
break;
|
||||
case DT_SCE_PLTRELSZ: //Size of the global offset table.
|
||||
m->dynamic_info.jmp_relocation_table_size = dyn->d_un.d_val;
|
||||
break;
|
||||
case DT_SCE_PLTREL: //The type of relocations in the relocation table. Should be DT_RELA
|
||||
m->dynamic_info.jmp_relocation_type = dyn->d_un.d_val;
|
||||
if (m->dynamic_info.jmp_relocation_type != DT_RELA)
|
||||
{
|
||||
LOG_WARN_IF(debug_loader, "DT_SCE_PLTREL is NOT DT_RELA should check!");
|
||||
}
|
||||
break;
|
||||
case DT_SCE_RELA: //Offset of the relocation table.
|
||||
m->dynamic_info.relocation_table = reinterpret_cast<elf_relocation*>(m->m_dynamic_data.data() + dyn->d_un.d_ptr);
|
||||
break;
|
||||
case DT_SCE_RELASZ: //Size of the relocation table.
|
||||
m->dynamic_info.relocation_table_size = dyn->d_un.d_val;
|
||||
break;
|
||||
case DT_SCE_RELAENT : //The size of relocation table entries.
|
||||
m->dynamic_info.relocation_table_entries_size = dyn->d_un.d_val;
|
||||
if (m->dynamic_info.relocation_table_entries_size != 0x18) //this value should always be 0x18
|
||||
{
|
||||
LOG_WARN_IF(debug_loader, "DT_SCE_RELAENT is NOT 0x18 should check!");
|
||||
}
|
||||
break;
|
||||
case DT_INIT_ARRAY:// Address of the array of pointers to initialization functions
|
||||
m->dynamic_info.init_array_virtual_addr = dyn->d_un.d_ptr;
|
||||
break;
|
||||
case DT_FINI_ARRAY: // Address of the array of pointers to termination functions
|
||||
m->dynamic_info.fini_array_virtual_addr = dyn->d_un.d_ptr;
|
||||
break;
|
||||
case DT_INIT_ARRAYSZ://Size in bytes of the array of initialization functions
|
||||
m->dynamic_info.init_array_size = dyn->d_un.d_val;
|
||||
break;
|
||||
case DT_FINI_ARRAYSZ://Size in bytes of the array of terminationfunctions
|
||||
m->dynamic_info.fini_array_size = dyn->d_un.d_val;
|
||||
break;
|
||||
case DT_PREINIT_ARRAY://Address of the array of pointers to pre - initialization functions
|
||||
m->dynamic_info.preinit_array_virtual_addr = dyn->d_un.d_ptr;
|
||||
break;
|
||||
case DT_PREINIT_ARRAYSZ://Size in bytes of the array of pre - initialization functions
|
||||
m->dynamic_info.preinit_array_size = dyn->d_un.d_val;
|
||||
break;
|
||||
case DT_SCE_SYMENT: //The size of symbol table entries
|
||||
m->dynamic_info.symbol_table_entries_size = dyn->d_un.d_val;
|
||||
if (m->dynamic_info.symbol_table_entries_size != 0x18) //this value should always be 0x18
|
||||
{
|
||||
LOG_WARN_IF(debug_loader, "DT_SCE_SYMENT is NOT 0x18 should check!");
|
||||
}
|
||||
break;
|
||||
case DT_DEBUG:
|
||||
m->dynamic_info.debug = dyn->d_un.d_val;
|
||||
break;
|
||||
case DT_TEXTREL:
|
||||
m->dynamic_info.textrel = dyn->d_un.d_val;
|
||||
break;
|
||||
case DT_FLAGS:
|
||||
m->dynamic_info.flags = dyn->d_un.d_val;
|
||||
if (m->dynamic_info.flags != 0x04) //this value should always be DF_TEXTREL (0x04)
|
||||
{
|
||||
LOG_WARN_IF(debug_loader, "DT_FLAGS is NOT 0x04 should check!");
|
||||
}
|
||||
break;
|
||||
case DT_NEEDED://Offset of the library string in the string table to be linked in.
|
||||
if (m->dynamic_info.str_table != nullptr)//in theory this should already be filled from about just make a test case
|
||||
{
|
||||
m->dynamic_info.needed.push_back(m->dynamic_info.str_table + dyn->d_un.d_val);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR_IF(debug_loader, "DT_NEEDED str table is not loaded should check!");
|
||||
}
|
||||
break;
|
||||
case DT_SCE_NEEDED_MODULE:
|
||||
{
|
||||
ModuleInfo info{};
|
||||
info.value = dyn->d_un.d_val;
|
||||
info.name = m->dynamic_info.str_table + info.name_offset;
|
||||
info.enc_id = encodeId(info.id);
|
||||
m->dynamic_info.import_modules.push_back(info);
|
||||
}
|
||||
break;
|
||||
case DT_SCE_IMPORT_LIB:
|
||||
{
|
||||
LibraryInfo info{};
|
||||
info.value = dyn->d_un.d_val;
|
||||
info.name = m->dynamic_info.str_table + info.name_offset;
|
||||
info.enc_id = encodeId(info.id);
|
||||
m->dynamic_info.import_libs.push_back(info);
|
||||
}
|
||||
break;
|
||||
case DT_SCE_FINGERPRINT:
|
||||
//The fingerprint is a 24 byte (0x18) size buffer that contains a unique identifier for the given app.
|
||||
//How exactly this is generated isn't known, however it is not necessary to have a valid fingerprint.
|
||||
//While an invalid fingerprint will cause a warning to be printed to the kernel log, the ELF will still load and run.
|
||||
LOG_INFO_IF(debug_loader, "unsupported DT_SCE_FINGERPRINT value = ..........: {:#018x}\n", dyn->d_un.d_val);
|
||||
break;
|
||||
case DT_SCE_IMPORT_LIB_ATTR:
|
||||
//The upper 32-bits should contain the module index multiplied by 0x10000. The lower 32-bits should be a constant 0x9.
|
||||
LOG_INFO_IF(debug_loader, "unsupported DT_SCE_IMPORT_LIB_ATTR value = ..........: {:#018x}\n", dyn->d_un.d_val);
|
||||
break;
|
||||
case DT_SCE_ORIGINAL_FILENAME:
|
||||
m->dynamic_info.filename = m->dynamic_info.str_table + dyn->d_un.d_val;
|
||||
break;
|
||||
case DT_SCE_MODULE_INFO://probably only useable in shared modules
|
||||
{
|
||||
ModuleInfo info{};
|
||||
info.value = dyn->d_un.d_val;
|
||||
info.name = m->dynamic_info.str_table + info.name_offset;
|
||||
info.enc_id = encodeId(info.id);
|
||||
m->dynamic_info.export_modules.push_back(info);
|
||||
}
|
||||
break;
|
||||
case DT_SCE_MODULE_ATTR:
|
||||
//TODO?
|
||||
LOG_INFO_IF(debug_loader, "unsupported DT_SCE_MODULE_ATTR value = ..........: {:#018x}\n", dyn->d_un.d_val);
|
||||
break;
|
||||
case DT_SCE_EXPORT_LIB:
|
||||
{
|
||||
LibraryInfo info{};
|
||||
info.value = dyn->d_un.d_val;
|
||||
info.name = m->dynamic_info.str_table + info.name_offset;
|
||||
info.enc_id = encodeId(info.id);
|
||||
m->dynamic_info.export_libs.push_back(info);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_INFO_IF(debug_loader, "unsupported dynamic tag ..........: {:#018x}\n", dyn->d_tag);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const ModuleInfo* Linker::FindModule(const Module& m, const std::string& id)
|
||||
{
|
||||
const auto& import_modules = m.dynamic_info.import_modules;
|
||||
int index = 0;
|
||||
for (const auto& mod : import_modules)
|
||||
{
|
||||
if (mod.enc_id.compare(id) == 0)
|
||||
{
|
||||
return &import_modules.at(index);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
const auto& export_modules = m.dynamic_info.export_modules;
|
||||
index = 0;
|
||||
for (const auto& mod : export_modules)
|
||||
{
|
||||
if (mod.enc_id.compare(id) == 0)
|
||||
{
|
||||
return &export_modules.at(index);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const LibraryInfo* Linker::FindLibrary(const Module& m, const std::string& id)
|
||||
{
|
||||
const auto& import_libs = m.dynamic_info.import_libs;
|
||||
int index = 0;
|
||||
for (const auto& lib : import_libs)
|
||||
{
|
||||
if (lib.enc_id.compare(id) == 0)
|
||||
{
|
||||
return &import_libs.at(index);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
const auto& export_libs = m.dynamic_info.export_libs;
|
||||
index = 0;
|
||||
for (const auto& lib : export_libs)
|
||||
{
|
||||
if (lib.enc_id.compare(id) == 0)
|
||||
{
|
||||
return &export_libs.at(index);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Linker::LoadSymbols(Module* m)
|
||||
{
|
||||
if (m->dynamic_info.symbol_table == nullptr || m->dynamic_info.str_table == nullptr || m->dynamic_info.symbol_table_total_size==0)
|
||||
{
|
||||
LOG_INFO_IF(debug_loader, "Symbol table not found!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto* sym = m->dynamic_info.symbol_table;
|
||||
reinterpret_cast<uint8_t*>(sym) < reinterpret_cast<uint8_t*>(m->dynamic_info.symbol_table) + m->dynamic_info.symbol_table_total_size;
|
||||
sym++)
|
||||
{
|
||||
std::string id = std::string(m->dynamic_info.str_table + sym->st_name);
|
||||
const auto ids = Common::SplitString(id, '#');
|
||||
if (ids.size() == 3)//symbols are 3 parts name , library , module
|
||||
{
|
||||
const auto* library = FindLibrary(*m, ids.at(1));
|
||||
const auto* module = FindModule(*m, ids.at(2));
|
||||
auto bind = sym->GetBind();
|
||||
auto type = sym->GetType();
|
||||
auto visibility = sym->GetVisibility();
|
||||
if (library != nullptr || module != nullptr)
|
||||
{
|
||||
switch (bind)
|
||||
{
|
||||
case STB_GLOBAL:
|
||||
case STB_WEAK:
|
||||
break;
|
||||
default:
|
||||
LOG_INFO_IF(debug_loader, "Unsupported bind {} for name symbol {} \n", bind,ids.at(0));
|
||||
continue;
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
case STT_OBJECT:
|
||||
case STT_FUN:
|
||||
break;
|
||||
default:
|
||||
LOG_INFO_IF(debug_loader, "Unsupported type {} for name symbol {} \n", type, ids.at(0));
|
||||
continue;
|
||||
}
|
||||
switch (visibility)
|
||||
{
|
||||
case STV_DEFAULT:
|
||||
break;
|
||||
default:
|
||||
LOG_INFO_IF(debug_loader, "Unsupported visibility {} for name symbol {} \n", visibility, ids.at(0));
|
||||
continue;
|
||||
}
|
||||
//if st_value!=0 then it's export symbol
|
||||
bool is_sym_export = sym->st_value != 0;
|
||||
std::string nidName = "";
|
||||
|
||||
auto aeronid = aerolib::find_by_nid(ids.at(0).c_str());
|
||||
|
||||
if (aeronid != nullptr)
|
||||
{
|
||||
nidName = aeronid->name;
|
||||
}
|
||||
else
|
||||
{
|
||||
nidName = "UNK";
|
||||
}
|
||||
|
||||
SymbolRes sym_r{};
|
||||
sym_r.name = ids.at(0);
|
||||
sym_r.nidName = nidName;
|
||||
sym_r.library = library->name;
|
||||
sym_r.library_version = library->version;
|
||||
sym_r.module = module->name;
|
||||
sym_r.module_version_major = module->version_major;
|
||||
sym_r.module_version_minor = module->version_minor;
|
||||
sym_r.type = type;
|
||||
|
||||
if (is_sym_export)
|
||||
{
|
||||
m->export_sym.AddSymbol(sym_r, sym->st_value + m->base_virtual_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
m->import_sym.AddSymbol(sym_r,0);
|
||||
}
|
||||
|
||||
|
||||
LOG_INFO_IF(debug_loader, "name {} function {} library {} module {} bind {} type {} visibility {}\n", ids.at(0),nidName,library->name, module->name, bind, type, visibility);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
static void relocate(u32 idx, elf_relocation* rel, Module* m, bool isJmpRel) {
|
||||
auto type = rel->GetType();
|
||||
auto symbol = rel->GetSymbol();
|
||||
auto addend = rel->rel_addend;
|
||||
auto* symbolsTlb = m->dynamic_info.symbol_table;
|
||||
auto* namesTlb = m->dynamic_info.str_table;
|
||||
|
||||
u64 rel_value = 0;
|
||||
u64 rel_base_virtual_addr = m->base_virtual_addr;
|
||||
u64 rel_virtual_addr = m->base_virtual_addr + rel->rel_offset;
|
||||
bool rel_isResolved = false;
|
||||
u08 rel_sym_type = 0;
|
||||
std::string rel_name;
|
||||
|
||||
switch (type) {
|
||||
case R_X86_64_RELATIVE:
|
||||
if (symbol != 0) // should be always zero
|
||||
{
|
||||
LOG_INFO_IF(debug_loader, "R_X86_64_RELATIVE symbol not zero = {:#010x}\n", type, symbol);
|
||||
}
|
||||
rel_value = rel_base_virtual_addr + addend;
|
||||
rel_isResolved = true;
|
||||
break;
|
||||
case R_X86_64_64:
|
||||
case R_X86_64_JUMP_SLOT: // similar but addend is not take into account
|
||||
{
|
||||
auto sym = symbolsTlb[symbol];
|
||||
auto sym_bind = sym.GetBind();
|
||||
auto sym_type = sym.GetType();
|
||||
auto sym_visibility = sym.GetVisibility();
|
||||
u64 symbol_vitrual_addr = 0;
|
||||
SymbolRecord symrec{};
|
||||
switch (sym_type) {
|
||||
case STT_FUN: rel_sym_type = 2; break;
|
||||
case STT_OBJECT: rel_sym_type = 1; break;
|
||||
default: LOG_INFO_IF(debug_loader, "unknown symbol type {}\n", sym_type);
|
||||
}
|
||||
if (sym_visibility != 0) // should be zero log if else
|
||||
{
|
||||
LOG_INFO_IF(debug_loader, "symbol visilibity !=0\n");
|
||||
}
|
||||
switch (sym_bind) {
|
||||
case STB_GLOBAL:
|
||||
rel_name = namesTlb + sym.st_name;
|
||||
m->linker->Resolve(rel_name, rel_sym_type, m, &symrec);
|
||||
symbol_vitrual_addr = symrec.virtual_address;
|
||||
rel_isResolved = (symbol_vitrual_addr != 0);
|
||||
|
||||
rel_name = symrec.name;
|
||||
if (type == R_X86_64_JUMP_SLOT) {
|
||||
addend = 0;
|
||||
}
|
||||
rel_value = (rel_isResolved ? symbol_vitrual_addr + addend : 0);
|
||||
if (!rel_isResolved) {
|
||||
LOG_INFO_IF(debug_loader, "R_X86_64_64-R_X86_64_JUMP_SLOT sym_type {} bind STB_GLOBAL symbol : {:#010x}\n", sym_type, symbol);
|
||||
}
|
||||
break;
|
||||
default: LOG_INFO_IF(debug_loader, "UNK bind {}\n", sym_bind);
|
||||
}
|
||||
|
||||
} break;
|
||||
default: LOG_INFO_IF(debug_loader, "UNK type {:#010x} rel symbol : {:#010x}\n", type, symbol);
|
||||
}
|
||||
|
||||
if (rel_isResolved) {
|
||||
VirtualMemory::memory_patch(rel_virtual_addr, rel_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_INFO_IF(debug_loader, "function not patched! {}\n",rel_name);
|
||||
}
|
||||
}
|
||||
|
||||
void Linker::Relocate(Module* m)
|
||||
{
|
||||
u32 idx = 0;
|
||||
for (auto* rel = m->dynamic_info.relocation_table; reinterpret_cast<u08*>(rel) < reinterpret_cast<u08*>(m->dynamic_info.relocation_table) + m->dynamic_info.relocation_table_size; rel++, idx++)
|
||||
{
|
||||
relocate(idx, rel, m, false);
|
||||
}
|
||||
idx = 0;
|
||||
for (auto* rel = m->dynamic_info.jmp_relocation_table; reinterpret_cast<u08*>(rel) < reinterpret_cast<u08*>(m->dynamic_info.jmp_relocation_table) + m->dynamic_info.jmp_relocation_table_size; rel++, idx++)
|
||||
{
|
||||
relocate(idx, rel, m, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Linker::Resolve(const std::string& name, int Symtype, Module* m, SymbolRecord* return_info) {
|
||||
const auto ids = Common::SplitString(name, '#');
|
||||
if (ids.size() == 3) // symbols are 3 parts name , library , module
|
||||
{
|
||||
const auto* library = FindLibrary(*m, ids.at(1));
|
||||
const auto* module = FindModule(*m, ids.at(2));
|
||||
|
||||
if (library != nullptr && module != nullptr) {
|
||||
SymbolRes sr{};
|
||||
sr.name = ids.at(0);
|
||||
sr.library = library->name;
|
||||
sr.library_version = library->version;
|
||||
sr.module = module->name;
|
||||
sr.module_version_major = module->version_major;
|
||||
sr.module_version_minor = module->version_minor;
|
||||
sr.type = Symtype;
|
||||
|
||||
const SymbolRecord* rec = nullptr;
|
||||
rec = m_hle_symbols.FindSymbol(sr);
|
||||
|
||||
if (rec != nullptr) {
|
||||
*return_info = *rec;
|
||||
} else {
|
||||
auto aeronid = aerolib::find_by_nid(sr.name.c_str());
|
||||
if (aeronid) {
|
||||
return_info->name = aeronid->name;
|
||||
return_info->virtual_address = GetStub(aeronid->nid);
|
||||
} else {
|
||||
return_info->virtual_address = GetStub(sr.name.c_str());
|
||||
return_info->name = "Unknown !!!";
|
||||
}
|
||||
LOG_ERROR_IF(debug_loader, "Linker: Stub resolved {} as {} (lib: {}, mod: {}) \n", sr.name, return_info->name, library->name, module->name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
__debugbreak();//den tha prepei na ftasoume edo
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
__debugbreak();//oute edo mallon
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
using exit_func_t = PS4_SYSV_ABI void (*)();
|
||||
using entry_func_t = PS4_SYSV_ABI void (*)(EntryParams* params, exit_func_t atexit_func);
|
||||
|
||||
static PS4_SYSV_ABI void ProgramExitFunc() {
|
||||
fmt::print("exit function called\n");
|
||||
}
|
||||
|
||||
static void run_main_entry(u64 addr, EntryParams* params, exit_func_t exit_func) {
|
||||
//reinterpret_cast<entry_func_t>(addr)(params, exit_func); // can't be used, stack has to have a specific layout
|
||||
|
||||
asm volatile (
|
||||
"andq $-16, %%rsp\n"// Align to 16 bytes
|
||||
"subq $8, %%rsp\n" // videoout_basic expects the stack to be misaligned
|
||||
|
||||
// Kernel also pushes some more things here during process init
|
||||
// at least: environment, auxv, possibly other things
|
||||
|
||||
"pushq 8(%1)\n" // copy EntryParams to top of stack like the kernel does
|
||||
"pushq 0(%1)\n" // OpenOrbis expects to find it there
|
||||
|
||||
"movq %1, %%rdi\n" // also pass params and exit func
|
||||
"movq %2, %%rsi\n" // as before
|
||||
|
||||
"jmp *%0\n" // can't use call here, as that would mangle the prepared stack.
|
||||
// there's no coming back
|
||||
:
|
||||
: "r"(addr), "r"(params), "r"(exit_func)
|
||||
: "rax", "rsi", "rdi", "rsp", "rbp"
|
||||
);
|
||||
}
|
||||
|
||||
void Linker::Execute()
|
||||
{
|
||||
HLE::Libs::LibKernel::ThreadManagement::Pthread_Init_Self_MainThread();
|
||||
EntryParams p{};
|
||||
p.argc = 1;
|
||||
p.argv[0] = "eboot.bin"; //hmm should be ok?
|
||||
|
||||
const auto& module = m_modules.at(0);
|
||||
run_main_entry(module.elf.GetElfEntry() + module.base_virtual_addr, &p, ProgramExitFunc);
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include "Loader/Elf.h"
|
||||
#include "Loader/SymbolsResolver.h"
|
||||
|
||||
struct DynamicModuleInfo;
|
||||
class Linker;
|
||||
|
||||
struct EntryParams {
|
||||
int argc;
|
||||
u32 padding;
|
||||
const char* argv[3];
|
||||
};
|
||||
|
||||
struct ModuleInfo
|
||||
{
|
||||
std::string name;
|
||||
union
|
||||
{
|
||||
u64 value;
|
||||
struct
|
||||
{
|
||||
u32 name_offset;
|
||||
u08 version_minor;
|
||||
u08 version_major;
|
||||
u16 id;
|
||||
};
|
||||
};
|
||||
std::string enc_id;
|
||||
};
|
||||
|
||||
struct LibraryInfo
|
||||
{
|
||||
std::string name;
|
||||
union
|
||||
{
|
||||
u64 value;
|
||||
struct
|
||||
{
|
||||
u32 name_offset;
|
||||
u16 version;
|
||||
u16 id;
|
||||
};
|
||||
};
|
||||
std::string enc_id;
|
||||
};
|
||||
|
||||
struct DynamicModuleInfo
|
||||
{
|
||||
void* hash_table = nullptr;
|
||||
u64 hash_table_size = 0;
|
||||
|
||||
char* str_table = nullptr;
|
||||
u64 str_table_size = 0;
|
||||
|
||||
elf_symbol* symbol_table = nullptr;
|
||||
u64 symbol_table_total_size = 0;
|
||||
u64 symbol_table_entries_size = 0;
|
||||
|
||||
u64 init_virtual_addr = 0;
|
||||
u64 fini_virtual_addr = 0;
|
||||
u64 pltgot_virtual_addr = 0;
|
||||
u64 init_array_virtual_addr = 0;
|
||||
u64 fini_array_virtual_addr = 0;
|
||||
u64 preinit_array_virtual_addr = 0;
|
||||
u64 init_array_size = 0;
|
||||
u64 fini_array_size = 0;
|
||||
u64 preinit_array_size = 0;
|
||||
|
||||
elf_relocation* jmp_relocation_table = nullptr;
|
||||
u64 jmp_relocation_table_size = 0;
|
||||
s64 jmp_relocation_type = 0;
|
||||
|
||||
elf_relocation* relocation_table = nullptr;
|
||||
u64 relocation_table_size = 0;
|
||||
u64 relocation_table_entries_size = 0;
|
||||
|
||||
u64 debug = 0;
|
||||
u64 textrel = 0;
|
||||
u64 flags = 0;
|
||||
|
||||
std::vector<const char*> needed;
|
||||
std::vector<ModuleInfo> import_modules;
|
||||
std::vector<ModuleInfo> export_modules;
|
||||
std::vector<LibraryInfo> import_libs;
|
||||
std::vector<LibraryInfo> export_libs;
|
||||
|
||||
std::string filename; // Filename with absolute path
|
||||
};
|
||||
|
||||
// This struct keeps neccesary info about loaded modules. Main executeable is included too as well
|
||||
struct Module
|
||||
{
|
||||
Elf elf;
|
||||
u64 aligned_base_size = 0;
|
||||
u64 base_virtual_addr = 0; // Base virtual address
|
||||
|
||||
Linker* linker = nullptr;
|
||||
|
||||
std::vector<u08> m_dynamic;
|
||||
std::vector<u08> m_dynamic_data;
|
||||
DynamicModuleInfo dynamic_info{};
|
||||
|
||||
SymbolsResolver export_sym;
|
||||
SymbolsResolver import_sym;
|
||||
};
|
||||
|
||||
class Linker {
|
||||
public:
|
||||
Linker();
|
||||
virtual ~Linker();
|
||||
|
||||
Module* LoadModule(const std::string& elf_name);
|
||||
Module* FindModule(/*u32 id*/);
|
||||
void LoadModuleToMemory(Module* m);
|
||||
void LoadDynamicInfo(Module* m);
|
||||
void LoadSymbols(Module* m);
|
||||
SymbolsResolver& getHLESymbols() { return m_hle_symbols; }
|
||||
void Relocate(Module* m);
|
||||
void Resolve(const std::string& name, int Symtype, Module* m, SymbolRecord* return_info);
|
||||
void Execute();
|
||||
|
||||
private:
|
||||
const ModuleInfo* FindModule(const Module& m, const std::string& id);
|
||||
const LibraryInfo* FindLibrary(const Module& program, const std::string& id);
|
||||
|
||||
std::vector<Module> m_modules;
|
||||
SymbolsResolver m_hle_symbols{};
|
||||
std::mutex m_mutex;
|
||||
};
|
|
@ -1,434 +0,0 @@
|
|||
#include "Elf.h"
|
||||
|
||||
#include "common/log.h"
|
||||
#include "common/debug.h"
|
||||
#include <fmt/core.h>
|
||||
|
||||
constexpr bool log_file_loader = true; // disable it to disable logging
|
||||
|
||||
static std::string_view getProgramTypeName(program_type_es type) {
|
||||
switch (type) {
|
||||
case PT_FAKE: return "PT_FAKE";
|
||||
case PT_NPDRM_EXEC: return "PT_NPDRM_EXEC";
|
||||
case PT_NPDRM_DYNLIB: return "PT_NPDRM_DYNLIB";
|
||||
case PT_SYSTEM_EXEC: return "PT_SYSTEM_EXEC";
|
||||
case PT_SYSTEM_DYNLIB: return "PT_SYSTEM_DYNLIB";
|
||||
case PT_HOST_KERNEL: return "PT_HOST_KERNEL";
|
||||
case PT_SECURE_MODULE: return "PT_SECURE_MODULE";
|
||||
case PT_SECURE_KERNEL: return "PT_SECURE_KERNEL";
|
||||
default: return "INVALID";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string_view getIdentClassName(ident_class_es elf_class) {
|
||||
switch (elf_class) {
|
||||
case ELF_CLASS_NONE: return "ELF_CLASS_NONE";
|
||||
case ELF_CLASS_32: return "ELF_CLASS_32";
|
||||
case ELF_CLASS_64: return "ELF_CLASS_64";
|
||||
case ELF_CLASS_NUM: return "ELF_CLASS_NUM";
|
||||
default: return "INVALID";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string_view getIdentEndianName(ident_endian_es endian) {
|
||||
switch (endian) {
|
||||
case ELF_DATA_NONE: return "ELF_DATA_NONE";
|
||||
case ELF_DATA_2LSB: return "ELF_DATA_2LSB";
|
||||
case ELF_DATA_2MSB: return "ELF_DATA_2MSB";
|
||||
case ELF_DATA_NUM: return "ELF_DATA_NUM";
|
||||
default: return "INVALID";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string_view getIdentVersionName(ident_version_es version) {
|
||||
switch (version) {
|
||||
case ELF_VERSION_NONE: return "ELF_VERSION_NONE";
|
||||
case ELF_VERSION_CURRENT: return "ELF_VERSION_CURRENT";
|
||||
case ELF_VERSION_NUM: return "ELF_VERSION_NUM";
|
||||
default: return "INVALID";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string_view getIdentOsabiName(ident_osabi_es osabi) {
|
||||
switch (osabi) {
|
||||
case ELF_OSABI_NONE: return "ELF_OSABI_NONE";
|
||||
case ELF_OSABI_HPUX: return "ELF_OSABI_HPUX";
|
||||
case ELF_OSABI_NETBSD: return "ELF_OSABI_NETBSD";
|
||||
case ELF_OSABI_LINUX: return "ELF_OSABI_LINUX";
|
||||
case ELF_OSABI_SOLARIS: return "ELF_OSABI_SOLARIS";
|
||||
case ELF_OSABI_AIX: return "ELF_OSABI_AIX";
|
||||
case ELF_OSABI_IRIX: return "ELF_OSABI_IRIX";
|
||||
case ELF_OSABI_FREEBSD: return "ELF_OSABI_FREEBSD";
|
||||
case ELF_OSABI_TRU64: return "ELF_OSABI_TRU64";
|
||||
case ELF_OSABI_MODESTO: return "ELF_OSABI_MODESTO";
|
||||
case ELF_OSABI_OPENBSD: return "ELF_OSABI_OPENBSD";
|
||||
case ELF_OSABI_OPENVMS: return "ELF_OSABI_OPENVMS";
|
||||
case ELF_OSABI_NSK: return "ELF_OSABI_NSK";
|
||||
case ELF_OSABI_AROS: return "ELF_OSABI_AROS";
|
||||
case ELF_OSABI_ARM_AEABI: return "ELF_OSABI_ARM_AEABI";
|
||||
case ELF_OSABI_ARM: return "ELF_OSABI_ARM";
|
||||
case ELF_OSABI_STANDALONE: return "ELF_OSABI_STANDALONE";
|
||||
default: return "INVALID";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string_view getIdentAbiversionName(ident_abiversion_es version) {
|
||||
switch (version) {
|
||||
case ELF_ABI_VERSION_AMDGPU_HSA_V2: return "ELF_ABI_VERSION_AMDGPU_HSA_V2";
|
||||
case ELF_ABI_VERSION_AMDGPU_HSA_V3: return "ELF_ABI_VERSION_AMDGPU_HSA_V3";
|
||||
case ELF_ABI_VERSION_AMDGPU_HSA_V4: return "ELF_ABI_VERSION_AMDGPU_HSA_V4";
|
||||
case ELF_ABI_VERSION_AMDGPU_HSA_V5: return "ELF_ABI_VERSION_AMDGPU_HSA_V5";
|
||||
default: return "INVALID";
|
||||
}
|
||||
}
|
||||
static std::string_view getVersion(e_version_es version) {
|
||||
switch (version) {
|
||||
case EV_NONE: return "EV_NONE";
|
||||
case EV_CURRENT: return "EV_CURRENT";
|
||||
default: return "INVALID";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string_view getType(e_type_s type) {
|
||||
switch (type) {
|
||||
case ET_NONE: return "ET_NONE";
|
||||
case ET_REL: return "ET_REL";
|
||||
case ET_EXEC: return "ET_EXEC";
|
||||
case ET_DYN: return "ET_DYN";
|
||||
case ET_CORE: return "ET_CORE";
|
||||
case ET_SCE_EXEC: return "ET_SCE_EXEC";
|
||||
case ET_SCE_STUBLIB: return "ET_SCE_STUBLIB";
|
||||
case ET_SCE_DYNEXEC: return "ET_SCE_DYNEXEC";
|
||||
case ET_SCE_DYNAMIC: return "ET_SCE_DYNAMIC";
|
||||
default: return "INVALID";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string_view getMachine(e_machine_es machine) {
|
||||
switch (machine) {
|
||||
case EM_X86_64: return "EM_X86_64";
|
||||
default: return "INVALID";
|
||||
}
|
||||
}
|
||||
|
||||
Elf::~Elf() { Reset(); }
|
||||
|
||||
void Elf::Reset() { m_f.close(); }
|
||||
|
||||
void Elf::Open(const std::string& file_name) {
|
||||
Reset();
|
||||
|
||||
m_f.open(file_name, Common::FS::OpenMode::Read);
|
||||
m_f.read(m_self);
|
||||
|
||||
if (is_self = isSelfFile(); !is_self) {
|
||||
m_f.seek(0, Common::FS::SeekMode::Set);
|
||||
} else {
|
||||
m_self_segments.resize(m_self.segment_count);
|
||||
m_f.read(m_self_segments);
|
||||
}
|
||||
|
||||
const u64 elf_header_pos = m_f.tell();
|
||||
m_f.read(m_elf_header);
|
||||
if (!isElfFile()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto load_headers = [this]<typename T>(std::vector<T>& out, u64 offset, u16 num) {
|
||||
if (!num) {
|
||||
return;
|
||||
}
|
||||
|
||||
out.resize(num);
|
||||
m_f.seek(offset, Common::FS::SeekMode::Set);
|
||||
m_f.read(out);
|
||||
};
|
||||
|
||||
load_headers(m_elf_phdr, elf_header_pos + m_elf_header.e_phoff, m_elf_header.e_phnum);
|
||||
load_headers(m_elf_shdr, elf_header_pos + m_elf_header.e_shoff, m_elf_header.e_shnum);
|
||||
|
||||
if (is_self) {
|
||||
u64 header_size = 0;
|
||||
header_size += sizeof(self_header);
|
||||
header_size += sizeof(self_segment_header) * m_self.segment_count;
|
||||
header_size += sizeof(elf_header);
|
||||
header_size += m_elf_header.e_phnum * m_elf_header.e_phentsize;
|
||||
header_size += m_elf_header.e_shnum * m_elf_header.e_shentsize;
|
||||
header_size += 15;
|
||||
header_size &= ~15; // Align
|
||||
|
||||
if (m_elf_header.e_ehsize - header_size >= sizeof(elf_program_id_header)) {
|
||||
m_f.seek(header_size, Common::FS::SeekMode::Set);
|
||||
m_f.read(m_self_id_header);
|
||||
}
|
||||
}
|
||||
|
||||
DebugDump();
|
||||
}
|
||||
|
||||
bool Elf::isSelfFile() const {
|
||||
if (m_self.magic != self_header::signature) [[unlikely]] {
|
||||
LOG_ERROR_IF(log_file_loader, "Not a SELF file.Magic file mismatched !current = {:#x} required = {:#x}\n ", m_self.magic,
|
||||
self_header::signature);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_self.version != 0x00 || m_self.mode != 0x01 || m_self.endian != 0x01 || m_self.attributes != 0x12) [[unlikely]] {
|
||||
LOG_ERROR_IF(log_file_loader, "Unknown SELF file\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_self.category != 0x01 || m_self.program_type != 0x01) [[unlikely]] {
|
||||
LOG_ERROR_IF(log_file_loader, "Unknown SELF file\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Elf::isElfFile() const {
|
||||
if (m_elf_header.e_ident.magic[EI_MAG0] != ELFMAG0 || m_elf_header.e_ident.magic[EI_MAG1] != ELFMAG1 ||
|
||||
m_elf_header.e_ident.magic[EI_MAG2] != ELFMAG2 || m_elf_header.e_ident.magic[EI_MAG3] != ELFMAG3) {
|
||||
LOG_ERROR_IF(log_file_loader, "Not an ELF file magic is wrong!\n");
|
||||
return false;
|
||||
}
|
||||
if (m_elf_header.e_ident.ei_class != ELF_CLASS_64) {
|
||||
LOG_ERROR_IF(log_file_loader, "e_ident[EI_CLASS] expected 0x02 is ({:#x})\n", static_cast<u32>(m_elf_header.e_ident.ei_class));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_elf_header.e_ident.ei_data != ELF_DATA_2LSB) {
|
||||
LOG_ERROR_IF(log_file_loader, "e_ident[EI_DATA] expected 0x01 is ({:#x})\n", static_cast<u32>(m_elf_header.e_ident.ei_data));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_elf_header.e_ident.ei_version != ELF_VERSION_CURRENT) {
|
||||
LOG_ERROR_IF(log_file_loader, "e_ident[EI_VERSION] expected 0x01 is ({:#x})\n", static_cast<u32>(m_elf_header.e_ident.ei_version));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_elf_header.e_ident.ei_osabi != ELF_OSABI_FREEBSD) {
|
||||
LOG_ERROR_IF(log_file_loader, "e_ident[EI_OSABI] expected 0x09 is ({:#x})\n", static_cast<u32>(m_elf_header.e_ident.ei_osabi));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_elf_header.e_ident.ei_abiversion != ELF_ABI_VERSION_AMDGPU_HSA_V2) {
|
||||
LOG_ERROR_IF(log_file_loader, "e_ident[EI_ABIVERSION] expected 0x00 is ({:#x})\n", static_cast<u32>(m_elf_header.e_ident.ei_abiversion));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_elf_header.e_type != ET_SCE_DYNEXEC && m_elf_header.e_type != ET_SCE_DYNAMIC && m_elf_header.e_type != ET_SCE_EXEC) {
|
||||
LOG_ERROR_IF(log_file_loader, "e_type expected 0xFE10 OR 0xFE18 OR 0xfe00 is ({:#x})\n", static_cast<u32>(m_elf_header.e_type));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_elf_header.e_machine != EM_X86_64) {
|
||||
LOG_ERROR_IF(log_file_loader, "e_machine expected 0x3E is ({:#x})\n", static_cast<u32>(m_elf_header.e_machine));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_elf_header.e_version != EV_CURRENT) {
|
||||
LOG_ERROR_IF(log_file_loader, "m_elf_header.e_version expected 0x01 is ({:#x})\n", static_cast<u32>(m_elf_header.e_version));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_elf_header.e_phentsize != sizeof(elf_program_header)) {
|
||||
LOG_ERROR_IF(log_file_loader, "e_phentsize ({}) != sizeof(elf_program_header)\n", static_cast<u32>(m_elf_header.e_phentsize));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_elf_header.e_shentsize > 0 &&
|
||||
m_elf_header.e_shentsize != sizeof(elf_section_header)) // Commercial games doesn't appear to have section headers
|
||||
{
|
||||
LOG_ERROR_IF(log_file_loader, "e_shentsize ({}) != sizeof(elf_section_header)\n", m_elf_header.e_shentsize);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Elf::DebugDump() {
|
||||
if (is_self) { // If we load elf instead
|
||||
LOG_INFO_IF(log_file_loader, (SElfHeaderStr()));
|
||||
for (u16 i = 0; i < m_self.segment_count; i++) {
|
||||
LOG_INFO_IF(log_file_loader, SELFSegHeader(i));
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO_IF(log_file_loader, ElfHeaderStr());
|
||||
|
||||
if (m_elf_header.e_phentsize > 0) {
|
||||
LOG_INFO_IF(log_file_loader, "Program headers:\n");
|
||||
for (u16 i = 0; i < m_elf_header.e_phnum; i++) {
|
||||
LOG_INFO_IF(log_file_loader, ElfPHeaderStr(i));
|
||||
}
|
||||
}
|
||||
if (m_elf_header.e_shentsize > 0) {
|
||||
LOG_INFO_IF(log_file_loader, "Section headers:\n");
|
||||
for (u16 i = 0; i < m_elf_header.e_shnum; i++) {
|
||||
LOG_INFO_IF(log_file_loader, "--- shdr {} --\n", i);
|
||||
LOG_INFO_IF(log_file_loader, "sh_name ........: {}\n", m_elf_shdr[i].sh_name);
|
||||
LOG_INFO_IF(log_file_loader, "sh_type ........: {:#010x}\n", m_elf_shdr[i].sh_type);
|
||||
LOG_INFO_IF(log_file_loader, "sh_flags .......: {:#018x}\n", m_elf_shdr[i].sh_flags);
|
||||
LOG_INFO_IF(log_file_loader, "sh_addr ........: {:#018x}\n", m_elf_shdr[i].sh_addr);
|
||||
LOG_INFO_IF(log_file_loader, "sh_offset ......: {:#018x}\n", m_elf_shdr[i].sh_offset);
|
||||
LOG_INFO_IF(log_file_loader, "sh_size ........: {:#018x}\n", m_elf_shdr[i].sh_size);
|
||||
LOG_INFO_IF(log_file_loader, "sh_link ........: {:#010x}\n", m_elf_shdr[i].sh_link);
|
||||
LOG_INFO_IF(log_file_loader, "sh_info ........: {:#010x}\n", m_elf_shdr[i].sh_info);
|
||||
LOG_INFO_IF(log_file_loader, "sh_addralign ...: {:#018x}\n", m_elf_shdr[i].sh_addralign);
|
||||
LOG_INFO_IF(log_file_loader, "sh_entsize .....: {:#018x}\n", m_elf_shdr[i].sh_entsize);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_self) {
|
||||
LOG_INFO_IF(log_file_loader, "SELF info:\n");
|
||||
LOG_INFO_IF(log_file_loader, "auth id ............: {:#018x}\n", m_self_id_header.authid);
|
||||
LOG_INFO_IF(log_file_loader, "program type .......: {}\n", getProgramTypeName(m_self_id_header.program_type));
|
||||
LOG_INFO_IF(log_file_loader, "app version ........: {:#018x}\n", m_self_id_header.appver);
|
||||
LOG_INFO_IF(log_file_loader, "fw version .........: {:#018x}\n", m_self_id_header.firmver);
|
||||
std::string digest;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
digest += fmt::format("{:02X}", m_self_id_header.digest[i]);
|
||||
}
|
||||
LOG_INFO_IF(log_file_loader, "digest..............: 0x{}\n", digest);
|
||||
}
|
||||
}
|
||||
|
||||
std::string Elf::SElfHeaderStr() {
|
||||
std::string header = fmt::format("======= SELF HEADER =========\n", m_self.magic);
|
||||
header += fmt::format("magic ..............: 0x{:X}\n", m_self.magic);
|
||||
header += fmt::format("version ............: {}\n", m_self.version);
|
||||
header += fmt::format("mode ...............: {:#04x}\n", m_self.mode);
|
||||
header += fmt::format("endian .............: {}\n", m_self.endian);
|
||||
header += fmt::format("attributes .........: {:#04x}\n", m_self.attributes);
|
||||
header += fmt::format("category ...........: {:#04x}\n", m_self.category);
|
||||
header += fmt::format("program_type........: {:#04x}\n", m_self.program_type);
|
||||
header += fmt::format("padding1 ...........: {:#06x}\n", m_self.padding1);
|
||||
header += fmt::format("header size ........: {}\n", m_self.header_size);
|
||||
header += fmt::format("meta size ..........: {}\n", m_self.meta_size);
|
||||
header += fmt::format("file size ..........: {}\n", m_self.file_size);
|
||||
header += fmt::format("padding2 ...........: {:#010x}\n", m_self.padding2);
|
||||
header += fmt::format("segment count ......: {}\n", m_self.segment_count);
|
||||
header += fmt::format("unknown 1A .........: {:#06x}\n", m_self.unknown1A);
|
||||
header += fmt::format("padding3 ...........: {:#010x}\n", m_self.padding3);
|
||||
return header;
|
||||
}
|
||||
|
||||
std::string Elf::SELFSegHeader(u16 no) {
|
||||
const auto segment_header = m_self_segments[no];
|
||||
std::string header = fmt::format("====== SEGMENT HEADER {} ========\n", no);
|
||||
header += fmt::format("flags ............: {:#018x}\n", segment_header.flags);
|
||||
header += fmt::format("file offset ......: {:#018x}\n", segment_header.file_offset);
|
||||
header += fmt::format("file size ........: {}\n", segment_header.file_size);
|
||||
header += fmt::format("memory size ......: {}\n", segment_header.memory_size);
|
||||
return header;
|
||||
}
|
||||
|
||||
std::string Elf::ElfHeaderStr() {
|
||||
std::string header = fmt::format("======= Elf header ===========\n");
|
||||
header += fmt::format("ident ............: 0x");
|
||||
for (auto i : m_elf_header.e_ident.magic) {
|
||||
header += fmt::format("{:02X}", i);
|
||||
}
|
||||
header += fmt::format("\n");
|
||||
|
||||
header += fmt::format("ident class.......: {}\n", getIdentClassName(m_elf_header.e_ident.ei_class));
|
||||
header += fmt::format("ident data .......: {}\n", getIdentEndianName(m_elf_header.e_ident.ei_data));
|
||||
header += fmt::format("ident version.....: {}\n", getIdentVersionName(m_elf_header.e_ident.ei_version));
|
||||
header += fmt::format("ident osabi .....: {}\n", getIdentOsabiName(m_elf_header.e_ident.ei_osabi));
|
||||
header += fmt::format("ident abiversion..: {}\n", getIdentAbiversionName(m_elf_header.e_ident.ei_abiversion));
|
||||
|
||||
header += fmt::format("ident UNK ........: 0x");
|
||||
for (auto i : m_elf_header.e_ident.pad) {
|
||||
header += fmt::format("{:02X}", i);
|
||||
}
|
||||
header += fmt::format("\n");
|
||||
|
||||
header += fmt::format("type ............: {}\n", getType(m_elf_header.e_type));
|
||||
header += fmt::format("machine ..........: {}\n", getMachine(m_elf_header.e_machine));
|
||||
header += fmt::format("version ..........: {}\n", getVersion(m_elf_header.e_version));
|
||||
header += fmt::format("entry ............: {:#018x}\n", m_elf_header.e_entry);
|
||||
header += fmt::format("phoff ............: {:#018x}\n", m_elf_header.e_phoff);
|
||||
header += fmt::format("shoff ............: {:#018x}\n", m_elf_header.e_shoff);
|
||||
header += fmt::format("flags ............: {:#010x}\n", m_elf_header.e_flags);
|
||||
header += fmt::format("ehsize ...........: {}\n", m_elf_header.e_ehsize);
|
||||
header += fmt::format("phentsize ........: {}\n", m_elf_header.e_phentsize);
|
||||
header += fmt::format("phnum ............: {}\n", m_elf_header.e_phnum);
|
||||
header += fmt::format("shentsize ........: {}\n", m_elf_header.e_shentsize);
|
||||
header += fmt::format("shnum ............: {}\n", m_elf_header.e_shnum);
|
||||
header += fmt::format("shstrndx .........: {}\n", m_elf_header.e_shstrndx);
|
||||
return header;
|
||||
}
|
||||
|
||||
std::string Elf::ElfPheaderTypeStr(u32 type) {
|
||||
switch (type) {
|
||||
case PT_NULL: return "Null";
|
||||
case PT_LOAD: return "Loadable";
|
||||
case PT_DYNAMIC: return "Dynamic";
|
||||
case PT_INTERP: return "Interpreter Path";
|
||||
case PT_NOTE: return "Note";
|
||||
case PT_SHLIB: return "Section Header Library";
|
||||
case PT_PHDR: return "Program Header";
|
||||
case PT_TLS: return "Thread-Local Storage";
|
||||
case PT_NUM: return "Defined Sections Number";
|
||||
case PT_SCE_RELA: return "SCE Relative";
|
||||
case PT_SCE_DYNLIBDATA: return "SCE Dynamic Library Data";
|
||||
case PT_SCE_PROCPARAM: return "SCE Processor Parameters";
|
||||
case PT_SCE_MODULE_PARAM: return "SCE Module Parameters";
|
||||
case PT_SCE_RELRO: return "SCE Read-Only After Relocation";
|
||||
case PT_GNU_EH_FRAME: return "GNU Entry Header Frame";
|
||||
case PT_GNU_STACK: return "GNU Stack (executability)";
|
||||
case PT_GNU_RELRO: return "GNU Read-Only After Relocation";
|
||||
case PT_SCE_COMMENT: return "SCE Comment";
|
||||
case PT_SCE_LIBVERSION: return "SCE Library Version";
|
||||
default: return "Unknown Section";
|
||||
}
|
||||
}
|
||||
|
||||
std::string Elf::ElfPheaderFlagsStr(u32 flags) {
|
||||
std::string flg = "(";
|
||||
flg += (flags & PF_READ) ? "R" : "_";
|
||||
flg += (flags & PF_WRITE) ? "W" : "_";
|
||||
flg += (flags & PF_EXEC) ? "X" : "_";
|
||||
flg += ")";
|
||||
return flg;
|
||||
}
|
||||
|
||||
std::string Elf::ElfPHeaderStr(u16 no) {
|
||||
std::string header = fmt::format("====== PROGRAM HEADER {} ========\n", no);
|
||||
header += fmt::format("p_type ....: {}\n", ElfPheaderTypeStr(m_elf_phdr[no].p_type));
|
||||
header += fmt::format("p_flags ...: {:#010x}\n", static_cast<u32>(m_elf_phdr[no].p_flags));
|
||||
header += fmt::format("p_offset ..: {:#018x}\n", m_elf_phdr[no].p_offset);
|
||||
header += fmt::format("p_vaddr ...: {:#018x}\n", m_elf_phdr[no].p_vaddr);
|
||||
header += fmt::format("p_paddr ...: {:#018x}\n", m_elf_phdr[no].p_paddr);
|
||||
header += fmt::format("p_filesz ..: {:#018x}\n", m_elf_phdr[no].p_filesz);
|
||||
header += fmt::format("p_memsz ...: {:#018x}\n", m_elf_phdr[no].p_memsz);
|
||||
header += fmt::format("p_align ...: {:#018x}\n", m_elf_phdr[no].p_align);
|
||||
return header;
|
||||
}
|
||||
|
||||
void Elf::LoadSegment(u64 virtual_addr, u64 file_offset, u64 size) {
|
||||
if (!is_self) {
|
||||
// It's elf file
|
||||
m_f.seek(file_offset, Common::FS::SeekMode::Set);
|
||||
m_f.read(reinterpret_cast<void*>(static_cast<uintptr_t>(virtual_addr)), size);
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < m_self.segment_count; i++) {
|
||||
const auto& seg = m_self_segments[i];
|
||||
|
||||
if (seg.IsBlocked()) {
|
||||
auto phdr_id = seg.GetId();
|
||||
const auto& phdr = m_elf_phdr[phdr_id];
|
||||
|
||||
if (file_offset >= phdr.p_offset && file_offset < phdr.p_offset + phdr.p_filesz) {
|
||||
auto offset = file_offset - phdr.p_offset;
|
||||
m_f.seek(offset + seg.file_offset, Common::FS::SeekMode::Set);
|
||||
m_f.read(reinterpret_cast<void*>(static_cast<uintptr_t>(virtual_addr)), size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
BREAKPOINT(); // Hmm we didn't return something...
|
||||
}
|
|
@ -1,504 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cinttypes>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
#include "common/types.h"
|
||||
#include "common/fs_file.h"
|
||||
|
||||
struct self_header
|
||||
{
|
||||
static const u32 signature = 0x1D3D154Fu;
|
||||
|
||||
u32 magic;
|
||||
u08 version;
|
||||
u08 mode;
|
||||
u08 endian;// 1 is little endian
|
||||
u08 attributes;
|
||||
u08 category;
|
||||
u08 program_type;
|
||||
u16 padding1;
|
||||
u16 header_size;
|
||||
u16 meta_size;
|
||||
u32 file_size;
|
||||
u32 padding2;
|
||||
u16 segment_count;
|
||||
u16 unknown1A; //always 0x22
|
||||
u32 padding3;
|
||||
};
|
||||
|
||||
struct self_segment_header
|
||||
{
|
||||
bool IsBlocked() const {
|
||||
return (flags & 0x800) != 0;//0 or 0x800
|
||||
}
|
||||
|
||||
u32 GetId() const {
|
||||
return (flags >> 20u) & 0xFFFu;
|
||||
}
|
||||
|
||||
bool IsOrdered() const {
|
||||
return (flags & 1) != 0;//0 or 1
|
||||
}
|
||||
|
||||
bool IsEncrypted() const {
|
||||
return (flags & 2) != 0;//0 or 2
|
||||
}
|
||||
|
||||
bool IsSigned() const {
|
||||
return (flags & 4) != 0;//0 or 4
|
||||
}
|
||||
|
||||
bool IsCompressed() const {
|
||||
return (flags & 8) != 0;//0 or 8
|
||||
}
|
||||
|
||||
u64 flags;
|
||||
u64 file_offset;
|
||||
u64 file_size;
|
||||
u64 memory_size;
|
||||
};
|
||||
|
||||
|
||||
constexpr u08 EI_MAG0 = 0;/* e_ident[] indexes */
|
||||
constexpr u08 EI_MAG1 = 1;
|
||||
constexpr u08 EI_MAG2 = 2;
|
||||
constexpr u08 EI_MAG3 = 3;
|
||||
constexpr u08 EI_CLASS = 4;
|
||||
constexpr u08 EI_DATA = 5;
|
||||
constexpr u08 EI_VERSION = 6;
|
||||
constexpr u08 EI_OSABI = 7;
|
||||
constexpr u08 EI_ABIVERSION = 8;
|
||||
|
||||
// Magic number
|
||||
constexpr u08 ELFMAG0 = 0x7F;
|
||||
constexpr u08 ELFMAG1 = 'E';
|
||||
constexpr u08 ELFMAG2 = 'L';
|
||||
constexpr u08 ELFMAG3 = 'F';
|
||||
|
||||
typedef enum : u16 {
|
||||
ET_NONE = 0x0,
|
||||
ET_REL = 0x1,
|
||||
ET_EXEC = 0x2,
|
||||
ET_DYN = 0x3,
|
||||
ET_CORE = 0x4,
|
||||
ET_SCE_EXEC = 0xfe00,
|
||||
ET_SCE_STUBLIB = 0xfe0c,
|
||||
ET_SCE_DYNEXEC = 0xfe10,
|
||||
ET_SCE_DYNAMIC = 0xfe18
|
||||
} e_type_s;
|
||||
|
||||
typedef enum : u16 {
|
||||
EM_NONE = 0, /* No machine */
|
||||
EM_M32 = 1, /* AT&T WE 32100 */
|
||||
EM_SPARC = 2, /* SPARC */
|
||||
EM_386 = 3, /* Intel 80386 */
|
||||
EM_68K = 4, /* Motorola 68000 */
|
||||
EM_88K = 5, /* Motorola 88000 */
|
||||
EM_860 = 7, /* Intel 80860 */
|
||||
EM_MIPS = 8, /* MIPS I Architecture */
|
||||
EM_S370 = 9, /* IBM System/370 Processor */
|
||||
EM_MIPS_RS3_LE = 10, /* MIPS RS3000 Little-endian */
|
||||
EM_PARISC = 15, /* Hewlett-Packard PA-RISC */
|
||||
EM_VPP500 = 17, /* Fujitsu VPP500 */
|
||||
EM_SPARC32PLUS = 18, /* Enhanced instruction set SPARC */
|
||||
EM_960 = 19, /* Intel 80960 */
|
||||
EM_PPC = 20, /* PowerPC */
|
||||
EM_PPC64 = 21, /* 64-bit PowerPC */
|
||||
EM_S390 = 22, /* IBM System/390 Processor */
|
||||
EM_V800 = 36, /* NEC V800 */
|
||||
EM_FR20 = 37, /* Fujitsu FR20 */
|
||||
EM_RH32 = 38, /* TRW RH-32 */
|
||||
EM_RCE = 39, /* Motorola RCE */
|
||||
EM_ARM = 40, /* Advanced RISC Machines ARM */
|
||||
EM_ALPHA = 41, /* Digital Alpha */
|
||||
EM_SH = 42, /* Hitachi SH */
|
||||
EM_SPARCV9 = 43, /* SPARC Version 9 */
|
||||
EM_TRICORE = 44, /* Siemens TriCore embedded processor */
|
||||
EM_ARC = 45, /* Argonaut RISC Core, Argonaut Technologies Inc. */
|
||||
EM_H8_300 = 46, /* Hitachi H8/300 */
|
||||
EM_H8_300H = 47, /* Hitachi H8/300H */
|
||||
EM_H8S = 48, /* Hitachi H8S */
|
||||
EM_H8_500 = 49, /* Hitachi H8/500 */
|
||||
EM_IA_64 = 50, /* Intel IA-64 processor architecture */
|
||||
EM_MIPS_X = 51, /* Stanford MIPS-X */
|
||||
EM_COLDFIRE = 52, /* Motorola ColdFire */
|
||||
EM_68HC12 = 53, /* Motorola M68HC12 */
|
||||
EM_MMA = 54, /* Fujitsu MMA Multimedia Accelerator */
|
||||
EM_PCP = 55, /* Siemens PCP */
|
||||
EM_NCPU = 56, /* Sony nCPU embedded RISC processor */
|
||||
EM_NDR1 = 57, /* Denso NDR1 microprocessor */
|
||||
EM_STARCORE = 58, /* Motorola Star*Core processor */
|
||||
EM_ME16 = 59, /* Toyota ME16 processor */
|
||||
EM_ST100 = 60, /* STMicroelectronics ST100 processor */
|
||||
EM_TINYJ = 61, /* Advanced Logic Corp. TinyJ embedded processor family */
|
||||
EM_X86_64 = 62, /* AMD x86-64 architecture (PS4) */
|
||||
EM_PDSP = 63, /* Sony DSP Processor */
|
||||
EM_PDP10 = 64, /* Digital Equipment Corp. PDP-10 */
|
||||
EM_PDP11 = 65, /* Digital Equipment Corp. PDP-11 */
|
||||
EM_FX66 = 66, /* Siemens FX66 microcontroller */
|
||||
EM_ST9PLUS = 67, /* STMicroelectronics ST9+ 8/16 bit microcontroller */
|
||||
EM_ST7 = 68, /* STMicroelectronics ST7 8-bit microcontroller */
|
||||
EM_68HC16 = 69, /* Motorola MC68HC16 Microcontroller */
|
||||
EM_68HC11 = 70, /* Motorola MC68HC11 Microcontroller */
|
||||
EM_68HC08 = 71, /* Motorola MC68HC08 Microcontroller */
|
||||
EM_68HC05 = 72, /* Motorola MC68HC05 Microcontroller */
|
||||
EM_SVX = 73, /* Silicon Graphics SVx */
|
||||
EM_ST19 = 75, /* Digital VAX */
|
||||
EM_CRIS = 76, /* Axis Communications 32-bit embedded processor */
|
||||
EM_JAVELIN = 77, /* Infineon Technologies 32-bit embedded processor */
|
||||
EM_FIREPATH = 78, /* Element 14 64-bit DSP Processor */
|
||||
EM_ZSP = 79, /* LSI Logic 16-bit DSP Processor */
|
||||
EM_MMIX = 80, /* Donald Knuth's educational 64-bit processor */
|
||||
EM_HUANY = 81, /* Harvard University machine-independent object files */
|
||||
EM_PRISM = 82, /* SiTera Prism */
|
||||
EM_AVR = 83, /* Atmel AVR 8-bit microcontroller */
|
||||
EM_FR30 = 84, /* Fujitsu FR30 */
|
||||
EM_D10V = 85, /* Mitsubishi D10V */
|
||||
EM_D30V = 86, /* Mitsubishi D30V */
|
||||
EM_V850 = 87, /* NEC v850 */
|
||||
EM_M32R = 88, /* Mitsubishi M32R */
|
||||
EM_MN10300 = 89, /* Matsushita MN10300 */
|
||||
EM_MN10200 = 90, /* Matsushita MN10200 */
|
||||
EM_PJ = 91, /* PicoJava */
|
||||
EM_OPENRISC = 92, /* OpenRISC 32-bit embedded processor */
|
||||
EM_ARC_A5 = 93, /* ARC Cores Tangent-A5 */
|
||||
EM_XTENSA = 94, /* Tensilica Xtensa Architecture */
|
||||
EM_VIDEOCORE = 95, /* Alphamosaic VideoCore processor */
|
||||
EM_TMM_GPP = 96, /* Thompson Multimedia General Purpose Processor */
|
||||
EM_NS32K = 97, /* National Semiconductor 32000 series */
|
||||
EM_TPC = 98, /* Tenor Network TPC processor */
|
||||
EM_SNP1K = 99, /* Trebia SNP 1000 processor */
|
||||
EM_ST200 = 100, /* STMicroelectronics (www.st.com) ST200 microcontroller */
|
||||
EM_IP2K = 101, /* Ubicom IP2xxx microcontroller family */
|
||||
EM_MAX = 102, /* MAX Processor */
|
||||
EM_CR = 103, /* National Semiconductor CompactRISC microprocessor */
|
||||
EM_F2MC16 = 104, /* Fujitsu F2MC16 */
|
||||
EM_MSP430 = 105, /* Texas Instruments embedded microcontroller msp430 */
|
||||
EM_BLACKFIN = 106, /* Analog Devices Blackfin (DSP) processor */
|
||||
EM_SE_C33 = 107, /* S1C33 Family of Seiko Epson processors */
|
||||
EM_SEP = 108, /* Sharp embedded microprocessor */
|
||||
EM_ARCA = 109, /* Arca RISC Microprocessor */
|
||||
EM_UNICORE = 110 /* Microprocessor series from PKU-Unity Ltd. and MPRC */
|
||||
} e_machine_es;
|
||||
|
||||
typedef enum :u32 {
|
||||
EV_NONE = 0x0,
|
||||
EV_CURRENT = 0x1
|
||||
} e_version_es;
|
||||
|
||||
typedef enum : u08 {
|
||||
ELF_CLASS_NONE =0x0,
|
||||
ELF_CLASS_32 =0x1,
|
||||
ELF_CLASS_64 =0x2,
|
||||
ELF_CLASS_NUM =0x3
|
||||
} ident_class_es;
|
||||
|
||||
typedef enum : u08 {
|
||||
ELF_DATA_NONE = 0x0,
|
||||
ELF_DATA_2LSB = 0x1,
|
||||
ELF_DATA_2MSB = 0x2,
|
||||
ELF_DATA_NUM = 0x3
|
||||
} ident_endian_es;
|
||||
|
||||
typedef enum :u08 {
|
||||
ELF_VERSION_NONE = 0x0,
|
||||
ELF_VERSION_CURRENT = 0x1,
|
||||
ELF_VERSION_NUM = 0x2
|
||||
} ident_version_es;
|
||||
|
||||
typedef enum :u08 {
|
||||
ELF_OSABI_NONE = 0x0, /* No extensions or unspecified */
|
||||
ELF_OSABI_HPUX = 0x1, /* Hewlett-Packard HP-UX */
|
||||
ELF_OSABI_NETBSD = 0x2, /* NetBSD */
|
||||
ELF_OSABI_LINUX = 0x3, /* Linux */
|
||||
ELF_OSABI_SOLARIS = 0x6, /* Sun Solaris */
|
||||
ELF_OSABI_AIX = 0x7, /* AIX */
|
||||
ELF_OSABI_IRIX = 0x8, /* IRIX */
|
||||
ELF_OSABI_FREEBSD = 0x9, /* FreeBSD (PS4) */
|
||||
ELF_OSABI_TRU64 = 0xA, /* Compaq TRU64 UNIX */
|
||||
ELF_OSABI_MODESTO = 0xB, /* Novell Modesto */
|
||||
ELF_OSABI_OPENBSD = 0xC, /* Open BSD */
|
||||
ELF_OSABI_OPENVMS = 0xD, /* Open VMS */
|
||||
ELF_OSABI_NSK = 0xE, /* Hewlett-Packard Non-Stop Kernel */
|
||||
ELF_OSABI_AROS = 0xF, /* Amiga Research OS */
|
||||
ELF_OSABI_ARM_AEABI = 0x40, /* ARM EABI */
|
||||
ELF_OSABI_ARM = 0x61, /* ARM */
|
||||
ELF_OSABI_STANDALONE = 0xFF /* Standalone (embedded applications) */
|
||||
} ident_osabi_es;
|
||||
|
||||
typedef enum :u08 {
|
||||
ELF_ABI_VERSION_AMDGPU_HSA_V2=0x0,
|
||||
ELF_ABI_VERSION_AMDGPU_HSA_V3=0x1,
|
||||
ELF_ABI_VERSION_AMDGPU_HSA_V4=0x2,
|
||||
ELF_ABI_VERSION_AMDGPU_HSA_V5=0x3
|
||||
} ident_abiversion_es;
|
||||
|
||||
struct elf_ident {
|
||||
u08 magic[4];
|
||||
ident_class_es ei_class;
|
||||
ident_endian_es ei_data;
|
||||
ident_version_es ei_version;
|
||||
ident_osabi_es ei_osabi;
|
||||
ident_abiversion_es ei_abiversion;
|
||||
u08 pad[6];
|
||||
};
|
||||
|
||||
struct elf_header
|
||||
{
|
||||
static const u32 signature = 0x7F454C46u;
|
||||
|
||||
elf_ident e_ident; /* ELF identification */
|
||||
e_type_s e_type; /* Object file type */
|
||||
e_machine_es e_machine; /* Machine type */
|
||||
e_version_es e_version; /* Object file version */
|
||||
u64 e_entry; /* Entry point address */
|
||||
u64 e_phoff; /* Program header offset */
|
||||
u64 e_shoff; /* Section header offset */
|
||||
u32 e_flags; /* Processor-specific flags */
|
||||
u16 e_ehsize; /* ELF header size */
|
||||
u16 e_phentsize; /* Size of program header entry */
|
||||
u16 e_phnum; /* Number of program header entries */
|
||||
u16 e_shentsize; /* Size of section header entry */
|
||||
u16 e_shnum; /* Number of section header entries */
|
||||
u16 e_shstrndx; /* Section name string table index */
|
||||
};
|
||||
|
||||
typedef enum : u32 {
|
||||
PT_NULL = 0x0,
|
||||
PT_LOAD = 0x1,
|
||||
PT_DYNAMIC = 0x2,
|
||||
PT_INTERP = 0x3,
|
||||
PT_NOTE = 0x4,
|
||||
PT_SHLIB = 0x5,
|
||||
PT_PHDR = 0x6,
|
||||
PT_TLS = 0x7,
|
||||
PT_NUM = 0x8,
|
||||
PT_SCE_RELA = 0x60000000,
|
||||
PT_SCE_DYNLIBDATA = 0x61000000,
|
||||
PT_SCE_PROCPARAM = 0x61000001,
|
||||
PT_SCE_MODULE_PARAM = 0x61000002,
|
||||
PT_SCE_RELRO = 0x61000010,
|
||||
PT_GNU_EH_FRAME = 0x6474e550,
|
||||
PT_GNU_STACK = 0x6474e551,
|
||||
PT_GNU_RELRO = 0x6474e552,
|
||||
PT_SCE_COMMENT = 0x6fffff00,
|
||||
PT_SCE_LIBVERSION = 0x6fffff01,
|
||||
PT_LOSUNW = 0x6ffffffa,
|
||||
PT_SUNWBSS = 0x6ffffffa,
|
||||
PT_SUNWSTACK = 0x6ffffffb,
|
||||
PT_HISUNW = 0x6fffffff,
|
||||
PT_HIOS = 0x6fffffff,
|
||||
PT_LOPROC = 0x70000000,
|
||||
PT_HIPROC = 0x7fffffff
|
||||
} elf_program_type;
|
||||
|
||||
typedef enum : u32 {
|
||||
PF_NONE = 0x0,
|
||||
PF_EXEC = 0x1,
|
||||
PF_WRITE = 0x2,
|
||||
PF_WRITE_EXEC = 0x3,
|
||||
PF_READ = 0x4,
|
||||
PF_READ_EXEC = 0x5,
|
||||
PF_READ_WRITE = 0x6,
|
||||
PF_READ_WRITE_EXEC = 0x7
|
||||
} elf_program_flags;
|
||||
|
||||
struct elf_program_header
|
||||
{
|
||||
elf_program_type p_type; /* Type of segment */
|
||||
elf_program_flags p_flags; /* Segment attributes */
|
||||
u64 p_offset; /* Offset in file */
|
||||
u64 p_vaddr; /* Virtual address in memory */
|
||||
u64 p_paddr; /* Reserved */
|
||||
u64 p_filesz; /* Size of segment in file */
|
||||
u64 p_memsz; /* Size of segment in memory */
|
||||
u64 p_align; /* Alignment of segment */
|
||||
};
|
||||
|
||||
struct elf_section_header
|
||||
{
|
||||
u32 sh_name; /* Section name */
|
||||
u32 sh_type; /* Section type */
|
||||
u64 sh_flags; /* Section attributes */
|
||||
u64 sh_addr; /* Virtual address in memory */
|
||||
u64 sh_offset; /* Offset in file */
|
||||
u64 sh_size; /* Size of section */
|
||||
u32 sh_link; /* Link to other section */
|
||||
u32 sh_info; /* Miscellaneous information */
|
||||
u64 sh_addralign; /* Address alignment boundary */
|
||||
u64 sh_entsize; /* Size of entries, if section has table */
|
||||
};
|
||||
|
||||
typedef enum :u64 {
|
||||
PT_FAKE = 0x1,
|
||||
PT_NPDRM_EXEC = 0x4,
|
||||
PT_NPDRM_DYNLIB = 0x5,
|
||||
PT_SYSTEM_EXEC = 0x8,
|
||||
PT_SYSTEM_DYNLIB = 0x9,
|
||||
PT_HOST_KERNEL = 0xC,
|
||||
PT_SECURE_MODULE = 0xE,
|
||||
PT_SECURE_KERNEL = 0xF
|
||||
} program_type_es;
|
||||
|
||||
struct elf_program_id_header
|
||||
{
|
||||
u64 authid;
|
||||
program_type_es program_type;
|
||||
u64 appver;
|
||||
u64 firmver;
|
||||
u08 digest[32];
|
||||
};
|
||||
|
||||
constexpr s64 DT_NULL = 0;
|
||||
constexpr s64 DT_NEEDED = 0x00000001;
|
||||
constexpr s64 DT_RELA = 0x00000007;
|
||||
constexpr s64 DT_INIT = 0x0000000c;
|
||||
constexpr s64 DT_FINI = 0x0000000d;
|
||||
constexpr s64 DT_DEBUG = 0x00000015;
|
||||
constexpr s64 DT_TEXTREL = 0x00000016;
|
||||
constexpr s64 DT_INIT_ARRAY = 0x00000019;
|
||||
constexpr s64 DT_FINI_ARRAY = 0x0000001a;
|
||||
constexpr s64 DT_INIT_ARRAYSZ = 0x0000001b;
|
||||
constexpr s64 DT_FINI_ARRAYSZ = 0x0000001c;
|
||||
constexpr s64 DT_FLAGS = 0x0000001e;
|
||||
constexpr s64 DT_PREINIT_ARRAY = 0x00000020;
|
||||
constexpr s64 DT_PREINIT_ARRAYSZ = 0x00000021;
|
||||
constexpr s64 DT_SCE_FINGERPRINT = 0x61000007;
|
||||
constexpr s64 DT_SCE_ORIGINAL_FILENAME = 0x61000009;
|
||||
constexpr s64 DT_SCE_MODULE_INFO = 0x6100000d;
|
||||
constexpr s64 DT_SCE_NEEDED_MODULE = 0x6100000f;
|
||||
constexpr s64 DT_SCE_MODULE_ATTR = 0x61000011;
|
||||
constexpr s64 DT_SCE_EXPORT_LIB = 0x61000013;
|
||||
constexpr s64 DT_SCE_IMPORT_LIB = 0x61000015;
|
||||
constexpr s64 DT_SCE_IMPORT_LIB_ATTR = 0x61000019;
|
||||
constexpr s64 DT_SCE_HASH = 0x61000025;
|
||||
constexpr s64 DT_SCE_PLTGOT = 0x61000027;
|
||||
constexpr s64 DT_SCE_JMPREL = 0x61000029;
|
||||
constexpr s64 DT_SCE_PLTREL = 0x6100002b;
|
||||
constexpr s64 DT_SCE_PLTRELSZ = 0x6100002d;
|
||||
constexpr s64 DT_SCE_RELA = 0x6100002f;
|
||||
constexpr s64 DT_SCE_RELASZ = 0x61000031;
|
||||
constexpr s64 DT_SCE_RELAENT = 0x61000033;
|
||||
constexpr s64 DT_SCE_SYMENT = 0x6100003b;
|
||||
constexpr s64 DT_SCE_HASHSZ = 0x6100003d;
|
||||
constexpr s64 DT_SCE_STRTAB = 0x61000035;
|
||||
constexpr s64 DT_SCE_STRSZ = 0x61000037;
|
||||
constexpr s64 DT_SCE_SYMTAB = 0x61000039;
|
||||
constexpr s64 DT_SCE_SYMTABSZ = 0x6100003f;
|
||||
|
||||
|
||||
struct elf_dynamic
|
||||
{
|
||||
s64 d_tag;
|
||||
union
|
||||
{
|
||||
u64 d_val;
|
||||
u64 d_ptr;
|
||||
} d_un;
|
||||
};
|
||||
|
||||
constexpr u08 STB_LOCAL = 0;
|
||||
constexpr u08 STB_GLOBAL = 1;
|
||||
constexpr u08 STB_WEAK = 2;
|
||||
|
||||
constexpr u08 STT_NOTYPE = 0;
|
||||
constexpr u08 STT_OBJECT = 1;
|
||||
constexpr u08 STT_FUN = 2;
|
||||
constexpr u08 STT_SECTION = 3;
|
||||
constexpr u08 STT_FILE = 4;
|
||||
constexpr u08 STT_COMMON = 5;
|
||||
constexpr u08 STT_TLS = 6;
|
||||
constexpr u08 STT_LOOS = 10;
|
||||
constexpr u08 STT_SCE = 11; //module_start/module_stop
|
||||
constexpr u08 STT_HIOS = 12;
|
||||
constexpr u08 STT_LOPRO = 13;
|
||||
constexpr u08 STT_SPARC_REGISTER = 13;
|
||||
constexpr u08 STT_HIPROC = 15;
|
||||
|
||||
constexpr u08 STV_DEFAULT = 0;
|
||||
constexpr u08 STV_INTERNAL = 1;
|
||||
constexpr u08 STV_HIDDEN = 2;
|
||||
constexpr u08 STV_PROTECTED = 3;
|
||||
|
||||
struct elf_symbol
|
||||
{
|
||||
u08 GetBind() const { return st_info >> 4u; }
|
||||
u08 GetType() const { return st_info & 0xfu; }
|
||||
u08 GetVisibility() const { return st_other & 3u; }
|
||||
|
||||
u32 st_name;
|
||||
u08 st_info;
|
||||
u08 st_other;
|
||||
u16 st_shndx;
|
||||
u64 st_value;
|
||||
u64 st_size;
|
||||
};
|
||||
|
||||
struct elf_relocation
|
||||
{
|
||||
u32 GetSymbol() const { return static_cast<u32>(rel_info >> 32u); }
|
||||
u32 GetType() const { return static_cast<u32>(rel_info & 0xffffffff); }
|
||||
|
||||
u64 rel_offset;
|
||||
u64 rel_info;
|
||||
s64 rel_addend;
|
||||
};
|
||||
constexpr u32 R_X86_64_64 = 1; // Direct 64 bit
|
||||
constexpr u32 R_X86_64_JUMP_SLOT = 7; // Create PLT entry
|
||||
constexpr u32 R_X86_64_RELATIVE = 8; // Adjust by program base
|
||||
|
||||
class Elf {
|
||||
public:
|
||||
Elf() = default;
|
||||
virtual ~Elf();
|
||||
|
||||
void Open(const std::string & file_name);
|
||||
bool isSelfFile() const;
|
||||
bool isElfFile() const;
|
||||
void DebugDump();
|
||||
|
||||
[[nodiscard]] self_header GetSElfHeader() const {
|
||||
return m_self;
|
||||
}
|
||||
|
||||
[[nodiscard]] elf_header GetElfHeader() const {
|
||||
return m_elf_header;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::span<const elf_program_header> GetProgramHeader() const {
|
||||
return m_elf_phdr;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::span<const self_segment_header> GetSegmentHeader() const {
|
||||
return m_self_segments;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 GetElfEntry() const {
|
||||
return m_elf_header.e_entry;
|
||||
}
|
||||
|
||||
std::string SElfHeaderStr();
|
||||
std::string SELFSegHeader(u16 no);
|
||||
std::string ElfHeaderStr();
|
||||
std::string ElfPHeaderStr(u16 no);
|
||||
std::string ElfPheaderTypeStr(u32 type);
|
||||
std::string ElfPheaderFlagsStr(u32 flags);
|
||||
|
||||
void LoadSegment(u64 virtual_addr, u64 file_offset, u64 size);
|
||||
|
||||
private:
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
Common::FS::File m_f{};
|
||||
bool is_self{};
|
||||
self_header m_self{};
|
||||
std::vector<self_segment_header> m_self_segments;
|
||||
elf_header m_elf_header{};
|
||||
std::vector<elf_program_header> m_elf_phdr;
|
||||
std::vector<elf_section_header> m_elf_shdr;
|
||||
elf_program_id_header m_self_id_header{};
|
||||
};
|
|
@ -1,29 +0,0 @@
|
|||
#include "common/types.h"
|
||||
#include "SymbolsResolver.h"
|
||||
#include "common/log.h"
|
||||
|
||||
void SymbolsResolver::AddSymbol(const SymbolRes& s, u64 virtual_addr)
|
||||
{
|
||||
SymbolRecord r{};
|
||||
r.name = GenerateName(s);
|
||||
r.virtual_address = virtual_addr;
|
||||
m_symbols.push_back(r);
|
||||
}
|
||||
|
||||
std::string SymbolsResolver::GenerateName(const SymbolRes& s) {
|
||||
return fmt::format("{} lib[{}_v{}]mod[{}_v{}.{}]",
|
||||
s.name, s.library, s.library_version,
|
||||
s.module, s.module_version_major, s.module_version_minor);
|
||||
}
|
||||
|
||||
const SymbolRecord* SymbolsResolver::FindSymbol(const SymbolRes& s) const {
|
||||
const std::string name = GenerateName(s);
|
||||
for (u32 i = 0; i < m_symbols.size(); i++) {
|
||||
if (m_symbols[i].name.compare(name) == 0) {
|
||||
return &m_symbols[i];
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO("Unresolved! {}\n", name);
|
||||
return nullptr;
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include "common/types.h"
|
||||
|
||||
struct SymbolRecord
|
||||
{
|
||||
std::string name;
|
||||
u64 virtual_address;
|
||||
};
|
||||
|
||||
struct SymbolRes
|
||||
{
|
||||
std::string name;
|
||||
std::string nidName;
|
||||
std::string library;
|
||||
u16 library_version;
|
||||
std::string module;
|
||||
u08 module_version_major;
|
||||
u08 module_version_minor;
|
||||
u32 type;
|
||||
};
|
||||
|
||||
class SymbolsResolver
|
||||
{
|
||||
public:
|
||||
SymbolsResolver() = default;
|
||||
virtual ~SymbolsResolver() = default;
|
||||
|
||||
void AddSymbol(const SymbolRes& s, u64 virtual_addr);
|
||||
const SymbolRecord* FindSymbol(const SymbolRes& s) const;
|
||||
|
||||
static std::string GenerateName(const SymbolRes& s);
|
||||
|
||||
private:
|
||||
std::vector<SymbolRecord> m_symbols;
|
||||
};
|
|
@ -1,80 +0,0 @@
|
|||
#include "Stubs.h"
|
||||
|
||||
#include "Util/aerolib.h"
|
||||
|
||||
#include "common/log.h"
|
||||
|
||||
// Helper to provide stub implementations for missing functions
|
||||
//
|
||||
// This works by pre-compiling generic stub functions ("slots"), and then
|
||||
// on lookup, setting up the nid_entry they are matched with
|
||||
//
|
||||
// If it runs out of stubs with name information, it will return
|
||||
// a default implemetnation without function name details
|
||||
|
||||
// Up to 512, larger values lead to more resolve stub slots
|
||||
// and to longer compile / CI times
|
||||
//
|
||||
// Must match STUBS_LIST define
|
||||
#define MAX_STUBS 128
|
||||
|
||||
u64 UnresolvedStub() {
|
||||
LOG_ERROR("Unresolved Stub: called, returning zero to {}\n", __builtin_return_address(0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 UnknownStub() {
|
||||
LOG_ERROR("Stub: Unknown (nid: Unknown) called, returning zero to {}\n", __builtin_return_address(0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static aerolib::nid_entry* stub_nids[MAX_STUBS];
|
||||
static std::string stub_nids_unknown[MAX_STUBS];
|
||||
|
||||
template <int stub_index>
|
||||
static u64 CommonStub() {
|
||||
auto entry = stub_nids[stub_index];
|
||||
if (entry) {
|
||||
LOG_ERROR("Stub: {} (nid: {}) called, returning zero to {}\n", entry->name, entry->nid, __builtin_return_address(0));
|
||||
} else {
|
||||
LOG_ERROR("Stub: Unknown (nid: {}) called, returning zero to {}\n", stub_nids_unknown[stub_index], __builtin_return_address(0));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 UsedStubEntries;
|
||||
|
||||
#define XREP_1(x) \
|
||||
&CommonStub<x>,
|
||||
|
||||
#define XREP_2(x) XREP_1(x) XREP_1(x + 1)
|
||||
#define XREP_4(x) XREP_2(x) XREP_2(x + 2)
|
||||
#define XREP_8(x) XREP_4(x) XREP_4(x + 4)
|
||||
#define XREP_16(x) XREP_8(x) XREP_8(x + 8)
|
||||
#define XREP_32(x) XREP_16(x) XREP_16(x + 16)
|
||||
#define XREP_64(x) XREP_32(x) XREP_32(x + 32)
|
||||
#define XREP_128(x) XREP_64(x) XREP_64(x + 64)
|
||||
#define XREP_256(x) XREP_128(x) XREP_128(x + 128)
|
||||
#define XREP_512(x) XREP_256(x) XREP_256(x + 256)
|
||||
|
||||
#define STUBS_LIST XREP_128(0)
|
||||
|
||||
static u64 (*stub_handlers[MAX_STUBS])() = {
|
||||
STUBS_LIST
|
||||
};
|
||||
|
||||
u64 GetStub(const char* nid) {
|
||||
if (UsedStubEntries >= MAX_STUBS) {
|
||||
return (u64)&UnknownStub;
|
||||
}
|
||||
|
||||
auto entry = aerolib::find_by_nid(nid);
|
||||
if (!entry) {
|
||||
stub_nids_unknown[UsedStubEntries] = nid;
|
||||
} else {
|
||||
stub_nids[UsedStubEntries] = entry;
|
||||
}
|
||||
|
||||
return (u64)stub_handlers[UsedStubEntries++];
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
#include "common/types.h"
|
||||
|
||||
u64 UnresolvedStub();
|
||||
u64 GetStub(const char *nid);
|
|
@ -1,38 +0,0 @@
|
|||
#include "aerolib.h"
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "common/log.h"
|
||||
|
||||
namespace aerolib {
|
||||
|
||||
// Use a direct table here + binary search as contents are static
|
||||
nid_entry nids[] = {
|
||||
#define STUB(nid, name) \
|
||||
{ nid, #name },
|
||||
#include "aerolib.inl"
|
||||
#undef STUB
|
||||
};
|
||||
|
||||
nid_entry* find_by_nid(const char* nid) {
|
||||
s64 l = 0;
|
||||
s64 r = sizeof(nids) / sizeof(nids[0]) - 1;
|
||||
|
||||
while (l <= r) {
|
||||
size_t m = l + (r - l) / 2;
|
||||
|
||||
int cmp = strcmp(nids[m].nid, nid);
|
||||
|
||||
if (cmp == 0)
|
||||
return &nids[m];
|
||||
else if (cmp < 0)
|
||||
l = m + 1;
|
||||
else
|
||||
r = m - 1;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace aerolib
|
|
@ -1,11 +0,0 @@
|
|||
#include <stdint.h>
|
||||
|
||||
namespace aerolib {
|
||||
|
||||
struct nid_entry {
|
||||
const char* nid;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
nid_entry* find_by_nid(const char* nid);
|
||||
};
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue