The Pedigree Project 0.1
VirtualAddressSpace-internal.h
1#ifndef KERNEL_X64_VIRTUALADDRESSSPACE_INTERNAL_H
2#define KERNEL_X64_VIRTUALADDRESSSPACE_INTERNAL_H
3#include "pedigree/kernel/Spinlock.h"
4#include "pedigree/kernel/panic.h"
5#include "pedigree/kernel/processor/Processor.h"
6
7#include "utils.h"
8
9//
10// Page Table/Directory entry flags
11//
12#define PAGE_PRESENT 0x01
13#define PAGE_WRITE 0x02
14#define PAGE_USER 0x04
15#define PAGE_WRITE_COMBINE 0x08
16#define PAGE_CACHE_DISABLE 0x10
17#define PAGE_ACCESSED 0x20
18#define PAGE_DIRTY 0x40
19#define PAGE_2MB 0x80
20#define PAGE_PAT 0x80
21#define PAGE_GLOBAL 0x100
22#define PAGE_SWAPPED 0x200
23#define PAGE_COPY_ON_WRITE 0x400
24#define PAGE_SHARED 0x800
25// Software bits outside the physical address and protection-key fields.
26#define PAGE_RUNTIME (1ULL << 55)
27#define PAGE_BORROWED (1ULL << 56)
28#define PAGE_NO_ACCESS (1ULL << 57)
29#define PAGE_WRITE_PROTECTED (1ULL << 58)
30#define PAGE_NX 0x8000000000000000
31#define PAGE_WRITE_THROUGH (PAGE_PAT | PAGE_WRITE_COMBINE)
32
33//
34// Macros
35//
36#define PML4_INDEX(x) ((reinterpret_cast<uintptr_t>(x) >> 39) & 0x1FF)
37#define PAGE_DIRECTORY_POINTER_INDEX(x) ((reinterpret_cast<uintptr_t>(x) >> 30) & 0x1FF)
38#define PAGE_DIRECTORY_INDEX(x) ((reinterpret_cast<uintptr_t>(x) >> 21) & 0x1FF)
39#define PAGE_TABLE_INDEX(x) ((reinterpret_cast<uintptr_t>(x) >> 12) & 0x1FF)
40
41#define TABLE_ENTRY(table, index) (&physicalAddress(reinterpret_cast<uint64_t*>(table))[index])
42
43#define PAGE_GET_FLAGS(x) (*x & 0x8780000000000FFFULL)
44#define PAGE_SET_FLAGS(x, f) *x = (*x & ~0x8780000000000FFFULL) | f
45#define PAGE_GET_PHYSICAL_ADDRESS(x) (*x & ~0x8780000000000FFFULL)
46
47static void beginMappingInvalidation(TlbInvalidationGuard& invalidation) {
48 switch (Processor::beginTlbInvalidation(invalidation)) {
49 case TlbInvalidationResult::Success:
50 return;
51 case TlbInvalidationResult::InvalidContext:
52 panic("Mapping mutation started from an invalid TLB-shootdown context");
53 case TlbInvalidationResult::UnsupportedTopology:
54 panic("Mapping mutation has no safe all-processor TLB route");
55 case TlbInvalidationResult::SerialisationTimedOut:
58 while (true) {
60 }
61 }
62 panic("Mapping mutation admission timed out");
63 case TlbInvalidationResult::SubmissionFailed:
64 case TlbInvalidationResult::AcknowledgementTimedOut:
65 case TlbInvalidationResult::DrainTimedOut:
66 panic("Mapping mutation admission returned an invalid phase result");
67 }
68 panic("Mapping mutation admission returned an unknown result");
69}
70
71static const char* mappingInvalidationFailureMessage(TlbInvalidationResult result) {
72 switch (result) {
73 case TlbInvalidationResult::InvalidContext:
74 return "Mapping changed from an invalid TLB-shootdown context";
75 case TlbInvalidationResult::UnsupportedTopology:
76 return "Mapping has no safe all-processor TLB route";
77 case TlbInvalidationResult::SerialisationTimedOut:
78 return "Cross-processor TLB shootdown serialisation timed out";
79 case TlbInvalidationResult::SubmissionFailed:
80 return "Cross-processor TLB shootdown IPI submission failed";
81 case TlbInvalidationResult::AcknowledgementTimedOut:
82 return "Cross-processor TLB shootdown acknowledgement timed out";
83 case TlbInvalidationResult::DrainTimedOut:
84 return "Cross-processor TLB shootdown service drain timed out";
85 case TlbInvalidationResult::Success:
86 break;
87 }
88 return "Cross-processor TLB shootdown returned an unknown result";
89}
90
97 public:
99 : m_Invalidation(),
100 m_RestoreInterrupts(Processor::getInterrupts()),
101 m_Locks(),
102 m_LockCount(0),
103 m_Result(TlbInvalidationResult::Success),
104 m_Coordinator(false),
105 m_Finished(false) {
106 beginMappingInvalidation(m_Invalidation);
107 }
108
110 finish(true);
111 }
112
113 void lock(Spinlock& lock) {
114 lock.acquire();
115 m_Locks[m_LockCount].lock = &lock;
116 m_Locks[m_LockCount].owned = true;
117 ++m_LockCount;
118 }
119
120 void unlock(Spinlock& lock) {
121 for (size_t i = m_LockCount; i > 0; --i) {
122 LockState& state = m_Locks[i - 1];
123 if (state.lock == &lock && state.owned) {
124 lock.exit();
125 state.owned = false;
126 return;
127 }
128 }
129 panicWithoutRestoringInterrupts("Mapping mutation released an unowned VAS lock");
130 }
131
132 void relock(Spinlock& lock) {
133 for (size_t i = 0; i < m_LockCount; ++i) {
134 LockState& state = m_Locks[i];
135 if (state.lock == &lock && !state.owned) {
136 lock.acquire();
137 state.owned = true;
138 return;
139 }
140 }
141 panicWithoutRestoringInterrupts("Mapping mutation reacquired an unknown VAS lock");
142 }
143
144 bool invalidate(void* virtualAddress) {
145 m_Result = Processor::invalidateAll(virtualAddress, m_Invalidation);
146 if (m_Result == TlbInvalidationResult::Success) {
147 return true;
148 }
149
150 m_Coordinator = m_Invalidation.closeAdmissionForTerminalFailure(m_Result);
151 return false;
152 }
153
154 bool failed() const {
155 return m_Result != TlbInvalidationResult::Success;
156 }
157
158 void panicInvalidationFailure() NORETURN {
159 const TlbInvalidationResult result = m_Result;
160 const bool coordinator = m_Coordinator;
161 finish(false);
162
163 if (!coordinator) {
164 while (true) {
166 }
167 }
168 panic(mappingInvalidationFailureMessage(result));
169 }
170
171 void panicWithoutRestoringInterrupts(const char* message) NORETURN {
172 finish(false);
173 panic(message);
174 }
175
176 private:
177 struct LockState {
178 Spinlock* lock;
179 bool owned;
180 };
181
182 void finish(bool restoreInterrupts) {
183 if (m_Finished) {
184 return;
185 }
186
188 for (size_t i = m_LockCount; i > 0; --i) {
189 LockState& state = m_Locks[i - 1];
190 if (state.owned) {
191 state.lock->exit();
192 state.owned = false;
193 }
194 }
195 m_Invalidation.retire();
196 m_Finished = true;
197
198 if (restoreInterrupts && m_RestoreInterrupts) {
200 }
201 }
202
203 TlbInvalidationGuard m_Invalidation;
204 bool m_RestoreInterrupts;
205 LockState m_Locks[2];
206 size_t m_LockCount;
207 TlbInvalidationResult m_Result;
208 bool m_Coordinator;
209 bool m_Finished;
210};
211
212#endif
static bool getInterrupts()
static MUST_USE_RESULT TlbInvalidationResult invalidateAll(void *pAddress)
static void pause()
static bool tlbInvalidationFailureActive()
static void setInterrupts(bool bEnable)
static MUST_USE_RESULT TlbInvalidationResult beginTlbInvalidation(TlbInvalidationGuard &guard)
bool acquire(bool recurse=false, bool safe=true)
Definition Spinlock.cc:35
void exit(uintptr_t ra=0)
Definition Spinlock.cc:157
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition panic.cc:117
MUST_USE_RESULT bool closeAdmissionForTerminalFailure(TlbInvalidationResult result)
Definition Processor.h:535
TlbInvalidationResult
Definition Processor.h:55