The Pedigree Project 0.1
memory-lock-syscalls.cc
1/* Copyright (c) 2026, Pedigree Developers. */
2#include "pedigree/kernel/process/Process.h"
3#include "pedigree/kernel/process/Thread.h"
4#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
5#include "pedigree/kernel/processor/Processor.h"
6#include "pedigree/kernel/processor/VirtualAddressSpace.h"
7#include "pedigree/kernel/syscallError.h"
8
9#include "PosixSubsystem.h"
11#include "user-namespace.h"
12#include "vm-syscalls.h"
13
14namespace {
15constexpr unsigned OnFault = 1;
16constexpr int Current = 1, Future = 2, AllOnFault = 4;
17
18int lockResult(MemoryLockStatus status) {
19 switch (status) {
20 case MemoryLockStatus::Success:
21 Processor::information().getCurrentThread()->setErrno(0);
22 return 0;
23 case MemoryLockStatus::InvalidRange:
24 SYSCALL_ERROR(InvalidArgument);
25 break;
26 case MemoryLockStatus::Unsupported:
27 SYSCALL_ERROR(OperationNotSupported);
28 break;
29 case MemoryLockStatus::PopulationNoMemory:
30 SYSCALL_ERROR(NoMoreProcesses);
31 break;
32 case MemoryLockStatus::PopulationIoError:
33 SYSCALL_ERROR(IoError);
34 break;
35 case MemoryLockStatus::NoMemory:
36 case MemoryLockStatus::Unmapped:
37 case MemoryLockStatus::LockLimit:
38 case MemoryLockStatus::PopulationInaccessible:
39 SYSCALL_ERROR(OutOfMemory);
40 break;
41 }
42 return -1;
43}
44
45bool mayLock(PosixSubsystem& subsystem, bool privileged) {
46 if (!privileged && !subsystem.memoryLockAccount().limit().current) {
47 SYSCALL_ERROR(NotEnoughPermissions);
48 return false;
49 }
50 return true;
51}
52
53int lockRange(const void* address, size_t length, MemoryLockMode mode) {
54 GRAB_POSIX_SUBSYSTEM(-1);
56 MemoryMapManager::OperationGuard operation(manager);
57 auto& space = Processor::information().getVirtualAddressSpace();
58 const bool privileged = posix_global_capable(14);
59 if (mode != MemoryLockMode::None && !mayLock(*pSubsystem, privileged))
60 return -1;
61
62 const size_t mask = PhysicalMemoryManager::getPageSize() - 1;
63 const uintptr_t at = reinterpret_cast<uintptr_t>(address);
64 const uintptr_t base = at & ~mask;
65 if (length > ~size_t(0) - (at & mask) || length + (at & mask) > ~size_t(0) - mask)
66 return lockResult(MemoryLockStatus::InvalidRange);
67 const size_t extent = (length + (at & mask) + mask) & ~mask;
68 if (extent > ~uintptr_t(0) - base)
69 return lockResult(MemoryLockStatus::InvalidRange);
70 if (!extent)
71 return lockResult(MemoryLockStatus::Success);
72 if (base < space.getUserStart() || base >= space.getKernelStart() ||
73 extent > space.getKernelStart() - base ||
74 !space.isAddressValid(reinterpret_cast<void*>(base)) ||
75 !space.isAddressValid(reinterpret_cast<void*>(base + extent - 1)))
76 return lockResult(MemoryLockStatus::Unmapped);
77 return lockResult(manager.lockMemory(space, base, extent, mode, privileged));
78}
79} // namespace
80
81int posix_mlock(const void* address, size_t length, unsigned int flags) {
82 if (flags & ~OnFault) {
83 SYSCALL_ERROR(InvalidArgument);
84 return -1;
85 }
86 return lockRange(address, length,
87 flags & OnFault ? MemoryLockMode::OnFault : MemoryLockMode::Eager);
88}
89
90int posix_munlock(const void* address, size_t length) {
91 return lockRange(address, length, MemoryLockMode::None);
92}
93
94int posix_mlockall(int flags) {
95 if (!flags || flags & ~(Current | Future | AllOnFault) || flags == AllOnFault) {
96 SYSCALL_ERROR(InvalidArgument);
97 return -1;
98 }
99 GRAB_POSIX_SUBSYSTEM(-1);
100 auto& manager = MemoryMapManager::instance();
101 MemoryMapManager::OperationGuard operation(manager);
102 const bool privileged = posix_global_capable(14);
103 if (!mayLock(*pSubsystem, privileged))
104 return -1;
105 const auto mode = flags & AllOnFault ? MemoryLockMode::OnFault : MemoryLockMode::Eager;
106 return lockResult(
107 manager.lockAllMemory(Processor::information().getVirtualAddressSpace(), flags & Current,
108 mode, flags & Future ? mode : MemoryLockMode::None, privileged));
109}
110
111int posix_munlockall() {
112 GRAB_POSIX_SUBSYSTEM(-1);
113 return lockResult(MemoryMapManager::instance().lockAllMemory(
114 Processor::information().getVirtualAddressSpace(), true, MemoryLockMode::None,
115 MemoryLockMode::None, false));
116}
Memory-mapped file interface.
static MemoryMapManager & instance()
static ProcessorInformation & information()