The Pedigree Project 0.1
panic.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/Service.h"
22#include "pedigree/kernel/ServiceFeatures.h"
23#include "pedigree/kernel/ServiceManager.h"
24#include "pedigree/kernel/debugger/DebuggerIO.h"
25#include "pedigree/kernel/debugger/LocalIO.h"
26#include "pedigree/kernel/debugger/SerialIO.h"
27#include "pedigree/kernel/graphics/GraphicsService.h"
28#include "pedigree/kernel/linker/KernelElf.h"
29#include "pedigree/kernel/machine/Display.h"
30#include "pedigree/kernel/machine/Machine.h"
31#include "pedigree/kernel/machine/Serial.h"
32#include "pedigree/kernel/machine/Vga.h"
33#include "pedigree/kernel/panic.h"
34#include "pedigree/kernel/processor/Processor.h"
35#include "pedigree/kernel/processor/types.h"
36#include "pedigree/kernel/utilities/StaticString.h"
37#include "pedigree/kernel/utilities/String.h"
38#include "pedigree/kernel/utilities/utility.h"
39
40#if HOSTED
41#include <stdio.h>
42#include <stdlib.h>
43#endif
44
45static size_t newlineCount(const char* pString) {
46 size_t nNewlines = 0;
47 while (*pString != '\0')
48 if (*pString++ == '\n')
49 ++nNewlines;
50
51 return nNewlines;
52}
53
54// TODO: We might want a separate parameter for a stacktrace/register dump
55static void _panic(const char* msg, DebuggerIO* pScreen) {
56 static HugeStaticString panic_output;
57 panic_output.clear();
58
59 panic_output.append("PANIC: ");
60 panic_output.append(msg);
61
62 // write the final string to the screen
63 pScreen->drawString(panic_output, 0, 0, DebuggerIO::Red, DebuggerIO::Black);
64
65 size_t nLines = newlineCount(panic_output) + 2;
66
67 Log& log = Log::instance();
69 static NormalStaticString Line;
70
71 size_t iEntry = 0, iUsedEntries = 0;
72 if ((pScreen->getHeight() - nLines) < (log.getStaticEntryCount() + log.getDynamicEntryCount()))
73 iEntry = log.getStaticEntryCount() + log.getDynamicEntryCount() -
74 (pScreen->getHeight() - nLines) + 1;
75 bool bPrintThisLine = false;
76 for (; iEntry < (log.getStaticEntryCount() + log.getDynamicEntryCount()); iEntry++) {
77 if (iEntry < log.getStaticEntryCount()) {
78 const Log::StaticLogEntry& entry = log.getStaticEntry(iEntry);
79
80 // level = entry.severity;
81 // if( level == Log::Fatal || level == Log::Error )
82 // {
83 Line.clear();
84 Line.append("[");
85 Line.append(entry.timestamp, 10, 8, '0');
86 Line.append("] ");
87 Line.append(entry.str);
88 Line.append("\n");
89
90 bPrintThisLine = true;
91 // }
92 } else {
93 const Log::DynamicLogEntry& entry = log.getDynamicEntry(iEntry);
94 level = entry.severity;
95
96 // if( level == Log::Fatal || level == Log::Error )
97 // {
98 Line.clear();
99 Line.append("[");
100 Line.append(entry.timestamp, 10, 8, '0');
101 Line.append("] ");
102 Line.append(entry.str);
103 Line.append("\n");
104
105 bPrintThisLine = true;
106 // }
107 }
108
109 // print the line
110 if (bPrintThisLine == true) {
111 ++iUsedEntries;
112 pScreen->drawString(Line, nLines + iUsedEntries, 0, DebuggerIO::White, DebuggerIO::Black);
113 bPrintThisLine = false;
114 }
115 }
116}
117
118void panic(const char* msg) {
119#if HOSTED
120 fprintf(stderr, "panic: %s\n", msg);
121 abort();
122#endif
123
124 const bool terminalTlbFailure = Processor::tlbInvalidationTerminal();
125 const bool terminalShutdown = KernelElf::instance().isShuttingDown();
127
128 HugeStaticString shutdownFailure;
129 if (terminalShutdown && !terminalTlbFailure) {
130 shutdownFailure.append("Shutdown failed. Filesystems may be unclean.\nPhase: ");
131 shutdownFailure.append(Machine::shutdownPhaseName());
132 shutdownFailure.append("\nReason: ");
133 shutdownFailure.append(msg);
134 }
135
136 // Graphics providers may already have been unloaded during shutdown.
137 // Preserve the initiating failure before touching those services.
138 if (Machine::instance().getNumSerial()) {
139 Serial* serial = Machine::instance().getSerial(0);
140 if (serial) {
141 serial->write_str("PANIC: ");
142 serial->write_str(msg);
143 serial->write_str("\r\n");
144 }
145 }
146
147 bool processorsStopped = true;
148#if MULTIPROCESSOR
149 if (terminalTlbFailure) {
150 do {
151 processorsStopped = Machine::instance().stopAllOtherProcessors();
152 if (!processorsStopped) {
154 }
155 } while (!processorsStopped);
156 } else {
157 processorsStopped = Machine::instance().stopAllOtherProcessors();
158 }
159 if (!processorsStopped && !terminalTlbFailure && !terminalShutdown) {
160 ERROR_NOLOCK("panic: not all other processors stopped");
161 }
162#endif
163
164 if (terminalShutdown && !terminalTlbFailure) {
165 // Module-backed graphics and debugger providers may already be unmapped.
166 // Keep the failure visible without turning it into a fault or a reset.
167 if (processorsStopped) {
168 Vga* console = Machine::instance().getNumVga() ? Machine::instance().getVga(0) : nullptr;
169 if (console) {
170 console->enterPanicMode();
171 }
172 Machine::instance().displayShutdownMessage(shutdownFailure);
173 } else if (Machine::instance().getNumSerial()) {
174 Machine::instance().getSerial(0)->write_str(shutdownFailure);
175 Machine::instance().getSerial(0)->write_str("\r\n");
176 }
177 while (true)
179 }
180
181 if (terminalTlbFailure) {
182 // Arbitrarily halted peers may own allocator, log, graphics, or input
183 // locks. Keep the terminal failure path to literal serial writes only.
184 SerialIO serialIO(Machine::instance().getSerial(0));
185 serialIO.drawString("PANIC: ", 0, 0, DebuggerIO::Red, DebuggerIO::Black);
186 serialIO.drawString(msg, 0, 7, DebuggerIO::Red, DebuggerIO::Black);
187 while (true) {
189 }
190 }
191
192 if (processorsStopped) {
193 static String graphicsService("graphics");
194
195 // Drop out of whatever graphics mode we were in.
197 ByteSet(&params, 0, sizeof(params));
198 params.wantTextMode = false;
199
200 ServiceFeatures* pFeatures = nullptr;
201 Service* pService = nullptr;
202 bool bSuccess = false;
203 if (ServiceManager::instance().tryGetService(graphicsService, pService, pFeatures) &&
204 pFeatures->provides(ServiceFeatures::probe)) {
205 bSuccess =
206 pService->serve(ServiceFeatures::probe, reinterpret_cast<void*>(&params), sizeof(params));
207 }
208
209 if (bSuccess && params.providerFound && !params.providerResult.bTextModes &&
210 params.providerResult.pDisplay) {
211 params.providerResult.pDisplay->setScreenMode(0);
212 }
213 }
214
215 /*
216 * I/O implementations.
217 */
218 SerialIO serialIO(Machine::instance().getSerial(0));
219
220 DebuggerIO* pInterfaces[2] = {0};
221
222 int nInterfaces = 0;
223 if (Machine::instance().getNumVga()) // Not all machines have "VGA", so handle that
224 {
225 static LocalIO localIO(Machine::instance().getVga(0), Machine::instance().getKeyboard());
226#if DONT_LOG_TO_SERIAL
227 pInterfaces[0] = &localIO;
228 nInterfaces = 1;
229#else
230 pInterfaces[0] = &localIO;
231 pInterfaces[1] = &serialIO;
232 nInterfaces = 2;
233#endif
234 }
235#if !DONT_LOG_TO_SERIAL
236 else {
237 pInterfaces[0] = &serialIO;
238 nInterfaces = 1;
239 }
240#endif
241
242 for (int nIFace = 0; nIFace < nInterfaces; nIFace++)
243 _panic(msg, pInterfaces[nIFace]);
244
245 // Halt the processor
246 while (1)
248}
virtual void drawString(const char *str, size_t row, size_t col, Colour foreColour, Colour backColour)=0
virtual bool setScreenMode(ScreenMode sm)
Definition Display.cc:90
static KernelElf & instance()
Definition KernelElf.h:135
the kernel's log
Definition Log.h:155
size_t getStaticEntryCount() const
Definition Log.cc:438
const StaticLogEntry & getStaticEntry(size_t n) const
Definition Log.cc:446
size_t getDynamicEntryCount() const
Definition Log.cc:442
static EXPORTED_PUBLIC Log & instance()
Definition Log.cc:117
SeverityLevel
Definition Log.h:170
const DynamicLogEntry & getDynamicEntry(size_t n) const
Definition Log.cc:450
virtual Vga * getVga(size_t n)=0
virtual Serial * getSerial(size_t n)=0
virtual size_t getNumVga()=0
virtual MUST_USE_RESULT bool stopAllOtherProcessors()
Definition Machine.cc:163
void displayShutdownMessage(const char *message)
Definition Machine.cc:100
static void halt()
static bool tlbInvalidationTerminal()
static void pause()
static void setInterrupts(bool bEnable)
void drawString(const char *str, size_t row, size_t col, DebuggerIO::Colour foreColour, DebuggerIO::Colour backColour)
Definition SerialIO.cc:240
virtual bool provides(Type service)
virtual bool serve(ServiceFeatures::Type type, void *pData, size_t dataLen)=0
void panic(const char *msg)
Definition panic.cc:118