core: Reorganize

This commit is contained in:
GPUCode 2023-11-06 01:11:54 +02:00
parent 89cf4dbfcb
commit 369d92fa56
73 changed files with 724 additions and 572 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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, &param) : 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

View file

@ -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

View file

@ -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

View file

@ -1,6 +0,0 @@
#pragma once
#include "common/types.h"
namespace HLE::Libs::LibKernel::CPUManagement {
int PS4_SYSV_ABI sceKernelIsNeoMode();
};

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);
}
};

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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)

View file

@ -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);
}

View file

@ -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;
};

View file

@ -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...
}

View file

@ -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{};
};

View file

@ -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;
}

View file

@ -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;
};

View file

@ -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++];
}

View file

@ -1,4 +0,0 @@
#include "common/types.h"
u64 UnresolvedStub();
u64 GetStub(const char *nid);

View file

@ -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

View file

@ -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