2#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
3#include "pedigree/kernel/processor/UserMemoryPolicy.h"
4#include "pedigree/kernel/processor/VirtualAddressSpace.h"
5#include "pedigree/kernel/utilities/Vector.h"
6#include "pedigree/kernel/utilities/assert.h"
9constexpr size_t MaximumRawSegments = 4096;
13bool validRange(uintptr_t base,
size_t length) {
14 return !(base % pageSize()) && !(length % pageSize()) && length <= ~uintptr_t(0) - base;
26 bool complete =
false;
31 explicit Plan(
RawUserMemory& owner) : owner(owner), epoch(owner.m_State.get()->epoch) {}
32 size_t removedPages()
const override {
35 size_t addedPages()
const override {
38 size_t coveredPages()
const override {
41 size_t eligiblePages()
const override {
44 size_t removedRangeCount()
const override {
45 return retired.
count();
48 return retired.
count() ? &retired[0] :
nullptr;
50 void commit()
override {
51 assert(!committed && owner.m_State.get()->epoch == epoch);
53 for (
size_t offset = 0; offset < region.length; offset += pageSize()) {
54 physical_uintptr_t physical = 0;
56 void* address =
reinterpret_cast<void*
>(region.base + offset);
57 if (owner.m_Space.detachMapping(address, physical, flags) &&
63 owner.m_State.get()->entries.swap(entries);
64 ++owner.m_State.get()->epoch;
67 PopulationStatus populate()
override {
68 for (
const UserRegion& region : populateRegions) {
69 for (
size_t offset = 0; offset < region.length; offset += pageSize()) {
70 void* address =
reinterpret_cast<void*
>(region.base + offset);
71 if (!owner.m_Space.isMapped(address))
72 return PopulationStatus::Inaccessible;
73 physical_uintptr_t physical = 0;
75 owner.m_Space.getMapping(address, physical, flags);
77 return PopulationStatus::Inaccessible;
80 return PopulationStatus::Inaccessible;
81 if (!owner.m_Space.handleCopyOnWriteFault(address,
true))
82 return PopulationStatus::NoMemory;
86 return PopulationStatus::Success;
89 if (!entry.region.length)
91 if (entries.count() == MaximumRawSegments || !entries.tryReserve(entries.count() + 1))
93 entries.pushBack(entry);
96 bool appendPart(
const State::Entry& entry, uintptr_t base,
size_t length, MemoryLockMode mode) {
98 part.region.base = base;
99 part.region.length = length;
103 bool retire(
const State::Entry& entry, uintptr_t base,
size_t length) {
106 if (!retired.tryReserve(retired.
count() + 1))
109 if (entry.mode != MemoryLockMode::None)
110 removed += length / pageSize();
116 if (!populateRegions.tryReserve(populateRegions.
count() + 1))
121 bool addRegion(
UserRegion region, MemoryLockMode mode) {
125 if (policy->overlapsManagedMemory(owner.m_Space, region.base, region.length))
128 for (
const auto& entry : entries) {
129 if (entry.region.base < region.base + region.length &&
130 region.base < entry.region.base + entry.region.length)
133 if (!append({region, mode}))
135 if (mode != MemoryLockMode::None)
136 added += region.length / pageSize();
137 return mode != MemoryLockMode::Eager || populateLater(region);
140 for (
size_t i = 1; i < entries.count(); ++i) {
143 while (j && entries[j - 1].region.base > value.region.base) {
144 entries[j] = entries[j - 1];
150 for (
size_t i = 0; i < entries.count(); ++i) {
151 const auto& current = entries[i];
153 auto& previous = entries[kept - 1];
154 if (previous.region.id == current.region.id && previous.mode == current.mode &&
155 previous.region.base + previous.region.length == current.region.base &&
156 previous.region.kind == current.region.kind &&
157 previous.region.privateWritable == current.region.privateWritable) {
158 previous.region.length += current.region.length;
162 entries[kept++] = current;
164 while (entries.count() > kept)
182 size_t removed = 0, added = 0, covered = 0, eligible = 0;
183 bool committed =
false;
187RawUserMemory::~RawUserMemory() =
default;
189uint64_t RawUserMemory::nextRegionId() {
192 if (!m_State || !m_State.get()->nextId)
194 return m_State.get()->nextId++;
197bool RawUserMemory::completeInventory()
const {
198 return m_State && m_State.get()->complete;
200void RawUserMemory::setCompleteInventory(
bool complete) {
204 m_State.get()->complete = complete;
208 if (!m_State || !length || length > ~uintptr_t(0) - base)
210 const uintptr_t end = base + length;
211 for (
const auto& entry : m_State.get()->entries) {
212 const uintptr_t regionEnd = entry.region.base + entry.region.length;
213 if (regionEnd <= base)
215 if (entry.region.base > base)
217 if (regionEnd >= end)
224bool RawUserMemory::hasLockedMemory(uintptr_t base,
size_t length)
const {
225 if (!m_State || length > ~uintptr_t(0) - base)
227 for (
const auto& entry : m_State.get()->entries) {
228 if (entry.mode != MemoryLockMode::None && entry.region.base < base + length &&
229 base < entry.region.base + entry.region.length)
235MemoryLockStatus RawUserMemory::prepareChange(
const UserRegion* previous,
238 if ((!previous && !replacement) ||
239 (previous && (!previous->id || !validRange(previous->base, previous->length))) ||
240 (replacement && (!replacement->id || !validRange(replacement->base, replacement->length))) ||
241 (previous && replacement && previous->id != replacement->id))
242 return MemoryLockStatus::InvalidRange;
244 Plan* plan = Plan::create(*
this, prepared);
246 return MemoryLockStatus::NoMemory;
247 for (
const auto& entry : m_State.get()->entries) {
248 if (!previous || entry.region.id != previous->id) {
249 if (!plan->append(entry))
250 return MemoryLockStatus::NoMemory;
253 const uintptr_t end = entry.region.base + entry.region.length;
254 const uintptr_t keepStart = replacement && replacement->base > entry.region.base
257 const uintptr_t replacementEnd = replacement ? replacement->base + replacement->length : 0;
258 const uintptr_t keepEnd = replacementEnd < end ? replacementEnd : end;
259 if (!replacement || keepStart >= keepEnd) {
260 if (!plan->retire(entry, entry.region.base, entry.region.length))
261 return MemoryLockStatus::NoMemory;
262 }
else if (!plan->retire(entry, entry.region.base, keepStart - entry.region.base) ||
263 !plan->appendPart(entry, keepStart, keepEnd - keepStart, entry.mode) ||
264 !plan->retire(entry, keepEnd, end - keepEnd)) {
265 return MemoryLockStatus::NoMemory;
270 const MemoryLockMode future = account ? account->futureMode() : MemoryLockMode::None;
273 if (!plan->addRegion(added, future))
274 return MemoryLockStatus::NoMemory;
278 if (replacement->base < previous->base) {
279 added.length = previous->base - replacement->base;
280 if (added.length > replacement->length)
281 added.length = replacement->length;
282 if (!plan->addRegion(added, future))
283 return MemoryLockStatus::NoMemory;
285 const uintptr_t oldEnd = previous->base + previous->length;
286 const uintptr_t newEnd = replacement->base + replacement->length;
287 if (newEnd > oldEnd) {
288 added.base = oldEnd > replacement->base ? oldEnd : replacement->base;
289 added.length = newEnd - added.base;
290 if (!plan->addRegion(added, future))
291 return MemoryLockStatus::NoMemory;
296 result = pedigree_std::move(prepared);
297 return MemoryLockStatus::Success;
302 if (!validRange(base, length))
303 return MemoryLockStatus::InvalidRange;
304 bool overlaps =
false;
305 if (m_State && length) {
306 const uintptr_t end = base + length;
307 for (
const auto& entry : m_State.get()->entries) {
308 if (entry.region.base >= end)
310 if (base < entry.region.base + entry.region.length) {
318 return MemoryLockStatus::Success;
321 Plan* plan = Plan::create(*
this, prepared);
323 return MemoryLockStatus::NoMemory;
324 for (
const auto& entry : m_State.get()->entries) {
325 const uintptr_t end = entry.region.base + entry.region.length;
326 const uintptr_t first = base > entry.region.base ? base : entry.region.base;
327 const uintptr_t last = base + length < end ? base + length : end;
329 if (!plan->append(entry))
330 return MemoryLockStatus::NoMemory;
332 plan->covered += (last - first) / pageSize();
333 if (!plan->appendPart(entry, entry.region.base, first - entry.region.base, entry.mode) ||
334 !plan->retire(entry, first, last - first) ||
335 !plan->appendPart(entry, last, end - last, entry.mode))
336 return MemoryLockStatus::NoMemory;
340 result = pedigree_std::move(prepared);
341 return MemoryLockStatus::Success;
344MemoryLockStatus RawUserMemory::prepareLocks(uintptr_t base,
size_t length, MemoryLockMode mode,
346 if (!validRange(base, length))
347 return MemoryLockStatus::InvalidRange;
349 Plan* plan = Plan::create(*
this, prepared);
351 return MemoryLockStatus::NoMemory;
352 for (
const auto& entry : m_State.get()->entries) {
353 const uintptr_t end = entry.region.base + entry.region.length;
354 const uintptr_t first = base > entry.region.base ? base : entry.region.base;
355 const uintptr_t last = base + length < end ? base + length : end;
357 if (!plan->append(entry))
358 return MemoryLockStatus::NoMemory;
361 const size_t pages = (last - first) / pageSize();
362 plan->covered += pages;
363 plan->eligible += pages;
364 if (entry.mode != MemoryLockMode::None)
365 plan->removed += pages;
366 if (mode != MemoryLockMode::None)
367 plan->added += pages;
368 if (!plan->appendPart(entry, entry.region.base, first - entry.region.base, entry.mode) ||
369 !plan->appendPart(entry, first, last - first, mode) ||
370 !plan->appendPart(entry, last, end - last, entry.mode))
371 return MemoryLockStatus::NoMemory;
372 if (mode == MemoryLockMode::Eager) {
375 region.length = last - first;
376 if (!plan->populateLater(region))
377 return MemoryLockStatus::NoMemory;
381 plan->covered += m_Space.runtimeMappingPages(base, length);
383 result = pedigree_std::move(prepared);
384 return MemoryLockStatus::Success;
387MemoryLockStatus RawUserMemory::prepareAllLocks(MemoryLockMode mode,
389 if (mode != MemoryLockMode::None && !completeInventory())
390 return MemoryLockStatus::Unsupported;
392 Plan* plan = Plan::create(*
this, prepared);
394 return MemoryLockStatus::NoMemory;
395 for (
const auto& entry : m_State.get()->entries) {
396 const size_t pages = entry.region.length / pageSize();
397 plan->covered += pages;
398 plan->eligible += pages;
399 if (entry.mode != MemoryLockMode::None)
400 plan->removed += pages;
401 if (mode != MemoryLockMode::None)
402 plan->added += pages;
403 if (!plan->appendPart(entry, entry.region.base, entry.region.length, mode) ||
404 (mode == MemoryLockMode::Eager && !plan->populateLater(entry.region)))
405 return MemoryLockStatus::NoMemory;
408 result = pedigree_std::move(prepared);
409 return MemoryLockStatus::Success;
412MemoryLockStatus RawUserMemory::cloneInto(
RawUserMemory& target) {
414 return MemoryLockStatus::InvalidRange;
417 return MemoryLockStatus::NoMemory;
419 copied.get()->complete = m_State.get()->complete;
420 copied.get()->nextId = m_State.get()->nextId;
421 if (!copied.get()->entries.tryReserve(m_State.get()->entries.count()))
422 return MemoryLockStatus::NoMemory;
423 for (
auto entry : m_State.get()->entries) {
424 entry.mode = MemoryLockMode::None;
425 copied.get()->entries.pushBack(entry);
428 target.m_State = pedigree_std::move(copied);
429 return MemoryLockStatus::Success;
432void RawUserMemory::clear() {
434 m_State.get()->entries.clear();
435 m_State.get()->complete =
false;
436 ++m_State.get()->epoch;
439 auto charge = account->charge();
441 account->publish(charge, account->futureMode());
445size_t RawUserMemory::retireRegion(uint64_t
id) {
448 State& state = *m_State.get();
449 size_t kept = 0, removed = 0;
450 for (
size_t i = 0; i < state.entries.count(); ++i) {
451 const State::Entry entry = state.entries[i];
452 if (entry.region.id !=
id) {
453 state.entries[kept++] = entry;
456 if (entry.mode != MemoryLockMode::None)
457 removed += entry.region.length / pageSize();
458 for (
size_t offset = 0; offset < entry.region.length; offset += pageSize()) {
459 physical_uintptr_t physical = 0;
461 if (m_Space.
detachMapping(
reinterpret_cast<void*
>(entry.region.base + offset), physical,
468 while (state.entries.count() > kept)
469 state.entries.popBack();
static PhysicalMemoryManager & instance()
static constexpr size_t getPageSize() PURE
virtual void freePage(physical_uintptr_t page)=0
bool covers(uintptr_t base, size_t length) const
MemoryLockStatus prepareReplacement(uintptr_t base, size_t length, UniquePointer< PreparedMemoryLock > &result)
static UniquePointer< T > adopt(T *pointer)
A vector / dynamic array.
static const size_t CopyOnWrite
static const size_t Borrowed
static const size_t Shared
static const size_t KernelMode
static const size_t NoAccess
virtual bool detachMapping(void *virtualAddress, physical_uintptr_t &physical, size_t &flags, size_t requiredFlags=0)
static const size_t WriteProtected
static const size_t Swapped
void pushBack(const T &value)