The Pedigree Project 0.1
Machine.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/compiler.h"
21#include "pedigree/kernel/machine/Machine.h"
22#include "pedigree/kernel/machine/Serial.h"
23#include "pedigree/kernel/machine/Vga.h"
24#include "pedigree/kernel/processor/Processor.h"
25#include "pedigree/kernel/utilities/StaticString.h"
26
27Machine::~Machine() {}
28
29namespace {
30Machine::ShutdownPhase shutdownPhase = Machine::ShutdownPhase::NotStarted;
31}
32
33void Machine::setShutdownPhase(ShutdownPhase phase, const char* detail) {
34 __atomic_store(&shutdownPhase, &phase, __ATOMIC_RELAXED);
35 setShutdownDetail(detail);
36}
37
38void Machine::setShutdownDetail(const char* detail) {
39 if (__atomic_load_n(&shutdownPhase, __ATOMIC_RELAXED) == ShutdownPhase::NotStarted) {
40 return;
41 }
43 message += "Shutting down...\nPhase: ";
44 message += shutdownPhaseName();
45 if (detail) {
46 message += '\n';
47 message += detail;
48 }
49 // Copy module-owned detail into the stack buffer and bypass log callbacks:
50 // the next drain may hang after the debugger and log renderers have retired.
52}
53
54const char* Machine::shutdownPhaseName() {
55 // Module callers publish an enum, never a pointer into unloadable text.
56 ShutdownPhase phase;
57 __atomic_load(&shutdownPhase, &phase, __ATOMIC_RELAXED);
58 switch (phase) {
59 case ShutdownPhase::NotStarted:
60 return "not started";
61 case ShutdownPhase::Requested:
62 return "shutdown request";
63 case ShutdownPhase::Userspace:
64 return "terminating userspace";
65 case ShutdownPhase::Syscalls:
66 return "draining system calls";
67 case ShutdownPhase::Filesystems:
68 return "detaching filesystems";
69 case ShutdownPhase::Modules:
70 return "unloading modules";
71 case ShutdownPhase::Firmware:
72 return "preparing firmware shutdown";
73 case ShutdownPhase::Destructors:
74 return "draining deferred destruction";
75 case ShutdownPhase::Input:
76 return "stopping input";
77 case ShutdownPhase::Caches:
78 return "flushing caches";
79 case ShutdownPhase::Timers:
80 return "stopping info block timer";
81 case ShutdownPhase::Devices:
82 return "stopping platform devices";
83 case ShutdownPhase::Processors:
84 return "stopping other processors";
85 case ShutdownPhase::ProcessorCleanup:
86 return "releasing processor services";
87 case ShutdownPhase::FinalAction:
88 return "final power/reset action";
89 }
90 return "unknown";
91}
92
93const char* Machine::finalShutdown(ShutdownType type) {
94 if (type == ShutdownType::Restart) {
96 }
97 return type == ShutdownType::Halt ? nullptr : "Automatic power-off or restart is unavailable.";
98}
99
101 if (!message)
102 return;
103 // Publish serial evidence before entering the display provider.
104 Serial* serial = getNumSerial() ? getSerial(0) : nullptr;
105 if (serial) {
106 serial->write_str(message);
107 serial->write_str("\r\n");
108 }
109 Vga* console = getNumVga() ? getVga(0) : nullptr;
110 if (console) {
111 console->setLargestTextMode();
112 uint16_t* cells = *console;
113 const size_t rows = console->getNumRows();
114 const size_t cols = console->getNumCols();
115 if (cells && rows && cols) {
116 for (size_t i = 0; i < rows * cols; ++i)
117 cells[i] = 0x0f20;
118 auto lineLength = [cols](const char* text) {
119 size_t length = 0;
120 while (length < cols && text[length] && text[length] != '\n')
121 ++length;
122 return length;
123 };
124 size_t lines = 0;
125 const char* text = message;
126 while (*text && lines < rows) {
127 text += lineLength(text);
128 if (*text == '\n')
129 ++text;
130 ++lines;
131 }
132 text = message;
133 const size_t firstRow = (rows - lines) / 2;
134 for (size_t line = 0; line < lines; ++line) {
135 const size_t length = lineLength(text);
136 const size_t start = (firstRow + line) * cols + (cols - length) / 2;
137 for (size_t i = 0; i < length; ++i)
138 cells[start + i] = 0x0f00 | static_cast<uint8_t>(text[i]);
139 text += length;
140 if (*text == '\n')
141 ++text;
142 }
143 console->moveCursor(cols, rows);
144 console->flush();
145 }
146 }
147}
148
150 EMIT_IF(MULTIPROCESSOR) {
151 return false;
152 }
153 return true;
154}
155
157 EMIT_IF(MULTIPROCESSOR) {
158 return false;
159 }
160 return true;
161}
162
164 EMIT_IF(MULTIPROCESSOR) {
165 return false;
166 }
167 return true;
168}
virtual MUST_USE_RESULT bool quiesceAllOtherProcessors()
Definition Machine.cc:149
virtual size_t getNumSerial()=0
virtual const char * finalShutdown(ShutdownType type)
Definition Machine.cc:93
virtual Vga * getVga(size_t n)=0
virtual Serial * getSerial(size_t n)=0
virtual size_t getNumVga()=0
static void setShutdownPhase(ShutdownPhase phase, const char *detail=nullptr)
Definition Machine.cc:33
static void setShutdownDetail(const char *detail)
Definition Machine.cc:38
virtual MUST_USE_RESULT bool resumeAllOtherProcessors()
Definition Machine.cc:156
virtual MUST_USE_RESULT bool stopAllOtherProcessors()
Definition Machine.cc:163
void displayShutdownMessage(const char *message)
Definition Machine.cc:100
static void reset()
virtual void moveCursor(size_t nX, size_t nY)=0
virtual bool setLargestTextMode()=0
virtual size_t getNumRows()=0
virtual size_t getNumCols()=0