2#include "pedigree/kernel/process/Process.h"
3#include "pedigree/kernel/process/TerminationDeferral.h"
4#include "pedigree/kernel/process/Thread.h"
5#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
6#include "pedigree/kernel/processor/Processor.h"
7#include "pedigree/kernel/processor/VirtualAddressSpace.h"
8#include "pedigree/kernel/syscallError.h"
9#include "pedigree/kernel/utilities/Pointers.h"
13#include "PosixSubsystem.h"
15#include "modules/system/vfs/VFS.h"
16#include "vm-syscalls.h"
19constexpr int MayMove = 1, Fixed = 2, DontUnmap = 4;
20constexpr int Discard = 4, PageOut = 21;
22bool roundLength(
size_t length,
size_t& rounded) {
24 if (length > ~
size_t(0) - mask)
26 rounded = (length + mask) & ~mask;
30bool userRange(uintptr_t base,
size_t length) {
32 return base >= space.getUserStart() && base < space.getKernelStart() &&
33 length <= space.getKernelStart() - base &&
34 space.isAddressValid(
reinterpret_cast<void*
>(base)) &&
35 (!length || space.isAddressValid(
reinterpret_cast<void*
>(base + length - 1)));
38struct ResidencyCredentials {
43bool mayInspectResidency(
File* file,
void* context) {
44 const auto& credentials = *
static_cast<ResidencyCredentials*
>(context);
45 if (credentials.uid == 0 || file->getAttributes().uid ==
static_cast<size_t>(credentials.uid))
48 const size_t savedError = thread->
getErrno();
49 const bool permitted =
VFS::checkAccess(file,
false,
true,
false, credentials.uid,
50 credentials.gid, credentials.groups);
57void* posix_mremap(
void* oldAddress,
size_t oldLength,
size_t newLength,
int flags,
60 const uintptr_t source =
reinterpret_cast<uintptr_t
>(oldAddress);
61 const uintptr_t destination =
reinterpret_cast<uintptr_t
>(newAddress);
63 size_t oldSize, newSize;
64 if ((source & mask) || !newLength || !roundLength(oldLength, oldSize) ||
65 !roundLength(newLength, newSize) || (flags & ~(MayMove | Fixed | DontUnmap)) ||
66 ((flags & (Fixed | DontUnmap)) && !(flags & MayMove)) || (!oldLength && !(flags & MayMove))) {
67 SYSCALL_ERROR(InvalidArgument);
68 return reinterpret_cast<void*
>(~uintptr_t(0));
70 if (!userRange(source, oldSize)) {
71 SYSCALL_ERROR(BadAddress);
72 return reinterpret_cast<void*
>(~uintptr_t(0));
74 if ((flags & Fixed) && ((destination & mask) || !userRange(destination, newSize) ||
75 (source < destination + newSize && destination < source + oldSize))) {
76 SYSCALL_ERROR(InvalidArgument);
77 return reinterpret_cast<void*
>(~uintptr_t(0));
79 if (flags & DontUnmap) {
80 if (oldSize != newSize)
81 SYSCALL_ERROR(InvalidArgument);
83 SYSCALL_ERROR(OperationNotSupported);
84 return reinterpret_cast<void*
>(~uintptr_t(0));
88 newSize, bool(flags & MayMove), bool(flags & Fixed)};
92 case MemoryMapManager::VmStatus::Success:
94 return reinterpret_cast<void*
>(result);
95 case MemoryMapManager::VmStatus::InvalidRange:
96 SYSCALL_ERROR(InvalidArgument);
98 case MemoryMapManager::VmStatus::Unmapped:
99 SYSCALL_ERROR(BadAddress);
101 case MemoryMapManager::VmStatus::Unsupported:
102 SYSCALL_ERROR(OperationNotSupported);
104 case MemoryMapManager::VmStatus::NoMemory:
105 SYSCALL_ERROR(OutOfMemory);
107 case MemoryMapManager::VmStatus::LockLimit:
108 SYSCALL_ERROR(NoMoreProcesses);
111 return reinterpret_cast<void*
>(~uintptr_t(0));
114int posix_remap_file_pages(
void* address,
size_t length,
size_t prot,
size_t pageOffset,
118 const uintptr_t base =
reinterpret_cast<uintptr_t
>(address) & ~(pageSize - 1);
119 const size_t extent = length & ~(pageSize - 1);
120 if (prot || !extent || extent > ~uintptr_t(0) - base || !userRange(base, extent) ||
121 extent / pageSize > ~size_t(0) - pageOffset) {
122 SYSCALL_ERROR(InvalidArgument);
125 if (pageOffset > ~
size_t(0) / pageSize ||
126 pageOffset >
static_cast<uint64_t
>(LLONG_MAX) / pageSize ||
127 extent >
static_cast<uint64_t
>(LLONG_MAX) - pageOffset * pageSize) {
128 SYSCALL_ERROR(ValueTooLarge);
132 constexpr size_t Nonblock = 0x10000;
133 using Status = MemoryMapManager::FileRemapStatus;
135 base, extent, pageOffset * pageSize, flags & Nonblock);
137 case Status::Success:
140 case Status::InvalidRange:
141 SYSCALL_ERROR(InvalidArgument);
143 case Status::Unsupported:
144 SYSCALL_ERROR(OperationNotSupported);
146 case Status::NoMemory:
147 SYSCALL_ERROR(OutOfMemory);
149 case Status::PolicyDenied:
150 case Status::PermissionDenied:
151 SYSCALL_ERROR(NotEnoughPermissions);
153 case Status::LockLimit:
154 SYSCALL_ERROR(NoMoreProcesses);
160int posix_mincore(
void* address,
size_t length,
unsigned char* vector) {
162 const uintptr_t base =
reinterpret_cast<uintptr_t
>(address);
164 if (base & (pageSize - 1)) {
165 SYSCALL_ERROR(InvalidArgument);
169 if (!roundLength(length, extent)) {
170 SYSCALL_ERROR(OutOfMemory);
175 if (!userRange(base, extent)) {
176 SYSCALL_ERROR(OutOfMemory);
179 const size_t pages = extent / pageSize;
180 const size_t capacity = pages < pageSize ? pages : pageSize;
183 SYSCALL_ERROR(NoMoreProcesses);
188 ResidencyCredentials credentials;
189 credentials.uid = process->getEffectiveUserId();
190 if (credentials.uid < 0)
192 credentials.gid = process->getEffectiveGroupId();
193 if (credentials.gid < 0)
194 credentials.gid = process->getGroupId();
195 if (!credentials.groups.tryReserve(NGROUPS_MAX)) {
196 SYSCALL_ERROR(NoMoreProcesses);
199 process->getSupplementalGroupIds(credentials.groups);
200 for (
size_t completed = 0; completed < pages;) {
201 const size_t count = pages - completed < capacity ? pages - completed : capacity;
204 snapshot.get(), mayInspectResidency, &credentials);
205 if (status != MemoryMapManager::VmStatus::Success) {
206 if (status == MemoryMapManager::VmStatus::NoMemory)
207 SYSCALL_ERROR(NoMoreProcesses);
209 SYSCALL_ERROR(OutOfMemory);
212 const uintptr_t output =
reinterpret_cast<uintptr_t
>(vector);
213 if (completed > ~uintptr_t(0) - output ||
216 SYSCALL_ERROR(BadAddress);
225int posix_madvise(
void* address,
size_t length,
int advice) {
227 const uintptr_t base =
reinterpret_cast<uintptr_t
>(address);
230 if ((base & mask) || !roundLength(length, extent) || (advice != Discard && advice != PageOut)) {
231 SYSCALL_ERROR(InvalidArgument);
236 if (!userRange(base, extent)) {
237 SYSCALL_ERROR(OutOfMemory);
240 if (advice == PageOut) {
243 case SwapStatus::Success:
246 case SwapStatus::IoError:
247 SYSCALL_ERROR(IoError);
249 case SwapStatus::NoMemory:
250 case SwapStatus::Unmapped:
251 SYSCALL_ERROR(OutOfMemory);
253 case SwapStatus::Unsupported:
254 case SwapStatus::NotActive:
255 SYSCALL_ERROR(OperationNotSupported);
258 SYSCALL_ERROR(InvalidArgument);
264 if (status == MemoryMapManager::VmStatus::Success) {
268 if (status == MemoryMapManager::VmStatus::InvalidRange ||
269 status == MemoryMapManager::VmStatus::Unsupported)
270 SYSCALL_ERROR(InvalidArgument);
272 SYSCALL_ERROR(OutOfMemory);
Memory-mapped file interface.
static MemoryMapManager & instance()
static constexpr size_t getPageSize() PURE
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
virtual int64_t getUserId() const
static ProcessorInformation & information()
void setErrno(size_t err)
Process * getParent() const
static bool checkAccess(File *pFile, bool bRead, bool bWrite, bool bExecute)
A vector / dynamic array.