The Pedigree Project 0.1
SwapStore.cc
1/* Copyright (c) 2026, Pedigree Developers. */
2#include "SwapStore.h"
3#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
4#include "pedigree/kernel/utilities/assert.h"
5#include "pedigree/kernel/utilities/new"
6#include "pedigree/kernel/utilities/utility.h"
7
9 struct Slot {
10 size_t references = 0;
11 uint32_t generation = 0;
12 } slots[MaximumPages];
13 PagingChannel channel;
14 alignas(16) unsigned char buffer[PagingChannel::PageBytes];
15 size_t pages = 0;
16 size_t used = 0;
17};
18
19SwapStore& SwapStore::instance() {
20 static SwapStore store;
21 return store;
22}
23bool SwapStore::prepareAtBoot() {
24#if (X64 || HOSTED) && THREADS
25 if (!m_State)
26 m_State = new State;
27 return m_State != nullptr;
28#else
29 return false;
30#endif
31}
32SwapStatus SwapStore::activate(uint32_t endpoint) {
33#if !(X64 || HOSTED) || !THREADS
34 return SwapStatus::Unsupported;
35#endif
36 if (!m_State)
37 return SwapStatus::NoMemory;
38 if (m_State->channel)
39 return SwapStatus::Busy;
40 switch (DiskEndpoints::prepare(endpoint, m_State->channel)) {
41 case PagingStatus::Success:
42 break;
43 case PagingStatus::Busy:
44 return SwapStatus::Busy;
45 case PagingStatus::NoMemory:
46 return SwapStatus::NoMemory;
47 case PagingStatus::Unsupported:
48 return SwapStatus::Unsupported;
49 case PagingStatus::Invalid:
50 case PagingStatus::Closed:
51 return SwapStatus::Invalid;
52 default:
53 return SwapStatus::IoError;
54 }
55 SwapStatus result = SwapStatus::IoError;
56 if (m_State->channel.readPage(0, m_State->buffer) == PagingStatus::Success)
57 result = validateHeader(m_State->buffer, m_State->channel.size(), m_State->pages);
58 if (result != SwapStatus::Success) {
59 m_State->pages = 0;
60 m_State->channel.reset();
61 }
62 return result;
63}
64SwapStatus SwapStore::finishDeactivate(uint32_t endpoint) {
65 if (!m_State || !m_State->channel || endpoint != m_State->channel.endpointId())
66 return SwapStatus::NotActive;
67 if (m_State->used)
68 return SwapStatus::Busy;
69 if (m_State->channel.flush() != PagingStatus::Success)
70 return SwapStatus::IoError;
71 m_State->channel.reset();
72 m_State->pages = 0;
73 return SwapStatus::Success;
74}
75SwapStatus SwapStore::writePage(physical_uintptr_t physical, SwapReference& result) {
76 if (result)
77 return SwapStatus::Invalid;
78 if (!m_State || !m_State->channel || !m_State->pages)
79 return SwapStatus::NotActive;
80 size_t index = 0;
81 for (; index < m_State->pages; ++index)
82 if (!m_State->slots[index].references && m_State->slots[index].generation != ~uint32_t(0))
83 break;
84 if (index == m_State->pages)
85 return SwapStatus::NoMemory;
86 if (!PhysicalMemoryManager::instance().copyPhysicalPageToBuffer(physical, m_State->buffer) ||
87 m_State->channel.writePage((index + 1) * PagingChannel::PageBytes, m_State->buffer) !=
88 PagingStatus::Success ||
89 m_State->channel.flush() != PagingStatus::Success)
90 return SwapStatus::IoError;
91 auto& slot = m_State->slots[index];
92 ++slot.generation;
93 slot.references = 1;
94 ++m_State->used;
95 result.value = (uint64_t(slot.generation) << 32) | (index + 1);
96 return SwapStatus::Success;
97}
98SwapStatus SwapStore::readPage(SwapReference reference, physical_uintptr_t physical) {
99 const size_t index = uint32_t(reference.value) - size_t(1);
100 if (!m_State || index >= m_State->pages || !m_State->slots[index].references ||
101 m_State->slots[index].generation != uint32_t(reference.value >> 32))
102 return SwapStatus::Invalid;
103 if (m_State->channel.readPage((index + 1) * PagingChannel::PageBytes, m_State->buffer) !=
104 PagingStatus::Success ||
105 !PhysicalMemoryManager::instance().copyPhysicalPageFromBuffer(physical, m_State->buffer))
106 return SwapStatus::IoError;
107 return SwapStatus::Success;
108}
109bool SwapStore::retain(SwapReference reference) {
110 const size_t index = uint32_t(reference.value) - size_t(1);
111 if (!m_State || index >= m_State->pages || !m_State->slots[index].references ||
112 m_State->slots[index].references == ~size_t(0) ||
113 m_State->slots[index].generation != uint32_t(reference.value >> 32))
114 return false;
115 ++m_State->slots[index].references;
116 return true;
117}
118void SwapStore::release(SwapReference& reference) {
119 if (!reference)
120 return;
121 const size_t index = uint32_t(reference.value) - size_t(1);
122 assert(m_State && index < m_State->pages && m_State->slots[index].references &&
123 m_State->slots[index].generation == uint32_t(reference.value >> 32));
124 if (!--m_State->slots[index].references)
125 --m_State->used;
126 reference.value = 0;
127}
128SwapSnapshot SwapStore::snapshot() const {
129 if (!m_State || !m_State->channel)
130 return {};
131 return {m_State->pages, m_State->used, true};
132}
133uint32_t SwapStore::endpointId() const {
134 return m_State ? m_State->channel.endpointId() : 0;
135}
136
137bool SwapStore::zeroPage(physical_uintptr_t physical) {
138 if (!m_State)
139 return false;
140 ByteSet(m_State->buffer, 0, PagingChannel::PageBytes);
141 return PhysicalMemoryManager::instance().copyPhysicalPageFromBuffer(physical, m_State->buffer);
142}
static PhysicalMemoryManager & instance()