From 0c59167c385248ec79ddac73fdff22bcb22f30e8 Mon Sep 17 00:00:00 2001 From: DH Date: Tue, 1 Aug 2023 15:40:35 +0300 Subject: [PATCH] [rpcsx-os] implement sys_query_memory_protection --- orbis-kernel/include/orbis/sys/sysproto.hpp | 5 +- .../include/orbis/thread/ProcessOps.hpp | 3 + orbis-kernel/include/orbis/vm.hpp | 13 ++++ orbis-kernel/src/sys/sys_sce.cpp | 9 ++- rpcsx-os/io-device.cpp | 2 - rpcsx-os/ops.cpp | 12 ++++ rpcsx-os/vm.cpp | 60 +++++++++++++++++-- rpcsx-os/vm.hpp | 2 +- 8 files changed, 95 insertions(+), 11 deletions(-) create mode 100644 orbis-kernel/include/orbis/vm.hpp diff --git a/orbis-kernel/include/orbis/sys/sysproto.hpp b/orbis-kernel/include/orbis/sys/sysproto.hpp index 1c3dbe5de..05f4120c2 100644 --- a/orbis-kernel/include/orbis/sys/sysproto.hpp +++ b/orbis-kernel/include/orbis/sys/sysproto.hpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -12,6 +11,7 @@ using cpuwhich_t = sint; using cpulevel_t = sint; using SceKernelModule = ModuleHandle; +struct MemoryProtection; struct ModuleInfo; struct ModuleInfoEx; struct KEvent; @@ -631,7 +631,8 @@ SysResult sys_evf_set(Thread *thread, sint id, uint64_t value); SysResult sys_evf_clear(Thread *thread, sint id, uint64_t value); SysResult sys_evf_cancel(Thread *thread, sint id, uint64_t value, ptr pNumWaitThreads); -SysResult sys_query_memory_protection(Thread *thread /* TODO */); +SysResult sys_query_memory_protection(Thread *thread, ptr address, + ptr protection); SysResult sys_batch_map(Thread *thread /* TODO */); SysResult sys_osem_create(Thread *thread, ptr name, uint attrs, sint initCount, sint maxCount); diff --git a/orbis-kernel/include/orbis/thread/ProcessOps.hpp b/orbis-kernel/include/orbis/thread/ProcessOps.hpp index 71ebb5aef..019af043e 100644 --- a/orbis-kernel/include/orbis/thread/ProcessOps.hpp +++ b/orbis-kernel/include/orbis/thread/ProcessOps.hpp @@ -10,6 +10,7 @@ struct Thread; struct Module; struct timespec; struct File; +struct MemoryProtection; struct ProcessOps { SysResult (*mmap)(Thread *thread, caddr_t addr, size_t len, sint prot, @@ -32,6 +33,8 @@ struct ProcessOps { SysResult (*munlock)(Thread *thread, ptr addr, size_t len); SysResult (*virtual_query)(Thread *thread, ptr addr, sint flags, ptr info, ulong infoSize); + SysResult (*query_memory_protection)(Thread *thread, ptr address, + ptr protection); SysResult (*open)(Thread *thread, ptr path, sint flags, sint mode, Ref *file); diff --git a/orbis-kernel/include/orbis/vm.hpp b/orbis-kernel/include/orbis/vm.hpp new file mode 100644 index 000000000..8e55bc27d --- /dev/null +++ b/orbis-kernel/include/orbis/vm.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "orbis-config.hpp" + +namespace orbis { +struct MemoryProtection { + uint64_t startAddress; + uint64_t endAddress; + int32_t prot; +}; + +static_assert(sizeof(MemoryProtection) == 24); +} // namespace orbis diff --git a/orbis-kernel/src/sys/sys_sce.cpp b/orbis-kernel/src/sys/sys_sce.cpp index 922920278..1170d64d3 100644 --- a/orbis-kernel/src/sys/sys_sce.cpp +++ b/orbis-kernel/src/sys/sys_sce.cpp @@ -299,7 +299,14 @@ orbis::SysResult orbis::sys_evf_cancel(Thread *thread, sint id, uint64_t value, } return {}; } -orbis::SysResult orbis::sys_query_memory_protection(Thread *thread /* TODO */) { +orbis::SysResult +orbis::sys_query_memory_protection(Thread *thread, ptr address, + ptr protection) { + if (auto query_memory_protection = + thread->tproc->ops->query_memory_protection) { + return query_memory_protection(thread, address, protection); + } + return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_batch_map(Thread *thread /* TODO */) { diff --git a/rpcsx-os/io-device.cpp b/rpcsx-os/io-device.cpp index b18e02a6a..aebbe2e55 100644 --- a/rpcsx-os/io-device.cpp +++ b/rpcsx-os/io-device.cpp @@ -20,8 +20,6 @@ struct HostFile : orbis::File { int hostFd = -1; ~HostFile() { - std::printf("Destroying host file\n"); - if (hostFd > 0) { ::close(hostFd); } diff --git a/rpcsx-os/ops.cpp b/rpcsx-os/ops.cpp index 75e5f0cc7..3d7944cc4 100644 --- a/rpcsx-os/ops.cpp +++ b/rpcsx-os/ops.cpp @@ -12,6 +12,7 @@ #include "orbis/umtx.hpp" #include "orbis/utils/Logs.hpp" #include "orbis/utils/Rc.hpp" +#include "orbis/vm.hpp" #include "thread.hpp" #include "vfs.hpp" #include "vm.hpp" @@ -247,6 +248,16 @@ orbis::SysResult virtual_query(orbis::Thread *thread, return {}; } +orbis::SysResult +query_memory_protection(orbis::Thread *thread, orbis::ptr address, + orbis::ptr protection) { + if (rx::vm::queryProtection(address, &protection->startAddress, + &protection->endAddress, &protection->prot)) { + return {}; + } + return ErrorCode::INVAL; +} + orbis::SysResult open(orbis::Thread *thread, orbis::ptr path, orbis::sint flags, orbis::sint mode, orbis::Ref *file) { @@ -588,6 +599,7 @@ ProcessOps rx::procOpsTable = { .munlockall = munlockall, .munlock = munlock, .virtual_query = virtual_query, + .query_memory_protection = query_memory_protection, .open = open, .shm_open = shm_open, .blockpool_open = blockpool_open, diff --git a/rpcsx-os/vm.cpp b/rpcsx-os/vm.cpp index 51aaafeef..08be460fa 100644 --- a/rpcsx-os/vm.cpp +++ b/rpcsx-os/vm.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -915,10 +916,60 @@ bool rx::vm::protect(void *addr, std::uint64_t size, std::int32_t prot) { return ::mprotect(addr, size, prot & kMapProtCpuAll) == 0; } +static std::int32_t getPageProtectionImpl(std::uint64_t address) { + return gBlocks[(address >> kBlockShift) - kFirstBlock].getProtection( + (address & kBlockMask) >> rx::vm::kPageShift); +} + bool rx::vm::queryProtection(const void *addr, std::uint64_t *startAddress, - std::uint64_t *endAddress, std::int64_t *prot) { - // TODO - return false; + std::uint64_t *endAddress, std::int32_t *prot) { + auto address = reinterpret_cast(addr); + if (address < kMinAddress || address >= kMaxAddress) { + return false; + } + + std::uint64_t start = address & ~kPageMask; + std::uint64_t end = start + kPageSize; + + std::lock_guard lock(g_mtx); + + auto resultProt = getPageProtectionImpl(address); + + while (true) { + auto testAddr = start - kPageSize; + if (testAddr < kMinAddress) { + break; + } + + auto testProt = getPageProtectionImpl(testAddr); + + if (resultProt != testProt) { + break; + } + + start = testAddr; + } + + while (true) { + auto testAddr = end; + if (testAddr >= kMaxAddress) { + break; + } + + auto testProt = getPageProtectionImpl(testAddr); + + if (resultProt != testProt) { + break; + } + + end = testAddr + kPageSize; + } + + *startAddress = start; + *endAddress = end; + *prot = resultProt; + + return true; } unsigned rx::vm::getPageProtection(std::uint64_t address) { @@ -929,8 +980,7 @@ unsigned rx::vm::getPageProtection(std::uint64_t address) { std::lock_guard lock(g_mtx); - return gBlocks[(address >> kBlockShift) - kFirstBlock].getProtection( - (address & kBlockMask) >> kPageShift); + return getPageProtectionImpl(address); } bool rx::vm::virtualQuery(const void *addr, std::int32_t flags, diff --git a/rpcsx-os/vm.hpp b/rpcsx-os/vm.hpp index f5184629e..5d7accccd 100644 --- a/rpcsx-os/vm.hpp +++ b/rpcsx-os/vm.hpp @@ -75,6 +75,6 @@ bool protect(void *addr, std::uint64_t size, std::int32_t prot); bool virtualQuery(const void *addr, std::int32_t flags, VirtualQueryInfo *info); bool queryProtection(const void *addr, std::uint64_t *startAddress, - std::uint64_t *endAddress, std::int64_t *prot); + std::uint64_t *endAddress, std::int32_t *prot); unsigned getPageProtection(std::uint64_t address); } // namespace rx::vm