mirror of
https://github.com/RPCSX/rpcsx.git
synced 2024-11-23 11:29:48 +00:00
vm: fix mapping of file's last page
thanks @red_prig for investigation
This commit is contained in:
parent
ea2915467a
commit
e6022c1c4c
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 <cerrno>
|
||||
@ -15,6 +16,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <filesystem>
|
||||
#include <netinet/in.h>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <sys/mman.h>
|
||||
@ -25,7 +27,6 @@
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
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<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 {};
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
|
@ -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>
|
||||
@ -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) {
|
||||
@ -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,
|
||||
@ -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<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);
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
@ -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() {
|
||||
@ -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");
|
||||
}
|
||||
@ -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);
|
||||
|
||||
@ -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<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;
|
||||
@ -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);
|
||||
|
||||
@ -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 ||
|
||||
|
@ -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)
|
||||
|
13
rx/include/rx/mem.hpp
Normal file
13
rx/include/rx/mem.hpp
Normal file
@ -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
|
27
rx/src/mem.cpp
Normal file
27
rx/src/mem.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include "mem.hpp"
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user