The Pedigree Project 0.1
Processor.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/process/Thread.h"
21#include "pedigree/kernel/processor/Processor.h"
22#include "pedigree/kernel/utilities/Vector.h"
23#include "pedigree/kernel/utilities/assert.h"
24#include "pedigree/kernel/utilities/new"
25
26#include "system/kernel/core/processor/DeviceHardIrqContext.h"
27
28#if HOSTED
29#include <unistd.h>
30#endif
31
33
36
37size_t ProcessorBase::m_nProcessors = 1;
38
39ProcessorInformation* ProcessorBase::informationAt(size_t cpu) {
40 if (cpu >= getCount())
41 return nullptr;
42 if (cpu < m_ProcessorInformation.count())
43 return m_ProcessorInformation[cpu];
44 return cpu == 0 && !m_ProcessorInformation.count() ? &m_SafeBspProcessorInformation : nullptr;
45}
46
47namespace {
48// Keep addressable kernel exports for modules built against the IRQ guard API.
49bool (*const inDeviceHardIrqEntry)() USED = &ProcessorBase::inDeviceHardIrq;
50bool (*const guardDeviceHardIrqOperationEntry)(DeviceHardIrqOperation) USED =
52
53#if HOSTED
54const char* deviceHardIrqViolationMessage(DeviceHardIrqOperation operation) {
55 switch (operation) {
56 case DeviceHardIrqOperation::Schedule:
57 return "Device hard-IRQ callback attempted to schedule.";
58 case DeviceHardIrqOperation::SemaphoreAcquire:
59 return "Device hard-IRQ callback attempted semaphore acquire.";
60 case DeviceHardIrqOperation::SemaphoreRelease:
61 return "Device hard-IRQ callback attempted semaphore release.";
62 case DeviceHardIrqOperation::WaitQueueAccess:
63 return "Device hard-IRQ callback attempted wait-queue access.";
64 case DeviceHardIrqOperation::HeapAllocate:
65 return "Device hard-IRQ callback attempted heap allocation.";
66 case DeviceHardIrqOperation::HeapFree:
67 return "Device hard-IRQ callback attempted heap free.";
68 }
69 return "Device hard-IRQ callback attempted a forbidden operation.";
70}
71#endif
72
73// Preserve the operation (plus one) for postmortem inspection before the
74// allocation-free terminal path stops the processor.
75volatile size_t g_DeviceHardIrqTerminalViolation = 0;
76
77void terminateDeviceHardIrqViolation(DeviceHardIrqOperation operation) NORETURN;
78void terminateDeviceHardIrqViolation(DeviceHardIrqOperation operation) {
79 __atomic_store_n(&g_DeviceHardIrqTerminalViolation, static_cast<size_t>(operation) + 1,
80 __ATOMIC_RELAXED);
81
82#if HOSTED
83 const char* message = deviceHardIrqViolationMessage(operation);
84 size_t length = 0;
85 while (message[length]) {
86 ++length;
87 }
88 (void)write(STDERR_FILENO, message, length);
89 (void)write(STDERR_FILENO, "\n", 1);
90 _exit(1);
91#else
93 while (true) {
95 }
96#endif
97}
98
99#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
100ProcessorBase::DeviceHardIrqOperationHook g_DeviceHardIrqOperationHook = nullptr;
101size_t g_DeviceHardIrqOperationDenials = 0;
102#endif
103} // namespace
104
106 return m_Initialised;
107}
108
110 Thread* current = information().getCurrentThread();
111 if (!current) {
112 return ExecutionContext::AtomicThread;
113 }
114
115 const ExecutionContext explicitContext = current->executionContext();
116 if (explicitContext != ExecutionContext::WaitableThread) {
117 return explicitContext;
118 }
119
120 return getInterrupts() ? ExecutionContext::WaitableThread : ExecutionContext::AtomicThread;
121}
122
123bool ProcessorBase::rejectDeviceHardIrqOperation(DeviceHardIrqOperation operation) {
124#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
125 DeviceHardIrqOperationHook hook =
126 __atomic_load_n(&g_DeviceHardIrqOperationHook, __ATOMIC_ACQUIRE);
127 if (hook && hook(operation)) {
128 __atomic_add_fetch(&g_DeviceHardIrqOperationDenials, static_cast<size_t>(1), __ATOMIC_RELAXED);
129 return false;
130 }
131#endif
132
133 // Logging, allocation, and debugger entry can all take guarded paths.
134 terminateDeviceHardIrqViolation(operation);
135}
136
137#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
138size_t ProcessorBase::deviceHardIrqDepthForTest() {
139 return information().m_DeviceHardIrqDepth;
140}
141
142void ProcessorBase::setDeviceHardIrqOperationHookForTest(DeviceHardIrqOperationHook hook) {
143 __atomic_store_n(&g_DeviceHardIrqOperationHook, hook, __ATOMIC_RELEASE);
144}
145
146size_t ProcessorBase::deviceHardIrqOperationDenialsForTest() {
147 return __atomic_load_n(&g_DeviceHardIrqOperationDenials, __ATOMIC_RELAXED);
148}
149#endif
150
151DeviceHardIrqContext::DeviceHardIrqContext(size_t& previousDepth, bool& restorationArmed)
152 : m_Information(Processor::information()),
153 m_RestorationArmed(restorationArmed),
154 m_PreviousDepth(m_Information.m_DeviceHardIrqDepth),
155 m_ExecutionContext(ExecutionContext::HardDeviceIrq) {
156 assert(!m_RestorationArmed);
157 previousDepth = m_PreviousDepth;
158 m_RestorationArmed = true;
159 ++m_Information.m_DeviceHardIrqDepth;
160}
161
162DeviceHardIrqContext::~DeviceHardIrqContext() {
163 assert(&Processor::information() == &m_Information);
164 assert(m_RestorationArmed);
165 restoreDepth(m_PreviousDepth);
166 m_RestorationArmed = false;
167}
168
169void DeviceHardIrqContext::restoreDepth(size_t previousDepth) {
170 Processor::information().m_DeviceHardIrqDepth = previousDepth;
171}
172
173SuspendDeviceHardIrqContext::SuspendDeviceHardIrqContext()
174 : m_Information(Processor::information()) {
175 assert(m_Information.m_DeviceHardIrqDepth == 1);
176 m_Information.m_DeviceHardIrqDepth = 0;
177}
178
179SuspendDeviceHardIrqContext::~SuspendDeviceHardIrqContext() {
180 assert(&Processor::information() == &m_Information);
181 assert(m_Information.m_DeviceHardIrqDepth == 0);
182 m_Information.m_DeviceHardIrqDepth = 1;
183}
184
185EnsureInterrupts::EnsureInterrupts(bool desired) {
186 EMIT_IF(!PEDIGREE_BENCHMARK) {
187 m_bPrevious = ProcessorBase::getInterrupts();
189 }
190}
191
192EnsureInterrupts::~EnsureInterrupts() {
193 EMIT_IF(!PEDIGREE_BENCHMARK) {
194 ProcessorBase::setInterrupts(m_bPrevious);
195 }
196}
static void restoreDepth(size_t previousDepth)
Definition Processor.cc:169
static void halt()
static bool getInterrupts()
static ProcessorInformation & information()
static size_t getCount()
static size_t m_Initialised
Definition Processor.h:483
static bool inDeviceHardIrq()
Definition Processor.h:581
static Vector< ProcessorInformation * > m_ProcessorInformation
Definition Processor.h:512
static bool guardDeviceHardIrqOperation(DeviceHardIrqOperation operation)
Definition Processor.h:585
static ExecutionContext executionContext()
Definition Processor.cc:109
static ProcessorInformation m_SafeBspProcessorInformation
Definition Processor.h:516
static ProcessorInformation * informationAt(size_t cpu)
Definition Processor.cc:39
static void setInterrupts(bool bEnable)
static size_t isInitialised()
Definition Processor.cc:105
ExecutionContext executionContext() const
Definition Thread.cc:836
A vector / dynamic array.
Definition Vector.h:33
DeviceHardIrqOperation
Definition Processor.h:46
size_t count() const
Definition Vector.h:270