Skip to content

Commit

Permalink
add stdin/out/err as virtual devices
Browse files Browse the repository at this point in the history
  • Loading branch information
viniciuslrangel committed Nov 29, 2024
1 parent b9c63b4 commit dc6d17d
Show file tree
Hide file tree
Showing 10 changed files with 219 additions and 28 deletions.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,10 @@ set(CORE src/core/aerolib/stubs.cpp
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/pkg.cpp
src/core/file_format/pkg.h
Expand Down
75 changes: 75 additions & 0 deletions src/core/devices/logger.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// 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 {

BaseDevice* Logger::Create(u32 handle, const char* raw_path, int, u16) {
std::string path{raw_path};
// remove /dev/ prefix
if (path.starts_with("/dev/")) {
path = path.substr(5);
}
bool is_err = path == "stderr";
return new Logger(handle, path, is_err);
}

Logger::Logger(u32 handle, std::string prefix, bool is_err)
: handle(handle), 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
40 changes: 40 additions & 0 deletions src/core/devices/logger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// 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 {
u32 handle;
std::string prefix;
bool is_err;

std::recursive_mutex mtx;
std::vector<char> buffer;

public:
static BaseDevice* Create(u32 handle, const char*, int, u16);

explicit Logger(u32 handle, 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
59 changes: 59 additions & 0 deletions src/core/devices/nop_device.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// 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:
static BaseDevice* Create(u32 handle, const char*, int, u16) {
return new NopDevice(handle);
};

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
29 changes: 22 additions & 7 deletions src/core/file_sys/fs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
#include <algorithm>
#include "common/config.h"
#include "common/string_util.h"
#include "core/devices/logger.h"
#include "core/devices/nop_device.h"
#include "core/file_sys/fs.h"

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,
bool read_only) {
std::scoped_lock lock{m_mutex};
Expand Down Expand Up @@ -142,23 +142,23 @@ int HandleTable::CreateHandle() {
for (int index = 0; index < existingFilesNum; index++) {
if (m_files.at(index) == nullptr) {
m_files[index] = file;
return index + RESERVED_HANDLES;
return index;
}
}

m_files.push_back(file);
return m_files.size() + RESERVED_HANDLES - 1;
return m_files.size() - 1;
}

void HandleTable::DeleteHandle(int d) {
std::scoped_lock lock{m_mutex};
delete m_files.at(d - RESERVED_HANDLES);
m_files[d - RESERVED_HANDLES] = nullptr;
delete m_files.at(d);
m_files[d] = nullptr;
}

File* HandleTable::GetFile(int d) {
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) {
Expand All @@ -170,4 +170,19 @@ File* HandleTable::GetFile(const std::filesystem::path& host_name) {
return nullptr;
}

void HandleTable::CreateStdHandles() {
auto setup = [this](auto Ctor, const char* path) {
int fd = CreateHandle();
auto* file = GetFile(fd);
file->is_opened = true;
file->type = FileType::Device;
file->m_guest_name = path;
file->device = std::unique_ptr<Devices::BaseDevice>{Ctor(fd, path, 0, 0)};
};
// order matters
setup(Devices::NopDevice::Create, "/dev/stdin"); // stdin
setup(Devices::Logger::Create, "/dev/stdout"); // stdout
setup(Devices::Logger::Create, "/dev/stderr"); // stderr
}

} // namespace Core::FileSys
2 changes: 2 additions & 0 deletions src/core/file_sys/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ class HandleTable {
File* GetFile(int d);
File* GetFile(const std::filesystem::path& host_name);

void CreateStdHandles();

private:
std::vector<File*> m_files;
std::mutex m_mutex;
Expand Down
23 changes: 10 additions & 13 deletions src/core/libraries/kernel/file_system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,18 @@
#include <map>
#include <ranges>

using FactoryDevice = std::function<Core::Devices::BaseDevice*(u32, const char*, int, u16)>;
#include "core/devices/logger.h"
#include "core/devices/nop_device.h"

namespace D = Core::Devices;
using FactoryDevice = std::function<D::BaseDevice*(u32, const char*, int, u16)>;

// prefix path
static std::map<std::string, FactoryDevice> available_device = {};
static std::map<std::string, FactoryDevice> available_device = {
{"/dev/stdin", D::NopDevice::Create},
{"/dev/stdout", D::Logger::Create},
{"/dev/stderr", D::Logger::Create},
};

namespace Libraries::Kernel {

Expand Down Expand Up @@ -60,9 +68,6 @@ int PS4_SYSV_ABI sceKernelOpen(const char* raw_path, int flags, u16 mode) {
if (path == "/dev/deci_tty6") {
return 2001;
}
if (path == "/dev/stdout") {
return 2002;
}
if (path == "/dev/urandom") {
return 2003;
}
Expand Down Expand Up @@ -179,14 +184,6 @@ int PS4_SYSV_ABI posix_close(int d) {
}

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* file = h->GetFile(d);
if (file == nullptr) {
Expand Down
8 changes: 0 additions & 8 deletions src/core/libraries/kernel/kernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,6 @@ void PS4_SYSV_ABI sceLibcHeapGetTraceInfo(HeapInfoInfo* info) {
}

s64 PS4_SYSV_ABI ps4__write(int d, const char* buf, std::size_t nbytes) {
if (d <= 2) { // stdin,stdout,stderr
std::string_view str{buf};
if (str[nbytes - 1] == '\n') {
str = str.substr(0, nbytes - 1);
}
LOG_INFO(Tty, "{}", str);
return nbytes;
}
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(d);
if (file == nullptr) {
Expand Down
3 changes: 3 additions & 0 deletions src/emulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ Emulator::Emulator() {
LOG_INFO(Config, "Vulkan rdocMarkersEnable: {}", Config::vkMarkersEnabled());
LOG_INFO(Config, "Vulkan crashDiagnostics: {}", Config::vkCrashDiagnosticEnabled());

// Create stdin/stdout/stderr
Common::Singleton<FileSys::HandleTable>::Instance()->CreateStdHandles();

// Defer until after logging is initialized.
memory = Core::Memory::Instance();
controller = Common::Singleton<Input::GameController>::Instance();
Expand Down
4 changes: 4 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
#endif

int main(int argc, char* argv[]) {
while (!IsDebuggerPresent()) {
Sleep(100);
}

#ifdef _WIN32
SetConsoleOutputCP(CP_UTF8);
#endif
Expand Down

0 comments on commit dc6d17d

Please sign in to comment.