mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14:32 -08:00
Add initial PCIe enumeration
This commit is contained in:
@@ -172,3 +172,19 @@ struct acpi_apic
|
||||
uint8_t controller_data[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct acpi_mcfg_entry
|
||||
{
|
||||
uint64_t base;
|
||||
uint16_t group;
|
||||
uint8_t bus_start;
|
||||
uint8_t bus_end;
|
||||
uint32_t reserved;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct acpi_mcfg
|
||||
{
|
||||
TABLE_HEADER('MCFG');
|
||||
uint64_t reserved;
|
||||
acpi_mcfg_entry entries[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "interrupts.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "memory_pages.h"
|
||||
|
||||
static const char expected_signature[] = "RSD PTR ";
|
||||
|
||||
@@ -35,6 +36,14 @@ struct acpi2_rsdp
|
||||
uint8_t reserved[3];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct pci_group
|
||||
{
|
||||
uint16_t group;
|
||||
uint16_t bus_start;
|
||||
uint16_t bus_end;
|
||||
|
||||
uint32_t *base;
|
||||
};
|
||||
|
||||
uint8_t
|
||||
acpi_checksum(const void *p, size_t len, size_t off = 0)
|
||||
@@ -54,7 +63,9 @@ acpi_table_header::validate(uint32_t expected_type) const
|
||||
|
||||
device_manager::device_manager(const void *root_table) :
|
||||
m_lapic(nullptr),
|
||||
m_num_ioapics(0)
|
||||
m_num_ioapics(0),
|
||||
m_pci(nullptr),
|
||||
m_num_pci_groups(0)
|
||||
{
|
||||
kassert(root_table != 0, "ACPI root table pointer is null.");
|
||||
|
||||
@@ -118,6 +129,10 @@ device_manager::load_xsdt(const acpi_xsdt *xsdt)
|
||||
load_apic(reinterpret_cast<const acpi_apic *>(header));
|
||||
break;
|
||||
|
||||
case acpi_mcfg::type_id:
|
||||
load_mcfg(reinterpret_cast<const acpi_mcfg *>(header));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -205,3 +220,87 @@ device_manager::load_apic(const acpi_apic *apic)
|
||||
m_ioapics[0]->dump_redirs();
|
||||
m_lapic->enable();
|
||||
}
|
||||
|
||||
static uint32_t *
|
||||
base_for(uint32_t *group, int bus, int dev, int func)
|
||||
{
|
||||
return kutil::offset_pointer(group,
|
||||
(bus << 20) + (dev << 15) + (func << 12));
|
||||
}
|
||||
|
||||
static bool
|
||||
check_function(uint32_t *group, int bus, int dev, int func)
|
||||
{
|
||||
uint32_t *base = base_for(group, bus, dev, func);
|
||||
|
||||
uint32_t vendor = base[0] & 0xffff;
|
||||
uint32_t device = (base[0] >> 16) & 0xffff;
|
||||
if (vendor == 0xffff) return false;
|
||||
|
||||
uint32_t revision = base[2] & 0xff;
|
||||
uint32_t subclass = (base[2] >> 16) & 0xff;
|
||||
uint32_t devclass = (base[2] >> 24) & 0xff;
|
||||
|
||||
uint32_t header = (base[3] >> 16) & 0x7f;
|
||||
bool multi = ((base[3] >> 16) & 0x80) == 0x80;
|
||||
|
||||
log::info(logs::devices, "Found PCIe device at %2d:%d:%d of type %d.%d id %x:%x",
|
||||
bus, dev, func, devclass, subclass, vendor, device);
|
||||
|
||||
if (header == 0) {
|
||||
log::debug(logs::devices, " Interrupt: %d", (base[15] >> 8) & 0xff);
|
||||
for (int i = 0; i < 5; ++i)
|
||||
log::debug(logs::devices, " BAR %d: %x", i + 1, base[i + 4]);
|
||||
}
|
||||
|
||||
return multi;
|
||||
}
|
||||
|
||||
static void
|
||||
check_device(uint32_t *group, int bus, int dev)
|
||||
{
|
||||
if (check_function(group, bus, dev, 0)) {
|
||||
for (int i = 1; i < 8; ++i)
|
||||
check_function(group, bus, dev, i);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
enumerate_devices(pci_group &group)
|
||||
{
|
||||
for (int bus = group.bus_start; bus <= group.bus_end; ++bus) {
|
||||
for (int dev = 0; dev < 32; ++dev) {
|
||||
check_device(group.base, bus - group.bus_start, dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
device_manager::load_mcfg(const acpi_mcfg *mcfg)
|
||||
{
|
||||
size_t count = acpi_table_entries(mcfg, sizeof(acpi_mcfg_entry));
|
||||
|
||||
m_pci = new pci_group[count];
|
||||
m_num_pci_groups = count;
|
||||
|
||||
page_manager *pm = page_manager::get();
|
||||
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
const acpi_mcfg_entry &mcfge = mcfg->entries[i];
|
||||
|
||||
m_pci[i].group = mcfge.group;
|
||||
m_pci[i].bus_start = mcfge.bus_start;
|
||||
m_pci[i].bus_end = mcfge.bus_end;
|
||||
m_pci[i].base = reinterpret_cast<uint32_t *>(mcfge.base);
|
||||
|
||||
int num_busses = m_pci[i].bus_end - m_pci[i].bus_start + 1;
|
||||
|
||||
/// Map the MMIO space into memory
|
||||
pm->map_offset_pointer(reinterpret_cast<void **>(&m_pci[i].base),
|
||||
(num_busses << 20));
|
||||
|
||||
log::debug(logs::devices, " Found MCFG entry: base %lx group %d bus %d-%d",
|
||||
mcfge.base, mcfge.group, mcfge.bus_start, mcfge.bus_end);
|
||||
enumerate_devices(m_pci[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
struct acpi_xsdt;
|
||||
struct acpi_apic;
|
||||
struct acpi_mcfg;
|
||||
|
||||
class lapic;
|
||||
class ioapic;
|
||||
struct pci_group;
|
||||
|
||||
class device_manager
|
||||
{
|
||||
@@ -18,12 +20,16 @@ public:
|
||||
ioapic * get_ioapic(int i);
|
||||
|
||||
private:
|
||||
static const int max_ioapics = 16;
|
||||
|
||||
lapic *m_lapic;
|
||||
|
||||
static const int max_ioapics = 16;
|
||||
ioapic *m_ioapics[16];
|
||||
int m_num_ioapics;
|
||||
|
||||
pci_group *m_pci;
|
||||
int m_num_pci_groups;
|
||||
|
||||
void load_xsdt(const acpi_xsdt *xsdt);
|
||||
void load_apic(const acpi_apic *apic);
|
||||
void load_mcfg(const acpi_mcfg *mcfg);
|
||||
};
|
||||
|
||||
@@ -6,12 +6,19 @@
|
||||
|
||||
inline void * operator new (size_t, void *p) throw() { return p; }
|
||||
|
||||
using addr_t = uint64_t;
|
||||
|
||||
namespace kutil {
|
||||
|
||||
void * memset(void *p, uint8_t v, size_t n);
|
||||
|
||||
template <typename T>
|
||||
T read_from(const void *p) { return *reinterpret_cast<const T *>(p); }
|
||||
inline T read_from(const void *p) { return *reinterpret_cast<const T *>(p); }
|
||||
|
||||
template <typename T>
|
||||
inline T * offset_pointer(T *p, size_t offset)
|
||||
{
|
||||
return reinterpret_cast<T *>(reinterpret_cast<addr_t>(p) + offset);
|
||||
}
|
||||
|
||||
} // namespace kutil
|
||||
|
||||
Reference in New Issue
Block a user