Skip to content

Commit

Permalink
vm: fix mapping of file's last page
Browse files Browse the repository at this point in the history
thanks @red_prig for investigation
  • Loading branch information
DHrpcs3 committed Aug 31, 2024
1 parent ea29154 commit e6022c1
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 69 deletions.
4 changes: 0 additions & 4 deletions orbis-kernel/src/sys/sys_vm_mmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
70 changes: 55 additions & 15 deletions rpcsx-os/io-device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@
#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 <cerrno>
#include <dirent.h>
#include <fcntl.h>
#include <filesystem>
#include <netinet/in.h>
#include <optional>
#include <span>
#include <string>
#include <sys/mman.h>
Expand All @@ -25,7 +27,6 @@
#include <thread>
#include <unistd.h>
#include <vector>
#include <optional>

struct HostFile : orbis::File {
bool closeOnExit = true;
Expand Down Expand Up @@ -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<IoDevice>().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 {};
Expand Down Expand Up @@ -701,19 +736,21 @@ orbis::ErrorCode createSocket(orbis::Ref<orbis::File> *file,
return {};
}

static std::optional<std::string> findFileInDir(const std::filesystem::path &dir, const char *name) {
static std::optional<std::string>
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<std::filesystem::path> toRealPath(const std::filesystem::path &inp) {
static std::optional<std::filesystem::path>
toRealPath(const std::filesystem::path &inp) {
if (inp.empty()) {
return{};
return {};
}

std::filesystem::path result;
Expand All @@ -725,7 +762,7 @@ static std::optional<std::filesystem::path> toRealPath(const std::filesystem::pa

auto icaseElem = findFileInDir(result, elem.c_str());
if (!icaseElem) {
return{};
return {};
}

result /= *icaseElem;
Expand Down Expand Up @@ -793,11 +830,13 @@ orbis::ErrorCode HostFsDevice::open(orbis::Ref<orbis::File> *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();
}
}
Expand Down Expand Up @@ -899,7 +938,8 @@ orbis::ErrorCode HostFsDevice::rename(const char *from, const char *to,
return convertErrorCode(ec);
}

orbis::File *createHostFile(int hostFd, orbis::Ref<IoDevice> device, bool alignTruncate) {
orbis::File *createHostFile(int hostFd, orbis::Ref<IoDevice> device,
bool alignTruncate) {
auto newFile = orbis::knew<HostFile>();
newFile->hostFd = hostFd;
newFile->ops = &hostOps;
Expand Down
80 changes: 31 additions & 49 deletions rpcsx-os/vm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "orbis/thread/Thread.hpp"
#include "orbis/utils/Logs.hpp"
#include "orbis/utils/Rc.hpp"
#include "rx/mem.hpp"
#include <bit>
#include <cassert>
#include <cinttypes>
Expand All @@ -20,32 +21,6 @@

#include <rx/MemoryTable.hpp>

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) {
Expand Down Expand Up @@ -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<std::uint32_t>(0), noOverwrite);
modifyFlags(firstPage, pagesCount, flags, ~static_cast<std::uint32_t>(0),
noOverwrite);
}

void addFlags(std::uint64_t firstPage, std::uint64_t pagesCount,
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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<void *>(address), kPageSize, PROT_READ);
rx::mem::protect(reinterpret_cast<void *>(address), kPageSize, PROT_READ);
std::memcpy(mapping, reinterpret_cast<void *>(address), kPageSize);
utils::unmap(mapping, kPageSize);
utils::unmap(reinterpret_cast<void *>(address), kPageSize);
rx::mem::unmap(mapping, kPageSize);
rx::mem::unmap(reinterpret_cast<void *>(address), kPageSize);

mapping = utils::map(reinterpret_cast<void *>(address), kPageSize,
prot & kMapProtCpuAll, MAP_FIXED | MAP_SHARED,
gMemoryShm, address - kMinAddress);
mapping = rx::mem::map(reinterpret_cast<void *>(address), kPageSize,
prot & kMapProtCpuAll, MAP_FIXED | MAP_SHARED,
gMemoryShm, address - kMinAddress);
assert(mapping != MAP_FAILED);
}

Expand All @@ -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<void *>(kMinAddress),
kMaxAddress - kMinAddress);
rx::mem::unmap(reinterpret_cast<void *>(kMinAddress),
kMaxAddress - kMinAddress);
if (::ftruncate64(gMemoryShm, 0) < 0) {
std::abort();
}
Expand All @@ -743,8 +720,8 @@ void rx::vm::reset() {
}

reserve(0, kMinAddress);
utils::reserve(reinterpret_cast<void *>(kMinAddress),
kMaxAddress - kMinAddress);
rx::mem::reserve(reinterpret_cast<void *>(kMinAddress),
kMaxAddress - kMinAddress);
}

void rx::vm::initialize() {
Expand All @@ -765,8 +742,8 @@ void rx::vm::initialize() {

reserve(0, kMinAddress); // unmapped area

utils::reserve(reinterpret_cast<void *>(kMinAddress),
kMaxAddress - kMinAddress);
rx::mem::reserve(reinterpret_cast<void *>(kMinAddress),
kMaxAddress - kMinAddress);

// orbis::bridge.setUpSharedMemory(kMinAddress, kMemorySize, "/orbis-memory");
}
Expand Down Expand Up @@ -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<std::uint64_t>(addr);

Expand All @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -962,9 +942,9 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot,
return reinterpret_cast<void *>(address);
}

auto result =
utils::map(reinterpret_cast<void *>(address), len, prot & kMapProtCpuAll,
realFlags, gMemoryShm, address - kMinAddress);
auto result = rx::mem::map(reinterpret_cast<void *>(address), len,
prot & kMapProtCpuAll, realFlags, gMemoryShm,
address - kMinAddress);

if (result != MAP_FAILED && isAnon) {
bool needReprotect = (prot & PROT_WRITE) == 0;
Expand All @@ -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<std::uint64_t>(addr);

Expand Down Expand Up @@ -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<std::uint64_t>(addr);
if (address < kMinAddress || address >= kMaxAddress || size > kMaxAddress ||
Expand Down
11 changes: 10 additions & 1 deletion rx/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
13 changes: 13 additions & 0 deletions rx/include/rx/mem.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include <cstddef>

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
Loading

0 comments on commit e6022c1

Please sign in to comment.