Virtual device abstraction (#1577)

* IOFile: removes seek limit checks when file is writable

* add virtual devices scaffold

* add stdin/out/err as virtual devices

* fixed some merging issues

* clang-fix

---------

Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
This commit is contained in:
Vinicius Rangel 2024-12-05 13:00:17 -03:00 committed by GitHub
parent c019b54fec
commit 2380f2f9c9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 687 additions and 77 deletions

View file

@ -502,6 +502,7 @@ set(COMMON src/common/logging/backend.cpp
src/common/types.h src/common/types.h
src/common/uint128.h src/common/uint128.h
src/common/unique_function.h src/common/unique_function.h
src/common/va_ctx.h
src/common/version.h src/common/version.h
src/common/ntapi.h src/common/ntapi.h
src/common/ntapi.cpp src/common/ntapi.cpp
@ -526,6 +527,12 @@ set(CORE src/core/aerolib/stubs.cpp
src/core/crypto/crypto.cpp src/core/crypto/crypto.cpp
src/core/crypto/crypto.h src/core/crypto/crypto.h
src/core/crypto/keys.h src/core/crypto/keys.h
src/core/devices/base_device.cpp
src/core/devices/base_device.h
src/core/devices/ioccom.h
src/core/devices/logger.cpp
src/core/devices/logger.h
src/core/devices/nop_device.h
src/core/file_format/pfs.h src/core/file_format/pfs.h
src/core/file_format/pkg.cpp src/core/file_format/pkg.cpp
src/core/file_format/pkg.h src/core/file_format/pkg.h

View file

@ -377,16 +377,18 @@ bool IOFile::Seek(s64 offset, SeekOrigin origin) const {
return false; return false;
} }
u64 size = GetSize(); if (False(file_access_mode & (FileAccessMode::Write | FileAccessMode::Append))) {
if (origin == SeekOrigin::CurrentPosition && Tell() + offset > size) { u64 size = GetSize();
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file"); if (origin == SeekOrigin::CurrentPosition && Tell() + offset > size) {
return false; LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
} else if (origin == SeekOrigin::SetOrigin && (u64)offset > size) { return false;
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file"); } else if (origin == SeekOrigin::SetOrigin && (u64)offset > size) {
return false; LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
} else if (origin == SeekOrigin::End && offset > 0) { return false;
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file"); } else if (origin == SeekOrigin::End && offset > 0) {
return false; LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
}
} }
errno = 0; errno = 0;

View file

@ -10,6 +10,7 @@
#include "common/concepts.h" #include "common/concepts.h"
#include "common/types.h" #include "common/types.h"
#include "enum.h"
namespace Common::FS { namespace Common::FS {
@ -42,6 +43,7 @@ enum class FileAccessMode {
*/ */
ReadAppend = Read | Append, ReadAppend = Read | Append,
}; };
DECLARE_ENUM_FLAG_OPERATORS(FileAccessMode);
enum class FileType { enum class FileType {
BinaryFile, BinaryFile,

View file

@ -69,6 +69,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Common, Memory) \ SUB(Common, Memory) \
CLS(Core) \ CLS(Core) \
SUB(Core, Linker) \ SUB(Core, Linker) \
SUB(Core, Devices) \
CLS(Config) \ CLS(Config) \
CLS(Debug) \ CLS(Debug) \
CLS(Kernel) \ CLS(Kernel) \

View file

@ -35,6 +35,7 @@ enum class Class : u8 {
Common_Memory, ///< Memory mapping and management functions Common_Memory, ///< Memory mapping and management functions
Core, ///< LLE emulation core Core, ///< LLE emulation core
Core_Linker, ///< The module linker Core_Linker, ///< The module linker
Core_Devices, ///< Devices emulation
Config, ///< Emulator configuration (including commandline) Config, ///< Emulator configuration (including commandline)
Debug, ///< Debugging tools Debug, ///< Debugging tools
Kernel, ///< The HLE implementation of the PS4 kernel. Kernel, ///< The HLE implementation of the PS4 kernel.

111
src/common/va_ctx.h Normal file
View file

@ -0,0 +1,111 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <xmmintrin.h>
#include "common/types.h"
#define VA_ARGS \
uint64_t rdi, uint64_t rsi, uint64_t rdx, uint64_t rcx, uint64_t r8, uint64_t r9, \
uint64_t overflow_arg_area, __m128 xmm0, __m128 xmm1, __m128 xmm2, __m128 xmm3, \
__m128 xmm4, __m128 xmm5, __m128 xmm6, __m128 xmm7, ...
#define VA_CTX(ctx) \
alignas(16)::Common::VaCtx ctx{}; \
(ctx).reg_save_area.gp[0] = rdi; \
(ctx).reg_save_area.gp[1] = rsi; \
(ctx).reg_save_area.gp[2] = rdx; \
(ctx).reg_save_area.gp[3] = rcx; \
(ctx).reg_save_area.gp[4] = r8; \
(ctx).reg_save_area.gp[5] = r9; \
(ctx).reg_save_area.fp[0] = xmm0; \
(ctx).reg_save_area.fp[1] = xmm1; \
(ctx).reg_save_area.fp[2] = xmm2; \
(ctx).reg_save_area.fp[3] = xmm3; \
(ctx).reg_save_area.fp[4] = xmm4; \
(ctx).reg_save_area.fp[5] = xmm5; \
(ctx).reg_save_area.fp[6] = xmm6; \
(ctx).reg_save_area.fp[7] = xmm7; \
(ctx).va_list.reg_save_area = &(ctx).reg_save_area; \
(ctx).va_list.gp_offset = offsetof(::Common::VaRegSave, gp); \
(ctx).va_list.fp_offset = offsetof(::Common::VaRegSave, fp); \
(ctx).va_list.overflow_arg_area = &overflow_arg_area;
namespace Common {
// https://stackoverflow.com/questions/4958384/what-is-the-format-of-the-x86-64-va-list-structure
struct VaList {
u32 gp_offset;
u32 fp_offset;
void* overflow_arg_area;
void* reg_save_area;
};
struct VaRegSave {
u64 gp[6];
__m128 fp[8];
};
struct VaCtx {
VaRegSave reg_save_area;
VaList va_list;
};
template <class T, uint32_t Size>
T vaArgRegSaveAreaGp(VaList* l) {
auto* addr = reinterpret_cast<T*>(static_cast<u8*>(l->reg_save_area) + l->gp_offset);
l->gp_offset += Size;
return *addr;
}
template <class T, u64 Align, u64 Size>
T vaArgOverflowArgArea(VaList* l) {
auto ptr = ((reinterpret_cast<u64>(l->overflow_arg_area) + (Align - 1)) & ~(Align - 1));
auto* addr = reinterpret_cast<T*>(ptr);
l->overflow_arg_area = reinterpret_cast<void*>(ptr + Size);
return *addr;
}
template <class T, uint32_t Size>
T vaArgRegSaveAreaFp(VaList* l) {
auto* addr = reinterpret_cast<T*>(static_cast<u8*>(l->reg_save_area) + l->fp_offset);
l->fp_offset += Size;
return *addr;
}
inline int vaArgInteger(VaList* l) {
if (l->gp_offset <= 40) {
return vaArgRegSaveAreaGp<int, 8>(l);
}
return vaArgOverflowArgArea<int, 1, 8>(l);
}
inline long long vaArgLongLong(VaList* l) {
if (l->gp_offset <= 40) {
return vaArgRegSaveAreaGp<long long, 8>(l);
}
return vaArgOverflowArgArea<long long, 1, 8>(l);
}
inline long vaArgLong(VaList* l) {
if (l->gp_offset <= 40) {
return vaArgRegSaveAreaGp<long, 8>(l);
}
return vaArgOverflowArgArea<long, 1, 8>(l);
}
inline double vaArgDouble(VaList* l) {
if (l->fp_offset <= 160) {
return vaArgRegSaveAreaFp<double, 16>(l);
}
return vaArgOverflowArgArea<double, 1, 8>(l);
}
template <class T>
T* vaArgPtr(VaList* l) {
if (l->gp_offset <= 40) {
return vaArgRegSaveAreaGp<T*, 8>(l);
}
return vaArgOverflowArgArea<T*, 1, 8>(l);
}
} // namespace Common

View file

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "base_device.h"
namespace Core::Devices {
BaseDevice::BaseDevice() = default;
BaseDevice::~BaseDevice() = default;
} // namespace Core::Devices

View file

@ -0,0 +1,72 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <core/libraries/kernel/orbis_error.h>
#include "common/types.h"
#include "common/va_ctx.h"
namespace Libraries::Kernel {
struct OrbisKernelStat;
struct SceKernelIovec;
} // namespace Libraries::Kernel
namespace Core::Devices {
class BaseDevice {
public:
explicit BaseDevice();
virtual ~BaseDevice() = 0;
virtual int ioctl(u64 cmd, Common::VaCtx* args) {
return ORBIS_KERNEL_ERROR_ENOTTY;
}
virtual s64 write(const void* buf, size_t nbytes) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual s64 lseek(s64 offset, int whence) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual s64 read(void* buf, size_t nbytes) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual int fstat(Libraries::Kernel::OrbisKernelStat* sb) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual s32 fsync() {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual int ftruncate(s64 length) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual int getdents(void* buf, u32 nbytes, s64* basep) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual s64 pwrite(const void* buf, size_t nbytes, u64 offset) {
return ORBIS_KERNEL_ERROR_EBADF;
}
};
} // namespace Core::Devices

67
src/core/devices/ioccom.h Normal file
View file

@ -0,0 +1,67 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
/*-
* Copyright (c) 1982, 1986, 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ioccom.h 8.2 (Berkeley) 3/28/94
* $FreeBSD$
*/
#define IOCPARM_SHIFT 13 /* number of bits for ioctl size */
#define IOCPARM_MASK ((1 << IOCPARM_SHIFT) - 1) /* parameter length mask */
#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
#define IOCBASECMD(x) ((x) & ~(IOCPARM_MASK << 16))
#define IOCGROUP(x) (((x) >> 8) & 0xff)
#define IOCPARM_MAX (1 << IOCPARM_SHIFT) /* max size of ioctl */
#define IOC_VOID 0x20000000 /* no parameters */
#define IOC_OUT 0x40000000 /* copy out parameters */
#define IOC_IN 0x80000000 /* copy in parameters */
#define IOC_INOUT (IOC_IN | IOC_OUT)
#define IOC_DIRMASK (IOC_VOID | IOC_OUT | IOC_IN)
#define _IOC(inout, group, num, len) \
((unsigned long)((inout) | (((len) & IOCPARM_MASK) << 16) | ((group) << 8) | (num)))
#define _IO(g, n) _IOC(IOC_VOID, (g), (n), 0)
#define _IOWINT(g, n) _IOC(IOC_VOID, (g), (n), sizeof(int))
#define _IOR(g, n, t) _IOC(IOC_OUT, (g), (n), sizeof(t))
#define _IOW(g, n, t) _IOC(IOC_IN, (g), (n), sizeof(t))
/* this should be _IORW, but stdio got there first */
#define _IOWR(g, n, t) _IOC(IOC_INOUT, (g), (n), sizeof(t))
/*
# Simple parse of ioctl cmd
def parse(v):
print('inout', (v >> 24 & 0xFF))
print('len', hex(v >> 16 & 0xFF))
print('group', chr(v >> 8 & 0xFF))
print('num', hex(v & 0xFF))
*/

View file

@ -0,0 +1,64 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/libraries/kernel/file_system.h"
#include "logger.h"
namespace Core::Devices {
Logger::Logger(std::string prefix, bool is_err) : prefix(std::move(prefix)), is_err(is_err) {}
Logger::~Logger() = default;
s64 Logger::write(const void* buf, size_t nbytes) {
log(static_cast<const char*>(buf), nbytes);
return nbytes;
}
size_t Logger::writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
for (int i = 0; i < iovcnt; i++) {
log(static_cast<const char*>(iov[i].iov_base), iov[i].iov_len);
}
return iovcnt;
}
s64 Logger::pwrite(const void* buf, size_t nbytes, u64 offset) {
log(static_cast<const char*>(buf), nbytes);
return nbytes;
}
s32 Logger::fsync() {
log_flush();
return 0;
}
void Logger::log(const char* buf, size_t nbytes) {
std::scoped_lock lock{mtx};
const char* end = buf + nbytes;
for (const char* it = buf; it < end; ++it) {
char c = *it;
if (c == '\r') {
continue;
}
if (c == '\n') {
log_flush();
continue;
}
buffer.push_back(c);
}
}
void Logger::log_flush() {
std::scoped_lock lock{mtx};
if (buffer.empty()) {
return;
}
if (is_err) {
LOG_ERROR(Tty, "[{}] {}", prefix, std::string_view{buffer});
} else {
LOG_INFO(Tty, "[{}] {}", prefix, std::string_view{buffer});
}
buffer.clear();
}
} // namespace Core::Devices

37
src/core/devices/logger.h Normal file
View file

@ -0,0 +1,37 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "base_device.h"
#include <mutex>
#include <string>
#include <vector>
namespace Core::Devices {
class Logger final : BaseDevice {
std::string prefix;
bool is_err;
std::recursive_mutex mtx;
std::vector<char> buffer;
public:
explicit Logger(std::string prefix, bool is_err);
~Logger() override;
s64 write(const void* buf, size_t nbytes) override;
size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
s32 fsync() override;
private:
void log(const char* buf, size_t nbytes);
void log_flush();
};
} // namespace Core::Devices

View file

@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "base_device.h"
namespace Core::Devices {
class NopDevice final : BaseDevice {
u32 handle;
public:
explicit NopDevice(u32 handle) : handle(handle) {}
~NopDevice() override = default;
int ioctl(u64 cmd, Common::VaCtx* args) override {
return 0;
}
s64 write(const void* buf, size_t nbytes) override {
return 0;
}
size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override {
return 0;
}
size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override {
return 0;
}
s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override {
return 0;
}
s64 lseek(s64 offset, int whence) override {
return 0;
}
s64 read(void* buf, size_t nbytes) override {
return 0;
}
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override {
return 0;
}
s32 fsync() override {
return 0;
}
int ftruncate(s64 length) override {
return 0;
}
int getdents(void* buf, u32 nbytes, s64* basep) override {
return 0;
}
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override {
return 0;
}
};
} // namespace Core::Devices

View file

@ -4,12 +4,12 @@
#include <algorithm> #include <algorithm>
#include "common/config.h" #include "common/config.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "core/devices/logger.h"
#include "core/devices/nop_device.h"
#include "core/file_sys/fs.h" #include "core/file_sys/fs.h"
namespace Core::FileSys { namespace Core::FileSys {
constexpr int RESERVED_HANDLES = 3; // First 3 handles are stdin,stdout,stderr
void MntPoints::Mount(const std::filesystem::path& host_folder, const std::string& guest_folder, void MntPoints::Mount(const std::filesystem::path& host_folder, const std::string& guest_folder,
bool read_only) { bool read_only) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
@ -135,7 +135,6 @@ int HandleTable::CreateHandle() {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
auto* file = new File{}; auto* file = new File{};
file->is_directory = false;
file->is_opened = false; file->is_opened = false;
int existingFilesNum = m_files.size(); int existingFilesNum = m_files.size();
@ -143,23 +142,23 @@ int HandleTable::CreateHandle() {
for (int index = 0; index < existingFilesNum; index++) { for (int index = 0; index < existingFilesNum; index++) {
if (m_files.at(index) == nullptr) { if (m_files.at(index) == nullptr) {
m_files[index] = file; m_files[index] = file;
return index + RESERVED_HANDLES; return index;
} }
} }
m_files.push_back(file); m_files.push_back(file);
return m_files.size() + RESERVED_HANDLES - 1; return m_files.size() - 1;
} }
void HandleTable::DeleteHandle(int d) { void HandleTable::DeleteHandle(int d) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
delete m_files.at(d - RESERVED_HANDLES); delete m_files.at(d);
m_files[d - RESERVED_HANDLES] = nullptr; m_files[d] = nullptr;
} }
File* HandleTable::GetFile(int d) { File* HandleTable::GetFile(int d) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
return m_files.at(d - RESERVED_HANDLES); return m_files.at(d);
} }
File* HandleTable::GetFile(const std::filesystem::path& host_name) { File* HandleTable::GetFile(const std::filesystem::path& host_name) {
@ -171,4 +170,20 @@ File* HandleTable::GetFile(const std::filesystem::path& host_name) {
return nullptr; return nullptr;
} }
void HandleTable::CreateStdHandles() {
auto setup = [this](const char* path, auto* device) {
int fd = CreateHandle();
auto* file = GetFile(fd);
file->is_opened = true;
file->type = FileType::Device;
file->m_guest_name = path;
file->device =
std::shared_ptr<Devices::BaseDevice>{reinterpret_cast<Devices::BaseDevice*>(device)};
};
// order matters
setup("/dev/stdin", new Devices::NopDevice(0)); // stdin
setup("/dev/stdout", new Devices::Logger("stdout", false)); // stdout
setup("/dev/stderr", new Devices::Logger("stderr", true)); // stderr
}
} // namespace Core::FileSys } // namespace Core::FileSys

View file

@ -9,6 +9,7 @@
#include <vector> #include <vector>
#include <tsl/robin_map.h> #include <tsl/robin_map.h>
#include "common/io_file.h" #include "common/io_file.h"
#include "core/devices/base_device.h"
namespace Core::FileSys { namespace Core::FileSys {
@ -55,15 +56,22 @@ struct DirEntry {
bool isFile; bool isFile;
}; };
enum class FileType {
Regular, // standard file
Directory,
Device,
};
struct File { struct File {
std::atomic_bool is_opened{}; std::atomic_bool is_opened{};
std::atomic_bool is_directory{}; std::atomic<FileType> type{FileType::Regular};
std::filesystem::path m_host_name; std::filesystem::path m_host_name;
std::string m_guest_name; std::string m_guest_name;
Common::FS::IOFile f; Common::FS::IOFile f;
std::vector<DirEntry> dirents; std::vector<DirEntry> dirents;
u32 dirents_index; u32 dirents_index;
std::mutex m_mutex; std::mutex m_mutex;
std::shared_ptr<Devices::BaseDevice> device; // only valid for type == Device
}; };
class HandleTable { class HandleTable {
@ -76,6 +84,8 @@ public:
File* GetFile(int d); File* GetFile(int d);
File* GetFile(const std::filesystem::path& host_name); File* GetFile(const std::filesystem::path& host_name);
void CreateStdHandles();
private: private:
std::vector<File*> m_files; std::vector<File*> m_files;
std::mutex m_mutex; std::mutex m_mutex;

View file

@ -11,6 +11,39 @@
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
#include "kernel.h" #include "kernel.h"
#include <map>
#include <ranges>
#include "core/devices/logger.h"
#include "core/devices/nop_device.h"
namespace D = Core::Devices;
using FactoryDevice = std::function<std::shared_ptr<D::BaseDevice>(u32, const char*, int, u16)>;
#define GET_DEVICE_FD(fd) \
[](u32, const char*, int, u16) { \
return Common::Singleton<Core::FileSys::HandleTable>::Instance()->GetFile(fd)->device; \
}
// prefix path, only dev devices
static std::map<std::string, FactoryDevice> available_device = {
// clang-format off
{"/dev/stdin", GET_DEVICE_FD(0)},
{"/dev/stdout", GET_DEVICE_FD(1)},
{"/dev/stderr", GET_DEVICE_FD(2)},
{"/dev/fd/0", GET_DEVICE_FD(0)},
{"/dev/fd/1", GET_DEVICE_FD(1)},
{"/dev/fd/2", GET_DEVICE_FD(2)},
{"/dev/deci_stdin", GET_DEVICE_FD(0)},
{"/dev/deci_stdout", GET_DEVICE_FD(1)},
{"/dev/deci_stderr", GET_DEVICE_FD(2)},
{"/dev/null", GET_DEVICE_FD(0)}, // fd0 (stdin) is a nop device
// clang-format on
};
namespace Libraries::Kernel { namespace Libraries::Kernel {
auto GetDirectoryEntries(const std::filesystem::path& path) { auto GetDirectoryEntries(const std::filesystem::path& path) {
@ -24,8 +57,8 @@ auto GetDirectoryEntries(const std::filesystem::path& path) {
return files; return files;
} }
int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) { int PS4_SYSV_ABI sceKernelOpen(const char* raw_path, int flags, u16 mode) {
LOG_INFO(Kernel_Fs, "path = {} flags = {:#x} mode = {}", path, flags, mode); LOG_INFO(Kernel_Fs, "path = {} flags = {:#x} mode = {}", raw_path, flags, mode);
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance(); auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance(); auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
@ -44,22 +77,35 @@ int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) {
bool direct = (flags & ORBIS_KERNEL_O_DIRECT) != 0; bool direct = (flags & ORBIS_KERNEL_O_DIRECT) != 0;
bool directory = (flags & ORBIS_KERNEL_O_DIRECTORY) != 0; bool directory = (flags & ORBIS_KERNEL_O_DIRECTORY) != 0;
if (std::string_view{path} == "/dev/console") { std::string_view path{raw_path};
if (path == "/dev/console") {
return 2000; return 2000;
} }
if (std::string_view{path} == "/dev/deci_tty6") { if (path == "/dev/deci_tty6") {
return 2001; return 2001;
} }
if (std::string_view{path} == "/dev/stdout") { if (path == "/dev/urandom") {
return 2002;
}
if (std::string_view{path} == "/dev/urandom") {
return 2003; return 2003;
} }
u32 handle = h->CreateHandle(); u32 handle = h->CreateHandle();
auto* file = h->GetFile(handle); auto* file = h->GetFile(handle);
if (path.starts_with("/dev/")) {
for (const auto& [prefix, factory] : available_device) {
if (path.starts_with(prefix)) {
file->is_opened = true;
file->type = Core::FileSys::FileType::Device;
file->m_guest_name = path;
file->device = factory(handle, path.data(), flags, mode);
return handle;
}
}
}
if (directory) { if (directory) {
file->is_directory = true; file->type = Core::FileSys::FileType::Directory;
file->m_guest_name = path; file->m_guest_name = path;
file->m_host_name = mnt->GetHostPath(file->m_guest_name); file->m_host_name = mnt->GetHostPath(file->m_guest_name);
if (!std::filesystem::is_directory(file->m_host_name)) { // directory doesn't exist if (!std::filesystem::is_directory(file->m_host_name)) { // directory doesn't exist
@ -135,11 +181,12 @@ int PS4_SYSV_ABI sceKernelClose(int d) {
if (file == nullptr) { if (file == nullptr) {
return ORBIS_KERNEL_ERROR_EBADF; return ORBIS_KERNEL_ERROR_EBADF;
} }
if (!file->is_directory) { if (file->type == Core::FileSys::FileType::Regular) {
file->f.Close(); file->f.Close();
} }
file->is_opened = false; file->is_opened = false;
LOG_INFO(Kernel_Fs, "Closing {}", file->m_guest_name); LOG_INFO(Kernel_Fs, "Closing {}", file->m_guest_name);
// FIXME: Lock file mutex before deleting it?
h->DeleteHandle(d); h->DeleteHandle(d);
return ORBIS_OK; return ORBIS_OK;
} }
@ -155,14 +202,6 @@ int PS4_SYSV_ABI posix_close(int d) {
} }
size_t PS4_SYSV_ABI sceKernelWrite(int d, const void* buf, size_t nbytes) { size_t PS4_SYSV_ABI sceKernelWrite(int d, const void* buf, size_t nbytes) {
if (d <= 2) { // stdin,stdout,stderr
char* str = strdup((const char*)buf);
if (str[nbytes - 1] == '\n')
str[nbytes - 1] = 0;
LOG_INFO(Tty, "{}", str);
free(str);
return nbytes;
}
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance(); auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(d); auto* file = h->GetFile(d);
if (file == nullptr) { if (file == nullptr) {
@ -170,6 +209,9 @@ size_t PS4_SYSV_ABI sceKernelWrite(int d, const void* buf, size_t nbytes) {
} }
std::scoped_lock lk{file->m_mutex}; std::scoped_lock lk{file->m_mutex};
if (file->type == Core::FileSys::FileType::Device) {
return file->device->write(buf, nbytes);
}
return file->f.WriteRaw<u8>(buf, nbytes); return file->f.WriteRaw<u8>(buf, nbytes);
} }
@ -207,17 +249,63 @@ int PS4_SYSV_ABI sceKernelUnlink(const char* path) {
size_t PS4_SYSV_ABI _readv(int d, const SceKernelIovec* iov, int iovcnt) { size_t PS4_SYSV_ABI _readv(int d, const SceKernelIovec* iov, int iovcnt) {
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance(); auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(d); auto* file = h->GetFile(d);
size_t total_read = 0; if (file == nullptr) {
return ORBIS_KERNEL_ERROR_EBADF;
}
std::scoped_lock lk{file->m_mutex}; std::scoped_lock lk{file->m_mutex};
if (file->type == Core::FileSys::FileType::Device) {
int r = file->device->readv(iov, iovcnt);
if (r < 0) {
ErrSceToPosix(r);
return -1;
}
return r;
}
size_t total_read = 0;
for (int i = 0; i < iovcnt; i++) { for (int i = 0; i < iovcnt; i++) {
total_read += file->f.ReadRaw<u8>(iov[i].iov_base, iov[i].iov_len); total_read += file->f.ReadRaw<u8>(iov[i].iov_base, iov[i].iov_len);
} }
return total_read; return total_read;
} }
size_t PS4_SYSV_ABI _writev(int fd, const SceKernelIovec* iov, int iovcn) {
if (fd == 1) {
size_t total_written = 0;
for (int i = 0; i < iovcn; i++) {
total_written += ::fwrite(iov[i].iov_base, 1, iov[i].iov_len, stdout);
}
return total_written;
}
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(fd);
if (file == nullptr) {
return ORBIS_KERNEL_ERROR_EBADF;
}
std::scoped_lock lk{file->m_mutex};
if (file->type == Core::FileSys::FileType::Device) {
return file->device->writev(iov, iovcn);
}
size_t total_written = 0;
for (int i = 0; i < iovcn; i++) {
total_written += file->f.WriteRaw<u8>(iov[i].iov_base, iov[i].iov_len);
}
return total_written;
}
s64 PS4_SYSV_ABI sceKernelLseek(int d, s64 offset, int whence) { s64 PS4_SYSV_ABI sceKernelLseek(int d, s64 offset, int whence) {
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance(); auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(d); auto* file = h->GetFile(d);
if (file == nullptr) {
return ORBIS_KERNEL_ERROR_EBADF;
}
std::scoped_lock lk{file->m_mutex};
if (file->type == Core::FileSys::FileType::Device) {
return file->device->lseek(offset, whence);
}
Common::FS::SeekOrigin origin{}; Common::FS::SeekOrigin origin{};
if (whence == 0) { if (whence == 0) {
@ -228,7 +316,6 @@ s64 PS4_SYSV_ABI sceKernelLseek(int d, s64 offset, int whence) {
origin = Common::FS::SeekOrigin::End; origin = Common::FS::SeekOrigin::End;
} }
std::scoped_lock lk{file->m_mutex};
if (!file->f.Seek(offset, origin)) { if (!file->f.Seek(offset, origin)) {
LOG_CRITICAL(Kernel_Fs, "sceKernelLseek: failed to seek"); LOG_CRITICAL(Kernel_Fs, "sceKernelLseek: failed to seek");
return ORBIS_KERNEL_ERROR_EINVAL; return ORBIS_KERNEL_ERROR_EINVAL;
@ -261,6 +348,9 @@ s64 PS4_SYSV_ABI sceKernelRead(int d, void* buf, size_t nbytes) {
} }
std::scoped_lock lk{file->m_mutex}; std::scoped_lock lk{file->m_mutex};
if (file->type == Core::FileSys::FileType::Device) {
return file->device->read(buf, nbytes);
}
return file->f.ReadRaw<u8>(buf, nbytes); return file->f.ReadRaw<u8>(buf, nbytes);
} }
@ -409,7 +499,13 @@ int PS4_SYSV_ABI posix_stat(const char* path, OrbisKernelStat* sb) {
int PS4_SYSV_ABI sceKernelCheckReachability(const char* path) { int PS4_SYSV_ABI sceKernelCheckReachability(const char* path) {
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance(); auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
const auto path_name = mnt->GetHostPath(path); std::string_view guest_path{path};
for (const auto& prefix : available_device | std::views::keys) {
if (guest_path.starts_with(prefix)) {
return ORBIS_OK;
}
}
const auto path_name = mnt->GetHostPath(guest_path);
if (!std::filesystem::exists(path_name)) { if (!std::filesystem::exists(path_name)) {
return ORBIS_KERNEL_ERROR_ENOENT; return ORBIS_KERNEL_ERROR_ENOENT;
} }
@ -431,6 +527,10 @@ s64 PS4_SYSV_ABI sceKernelPreadv(int d, SceKernelIovec* iov, int iovcnt, s64 off
} }
std::scoped_lock lk{file->m_mutex}; std::scoped_lock lk{file->m_mutex};
if (file->type == Core::FileSys::FileType::Device) {
return file->device->preadv(iov, iovcnt, offset);
}
const s64 pos = file->f.Tell(); const s64 pos = file->f.Tell();
SCOPE_EXIT { SCOPE_EXIT {
file->f.Seek(pos); file->f.Seek(pos);
@ -466,18 +566,25 @@ int PS4_SYSV_ABI sceKernelFStat(int fd, OrbisKernelStat* sb) {
} }
std::memset(sb, 0, sizeof(OrbisKernelStat)); std::memset(sb, 0, sizeof(OrbisKernelStat));
if (file->is_directory) { switch (file->type) {
sb->st_mode = 0000777u | 0040000u; case Core::FileSys::FileType::Device:
sb->st_size = 0; return file->device->fstat(sb);
sb->st_blksize = 512; case Core::FileSys::FileType::Regular:
sb->st_blocks = 0;
// TODO incomplete
} else {
sb->st_mode = 0000777u | 0100000u; sb->st_mode = 0000777u | 0100000u;
sb->st_size = file->f.GetSize(); sb->st_size = file->f.GetSize();
sb->st_blksize = 512; sb->st_blksize = 512;
sb->st_blocks = (sb->st_size + 511) / 512; sb->st_blocks = (sb->st_size + 511) / 512;
// TODO incomplete // TODO incomplete
break;
case Core::FileSys::FileType::Directory:
sb->st_mode = 0000777u | 0040000u;
sb->st_size = 0;
sb->st_blksize = 512;
sb->st_blocks = 0;
// TODO incomplete
break;
default:
UNREACHABLE();
} }
return ORBIS_OK; return ORBIS_OK;
} }
@ -495,6 +602,13 @@ int PS4_SYSV_ABI posix_fstat(int fd, OrbisKernelStat* sb) {
s32 PS4_SYSV_ABI sceKernelFsync(int fd) { s32 PS4_SYSV_ABI sceKernelFsync(int fd) {
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance(); auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(fd); auto* file = h->GetFile(fd);
if (file == nullptr) {
return ORBIS_KERNEL_ERROR_EBADF;
}
if (file->type == Core::FileSys::FileType::Device) {
return file->device->fsync();
}
file->f.Flush(); file->f.Flush();
return ORBIS_OK; return ORBIS_OK;
} }
@ -517,6 +631,10 @@ int PS4_SYSV_ABI sceKernelFtruncate(int fd, s64 length) {
return ORBIS_KERNEL_ERROR_EBADF; return ORBIS_KERNEL_ERROR_EBADF;
} }
if (file->type == Core::FileSys::FileType::Device) {
return file->device->ftruncate(length);
}
if (file->m_host_name.empty()) { if (file->m_host_name.empty()) {
return ORBIS_KERNEL_ERROR_EACCES; return ORBIS_KERNEL_ERROR_EACCES;
} }
@ -538,10 +656,15 @@ static int GetDents(int fd, char* buf, int nbytes, s64* basep) {
if (file == nullptr) { if (file == nullptr) {
return ORBIS_KERNEL_ERROR_EBADF; return ORBIS_KERNEL_ERROR_EBADF;
} }
if (file->type != Core::FileSys::FileType::Device) {
return file->device->getdents(buf, nbytes, basep);
}
if (file->dirents_index == file->dirents.size()) { if (file->dirents_index == file->dirents.size()) {
return ORBIS_OK; return ORBIS_OK;
} }
if (!file->is_directory || nbytes < 512 || file->dirents_index > file->dirents.size()) { if (file->type != Core::FileSys::FileType::Directory || nbytes < 512 ||
file->dirents_index > file->dirents.size()) {
return ORBIS_KERNEL_ERROR_EINVAL; return ORBIS_KERNEL_ERROR_EINVAL;
} }
const auto& entry = file->dirents.at(file->dirents_index++); const auto& entry = file->dirents.at(file->dirents_index++);
@ -586,6 +709,10 @@ s64 PS4_SYSV_ABI sceKernelPwrite(int d, void* buf, size_t nbytes, s64 offset) {
} }
std::scoped_lock lk{file->m_mutex}; std::scoped_lock lk{file->m_mutex};
if (file->type == Core::FileSys::FileType::Device) {
return file->device->pwrite(buf, nbytes, offset);
}
const s64 pos = file->f.Tell(); const s64 pos = file->f.Tell();
SCOPE_EXIT { SCOPE_EXIT {
file->f.Seek(pos); file->f.Seek(pos);
@ -637,6 +764,7 @@ void RegisterFileSystem(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("4wSze92BhLI", "libkernel", 1, "libkernel", 1, 1, sceKernelWrite); LIB_FUNCTION("4wSze92BhLI", "libkernel", 1, "libkernel", 1, 1, sceKernelWrite);
LIB_FUNCTION("+WRlkKjZvag", "libkernel", 1, "libkernel", 1, 1, _readv); LIB_FUNCTION("+WRlkKjZvag", "libkernel", 1, "libkernel", 1, 1, _readv);
LIB_FUNCTION("YSHRBRLn2pI", "libkernel", 1, "libkernel", 1, 1, _writev);
LIB_FUNCTION("Oy6IpwgtYOk", "libkernel", 1, "libkernel", 1, 1, posix_lseek); LIB_FUNCTION("Oy6IpwgtYOk", "libkernel", 1, "libkernel", 1, 1, posix_lseek);
LIB_FUNCTION("Oy6IpwgtYOk", "libScePosix", 1, "libkernel", 1, 1, posix_lseek); LIB_FUNCTION("Oy6IpwgtYOk", "libScePosix", 1, "libkernel", 1, 1, posix_lseek);
LIB_FUNCTION("oib76F-12fk", "libkernel", 1, "libkernel", 1, 1, sceKernelLseek); LIB_FUNCTION("oib76F-12fk", "libkernel", 1, "libkernel", 1, 1, sceKernelLseek);

View file

@ -9,6 +9,9 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/polyfill_thread.h" #include "common/polyfill_thread.h"
#include "common/thread.h" #include "common/thread.h"
#include "common/va_ctx.h"
#include "core/file_sys/fs.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/equeue.h" #include "core/libraries/kernel/equeue.h"
#include "core/libraries/kernel/file_system.h" #include "core/libraries/kernel/file_system.h"
#include "core/libraries/kernel/kernel.h" #include "core/libraries/kernel/kernel.h"
@ -24,6 +27,7 @@
#ifdef _WIN64 #ifdef _WIN64
#include <Rpc.h> #include <Rpc.h>
#endif #endif
#include <common/singleton.h>
namespace Libraries::Kernel { namespace Libraries::Kernel {
@ -65,19 +69,6 @@ static PS4_SYSV_ABI void stack_chk_fail() {
UNREACHABLE(); UNREACHABLE();
} }
struct iovec {
void* iov_base; /* Base address. */
size_t iov_len; /* Length. */
};
size_t PS4_SYSV_ABI _writev(int fd, const struct iovec* iov, int iovcn) {
size_t total_written = 0;
for (int i = 0; i < iovcn; i++) {
total_written += ::fwrite(iov[i].iov_base, 1, iov[i].iov_len, stdout);
}
return total_written;
}
static thread_local int g_posix_errno = 0; static thread_local int g_posix_errno = 0;
int* PS4_SYSV_ABI __Error() { int* PS4_SYSV_ABI __Error() {
@ -142,24 +133,33 @@ void PS4_SYSV_ABI sceLibcHeapGetTraceInfo(HeapInfoInfo* info) {
} }
s64 PS4_SYSV_ABI ps4__write(int d, const char* buf, std::size_t nbytes) { s64 PS4_SYSV_ABI ps4__write(int d, const char* buf, std::size_t nbytes) {
if (d <= 2) { // stdin,stdout,stderr auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
std::string_view str{buf}; auto* file = h->GetFile(d);
if (str[nbytes - 1] == '\n') { if (file == nullptr) {
str = str.substr(0, nbytes - 1); return ORBIS_KERNEL_ERROR_EBADF;
}
LOG_INFO(Tty, "{}", str);
return nbytes;
} }
LOG_ERROR(Kernel, "(STUBBED) called d = {} nbytes = {} ", d, nbytes); std::scoped_lock lk{file->m_mutex};
UNREACHABLE(); if (file->type == Core::FileSys::FileType::Device) {
return ORBIS_OK; return file->device->write(buf, nbytes);
}
return file->f.WriteRaw<u8>(buf, nbytes);
} }
s64 PS4_SYSV_ABI ps4__read(int d, void* buf, u64 nbytes) { s64 PS4_SYSV_ABI ps4__read(int d, void* buf, u64 nbytes) {
ASSERT_MSG(d == 0, "d is not 0!"); if (d == 0) {
return static_cast<s64>(
return static_cast<s64>( strlen(std::fgets(static_cast<char*>(buf), static_cast<int>(nbytes), stdin)));
strlen(std::fgets(static_cast<char*>(buf), static_cast<int>(nbytes), stdin))); }
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(d);
if (file == nullptr) {
return ORBIS_KERNEL_ERROR_EBADF;
}
std::scoped_lock lk{file->m_mutex};
if (file->type == Core::FileSys::FileType::Device) {
return file->device->read(buf, nbytes);
}
return file->f.ReadRaw<u8>(buf, nbytes);
} }
struct OrbisKernelUuid { struct OrbisKernelUuid {
@ -189,6 +189,29 @@ int PS4_SYSV_ABI sceKernelUuidCreate(OrbisKernelUuid* orbisUuid) {
return 0; return 0;
} }
int PS4_SYSV_ABI kernel_ioctl(int fd, u64 cmd, VA_ARGS) {
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(fd);
if (file == nullptr) {
LOG_INFO(Lib_Kernel, "ioctl: fd = {:X} cmd = {:X} file == nullptr", fd, cmd);
g_posix_errno = POSIX_EBADF;
return -1;
}
if (file->type != Core::FileSys::FileType::Device) {
LOG_WARNING(Lib_Kernel, "ioctl: fd = {:X} cmd = {:X} file->type != Device", fd, cmd);
g_posix_errno = ENOTTY;
return -1;
}
VA_CTX(ctx);
int result = file->device->ioctl(cmd, &ctx);
LOG_TRACE(Lib_Kernel, "ioctl: fd = {:X} cmd = {:X} result = {}", fd, cmd, result);
if (result < 0) {
ErrSceToPosix(result);
return -1;
}
return result;
}
const char* PS4_SYSV_ABI sceKernelGetFsSandboxRandomWord() { const char* PS4_SYSV_ABI sceKernelGetFsSandboxRandomWord() {
const char* path = "sys"; const char* path = "sys";
return path; return path;
@ -219,13 +242,13 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
Libraries::Kernel::RegisterException(sym); Libraries::Kernel::RegisterException(sym);
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard); LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard);
LIB_FUNCTION("PfccT7qURYE", "libkernel", 1, "libkernel", 1, 1, kernel_ioctl);
LIB_FUNCTION("JGfTMBOdUJo", "libkernel", 1, "libkernel", 1, 1, sceKernelGetFsSandboxRandomWord); LIB_FUNCTION("JGfTMBOdUJo", "libkernel", 1, "libkernel", 1, 1, sceKernelGetFsSandboxRandomWord);
LIB_FUNCTION("XVL8So3QJUk", "libkernel", 1, "libkernel", 1, 1, posix_connect); LIB_FUNCTION("XVL8So3QJUk", "libkernel", 1, "libkernel", 1, 1, posix_connect);
LIB_FUNCTION("6xVpy0Fdq+I", "libkernel", 1, "libkernel", 1, 1, _sigprocmask); LIB_FUNCTION("6xVpy0Fdq+I", "libkernel", 1, "libkernel", 1, 1, _sigprocmask);
LIB_FUNCTION("Xjoosiw+XPI", "libkernel", 1, "libkernel", 1, 1, sceKernelUuidCreate); LIB_FUNCTION("Xjoosiw+XPI", "libkernel", 1, "libkernel", 1, 1, sceKernelUuidCreate);
LIB_FUNCTION("Ou3iL1abvng", "libkernel", 1, "libkernel", 1, 1, stack_chk_fail); LIB_FUNCTION("Ou3iL1abvng", "libkernel", 1, "libkernel", 1, 1, stack_chk_fail);
LIB_FUNCTION("9BcDykPmo1I", "libkernel", 1, "libkernel", 1, 1, __Error); LIB_FUNCTION("9BcDykPmo1I", "libkernel", 1, "libkernel", 1, 1, __Error);
LIB_FUNCTION("YSHRBRLn2pI", "libkernel", 1, "libkernel", 1, 1, _writev);
LIB_FUNCTION("DRuBt2pvICk", "libkernel", 1, "libkernel", 1, 1, ps4__read); LIB_FUNCTION("DRuBt2pvICk", "libkernel", 1, "libkernel", 1, 1, ps4__read);
LIB_FUNCTION("k+AXqu2-eBc", "libkernel", 1, "libkernel", 1, 1, posix_getpagesize); LIB_FUNCTION("k+AXqu2-eBc", "libkernel", 1, "libkernel", 1, 1, posix_getpagesize);
LIB_FUNCTION("k+AXqu2-eBc", "libScePosix", 1, "libkernel", 1, 1, posix_getpagesize); LIB_FUNCTION("k+AXqu2-eBc", "libScePosix", 1, "libkernel", 1, 1, posix_getpagesize);

View file

@ -20,7 +20,7 @@ int PS4_SYSV_ABI sceKernelIsNeoMode() {
int PS4_SYSV_ABI sceKernelGetCompiledSdkVersion(int* ver) { int PS4_SYSV_ABI sceKernelGetCompiledSdkVersion(int* ver) {
int version = Common::ElfInfo::Instance().RawFirmwareVer(); int version = Common::ElfInfo::Instance().RawFirmwareVer();
*ver = version; *ver = version;
return (version > 0) ? ORBIS_OK : ORBIS_KERNEL_ERROR_EINVAL; return (version >= 0) ? ORBIS_OK : ORBIS_KERNEL_ERROR_EINVAL;
} }
int PS4_SYSV_ABI sceKernelGetCpumode() { int PS4_SYSV_ABI sceKernelGetCpumode() {

View file

@ -75,6 +75,9 @@ Emulator::Emulator() {
LOG_INFO(Config, "Vulkan rdocMarkersEnable: {}", Config::vkMarkersEnabled()); LOG_INFO(Config, "Vulkan rdocMarkersEnable: {}", Config::vkMarkersEnabled());
LOG_INFO(Config, "Vulkan crashDiagnostics: {}", Config::vkCrashDiagnosticEnabled()); LOG_INFO(Config, "Vulkan crashDiagnostics: {}", Config::vkCrashDiagnosticEnabled());
// Create stdin/stdout/stderr
Common::Singleton<FileSys::HandleTable>::Instance()->CreateStdHandles();
// Defer until after logging is initialized. // Defer until after logging is initialized.
memory = Core::Memory::Instance(); memory = Core::Memory::Instance();
controller = Common::Singleton<Input::GameController>::Instance(); controller = Common::Singleton<Input::GameController>::Instance();