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

@ -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