From 89db63ca46bc4abe438a139ca16e6112df757bd8 Mon Sep 17 00:00:00 2001 From: DH Date: Sun, 30 Jul 2023 14:56:25 +0300 Subject: [PATCH] [rpcsx-os] implement blockpool device --- orbis-kernel/include/orbis/KernelContext.hpp | 1 + orbis-kernel/include/orbis/sys/sysproto.hpp | 8 +- .../include/orbis/thread/ProcessOps.hpp | 4 + orbis-kernel/src/sys/sys_sce.cpp | 24 +++- rpcsx-os/CMakeLists.txt | 1 + rpcsx-os/io-devices.hpp | 1 + rpcsx-os/iodev/blockpool.cpp | 117 ++++++++++++++++++ rpcsx-os/iodev/blockpool.hpp | 21 ++++ rpcsx-os/main.cpp | 1 + rpcsx-os/ops.cpp | 31 +++++ 10 files changed, 203 insertions(+), 6 deletions(-) create mode 100644 rpcsx-os/iodev/blockpool.cpp create mode 100644 rpcsx-os/iodev/blockpool.hpp diff --git a/orbis-kernel/include/orbis/KernelContext.hpp b/orbis-kernel/include/orbis/KernelContext.hpp index 6d88698fc..1a554405e 100644 --- a/orbis-kernel/include/orbis/KernelContext.hpp +++ b/orbis-kernel/include/orbis/KernelContext.hpp @@ -149,6 +149,7 @@ public: Ref shmDevice; Ref dmemDevice; + Ref blockpoolDevice; private: mutable pthread_mutex_t m_heap_mtx; diff --git a/orbis-kernel/include/orbis/sys/sysproto.hpp b/orbis-kernel/include/orbis/sys/sysproto.hpp index ebe0d4452..1c3dbe5de 100644 --- a/orbis-kernel/include/orbis/sys/sysproto.hpp +++ b/orbis-kernel/include/orbis/sys/sysproto.hpp @@ -759,9 +759,11 @@ SysResult sys_dynlib_get_obj_member(Thread *thread, SceKernelModule handle, SysResult sys_budget_get_ptype_of_budget(Thread *thread /* TODO */); SysResult sys_prepare_to_resume_process(Thread *thread /* TODO */); SysResult sys_process_terminate(Thread *thread /* TODO */); -SysResult sys_blockpool_open(Thread *thread /* TODO */); -SysResult sys_blockpool_map(Thread *thread /* TODO */); -SysResult sys_blockpool_unmap(Thread *thread /* TODO */); +SysResult sys_blockpool_open(Thread *thread); +SysResult sys_blockpool_map(Thread *thread, caddr_t addr, size_t len, sint prot, + sint flags); +SysResult sys_blockpool_unmap(Thread *thread, caddr_t addr, size_t len, + sint flags); SysResult sys_dynlib_get_info_for_libdbg(Thread *thread /* TODO */); SysResult sys_blockpool_batch(Thread *thread /* TODO */); SysResult sys_fdatasync(Thread *thread /* TODO */); diff --git a/orbis-kernel/include/orbis/thread/ProcessOps.hpp b/orbis-kernel/include/orbis/thread/ProcessOps.hpp index 6113cc0f8..71ebb5aef 100644 --- a/orbis-kernel/include/orbis/thread/ProcessOps.hpp +++ b/orbis-kernel/include/orbis/thread/ProcessOps.hpp @@ -37,6 +37,10 @@ struct ProcessOps { Ref *file); SysResult (*shm_open)(Thread *thread, const char *path, sint flags, sint mode, Ref *file); + SysResult (*blockpool_open)(Thread *thread, Ref *file); + SysResult (*blockpool_map)(Thread *thread, caddr_t addr, size_t len, + sint prot, sint flags); + SysResult (*blockpool_unmap)(Thread *thread, caddr_t addr, size_t len); SysResult (*socket)(Thread *thread, ptr name, sint domain, sint type, sint protocol, Ref *file); SysResult (*shm_unlink)(Thread *thread, const char *path); diff --git a/orbis-kernel/src/sys/sys_sce.cpp b/orbis-kernel/src/sys/sys_sce.cpp index d8f402260..5bb22a89f 100644 --- a/orbis-kernel/src/sys/sys_sce.cpp +++ b/orbis-kernel/src/sys/sys_sce.cpp @@ -1217,13 +1217,31 @@ orbis::sys_prepare_to_resume_process(Thread *thread /* TODO */) { orbis::SysResult orbis::sys_process_terminate(Thread *thread /* TODO */) { return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_blockpool_open(Thread *thread /* TODO */) { +orbis::SysResult orbis::sys_blockpool_open(Thread *thread) { + if (auto blockpool_open = thread->tproc->ops->blockpool_open) { + Ref file; + auto result = blockpool_open(thread, &file); + if (result.isError()) { + return result; + } + + thread->retval[0] = thread->tproc->fileDescriptors.insert(file); + return {}; + } return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_blockpool_map(Thread *thread /* TODO */) { +orbis::SysResult orbis::sys_blockpool_map(Thread *thread, caddr_t addr, + size_t len, sint prot, sint flags) { + if (auto blockpool_map = thread->tproc->ops->blockpool_map) { + return blockpool_map(thread, addr, len, prot, flags); + } return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_blockpool_unmap(Thread *thread /* TODO */) { +orbis::SysResult orbis::sys_blockpool_unmap(Thread *thread, caddr_t addr, + size_t len, sint flags) { + if (auto blockpool_unmap = thread->tproc->ops->blockpool_unmap) { + return blockpool_unmap(thread, addr, len); + } return ErrorCode::NOSYS; } orbis::SysResult diff --git a/rpcsx-os/CMakeLists.txt b/rpcsx-os/CMakeLists.txt index 87f497f70..a79f94f92 100644 --- a/rpcsx-os/CMakeLists.txt +++ b/rpcsx-os/CMakeLists.txt @@ -4,6 +4,7 @@ add_library(orbis::kernel::config ALIAS standalone-config) add_executable(rpcsx-os iodev/ajm.cpp + iodev/blockpool.cpp iodev/dce.cpp iodev/dipsw.cpp iodev/dmem.cpp diff --git a/rpcsx-os/io-devices.hpp b/rpcsx-os/io-devices.hpp index ec27c863a..437d0b1f1 100644 --- a/rpcsx-os/io-devices.hpp +++ b/rpcsx-os/io-devices.hpp @@ -17,3 +17,4 @@ IoDevice *createRngCharacterDevice(); IoDevice *createAjmCharacterDevice(); IoDevice *createSblSrvCharacterDevice(); IoDevice *createShmDevice(); +IoDevice *createBlockPoolDevice(); diff --git a/rpcsx-os/iodev/blockpool.cpp b/rpcsx-os/iodev/blockpool.cpp new file mode 100644 index 000000000..80b5067e9 --- /dev/null +++ b/rpcsx-os/iodev/blockpool.cpp @@ -0,0 +1,117 @@ +#include "blockpool.hpp" +#include "dmem.hpp" +#include "io-device.hpp" +#include "orbis/KernelAllocator.hpp" +#include "orbis/KernelContext.hpp" +#include "orbis/file.hpp" +#include "orbis/thread/Thread.hpp" +#include "orbis/utils/Logs.hpp" +#include "vm.hpp" +#include +#include + +struct BlockPoolFile : public orbis::File {}; + +static orbis::ErrorCode blockpool_ioctl(orbis::File *file, + std::uint64_t request, void *argp, + orbis::Thread *thread) { + auto blockPool = static_cast(file->device.get()); + std::lock_guard lock(blockPool->mtx); + + switch (request) { + case 0xc020a801: { + auto dmem = static_cast(orbis::g_context.dmemDevice.get()); + std::lock_guard lock(dmem->mtx); + + struct Args { + std::uint64_t len; + std::uint64_t searchStart; + std::uint64_t searchEnd; + std::uint32_t flags; + }; + auto args = reinterpret_cast(argp); + ORBIS_LOG_TODO("blockpool expand", args->len, args->searchStart, + args->searchEnd, args->flags); + + std::uint64_t start = args->searchStart; + std::uint64_t len = std::min(args->searchEnd - start, args->len); + if (dmem->nextOffset > args->searchEnd) { + ORBIS_LOG_TODO("blockpool out of allocation", args->len, + args->searchStart, args->searchEnd, args->flags); + return orbis::ErrorCode::INVAL; + } + + start = std::max(dmem->nextOffset, start); + auto end = std::min(start + len, args->searchEnd); + dmem->nextOffset = end; + args->searchStart = start; + + blockPool->len += end - start; + return {}; + } + } + + ORBIS_LOG_FATAL("Unhandled blockpool ioctl", request); + thread->where(); + return {}; +} + +static orbis::ErrorCode blockpool_mmap(orbis::File *file, void **address, + std::uint64_t size, std::int32_t prot, + std::int32_t flags, std::int64_t offset, + orbis::Thread *thread) { + auto blockPool = static_cast(file->device.get()); + std::lock_guard lock(blockPool->mtx); + ORBIS_LOG_FATAL("blockpool mmap", *address, size, offset, blockPool->len); + size = std::min( + 0x1000000, size); // FIXME: hack, investigate why we report so many memory + size = std::min(blockPool->len, size); + auto result = rx::vm::map(*address, size, prot, flags); + + if (result == (void *)-1) { + return orbis::ErrorCode::INVAL; // TODO + } + + blockPool->len -= size; + *address = result; + return {}; +} + +static const orbis::FileOps ops = { + .ioctl = blockpool_ioctl, + .mmap = blockpool_mmap, +}; + +orbis::ErrorCode BlockPoolDevice::open(orbis::Ref *file, + const char *path, std::uint32_t flags, + std::uint32_t mode, + orbis::Thread *thread) { + auto newFile = orbis::knew(); + newFile->device = this; + newFile->ops = &ops; + *file = newFile; + return {}; +} + +orbis::ErrorCode BlockPoolDevice::map(void **address, std::uint64_t len, + std::int32_t prot, std::int32_t flags, + orbis::Thread *thread) { + ORBIS_LOG_FATAL("blockpool device map", *address, len); + auto result = rx::vm::map(*address, len, prot, flags); + + if (result == (void *)-1) { + return orbis::ErrorCode::NOMEM; + } + + *address = result; + return {}; +} +orbis::ErrorCode BlockPoolDevice::unmap(void *address, std::uint64_t len, + orbis::Thread *thread) { + ORBIS_LOG_FATAL("blockpool device unmap", address, len); + if (rx::vm::unmap(address, len)) { + return {}; + } + return orbis::ErrorCode::INVAL; +} +IoDevice *createBlockPoolDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/blockpool.hpp b/rpcsx-os/iodev/blockpool.hpp new file mode 100644 index 000000000..4b428ea79 --- /dev/null +++ b/rpcsx-os/iodev/blockpool.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "io-device.hpp" +#include "orbis/error/ErrorCode.hpp" +#include "orbis/file.hpp" +#include "orbis/utils/Rc.hpp" +#include "orbis/utils/SharedMutex.hpp" +#include + +struct BlockPoolDevice : public IoDevice { + orbis::shared_mutex mtx; + std::uint64_t len = 0; + + orbis::ErrorCode open(orbis::Ref *file, const char *path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread *thread) override; + orbis::ErrorCode map(void **address, std::uint64_t len, std::int32_t prot, + std::int32_t flags, orbis::Thread *thread); + orbis::ErrorCode unmap(void *address, std::uint64_t len, + orbis::Thread *thread); +}; diff --git a/rpcsx-os/main.cpp b/rpcsx-os/main.cpp index b9c397cb9..f69cb679e 100644 --- a/rpcsx-os/main.cpp +++ b/rpcsx-os/main.cpp @@ -342,6 +342,7 @@ static int ps4Exec(orbis::Thread *mainThread, mainThread->tproc->fileDescriptors.insert(stderrFile); orbis::g_context.shmDevice = createShmDevice(); + orbis::g_context.blockpoolDevice = createBlockPoolDevice(); std::vector argvOffsets; std::vector envpOffsets; diff --git a/rpcsx-os/ops.cpp b/rpcsx-os/ops.cpp index d83fb5d88..75e5f0cc7 100644 --- a/rpcsx-os/ops.cpp +++ b/rpcsx-os/ops.cpp @@ -2,6 +2,7 @@ #include "align.hpp" #include "backtrace.hpp" #include "io-device.hpp" +#include "iodev/blockpool.hpp" #include "iodev/dmem.hpp" #include "linker.hpp" #include "orbis/KernelContext.hpp" @@ -259,6 +260,33 @@ orbis::SysResult shm_open(orbis::Thread *thread, const char *path, return dev->open(file, path, flags, mode, thread); } +orbis::SysResult blockpool_open(orbis::Thread *thread, + orbis::Ref *file) { + auto dev = static_cast(orbis::g_context.blockpoolDevice.get()); + return dev->open(file, nullptr, 0, 0, thread); +} + +orbis::SysResult blockpool_map(orbis::Thread *thread, orbis::caddr_t addr, + orbis::size_t len, orbis::sint prot, + orbis::sint flags) { + auto blockpool = + static_cast(orbis::g_context.blockpoolDevice.get()); + void *address = addr; + auto result = blockpool->map(&address, len, prot, flags, thread); + if (result != ErrorCode{}) { + return result; + } + + thread->retval[0] = reinterpret_cast(address); + return {}; +} +orbis::SysResult blockpool_unmap(orbis::Thread *thread, orbis::caddr_t addr, + orbis::size_t len) { + auto blockpool = + static_cast(orbis::g_context.blockpoolDevice.get()); + return blockpool->unmap(addr, len, thread); +} + orbis::SysResult socket(orbis::Thread *thread, orbis::ptr name, orbis::sint domain, orbis::sint type, orbis::sint protocol, Ref *file) { @@ -562,6 +590,9 @@ ProcessOps rx::procOpsTable = { .virtual_query = virtual_query, .open = open, .shm_open = shm_open, + .blockpool_open = blockpool_open, + .blockpool_map = blockpool_map, + .blockpool_unmap = blockpool_unmap, .socket = socket, .shm_unlink = shm_unlink, .dynlib_get_obj_member = dynlib_get_obj_member,