diff --git a/orbis-kernel/src/sys/sys_vm_mmap.cpp b/orbis-kernel/src/sys/sys_vm_mmap.cpp index da11ea11..811ff8ec 100644 --- a/orbis-kernel/src/sys/sys_vm_mmap.cpp +++ b/orbis-kernel/src/sys/sys_vm_mmap.cpp @@ -14,10 +14,6 @@ orbis::SysResult orbis::sys_sstk(Thread *, sint) { orbis::SysResult orbis::sys_mmap(Thread *thread, caddr_t addr, size_t len, sint prot, sint flags, sint fd, off_t pos) { if (auto impl = thread->tproc->ops->mmap) { - // hack for audio control shared memory - if (len == 3880) { - return impl(thread, addr, 0x10000, prot, flags, fd, pos); - } return impl(thread, addr, len, prot, flags, fd, pos); } diff --git a/rpcsx-os/io-device.cpp b/rpcsx-os/io-device.cpp index f05b3c6a..99111cb2 100644 --- a/rpcsx-os/io-device.cpp +++ b/rpcsx-os/io-device.cpp @@ -8,6 +8,7 @@ #include "orbis/thread/Thread.hpp" #include "orbis/uio.hpp" #include "orbis/utils/Logs.hpp" +#include "rx/mem.hpp" #include "vfs.hpp" #include "vm.hpp" #include @@ -15,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -25,7 +27,6 @@ #include #include #include -#include struct HostFile : orbis::File { bool closeOnExit = true; @@ -339,20 +340,54 @@ static orbis::ErrorCode host_mmap(orbis::File *file, void **address, return orbis::ErrorCode::ISDIR; auto result = - rx::vm::map(*address, size, prot, flags, rx::vm::kMapInternalReserveOnly); + rx::vm::map(*address, size, prot, flags, rx::vm::kMapInternalReserveOnly, + hostFile->device.cast().get(), offset); if (result == (void *)-1) { return orbis::ErrorCode::NOMEM; } - result = ::mmap(result, size, prot & rx::vm::kMapProtCpuAll, - MAP_SHARED | MAP_FIXED, hostFile->hostFd, offset); + size = utils::alignUp(size, rx::vm::kPageSize); + + result = ::mmap( + result, size, prot & rx::vm::kMapProtCpuAll, + ((prot & rx::vm::kMapFlagPrivate) != 0 ? MAP_PRIVATE : MAP_SHARED) | + MAP_FIXED, + hostFile->hostFd, offset); if (result == (void *)-1) { - auto result = convertErrno(); - return result; + auto errc = convertErrno(); + std::printf("Failed to map file at %p-%p\n", *address, + (char *)*address + size); + return errc; } - std::printf("shm mapped at %p-%p\n", result, (char *)result + size); + std::printf("file mapped at %p-%p:%lx\n", result, (char *)result + size, + offset); + + struct stat stat; + fstat(hostFile->hostFd, &stat); + if (stat.st_size < offset + size) { + std::size_t rest = + std::min(offset + size - stat.st_size, rx::vm::kPageSize); + + if (rest > rx::mem::pageSize) { + auto fillSize = + utils::alignUp(rest, rx::mem::pageSize) - rx::mem::pageSize; + + std::printf("adding dummy mapping %p-%p, file ends at %p\n", + (char *)result + size - fillSize, (char *)result + size, + (char *)result + (stat.st_size - offset)); + + auto ptr = ::mmap((char *)result + size - fillSize, fillSize, + prot & rx::vm::kMapProtCpuAll, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); + + if (ptr == (void *)-1) { + std::printf("failed to add dummy mapping %p-%p\n", result, + (char *)result + size); + } + } + } *address = result; return {}; @@ -701,19 +736,21 @@ orbis::ErrorCode createSocket(orbis::Ref *file, return {}; } -static std::optional findFileInDir(const std::filesystem::path &dir, const char *name) { +static std::optional +findFileInDir(const std::filesystem::path &dir, const char *name) { for (auto entry : std::filesystem::directory_iterator(dir)) { auto entryName = entry.path().filename(); if (strcasecmp(entryName.c_str(), name) == 0) { return entryName; } } - return{}; + return {}; } -static std::optional toRealPath(const std::filesystem::path &inp) { +static std::optional +toRealPath(const std::filesystem::path &inp) { if (inp.empty()) { - return{}; + return {}; } std::filesystem::path result; @@ -725,7 +762,7 @@ static std::optional toRealPath(const std::filesystem::pa auto icaseElem = findFileInDir(result, elem.c_str()); if (!icaseElem) { - return{}; + return {}; } result /= *icaseElem; @@ -793,11 +830,13 @@ orbis::ErrorCode HostFsDevice::open(orbis::Ref *file, error = convertErrno(); if (auto icaseRealPath = toRealPath(realPath)) { - ORBIS_LOG_WARNING(__FUNCTION__, path, realPath.c_str(), icaseRealPath->c_str()); + ORBIS_LOG_WARNING(__FUNCTION__, path, realPath.c_str(), + icaseRealPath->c_str()); hostFd = ::open(icaseRealPath->c_str(), realFlags, 0777); if (hostFd < 0) { - ORBIS_LOG_ERROR("host_open failed", path, realPath.c_str(), icaseRealPath->c_str(), error); + ORBIS_LOG_ERROR("host_open failed", path, realPath.c_str(), + icaseRealPath->c_str(), error); return convertErrno(); } } @@ -899,7 +938,8 @@ orbis::ErrorCode HostFsDevice::rename(const char *from, const char *to, return convertErrorCode(ec); } -orbis::File *createHostFile(int hostFd, orbis::Ref device, bool alignTruncate) { +orbis::File *createHostFile(int hostFd, orbis::Ref device, + bool alignTruncate) { auto newFile = orbis::knew(); newFile->hostFd = hostFd; newFile->ops = &hostOps; diff --git a/rpcsx-os/vm.cpp b/rpcsx-os/vm.cpp index cf5b21d0..ba570563 100644 --- a/rpcsx-os/vm.cpp +++ b/rpcsx-os/vm.cpp @@ -7,6 +7,7 @@ #include "orbis/thread/Thread.hpp" #include "orbis/utils/Logs.hpp" #include "orbis/utils/Rc.hpp" +#include "rx/mem.hpp" #include #include #include @@ -20,32 +21,6 @@ #include -namespace utils { -namespace { -void *map(void *address, std::size_t size, int prot, int flags, int fd = -1, - off_t offset = 0) { - return ::mmap(address, size, prot, flags, fd, offset); -} - -void *reserve(std::size_t size) { - return map(nullptr, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS); -} - -bool reserve(void *address, std::size_t size) { - return map(address, size, PROT_NONE, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED) != MAP_FAILED; -} - -bool protect(void *address, std::size_t size, int prot) { - return ::mprotect(address, size, prot) == 0; -} - -bool unmap(void *address, std::size_t size) { - return ::munmap(address, size) == 0; -} -} // namespace -} // namespace utils - static std::mutex g_mtx; std::string rx::vm::mapFlagsToString(std::int32_t flags) { @@ -305,7 +280,8 @@ struct Block { void setFlags(std::uint64_t firstPage, std::uint64_t pagesCount, std::uint32_t flags, bool noOverwrite) { - modifyFlags(firstPage, pagesCount, flags, ~static_cast(0), noOverwrite); + modifyFlags(firstPage, pagesCount, flags, ~static_cast(0), + noOverwrite); } void addFlags(std::uint64_t firstPage, std::uint64_t pagesCount, @@ -681,7 +657,8 @@ static void reserve(std::uint64_t startAddress, std::uint64_t endAddress) { auto pagesCount = (endAddress - startAddress + (rx::vm::kPageSize - 1)) >> rx::vm::kPageShift; - gBlocks[blockIndex - kFirstBlock].setFlags(firstPage, pagesCount, kAllocated, false); + gBlocks[blockIndex - kFirstBlock].setFlags(firstPage, pagesCount, kAllocated, + false); } void rx::vm::fork(std::uint64_t pid) { @@ -711,18 +688,18 @@ void rx::vm::fork(std::uint64_t pid) { } if (prot & kMapProtCpuAll) { - auto mapping = utils::map(nullptr, kPageSize, PROT_WRITE, MAP_SHARED, - gMemoryShm, address - kMinAddress); + auto mapping = rx::mem::map(nullptr, kPageSize, PROT_WRITE, MAP_SHARED, + gMemoryShm, address - kMinAddress); assert(mapping != MAP_FAILED); - utils::protect(reinterpret_cast(address), kPageSize, PROT_READ); + rx::mem::protect(reinterpret_cast(address), kPageSize, PROT_READ); std::memcpy(mapping, reinterpret_cast(address), kPageSize); - utils::unmap(mapping, kPageSize); - utils::unmap(reinterpret_cast(address), kPageSize); + rx::mem::unmap(mapping, kPageSize); + rx::mem::unmap(reinterpret_cast(address), kPageSize); - mapping = utils::map(reinterpret_cast(address), kPageSize, - prot & kMapProtCpuAll, MAP_FIXED | MAP_SHARED, - gMemoryShm, address - kMinAddress); + mapping = rx::mem::map(reinterpret_cast(address), kPageSize, + prot & kMapProtCpuAll, MAP_FIXED | MAP_SHARED, + gMemoryShm, address - kMinAddress); assert(mapping != MAP_FAILED); } @@ -733,8 +710,8 @@ void rx::vm::fork(std::uint64_t pid) { void rx::vm::reset() { std::memset(gBlocks, 0, sizeof(gBlocks)); - utils::unmap(reinterpret_cast(kMinAddress), - kMaxAddress - kMinAddress); + rx::mem::unmap(reinterpret_cast(kMinAddress), + kMaxAddress - kMinAddress); if (::ftruncate64(gMemoryShm, 0) < 0) { std::abort(); } @@ -743,8 +720,8 @@ void rx::vm::reset() { } reserve(0, kMinAddress); - utils::reserve(reinterpret_cast(kMinAddress), - kMaxAddress - kMinAddress); + rx::mem::reserve(reinterpret_cast(kMinAddress), + kMaxAddress - kMinAddress); } void rx::vm::initialize() { @@ -765,8 +742,8 @@ void rx::vm::initialize() { reserve(0, kMinAddress); // unmapped area - utils::reserve(reinterpret_cast(kMinAddress), - kMaxAddress - kMinAddress); + rx::mem::reserve(reinterpret_cast(kMinAddress), + kMaxAddress - kMinAddress); // orbis::bridge.setUpSharedMemory(kMinAddress, kMemorySize, "/orbis-memory"); } @@ -796,6 +773,7 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, addr, len, mapProtToString(prot).c_str(), mapFlagsToString(flags).c_str()); + len = utils::alignUp(len, kPageSize); auto pagesCount = (len + (kPageSize - 1)) >> kPageShift; auto hitAddress = reinterpret_cast(addr); @@ -820,7 +798,8 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, flags &= ~kMapFlagsAlignMask; - bool noOverwrite = (flags & (kMapFlagNoOverwrite | kMapFlagFixed)) == (kMapFlagNoOverwrite | kMapFlagFixed); + bool noOverwrite = (flags & (kMapFlagNoOverwrite | kMapFlagFixed)) == + (kMapFlagNoOverwrite | kMapFlagFixed); if (hitAddress & (alignment - 1)) { if (flags & kMapFlagStack) { @@ -929,8 +908,9 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, } block.setFlags((address & kBlockMask) >> kPageShift, pagesCount, - (prot & (kMapProtCpuAll | kMapProtGpuAll)) | kAllocated | - (isShared ? kShared : 0), false); + (prot & (kMapProtCpuAll | kMapProtGpuAll)) | kAllocated | + (isShared ? kShared : 0), + false); /* if (flags & kMapFlagStack) { @@ -962,9 +942,9 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, return reinterpret_cast(address); } - auto result = - utils::map(reinterpret_cast(address), len, prot & kMapProtCpuAll, - realFlags, gMemoryShm, address - kMinAddress); + auto result = rx::mem::map(reinterpret_cast(address), len, + prot & kMapProtCpuAll, realFlags, gMemoryShm, + address - kMinAddress); if (result != MAP_FAILED && isAnon) { bool needReprotect = (prot & PROT_WRITE) == 0; @@ -990,6 +970,7 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, } bool rx::vm::unmap(void *addr, std::uint64_t size) { + size = utils::alignUp(size, kPageSize); auto pages = (size + (kPageSize - 1)) >> kPageShift; auto address = reinterpret_cast(addr); @@ -1021,13 +1002,14 @@ bool rx::vm::unmap(void *addr, std::uint64_t size) { } else { std::fprintf(stderr, "ignoring mapping %lx-%lx\n", address, address + size); } - return utils::unmap(addr, size); + return rx::mem::unmap(addr, size); } bool rx::vm::protect(void *addr, std::uint64_t size, std::int32_t prot) { std::printf("rx::vm::protect(addr = %p, len = %" PRIu64 ", prot = %s)\n", addr, size, mapProtToString(prot).c_str()); + size = utils::alignUp(size, kPageSize); auto pages = (size + (kPageSize - 1)) >> kPageShift; auto address = reinterpret_cast(addr); if (address < kMinAddress || address >= kMaxAddress || size > kMaxAddress || diff --git a/rx/CMakeLists.txt b/rx/CMakeLists.txt index 64eed8c9..e079538c 100644 --- a/rx/CMakeLists.txt +++ b/rx/CMakeLists.txt @@ -4,9 +4,18 @@ find_package(Git) add_library(${PROJECT_NAME} OBJECT + src/mem.cpp src/Version.cpp ) -target_include_directories(${PROJECT_NAME} PUBLIC include) + +target_include_directories(${PROJECT_NAME} +PUBLIC + include + +PRIVATE + include/${PROJECT_NAME} +) + execute_process(COMMAND date +%+4Y%m%d OUTPUT_VARIABLE RAW_VERSION) string(STRIP "${RAW_VERSION}" RAW_VERSION) diff --git a/rx/include/rx/mem.hpp b/rx/include/rx/mem.hpp new file mode 100644 index 00000000..8a8cdd95 --- /dev/null +++ b/rx/include/rx/mem.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace rx::mem { +extern const std::size_t pageSize; +void *map(void *address, std::size_t size, int prot, int flags, int fd = -1, + std::ptrdiff_t offset = 0); +void *reserve(std::size_t size); +bool reserve(void *address, std::size_t size); +bool protect(void *address, std::size_t size, int prot); +bool unmap(void *address, std::size_t size); +} // namespace rx::mem diff --git a/rx/src/mem.cpp b/rx/src/mem.cpp new file mode 100644 index 00000000..4543c5f5 --- /dev/null +++ b/rx/src/mem.cpp @@ -0,0 +1,27 @@ +#include "mem.hpp" +#include +#include + +extern const std::size_t rx::mem::pageSize = sysconf(_SC_PAGE_SIZE); + +void *rx::mem::map(void *address, std::size_t size, int prot, int flags, + int fd, std::ptrdiff_t offset) { + return ::mmap(address, size, prot, flags, fd, offset); +} + +void *rx::mem::reserve(std::size_t size) { + return map(nullptr, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS); +} + +bool rx::mem::reserve(void *address, std::size_t size) { + return map(address, size, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED) != MAP_FAILED; +} + +bool rx::mem::protect(void *address, std::size_t size, int prot) { + return ::mprotect(address, size, prot) == 0; +} + +bool rx::mem::unmap(void *address, std::size_t size) { + return ::munmap(address, size) == 0; +}