Max OS 0.3
Loading...
Searching...
No Matches
pci.cpp
Go to the documentation of this file.
1
10#include <common/logger.h>
11
12// Divers that need PCI descriptors
15#include <drivers/disk/ide.h>
16
17using namespace MaxOS;
18using namespace MaxOS::common;
19using namespace MaxOS::hardwarecommunication;
20using namespace MaxOS::memory;
21using namespace MaxOS::drivers;
22using namespace MaxOS::drivers::ethernet;
23using namespace MaxOS::drivers::video;
24using namespace MaxOS::drivers::disk;
25
26PCIDeviceDescriptor::PCIDeviceDescriptor() = default;
27
28PCIDeviceDescriptor::~PCIDeviceDescriptor() = default;
29
38
39 switch (class_id) {
40 case 0x00:
41 return (subclass_id == 0x01) ? "VGA" : "Legacy";
42 case 0x01:
43 switch (subclass_id) {
44 case 0x01:
45 return "IDE interface";
46 case 0x06:
47 return "SATA controller";
48 default:
49 return "Storage";
50 }
51 case 0x02:
52 return "Network";
53 case 0x03:
54 return "Display";
55 case 0x04:
56 switch (subclass_id) {
57 case 0x00:
58 return "Video";
59 case 0x01:
60 case 0x03:
61 return "Audio";
62 default:
63 return "Multimedia";
64 }
65 case 0x06:
66 switch (subclass_id) {
67 case 0x00:
68 return "Host bridge";
69 case 0x01:
70 return "ISA bridge";
71 case 0x04:
72 return "PCI bridge";
73 default:
74 return "Bridge";
75 }
76 case 0x07:
77 switch (subclass_id) {
78 case 0x00:
79 return "Serial controller";
80 case 0x80:
81 return "Communication controller";
82 }
83 break;
84 case 0x0C:
85 switch (subclass_id) {
86 case 0x03:
87 return "USB";
88 case 0x05:
89 return "System Management Bus";
90 }
91 break;
92 }
93 return "Unknown";
94}
95
100: m_data_port(0xCFC),
101 m_command_port(0xCF8)
102{
103
104
105}
106
107PCIController::~PCIController() = default;
108
118uint32_t PCIController::read(uint16_t bus, uint16_t device, uint16_t function,
120
121 // Calculate the id
122 uint32_t id = 0x1 << 31
123 | ((bus & 0xFF) << 16)
124 | ((device & 0x1F) << 11)
125 | ((function & 0x07) << 8)
126 | (register_offset & 0xFC);
127 m_command_port.write(id);
128
129 // Read the data from the port
130 uint32_t result = m_data_port.read();
131 return result >> (8 * (register_offset % 4));
132
133}
134
144void PCIController::write(uint16_t bus, uint16_t device, uint16_t function,
146
147 // Calculate the id
148 uint32_t id = 0x1 << 31
149 | ((bus & 0xFF) << 16)
150 | ((device & 0x1F) << 11)
151 | ((function & 0x07) << 8)
152 | (register_offset & 0xFC);
153 m_command_port.write(id);
154
155 // Write the data to the port
156 m_data_port.write(value);
157}
158
166bool PCIController::device_has_functions(uint16_t bus, uint16_t device) {
167
168 return read(bus, device, 0, 0x0E) & (1 << 7);
169}
170
177
178 for (int bus = 0; bus < 8; ++bus) {
179 for (int device = 0; device < 32; ++device) {
180
181 int num_functions = (device_has_functions(bus, device)) ? 8 : 1;
182
183 for (int function = 0; function < num_functions; ++function) {
184
185 // Get the device descriptor, if the vendor id is 0x0000 or 0xFFFF, the device is not present/ready
186 PCIDeviceDescriptor device_descriptor = get_device_descriptor(bus, device,
187 function);
188 if (device_descriptor.vendor_id == 0x0000 || device_descriptor.vendor_id == 0x0001 ||
189 device_descriptor.vendor_id == 0xFFFF)
190 continue;
191
192 // Get the earliest port number
193 for (int bar_num = 5; bar_num >= 0; bar_num--) {
194 BaseAddressRegister bar = get_base_address_register(bus, device, function, bar_num);
195 if (bar.address && (bar.type == BARType::InputOutput))
196 device_descriptor.port_base = (uint64_t) bar.address;
197 }
198
199 Logger::DEBUG() << "DEVICE FOUND: " << device_descriptor.get_type() << " - ";
200
201 // Select the driver and print information about the device
203 if (driver != nullptr) {
204 handler->on_driver_selected(driver);
205 Logger::Out() << driver->vendor_name() << " " << driver->device_name();
206 } else {
208 }
209
210 Logger::Out() << "\n";
211 }
212 }
213 }
214}
215
224PCIDeviceDescriptor PCIController::get_device_descriptor(uint16_t bus, uint16_t device, uint16_t function) {
225
227
228 result.bus = bus;
229 result.device = device;
230 result.function = function;
231
232 result.vendor_id = read(bus, device, function, 0x00);
233 result.device_id = read(bus, device, function, 0x02);
234
235 result.class_id = read(bus, device, function, 0x0B);
236 result.subclass_id = read(bus, device, function, 0x0A);
237 result.interface_id = read(bus, device, function, 0x09);
238
239 result.revision = read(bus, device, function, 0x8);
240 result.interrupt = read(bus, device, function, 0x3C);
241
242 return result;
243}
244
252
253 switch (dev.vendor_id) {
254 case 0x1022: //AMD
255 {
256 switch (dev.device_id) {
257 case 0x2000: {
258 return new AMD_AM79C973(&dev);
259
260 }
261 default:
262 break;
263 }
264 break;
265 }
266 case 0x8086: //Intel
267 {
268 switch (dev.device_id) {
269
270 case 0x100E: //i217 (Ethernet Controller)
271 {
272 return new IntelI217(&dev);
273 }
274
275 case 0x7010: // PIIX4 (IDE Controller)
276 {
278 }
279
280 default:
281 break;
282 }
283 break;
284 }//End Intel
285 }
286
287 //If there is no driver for the particular device, go into generic devices
288 switch (dev.class_id) {
289 case 0x03: //Graphics
290 {
291
292 switch (dev.subclass_id) {
293 case 0x00: //VGA
294 {
295 return new VideoGraphicsArray();
296 }
297 }
298 break;
299 }
300 }
301
302 return nullptr;
303}
304
311
312 switch (dev.vendor_id) {
313 case 0x1022: {
314 // The vendor is AMD
315 Logger::Out() << "AMD ";
316
317 // List the device
318 switch (dev.device_id) {
319 default:
320 Logger::Out() << "0x%x" << dev.device_id;
321 break;
322 }
323 break;
324 }
325
326 case 0x106B: {
327 // The vendor is Apple
328 Logger::Out() << "Apple ";
329
330 // List the device
331 switch (dev.device_id) {
332 case 0x003F: {
333 Logger::Out() << "KeyLargo/Intrepid USB";
334 break;
335 }
336
337 default:
338 Logger::Out() << "0x%x" << dev.device_id;
339 break;
340 }
341 break;
342 }
343
344 case 1234: {
345 // The vendor is QEMU
346 Logger::Out() << "QEMU ";
347
348 // List the device
349 switch (dev.device_id) {
350
351 case 0x1111: {
352 Logger::Out() << "Virtual Video Controller";
353 break;
354 }
355 }
356 break;
357 }
358
359 case 0x8086: {
360 // The vendor is Intel
361 Logger::Out() << "Intel ";
362
363 // List the device
364 switch (dev.device_id) {
365
366 case 0x1237: {
367 Logger::Out() << "440FX";
368 break;
369 }
370
371 case 0x2415: {
372 Logger::Out() << "AC'97";
373 break;
374 }
375
376 case 0x7000: {
377 Logger::Out() << "PIIX3";
378 break;
379
380 }
381
382 case 0x7111: {
383 Logger::Out() << "PIIX3 ACPI";
384 break;
385 }
386
387 case 0x7113: {
388 Logger::Out() << "PIIX4 ACPI";
389 break;
390 }
391
392 default:
393 Logger::Out() << "0x%x" << dev.device_id;
394 break;
395
396 }
397 break;
398 }
399
400 case 0x80EE: {
401
402 // The vendor is VirtualBox
403 Logger::Out() << "VirtualBox ";
404
405 // List the device
406 switch (dev.device_id) {
407
408 case 0xBEEF: {
409 Logger::Out() << "Graphics Adapter";
410 break;
411 }
412
413 case 0xCAFE: {
414 Logger::Out() << "Guest Service";
415 break;
416 }
417 }
418 break;
419 }
420
421 // Unknown
422 default:
423 Logger::Out() << "Unknown (0x" << dev.vendor_id << ":0x" << dev.device_id << ")";
424 break;
425
426 }
427}
428
438BaseAddressRegister PCIController::get_base_address_register(uint16_t bus, uint16_t device, uint16_t function, uint16_t bar) {
439
441
442 // Only types 0x00 (normal devices) and 0x01 (PCI-to-PCI bridges) are supported:
443 uint32_t header_type = read(bus, device, function, 0x0E);
444 if (header_type & 0x3F)
445 return result;
446
447 // read the base address register
448 uint64_t bar_value = read(bus, device, function, 0x10 + 4 * bar);
449 result.type = (bar_value & 0x1) ? BARType::InputOutput : BARType::MemoryMapped;
450 result.address = (uint8_t*) (bar_value & ~0xF);
451
452 // Read the size of the base address register
453 write(bus, device, function, 0x10 + 4 * bar, 0xFFFFFFF0 | (int) result.type);
454 result.size = read(bus, device, function, 0x10 + 4 * bar);
455 result.size = (~result.size | 0xF) + 1;
456
457 // Restore the original value of the base address register
458 write(bus, device, function, 0x10 + 4 * bar, bar_value);
459
460 return result;
461}
Driver for the AMD AM79C973 Ethernet Controller.
static Logger DEBUG()
Gets active logger set to DEBUG level.
Definition logger.cpp:193
static Logger & Out()
Gets the active logger.
Definition logger.cpp:149
Stores the left, top, width and height of a rectangle.
Definition rectangle.h:22
Event handler for the DriverSelector class, handles the event when a driver is selected.
Definition driver.h:47
base class for all drivers, handles the activation, deactivation, initialisation and reset of the dri...
Definition driver.h:27
Driver for the IDE controller, handles the creation and management of the IDE devices.
Definition ide.h:25
Driver for the AMD AM79C973 Ethernet Controller.
Driver for the Intel I217 Ethernet Controller.
Definition intel_i217.h:64
Driver for the VGA graphics controller, handles the rendering of pixels to the screen.
Definition vga.h:28
Used to store the Base Address Register (BAR) of a PCI device.
Definition pci.h:38
static void list_known_device(const PCIDeviceDescriptor &dev)
Print the vednor and device id of known devices, or "Unknown" + their ids if not known.
Definition pci.cpp:310
PCIController()
Construct a new PCI Controller object.
Definition pci.cpp:99
static drivers::Driver * get_driver(PCIDeviceDescriptor dev)
Get the driver for the device.
Definition pci.cpp:251
void select_drivers(drivers::DriverSelectorEventHandler *handler) override
Select the driver for the device.
Definition pci.cpp:176
Stores information about a PCI device.
Definition pci.h:54
uint8_t class_id
The class type of the device.
Definition pci.h:71
uint8_t subclass_id
The subclass type of the device.
Definition pci.h:72
string get_type() const
Get the type of the device.
Definition pci.cpp:37
virtual uint32_t read()
read a double word from the port (32Bit)
Definition port.cpp:138
virtual void write(uint32_t data)
write a double word to the port (32Bit)
Definition port.cpp:128
Defines a driver for the Integrated Drive Electronics (IDE) controller.
Driver for the Intel I217 Ethernet Controller.
Defines a Logger class for logging messages with different severity levels to multiple output streams...
Defines a Peripheral Component Interconnect (PCI) controller for managing PCI devices and loading the...
BARType
Determines whether the PCI device communicates via IO ports or memory.
Definition pci.h:27