The Pedigree Project 0.1
armv7/Processor.cc
1#include "pedigree/kernel/BootstrapInfo.h"
2#include "pedigree/kernel/machine/Machine.h"
3#include "pedigree/kernel/panic.h"
4#include "pedigree/kernel/process/initialiseMultitasking.h"
5#include "pedigree/kernel/processor/PageFaultHandler.h"
6#include "pedigree/kernel/processor/Processor.h"
7#include "pedigree/kernel/processor/state.h"
8
9#include "../../../machine/mach_virt/DeviceTree.h"
10#include "PhysicalMemoryManager.h"
11#include "VirtualAddressSpace.h"
12
13extern "C" bool armv7SaveSchedulerState(SchedulerState* state);
14extern "C" void armv7RestoreSchedulerState(SchedulerState* state,
15 volatile uintptr_t* lock) NORETURN;
16extern "C" void armv7ReturnToUser(InterruptState* state, volatile uintptr_t* lock,
17 uintptr_t kernelStack) NORETURN;
18extern "C" void armv7JumpKernel(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 armv7JumpUser(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("mcr p15, 0, %0, c13, c0, 4" : : "r"(current) : "memory");
31 if (!VirtDeviceTree::valid()) {
32 virtSetDeviceTree(reinterpret_cast<const void*>(0xc0000000U));
33 }
34 Armv7PhysicalMemoryManager::instance().initialise(info);
36 m_Initialised = 1;
37}
38
40 initialiseMultitasking();
41 m_Initialised = 2;
42}
43
45 g_pBootstrapInfo = nullptr;
46}
47
49 shutdownMultitasking();
50}
51
53 auto& armSpace = static_cast<Armv7VirtualAddressSpace&>(addressSpace);
54 uintptr_t root = armSpace.root();
55 uintptr_t current;
56 asm volatile("mrc p15, 0, %0, c2, c0, 0" : "=r"(current));
57 if ((current & ~uintptr_t(0x1fff)) != root) {
58 asm volatile("dsb sy\n\tmcr p15, 0, %0, c2, c0, 0\n\tisb" : : "r"(root) : "memory");
59 invalidate(nullptr);
60 }
61 information().setVirtualAddressSpace(addressSpace);
62}
63
64bool ProcessorBase::saveState(SchedulerState& state) {
65 return armv7SaveSchedulerState(&state);
66}
67
68void ProcessorBase::restoreState(SchedulerState& state, volatile uintptr_t* lock) {
69 armv7RestoreSchedulerState(&state, lock);
70}
71
72void ProcessorBase::restoreState(SyscallState& state, volatile uintptr_t* lock) {
73 armv7ReturnToUser(&state, lock, information().getKernelStack());
74}
75
76void ProcessorBase::switchState(bool interrupts, SchedulerState& previous, SchedulerState& next,
77 volatile uintptr_t* lock) {
78 if (saveState(previous)) {
79 return;
80 }
81 setInterrupts(interrupts);
82 restoreState(next, lock);
83}
84
85void ProcessorBase::switchState(bool interrupts, SchedulerState& previous, SyscallState& next,
86 volatile uintptr_t* lock) {
87 if (saveState(previous)) {
88 return;
89 }
90 setInterrupts(interrupts);
91 restoreState(next, lock);
92}
93
94void ProcessorBase::saveAndJumpKernel(bool interrupts, SchedulerState& state,
95 volatile uintptr_t* lock, uintptr_t address, uintptr_t stack,
96 uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4) {
97 if (saveState(state)) {
98 return;
99 }
100 setInterrupts(interrupts);
101 jumpKernel(lock, address, stack, p1, p2, p3, p4);
102}
103
104void ProcessorBase::saveAndJumpUser(bool interrupts, SchedulerState& state,
105 volatile uintptr_t* lock, uintptr_t address, uintptr_t stack,
106 uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4) {
107 if (saveState(state)) {
108 return;
109 }
110 setInterrupts(interrupts);
111 jumpUser(lock, address, stack, p1, p2, p3, p4);
112}
113
114void ProcessorBase::jumpKernel(volatile uintptr_t* lock, uintptr_t address, uintptr_t stack,
115 uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4) {
116 armv7JumpKernel(lock, address, stack, p1, p2, p3, p4);
117}
118
119void ProcessorBase::jumpUser(volatile uintptr_t* lock, uintptr_t address, uintptr_t stack,
120 uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4) {
121 uintptr_t kernelStack = information().getKernelStack();
122 if (!kernelStack) {
123 kernelStack = getStackPointer();
124 }
125 armv7JumpUser(lock, address, stack, p1, p2, p3, p4, kernelStack);
126}
127
129 uintptr_t value;
130 asm volatile("mov %0, fp" : "=r"(value));
131 return value;
132}
133
135 uintptr_t value;
136 asm volatile("mov %0, sp" : "=r"(value));
137 return value;
138}
139
141 return reinterpret_cast<uintptr_t>(__builtin_return_address(0));
142}
143
144void ProcessorBase::setTlsBase(uintptr_t value) {
145 asm volatile("mcr p15, 0, %0, c13, c0, 2" : : "r"(value) : "memory");
146 asm volatile("mcr p15, 0, %0, c13, c0, 3" : : "r"(value) : "memory");
147}
148
149void ProcessorBase::setInterrupts(bool enable) {
150 if (enable) {
151 asm volatile("cpsie i" : : : "memory");
152 } else {
153 asm volatile("cpsid i" : : : "memory");
154 }
155}
156
158 uintptr_t cpsr;
159 asm volatile("mrs %0, cpsr" : "=r"(cpsr));
160 return !(cpsr & (1U << 7));
161}
162
164 asm volatile("bkpt #0");
165}
166
167void ProcessorBase::halt() {
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}
208
209void ProcessorBase::invalidate(void* address) {
210 asm volatile("dsb sy" : : : "memory");
211 if (address) {
212 uintptr_t value = reinterpret_cast<uintptr_t>(address);
213 asm volatile("mcr p15, 0, %0, c8, c7, 1" : : "r"(value) : "memory");
214 } else {
215 uintptr_t zero = 0;
216 asm volatile("mcr p15, 0, %0, c8, c7, 0" : : "r"(zero) : "memory");
217 }
218 asm volatile("dsb sy\n\tisb" : : : "memory");
219}
220
222 ExecutionContext context = executionContext();
223 if (terminalTlbFailure || guard.m_Active ||
224 (context != ExecutionContext::WaitableThread && context != ExecutionContext::AtomicThread)) {
225 return TlbInvalidationResult::InvalidContext;
226 }
227 guard.m_Active = true;
228 guard.m_Global = false;
229 return TlbInvalidationResult::Success;
230}
231
233 guard.m_Active = false;
234 guard.m_Global = false;
235}
236
239 if (!guard.m_Active || terminalTlbFailure) {
240 return false;
241 }
242 terminalTlbFailure = true;
243 return true;
244}
245
247 return terminalTlbFailure;
248}
249
251 return terminalTlbFailure;
252}
253
257 return result == TlbInvalidationResult::Success ? invalidateAll(address, guard) : result;
258}
259
261 if (!guard.m_Active) {
262 return TlbInvalidationResult::InvalidContext;
263 }
264 if (m_nProcessors != 1) {
265 return TlbInvalidationResult::UnsupportedTopology;
266 }
267 invalidate(address);
268 return TlbInvalidationResult::Success;
269}
270
271void ProcessorBase::invalidateICache(uintptr_t address) {
272 asm volatile("mcr p15, 0, %0, c7, c5, 1\n\tdsb sy\n\tisb" : : "r"(address) : "memory");
273}
274
275void ProcessorBase::invalidateDCache(uintptr_t address) {
276 asm volatile("mcr p15, 0, %0, c7, c6, 1\n\tdsb sy" : : "r"(address) : "memory");
277}
278
279void ProcessorBase::flushDCache(uintptr_t address) {
280 asm volatile("mcr p15, 0, %0, c7, c10, 1\n\tdsb sy" : : "r"(address) : "memory");
281}
282
283void ProcessorBase::flushDCacheAndInvalidateICache(uintptr_t start, uintptr_t end) {
284 uintptr_t ctr;
285 asm volatile("mrc p15, 0, %0, c0, c0, 1" : "=r"(ctr));
286 const size_t dline = 4U << ((ctr >> 16) & 0xf);
287 const size_t iline = 4U << (ctr & 0xf);
288 for (uintptr_t p = start & ~(dline - 1); p < end; p += dline) {
289 asm volatile("mcr p15, 0, %0, c7, c11, 1" : : "r"(p) : "memory");
290 }
291 asm volatile("dsb sy" : : : "memory");
292 for (uintptr_t p = start & ~(iline - 1); p < end; p += iline) {
293 asm volatile("mcr p15, 0, %0, c7, c5, 1" : : "r"(p) : "memory");
294 }
295 asm volatile("dsb sy\n\tisb" : : : "memory");
296}
297
299 uintptr_t midr;
300 asm volatile("mrc p15, 0, %0, c0, c0, 0" : "=r"(midr));
301 text = "ARMv7 (MIDR ";
302 text.append(midr, 16, 8, '0');
303 text += ")";
304}
305
307 return information().processorId();
308}
309
311 return m_nProcessors;
312}
313
314extern "C" int __aeabi_idiv0(int) {
315 panic("ARMv7: divide by zero");
316}
317
318extern "C" long long __aeabi_ldiv0(long long) {
319 panic("ARMv7: divide by zero");
320}
virtual const char * finalShutdown(ShutdownType type)
Definition Machine.cc:93
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:483
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 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:516
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()
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition panic.cc:118
size_t ProcessorId
TlbInvalidationResult
Definition Processor.h:56