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