The Pedigree Project 0.1
arm64/Processor.cc
1#include "pedigree/kernel/BootstrapInfo.h"
2#include "pedigree/kernel/machine/Machine.h"
3#include "pedigree/kernel/process/initialiseMultitasking.h"
4#include "pedigree/kernel/processor/PageFaultHandler.h"
5#include "pedigree/kernel/processor/Processor.h"
6#include "pedigree/kernel/processor/state.h"
7#include "pedigree/kernel/utilities/StaticString.h"
8
9#include "PhysicalMemoryManager.h"
10#include "VirtualAddressSpace.h"
11
12extern "C" char arm64_boot_low_l0;
13extern "C" bool arm64SaveSchedulerState(SchedulerState* state);
14extern "C" void arm64RestoreSchedulerState(SchedulerState* state,
15 volatile uintptr_t* lock) NORETURN;
16extern "C" void arm64ReturnToUser(InterruptState* state, volatile uintptr_t* lock,
17 uintptr_t kernelStack) NORETURN;
18extern "C" void arm64JumpKernel(volatile uintptr_t* lock, uintptr_t address, uintptr_t stack,
19 uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4) NORETURN;
20extern "C" void arm64JumpUser(volatile uintptr_t* lock, uintptr_t address, uintptr_t stack,
21 uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4,
22 uintptr_t kernelStack) NORETURN;
23
24namespace {
25bool terminalTlbFailure = false;
26}
27
29 ProcessorInformation* current = &m_SafeBspProcessorInformation;
30 asm volatile("msr tpidr_el1, %0" : : "r"(current) : "memory");
31 Arm64PhysicalMemoryManager::instance().initialise(info);
33 m_Initialised = 1;
34}
35
37 initialiseMultitasking();
38 m_Initialised = 2;
39}
40
42 g_pBootstrapInfo = nullptr;
43}
44
46 shutdownMultitasking();
47}
48
50 auto& armSpace = static_cast<Arm64VirtualAddressSpace&>(addressSpace);
51 uintptr_t root = &addressSpace == &VirtualAddressSpace::getKernelAddressSpace()
52 ? reinterpret_cast<uintptr_t>(&arm64_boot_low_l0)
53 : armSpace.root();
54 uintptr_t current;
55 asm volatile("mrs %0, ttbr0_el1" : "=r"(current));
56 if ((current & ~uintptr_t(PAGE_SIZE - 1)) != root) {
57 asm volatile("dsb ishst\n\tmsr ttbr0_el1, %0\n\tisb\n\ttlbi vmalle1is\n\tdsb ish\n\tisb"
58 :
59 : "r"(root)
60 : "memory");
61 }
62 information().setVirtualAddressSpace(addressSpace);
63}
64
65bool ProcessorBase::saveState(SchedulerState& state) {
66 return arm64SaveSchedulerState(&state);
67}
68
69void ProcessorBase::restoreState(SchedulerState& state, volatile uintptr_t* lock) {
70 arm64RestoreSchedulerState(&state, lock);
71}
72
73void ProcessorBase::restoreState(SyscallState& state, volatile uintptr_t* lock) {
74 arm64ReturnToUser(&state, lock, information().getKernelStack());
75}
76
77void ProcessorBase::switchState(bool interrupts, SchedulerState& previous, SchedulerState& next,
78 volatile uintptr_t* lock) {
79 if (saveState(previous)) {
80 return;
81 }
82 setInterrupts(interrupts);
83 restoreState(next, lock);
84}
85
86void ProcessorBase::switchState(bool interrupts, SchedulerState& previous, SyscallState& next,
87 volatile uintptr_t* lock) {
88 if (saveState(previous)) {
89 return;
90 }
91 setInterrupts(interrupts);
92 restoreState(next, lock);
93}
94
95void ProcessorBase::saveAndJumpKernel(bool interrupts, SchedulerState& state,
96 volatile uintptr_t* lock, uintptr_t address, uintptr_t stack,
97 uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4) {
98 if (saveState(state)) {
99 return;
100 }
101 setInterrupts(interrupts);
102 jumpKernel(lock, address, stack, p1, p2, p3, p4);
103}
104
105void ProcessorBase::saveAndJumpUser(bool interrupts, SchedulerState& state,
106 volatile uintptr_t* lock, uintptr_t address, uintptr_t stack,
107 uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4) {
108 if (saveState(state)) {
109 return;
110 }
111 setInterrupts(interrupts);
112 jumpUser(lock, address, stack, p1, p2, p3, p4);
113}
114
115void ProcessorBase::jumpKernel(volatile uintptr_t* lock, uintptr_t address, uintptr_t stack,
116 uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4) {
117 arm64JumpKernel(lock, address, stack, p1, p2, p3, p4);
118}
119
120void ProcessorBase::jumpUser(volatile uintptr_t* lock, uintptr_t address, uintptr_t stack,
121 uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4) {
122 uintptr_t kernelStack = information().getKernelStack();
123 if (!kernelStack) {
124 kernelStack = getStackPointer();
125 }
126 arm64JumpUser(lock, address, stack, p1, p2, p3, p4, kernelStack);
127}
128
130 uintptr_t value;
131 asm volatile("mov %0, x29" : "=r"(value));
132 return value;
133}
134
136 uintptr_t value;
137 asm volatile("mov %0, sp" : "=r"(value));
138 return value;
139}
140
142 return reinterpret_cast<uintptr_t>(__builtin_return_address(0));
143}
144
145void ProcessorBase::setTlsBase(uintptr_t value) {
146 asm volatile("msr tpidr_el0, %0" : : "r"(value) : "memory");
147}
148
150 if (enable) {
151 asm volatile("msr daifclr, #2" : : : "memory");
152 } else {
153 asm volatile("msr daifset, #2" : : : "memory");
154 }
155}
156
158 uintptr_t daif;
159 asm volatile("mrs %0, daif" : "=r"(daif));
160 return !(daif & (1U << 7));
161}
162
164 asm volatile("brk #0");
165}
166
168 asm volatile("wfi");
169}
170
172 const bool enabled = getInterrupts();
173 setInterrupts(true);
174 asm volatile("wfi" : : : "memory");
175 if (!enabled) {
176 setInterrupts(false);
177 }
178}
179
181 asm volatile("yield");
182}
183
185 Machine::instance().finalShutdown(Machine::ShutdownType::Restart);
186 while (true) {
187 halt();
188 }
189}
190
192 return 0;
193}
194
195uintptr_t ProcessorBase::getDebugBreakpoint(size_t, DebugFlags::FaultType& type, size_t& length,
196 bool& enabled) {
197 type = DebugFlags::InstructionFetch;
198 length = 0;
199 enabled = false;
200 return 0;
201}
202
203void ProcessorBase::enableDebugBreakpoint(size_t, uintptr_t, DebugFlags::FaultType, size_t) {}
206 return 0;
207}
208void ProcessorBase::setSingleStep(bool enable, InterruptState& state) {
209 if (enable) {
210 state.pstate |= 1ULL << 21;
211 } else {
212 state.pstate &= ~(1ULL << 21);
213 }
214}
215
216void ProcessorBase::invalidate(void* address) {
217 asm volatile("dsb ishst" : : : "memory");
218 if (address) {
219 uintptr_t page = reinterpret_cast<uintptr_t>(address) >> 12;
220 asm volatile("tlbi vaae1is, %0" : : "r"(page) : "memory");
221 } else {
222 asm volatile("tlbi vmalle1is" : : : "memory");
223 }
224 asm volatile("dsb ish\n\tisb" : : : "memory");
225}
226
228 ExecutionContext context = executionContext();
229 if (terminalTlbFailure || guard.m_Active ||
230 (context != ExecutionContext::WaitableThread && context != ExecutionContext::AtomicThread)) {
231 return TlbInvalidationResult::InvalidContext;
232 }
233 guard.m_Active = true;
234 guard.m_Global = false;
235 return TlbInvalidationResult::Success;
236}
237
239 guard.m_Active = false;
240 guard.m_Global = false;
241}
242
245 if (!guard.m_Active || terminalTlbFailure) {
246 return false;
247 }
248 terminalTlbFailure = true;
249 return true;
250}
251
253 return terminalTlbFailure;
254}
256 return terminalTlbFailure;
257}
258
262 return result == TlbInvalidationResult::Success ? invalidateAll(address, guard) : result;
263}
264
266 if (!guard.m_Active) {
267 return TlbInvalidationResult::InvalidContext;
268 }
269 if (m_nProcessors != 1) {
270 return TlbInvalidationResult::UnsupportedTopology;
271 }
272 invalidate(address);
273 return TlbInvalidationResult::Success;
274}
275
276void ProcessorBase::invalidateICache(uintptr_t address) {
277 asm volatile("ic ivau, %0\n\tdsb ish\n\tisb" : : "r"(address) : "memory");
278}
279
280void ProcessorBase::invalidateDCache(uintptr_t address) {
281 asm volatile("dc ivac, %0\n\tdsb ish" : : "r"(address) : "memory");
282}
283
284void ProcessorBase::flushDCache(uintptr_t address) {
285 asm volatile("dc cvac, %0\n\tdsb ish" : : "r"(address) : "memory");
286}
287
288void ProcessorBase::flushDCacheAndInvalidateICache(uintptr_t start, uintptr_t end) {
289 uintptr_t ctr;
290 asm volatile("mrs %0, ctr_el0" : "=r"(ctr));
291 size_t dline = 4U << ((ctr >> 16) & 0xf);
292 size_t iline = 4U << (ctr & 0xf);
293 for (uintptr_t p = start & ~(dline - 1); p < end; p += dline) {
294 asm volatile("dc cvau, %0" : : "r"(p) : "memory");
295 }
296 asm volatile("dsb ish" : : : "memory");
297 for (uintptr_t p = start & ~(iline - 1); p < end; p += iline) {
298 asm volatile("ic ivau, %0" : : "r"(p) : "memory");
299 }
300 asm volatile("dsb ish\n\tisb" : : : "memory");
301}
302
304 uintptr_t midr;
305 asm volatile("mrs %0, midr_el1" : "=r"(midr));
306 text = "ARM64 (MIDR ";
307 text.append(midr, 16, 16, '0');
308 text += ")";
309}
310
312 return information().processorId();
313}
315 return m_nProcessors;
316}
virtual void finalShutdown(ShutdownType type)
Definition Machine.cc:73
static PageFaultHandler & instance()
static void restoreState(SchedulerState &state, volatile uintptr_t *pLock=0) NORETURN
static void halt()
static void jumpUser(volatile uintptr_t *pLock, uintptr_t address, uintptr_t stack, uintptr_t p1=0, uintptr_t p2=0, uintptr_t p3=0, uintptr_t p4=0) NORETURN
static uintptr_t getDebugStatus()
static uintptr_t getInstructionPointer()
static void flushDCache(uintptr_t nAddr)
static void invalidateICache(uintptr_t nAddr)
static bool getInterrupts()
static ProcessorId id()
static void reset()
static MUST_USE_RESULT TlbInvalidationResult invalidateAll(void *pAddress)
static void initialise2(const BootstrapStruct_t &Info) INITIALISATION_ONLY
second/last stage in the initialisation of the processor-specific interface
static void setTlsBase(uintptr_t newBase)
static void initialise1(const BootstrapStruct_t &Info) INITIALISATION_ONLY
first stage in the initialisation of the processor-specific interface
static void initialisationDone()
static ProcessorInformation & information()
static void identify(HugeStaticString &str)
static bool saveState(SchedulerState &state)
static bool tlbInvalidationTerminal()
static size_t getCount()
static void pause()
static uintptr_t getDebugBreakpoint(size_t nBpNumber, DebugFlags::FaultType &nFaultType, size_t &nLength, bool &bEnabled)
static bool tlbInvalidationFailureActive()
static void breakpoint()
static size_t m_Initialised
Definition Processor.h:475
static uintptr_t getStackPointer()
static void disableDebugBreakpoint(size_t nBpNumber)
static void switchAddressSpace(VirtualAddressSpace &AddressSpace)
static ExecutionContext executionContext()
Definition Processor.cc:109
static void flushDCacheAndInvalidateICache(uintptr_t startAddr, uintptr_t endAddr)
static void setSingleStep(bool bEnable, InterruptState &state)
static void switchState(bool bInterrupts, SchedulerState &a, SchedulerState &b, volatile uintptr_t *pLock=0)
static void endTlbInvalidation(TlbInvalidationGuard &guard)
static void invalidate(void *pAddress)
static uintptr_t getBasePointer()
static void jumpKernel(volatile uintptr_t *pLock, uintptr_t address, uintptr_t stack, uintptr_t p1=0, uintptr_t p2=0, uintptr_t p3=0, uintptr_t p4=0) NORETURN
static ProcessorInformation m_SafeBspProcessorInformation
Definition Processor.h:508
static void invalidateDCache(uintptr_t nAddr)
static void enableDebugBreakpoint(size_t nBpNumber, uintptr_t nLinearAddress, DebugFlags::FaultType nFaultType, size_t nLength)
static void saveAndJumpKernel(bool bInterrupts, SchedulerState &s, volatile uintptr_t *pLock, uintptr_t address, uintptr_t stack, uintptr_t p1=0, uintptr_t p2=0, uintptr_t p3=0, uintptr_t p4=0)
static void setInterrupts(bool bEnable)
static void deinitialise()
static MUST_USE_RESULT TlbInvalidationResult beginTlbInvalidation(TlbInvalidationGuard &guard)
static size_t getDebugBreakpointCount()
static void saveAndJumpUser(bool bInterrupts, SchedulerState &s, volatile uintptr_t *pLock, uintptr_t address, uintptr_t stack, uintptr_t p1=0, uintptr_t p2=0, uintptr_t p3=0, uintptr_t p4=0)
static MUST_USE_RESULT bool closeTlbInvalidationAdmissionForTerminalFailure(TlbInvalidationGuard &guard, TlbInvalidationResult result)
static void haltUntilInterrupt()
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
size_t ProcessorId
TlbInvalidationResult
Definition Processor.h:55