kernel: Implement filtered PCI scans
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
apio 2023-01-23 21:24:05 +01:00
parent 3a4ca73df7
commit 15c89a3592
Signed by: apio
GPG Key ID: B8A7D06E42258954
3 changed files with 48 additions and 18 deletions

View File

@ -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 });
}
}
}

View File

@ -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);
}

View File

@ -70,7 +70,12 @@ Result<void> 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();