2#include "pedigree/kernel/process/Scheduler.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/ProcessorInformation.h"
8#include "pedigree/kernel/syscallError.h"
9#include "pedigree/kernel/utilities/Pointers.h"
11#include "process-vm-syscalls.h"
12#if PEDIGREE_PROCESS_MEMORY_TESTS
13#include "pedigree/kernel/utilities/assert.h"
18#include "PosixProcess.h"
19#include "PosixSubsystem.h"
24constexpr size_t MaximumVectors = 1024, MaximumTransfer = 0x7ffff000;
25#if PEDIGREE_PROCESS_MEMORY_TESTS
26Thread* fragmentCaller =
nullptr;
27ProcessVmAfterFragmentHook fragmentHook =
nullptr;
28void* fragmentContext =
nullptr;
31class ProcessMemoryResult {
33 explicit ProcessMemoryResult(
Thread& thread) : m_Thread(thread) {}
34 ssize_t finish(ssize_t result) {
35 m_Error = result < 0 ? m_Thread.getErrno() : 0;
38 ~ProcessMemoryResult() {
39 m_Thread.setErrno(m_Error);
47bool localRange(uintptr_t address,
size_t length) {
50 if (limit > 0x0000800000000000ULL)
51 limit = 0x0000800000000000ULL;
55 return address < limit && length <= limit - address;
58bool importVectors(
const iovec* user,
size_t count,
bool local,
UniqueArray<iovec>& owner,
61 if (count > MaximumVectors) {
62 SYSCALL_ERROR(InvalidArgument);
69 SYSCALL_ERROR(OutOfMemory);
73 SYSCALL_ERROR(BadAddress);
76 for (
size_t n = 0; n < count; ++n) {
77 auto& item = owner.get()[n];
78 if (item.iov_len >
static_cast<size_t>(SSIZE_MAX)) {
79 SYSCALL_ERROR(InvalidArgument);
84 if (count == 1 && item.iov_len > MaximumTransfer)
85 item.iov_len = MaximumTransfer;
86 if (!localRange(
reinterpret_cast<uintptr_t
>(item.iov_base), item.iov_len)) {
87 SYSCALL_ERROR(BadAddress);
90 if (item.iov_len > MaximumTransfer - total)
91 item.iov_len = MaximumTransfer - total;
92 total += item.iov_len;
93 }
else if (item.iov_len) {
106 if (scheduler.acquireProcessByUserspaceId(process,
static_cast<size_t>(pid)))
109 if (!scheduler.acquireThreadByUserspaceId(task,
static_cast<size_t>(pid))) {
114 return scheduler.acquireProcess(process, task->
getParent());
118 if (&caller == &target)
120 const auto source = caller.snapshotCredentials();
121 const auto destination = target.snapshotCredentials();
122 return destination.dumpable && source.ruid == destination.ruid &&
123 source.ruid == destination.euid && source.ruid == destination.suid &&
124 source.rgid == destination.rgid && source.rgid == destination.egid &&
125 source.rgid == destination.sgid;
129 const iovec* vectors;
130 size_t count, index = 0, offset = 0;
132 bool advanceEmpty() {
133 while (index < count && offset == vectors[index].iov_len) {
137 return index < count;
139 bool position(uintptr_t& address,
size_t& remaining)
const {
140 const auto& vector = vectors[index];
141 const uintptr_t base =
reinterpret_cast<uintptr_t
>(vector.iov_base);
142 if (offset > ~uintptr_t(0) - base)
144 address = base + offset;
145 remaining = vector.iov_len - offset;
150ssize_t transfer(
int pid,
const iovec* local,
size_t localCount,
const iovec* remote,
151 size_t remoteCount,
unsigned long flags,
bool write) {
153 ProcessMemoryResult completion(*thread);
156 SYSCALL_ERROR(InvalidArgument);
157 return completion.finish(-1);
160 size_t total = 0, nonemptyRemote = 0;
161 if (!importVectors(local, localCount,
true, localVectors, total))
162 return completion.finish(-1);
164 return completion.finish(0);
165 if (!importVectors(remote, remoteCount,
false, remoteVectors, nonemptyRemote))
166 return completion.finish(-1);
168 return completion.finish(0);
173 SYSCALL_ERROR(OutOfMemory);
174 return completion.finish(-1);
177 if (!acquireTarget(pid, process) || process->getType() != Process::Posix ||
178 !process->getSubsystem()) {
179 SYSCALL_ERROR(NoSuchProcess);
180 return completion.finish(-1);
183 if (callerProcess->getType() != Process::Posix) {
184 SYSCALL_ERROR(NotEnoughPermissions);
185 return completion.finish(-1);
187 auto& caller = *
static_cast<PosixProcess*
>(callerProcess);
188 auto& target = *
static_cast<PosixProcess*
>(process.get());
189 auto& subsystem = *
static_cast<PosixSubsystem*
>(process->getSubsystem());
194 if (!permitted(caller, target)) {
195 SYSCALL_ERROR(NotEnoughPermissions);
196 return completion.finish(-1);
198 if (!subsystem.snapshotUserImage(image)) {
199 SYSCALL_ERROR(NoSuchProcess);
200 return completion.finish(-1);
204 Cursor localCursor{localVectors.get(), localCount},
205 remoteCursor{remoteVectors.get(), remoteCount};
207 while (copied < total && localCursor.advanceEmpty() && remoteCursor.advanceEmpty()) {
209 SYSCALL_ERROR(Interrupted);
212 uintptr_t localAddress, remoteAddress;
213 size_t localRemaining, remoteRemaining;
214 if (!localCursor.position(localAddress, localRemaining) ||
215 !remoteCursor.position(remoteAddress, remoteRemaining)) {
216 SYSCALL_ERROR(BadAddress);
219 size_t length = total - copied;
220 if (length > localRemaining)
221 length = localRemaining;
222 if (length > remoteRemaining)
223 length = remoteRemaining;
224 const size_t localPage = pageSize - (localAddress % pageSize);
225 const size_t remotePage = pageSize - (remoteAddress % pageSize);
226 if (length > localPage)
228 if (length > remotePage)
233 if (!subsystem.matchesUserImage(image)) {
234 SYSCALL_ERROR(NoSuchProcess);
237 if (!permitted(caller, target)) {
238 SYSCALL_ERROR(NotEnoughPermissions);
242 bounce.get(),
reinterpret_cast<const void*
>(localAddress), length)) {
243 SYSCALL_ERROR(BadAddress);
247 manager.copyUserPage(*image.space, remoteAddress, bounce.get(), length, write);
248 if (status != MemoryMapManager::UserPageCopyStatus::Success) {
251 syscallError(status == MemoryMapManager::UserPageCopyStatus::Unsupported
252 ? Error::OperationNotSupported
253 : Error::BadAddress);
258 SYSCALL_ERROR(BadAddress);
262 localCursor.offset += length;
263 remoteCursor.offset += length;
265#if PEDIGREE_PROCESS_MEMORY_TESTS
266 if (__atomic_load_n(&fragmentCaller, __ATOMIC_ACQUIRE) == thread) {
267 const auto hook = __atomic_load_n(&fragmentHook, __ATOMIC_ACQUIRE);
269 hook(copied, __atomic_load_n(&fragmentContext, __ATOMIC_ACQUIRE));
273 return completion.finish(copied ?
static_cast<ssize_t
>(copied) : -1);
277#if PEDIGREE_PROCESS_MEMORY_TESTS
278void setProcessVmAfterFragmentHookForTest(
Thread* expectedCaller, ProcessVmAfterFragmentHook hook,
281 __atomic_store_n(&fragmentCaller,
static_cast<Thread*
>(
nullptr), __ATOMIC_RELEASE);
282 __atomic_store_n(&fragmentHook, hook, __ATOMIC_RELEASE);
283 __atomic_store_n(&fragmentContext, context, __ATOMIC_RELEASE);
284 __atomic_store_n(&fragmentCaller, expectedCaller, __ATOMIC_RELEASE);
288ssize_t posix_process_vm_readv(
int pid,
const iovec* local,
size_t localCount,
const iovec* remote,
289 size_t remoteCount,
unsigned long flags) {
290 return transfer(pid, local, localCount, remote, remoteCount, flags,
false);
293ssize_t posix_process_vm_writev(
int pid,
const iovec* local,
size_t localCount,
const iovec* remote,
294 size_t remoteCount,
unsigned long flags) {
295 return transfer(pid, local, localCount, remote, remoteCount, flags,
true);
Memory-mapped file interface.
static MemoryMapManager & instance()
static constexpr size_t getPageSize() PURE
static bool copyFromUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static ProcessorInformation & information()
static Scheduler & instance()
@ Continue
No unwind necessary, carry on as normal.
Process * getParent() const