From 15c89a359226ed9cd4f423d10f6834378533738f Mon Sep 17 00:00:00 2001 From: apio Date: Mon, 23 Jan 2023 21:24:05 +0100 Subject: [PATCH] kernel: Implement filtered PCI scans --- kernel/src/arch/PCI.cpp | 40 ++++++++++++++++++++++++++-------------- kernel/src/arch/PCI.h | 19 ++++++++++++++++--- kernel/src/main.cpp | 7 ++++++- 3 files changed, 48 insertions(+), 18 deletions(-) diff --git a/kernel/src/arch/PCI.cpp b/kernel/src/arch/PCI.cpp index e3934185..0ac20bbc 100644 --- a/kernel/src/arch/PCI.cpp +++ b/kernel/src/arch/PCI.cpp @@ -1,6 +1,12 @@ #include "arch/PCI.h" #include "Log.h" +struct ScanInfo +{ + PCI::callback_t callback; + PCI::Match match; +}; + namespace PCI { Device::ID read_id(const Device::Address& address) @@ -27,32 +33,38 @@ namespace PCI read8(address, Field::Subclass) == PCI_TO_PCI_BRIDGE_SUBCLASS; } - void scan_bus(u32); + static bool matches(const Device::Type& type, const Match& match) + { + if (match.klass != -1 && type.klass != match.klass) return false; + if (match.subclass != -1 && type.subclass != match.subclass) return false; + if (match.prog_if != -1 && type.prog_if != match.prog_if) return false; + return true; + } - void scan_function(const Device::Address& address) + void scan_bus(u32, ScanInfo); + + void scan_function(const Device::Address& address, ScanInfo info) { Device::ID id = read_id(address); Device::Type type = read_type(address); - kinfoln("Found PCI device %.4x:%.4x (Class %.2x, Subclass %.2x, ProgIF %.2x) at PCI address %u:%u:%u", - id.vendor, id.device, type.klass, type.subclass, type.prog_if, address.bus, address.slot, - address.function); + if (matches(type, info.match)) { info.callback({ id, type, address }); } if (is_pci_to_pci_bridge(address)) { kdbgln("PCI-to-PCI bridge detected, performing another bus scan"); - scan_bus(read8(address, Field::SecondaryBus)); + scan_bus(read8(address, Field::SecondaryBus), info); } } - void scan_slot(u32 bus, u32 slot) + void scan_slot(u32 bus, u32 slot, ScanInfo info) { Device::Address address { bus, slot, 0 }; // No device on this slot! if (read16(address, Field::VendorID) == PCI::INVALID_ID) return; - scan_function(address); + scan_function(address, info); u8 header_type = read8(address, Field::HeaderType); @@ -63,17 +75,17 @@ namespace PCI { address.function = function; if (read16(address, Field::VendorID) == PCI::INVALID_ID) continue; - scan_function(address); + scan_function(address, info); } } } - void scan_bus(u32 bus) + void scan_bus(u32 bus, ScanInfo info) { - for (u32 slot = 0; slot < 32; slot++) { scan_slot(bus, slot); } + for (u32 slot = 0; slot < 32; slot++) { scan_slot(bus, slot, info); } } - void scan() + void scan(callback_t callback, Match match) { u8 header_type = read8({ 0, 0, 0 }, Field::HeaderType); @@ -81,7 +93,7 @@ namespace PCI if ((header_type & 0x80) == 0) { kdbgln("PCI bus is single-function"); - scan_bus(0); + scan_bus(0, { callback, match }); } else { @@ -91,7 +103,7 @@ namespace PCI if (read16({ 0, 0, function }, Field::VendorID) != PCI::INVALID_ID) { kdbgln("PCI bus has function %u", function); - scan_bus(function); + scan_bus(function, { callback, match }); } } } diff --git a/kernel/src/arch/PCI.h b/kernel/src/arch/PCI.h index 15d552d3..99706db9 100644 --- a/kernel/src/arch/PCI.h +++ b/kernel/src/arch/PCI.h @@ -20,7 +20,7 @@ namespace PCI SecondaryBus = 0x19 }; - namespace Device + struct Device { struct ID { @@ -41,7 +41,20 @@ namespace PCI u32 slot; u32 function; }; - } + + ID id; + Type type; + Address address; + }; + + typedef void (*callback_t)(const Device&); + + struct Match + { + i16 klass { -1 }; + i16 subclass { -1 }; + i16 prog_if { -1 }; + }; constexpr u16 INVALID_ID = 0xFFFF; @@ -56,5 +69,5 @@ namespace PCI Device::ID read_id(const Device::Address& address); Device::Type read_type(const Device::Address& address); - void scan(); + void scan(callback_t callback, Match match); } diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index 69e5f670..4a8d08c1 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -70,7 +70,12 @@ Result init() TRY(Scheduler::new_kernel_thread(heap_thread)); TRY(Scheduler::new_kernel_thread(reap_thread)); - PCI::scan(); + PCI::scan( + [](const PCI::Device& device) { + kinfoln("Found PCI mass storage device %.4x:%.4x, at address %u:%u:%u", device.id.vendor, device.id.device, + device.address.bus, device.address.slot, device.address.function); + }, + { .klass = 1 }); CPU::platform_finish_init();