The Pedigree Project 0.1
mach_virt/Machine.cc
1/*
2 * Copyright (c) 2026, Pedigree Developers
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted.
6 */
7
8#include "Machine.h"
9#include "pedigree/kernel/machine/Machine.h"
10#include "pedigree/kernel/machine/Pci.h"
11#include "pedigree/kernel/panic.h"
12
13#include "DeviceTree.h"
14#include "IrqManager.h"
15#include "SchedulerTimer.h"
16#include "Timer.h"
17
18namespace {
19void psci(uint64_t function, bool hvc) {
20#if ARMV7
21 register uint32_t r0 asm("r0") = static_cast<uint32_t>(function);
22 if (hvc) {
23 asm volatile(".arch_extension virt\n\thvc #0" : "+r"(r0) : : "memory");
24 } else {
25 asm volatile(".arch_extension sec\n\tsmc #0" : "+r"(r0) : : "memory");
26 }
27#else
28 register uint64_t x0 asm("x0") = function;
29 if (hvc) {
30 asm volatile("hvc #0" : "+r"(x0) : : "memory");
31 } else {
32 asm volatile("smc #0" : "+r"(x0) : : "memory");
33 }
34#endif
35}
36} // namespace
37
38VirtMachine VirtMachine::m_Instance;
39
40Machine& Machine::instance() {
41 return VirtMachine::instance();
42}
43
44VirtMachine& VirtMachine::instance() {
45 return m_Instance;
46}
47
48VirtMachine::VirtMachine()
49 : m_Serial(), m_SerialKeyboard(m_Serial), m_Keyboard(&m_SerialKeyboard) {}
50
51VirtMachine::~VirtMachine() {
53}
54
56 PciBus::instance().initialise();
57}
58
60 if (!VirtDeviceTree::valid()) {
61 panic("Virt: invalid device tree");
62 }
64 m_SerialKeyboard.initialise();
65 if (!VirtIrqManager::instance().initialise()) {
66 panic("Virt: GIC initialisation failed");
67 }
68 if (!VirtTimer::instance().initialise1()) {
69 panic("Virt: architectural clock initialisation failed");
70 }
71 if (!VirtSchedulerTimer::instance().initialise()) {
72 panic("Virt: scheduler timer initialisation failed");
73 }
74 m_bInitialised = true;
75}
76
78 if (!VirtTimer::instance().initialise3()) {
79 panic("Virt: timer worker initialisation failed");
80 }
81 if (!VirtIrqManager::instance().initialiseThreaded()) {
82 panic("Virt: PCI interrupt worker initialisation failed");
83 }
84}
85
87 if (!m_bInitialised) {
88 return;
89 }
90 if (!VirtIrqManager::instance().shutdownThreaded()) {
91 panic("Shutdown aborted: PCI interrupt workers did not stop");
92 }
93 VirtTimer::instance().uninitialise();
94 VirtSchedulerTimer::instance().uninitialise();
96}
97
98bool VirtMachine::supportsPowerOff() const {
99 return VirtDeviceTree::psciAvailable();
100}
101
102void VirtMachine::finalShutdown(ShutdownType type) {
103 if (!VirtDeviceTree::psciAvailable()) {
104 return;
105 }
106 if (type == ShutdownType::Restart) {
107 psci(0x84000009, VirtDeviceTree::psciUsesHvc());
108 } else if (type == ShutdownType::PowerOff) {
109 psci(0x84000008, VirtDeviceTree::psciUsesHvc());
110 }
111}
112
114 return n == 0 ? &m_Serial : nullptr;
115}
116
118 return 1;
119}
120
122 return nullptr;
123}
124
126 return 0;
127}
128
129IrqManager* VirtMachine::getIrqManager() {
130 return &VirtIrqManager::instance();
131}
132
134 return &VirtSchedulerTimer::instance();
135}
136
138 return &VirtTimer::instance();
139}
140
142 return m_Keyboard;
143}
144
146 m_Keyboard = keyboard ? keyboard : &m_SerialKeyboard;
147}
void initialise()
static uintptr_t uartBase()
void initialise() override
void deinitialise() override
void initialiseDeviceTree() override
Vga * getVga(size_t n) override
Timer * getTimer() override
size_t getNumSerial() override
size_t getNumVga() override
void initialise3() override
Called after processor startup - for thread creation etc.
Keyboard * getKeyboard() override
Serial * getSerial(size_t n) override
void setKeyboard(Keyboard *keyboard) override
void initialise() override
void finalShutdown(ShutdownType type) override
SchedulerTimer * getSchedulerTimer() override
void setBase(uintptr_t base) override
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition panic.cc:117