From 1e57195ded25a0a7cf1522dd9da24ba95fe41d9c Mon Sep 17 00:00:00 2001 From: Esdras Tarsis Date: Thu, 22 Jun 2023 22:48:55 -0300 Subject: [PATCH] Add initial Linux support. --- CMakeLists.txt | 3 +- README.md | 38 ++++++++++++++++++------ src/Core/FsFile.cpp | 58 ++++++++++++++++++++++++++++--------- src/Core/FsFile.h | 3 +- src/Core/Memory.cpp | 43 +++++++++++++++++++-------- src/Core/PS4/Loader/Elf.cpp | 29 +++++++++++++------ src/Util/Disassembler.h | 4 +-- 7 files changed, 130 insertions(+), 48 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index af06afb9..c7d27e22 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ include_directories(third-party/imgui/backends) include_directories(third-party/sdl/) include_directories(third-party/fmt/include) include_directories(third-party/magic_enum/include) +include_directories(third-party/zydis/include/Zydis) add_subdirectory("third-party") #=================== EXAMPLE =================== @@ -42,4 +43,4 @@ target_link_libraries(shadps4 PUBLIC fmt spdlog IMGUI SDL3-shared ${OPENGL_LIBRA add_custom_command(TARGET shadps4 POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $ - $) \ No newline at end of file + $) diff --git a/README.md b/README.md index 1b0d65e8..582fbd25 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ # shadPS4 -An early PS4 emulator for Windows +An early PS4 emulator for Windows and Linux [Check us on twitter](https://twitter.com/shadps4 "Check us on twitter") # Status -Currently it can only load PS4 ELF files . +Currently it can only load PS4 ELF files. ![](https://geps.dev/progress/60) Elf Loader @@ -19,20 +19,40 @@ Currently it can only load PS4 ELF files . The project started as a fun project. Due to short amount of free time probably it will take a while since it will be able to run something decent but I am trying to do regular small commits. -# Build +# Build -Project is using cmake files. To build, Visual Studio 2022 is enough +## Windows + +The project is using cmake files. To build, just use Visual Studio 2022. + +## Linux + +Generate the build directory in the shadPS4 directory: +``` +cmake -S . -B build/ +``` + +Enter the directory: +``` +cd build/ +``` + +Use make to build the project: +``` +make -j$(nproc) +``` |Platform|Build status| |--------|------------| |Windows build|[![Windows](https://github.com/georgemoralis/shadPS4/actions/workflows/windows.yml/badge.svg)](https://github.com/georgemoralis/shadPS4/actions/workflows/windows.yml) +|Linux build| TODO To discuss this emulator please join our Discord server: [![Discord](https://img.shields.io/discord/1080089157554155590)](https://discord.gg/MyZRaBngxA) # Who are you? -Old emulator fans and devs can recongnize me as "shadow" . I was the founder and coder for a lot of emulation projects +Old emulator fans and devs can recongnize me as "shadow". I was the founder and coder for a lot of emulation projects: * PCSX * PCSX2 * PCSP @@ -42,12 +62,12 @@ Old emulator fans and devs can recongnize me as "shadow" . I was the founder and # Contribution -Currently I accept any kind of contribution some hints for what is might be useful. +I currently accept any kind of contribution, here is a list of some items that may be useful: -* PKG extractor (there was an initial work on this, just search project history commits) +* PKG extractor (there was an initial work on this, just search project history commits). * Initial GUI with imgui, SDL3 and Vulkan. -* Better logging system with spdlog -* ..to be filled +* Better logging system with spdlog. +* to be filled... # Documentation diff --git a/src/Core/FsFile.cpp b/src/Core/FsFile.cpp index 2ea882f1..7f23ad17 100644 --- a/src/Core/FsFile.cpp +++ b/src/Core/FsFile.cpp @@ -4,16 +4,23 @@ FsFile::FsFile() { m_file = nullptr; } + FsFile::FsFile(const std::string& path, fsOpenMode mode) { Open(path, mode); } + bool FsFile::Open(const std::string& path, fsOpenMode mode) { Close(); - fopen_s(&m_file, path.c_str(), getOpenMode(mode)); + #ifdef _WIN64 + fopen_s(&m_file, path.c_str(), getOpenMode(mode)); + #else + m_file = std::fopen(path.c_str(), getOpenMode(mode)); + #endif return IsOpen(); } + bool FsFile::Close() { if (!IsOpen() || std::fclose(m_file) != 0) { @@ -24,6 +31,7 @@ bool FsFile::Close() m_file = nullptr; return true; } + FsFile::~FsFile() { Close(); @@ -52,16 +60,26 @@ u32 FsFile::ReadBytes(void* dst, u64 size) bool FsFile::Seek(s64 offset, fsSeekMode mode) { - if (!IsOpen() || _fseeki64(m_file, offset, getSeekMode(mode)) != 0) { - return false; - } + #ifdef _WIN64 + if (!IsOpen() || _fseeki64(m_file, offset, getSeekMode(mode)) != 0) { + return false; + } + #else + if (!IsOpen() || fseeko64(m_file, offset, getSeekMode(mode)) != 0) { + return false; + } + #endif return true; } u64 FsFile::Tell() const { if (IsOpen()) { - return _ftelli64(m_file); + #ifdef _WIN64 + return _ftelli64(m_file); + #else + return ftello64(m_file); + #endif } else { return -1; @@ -69,17 +87,31 @@ u64 FsFile::Tell() const } u64 FsFile::getFileSize() { - u64 pos = _ftelli64(m_file); - if (_fseeki64(m_file, 0, SEEK_END) != 0) { + #ifdef _WIN64 + u64 pos = _ftelli64(m_file); + if (_fseeki64(m_file, 0, SEEK_END) != 0) { - return 0; - } + return 0; + } - u64 size = _ftelli64(m_file); - if (_fseeki64(m_file, pos, SEEK_SET) != 0) { + u64 size = _ftelli64(m_file); + if (_fseeki64(m_file, pos, SEEK_SET) != 0) { - return 0; - } + return 0; + } + #else + u64 pos = ftello64(m_file); + if (fseeko64(m_file, 0, SEEK_END) != 0) { + + return 0; + } + + u64 size = ftello64(m_file); + if (fseeko64(m_file, pos, SEEK_SET) != 0) { + + return 0; + } + #endif return size; } diff --git a/src/Core/FsFile.h b/src/Core/FsFile.h index dd505df8..8bc019da 100644 --- a/src/Core/FsFile.h +++ b/src/Core/FsFile.h @@ -1,7 +1,7 @@ #pragma once #include #include -#include "../Types.h" +#include "../types.h" enum fsOpenMode { @@ -60,4 +60,3 @@ public: return m_file; } }; - diff --git a/src/Core/Memory.cpp b/src/Core/Memory.cpp index 935e8542..a3bc36d1 100644 --- a/src/Core/Memory.cpp +++ b/src/Core/Memory.cpp @@ -1,5 +1,11 @@ #include "../Core/PS4/Loader/Elf.h" -#include + +#ifdef _WIN64 + #include +#else + #include +#endif + #include "../Util/Log.h" namespace Memory @@ -9,18 +15,31 @@ namespace Memory u64 memory_alloc(u64 address, u64 size) { //TODO it supports only execute_read_write mode - auto ptr = reinterpret_cast(VirtualAlloc(reinterpret_cast(static_cast(address)), - size, - static_cast(MEM_COMMIT) | static_cast(MEM_RESERVE), - PAGE_EXECUTE_READWRITE)); + #ifdef _WIN64 + auto ptr = reinterpret_cast(VirtualAlloc(reinterpret_cast(static_cast(address)), + size, + static_cast(MEM_COMMIT) | static_cast(MEM_RESERVE), + PAGE_EXECUTE_READWRITE)); - if (ptr == 0) - { - auto err = static_cast(GetLastError()); - LOG_ERROR_IF(true,"VirtualAlloc() failed: 0x{:X}\n", err); - } + if (ptr == 0) + { + auto err = static_cast(GetLastError()); + LOG_ERROR_IF(true, "VirtualAlloc() failed: 0x{:X}\n", err); + } + #else + auto ptr = reinterpret_cast(mmap(reinterpret_cast(static_cast(address)), + size, + PROT_EXEC | PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, + -1, + 0)); + + if (ptr == reinterpret_castMAP_FAILED) + { + LOG_ERROR_IF(true, "mmap() failed: {}\n", std::strerror(errno)); + } + #endif return ptr; } } - -} \ No newline at end of file +} diff --git a/src/Core/PS4/Loader/Elf.cpp b/src/Core/PS4/Loader/Elf.cpp index f9ec3686..5f44a13f 100644 --- a/src/Core/PS4/Loader/Elf.cpp +++ b/src/Core/PS4/Loader/Elf.cpp @@ -7,6 +7,13 @@ #include #include "../../../Util/Log.h" +#ifdef _WIN64 + #define DBG_BREAKPOINT __debugbreak(); +#else + #include + #define DBG_BREAKPOINT raise(SIGTRAP); +#endif + constexpr bool debug_elf = true; template <> @@ -29,7 +36,6 @@ static self_header* load_self(FsFile& f) return self; } - static self_segment_header* load_self_segments(FsFile& f, u16 num) { auto* segs = new self_segment_header[num]; @@ -39,7 +45,6 @@ static self_segment_header* load_self_segments(FsFile& f, u16 num) return segs; } - static elf_header* load_elf_header(FsFile& f) { auto* m_elf_header = new elf_header; @@ -95,6 +100,7 @@ void Elf::Reset()//reset all variables m_elf_shdr = nullptr; m_self_id_header = nullptr; } + void Elf::Open(const std::string& file_name) { Reset();//reset all variables @@ -151,7 +157,6 @@ void Elf::Open(const std::string& file_name) } } - DebugDump(); } @@ -272,7 +277,9 @@ bool Elf::isElfFile() const void Elf::DebugDump() { std::vector sinks; sinks.push_back(std::make_shared()); - sinks.push_back(std::make_shared(L"output.log", true)); //this might work only in windows ;/ + #ifdef _WIN64 + sinks.push_back(std::make_shared(L"output.log", true)); //this might work only in windows ;/ + #endif spdlog::set_default_logger(std::make_shared("shadps4 logger", begin(sinks), end(sinks))); auto f = std::make_unique("%v", spdlog::pattern_time_type::local, std::string("")); // disable eol spdlog::set_formatter(std::move(f)); @@ -355,6 +362,7 @@ std::string Elf::SElfHeaderStr() { header+= fmt::format("padding3 ...........: {:#010x}\n", m_self->padding3); return header; } + std::string Elf::SELFSegHeader(u16 no) { auto segment_header = m_self_segments[no]; @@ -365,6 +373,7 @@ std::string Elf::SELFSegHeader(u16 no) header += fmt::format("memory size ......: {}\n", segment_header.memory_size); return header; } + std::string Elf::ElfHeaderStr() { std::string header = fmt::format("======= Elf header ===========\n"); @@ -499,7 +508,7 @@ std::string Elf::ElfPHeaderStr(u16 no) { std::string header = fmt::format("====== PROGRAM HEADER {} ========\n", no); header += fmt::format("p_type ....: {}\n", ElfPheaderTypeStr((m_elf_phdr + no)->p_type)); - + auto flags = magic_enum::enum_cast((m_elf_phdr + no)->p_flags); if (flags.has_value()) { @@ -514,6 +523,7 @@ std::string Elf::ElfPHeaderStr(u16 no) header += fmt::format("p_align ...: {:#018x}\n", (m_elf_phdr + no)->p_align); return header; } + void Elf::LoadSegment(u64 virtual_addr, u64 file_offset, u64 size) { if (m_self!=nullptr) @@ -521,7 +531,7 @@ void Elf::LoadSegment(u64 virtual_addr, u64 file_offset, u64 size) for (uint16_t i = 0; i < m_self->segment_count; i++) { const auto& seg = m_self_segments[i]; - + if (seg.IsBlocked()) { auto phdr_id = seg.GetId(); @@ -530,13 +540,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,fsSeekMode::fsSeekSet); + m_f->Seek(offset + seg.file_offset, fsSeekMode::fsSeekSet); m_f->Read(reinterpret_cast(static_cast(virtual_addr)), size); return; } } } - __debugbreak();//hmm we didn't return something... + DBG_BREAKPOINT //hmm we didn't return something... } else { @@ -545,7 +555,8 @@ void Elf::LoadSegment(u64 virtual_addr, u64 file_offset, u64 size) m_f->Read(reinterpret_cast(static_cast(virtual_addr)), size); } } + u64 Elf::GetElfEntry() { return m_elf_header->e_entry; -} \ No newline at end of file +} diff --git a/src/Util/Disassembler.h b/src/Util/Disassembler.h index 896a7632..7e444c5a 100644 --- a/src/Util/Disassembler.h +++ b/src/Util/Disassembler.h @@ -1,6 +1,6 @@ #pragma once -#include "zydis/Zydis.h" +#include "Zydis.h" #include "../types.h" class Disassembler @@ -14,4 +14,4 @@ public: private: ZydisDecoder m_decoder; ZydisFormatter m_formatter; -}; \ No newline at end of file +};