rpcsx/kernel/orbis/src/sys/sys_vm_mmap.cpp
2025-12-02 03:02:22 +03:00

216 lines
6.2 KiB
C++

#include "KernelContext.hpp"
#include "error.hpp"
#include "rx/AddressRange.hpp"
#include "rx/align.hpp"
#include "rx/format.hpp"
#include "rx/print.hpp"
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/ProcessOps.hpp"
#include "thread/Thread.hpp"
#include "utils/Logs.hpp"
#include "vmem.hpp"
orbis::SysResult orbis::sys_sbrk(Thread *, sint) {
return ErrorCode::OPNOTSUPP;
}
orbis::SysResult orbis::sys_sstk(Thread *, sint) {
return ErrorCode::OPNOTSUPP;
}
orbis::SysResult orbis::sys_mmap(Thread *thread, uintptr_t addr, size_t len,
rx::EnumBitSet<vmem::Protection> prot,
rx::EnumBitSet<vmem::MapFlags> flags, sint fd,
off_t pos) {
std::uint64_t callerAddress = getCallerAddress(thread);
auto shift = addr & (vmem::kPageSize - 1);
if ((flags & vmem::MapFlags::Fixed) && shift != 0) {
return ErrorCode::INVAL;
}
if (len == 0) {
return ErrorCode::INVAL;
}
addr = rx::alignUp(addr, vmem::kPageSize);
rx::EnumBitSet<AllocationFlags> allocFlags{};
rx::EnumBitSet<vmem::BlockFlags> blockFlags{};
rx::EnumBitSet<vmem::BlockFlagsEx> blockFlagsEx{};
std::uint64_t alignment = vmem::kPageSize;
{
auto unpacked = unpackMapFlags(flags, vmem::kPageSize);
alignment = unpacked.first;
flags = unpacked.second;
}
len = rx::alignUp(len, vmem::kPageSize);
if (flags & vmem::MapFlags::Stack) {
allocFlags |= AllocationFlags::Stack;
}
if (flags & vmem::MapFlags::Fixed) {
allocFlags |= AllocationFlags::Fixed;
}
if (flags & vmem::MapFlags::NoOverwrite) {
allocFlags |= AllocationFlags::NoOverwrite;
}
if (flags & vmem::MapFlags::NoCoalesce) {
allocFlags |= AllocationFlags::NoMerge;
}
if (flags & vmem::MapFlags::Shared) {
blockFlagsEx |= vmem::BlockFlagsEx::Shared;
if (flags & vmem::MapFlags::Private) {
return ErrorCode::INVAL;
}
}
if (flags & vmem::MapFlags::Private) {
blockFlagsEx |= vmem::BlockFlagsEx::Private;
}
if (addr == 0) {
addr = flags & vmem::MapFlags::System ? 0xfc0000000 : 0x200000000;
}
auto name = callerAddress ? rx::format("anon:{:012x}", callerAddress) : "";
if (flags & vmem::MapFlags::Void) {
if (fd != -1 || pos != 0) {
return ErrorCode::INVAL;
}
auto [range, errc] = vmem::mapVoid(thread->tproc, len, addr, allocFlags,
name, alignment, callerAddress);
if (errc != orbis::ErrorCode{}) {
return errc;
}
thread->retval[0] = range.beginAddress();
return {};
}
if (flags & vmem::MapFlags::Stack) {
flags |= vmem::MapFlags::Anon;
blockFlags |= vmem::BlockFlags::Stack;
if (fd != -1 || pos != 0) {
return ErrorCode::INVAL;
}
if ((prot & (vmem::Protection::CpuRead | vmem::Protection::CpuWrite)) !=
(vmem::Protection::CpuRead | vmem::Protection::CpuWrite)) {
return ErrorCode::INVAL;
}
} else {
shift = 0;
}
if (flags & vmem::MapFlags::Anon) {
if (fd != -1 || pos != 0) {
return ErrorCode::INVAL;
}
auto [range, errc] =
vmem::mapFlex(thread->tproc, len, prot, addr, allocFlags, blockFlags,
name, alignment, callerAddress);
if (errc != orbis::ErrorCode{}) {
return errc;
}
thread->retval[0] = range.beginAddress() + shift;
return {};
}
auto file = thread->tproc->fileDescriptors.get(fd);
if (file == nullptr) {
return ErrorCode::BADF;
}
if (!file->device->blockFlags) {
blockFlags |= vmem::BlockFlags::FlexibleMemory;
prot &= ~vmem::Protection::CpuExec;
}
auto [range, errc] = vmem::mapFile(thread->tproc, addr, len, allocFlags, prot,
blockFlags, blockFlagsEx, file.get(), pos,
name, alignment, callerAddress);
if (errc != ErrorCode{}) {
return errc;
}
thread->retval[0] = range.beginAddress() + shift;
return {};
}
orbis::SysResult orbis::sys_freebsd6_mmap(Thread *thread, uintptr_t addr,
size_t len,
rx::EnumBitSet<vmem::Protection> prot,
rx::EnumBitSet<vmem::MapFlags> flags,
sint fd, sint, off_t pos) {
return sys_mmap(thread, addr, len, prot, flags, fd, pos);
}
orbis::SysResult orbis::sys_msync(Thread *thread, uintptr_t addr, size_t len,
sint flags) {
ORBIS_LOG_TODO(__FUNCTION__, addr, len, flags);
return {};
}
orbis::SysResult orbis::sys_munmap(Thread *thread, uintptr_t addr, size_t len) {
if (len == 0) {
return ErrorCode::INVAL;
}
auto range = rx::AddressRange::fromBeginSize(addr, len);
return vmem::unmap(thread->tproc, range);
}
orbis::SysResult orbis::sys_mprotect(Thread *thread, uintptr_t addr, size_t len,
rx::EnumBitSet<vmem::Protection> prot) {
auto range = rx::AddressRange::fromBeginSize(addr, len);
return vmem::protect(thread->tproc, range, prot);
}
orbis::SysResult orbis::sys_minherit(Thread *thread, uintptr_t addr, size_t len,
sint inherit) {
ORBIS_LOG_TODO(__FUNCTION__, addr, len, inherit);
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_madvise(Thread *thread, uintptr_t addr, size_t len,
sint behav) {
ORBIS_LOG_TODO(__FUNCTION__, addr, len, behav);
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_mincore(Thread *thread, uintptr_t addr, size_t len,
ptr<char> vec) {
ORBIS_LOG_TODO(__FUNCTION__, addr, len, vec);
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_mlock(Thread *thread, uintptr_t addr, size_t len) {
ORBIS_LOG_TODO(__FUNCTION__, addr, len);
return {};
}
orbis::SysResult orbis::sys_mlockall(Thread *thread, sint how) {
ORBIS_LOG_TODO(__FUNCTION__, how);
return {};
}
orbis::SysResult orbis::sys_munlockall(Thread *thread) {
ORBIS_LOG_TODO(__FUNCTION__);
return {};
}
orbis::SysResult orbis::sys_munlock(Thread *thread, uintptr_t addr,
size_t len) {
ORBIS_LOG_TODO(__FUNCTION__, addr, len);
return {};
}