The Pedigree Project 0.1
hosted/ProcessorInformation.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/Log.h"
21#include "pedigree/kernel/process/PerProcessorScheduler.h"
22#include "pedigree/kernel/processor/Processor.h"
23#include "pedigree/kernel/processor/hosted/ProcessorInformation.h"
24#include "pedigree/kernel/processor/types.h"
25
26#include "VirtualAddressSpace.h"
27
28namespace __pedigree_hosted {};
29using namespace __pedigree_hosted;
30
31#include <errno.h>
32#include <pthread.h>
33#include <signal.h>
34
35#ifndef SS_AUTODISARM
36#define SS_AUTODISARM (1U << 31)
37#endif
38
39extern void* safe_stack_top;
40
41namespace {
42enum class HostedSignalStackMode : size_t {
43 Unprobed,
44 Autodisarm,
45 ExplicitHandoff,
46};
47
48size_t g_HostedSignalStackMode = static_cast<size_t>(HostedSignalStackMode::Unprobed);
49
50HostedSignalStackMode hostedSignalStackMode() {
51 return static_cast<HostedSignalStackMode>(
52 __atomic_load_n(&g_HostedSignalStackMode, __ATOMIC_ACQUIRE));
53}
54
55int desiredHostedSignalStackFlags() {
56 return hostedSignalStackMode() == HostedSignalStackMode::ExplicitHandoff ? 0 : SS_AUTODISARM;
57}
58} // namespace
59
61 : m_ProcessorId(processorId),
62 m_VirtualAddressSpace(&VirtualAddressSpace::getKernelAddressSpace()),
63 m_pCurrentThread(0),
64 m_Scheduler(0),
65 m_KernelStack(0),
66 m_HostedExecutionThreadId(0),
67 m_DeviceHardIrqDepth(0),
68 m_HostedSignalFrameDepth(0) {}
69
71
78
80 m_VirtualAddressSpace = &virtualAddressSpace;
81}
82
83Thread* HostedProcessorInformation::getCurrentThread() const {
84 return m_pCurrentThread;
85}
86
87void HostedProcessorInformation::setCurrentThread(Thread* pThread) {
88 if (m_RcuState.active()) {
89 panic("Context switch inside an RCU read section.");
90 }
91 m_pCurrentThread = pThread;
92}
93
94PerProcessorScheduler& HostedProcessorInformation::getScheduler() {
95 if (m_Scheduler == nullptr) {
97 }
98 return *m_Scheduler;
99}
100
110static int trickSigaltstack(stack_t* p) {
111 return callOnStack(reinterpret_cast<uintptr_t>(&safe_stack_top),
112 reinterpret_cast<uintptr_t>(sigaltstack), reinterpret_cast<uintptr_t>(p));
113}
114
115static void installHostedSignalStack(stack_t& stack) {
116 int result = sigaltstack(&stack, nullptr);
117 if (result < 0 && errno == EPERM) {
118 result = trickSigaltstack(&stack);
119 }
120
121 if (result < 0 && errno == EINVAL && (stack.ss_flags & SS_AUTODISARM) &&
122 hostedSignalStackMode() == HostedSignalStackMode::Unprobed) {
123 // Some Linux hosts reject AUTODISARM. Pedigree already installs the
124 // selected Thread/state stack at every context handoff, including via the
125 // scratch stack when the suspended stack is still active. That is the
126 // explicit equivalent needed to keep nested frames disjoint.
127 stack.ss_flags &= ~SS_AUTODISARM;
128 result = sigaltstack(&stack, nullptr);
129 if (result < 0 && errno == EPERM) {
130 result = trickSigaltstack(&stack);
131 }
132 if (result >= 0) {
133 __atomic_store_n(&g_HostedSignalStackMode,
134 static_cast<size_t>(HostedSignalStackMode::ExplicitHandoff),
135 __ATOMIC_RELEASE);
136 WARNING(
137 "Hosted signal stacks are using explicit scheduler "
138 "handoff because SS_AUTODISARM is unavailable");
139 return;
140 }
141 }
142
143 if (result >= 0) {
144 if (stack.ss_flags & SS_AUTODISARM) {
145 __atomic_store_n(&g_HostedSignalStackMode,
146 static_cast<size_t>(HostedSignalStackMode::Autodisarm), __ATOMIC_RELEASE);
147 }
148 return;
149 }
150
151 FATAL("Hosted failed to install a scheduler signal stack: errno=" << Dec << errno);
152}
153
154void HostedProcessorInformation::setKernelStack(uintptr_t stack) {
155#if defined(PEDIGREE_HOSTED_DARWIN) && PEDIGREE_HOSTED_DARWIN
156 m_KernelStack = stack;
157 return;
158#endif
159
160 sigset_t blockedSignals;
161 sigset_t previousSignals;
162 sigfillset(&blockedSignals);
163 if (pthread_sigmask(SIG_SETMASK, &blockedSignals, &previousSignals) != 0) {
164 FATAL("Hosted failed to mask signals for a scheduler stack handoff");
165 }
166
167 // Keep every catchable asynchronous handler off the shared scratch stack,
168 // and do not expose the new registered stack before its metadata agrees.
169 if (stack) {
170 void* new_sp = reinterpret_cast<void*>(stack - KERNEL_STACK_SIZE);
171 const int desiredFlags = desiredHostedSignalStackFlags();
172 stack_t s;
173 if (sigaltstack(nullptr, &s) < 0) {
174 FATAL("Hosted failed to inspect the scheduler signal stack");
175 }
176 if (s.ss_sp != new_sp || s.ss_size != KERNEL_STACK_SIZE || (s.ss_flags & SS_DISABLE) ||
177 (s.ss_flags & SS_AUTODISARM) != (desiredFlags & SS_AUTODISARM)) {
178 ByteSet(&s, 0, sizeof(s));
179 s.ss_sp = new_sp;
180 s.ss_size = KERNEL_STACK_SIZE;
181 s.ss_flags = desiredFlags;
182 installHostedSignalStack(s);
183 }
184 } else {
185 stack_t s;
186 if (sigaltstack(nullptr, &s) < 0) {
187 FATAL("Hosted failed to inspect the scheduler signal stack");
188 }
189 if (!(s.ss_flags & SS_DISABLE)) {
190 ByteSet(&s, 0, sizeof(s));
191 s.ss_flags = SS_DISABLE;
192 installHostedSignalStack(s);
193 }
194 }
195
196 m_KernelStack = stack;
197
198 const int handoffErrno = errno;
199 if (pthread_sigmask(SIG_SETMASK, &previousSignals, nullptr) != 0) {
200 FATAL("Hosted failed to restore signals after a scheduler stack handoff");
201 }
202 errno = handoffErrno;
203}
204
205uintptr_t HostedProcessorInformation::getKernelStack() const {
206 return m_KernelStack;
207}
VirtualAddressSpace * m_VirtualAddressSpace
void setVirtualAddressSpace(VirtualAddressSpace &virtualAddressSpace)
EXPORTED_PUBLIC VirtualAddressSpace & getVirtualAddressSpace() const
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition panic.cc:117
@ Dec
Definition Log.h:126
size_t ProcessorId