kernel: Implement filtered PCI scans
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
3a4ca73df7
commit
15c89a3592
@ -1,6 +1,12 @@
|
|||||||
#include "arch/PCI.h"
|
#include "arch/PCI.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
|
struct ScanInfo
|
||||||
|
{
|
||||||
|
PCI::callback_t callback;
|
||||||
|
PCI::Match match;
|
||||||
|
};
|
||||||
|
|
||||||
namespace PCI
|
namespace PCI
|
||||||
{
|
{
|
||||||
Device::ID read_id(const Device::Address& address)
|
Device::ID read_id(const Device::Address& address)
|
||||||
@ -27,32 +33,38 @@ namespace PCI
|
|||||||
read8(address, Field::Subclass) == PCI_TO_PCI_BRIDGE_SUBCLASS;
|
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::ID id = read_id(address);
|
||||||
Device::Type type = read_type(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",
|
if (matches(type, info.match)) { info.callback({ id, type, address }); }
|
||||||
id.vendor, id.device, type.klass, type.subclass, type.prog_if, address.bus, address.slot,
|
|
||||||
address.function);
|
|
||||||
|
|
||||||
if (is_pci_to_pci_bridge(address))
|
if (is_pci_to_pci_bridge(address))
|
||||||
{
|
{
|
||||||
kdbgln("PCI-to-PCI bridge detected, performing another bus scan");
|
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 };
|
Device::Address address { bus, slot, 0 };
|
||||||
|
|
||||||
// No device on this slot!
|
// No device on this slot!
|
||||||
if (read16(address, Field::VendorID) == PCI::INVALID_ID) return;
|
if (read16(address, Field::VendorID) == PCI::INVALID_ID) return;
|
||||||
|
|
||||||
scan_function(address);
|
scan_function(address, info);
|
||||||
|
|
||||||
u8 header_type = read8(address, Field::HeaderType);
|
u8 header_type = read8(address, Field::HeaderType);
|
||||||
|
|
||||||
@ -63,17 +75,17 @@ namespace PCI
|
|||||||
{
|
{
|
||||||
address.function = function;
|
address.function = function;
|
||||||
if (read16(address, Field::VendorID) == PCI::INVALID_ID) continue;
|
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);
|
u8 header_type = read8({ 0, 0, 0 }, Field::HeaderType);
|
||||||
|
|
||||||
@ -81,7 +93,7 @@ namespace PCI
|
|||||||
if ((header_type & 0x80) == 0)
|
if ((header_type & 0x80) == 0)
|
||||||
{
|
{
|
||||||
kdbgln("PCI bus is single-function");
|
kdbgln("PCI bus is single-function");
|
||||||
scan_bus(0);
|
scan_bus(0, { callback, match });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -91,7 +103,7 @@ namespace PCI
|
|||||||
if (read16({ 0, 0, function }, Field::VendorID) != PCI::INVALID_ID)
|
if (read16({ 0, 0, function }, Field::VendorID) != PCI::INVALID_ID)
|
||||||
{
|
{
|
||||||
kdbgln("PCI bus has function %u", function);
|
kdbgln("PCI bus has function %u", function);
|
||||||
scan_bus(function);
|
scan_bus(function, { callback, match });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ namespace PCI
|
|||||||
SecondaryBus = 0x19
|
SecondaryBus = 0x19
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Device
|
struct Device
|
||||||
{
|
{
|
||||||
struct ID
|
struct ID
|
||||||
{
|
{
|
||||||
@ -41,7 +41,20 @@ namespace PCI
|
|||||||
u32 slot;
|
u32 slot;
|
||||||
u32 function;
|
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;
|
constexpr u16 INVALID_ID = 0xFFFF;
|
||||||
|
|
||||||
@ -56,5 +69,5 @@ namespace PCI
|
|||||||
Device::ID read_id(const Device::Address& address);
|
Device::ID read_id(const Device::Address& address);
|
||||||
Device::Type read_type(const Device::Address& address);
|
Device::Type read_type(const Device::Address& address);
|
||||||
|
|
||||||
void scan();
|
void scan(callback_t callback, Match match);
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,12 @@ Result<void> init()
|
|||||||
TRY(Scheduler::new_kernel_thread(heap_thread));
|
TRY(Scheduler::new_kernel_thread(heap_thread));
|
||||||
TRY(Scheduler::new_kernel_thread(reap_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();
|
CPU::platform_finish_init();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user