Add initial Linux support.

This commit is contained in:
Esdras Tarsis 2023-06-22 22:48:55 -03:00
parent 8acfc3d557
commit 1e57195ded
7 changed files with 130 additions and 48 deletions

View File

@ -14,6 +14,7 @@ include_directories(third-party/imgui/backends)
include_directories(third-party/sdl/) include_directories(third-party/sdl/)
include_directories(third-party/fmt/include) include_directories(third-party/fmt/include)
include_directories(third-party/magic_enum/include) include_directories(third-party/magic_enum/include)
include_directories(third-party/zydis/include/Zydis)
add_subdirectory("third-party") add_subdirectory("third-party")
#=================== EXAMPLE =================== #=================== EXAMPLE ===================
@ -42,4 +43,4 @@ target_link_libraries(shadps4 PUBLIC fmt spdlog IMGUI SDL3-shared ${OPENGL_LIBRA
add_custom_command(TARGET shadps4 POST_BUILD add_custom_command(TARGET shadps4 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:SDL3-shared> $<TARGET_FILE:SDL3-shared>
$<TARGET_FILE_DIR:shadps4>) $<TARGET_FILE_DIR:shadps4>)

View File

@ -1,13 +1,13 @@
# shadPS4 # 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") [Check us on twitter](https://twitter.com/shadps4 "Check us on twitter")
# Status # Status
Currently it can only load PS4 ELF files . Currently it can only load PS4 ELF files.
![](https://geps.dev/progress/60) Elf Loader ![](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. 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| |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) |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) To discuss this emulator please join our Discord server: [![Discord](https://img.shields.io/discord/1080089157554155590)](https://discord.gg/MyZRaBngxA)
# Who are you? # 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 * PCSX
* PCSX2 * PCSX2
* PCSP * PCSP
@ -42,12 +62,12 @@ Old emulator fans and devs can recongnize me as "shadow" . I was the founder and
# Contribution # 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. * Initial GUI with imgui, SDL3 and Vulkan.
* Better logging system with spdlog * Better logging system with spdlog.
* ..to be filled * to be filled...
# Documentation # Documentation

View File

@ -4,16 +4,23 @@ FsFile::FsFile()
{ {
m_file = nullptr; m_file = nullptr;
} }
FsFile::FsFile(const std::string& path, fsOpenMode mode) FsFile::FsFile(const std::string& path, fsOpenMode mode)
{ {
Open(path, mode); Open(path, mode);
} }
bool FsFile::Open(const std::string& path, fsOpenMode mode) bool FsFile::Open(const std::string& path, fsOpenMode mode)
{ {
Close(); 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(); return IsOpen();
} }
bool FsFile::Close() bool FsFile::Close()
{ {
if (!IsOpen() || std::fclose(m_file) != 0) { if (!IsOpen() || std::fclose(m_file) != 0) {
@ -24,6 +31,7 @@ bool FsFile::Close()
m_file = nullptr; m_file = nullptr;
return true; return true;
} }
FsFile::~FsFile() FsFile::~FsFile()
{ {
Close(); Close();
@ -52,16 +60,26 @@ u32 FsFile::ReadBytes(void* dst, u64 size)
bool FsFile::Seek(s64 offset, fsSeekMode mode) bool FsFile::Seek(s64 offset, fsSeekMode mode)
{ {
if (!IsOpen() || _fseeki64(m_file, offset, getSeekMode(mode)) != 0) { #ifdef _WIN64
return false; 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; return true;
} }
u64 FsFile::Tell() const u64 FsFile::Tell() const
{ {
if (IsOpen()) { if (IsOpen()) {
return _ftelli64(m_file); #ifdef _WIN64
return _ftelli64(m_file);
#else
return ftello64(m_file);
#endif
} }
else { else {
return -1; return -1;
@ -69,17 +87,31 @@ u64 FsFile::Tell() const
} }
u64 FsFile::getFileSize() u64 FsFile::getFileSize()
{ {
u64 pos = _ftelli64(m_file); #ifdef _WIN64
if (_fseeki64(m_file, 0, SEEK_END) != 0) { u64 pos = _ftelli64(m_file);
if (_fseeki64(m_file, 0, SEEK_END) != 0) {
return 0; return 0;
} }
u64 size = _ftelli64(m_file); u64 size = _ftelli64(m_file);
if (_fseeki64(m_file, pos, SEEK_SET) != 0) { 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; return size;
} }

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <cstdio> #include <cstdio>
#include <string> #include <string>
#include "../Types.h" #include "../types.h"
enum fsOpenMode enum fsOpenMode
{ {
@ -60,4 +60,3 @@ public:
return m_file; return m_file;
} }
}; };

View File

@ -1,5 +1,11 @@
#include "../Core/PS4/Loader/Elf.h" #include "../Core/PS4/Loader/Elf.h"
#include <windows.h>
#ifdef _WIN64
#include <windows.h>
#else
#include <sys/mman.h>
#endif
#include "../Util/Log.h" #include "../Util/Log.h"
namespace Memory namespace Memory
@ -9,18 +15,31 @@ namespace Memory
u64 memory_alloc(u64 address, u64 size) u64 memory_alloc(u64 address, u64 size)
{ {
//TODO it supports only execute_read_write mode //TODO it supports only execute_read_write mode
auto ptr = reinterpret_cast<uintptr_t>(VirtualAlloc(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), #ifdef _WIN64
size, auto ptr = reinterpret_cast<uintptr_t>(VirtualAlloc(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)),
static_cast<DWORD>(MEM_COMMIT) | static_cast<DWORD>(MEM_RESERVE), size,
PAGE_EXECUTE_READWRITE)); static_cast<DWORD>(MEM_COMMIT) | static_cast<DWORD>(MEM_RESERVE),
PAGE_EXECUTE_READWRITE));
if (ptr == 0) if (ptr == 0)
{ {
auto err = static_cast<u32>(GetLastError()); auto err = static_cast<u32>(GetLastError());
LOG_ERROR_IF(true,"VirtualAlloc() failed: 0x{:X}\n", err); LOG_ERROR_IF(true, "VirtualAlloc() failed: 0x{:X}\n", err);
} }
#else
auto ptr = reinterpret_cast<uintptr_t>(mmap(reinterpret_cast<void *>(static_cast<uintptr_t>(address)),
size,
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));
}
#endif
return ptr; return ptr;
} }
} }
}
}

View File

@ -7,6 +7,13 @@
#include <fmt/core.h> #include <fmt/core.h>
#include "../../../Util/Log.h" #include "../../../Util/Log.h"
#ifdef _WIN64
#define DBG_BREAKPOINT __debugbreak();
#else
#include <signal.h>
#define DBG_BREAKPOINT raise(SIGTRAP);
#endif
constexpr bool debug_elf = true; constexpr bool debug_elf = true;
template <> template <>
@ -29,7 +36,6 @@ static self_header* load_self(FsFile& f)
return self; return self;
} }
static self_segment_header* load_self_segments(FsFile& f, u16 num) static self_segment_header* load_self_segments(FsFile& f, u16 num)
{ {
auto* segs = new self_segment_header[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; return segs;
} }
static elf_header* load_elf_header(FsFile& f) static elf_header* load_elf_header(FsFile& f)
{ {
auto* m_elf_header = new elf_header; auto* m_elf_header = new elf_header;
@ -95,6 +100,7 @@ void Elf::Reset()//reset all variables
m_elf_shdr = nullptr; m_elf_shdr = nullptr;
m_self_id_header = nullptr; m_self_id_header = nullptr;
} }
void Elf::Open(const std::string& file_name) void Elf::Open(const std::string& file_name)
{ {
Reset();//reset all variables Reset();//reset all variables
@ -151,7 +157,6 @@ void Elf::Open(const std::string& file_name)
} }
} }
DebugDump(); DebugDump();
} }
@ -272,7 +277,9 @@ bool Elf::isElfFile() const
void Elf::DebugDump() { void Elf::DebugDump() {
std::vector<spdlog::sink_ptr> sinks; std::vector<spdlog::sink_ptr> sinks;
sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>()); sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>(L"output.log", true)); //this might work only in windows ;/ #ifdef _WIN64
sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>(L"output.log", true)); //this might work only in windows ;/
#endif
spdlog::set_default_logger(std::make_shared<spdlog::logger>("shadps4 logger", begin(sinks), end(sinks))); spdlog::set_default_logger(std::make_shared<spdlog::logger>("shadps4 logger", begin(sinks), end(sinks)));
auto f = std::make_unique<spdlog::pattern_formatter>("%v", spdlog::pattern_time_type::local, std::string("")); // disable eol auto f = std::make_unique<spdlog::pattern_formatter>("%v", spdlog::pattern_time_type::local, std::string("")); // disable eol
spdlog::set_formatter(std::move(f)); spdlog::set_formatter(std::move(f));
@ -355,6 +362,7 @@ std::string Elf::SElfHeaderStr() {
header+= fmt::format("padding3 ...........: {:#010x}\n", m_self->padding3); header+= fmt::format("padding3 ...........: {:#010x}\n", m_self->padding3);
return header; return header;
} }
std::string Elf::SELFSegHeader(u16 no) std::string Elf::SELFSegHeader(u16 no)
{ {
auto segment_header = m_self_segments[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); header += fmt::format("memory size ......: {}\n", segment_header.memory_size);
return header; return header;
} }
std::string Elf::ElfHeaderStr() std::string Elf::ElfHeaderStr()
{ {
std::string header = fmt::format("======= Elf header ===========\n"); 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); std::string header = fmt::format("====== PROGRAM HEADER {} ========\n", no);
header += fmt::format("p_type ....: {}\n", ElfPheaderTypeStr((m_elf_phdr + no)->p_type)); header += fmt::format("p_type ....: {}\n", ElfPheaderTypeStr((m_elf_phdr + no)->p_type));
auto flags = magic_enum::enum_cast<elf_program_flags>((m_elf_phdr + no)->p_flags); auto flags = magic_enum::enum_cast<elf_program_flags>((m_elf_phdr + no)->p_flags);
if (flags.has_value()) 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); header += fmt::format("p_align ...: {:#018x}\n", (m_elf_phdr + no)->p_align);
return header; return header;
} }
void Elf::LoadSegment(u64 virtual_addr, u64 file_offset, u64 size) void Elf::LoadSegment(u64 virtual_addr, u64 file_offset, u64 size)
{ {
if (m_self!=nullptr) 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++) for (uint16_t i = 0; i < m_self->segment_count; i++)
{ {
const auto& seg = m_self_segments[i]; const auto& seg = m_self_segments[i];
if (seg.IsBlocked()) if (seg.IsBlocked())
{ {
auto phdr_id = seg.GetId(); 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) if (file_offset >= phdr.p_offset && file_offset < phdr.p_offset + phdr.p_filesz)
{ {
auto offset = file_offset - phdr.p_offset; 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<void*>(static_cast<uintptr_t>(virtual_addr)), size); m_f->Read(reinterpret_cast<void*>(static_cast<uintptr_t>(virtual_addr)), size);
return; return;
} }
} }
} }
__debugbreak();//hmm we didn't return something... DBG_BREAKPOINT //hmm we didn't return something...
} }
else else
{ {
@ -545,7 +555,8 @@ void Elf::LoadSegment(u64 virtual_addr, u64 file_offset, u64 size)
m_f->Read(reinterpret_cast<void*>(static_cast<uintptr_t>(virtual_addr)), size); m_f->Read(reinterpret_cast<void*>(static_cast<uintptr_t>(virtual_addr)), size);
} }
} }
u64 Elf::GetElfEntry() u64 Elf::GetElfEntry()
{ {
return m_elf_header->e_entry; return m_elf_header->e_entry;
} }

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "zydis/Zydis.h" #include "Zydis.h"
#include "../types.h" #include "../types.h"
class Disassembler class Disassembler
@ -14,4 +14,4 @@ public:
private: private:
ZydisDecoder m_decoder; ZydisDecoder m_decoder;
ZydisFormatter m_formatter; ZydisFormatter m_formatter;
}; };