The Pedigree Project 0.1
Drivers.cc
1/* Copyright (c) 2026, Pedigree Developers. SPDX-License-Identifier: ISC */
2#include "pedigree/kernel/LockGuard.h"
3#include "pedigree/kernel/machine/Device.h"
4#include "pedigree/kernel/machine/Pci.h"
5#include "pedigree/kernel/machine/PciDrivers.h"
6#include "pedigree/kernel/process/Mutex.h"
7#include "pedigree/kernel/utilities/List.h"
8#include "pedigree/kernel/utilities/new"
9
10namespace {
11enum class State { Available, SlotPrepared, UnloadPrepared, Retired };
12
13struct Registration {
14 const PciDrivers::Driver* driver;
15 bool closing = false;
16};
17
18struct Function {
19 uint16_t route;
20 Registration* owner = nullptr;
21 Device* pci = nullptr;
22 Device* controller = nullptr;
23 State state = State::Available;
24};
25
26Mutex g_Lock;
27List<Registration*> g_Drivers;
28List<Function*> g_Functions;
29bool g_Ready = false;
30
31uint16_t routeId(Device* device) {
32 return (device->getPciBusPosition() << 8) | (device->getPciDevicePosition() << 3) |
33 device->getPciFunctionNumber();
34}
35
36bool pciFunction(Device* device) {
37 Device* parent = device->getParent();
38 return parent && parent->getSpecificType() == "pci" && device->getPciVendorId() &&
39 device->getPciVendorId() != 0xffff && device->getPciBusPosition() < 256 &&
40 device->getPciDevicePosition() < 32 && device->getPciFunctionNumber() < 8;
41}
42
43Function* findFunction(uint16_t route) {
44 for (auto* function : g_Functions) {
45 if (function->route == route) {
46 return function;
47 }
48 }
49 return nullptr;
50}
51
52Registration* findDriver(const PciDrivers::Driver* driver) {
53 for (auto* registration : g_Drivers) {
54 if (registration->driver == driver) {
55 return registration;
56 }
57 }
58 return nullptr;
59}
60
61Device* resolve(uint16_t route, const PciDrivers::Driver* driver = nullptr) {
62 Device* result = nullptr;
63 bool duplicate = false;
64 auto visit = [&](Device* device) -> Device* {
65 if (pciFunction(device) && routeId(device) == route &&
66 (!driver || (device->getPciClassCode() == driver->classCode &&
67 device->getPciSubclassCode() == driver->subclass &&
68 device->getPciProgInterface() == driver->progInterface &&
69 device->getType() == Device::Root && !device->getNumChildren()))) {
70 duplicate |= result != nullptr;
71 result = device;
72 }
73 return device;
74 };
75 pedigree_std::Callable<decltype(visit)> callback(visit);
76 Device::foreach (callback, nullptr);
77 return duplicate ? nullptr : result;
78}
79
80bool bind(Function& function, Registration& registration) {
81 if (registration.closing || function.owner || function.state != State::Available) {
82 return false;
83 }
84 // Legacy PCI drivers may replace their generic nodes. Resolve unbound BDFs
85 // afresh; only this registry's bindings retain the generic node pointer.
86 const auto& driver = *registration.driver;
87 Device* pci = resolve(function.route, &driver);
88 if (!pci) {
89 return false;
90 }
91 Device* controller = driver.attach(pci);
92 if (!controller) {
93 return false;
94 }
95 function.pci = pci;
96 function.controller = controller;
97 function.owner = &registration;
98 return true;
99}
100
101void unbind(Function& function) {
102 function.owner->driver->remove(function.controller);
103 function.owner = nullptr;
104 function.controller = nullptr;
105 function.pci = nullptr;
106 function.state = State::Available;
107}
108} // namespace
109
110namespace PciDrivers {
111bool initialize() {
112 LockGuard<Mutex> guard(g_Lock);
113 if (g_Ready) {
114 return true;
115 }
116 bool valid = true;
117 auto visit = [&](Device* device) -> Device* {
118 if (valid && pciFunction(device)) {
119 const uint16_t route = routeId(device);
120 if (findFunction(route)) {
121 valid = false;
122 } else {
123 auto* function = new Function{route};
124 if (!function || !g_Functions.tryPushBack(function)) {
125 delete function;
126 valid = false;
127 }
128 }
129 }
130 return device;
131 };
132 pedigree_std::Callable<decltype(visit)> callback(visit);
133 Device::foreach (callback, nullptr);
134 if (!valid) {
135 while (g_Functions.count()) {
136 delete g_Functions.popFront();
137 }
138 return false;
139 }
140 g_Ready = true;
141 return true;
142}
143
144bool registerDriver(const Driver* driver) {
145 if (!driver || !driver->attach || !driver->prepareRemove || !driver->cancelRemove ||
146 !driver->remove) {
147 return false;
148 }
149 LockGuard<Mutex> guard(g_Lock);
150 if (!g_Ready || findDriver(driver)) {
151 return false;
152 }
153 auto* registration = new Registration{driver};
154 if (!registration || !g_Drivers.tryPushBack(registration)) {
155 delete registration;
156 return false;
157 }
158 for (auto* function : g_Functions) {
159 bind(*function, *registration);
160 }
161 return true;
162}
163
164bool prepareUnregisterDriver(const Driver* driver) {
165 LockGuard<Mutex> guard(g_Lock);
166 Registration* registration = findDriver(driver);
167 if (!registration || registration->closing) {
168 return true;
169 }
170 for (auto* function : g_Functions) {
171 if (function->owner == registration && function->state != State::Available) {
172 return false;
173 }
174 }
175 registration->closing = true;
176 for (auto* function : g_Functions) {
177 if (function->owner != registration) {
178 continue;
179 }
180 if (!driver->prepareRemove(function->controller)) {
181 for (auto* prepared : g_Functions) {
182 if (prepared->owner == registration && prepared->state == State::UnloadPrepared) {
183 driver->cancelRemove(prepared->controller);
184 prepared->state = State::Available;
185 }
186 }
187 registration->closing = false;
188 return false;
189 }
190 function->state = State::UnloadPrepared;
191 }
192 return true;
193}
194
195bool unregisterDriver(const Driver* driver) {
196 LockGuard<Mutex> guard(g_Lock);
197 Registration* registration = findDriver(driver);
198 if (!registration) {
199 return true;
200 }
201 if (!registration->closing) {
202 return false;
203 }
204 for (auto* function : g_Functions) {
205 if (function->owner == registration && function->state != State::UnloadPrepared) {
206 return false;
207 }
208 }
209 for (auto* function : g_Functions) {
210 if (function->owner == registration) {
211 unbind(*function);
212 }
213 }
214 for (auto it = g_Drivers.begin(); it != g_Drivers.end(); ++it) {
215 if (*it == registration) {
216 g_Drivers.erase(it);
217 break;
218 }
219 }
220 delete registration;
221 return true;
222}
223
224bool attach(Device* pci) {
225 if (!pci) {
226 return false;
227 }
228 LockGuard<Mutex> guard(g_Lock);
229 if (!g_Ready || resolve(routeId(pci)) != pci) {
230 return false;
231 }
232 Function* function = findFunction(routeId(pci));
233 if (!function) {
234 function = new Function{routeId(pci)};
235 if (!function || !g_Functions.tryPushBack(function)) {
236 delete function;
237 return false;
238 }
239 }
240 if (function->owner) {
241 return function->pci == pci && function->state == State::Available;
242 }
243 if (function->state == State::Retired) {
244 function->state = State::Available;
245 }
246 for (auto* registration : g_Drivers) {
247 if (bind(*function, *registration)) {
248 return true;
249 }
250 }
251 return false;
252}
253
254bool prepareRemove(Device* pci) {
255 if (!pci) {
256 return false;
257 }
258 LockGuard<Mutex> guard(g_Lock);
259 Function* function = findFunction(routeId(pci));
260 if (!function || function->state != State::Available ||
261 (function->owner && function->pci != pci)) {
262 return false;
263 }
264 // Legacy remapping domains retain the requester pointer and cannot yet be
265 // detached safely; module unload may keep the node, physical removal cannot.
266 auto& bus = PciBus::instance();
267 if (bus.hasDmaRemapping(pci) && !bus.hasDmaIsolation(pci)) {
268 return false;
269 }
270 if (function->owner) {
271 if (function->owner->closing || !function->owner->driver->prepareRemove(function->controller)) {
272 return false;
273 }
274 } else {
275 if (resolve(function->route) != pci || bus.hasDmaRemapping(pci)) {
276 return false;
277 }
278 {
280 if (pci->getType() != Device::Root || pci->getNumChildren()) {
281 return false;
282 }
283 }
284 uint16_t command = 0;
285 if (!PciBus::instance().readConfig16(pci, 4, command) || (command & 4)) {
286 return false;
287 }
288 function->pci = pci;
289 }
290 function->state = State::SlotPrepared;
291 return true;
292}
293
294void cancelRemove(Device* pci) {
295 if (!pci) {
296 return;
297 }
298 LockGuard<Mutex> guard(g_Lock);
299 Function* function = findFunction(routeId(pci));
300 if (!function || function->state != State::SlotPrepared || function->pci != pci) {
301 return;
302 }
303 if (function->owner) {
304 function->owner->driver->cancelRemove(function->controller);
305 } else {
306 function->pci = nullptr;
307 }
308 function->state = State::Available;
309}
310
311bool remove(Device* pci) {
312 if (!pci) {
313 return false;
314 }
315 LockGuard<Mutex> guard(g_Lock);
316 Function* function = findFunction(routeId(pci));
317 if (!function || function->state != State::SlotPrepared || function->pci != pci) {
318 return false;
319 }
320 if (function->owner) {
321 unbind(*function);
322 }
323 function->pci = nullptr;
324 function->state = State::Retired;
325 return true;
326}
327} // namespace PciDrivers
size_t getNumChildren()
Definition Device.cc:143
static void foreach(Callback callback, Device *root=0)
Definition Device.cc:107
@ Root
The device is the root of the device tree.
Definition Device.h:74
virtual const String & getSpecificType()
Definition Device.h:183
virtual Type getType()
Definition Device.h:178
Definition List.h:61
Iterator begin()
Definition List.h:122
Iterator end()
Definition List.h:132
Definition Mutex.h:56
Iterator erase(Iterator &Iter)
Definition List.h:352
T popFront()
Definition List.h:330
bool tryPushBack(const T &value)
Definition List.h:246
size_t count() const
Definition List.h:212