mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-05-30 23:33:17 +00:00
common: Rewrite logging based on cut down citra logger (#86)
* common: Rewrite logging based on cut down Citra logger * code: Misc fixes * core: Bring back tls handler * linker: Cleanup * config: Remove log level * logging: Enable console output by default * core: Fix windows build
This commit is contained in:
parent
b3084646a8
commit
79d6c8a377
70 changed files with 3212 additions and 1541 deletions
|
@ -1,14 +1,12 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/PS4/GPU/tile_manager.h"
|
||||
#include "core/PS4/GPU/video_out_buffer.h"
|
||||
#include "vulkan_util.h"
|
||||
|
||||
constexpr bool log_file_videoOutBuffer = true; // disable it to disable logging
|
||||
|
||||
static void update_func(HLE::Libs::Graphics::GraphicCtx* ctx, const u64* params, void* obj,
|
||||
const u64* virtual_addr, const u64* size, int virtual_addr_num) {
|
||||
|
||||
|
@ -55,8 +53,7 @@ static void* create_func(HLE::Libs::Graphics::GraphicCtx* ctx, const u64* params
|
|||
vk_format = VK_FORMAT_B8G8R8A8_SRGB;
|
||||
break;
|
||||
default:
|
||||
LOG_CRITICAL_IF(log_file_videoOutBuffer, "unknown pixelFormat = {}\n", pixel_format);
|
||||
std::exit(0);
|
||||
UNREACHABLE_MSG("Unknown pixelFormat = {}", pixel_format);
|
||||
}
|
||||
|
||||
vk_obj->extent.width = width;
|
||||
|
@ -91,8 +88,7 @@ static void* create_func(HLE::Libs::Graphics::GraphicCtx* ctx, const u64* params
|
|||
vkCreateImage(ctx->m_device, &image_info, nullptr, &vk_obj->image);
|
||||
|
||||
if (vk_obj->image == nullptr) {
|
||||
LOG_CRITICAL_IF(log_file_videoOutBuffer, "vk_obj->image is null\n");
|
||||
std::exit(0);
|
||||
UNREACHABLE_MSG("vk_obj->image is null");
|
||||
}
|
||||
|
||||
vkGetImageMemoryRequirements(ctx->m_device, vk_obj->image, &mem->requirements);
|
||||
|
@ -102,19 +98,15 @@ static void* create_func(HLE::Libs::Graphics::GraphicCtx* ctx, const u64* params
|
|||
bool allocated = GPU::vulkanAllocateMemory(ctx, mem);
|
||||
|
||||
if (!allocated) {
|
||||
LOG_CRITICAL_IF(log_file_videoOutBuffer, "can't allocate vulkan memory\n");
|
||||
std::exit(0);
|
||||
UNREACHABLE_MSG("Can't allocate vulkan memory");
|
||||
}
|
||||
|
||||
vkBindImageMemory(ctx->m_device, vk_obj->image, mem->memory, mem->offset);
|
||||
|
||||
vk_obj->memory = *mem;
|
||||
|
||||
LOG_INFO_IF(log_file_videoOutBuffer, "videoOutBuffer create object\n");
|
||||
LOG_INFO_IF(log_file_videoOutBuffer, "mem requirements.size = {}\n", mem->requirements.size);
|
||||
LOG_INFO_IF(log_file_videoOutBuffer, "width = {}\n", width);
|
||||
LOG_INFO_IF(log_file_videoOutBuffer, "height = {}\n", height);
|
||||
LOG_INFO_IF(log_file_videoOutBuffer, "size = {}\n", *size);
|
||||
LOG_INFO(Lib_VideoOut, "videoOutBuffer create object width = {}, height = {}, size = {}", width,
|
||||
height, *size);
|
||||
|
||||
update_func(ctx, params, vk_obj, virtual_addr, size, virtual_addr_num);
|
||||
|
||||
|
@ -139,8 +131,7 @@ static void* create_func(HLE::Libs::Graphics::GraphicCtx* ctx, const u64* params
|
|||
&vk_obj->image_view[HLE::Libs::Graphics::VulkanImage::VIEW_DEFAULT]);
|
||||
|
||||
if (vk_obj->image_view[HLE::Libs::Graphics::VulkanImage::VIEW_DEFAULT] == nullptr) {
|
||||
LOG_CRITICAL_IF(log_file_videoOutBuffer, "vk_obj->image_view is null\n");
|
||||
std::exit(0);
|
||||
UNREACHABLE_MSG("vk_obj->image_view is null");
|
||||
}
|
||||
|
||||
return vk_obj;
|
||||
|
|
|
@ -3,11 +3,10 @@
|
|||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <magic_enum.hpp>
|
||||
#include "Objects/video_out_ctx.h"
|
||||
#include "Util/config.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/singleton.h"
|
||||
#include "core/PS4/GPU/gpu_memory.h"
|
||||
#include "core/PS4/GPU/video_out_buffer.h"
|
||||
|
@ -58,17 +57,11 @@ std::string getPixelFormatString(s32 format) {
|
|||
void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(SceVideoOutBufferAttribute* attribute,
|
||||
u32 pixelFormat, u32 tilingMode, u32 aspectRatio,
|
||||
u32 width, u32 height, u32 pitchInPixel) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
|
||||
auto tileMode = magic_enum::enum_cast<SceVideoOutTilingMode>(tilingMode);
|
||||
auto aspectR = magic_enum::enum_cast<AspectRatioMode>(aspectRatio);
|
||||
|
||||
LOG_INFO_IF(log_file_videoout, "pixelFormat = {}\n", getPixelFormatString(pixelFormat));
|
||||
LOG_INFO_IF(log_file_videoout, "tilingMode = {}\n", magic_enum::enum_name(tileMode.value()));
|
||||
LOG_INFO_IF(log_file_videoout, "aspectRatio = {}\n", magic_enum::enum_name(aspectR.value()));
|
||||
LOG_INFO_IF(log_file_videoout, "width = {}\n", width);
|
||||
LOG_INFO_IF(log_file_videoout, "height = {}\n", height);
|
||||
LOG_INFO_IF(log_file_videoout, "pitchInPixel = {}\n", pitchInPixel);
|
||||
LOG_INFO(Lib_VideoOut,
|
||||
"pixelFormat = {}, tilingMode = {}, aspectRatio = {}, width = {}, height = {}, "
|
||||
"pitchInPixel = {}",
|
||||
getPixelFormatString(pixelFormat), tilingMode, aspectRatio, width, height,
|
||||
pitchInPixel);
|
||||
|
||||
std::memset(attribute, 0, sizeof(SceVideoOutBufferAttribute));
|
||||
|
||||
|
@ -100,7 +93,8 @@ static void flip_delete_event_func(Core::Kernel::SceKernelEqueue eq,
|
|||
|
||||
s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Core::Kernel::SceKernelEqueue eq, s32 handle,
|
||||
void* udata) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
LOG_INFO(Lib_VideoOut, "handle = {}", handle);
|
||||
|
||||
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
||||
|
||||
auto* ctx = videoOut->getCtx(handle);
|
||||
|
@ -136,46 +130,43 @@ s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Core::Kernel::SceKernelEqueue eq, s32 h
|
|||
s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* const* addresses,
|
||||
s32 bufferNum,
|
||||
const SceVideoOutBufferAttribute* attribute) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
||||
auto* ctx = videoOut->getCtx(handle);
|
||||
|
||||
if (handle == 1) { // main port
|
||||
if (startIndex < 0 || startIndex > 15) {
|
||||
LOG_TRACE_IF(log_file_videoout, "invalid startIndex = {}\n", startIndex);
|
||||
LOG_ERROR(Lib_VideoOut, "Invalid startIndex = {}", startIndex);
|
||||
return SCE_VIDEO_OUT_ERROR_INVALID_VALUE;
|
||||
}
|
||||
if (bufferNum < 1 || bufferNum > 16) {
|
||||
LOG_TRACE_IF(log_file_videoout, "invalid bufferNum = {}\n", bufferNum);
|
||||
LOG_ERROR(Lib_VideoOut, "Invalid bufferNum = {}", bufferNum);
|
||||
return SCE_VIDEO_OUT_ERROR_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
if (addresses == nullptr) {
|
||||
LOG_TRACE_IF(log_file_videoout, "addresses are null\n");
|
||||
LOG_ERROR(Lib_VideoOut, "Addresses are null");
|
||||
return SCE_VIDEO_OUT_ERROR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
if (attribute == nullptr) {
|
||||
LOG_TRACE_IF(log_file_videoout, "attribute is null\n");
|
||||
LOG_ERROR(Lib_VideoOut, "Attribute is null");
|
||||
return SCE_VIDEO_OUT_ERROR_INVALID_OPTION;
|
||||
}
|
||||
if (attribute->aspectRatio != 0) {
|
||||
LOG_TRACE_IF(log_file_videoout, "invalid aspect ratio = {}\n", attribute->aspectRatio);
|
||||
LOG_ERROR(Lib_VideoOut, "Invalid aspect ratio = {}", attribute->aspectRatio);
|
||||
return SCE_VIDEO_OUT_ERROR_INVALID_ASPECT_RATIO;
|
||||
}
|
||||
if (attribute->tilingMode < 0 || attribute->tilingMode > 1) {
|
||||
LOG_TRACE_IF(log_file_videoout, "invalid tilingMode = {}\n", attribute->tilingMode);
|
||||
LOG_ERROR(Lib_VideoOut, "Invalid tilingMode = {}", attribute->tilingMode);
|
||||
return SCE_VIDEO_OUT_ERROR_INVALID_TILING_MODE;
|
||||
}
|
||||
LOG_INFO_IF(log_file_videoout, "startIndex = {}\n", startIndex);
|
||||
LOG_INFO_IF(log_file_videoout, "bufferNum = {}\n", bufferNum);
|
||||
LOG_INFO_IF(log_file_videoout, "pixelFormat = {:#x}\n", attribute->pixelFormat);
|
||||
LOG_INFO_IF(log_file_videoout, "tilingMode = {}\n", attribute->tilingMode);
|
||||
LOG_INFO_IF(log_file_videoout, "aspectRatio = {}\n", attribute->aspectRatio);
|
||||
LOG_INFO_IF(log_file_videoout, "width = {}\n", attribute->width);
|
||||
LOG_INFO_IF(log_file_videoout, "height = {}\n", attribute->height);
|
||||
LOG_INFO_IF(log_file_videoout, "pitchInPixel = {}\n", attribute->pitchInPixel);
|
||||
LOG_INFO_IF(log_file_videoout, "option = {}\n", attribute->option);
|
||||
|
||||
LOG_INFO(Lib_VideoOut,
|
||||
"handle = {}, startIndex = {}, bufferNum = {}, pixelFormat = {:#x}, aspectRatio = {}, "
|
||||
"tilingMode = {}, width = {}, height = {}, pitchInPixel = {}, option = {:#x}",
|
||||
handle, startIndex, bufferNum, attribute->pixelFormat, attribute->aspectRatio,
|
||||
attribute->tilingMode, attribute->width, attribute->height, attribute->pitchInPixel,
|
||||
attribute->option);
|
||||
|
||||
int registration_index = ctx->buffers_registration_index++;
|
||||
|
||||
|
@ -214,7 +205,7 @@ s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* co
|
|||
|
||||
for (int i = 0; i < bufferNum; i++) {
|
||||
if (ctx->buffers[i + startIndex].buffer != nullptr) {
|
||||
LOG_TRACE_IF(log_file_videoout, "buffer slot {} is occupied!\n", i + startIndex);
|
||||
LOG_ERROR(Lib_VideoOut, "Buffer slot {} is occupied!", i + startIndex);
|
||||
return SCE_VIDEO_OUT_ERROR_SLOT_OCCUPIED;
|
||||
}
|
||||
|
||||
|
@ -227,51 +218,49 @@ s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* co
|
|||
0, videoOut->getGraphicCtx(), nullptr, reinterpret_cast<uint64_t>(addresses[i]),
|
||||
buffer_size, buffer_info));
|
||||
|
||||
LOG_INFO_IF(log_file_videoout, "buffers[{}] = {:#x}\n", i + startIndex,
|
||||
reinterpret_cast<u64>(addresses[i]));
|
||||
LOG_INFO(Lib_VideoOut, "buffers[{}] = {:#x}", i + startIndex,
|
||||
reinterpret_cast<u64>(addresses[i]));
|
||||
}
|
||||
|
||||
return registration_index;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutSetFlipRate(s32 handle, s32 rate) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
LOG_INFO(Lib_VideoOut, "called");
|
||||
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();
|
||||
LOG_INFO(Lib_VideoOut, "called");
|
||||
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();
|
||||
auto* ctx = videoOut->getCtx(handle);
|
||||
|
||||
if (flipMode != 1) {
|
||||
// BREAKPOINT(); // only flipmode==1 is supported
|
||||
LOG_TRACE_IF(log_file_videoout, "sceVideoOutSubmitFlip flipmode {}\n",
|
||||
bufferIndex); // openBOR needs 2 but seems to work
|
||||
LOG_WARNING(Lib_VideoOut, "flipmode = {}",
|
||||
flipMode); // openBOR needs 2 but seems to work
|
||||
}
|
||||
if (bufferIndex == -1) {
|
||||
BREAKPOINT(); // blank output not supported
|
||||
}
|
||||
if (bufferIndex < -1 || bufferIndex > 15) {
|
||||
LOG_TRACE_IF(log_file_videoout, "sceVideoOutSubmitFlip invalid bufferIndex {}\n",
|
||||
bufferIndex);
|
||||
LOG_ERROR(Lib_VideoOut, "Invalid bufferIndex = {}", bufferIndex);
|
||||
return SCE_VIDEO_OUT_ERROR_INVALID_INDEX;
|
||||
}
|
||||
LOG_INFO_IF(log_file_videoout, "bufferIndex = {}\n", bufferIndex);
|
||||
LOG_INFO_IF(log_file_videoout, "flipMode = {}\n", flipMode);
|
||||
LOG_INFO_IF(log_file_videoout, "flipArg = {}\n", flipArg);
|
||||
|
||||
LOG_INFO(Lib_VideoOut, "bufferIndex = {}, flipMode = {}, flipArg = {}", bufferIndex, flipMode,
|
||||
flipArg);
|
||||
|
||||
if (!videoOut->getFlipQueue().submitFlip(ctx, bufferIndex, flipArg)) {
|
||||
LOG_TRACE_IF(log_file_videoout, "sceVideoOutSubmitFlip flip queue is full\n");
|
||||
LOG_ERROR(Lib_VideoOut, "Flip queue is full");
|
||||
return SCE_VIDEO_OUT_ERROR_FLIP_QUEUE_FULL;
|
||||
}
|
||||
Core::Libraries::LibSceGnmDriver::sceGnmFlushGarlic(); // hackish should be done that neccesary
|
||||
|
@ -280,24 +269,20 @@ s32 PS4_SYSV_ABI sceVideoOutSubmitFlip(s32 handle, s32 bufferIndex, s32 flipMode
|
|||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutGetFlipStatus(s32 handle, SceVideoOutFlipStatus* status) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
||||
auto* ctx = videoOut->getCtx(handle);
|
||||
videoOut->getFlipQueue().getFlipStatus(ctx, status);
|
||||
|
||||
LOG_INFO_IF(log_file_videoout, "count = {}\n", status->count);
|
||||
LOG_INFO_IF(log_file_videoout, "processTime = {}\n", status->processTime);
|
||||
LOG_INFO_IF(log_file_videoout, "tsc = {}\n", status->tsc);
|
||||
LOG_INFO_IF(log_file_videoout, "submitTsc = {}\n", status->submitTsc);
|
||||
LOG_INFO_IF(log_file_videoout, "flipArg = {}\n", status->flipArg);
|
||||
LOG_INFO_IF(log_file_videoout, "gcQueueNum = {}\n", status->gcQueueNum);
|
||||
LOG_INFO_IF(log_file_videoout, "flipPendingNum = {}\n", status->flipPendingNum);
|
||||
LOG_INFO_IF(log_file_videoout, "currentBuffer = {}\n", status->currentBuffer);
|
||||
LOG_INFO(Lib_VideoOut,
|
||||
"count = {}, processTime = {}, tsc = {}, submitTsc = {}, flipArg = {}, gcQueueNum = "
|
||||
"{}, flipPendingNum = {}, currentBuffer = {}",
|
||||
status->count, status->processTime, status->tsc, status->submitTsc, status->flipArg,
|
||||
status->gcQueueNum, status->flipPendingNum, status->currentBuffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutGetResolutionStatus(s32 handle, SceVideoOutResolutionStatus* status) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
LOG_INFO(Lib_VideoOut, "called");
|
||||
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
||||
*status = videoOut->getCtx(handle)->m_resolution;
|
||||
return SCE_OK;
|
||||
|
@ -305,7 +290,7 @@ s32 PS4_SYSV_ABI sceVideoOutGetResolutionStatus(s32 handle, SceVideoOutResolutio
|
|||
|
||||
s32 PS4_SYSV_ABI sceVideoOutOpen(SceUserServiceUserId userId, s32 busType, s32 index,
|
||||
const void* param) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
LOG_INFO(Lib_VideoOut, "called");
|
||||
if (userId != SCE_USER_SERVICE_USER_ID_SYSTEM && userId != 0) {
|
||||
BREAKPOINT();
|
||||
}
|
||||
|
@ -313,7 +298,7 @@ s32 PS4_SYSV_ABI sceVideoOutOpen(SceUserServiceUserId userId, s32 busType, s32 i
|
|||
BREAKPOINT();
|
||||
}
|
||||
if (index != 0) {
|
||||
LOG_TRACE_IF(log_file_videoout, "sceVideoOutOpen index!=0\n");
|
||||
LOG_ERROR(Lib_VideoOut, "Index != 0");
|
||||
return SCE_VIDEO_OUT_ERROR_INVALID_VALUE;
|
||||
}
|
||||
if (param != nullptr) {
|
||||
|
@ -323,7 +308,7 @@ s32 PS4_SYSV_ABI sceVideoOutOpen(SceUserServiceUserId userId, s32 busType, s32 i
|
|||
int handle = videoOut->Open();
|
||||
|
||||
if (handle < 0) {
|
||||
LOG_TRACE_IF(log_file_videoout, "sceVideoOutOpen all available handles are open\n");
|
||||
LOG_ERROR(Lib_VideoOut, "All available handles are open");
|
||||
return SCE_VIDEO_OUT_ERROR_RESOURCE_BUSY; // it is alreadyOpened
|
||||
}
|
||||
|
||||
|
@ -342,7 +327,6 @@ s32 PS4_SYSV_ABI sceVideoOutUnregisterBuffers(s32 handle, s32 attributeIndex) {
|
|||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/log.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/aerolib/aerolib.h"
|
||||
#include "core/aerolib/stubs.h"
|
||||
|
||||
|
@ -22,13 +22,12 @@ namespace Core::AeroLib {
|
|||
constexpr u32 MAX_STUBS = 128;
|
||||
|
||||
u64 UnresolvedStub() {
|
||||
LOG_ERROR("Unresolved Stub: called, returning zero to {}\n", __builtin_return_address(0));
|
||||
LOG_ERROR(Core, "Returning zero to {}", __builtin_return_address(0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 UnknownStub() {
|
||||
LOG_ERROR("Stub: Unknown (nid: Unknown) called, returning zero to {}\n",
|
||||
__builtin_return_address(0));
|
||||
LOG_ERROR(Core, "Returning zero to {}", __builtin_return_address(0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -39,10 +38,10 @@ 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,
|
||||
LOG_ERROR(Core, "Stub: {} (nid: {}) called, returning zero to {}", entry->name, entry->nid,
|
||||
__builtin_return_address(0));
|
||||
} else {
|
||||
LOG_ERROR("Stub: Unknown (nid: {}) called, returning zero to {}\n",
|
||||
LOG_ERROR(Core, "Stub: Unknown (nid: {}) called, returning zero to {}",
|
||||
stub_nids_unknown[stub_index], __builtin_return_address(0));
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -8,21 +8,24 @@ namespace Core::FileSys {
|
|||
|
||||
constexpr int RESERVED_HANDLES = 3; // First 3 handles are stdin,stdout,stderr
|
||||
|
||||
void MntPoints::mount(const std::string& host_folder, const std::string& guest_folder) {
|
||||
void MntPoints::Mount(const std::filesystem::path& host_folder, const std::string& guest_folder) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
MntPair pair;
|
||||
pair.host_path = host_folder;
|
||||
pair.host_path = host_folder.string();
|
||||
pair.guest_path = guest_folder;
|
||||
|
||||
m_mnt_pairs.push_back(pair);
|
||||
}
|
||||
void MntPoints::unmount(const std::string& path) {} // TODO!
|
||||
void MntPoints::unmountAll() {
|
||||
|
||||
void MntPoints::Unmount(const std::string& path) {} // TODO!
|
||||
|
||||
void MntPoints::UnmountAll() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
m_mnt_pairs.clear();
|
||||
}
|
||||
std::string MntPoints::getHostDirectory(const std::string& guest_directory) {
|
||||
|
||||
std::string MntPoints::GetHostDirectory(const std::string& guest_directory) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
for (auto& pair : m_mnt_pairs) {
|
||||
if (pair.guest_path.starts_with(guest_directory)) {
|
||||
|
@ -38,7 +41,8 @@ std::string MntPoints::getHostDirectory(const std::string& guest_directory) {
|
|||
}
|
||||
return "";
|
||||
}
|
||||
std::string MntPoints::getHostFile(const std::string& guest_file) {
|
||||
|
||||
std::string MntPoints::GetHostFile(const std::string& guest_file) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
for (auto& pair : m_mnt_pairs) {
|
||||
|
@ -52,11 +56,13 @@ std::string MntPoints::getHostFile(const std::string& guest_file) {
|
|||
}
|
||||
return "";
|
||||
}
|
||||
int HandleTable::createHandle() {
|
||||
|
||||
int HandleTable::CreateHandle() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
auto* file = new File{};
|
||||
file->isDirectory = false;
|
||||
file->isOpened = false;
|
||||
file->is_directory = false;
|
||||
file->is_opened = false;
|
||||
|
||||
int existingFilesNum = m_files.size();
|
||||
|
||||
|
@ -68,19 +74,20 @@ int HandleTable::createHandle() {
|
|||
}
|
||||
|
||||
m_files.push_back(file);
|
||||
|
||||
return m_files.size() + RESERVED_HANDLES - 1;
|
||||
}
|
||||
void HandleTable::deleteHandle(int d) {
|
||||
|
||||
void HandleTable::DeleteHandle(int d) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
delete m_files.at(d - RESERVED_HANDLES);
|
||||
m_files[d - RESERVED_HANDLES] = nullptr;
|
||||
}
|
||||
|
||||
File* HandleTable::getFile(int d) {
|
||||
File* HandleTable::GetFile(int d) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return m_files.at(d - RESERVED_HANDLES);
|
||||
}
|
||||
|
||||
File* HandleTable::getFile(const std::string& host_name) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
for (auto* file : m_files) {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "common/fs_file.h"
|
||||
#include "common/io_file.h"
|
||||
|
||||
namespace Core::FileSys {
|
||||
|
@ -21,11 +20,12 @@ public:
|
|||
|
||||
MntPoints() = default;
|
||||
virtual ~MntPoints() = default;
|
||||
void mount(const std::string& host_folder, const std::string& guest_folder);
|
||||
void unmount(const std::string& path);
|
||||
void unmountAll();
|
||||
std::string getHostDirectory(const std::string& guest_directory);
|
||||
std::string getHostFile(const std::string& guest_file);
|
||||
|
||||
void Mount(const std::filesystem::path& host_folder, const std::string& guest_folder);
|
||||
void Unmount(const std::string& path);
|
||||
void UnmountAll();
|
||||
std::string GetHostDirectory(const std::string& guest_directory);
|
||||
std::string GetHostFile(const std::string& guest_file);
|
||||
|
||||
private:
|
||||
std::vector<MntPair> m_mnt_pairs;
|
||||
|
@ -33,22 +33,24 @@ private:
|
|||
};
|
||||
|
||||
struct File {
|
||||
std::atomic_bool isOpened;
|
||||
std::atomic_bool isDirectory;
|
||||
std::atomic_bool is_opened{};
|
||||
std::atomic_bool is_directory{};
|
||||
std::string m_host_name;
|
||||
std::string m_guest_name;
|
||||
IOFile f;
|
||||
Common::FS::IOFile f;
|
||||
// std::vector<Common::FS::DirEntry> dirents;
|
||||
u32 dirents_index;
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
class HandleTable {
|
||||
public:
|
||||
HandleTable() {}
|
||||
virtual ~HandleTable() {}
|
||||
int createHandle();
|
||||
void deleteHandle(int d);
|
||||
File* getFile(int d);
|
||||
HandleTable() = default;
|
||||
virtual ~HandleTable() = default;
|
||||
|
||||
int CreateHandle();
|
||||
void DeleteHandle(int d);
|
||||
File* GetFile(int d);
|
||||
File* getFile(const std::string& host_name);
|
||||
|
||||
private:
|
||||
|
|
|
@ -2,14 +2,13 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "Util/config.h"
|
||||
#include "common/log.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/kernel/cpu_management.h"
|
||||
#include "core/hle/libraries/libs.h"
|
||||
|
||||
namespace Core::Kernel {
|
||||
|
||||
int PS4_SYSV_ABI sceKernelIsNeoMode() {
|
||||
PRINT_FUNCTION_NAME();
|
||||
LOG_INFO(Kernel_Sce, "called");
|
||||
return Config::isNeoMode();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,51 +1,44 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/error_codes.h"
|
||||
#include "core/hle/kernel/event_queues.h"
|
||||
#include "core/hle/libraries/libs.h"
|
||||
|
||||
namespace Core::Kernel {
|
||||
|
||||
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");
|
||||
LOG_ERROR(Kernel_Event, "Event queue is null!");
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (name == nullptr) {
|
||||
LOG_TRACE_IF(log_file_equeues,
|
||||
"sceKernelCreateEqueue returned SCE_KERNEL_ERROR_EFAULT name invalid\n");
|
||||
LOG_ERROR(Kernel_Event, "Event queue name is invalid!");
|
||||
return SCE_KERNEL_ERROR_EFAULT;
|
||||
}
|
||||
if (name == NULL) {
|
||||
LOG_TRACE_IF(log_file_equeues,
|
||||
"sceKernelCreateEqueue returned SCE_KERNEL_ERROR_EINVAL name is null\n");
|
||||
LOG_ERROR(Kernel_Event, "Event queue name is null!");
|
||||
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");
|
||||
// Maximum is 32 including null terminator
|
||||
static constexpr size_t MaxEventQueueNameSize = 32;
|
||||
if (std::strlen(name) > MaxEventQueueNameSize) {
|
||||
LOG_ERROR(Kernel_Event, "Event queue name exceeds 32 bytes!");
|
||||
return SCE_KERNEL_ERROR_ENAMETOOLONG;
|
||||
}
|
||||
|
||||
LOG_INFO(Kernel_Event, "name = {}", name);
|
||||
|
||||
*eq = new 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, SceKernelEvent* ev, int num, int* out,
|
||||
SceKernelUseconds* timo) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
LOG_INFO(Kernel_Event, "num = {}", num);
|
||||
|
||||
if (eq == nullptr) {
|
||||
return SCE_KERNEL_ERROR_EBADF;
|
||||
|
@ -66,10 +59,10 @@ int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int
|
|||
if (timo != nullptr) {
|
||||
// Only events that have already arrived at the time of this function call can be received
|
||||
if (*timo == 0) {
|
||||
BREAKPOINT();
|
||||
UNREACHABLE();
|
||||
} else {
|
||||
// Wait until an event arrives with timing out
|
||||
BREAKPOINT();
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,106 +2,85 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <bit>
|
||||
#include <magic_enum.hpp>
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/singleton.h"
|
||||
#include "core/PS4/GPU/gpu_memory.h"
|
||||
#include "core/hle/error_codes.h"
|
||||
#include "core/hle/kernel/Objects/physical_memory.h"
|
||||
#include "core/hle/kernel/memory_management.h"
|
||||
#include "core/hle/libraries/libs.h"
|
||||
#include "core/virtual_memory.h"
|
||||
|
||||
namespace Core::Kernel {
|
||||
|
||||
constexpr bool log_file_memory = true; // disable it to disable logging
|
||||
|
||||
bool is16KBAligned(u64 n) {
|
||||
return ((n % (16ull * 1024) == 0));
|
||||
}
|
||||
|
||||
u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize() {
|
||||
PRINT_FUNCTION_NAME();
|
||||
LOG_WARNING(Kernel_Vmm, "(STUBBED) called");
|
||||
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();
|
||||
LOG_INFO(Kernel_Vmm,
|
||||
"searchStart = {:#x}, searchEnd = {:#x}, len = {:#x}, alignment = {:#x}, memoryType = "
|
||||
"{:#x}",
|
||||
searchStart, searchEnd, len, alignment, memoryType);
|
||||
|
||||
if (searchStart < 0 || searchEnd <= searchStart) {
|
||||
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned "
|
||||
"SCE_KERNEL_ERROR_EINVAL searchStart,searchEnd invalid\n");
|
||||
LOG_ERROR(Kernel_Vmm, "Provided address range is invalid!");
|
||||
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");
|
||||
const bool is_in_range = (searchStart < len && searchEnd > len);
|
||||
if (len <= 0 || !is16KBAligned(len) || !is_in_range) {
|
||||
LOG_ERROR(Kernel_Vmm, "Provided address range is invalid!");
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if ((alignment != 0 || is16KBAligned(alignment)) && !std::has_single_bit(alignment)) {
|
||||
LOG_TRACE_IF(
|
||||
log_file_memory,
|
||||
"sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EINVAL alignment invalid\n");
|
||||
LOG_ERROR(Kernel_Vmm, "Alignment value is invalid!");
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (physAddrOut == nullptr) {
|
||||
LOG_TRACE_IF(
|
||||
log_file_memory,
|
||||
"sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EINVAL physAddrOut is null\n");
|
||||
LOG_ERROR(Kernel_Vmm, "Result physical address pointer is null!");
|
||||
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<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");
|
||||
LOG_CRITICAL(Kernel_Vmm, "Unable to allocate physical memory");
|
||||
return SCE_KERNEL_ERROR_EAGAIN;
|
||||
}
|
||||
*physAddrOut = static_cast<s64>(physical_addr);
|
||||
LOG_INFO_IF(true, "physAddrOut = {:#x}\n", physical_addr);
|
||||
LOG_INFO(Kernel_Vmm, "physAddrOut = {:#x}", 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();
|
||||
LOG_INFO(
|
||||
Kernel_Vmm,
|
||||
"len = {:#x}, prot = {:#x}, flags = {:#x}, directMemoryStart = {:#x}, alignment = {:#x}",
|
||||
len, prot, flags, directMemoryStart, alignment);
|
||||
|
||||
if (len == 0 || !is16KBAligned(len)) {
|
||||
LOG_TRACE_IF(log_file_memory,
|
||||
"sceKernelMapDirectMemory returned SCE_KERNEL_ERROR_EINVAL len invalid\n");
|
||||
LOG_ERROR(Kernel_Vmm, "Map size is either zero or not 16KB aligned!");
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (!is16KBAligned(directMemoryStart)) {
|
||||
LOG_TRACE_IF(log_file_memory, "sceKernelMapDirectMemory returned SCE_KERNEL_ERROR_EINVAL "
|
||||
"directMemoryStart invalid\n");
|
||||
LOG_ERROR(Kernel_Vmm, "Start address is not 16KB aligned!");
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (alignment != 0) {
|
||||
if ((!std::has_single_bit(alignment) && !is16KBAligned(alignment))) {
|
||||
LOG_TRACE_IF(
|
||||
log_file_memory,
|
||||
"sceKernelMapDirectMemory returned SCE_KERNEL_ERROR_EINVAL alignment invalid\n");
|
||||
LOG_ERROR(Kernel_Vmm, "Alignment value is invalid!");
|
||||
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;
|
||||
|
||||
|
@ -112,7 +91,7 @@ int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int fl
|
|||
gpu_mode = GPU::MemoryMode::ReadWrite;
|
||||
break;
|
||||
default:
|
||||
BREAKPOINT();
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
auto in_addr = reinterpret_cast<u64>(*addr);
|
||||
|
@ -121,8 +100,7 @@ int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int fl
|
|||
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);
|
||||
LOG_INFO(Kernel_Vmm, "in_addr = {:#x}, out_addr = {:#x}", in_addr, out_addr);
|
||||
|
||||
*addr = reinterpret_cast<void*>(out_addr); // return out_addr to first functions parameter
|
||||
|
||||
|
@ -132,7 +110,7 @@ int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int fl
|
|||
|
||||
auto* physical_memory = Common::Singleton<PhysicalMemory>::Instance();
|
||||
if (!physical_memory->Map(out_addr, directMemoryStart, len, prot, cpu_mode, gpu_mode)) {
|
||||
BREAKPOINT();
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
if (gpu_mode != GPU::MemoryMode::NoAccess) {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include <cstdlib>
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/singleton.h"
|
||||
#include "core/hle/libraries/libc/libc.h"
|
||||
#include "core/hle/libraries/libc/libc_cxa.h"
|
||||
|
@ -49,15 +49,15 @@ void PS4_SYSV_ABI ps4___cxa_pure_virtual() {
|
|||
}
|
||||
|
||||
static PS4_SYSV_ABI void ps4_init_env() {
|
||||
PRINT_DUMMY_FUNCTION_NAME();
|
||||
LOG_INFO(Lib_LibC, "called");
|
||||
}
|
||||
|
||||
static PS4_SYSV_ABI void ps4_catchReturnFromMain(int status) {
|
||||
LOG_INFO_IF(log_file_libc, "catchReturnFromMain returned ={}\n", status);
|
||||
LOG_INFO(Lib_LibC, "returned = {}", status);
|
||||
}
|
||||
|
||||
static PS4_SYSV_ABI void ps4__Assert() {
|
||||
PRINT_DUMMY_FUNCTION_NAME();
|
||||
LOG_INFO(Lib_LibC, "called");
|
||||
BREAKPOINT();
|
||||
}
|
||||
|
||||
|
@ -66,18 +66,18 @@ PS4_SYSV_ABI void ps4__ZdlPv(void* ptr) {
|
|||
}
|
||||
|
||||
PS4_SYSV_ABI void ps4__ZSt11_Xbad_allocv() {
|
||||
PRINT_DUMMY_FUNCTION_NAME();
|
||||
LOG_INFO(Lib_LibC, "called");
|
||||
BREAKPOINT();
|
||||
}
|
||||
|
||||
PS4_SYSV_ABI void ps4__ZSt14_Xlength_errorPKc() {
|
||||
PRINT_DUMMY_FUNCTION_NAME();
|
||||
LOG_INFO(Lib_LibC, "called");
|
||||
BREAKPOINT();
|
||||
}
|
||||
|
||||
PS4_SYSV_ABI void* ps4__Znwm(u64 count) {
|
||||
if (count == 0) {
|
||||
LOG_ERROR_IF(log_file_libc, "_Znwm count ={}\n", count);
|
||||
LOG_INFO(Lib_LibC, "_Znwm count ={}", count);
|
||||
BREAKPOINT();
|
||||
}
|
||||
void* ptr = std::malloc(count);
|
||||
|
@ -457,6 +457,7 @@ void libcSymbolsRegister(Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("8zTFvBIAIN8", "libc", 1, "libc", 1, 1, ps4_memset);
|
||||
|
||||
// stdio functions
|
||||
LIB_FUNCTION("xeYO4u7uyJ0", "libc", 1, "libc", 1, 1, ps4_fopen);
|
||||
LIB_FUNCTION("hcuQgD53UxM", "libc", 1, "libc", 1, 1, ps4_printf);
|
||||
LIB_FUNCTION("Q2V+iqvjgC0", "libc", 1, "libc", 1, 1, ps4_vsnprintf);
|
||||
LIB_FUNCTION("YQ0navp+YIc", "libc", 1, "libc", 1, 1, ps4_puts);
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/libraries/libc/libc_cxa.h"
|
||||
|
||||
// adapted from
|
||||
|
@ -10,8 +9,6 @@
|
|||
|
||||
namespace Core::Libraries::LibC {
|
||||
|
||||
constexpr bool log_file_cxa = true; // disable it to disable logging
|
||||
|
||||
// This file implements the __cxa_guard_* functions as defined at:
|
||||
// http://www.codesourcery.com/public/cxx-abi/abi.html
|
||||
//
|
||||
|
@ -103,8 +100,7 @@ int PS4_SYSV_ABI ps4___cxa_guard_acquire(u64* guard_object) {
|
|||
|
||||
int result = ::pthread_mutex_lock(guard_mutex());
|
||||
if (result != 0) {
|
||||
LOG_TRACE_IF(log_file_cxa, "__cxa_guard_acquire(): pthread_mutex_lock failed with {}\n",
|
||||
result);
|
||||
LOG_ERROR(Lib_LibC, "pthread_mutex_lock failed with {}", result);
|
||||
}
|
||||
// At this point all other threads will block in __cxa_guard_acquire()
|
||||
|
||||
|
@ -112,8 +108,7 @@ int PS4_SYSV_ABI ps4___cxa_guard_acquire(u64* guard_object) {
|
|||
if (initializerHasRun(guard_object)) {
|
||||
int result = ::pthread_mutex_unlock(guard_mutex());
|
||||
if (result != 0) {
|
||||
LOG_TRACE_IF(log_file_cxa,
|
||||
"__cxa_guard_acquire(): pthread_mutex_unlock failed with {}\n", result);
|
||||
LOG_ERROR(Lib_LibC, "pthread_mutex_lock failed with {}", result);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -123,8 +118,8 @@ int PS4_SYSV_ABI ps4___cxa_guard_acquire(u64* guard_object) {
|
|||
// But if the same thread can call __cxa_guard_acquire() on the
|
||||
// *same* guard object again, we call abort();
|
||||
if (inUse(guard_object)) {
|
||||
LOG_TRACE_IF(log_file_cxa, "__cxa_guard_acquire(): initializer for function local static "
|
||||
"variable called enclosing function\n");
|
||||
LOG_ERROR(Lib_LibC,
|
||||
"initializer for function local static variable called enclosing function");
|
||||
}
|
||||
|
||||
// mark this guard object as being in use
|
||||
|
@ -146,8 +141,7 @@ void PS4_SYSV_ABI ps4___cxa_guard_release(u64* guard_object) {
|
|||
// release global mutex
|
||||
int result = ::pthread_mutex_unlock(guard_mutex());
|
||||
if (result != 0) {
|
||||
LOG_TRACE_IF(log_file_cxa, "__cxa_guard_acquire(): pthread_mutex_unlock failed with {}\n",
|
||||
result);
|
||||
LOG_ERROR(Lib_LibC, "pthread_mutex_unlock failed with {}", result);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,8 +151,7 @@ void PS4_SYSV_ABI ps4___cxa_guard_release(u64* guard_object) {
|
|||
void PS4_SYSV_ABI ps4___cxa_guard_abort(u64* guard_object) {
|
||||
int result = ::pthread_mutex_unlock(guard_mutex());
|
||||
if (result != 0) {
|
||||
LOG_TRACE_IF(log_file_cxa, "__cxa_guard_abort(): pthread_mutex_unlock failed with {}\n",
|
||||
result);
|
||||
LOG_ERROR(Lib_LibC, "pthread_mutex_unlock failed with {}", result);
|
||||
}
|
||||
|
||||
// now reset state, so possible to try to initialize again
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/singleton.h"
|
||||
#include "core/file_sys/fs.h"
|
||||
#include "core/hle/libraries/libc/libc_stdio.h"
|
||||
|
||||
namespace Core::Libraries::LibC {
|
||||
|
||||
constexpr bool log_file_libc = true; // disable it to disable logging
|
||||
std::FILE* PS4_SYSV_ABI ps4_fopen(const char* filename, const char* mode) {
|
||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||
return std::fopen(mnt->GetHostFile(filename).c_str(), mode);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI ps4_printf(VA_ARGS) {
|
||||
VA_CTX(ctx);
|
||||
|
@ -20,8 +24,8 @@ int PS4_SYSV_ABI ps4_fprintf(FILE* file, VA_ARGS) {
|
|||
VA_CTX(ctx);
|
||||
return printf_ctx(&ctx);
|
||||
}
|
||||
LOG_ERROR_IF(log_file_libc, "libc:Unimplemented fprintf case\n");
|
||||
BREAKPOINT();
|
||||
|
||||
UNREACHABLE_MSG("Unimplemented fprintf case");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
namespace Core::Libraries::LibC {
|
||||
|
||||
std::FILE* PS4_SYSV_ABI ps4_fopen(const char* filename, const char* mode);
|
||||
int PS4_SYSV_ABI ps4_printf(VA_ARGS);
|
||||
int PS4_SYSV_ABI ps4_vsnprintf(char* s, size_t n, const char* format, VaList* arg);
|
||||
int PS4_SYSV_ABI ps4_puts(const char* s);
|
||||
|
|
|
@ -2,24 +2,18 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstdlib>
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "common/assert.h"
|
||||
#include "core/hle/libraries/libc/libc_stdlib.h"
|
||||
|
||||
namespace Core::Libraries::LibC {
|
||||
|
||||
constexpr bool log_file_libc = true; // disable it to disable logging
|
||||
|
||||
void PS4_SYSV_ABI ps4_exit(int code) {
|
||||
std::exit(code);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI ps4_atexit(void (*func)()) {
|
||||
int rt = std::atexit(func);
|
||||
if (rt != 0) {
|
||||
LOG_ERROR_IF(log_file_libc, "atexit returned {}\n", rt);
|
||||
BREAKPOINT();
|
||||
}
|
||||
ASSERT_MSG(rt == 0, "atexit returned {}", rt);
|
||||
return rt;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
#include <cstdbool>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "va_ctx.h"
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/singleton.h"
|
||||
#include "core/file_sys/fs.h"
|
||||
#include "core/hle/error_codes.h"
|
||||
|
@ -11,45 +11,41 @@
|
|||
|
||||
namespace Core::Libraries::LibKernel {
|
||||
|
||||
constexpr bool log_file_fs = true; // disable it to disable logging
|
||||
|
||||
int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) {
|
||||
LOG_INFO_IF(log_file_fs, "sceKernelOpen path = {} flags = {:#x} mode = {:#x}\n", path, flags,
|
||||
mode);
|
||||
LOG_INFO(Kernel_Fs, "path = {} flags = {:#x} mode = {:#x}", path, flags, mode);
|
||||
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||
|
||||
// only open files support!
|
||||
u32 handle = h->createHandle();
|
||||
auto* file = h->getFile(handle);
|
||||
u32 handle = h->CreateHandle();
|
||||
auto* file = h->GetFile(handle);
|
||||
file->m_guest_name = path;
|
||||
file->m_host_name = mnt->getHostFile(file->m_guest_name);
|
||||
file->m_host_name = mnt->GetHostFile(file->m_guest_name);
|
||||
|
||||
bool result = file->f.open(file->m_host_name);
|
||||
if (!result) {
|
||||
h->deleteHandle(handle);
|
||||
file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Read);
|
||||
if (!file->f.IsOpen()) {
|
||||
h->DeleteHandle(handle);
|
||||
return SCE_KERNEL_ERROR_EACCES;
|
||||
}
|
||||
file->isOpened = true;
|
||||
file->is_opened = true;
|
||||
return handle;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_open(const char* path, int flags, /* SceKernelMode*/ u16 mode) {
|
||||
LOG_INFO_IF(log_file_fs, "posix open redirect to sceKernelOpen\n");
|
||||
LOG_INFO(Kernel_Fs, "posix open redirect to sceKernelOpen\n");
|
||||
int result = sceKernelOpen(path, flags, mode);
|
||||
if (result < 0) {
|
||||
BREAKPOINT(); // posix calls different only for their return values
|
||||
}
|
||||
// Posix calls different only for their return values
|
||||
ASSERT(result >= 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t PS4_SYSV_ABI _readv(int d, const SceKernelIovec* iov, int iovcnt) {
|
||||
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||
auto* file = h->getFile(d);
|
||||
auto* file = h->GetFile(d);
|
||||
size_t total_read = 0;
|
||||
file->m_mutex.lock();
|
||||
for (int i = 0; i < iovcnt; i++) {
|
||||
total_read += file->f.readBytes(iov[i].iov_base, iov[i].iov_len).second;
|
||||
total_read += file->f.ReadRaw<u8>(iov[i].iov_base, iov[i].iov_len);
|
||||
}
|
||||
file->m_mutex.unlock();
|
||||
return total_read;
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Core::Libraries::LibKernel {
|
|||
|
||||
struct SceKernelIovec {
|
||||
void* iov_base;
|
||||
size_t iov_len;
|
||||
std::size_t iov_len;
|
||||
};
|
||||
|
||||
int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, /* SceKernelMode*/ u16 mode);
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "common/singleton.h"
|
||||
#include "core/hle/kernel/Objects/physical_memory.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/kernel/cpu_management.h"
|
||||
#include "core/hle/kernel/event_queues.h"
|
||||
#include "core/hle/kernel/memory_management.h"
|
||||
|
@ -24,21 +22,19 @@
|
|||
|
||||
namespace Core::Libraries::LibKernel {
|
||||
|
||||
constexpr bool log_libkernel_file = true; // disable it to disable logging
|
||||
|
||||
static u64 g_stack_chk_guard = 0xDEADBEEF54321ABC; // dummy return
|
||||
|
||||
int32_t PS4_SYSV_ABI sceKernelReleaseDirectMemory(off_t start, size_t len) {
|
||||
BREAKPOINT();
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PS4_SYSV_ABI void stack_chk_fail() {
|
||||
BREAKPOINT();
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len) {
|
||||
BREAKPOINT();
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void PS4_SYSV_ABI sceKernelUsleep(unsigned int microseconds) {
|
||||
|
@ -71,10 +67,9 @@ int* PS4_SYSV_ABI __Error() {
|
|||
int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd, off_t offset,
|
||||
void** res) {
|
||||
#ifdef _WIN64
|
||||
PRINT_FUNCTION_NAME();
|
||||
if (prot > 3) // READ,WRITE or bitwise READ | WRITE supported
|
||||
{
|
||||
LOG_ERROR_IF(log_libkernel_file, "sceKernelMmap prot ={} not supported\n", prot);
|
||||
LOG_INFO(Kernel_Vmm, "called");
|
||||
if (prot > 3) {
|
||||
LOG_ERROR(Kernel_Vmm, "prot = {} not supported", prot);
|
||||
}
|
||||
DWORD flProtect;
|
||||
if (prot & PROT_WRITE) {
|
||||
|
@ -114,13 +109,11 @@ int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd,
|
|||
|
||||
PS4_SYSV_ABI void* posix_mmap(void* addr, u64 len, int prot, int flags, int fd, u64 offset) {
|
||||
void* ptr;
|
||||
LOG_INFO_IF(log_libkernel_file, "posix mmap redirect to sceKernelMmap\n");
|
||||
LOG_INFO(Kernel_Vmm, "posix mmap redirect to sceKernelMmap\n");
|
||||
// posix call the difference is that there is a different behaviour when it doesn't return 0 or
|
||||
// SCE_OK
|
||||
int result = sceKernelMmap(addr, len, prot, flags, fd, offset, &ptr);
|
||||
if (result != 0) {
|
||||
BREAKPOINT();
|
||||
}
|
||||
ASSERT(result == 0);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/error_codes.h"
|
||||
#include "core/hle/libraries/libkernel/thread_management.h"
|
||||
#include "core/hle/libraries/libs.h"
|
||||
|
@ -12,8 +12,6 @@ namespace Core::Libraries::LibKernel {
|
|||
thread_local ScePthread g_pthread_self{};
|
||||
PThreadCxt* g_pthread_cxt = nullptr;
|
||||
|
||||
constexpr bool log_pthread_file = true; // disable it to disable logging
|
||||
|
||||
void init_pthreads() {
|
||||
g_pthread_cxt = new PThreadCxt{};
|
||||
// default mutex init
|
||||
|
@ -73,9 +71,7 @@ int PS4_SYSV_ABI scePthreadAttrSetdetachstate(ScePthreadAttr* attr, int detachst
|
|||
pstate = PTHREAD_CREATE_DETACHED;
|
||||
break;
|
||||
default:
|
||||
LOG_TRACE_IF(log_pthread_file, "scePthreadAttrSetdetachstate invalid detachstate: {}\n",
|
||||
detachstate);
|
||||
std::exit(0);
|
||||
UNREACHABLE_MSG("Invalid detachstate: {}", detachstate);
|
||||
}
|
||||
|
||||
// int result = pthread_attr_setdetachstate(&(*attr)->pth_attr, pstate); doesn't seem to work
|
||||
|
@ -101,9 +97,7 @@ int PS4_SYSV_ABI scePthreadAttrSetinheritsched(ScePthreadAttr* attr, int inherit
|
|||
pinherit_sched = PTHREAD_INHERIT_SCHED;
|
||||
break;
|
||||
default:
|
||||
LOG_TRACE_IF(log_pthread_file, "scePthreadAttrSetinheritsched invalid inheritSched: {}\n",
|
||||
inheritSched);
|
||||
std::exit(0);
|
||||
UNREACHABLE_MSG("Invalid inheritSched: {}", inheritSched);
|
||||
}
|
||||
|
||||
int result = pthread_attr_setinheritsched(&(*attr)->pth_attr, pinherit_sched);
|
||||
|
@ -138,9 +132,7 @@ int PS4_SYSV_ABI scePthreadAttrSetschedpolicy(ScePthreadAttr* attr, int policy)
|
|||
|
||||
int ppolicy = SCHED_OTHER; // winpthreads only supports SCHED_OTHER
|
||||
if (policy != SCHED_OTHER) {
|
||||
LOG_TRACE_IF(log_pthread_file,
|
||||
"scePthreadAttrSetschedpolicy policy={} not supported by winpthreads\n",
|
||||
policy);
|
||||
LOG_ERROR(Kernel_Pthread, "policy={} not supported by winpthreads\n", policy);
|
||||
}
|
||||
(*attr)->policy = policy;
|
||||
|
||||
|
@ -154,7 +146,7 @@ ScePthread PS4_SYSV_ABI scePthreadSelf() {
|
|||
|
||||
int PS4_SYSV_ABI scePthreadAttrSetaffinity(ScePthreadAttr* pattr,
|
||||
const /*SceKernelCpumask*/ u64 mask) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
LOG_INFO(Kernel_Pthread, "called");
|
||||
|
||||
if (pattr == nullptr || *pattr == nullptr) {
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
|
@ -166,7 +158,7 @@ int PS4_SYSV_ABI scePthreadAttrSetaffinity(ScePthreadAttr* pattr,
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadSetaffinity(ScePthread thread, const /*SceKernelCpumask*/ u64 mask) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
LOG_INFO(Kernel_Pthread, "called");
|
||||
|
||||
if (thread == nullptr) {
|
||||
return SCE_KERNEL_ERROR_ESRCH;
|
||||
|
@ -178,12 +170,10 @@ int PS4_SYSV_ABI scePthreadSetaffinity(ScePthread thread, const /*SceKernelCpuma
|
|||
}
|
||||
int PS4_SYSV_ABI scePthreadCreate(ScePthread* thread, const ScePthreadAttr* attr,
|
||||
pthreadEntryFunc start_routine, void* arg, const char* name) {
|
||||
PRINT_DUMMY_FUNCTION_NAME();
|
||||
LOG_INFO(Kernel_Pthread, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
/****
|
||||
* Mutex calls
|
||||
*/
|
||||
|
||||
void* createMutex(void* addr) {
|
||||
if (addr == nullptr || *static_cast<ScePthreadMutex*>(addr) != nullptr) {
|
||||
return addr;
|
||||
|
@ -197,7 +187,7 @@ void* createMutex(void* addr) {
|
|||
|
||||
int PS4_SYSV_ABI scePthreadMutexInit(ScePthreadMutex* mutex, const ScePthreadMutexattr* attr,
|
||||
const char* name) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
LOG_INFO(Kernel_Pthread, "called");
|
||||
if (mutex == nullptr) {
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
@ -215,7 +205,7 @@ int PS4_SYSV_ABI scePthreadMutexInit(ScePthreadMutex* mutex, const ScePthreadMut
|
|||
int result = pthread_mutex_init(&(*mutex)->pth_mutex, &(*attr)->pth_mutex_attr);
|
||||
|
||||
if (name != nullptr) {
|
||||
LOG_INFO_IF(log_pthread_file, "mutex_init name={},result={}\n", name, result);
|
||||
LOG_INFO(Kernel_Pthread, "name={}, result={}", name, result);
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
|
@ -264,8 +254,7 @@ int PS4_SYSV_ABI scePthreadMutexattrSettype(ScePthreadMutexattr* attr, int type)
|
|||
ptype = PTHREAD_MUTEX_NORMAL;
|
||||
break;
|
||||
default:
|
||||
LOG_TRACE_IF(log_pthread_file, "scePthreadMutexattrSettype invalid type: {}\n", type);
|
||||
std::exit(0);
|
||||
UNREACHABLE_MSG("Invalid type: {}", type);
|
||||
}
|
||||
|
||||
int result = pthread_mutexattr_settype(&(*attr)->pth_mutex_attr, ptype);
|
||||
|
@ -286,9 +275,7 @@ int PS4_SYSV_ABI scePthreadMutexattrSetprotocol(ScePthreadMutexattr* attr, int p
|
|||
pprotocol = PTHREAD_PRIO_PROTECT;
|
||||
break;
|
||||
default:
|
||||
LOG_TRACE_IF(log_pthread_file, "scePthreadMutexattrSetprotocol invalid protocol: {}\n",
|
||||
protocol);
|
||||
std::exit(0);
|
||||
UNREACHABLE_MSG("Invalid protocol: {}", protocol);
|
||||
}
|
||||
|
||||
int result = 0; // pthread_mutexattr_setprotocol(&(*attr)->p, pprotocol); //it appears that
|
||||
|
@ -298,7 +285,7 @@ int PS4_SYSV_ABI scePthreadMutexattrSetprotocol(ScePthreadMutexattr* attr, int p
|
|||
return result == 0 ? SCE_OK : SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
int PS4_SYSV_ABI scePthreadMutexLock(ScePthreadMutex* mutex) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
LOG_INFO(Kernel_Pthread, "called");
|
||||
mutex = static_cast<ScePthreadMutex*>(createMutex(mutex));
|
||||
|
||||
if (mutex == nullptr) {
|
||||
|
@ -306,8 +293,7 @@ int PS4_SYSV_ABI scePthreadMutexLock(ScePthreadMutex* mutex) {
|
|||
}
|
||||
|
||||
int result = pthread_mutex_lock(&(*mutex)->pth_mutex);
|
||||
LOG_INFO_IF(log_pthread_file, "scePthreadMutexLock name={} result={}\n", (*mutex)->name,
|
||||
result);
|
||||
LOG_INFO(Kernel_Pthread, "name={}, result={}", (*mutex)->name, result);
|
||||
switch (result) {
|
||||
case 0:
|
||||
return SCE_OK;
|
||||
|
@ -322,15 +308,14 @@ int PS4_SYSV_ABI scePthreadMutexLock(ScePthreadMutex* mutex) {
|
|||
}
|
||||
}
|
||||
int PS4_SYSV_ABI scePthreadMutexUnlock(ScePthreadMutex* mutex) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
LOG_INFO(Kernel_Pthread, "called");
|
||||
mutex = static_cast<ScePthreadMutex*>(createMutex(mutex));
|
||||
if (mutex == nullptr) {
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
int result = pthread_mutex_unlock(&(*mutex)->pth_mutex);
|
||||
LOG_INFO_IF(log_pthread_file, "scePthreadMutexUnlock name={} result={}\n", (*mutex)->name,
|
||||
result);
|
||||
LOG_INFO(Kernel_Pthread, "name={}, result={}", (*mutex)->name, result);
|
||||
switch (result) {
|
||||
case 0:
|
||||
return SCE_OK;
|
||||
|
@ -344,9 +329,6 @@ int PS4_SYSV_ABI scePthreadMutexUnlock(ScePthreadMutex* mutex) {
|
|||
}
|
||||
}
|
||||
|
||||
/****
|
||||
* Cond calls
|
||||
*/
|
||||
void* createCond(void* addr) {
|
||||
if (addr == nullptr || *static_cast<ScePthreadCond*>(addr) != nullptr) {
|
||||
return addr;
|
||||
|
@ -379,7 +361,7 @@ int PS4_SYSV_ABI scePthreadCondInit(ScePthreadCond* cond, const ScePthreadCondat
|
|||
int result = pthread_cond_init(&(*cond)->cond, &(*attr)->cond_attr);
|
||||
|
||||
if (name != nullptr) {
|
||||
LOG_INFO_IF(log_pthread_file, "cond init name={},result={}\n", (*cond)->name, result);
|
||||
LOG_INFO(Kernel_Pthread, "name={}, result={}", (*cond)->name, result);
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
|
@ -412,7 +394,7 @@ int PS4_SYSV_ABI scePthreadCondattrInit(ScePthreadCondattr* attr) {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadCondBroadcast(ScePthreadCond* cond) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
LOG_INFO(Kernel_Pthread, "called");
|
||||
cond = static_cast<ScePthreadCond*>(createCond(cond));
|
||||
|
||||
if (cond == nullptr) {
|
||||
|
@ -421,15 +403,13 @@ int PS4_SYSV_ABI scePthreadCondBroadcast(ScePthreadCond* cond) {
|
|||
|
||||
int result = pthread_cond_broadcast(&(*cond)->cond);
|
||||
|
||||
LOG_INFO_IF(log_pthread_file, "cond broadcast name={},result={}\n", (*cond)->name, result);
|
||||
LOG_INFO(Kernel_Pthread, "name={}, result={}", (*cond)->name, result);
|
||||
|
||||
return (result == 0 ? SCE_OK : SCE_KERNEL_ERROR_EINVAL);
|
||||
}
|
||||
/****
|
||||
* Posix calls
|
||||
*/
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_mutex_init(ScePthreadMutex* mutex, const ScePthreadMutexattr* attr) {
|
||||
LOG_INFO_IF(log_pthread_file, "posix pthread_mutex_init redirect to scePthreadMutexInit\n");
|
||||
LOG_INFO(Kernel_Pthread, "posix pthread_mutex_init redirect to scePthreadMutexInit");
|
||||
int result = scePthreadMutexInit(mutex, attr, nullptr);
|
||||
if (result < 0) {
|
||||
int rt = result > SCE_KERNEL_ERROR_UNKNOWN && result <= SCE_KERNEL_ERROR_ESTOP
|
||||
|
@ -441,7 +421,7 @@ int PS4_SYSV_ABI posix_pthread_mutex_init(ScePthreadMutex* mutex, const ScePthre
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_mutex_lock(ScePthreadMutex* mutex) {
|
||||
LOG_INFO_IF(log_pthread_file, "posix pthread_mutex_lock redirect to scePthreadMutexLock\n");
|
||||
LOG_INFO(Kernel_Pthread, "posix pthread_mutex_lock redirect to scePthreadMutexLock");
|
||||
int result = scePthreadMutexLock(mutex);
|
||||
if (result < 0) {
|
||||
int rt = result > SCE_KERNEL_ERROR_UNKNOWN && result <= SCE_KERNEL_ERROR_ESTOP
|
||||
|
@ -453,7 +433,7 @@ int PS4_SYSV_ABI posix_pthread_mutex_lock(ScePthreadMutex* mutex) {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_mutex_unlock(ScePthreadMutex* mutex) {
|
||||
LOG_INFO_IF(log_pthread_file, "posix pthread_mutex_unlock redirect to scePthreadMutexUnlock\n");
|
||||
LOG_INFO(Kernel_Pthread, "posix pthread_mutex_unlock redirect to scePthreadMutexUnlock");
|
||||
int result = scePthreadMutexUnlock(mutex);
|
||||
if (result < 0) {
|
||||
int rt = result > SCE_KERNEL_ERROR_UNKNOWN && result <= SCE_KERNEL_ERROR_ESTOP
|
||||
|
@ -465,8 +445,8 @@ int PS4_SYSV_ABI posix_pthread_mutex_unlock(ScePthreadMutex* mutex) {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_cond_broadcast(ScePthreadCond* cond) {
|
||||
LOG_INFO_IF(log_pthread_file,
|
||||
"posix posix_pthread_cond_broadcast redirect to scePthreadCondBroadcast\n");
|
||||
LOG_INFO(Kernel_Pthread,
|
||||
"posix posix_pthread_cond_broadcast redirect to scePthreadCondBroadcast");
|
||||
int result = scePthreadCondBroadcast(cond);
|
||||
if (result != 0) {
|
||||
int rt = result > SCE_KERNEL_ERROR_UNKNOWN && result <= SCE_KERNEL_ERROR_ESTOP
|
||||
|
@ -510,4 +490,4 @@ void pthreadSymbolsRegister(Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("mkx2fVhNMsg", "libkernel", 1, "libkernel", 1, 1, posix_pthread_cond_broadcast);
|
||||
}
|
||||
|
||||
} // namespace Core::Libraries::LibKernel
|
||||
} // namespace Core::Libraries::LibKernel
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "Emulator/Host/controller.h"
|
||||
#include "common/log.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/singleton.h"
|
||||
#include "core/hle/error_codes.h"
|
||||
#include "core/hle/libraries/libpad/pad.h"
|
||||
|
@ -10,15 +10,14 @@
|
|||
|
||||
namespace Core::Libraries::LibPad {
|
||||
|
||||
constexpr bool log_file_pad = true; // disable it to disable logging
|
||||
|
||||
int PS4_SYSV_ABI scePadInit() {
|
||||
LOG_WARNING(Lib_Pad, "(STUBBED) called");
|
||||
return SCE_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePadOpen(Core::Libraries::LibUserService::SceUserServiceUserId userId, s32 type,
|
||||
int PS4_SYSV_ABI scePadOpen(Core::Libraries::LibUserService::SceUserServiceUserId user_id, s32 type,
|
||||
s32 index, const ScePadOpenParam* pParam) {
|
||||
LOG_INFO_IF(log_file_pad, "scePadOpen userid = {} type = {} index = {}\n", userId, type, index);
|
||||
LOG_INFO(Lib_Pad, "(STUBBED) called user_id = {} type = {} index = {}", user_id, type, index);
|
||||
return 1; // dummy
|
||||
}
|
||||
|
||||
|
|
|
@ -34,15 +34,6 @@
|
|||
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__); }
|
||||
|
||||
#define PRINT_UNIMPLEMENTED_FUNCTION_NAME() \
|
||||
{ LOG_ERROR_IF(true, "{}()\n", __func__); }
|
||||
|
||||
namespace Core::Libraries {
|
||||
|
||||
void InitHLELibs(Loader::SymbolsResolver* sym);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/log.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/PS4/GPU/gpu_memory.h"
|
||||
#include "core/hle/libraries/libs.h"
|
||||
#include "core/hle/libraries/libscegnmdriver/libscegnmdriver.h"
|
||||
|
@ -10,12 +10,12 @@
|
|||
namespace Core::Libraries::LibSceGnmDriver {
|
||||
|
||||
int32_t sceGnmSubmitDone() {
|
||||
PRINT_DUMMY_FUNCTION_NAME();
|
||||
LOG_WARNING(Lib_GnmDriver, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceGnmFlushGarlic() {
|
||||
PRINT_FUNCTION_NAME();
|
||||
LOG_WARNING(Lib_GnmDriver, "(STUBBED) called");
|
||||
GPU::flushGarlic(Emu::getGraphicCtx());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/log.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/error_codes.h"
|
||||
#include "core/hle/libraries/libs.h"
|
||||
#include "core/hle/libraries/libsystemservice/system_service.h"
|
||||
|
@ -9,7 +9,7 @@
|
|||
namespace Core::Libraries::LibSystemService {
|
||||
|
||||
s32 PS4_SYSV_ABI sceSystemServiceHideSplashScreen() {
|
||||
PRINT_DUMMY_FUNCTION_NAME();
|
||||
LOG_WARNING(Lib_SystemService, "(STUBBED) called");
|
||||
return SCE_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/log.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/error_codes.h"
|
||||
#include "core/hle/libraries/libs.h"
|
||||
#include "core/hle/libraries/libuserservice/libuserservice.h"
|
||||
|
@ -9,12 +9,12 @@
|
|||
namespace Core::Libraries::LibUserService {
|
||||
|
||||
s32 PS4_SYSV_ABI sceUserServiceInitialize(const SceUserServiceInitializeParams* initParams) {
|
||||
PRINT_DUMMY_FUNCTION_NAME();
|
||||
LOG_WARNING(Lib_UserService, "(STUBBED) called");
|
||||
return SCE_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceUserServiceGetLoginUserIdList(SceUserServiceLoginUserIdList* userIdList) {
|
||||
PRINT_DUMMY_FUNCTION_NAME();
|
||||
LOG_WARNING(Lib_UserService, "(STUBBED) called");
|
||||
userIdList->user_id[0] = 1;
|
||||
userIdList->user_id[1] = -1;
|
||||
userIdList->user_id[2] = -1;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,31 +2,29 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <Zydis/Zydis.h>
|
||||
#include <fmt/core.h>
|
||||
#include "common/log.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/aerolib/aerolib.h"
|
||||
#include "core/aerolib/stubs.h"
|
||||
#include "core/hle/libraries/libkernel/thread_management.h"
|
||||
#include "core/linker.h"
|
||||
#include "core/tls.h"
|
||||
#include "core/virtual_memory.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
constexpr bool debug_loader = true;
|
||||
static constexpr u64 LoadAddress = SYSTEM_RESERVED + CODE_BASE_OFFSET;
|
||||
|
||||
static u64 g_load_addr = SYSTEM_RESERVED + CODE_BASE_OFFSET;
|
||||
|
||||
static u64 get_aligned_size(const elf_program_header& phdr) {
|
||||
static u64 GetAlignedSize(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) {
|
||||
static u64 CalculateBaseSize(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]);
|
||||
u64 last_addr = phdr[i].p_vaddr + GetAlignedSize(phdr[i]);
|
||||
if (last_addr > base_size) {
|
||||
base_size = last_addr;
|
||||
}
|
||||
|
@ -35,7 +33,7 @@ static u64 calculate_base_size(const elf_header& ehdr, std::span<const elf_progr
|
|||
return base_size;
|
||||
}
|
||||
|
||||
static std::string encodeId(u64 nVal) {
|
||||
static std::string EncodeId(u64 nVal) {
|
||||
std::string enc;
|
||||
const char pCodes[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
|
||||
if (nVal < 0x40u) {
|
||||
|
@ -57,97 +55,37 @@ Linker::Linker() = default;
|
|||
|
||||
Linker::~Linker() = default;
|
||||
|
||||
Module* Linker::LoadModule(const std::string& elf_name) {
|
||||
Module* Linker::LoadModule(const std::filesystem::path& elf_name) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
auto& m = m_modules.emplace_back();
|
||||
m.linker = this;
|
||||
m.elf.Open(elf_name);
|
||||
if (!std::filesystem::exists(elf_name)) {
|
||||
LOG_ERROR(Core_Linker, "Provided module {} does not exist", elf_name.string());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (m.elf.isElfFile()) {
|
||||
LoadModuleToMemory(&m);
|
||||
LoadDynamicInfo(&m);
|
||||
LoadSymbols(&m);
|
||||
Relocate(&m);
|
||||
auto& m = m_modules.emplace_back();
|
||||
m = std::make_unique<Module>();
|
||||
m->elf.Open(elf_name);
|
||||
|
||||
if (m->elf.IsElfFile()) {
|
||||
LoadModuleToMemory(m.get());
|
||||
LoadDynamicInfo(m.get());
|
||||
LoadSymbols(m.get());
|
||||
Relocate(m.get());
|
||||
} else {
|
||||
m_modules.pop_back();
|
||||
return nullptr; // It is not a valid elf file //TODO check it why!
|
||||
}
|
||||
|
||||
return &m;
|
||||
return m.get();
|
||||
}
|
||||
|
||||
Module* Linker::FindModule(/*u32 id*/) {
|
||||
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];
|
||||
}
|
||||
|
||||
struct TLSPattern {
|
||||
uint8_t pattern[5];
|
||||
uint8_t pattern_size;
|
||||
uint8_t imm_size;
|
||||
uint8_t target_reg;
|
||||
};
|
||||
|
||||
constexpr TLSPattern tls_patterns[] = {
|
||||
{{0x64, 0x48, 0xA1},
|
||||
3,
|
||||
8,
|
||||
0}, // 64 48 A1 | 00 00 00 00 00 00 00 00 # mov rax, qword ptr fs:[64b imm]
|
||||
|
||||
{{0x64, 0x48, 0x8B, 0x4, 0x25},
|
||||
5,
|
||||
4,
|
||||
0}, // 64 48 8B 04 25 | 00 00 00 00 # mov rax,qword ptr fs:[0]
|
||||
{{0x64, 0x48, 0x8B, 0xC, 0x25}, 5, 4, 1}, // rcx
|
||||
{{0x64, 0x48, 0x8B, 0x14, 0x25}, 5, 4, 2}, // rdx
|
||||
{{0x64, 0x48, 0x8B, 0x1C, 0x25}, 5, 4, 3}, // rbx
|
||||
{{0x64, 0x48, 0x8B, 0x24, 0x25}, 5, 4, 4}, // rsp
|
||||
{{0x64, 0x48, 0x8B, 0x2C, 0x25}, 5, 4, 5}, // rbp
|
||||
{{0x64, 0x48, 0x8B, 0x34, 0x25}, 5, 4, 6}, // rsi
|
||||
{{0x64, 0x48, 0x8B, 0x3C, 0x25}, 5, 4, 7}, // rdi
|
||||
{{0x64, 0x4C, 0x8B, 0x4, 0x25}, 5, 4, 8}, // r8
|
||||
{{0x64, 0x4C, 0x8B, 0xC, 0x25}, 5, 4, 9}, // r9
|
||||
{{0x64, 0x4C, 0x8B, 0x14, 0x25}, 5, 4, 10}, // r10
|
||||
{{0x64, 0x4C, 0x8B, 0x1C, 0x25}, 5, 4, 11}, // r11
|
||||
{{0x64, 0x4C, 0x8B, 0x24, 0x25}, 5, 4, 12}, // r12
|
||||
{{0x64, 0x4C, 0x8B, 0x2C, 0x25}, 5, 4, 13}, // r13
|
||||
{{0x64, 0x4C, 0x8B, 0x34, 0x25}, 5, 4, 14}, // r14
|
||||
{{0x64, 0x4C, 0x8B, 0x3C, 0x25}, 5, 4, 15}, // r15
|
||||
};
|
||||
|
||||
void PatchTLS(u64 segment_addr, u64 segment_size) {
|
||||
uint8_t* code = (uint8_t*)segment_addr;
|
||||
auto remaining_size = segment_size;
|
||||
|
||||
while (remaining_size) {
|
||||
for (auto& tls_pattern : tls_patterns) {
|
||||
auto total_size = tls_pattern.pattern_size + tls_pattern.imm_size;
|
||||
if (remaining_size >= total_size) {
|
||||
if (memcmp(code, tls_pattern.pattern, tls_pattern.pattern_size) == 0) {
|
||||
if (tls_pattern.imm_size == 4)
|
||||
printf("PATTERN32 FOUND @ %p, reg: %d offset: %X\n", code,
|
||||
tls_pattern.target_reg,
|
||||
*(uint32_t*)(code + tls_pattern.pattern_size));
|
||||
else
|
||||
printf("PATTERN64 FOUND @ %p, reg: %d offset: %lX\n", code,
|
||||
tls_pattern.target_reg,
|
||||
*(uint64_t*)(code + tls_pattern.pattern_size));
|
||||
code[0] = 0xcd;
|
||||
code[1] = 0x80 + tls_pattern.target_reg;
|
||||
code[2] = tls_pattern.pattern_size | (tls_pattern.imm_size << 4);
|
||||
code += total_size - 1;
|
||||
remaining_size -= total_size - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
code++;
|
||||
remaining_size--;
|
||||
}
|
||||
return m_modules[0].get();
|
||||
}
|
||||
|
||||
void Linker::LoadModuleToMemory(Module* m) {
|
||||
|
@ -155,18 +93,18 @@ void Linker::LoadModuleToMemory(Module* m) {
|
|||
const auto elf_header = m->elf.GetElfHeader();
|
||||
const auto elf_pheader = m->elf.GetProgramHeader();
|
||||
|
||||
u64 base_size = calculate_base_size(elf_header, elf_pheader);
|
||||
u64 base_size = CalculateBaseSize(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,
|
||||
m->base_virtual_addr = VirtualMemory::memory_alloc(LoadAddress, 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);
|
||||
LOG_INFO(Core_Linker, "====Load Module to Memory ========");
|
||||
LOG_INFO(Core_Linker, "base_virtual_addr ......: {:#018x}", m->base_virtual_addr);
|
||||
LOG_INFO(Core_Linker, "base_size ..............: {:#018x}", base_size);
|
||||
LOG_INFO(Core_Linker, "aligned_base_size ......: {:#018x}", m->aligned_base_size);
|
||||
|
||||
for (u16 i = 0; i < elf_header.e_phnum; i++) {
|
||||
switch (elf_pheader[i].p_type) {
|
||||
|
@ -175,14 +113,14 @@ void Linker::LoadModuleToMemory(Module* m) {
|
|||
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]);
|
||||
u64 segment_memory_size = GetAlignedSize(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);
|
||||
LOG_INFO(Core_Linker, "program header = [{}] type = {}", i,
|
||||
m->elf.ElfPheaderTypeStr(elf_pheader[i].p_type));
|
||||
LOG_INFO(Core_Linker, "segment_addr ..........: {:#018x}", segment_addr);
|
||||
LOG_INFO(Core_Linker, "segment_file_size .....: {}", segment_file_size);
|
||||
LOG_INFO(Core_Linker, "segment_memory_size ...: {}", segment_memory_size);
|
||||
LOG_INFO(Core_Linker, "segment_mode ..........: {}", segment_mode);
|
||||
|
||||
m->elf.LoadSegment(segment_addr, elf_pheader[i].p_offset, segment_file_size);
|
||||
|
||||
|
@ -190,8 +128,8 @@ void Linker::LoadModuleToMemory(Module* m) {
|
|||
PatchTLS(segment_addr, segment_file_size);
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR_IF(debug_loader, "p_memsz==0 in type {}\n",
|
||||
m->elf.ElfPheaderTypeStr(elf_pheader[i].p_type));
|
||||
LOG_ERROR(Core_Linker, "p_memsz==0 in type {}",
|
||||
m->elf.ElfPheaderTypeStr(elf_pheader[i].p_type));
|
||||
}
|
||||
break;
|
||||
case PT_DYNAMIC:
|
||||
|
@ -200,8 +138,8 @@ void Linker::LoadModuleToMemory(Module* m) {
|
|||
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));
|
||||
LOG_ERROR(Core_Linker, "p_filesz==0 in type {}",
|
||||
m->elf.ElfPheaderTypeStr(elf_pheader[i].p_type));
|
||||
}
|
||||
break;
|
||||
case PT_SCE_DYNLIBDATA:
|
||||
|
@ -210,23 +148,23 @@ void Linker::LoadModuleToMemory(Module* m) {
|
|||
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));
|
||||
LOG_ERROR(Core_Linker, "p_filesz==0 in type {}",
|
||||
m->elf.ElfPheaderTypeStr(elf_pheader[i].p_type));
|
||||
}
|
||||
break;
|
||||
case PT_TLS:
|
||||
m->tls.image_virtual_addr = elf_pheader[i].p_vaddr + m->base_virtual_addr;
|
||||
m->tls.image_size = get_aligned_size(elf_pheader[i]);
|
||||
LOG_INFO_IF(debug_loader, "tls virtual address ={:#x}\n", m->tls.image_virtual_addr);
|
||||
LOG_INFO_IF(debug_loader, "tls image size ={}\n", m->tls.image_size);
|
||||
m->tls.image_size = GetAlignedSize(elf_pheader[i]);
|
||||
LOG_INFO(Core_Linker, "tls virtual address ={:#x}", m->tls.image_virtual_addr);
|
||||
LOG_INFO(Core_Linker, "tls image size ={}", m->tls.image_size);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR_IF(debug_loader, "Unimplemented type {}\n",
|
||||
m->elf.ElfPheaderTypeStr(elf_pheader[i].p_type));
|
||||
LOG_ERROR(Core_Linker, "Unimplemented type {}",
|
||||
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);
|
||||
LOG_INFO(Core_Linker, "program entry addr ..........: {:#018x}",
|
||||
m->elf.GetElfEntry() + m->base_virtual_addr);
|
||||
}
|
||||
|
||||
void Linker::LoadDynamicInfo(Module* m) {
|
||||
|
@ -273,7 +211,7 @@ void Linker::LoadDynamicInfo(Module* m) {
|
|||
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!");
|
||||
LOG_WARNING(Core_Linker, "DT_SCE_PLTREL is NOT DT_RELA should check!");
|
||||
}
|
||||
break;
|
||||
case DT_SCE_RELA: // Offset of the relocation table.
|
||||
|
@ -288,7 +226,7 @@ void Linker::LoadDynamicInfo(Module* m) {
|
|||
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!");
|
||||
LOG_WARNING(Core_Linker, "DT_SCE_RELAENT is NOT 0x18 should check!");
|
||||
}
|
||||
break;
|
||||
case DT_INIT_ARRAY: // Address of the array of pointers to initialization functions
|
||||
|
@ -314,7 +252,7 @@ void Linker::LoadDynamicInfo(Module* m) {
|
|||
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!");
|
||||
LOG_WARNING(Core_Linker, "DT_SCE_SYMENT is NOT 0x18 should check!");
|
||||
}
|
||||
break;
|
||||
case DT_DEBUG:
|
||||
|
@ -327,7 +265,7 @@ void Linker::LoadDynamicInfo(Module* m) {
|
|||
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!");
|
||||
LOG_WARNING(Core_Linker, "DT_FLAGS is NOT 0x04 should check!");
|
||||
}
|
||||
break;
|
||||
case DT_NEEDED: // Offset of the library string in the string table to be linked in.
|
||||
|
@ -336,21 +274,21 @@ void Linker::LoadDynamicInfo(Module* m) {
|
|||
{
|
||||
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!");
|
||||
LOG_ERROR(Core_Linker, "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);
|
||||
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);
|
||||
info.enc_id = EncodeId(info.id);
|
||||
m->dynamic_info.import_libs.push_back(info);
|
||||
} break;
|
||||
case DT_SCE_FINGERPRINT:
|
||||
|
@ -358,16 +296,14 @@ void Linker::LoadDynamicInfo(Module* m) {
|
|||
// 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);
|
||||
LOG_INFO(Core_Linker, "unsupported DT_SCE_FINGERPRINT value = ..........: {:#018x}",
|
||||
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);
|
||||
LOG_INFO(Core_Linker, "unsupported DT_SCE_IMPORT_LIB_ATTR value = ......: {:#018x}",
|
||||
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;
|
||||
|
@ -377,24 +313,23 @@ void Linker::LoadDynamicInfo(Module* m) {
|
|||
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);
|
||||
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);
|
||||
LOG_INFO(Core_Linker, "unsupported DT_SCE_MODULE_ATTR value = ..........: {:#018x}",
|
||||
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);
|
||||
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);
|
||||
LOG_INFO(Core_Linker, "unsupported dynamic tag ..........: {:#018x}", dyn->d_tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -442,7 +377,7 @@ const LibraryInfo* Linker::FindLibrary(const Module& m, const std::string& id) {
|
|||
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");
|
||||
LOG_INFO(Core_Linker, "Symbol table not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -466,8 +401,8 @@ void Linker::LoadSymbols(Module* m) {
|
|||
case STB_WEAK:
|
||||
break;
|
||||
default:
|
||||
LOG_INFO_IF(debug_loader, "Unsupported bind {} for name symbol {} \n", bind,
|
||||
ids.at(0));
|
||||
LOG_INFO(Core_Linker, "Unsupported bind {} for name symbol {}", bind,
|
||||
ids.at(0));
|
||||
continue;
|
||||
}
|
||||
switch (type) {
|
||||
|
@ -475,16 +410,16 @@ void Linker::LoadSymbols(Module* m) {
|
|||
case STT_FUN:
|
||||
break;
|
||||
default:
|
||||
LOG_INFO_IF(debug_loader, "Unsupported type {} for name symbol {} \n", type,
|
||||
ids.at(0));
|
||||
LOG_INFO(Core_Linker, "Unsupported type {} for name symbol {}", 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));
|
||||
LOG_INFO(Core_Linker, "Unsupported visibility {} for name symbol {}",
|
||||
visibility, ids.at(0));
|
||||
continue;
|
||||
}
|
||||
// if st_value!=0 then it's export symbol
|
||||
|
@ -515,97 +450,98 @@ void Linker::LoadSymbols(Module* m) {
|
|||
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);
|
||||
LOG_INFO(Core_Linker,
|
||||
"name = {}, function = {}, library = {}, module = {}, bind = {}, type = "
|
||||
"{}, visibility = {}",
|
||||
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;
|
||||
u8 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);//found it openorbis but i am not sure it worth logging
|
||||
}
|
||||
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;
|
||||
Loader::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) {
|
||||
const auto relocate = [this](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;
|
||||
u8 rel_sym_type = 0;
|
||||
std::string rel_name;
|
||||
|
||||
switch (type) {
|
||||
case R_X86_64_RELATIVE:
|
||||
if (symbol != 0) // should be always zero
|
||||
{
|
||||
// LOG_INFO(Core_Linker, "R_X86_64_RELATIVE symbol not zero = {:#010x}\n", type,
|
||||
// symbol);//found it openorbis but i am not sure it worth logging
|
||||
}
|
||||
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;
|
||||
Loader::SymbolRecord symrec{};
|
||||
switch (sym_type) {
|
||||
case STT_FUN:
|
||||
rel_sym_type = 2;
|
||||
break;
|
||||
case STT_OBJECT:
|
||||
rel_sym_type = 1;
|
||||
break;
|
||||
default:
|
||||
LOG_INFO(Core_Linker, "unknown symbol type {}", sym_type);
|
||||
}
|
||||
if (sym_visibility != 0) // should be zero log if else
|
||||
{
|
||||
LOG_INFO(Core_Linker, "symbol visilibity !=0");
|
||||
}
|
||||
switch (sym_bind) {
|
||||
case STB_GLOBAL:
|
||||
rel_name = namesTlb + sym.st_name;
|
||||
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(Core_Linker,
|
||||
"R_X86_64_64-R_X86_64_JUMP_SLOT sym_type {} bind STB_GLOBAL symbol : "
|
||||
"{:#010x}",
|
||||
sym_type, symbol);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_INFO(Core_Linker, "UNK bind {}", sym_bind);
|
||||
}
|
||||
|
||||
} break;
|
||||
default:
|
||||
LOG_INFO(Core_Linker, "UNK type {:#010x} rel symbol : {:#010x}", type, symbol);
|
||||
}
|
||||
|
||||
if (rel_isResolved) {
|
||||
VirtualMemory::memory_patch(rel_virtual_addr, rel_value);
|
||||
} else {
|
||||
LOG_INFO(Core_Linker, "function not patched! {}", rel_name);
|
||||
}
|
||||
};
|
||||
|
||||
u32 idx = 0;
|
||||
for (auto* rel = m->dynamic_info.relocation_table;
|
||||
reinterpret_cast<u8*>(rel) < reinterpret_cast<u8*>(m->dynamic_info.relocation_table) +
|
||||
|
@ -654,8 +590,8 @@ void Linker::Resolve(const std::string& name, int Symtype, Module* m,
|
|||
return_info->virtual_address = AeroLib::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);
|
||||
LOG_ERROR(Core_Linker, "Linker: Stub resolved {} as {} (lib: {}, mod: {})", sr.name,
|
||||
return_info->name, library->name, module->name);
|
||||
}
|
||||
} else {
|
||||
//__debugbreak();//den tha prepei na ftasoume edo
|
||||
|
@ -672,7 +608,7 @@ 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) {
|
||||
static void RunMainEntry(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
|
||||
|
||||
|
@ -702,7 +638,7 @@ void Linker::Execute() {
|
|||
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);
|
||||
RunMainEntry(module->elf.GetElfEntry() + module->base_virtual_addr, &p, ProgramExitFunc);
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
|
|
@ -51,6 +51,7 @@ struct PS4ThreadLocal {
|
|||
u64 image_size = 0;
|
||||
u64 handler_virtual_addr = 0;
|
||||
};
|
||||
|
||||
struct DynamicModuleInfo {
|
||||
void* hash_table = nullptr;
|
||||
u64 hash_table_size = 0;
|
||||
|
@ -97,9 +98,7 @@ struct DynamicModuleInfo {
|
|||
struct Module {
|
||||
Loader::Elf elf;
|
||||
u64 aligned_base_size = 0;
|
||||
u64 base_virtual_addr = 0; // Base virtual address
|
||||
|
||||
Linker* linker = nullptr;
|
||||
u64 base_virtual_addr = 0;
|
||||
|
||||
std::vector<u8> m_dynamic;
|
||||
std::vector<u8> m_dynamic_data;
|
||||
|
@ -116,8 +115,8 @@ public:
|
|||
Linker();
|
||||
virtual ~Linker();
|
||||
|
||||
Module* LoadModule(const std::string& elf_name);
|
||||
Module* FindModule(/*u32 id*/);
|
||||
Module* LoadModule(const std::filesystem::path& elf_name);
|
||||
Module* FindModule(u32 id = 0);
|
||||
void LoadModuleToMemory(Module* m);
|
||||
void LoadDynamicInfo(Module* m);
|
||||
void LoadSymbols(Module* m);
|
||||
|
@ -133,7 +132,7 @@ 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;
|
||||
std::vector<std::unique_ptr<Module>> m_modules;
|
||||
Loader::SymbolsResolver m_hle_symbols{};
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/loader/elf.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
|
||||
constexpr bool log_file_loader = false; // disable it to disable logging
|
||||
using namespace Common::FS;
|
||||
|
||||
static std::string_view getProgramTypeName(program_type_es type) {
|
||||
static std::string_view GetProgramTypeName(program_type_es type) {
|
||||
switch (type) {
|
||||
case PT_FAKE:
|
||||
return "PT_FAKE";
|
||||
|
@ -33,7 +33,7 @@ static std::string_view getProgramTypeName(program_type_es type) {
|
|||
}
|
||||
}
|
||||
|
||||
static std::string_view getIdentClassName(ident_class_es elf_class) {
|
||||
static std::string_view GetIdentClassName(ident_class_es elf_class) {
|
||||
switch (elf_class) {
|
||||
case ELF_CLASS_NONE:
|
||||
return "ELF_CLASS_NONE";
|
||||
|
@ -48,7 +48,7 @@ static std::string_view getIdentClassName(ident_class_es elf_class) {
|
|||
}
|
||||
}
|
||||
|
||||
static std::string_view getIdentEndianName(ident_endian_es endian) {
|
||||
static std::string_view GetIdentEndianName(ident_endian_es endian) {
|
||||
switch (endian) {
|
||||
case ELF_DATA_NONE:
|
||||
return "ELF_DATA_NONE";
|
||||
|
@ -63,7 +63,7 @@ static std::string_view getIdentEndianName(ident_endian_es endian) {
|
|||
}
|
||||
}
|
||||
|
||||
static std::string_view getIdentVersionName(ident_version_es version) {
|
||||
static std::string_view GetIdentVersionName(ident_version_es version) {
|
||||
switch (version) {
|
||||
case ELF_VERSION_NONE:
|
||||
return "ELF_VERSION_NONE";
|
||||
|
@ -76,7 +76,7 @@ static std::string_view getIdentVersionName(ident_version_es version) {
|
|||
}
|
||||
}
|
||||
|
||||
static std::string_view getIdentOsabiName(ident_osabi_es osabi) {
|
||||
static std::string_view GetIdentOsabiName(ident_osabi_es osabi) {
|
||||
switch (osabi) {
|
||||
case ELF_OSABI_NONE:
|
||||
return "ELF_OSABI_NONE";
|
||||
|
@ -117,7 +117,7 @@ static std::string_view getIdentOsabiName(ident_osabi_es osabi) {
|
|||
}
|
||||
}
|
||||
|
||||
static std::string_view getIdentAbiversionName(ident_abiversion_es version) {
|
||||
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";
|
||||
|
@ -131,7 +131,7 @@ static std::string_view getIdentAbiversionName(ident_abiversion_es version) {
|
|||
return "INVALID";
|
||||
}
|
||||
}
|
||||
static std::string_view getVersion(e_version_es version) {
|
||||
static std::string_view GetVersion(e_version_es version) {
|
||||
switch (version) {
|
||||
case EV_NONE:
|
||||
return "EV_NONE";
|
||||
|
@ -142,7 +142,7 @@ static std::string_view getVersion(e_version_es version) {
|
|||
}
|
||||
}
|
||||
|
||||
static std::string_view getType(e_type_s type) {
|
||||
static std::string_view GetType(e_type_s type) {
|
||||
switch (type) {
|
||||
case ET_NONE:
|
||||
return "ET_NONE";
|
||||
|
@ -167,7 +167,7 @@ static std::string_view getType(e_type_s type) {
|
|||
}
|
||||
}
|
||||
|
||||
static std::string_view getMachine(e_machine_es machine) {
|
||||
static std::string_view GetMachine(e_machine_es machine) {
|
||||
switch (machine) {
|
||||
case EM_X86_64:
|
||||
return "EM_X86_64";
|
||||
|
@ -176,30 +176,25 @@ static std::string_view getMachine(e_machine_es machine) {
|
|||
}
|
||||
}
|
||||
|
||||
Elf::~Elf() {
|
||||
Reset();
|
||||
}
|
||||
Elf::~Elf() = default;
|
||||
|
||||
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);
|
||||
void Elf::Open(const std::filesystem::path& file_name) {
|
||||
m_f.Open(file_name, FileAccessMode::Read);
|
||||
if (!m_f.ReadObject(m_self)) {
|
||||
LOG_ERROR(Loader, "Unable to read self header!");
|
||||
return;
|
||||
}
|
||||
|
||||
const u64 elf_header_pos = m_f.tell();
|
||||
m_f.read(m_elf_header);
|
||||
if (!isElfFile()) {
|
||||
if (is_self = IsSelfFile(); !is_self) {
|
||||
m_f.Seek(0, SeekOrigin::SetOrigin);
|
||||
} 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;
|
||||
}
|
||||
|
||||
|
@ -209,8 +204,8 @@ void Elf::Open(const std::string& file_name) {
|
|||
}
|
||||
|
||||
out.resize(num);
|
||||
m_f.seek(offset, Common::FS::SeekMode::Set);
|
||||
m_f.read(out);
|
||||
m_f.Seek(offset, SeekOrigin::SetOrigin);
|
||||
m_f.Read(out);
|
||||
};
|
||||
|
||||
load_headers(m_elf_phdr, elf_header_pos + m_elf_header.e_phoff, m_elf_header.e_phnum);
|
||||
|
@ -227,96 +222,95 @@ void Elf::Open(const std::string& file_name) {
|
|||
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);
|
||||
m_f.Seek(header_size, SeekOrigin::SetOrigin);
|
||||
m_f.ReadObject(m_self_id_header);
|
||||
}
|
||||
}
|
||||
|
||||
DebugDump();
|
||||
}
|
||||
|
||||
bool Elf::isSelfFile() const {
|
||||
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);
|
||||
LOG_INFO(Loader, "Not a SELF file. Magic mismatch current = {:#x} expected = {:#x}",
|
||||
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");
|
||||
LOG_INFO(Loader, "Unknown SELF file");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_self.category != 0x01 || m_self.program_type != 0x01) [[unlikely]] {
|
||||
LOG_ERROR_IF(log_file_loader, "Unknown SELF file\n");
|
||||
LOG_INFO(Loader, "Unknown SELF file");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Elf::isElfFile() const {
|
||||
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");
|
||||
LOG_INFO(Loader, "Not an ELF file magic is wrong!");
|
||||
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));
|
||||
LOG_INFO(Loader, "e_ident[EI_CLASS] expected 0x02 is ({:#x})",
|
||||
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));
|
||||
LOG_INFO(Loader, "e_ident[EI_DATA] expected 0x01 is ({:#x})",
|
||||
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));
|
||||
LOG_INFO(Loader, "e_ident[EI_VERSION] expected 0x01 is ({:#x})",
|
||||
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));
|
||||
LOG_INFO(Loader, "e_ident[EI_OSABI] expected 0x09 is ({:#x})",
|
||||
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));
|
||||
LOG_INFO(Loader, "e_ident[EI_ABIVERSION] expected 0x00 is ({:#x})",
|
||||
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));
|
||||
LOG_INFO(Loader, "e_type expected 0xFE10 OR 0xFE18 OR 0xfe00 is ({:#x})",
|
||||
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));
|
||||
LOG_INFO(Loader, "e_machine expected 0x3E is ({:#x})",
|
||||
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));
|
||||
LOG_INFO(Loader, "m_elf_header.e_version expected 0x01 is ({:#x})",
|
||||
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));
|
||||
LOG_INFO(Loader, "e_phentsize ({}) != sizeof(elf_program_header)",
|
||||
m_elf_header.e_phentsize);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -324,8 +318,8 @@ bool Elf::isElfFile() const {
|
|||
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);
|
||||
LOG_INFO(Loader, "e_shentsize ({}) != sizeof(elf_section_header)",
|
||||
m_elf_header.e_shentsize);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -334,50 +328,49 @@ bool Elf::isElfFile() const {
|
|||
|
||||
void Elf::DebugDump() {
|
||||
if (is_self) { // If we load elf instead
|
||||
LOG_INFO_IF(log_file_loader, (SElfHeaderStr()));
|
||||
LOG_INFO(Loader, "{}", SElfHeaderStr());
|
||||
for (u16 i = 0; i < m_self.segment_count; i++) {
|
||||
LOG_INFO_IF(log_file_loader, SELFSegHeader(i));
|
||||
LOG_INFO(Loader, "{}", SELFSegHeader(i));
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO_IF(log_file_loader, ElfHeaderStr());
|
||||
LOG_INFO(Loader, "{}", ElfHeaderStr());
|
||||
|
||||
if (m_elf_header.e_phentsize > 0) {
|
||||
LOG_INFO_IF(log_file_loader, "Program headers:\n");
|
||||
LOG_INFO(Loader, "Program headers:");
|
||||
for (u16 i = 0; i < m_elf_header.e_phnum; i++) {
|
||||
LOG_INFO_IF(log_file_loader, ElfPHeaderStr(i));
|
||||
LOG_INFO(Loader, "{}", ElfPHeaderStr(i));
|
||||
}
|
||||
}
|
||||
if (m_elf_header.e_shentsize > 0) {
|
||||
LOG_INFO_IF(log_file_loader, "Section headers:\n");
|
||||
LOG_INFO(Loader, "Section headers:");
|
||||
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);
|
||||
LOG_INFO(Loader, "--- shdr {} --", i);
|
||||
LOG_INFO(Loader, "sh_name ........: {}", m_elf_shdr[i].sh_name);
|
||||
LOG_INFO(Loader, "sh_type ........: {:#010x}", m_elf_shdr[i].sh_type);
|
||||
LOG_INFO(Loader, "sh_flags .......: {:#018x}", m_elf_shdr[i].sh_flags);
|
||||
LOG_INFO(Loader, "sh_addr ........: {:#018x}", m_elf_shdr[i].sh_addr);
|
||||
LOG_INFO(Loader, "sh_offset ......: {:#018x}", m_elf_shdr[i].sh_offset);
|
||||
LOG_INFO(Loader, "sh_size ........: {:#018x}", m_elf_shdr[i].sh_size);
|
||||
LOG_INFO(Loader, "sh_link ........: {:#010x}", m_elf_shdr[i].sh_link);
|
||||
LOG_INFO(Loader, "sh_info ........: {:#010x}", m_elf_shdr[i].sh_info);
|
||||
LOG_INFO(Loader, "sh_addralign ...: {:#018x}", m_elf_shdr[i].sh_addralign);
|
||||
LOG_INFO(Loader, "sh_entsize .....: {:#018x}", 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);
|
||||
LOG_INFO(Loader, "SELF info:");
|
||||
LOG_INFO(Loader, "auth id ............: {:#018x}", m_self_id_header.authid);
|
||||
LOG_INFO(Loader, "program type .......: {}",
|
||||
GetProgramTypeName(m_self_id_header.program_type));
|
||||
LOG_INFO(Loader, "app version ........: {:#018x}", m_self_id_header.appver);
|
||||
LOG_INFO(Loader, "fw version .........: {:#018x}", 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);
|
||||
LOG_INFO(Loader, "digest..............: 0x{}", digest);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -420,15 +413,15 @@ std::string Elf::ElfHeaderStr() {
|
|||
header += fmt::format("\n");
|
||||
|
||||
header +=
|
||||
fmt::format("ident class.......: {}\n", getIdentClassName(m_elf_header.e_ident.ei_class));
|
||||
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));
|
||||
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));
|
||||
GetIdentVersionName(m_elf_header.e_ident.ei_version));
|
||||
header +=
|
||||
fmt::format("ident osabi .....: {}\n", getIdentOsabiName(m_elf_header.e_ident.ei_osabi));
|
||||
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));
|
||||
GetIdentAbiversionName(m_elf_header.e_ident.ei_abiversion));
|
||||
|
||||
header += fmt::format("ident UNK ........: 0x");
|
||||
for (auto i : m_elf_header.e_ident.pad) {
|
||||
|
@ -436,9 +429,9 @@ std::string Elf::ElfHeaderStr() {
|
|||
}
|
||||
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("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);
|
||||
|
@ -522,8 +515,8 @@ std::string Elf::ElfPHeaderStr(u16 no) {
|
|||
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);
|
||||
m_f.Seek(file_offset, SeekOrigin::SetOrigin);
|
||||
m_f.ReadRaw<u8>(reinterpret_cast<u8*>(virtual_addr), size);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -536,13 +529,13 @@ void Elf::LoadSegment(u64 virtual_addr, u64 file_offset, u64 size) {
|
|||
|
||||
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);
|
||||
m_f.Seek(offset + seg.file_offset, SeekOrigin::SetOrigin);
|
||||
m_f.ReadRaw<u8>(reinterpret_cast<u8*>(virtual_addr), size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
BREAKPOINT(); // Hmm we didn't return something...
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
} // namespace Core::Loader
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/fs_file.h"
|
||||
#include "common/io_file.h"
|
||||
#include "common/types.h"
|
||||
|
||||
struct self_header {
|
||||
static const u32 signature = 0x1D3D154Fu;
|
||||
static constexpr u32 signature = 0x1D3D154Fu;
|
||||
|
||||
u32 magic;
|
||||
u8 version;
|
||||
|
@ -455,11 +455,11 @@ namespace Core::Loader {
|
|||
class Elf {
|
||||
public:
|
||||
Elf() = default;
|
||||
virtual ~Elf();
|
||||
~Elf();
|
||||
|
||||
void Open(const std::string& file_name);
|
||||
bool isSelfFile() const;
|
||||
bool isElfFile() const;
|
||||
void Open(const std::filesystem::path& file_name);
|
||||
bool IsSelfFile() const;
|
||||
bool IsElfFile() const;
|
||||
void DebugDump();
|
||||
|
||||
[[nodiscard]] self_header GetSElfHeader() const {
|
||||
|
@ -492,10 +492,7 @@ public:
|
|||
void LoadSegment(u64 virtual_addr, u64 file_offset, u64 size);
|
||||
|
||||
private:
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
Common::FS::File m_f{};
|
||||
Common::FS::IOFile m_f{};
|
||||
bool is_self{};
|
||||
self_header m_self{};
|
||||
std::vector<self_segment_header> m_self_segments;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/log.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/types.h"
|
||||
#include "core/loader/symbols_resolver.h"
|
||||
|
||||
|
@ -27,7 +27,7 @@ const SymbolRecord* SymbolsResolver::FindSymbol(const SymbolRes& s) const {
|
|||
}
|
||||
}
|
||||
|
||||
LOG_INFO("Unresolved! {}\n", name);
|
||||
LOG_INFO(Core_Linker, "Unresolved! {}", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
177
src/core/tls.cpp
Normal file
177
src/core/tls.cpp
Normal file
|
@ -0,0 +1,177 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/types.h"
|
||||
#include "core/tls.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace Core {
|
||||
|
||||
thread_local u8 TLS[1024];
|
||||
|
||||
struct TLSPattern {
|
||||
uint8_t pattern[5];
|
||||
uint8_t pattern_size;
|
||||
uint8_t imm_size;
|
||||
uint8_t target_reg;
|
||||
};
|
||||
|
||||
constexpr static TLSPattern TlsPatterns[] = {
|
||||
{{0x64, 0x48, 0xA1},
|
||||
3,
|
||||
8,
|
||||
0}, // 64 48 A1 | 00 00 00 00 00 00 00 00 # mov rax, qword ptr fs:[64b imm]
|
||||
|
||||
{{0x64, 0x48, 0x8B, 0x4, 0x25},
|
||||
5,
|
||||
4,
|
||||
0}, // 64 48 8B 04 25 | 00 00 00 00 # mov rax,qword ptr fs:[0]
|
||||
{{0x64, 0x48, 0x8B, 0xC, 0x25}, 5, 4, 1}, // rcx
|
||||
{{0x64, 0x48, 0x8B, 0x14, 0x25}, 5, 4, 2}, // rdx
|
||||
{{0x64, 0x48, 0x8B, 0x1C, 0x25}, 5, 4, 3}, // rbx
|
||||
{{0x64, 0x48, 0x8B, 0x24, 0x25}, 5, 4, 4}, // rsp
|
||||
{{0x64, 0x48, 0x8B, 0x2C, 0x25}, 5, 4, 5}, // rbp
|
||||
{{0x64, 0x48, 0x8B, 0x34, 0x25}, 5, 4, 6}, // rsi
|
||||
{{0x64, 0x48, 0x8B, 0x3C, 0x25}, 5, 4, 7}, // rdi
|
||||
{{0x64, 0x4C, 0x8B, 0x4, 0x25}, 5, 4, 8}, // r8
|
||||
{{0x64, 0x4C, 0x8B, 0xC, 0x25}, 5, 4, 9}, // r9
|
||||
{{0x64, 0x4C, 0x8B, 0x14, 0x25}, 5, 4, 10}, // r10
|
||||
{{0x64, 0x4C, 0x8B, 0x1C, 0x25}, 5, 4, 11}, // r11
|
||||
{{0x64, 0x4C, 0x8B, 0x24, 0x25}, 5, 4, 12}, // r12
|
||||
{{0x64, 0x4C, 0x8B, 0x2C, 0x25}, 5, 4, 13}, // r13
|
||||
{{0x64, 0x4C, 0x8B, 0x34, 0x25}, 5, 4, 14}, // r14
|
||||
{{0x64, 0x4C, 0x8B, 0x3C, 0x25}, 5, 4, 15}, // r15
|
||||
};
|
||||
|
||||
uintptr_t GetGuestTls(s64 tls_offset) {
|
||||
if (tls_offset == 0) {
|
||||
return reinterpret_cast<uintptr_t>(TLS);
|
||||
}
|
||||
UNREACHABLE_MSG("Unimplemented offset info tls");
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
static LONG WINAPI ExceptionHandler(PEXCEPTION_POINTERS pExp) noexcept {
|
||||
auto orig_rip = pExp->ContextRecord->Rip;
|
||||
while (*(u8*)pExp->ContextRecord->Rip == 0x66) {
|
||||
pExp->ContextRecord->Rip++;
|
||||
}
|
||||
|
||||
if (*(u8*)pExp->ContextRecord->Rip == 0xcd) {
|
||||
int reg = *(u8*)(pExp->ContextRecord->Rip + 1) - 0x80;
|
||||
int sizes = *(u8*)(pExp->ContextRecord->Rip + 2);
|
||||
int pattern_size = sizes & 0xF;
|
||||
int imm_size = sizes >> 4;
|
||||
|
||||
int64_t tls_offset;
|
||||
if (imm_size == 4) {
|
||||
tls_offset = *(s32*)(pExp->ContextRecord->Rip + pattern_size);
|
||||
} else {
|
||||
tls_offset = *(s64*)(pExp->ContextRecord->Rip + pattern_size);
|
||||
}
|
||||
|
||||
(&pExp->ContextRecord->Rax)[reg] = GetGuestTls(tls_offset); /* GetGuestTls */
|
||||
pExp->ContextRecord->Rip += pattern_size + imm_size;
|
||||
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
pExp->ContextRecord->Rip = orig_rip;
|
||||
const u32 ec = pExp->ExceptionRecord->ExceptionCode;
|
||||
switch (ec) {
|
||||
case EXCEPTION_ACCESS_VIOLATION: {
|
||||
LOG_CRITICAL(Core, "Exception EXCEPTION_ACCESS_VIOLATION ({:#x})", ec);
|
||||
const auto info = pExp->ExceptionRecord->ExceptionInformation;
|
||||
switch (info[0]) {
|
||||
case 0:
|
||||
LOG_CRITICAL(Core, "Read violation at address {:#x}", info[1]);
|
||||
break;
|
||||
case 1:
|
||||
LOG_CRITICAL(Core, "Write violation at address {:#x}", info[1]);
|
||||
break;
|
||||
case 8:
|
||||
LOG_CRITICAL(Core, "DEP violation at address {:#x}", info[1]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
||||
LOG_CRITICAL(Core, "Exception EXCEPTION_ARRAY_BOUNDS_EXCEEDED ({:#x})", ec);
|
||||
break;
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||||
LOG_CRITICAL(Core, "Exception EXCEPTION_DATATYPE_MISALIGNMENT ({:#x})", ec);
|
||||
break;
|
||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
||||
LOG_CRITICAL(Core, "Exception EXCEPTION_FLT_DIVIDE_BY_ZERO ({:#x})", ec);
|
||||
break;
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
LOG_CRITICAL(Core, "Exception EXCEPTION_ILLEGAL_INSTRUCTION ({:#x})", ec);
|
||||
break;
|
||||
case EXCEPTION_IN_PAGE_ERROR:
|
||||
LOG_CRITICAL(Core, "Exception EXCEPTION_IN_PAGE_ERROR ({:#x})", ec);
|
||||
break;
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
LOG_CRITICAL(Core, "Exception EXCEPTION_INT_DIVIDE_BY_ZERO ({:#x})", ec);
|
||||
break;
|
||||
case EXCEPTION_PRIV_INSTRUCTION:
|
||||
LOG_CRITICAL(Core, "Exception EXCEPTION_PRIV_INSTRUCTION ({:#x})", ec);
|
||||
break;
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
LOG_CRITICAL(Core, "Exception EXCEPTION_STACK_OVERFLOW ({:#x})", ec);
|
||||
break;
|
||||
default:
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
#endif
|
||||
|
||||
void InstallTlsHandler() {
|
||||
#ifdef _WIN64
|
||||
if (!AddVectoredExceptionHandler(0, ExceptionHandler)) {
|
||||
LOG_CRITICAL(Core, "Failed to register an exception handler");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PatchTLS(u64 segment_addr, u64 segment_size) {
|
||||
u8* code = reinterpret_cast<u8*>(segment_addr);
|
||||
auto remaining_size = segment_size;
|
||||
|
||||
while (remaining_size) {
|
||||
for (const auto& tls_pattern : TlsPatterns) {
|
||||
const auto total_size = tls_pattern.pattern_size + tls_pattern.imm_size;
|
||||
if (remaining_size < total_size) {
|
||||
continue;
|
||||
}
|
||||
if (std::memcmp(code, tls_pattern.pattern, tls_pattern.pattern_size) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (tls_pattern.imm_size == 4) {
|
||||
LOG_INFO(Core_Linker, "PATTERN32 FOUND at {}, reg: {} offset: {:#x}",
|
||||
fmt::ptr(code), tls_pattern.target_reg,
|
||||
*(u32*)(code + tls_pattern.pattern_size));
|
||||
} else {
|
||||
LOG_INFO(Core_Linker, "PATTERN64 FOUND at {}, reg: {} offset: {:#x}",
|
||||
fmt::ptr(code), tls_pattern.target_reg,
|
||||
*(u32*)(code + tls_pattern.pattern_size));
|
||||
}
|
||||
code[0] = 0xcd;
|
||||
code[1] = 0x80 + tls_pattern.target_reg;
|
||||
code[2] = tls_pattern.pattern_size | (tls_pattern.imm_size << 4);
|
||||
code += total_size - 1;
|
||||
remaining_size -= total_size - 1;
|
||||
break;
|
||||
}
|
||||
code++;
|
||||
remaining_size--;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Core
|
16
src/core/tls.h
Normal file
16
src/core/tls.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
/// Installs a host exception handler to handle guest TLS access.
|
||||
void InstallTlsHandler();
|
||||
|
||||
/// Patches any instructions that access TLS to trigger the exception handler.
|
||||
void PatchTLS(u64 segment_addr, u64 segment_size);
|
||||
|
||||
} // namespace Core
|
|
@ -1,10 +1,11 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/error.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/virtual_memory.h"
|
||||
|
||||
#include "common/log.h"
|
||||
|
||||
#ifdef _WIN64
|
||||
#include <windows.h>
|
||||
#else
|
||||
|
@ -72,7 +73,7 @@ u64 memory_alloc(u64 address, u64 size, MemoryMode mode) {
|
|||
|
||||
if (ptr == 0) {
|
||||
auto err = static_cast<u32>(GetLastError());
|
||||
LOG_ERROR_IF(true, "VirtualAlloc() failed: 0x{:X}\n", err);
|
||||
LOG_ERROR(Common_Memory, "VirtualAlloc() failed: 0x{:X}", err);
|
||||
}
|
||||
#else
|
||||
auto ptr = reinterpret_cast<uintptr_t>(
|
||||
|
@ -80,7 +81,7 @@ u64 memory_alloc(u64 address, u64 size, MemoryMode mode) {
|
|||
PROT_EXEC | PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
|
||||
|
||||
if (ptr == reinterpret_cast<uintptr_t> MAP_FAILED) {
|
||||
LOG_ERROR_IF(true, "mmap() failed: {}\n", std::strerror(errno));
|
||||
LOG_ERROR(Common_Memory, "mmap() failed: {}", std::strerror(errno));
|
||||
}
|
||||
#endif
|
||||
return ptr;
|
||||
|
@ -91,7 +92,7 @@ bool memory_protect(u64 address, u64 size, MemoryMode mode, MemoryMode* old_mode
|
|||
if (VirtualProtect(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
|
||||
convertMemoryMode(mode), &old_protect) == 0) {
|
||||
auto err = static_cast<u32>(GetLastError());
|
||||
LOG_ERROR_IF(true, "VirtualProtect() failed: 0x{:X}\n", err);
|
||||
LOG_ERROR(Common_Memory, "VirtualProtect() failed: 0x{:X}", err);
|
||||
return false;
|
||||
}
|
||||
if (old_mode != nullptr) {
|
||||
|
@ -100,6 +101,10 @@ bool memory_protect(u64 address, u64 size, MemoryMode mode, MemoryMode* old_mode
|
|||
return true;
|
||||
#else
|
||||
int ret = mprotect(reinterpret_cast<void*>(address), size, convertMemoryMode(mode));
|
||||
if (ret != 0) {
|
||||
const auto error = Common::GetLastErrorMsg();
|
||||
ASSERT(false);
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
@ -110,7 +115,7 @@ bool memory_flush(u64 address, u64 size) {
|
|||
reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)),
|
||||
size) == 0) {
|
||||
auto err = static_cast<u32>(GetLastError());
|
||||
LOG_ERROR_IF(true, "FlushInstructionCache() failed: 0x{:X}\n", err);
|
||||
LOG_ERROR(Common_Memory, "FlushInstructionCache() failed: 0x{:X}", err);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -120,7 +125,7 @@ bool memory_flush(u64 address, u64 size) {
|
|||
}
|
||||
bool memory_patch(u64 vaddr, u64 value) {
|
||||
MemoryMode old_mode{};
|
||||
memory_protect(vaddr, 8, MemoryMode::ReadWrite, &old_mode);
|
||||
// memory_protect(vaddr, 8, MemoryMode::ReadWrite, &old_mode);
|
||||
|
||||
auto* ptr = reinterpret_cast<uint64_t*>(vaddr);
|
||||
|
||||
|
@ -128,7 +133,7 @@ bool memory_patch(u64 vaddr, u64 value) {
|
|||
|
||||
*ptr = value;
|
||||
|
||||
memory_protect(vaddr, 8, old_mode, nullptr);
|
||||
// memory_protect(vaddr, 8, old_mode, nullptr);
|
||||
|
||||
// if mode is executable flush it so insure that cpu finds it
|
||||
if (containsExecuteMode(old_mode)) {
|
||||
|
@ -161,15 +166,13 @@ u64 memory_alloc_aligned(u64 address, u64 size, MemoryMode mode, u64 alignment)
|
|||
|
||||
if (ptr == 0) {
|
||||
auto err = static_cast<u32>(GetLastError());
|
||||
LOG_ERROR_IF(true, "VirtualAlloc2() failed: 0x{:X}\n", err);
|
||||
LOG_ERROR(Common_Memory, "VirtualAlloc2() failed: 0x{:X}", err);
|
||||
}
|
||||
return ptr;
|
||||
#else
|
||||
void* hint_address = reinterpret_cast<void*>(AlignUp(address, alignment));
|
||||
void* ptr = mmap(hint_address, size, convertMemoryMode(mode), MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
if (ptr == MAP_FAILED) {
|
||||
std::abort();
|
||||
}
|
||||
ASSERT(ptr != MAP_FAILED);
|
||||
return reinterpret_cast<u64>(ptr);
|
||||
#endif
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue