From 712cd692420cc3e6441b808ebdd6cea068a42d48 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Tue, 8 May 2018 01:02:34 -0700 Subject: [PATCH] Put devices into a device vector. --- src/kernel/device_manager.cpp | 130 ++++++++++++++++++++-------------- src/kernel/device_manager.h | 39 +++++++++- src/modules/kutil/vector.h | 38 +++++++++- 3 files changed, 148 insertions(+), 59 deletions(-) diff --git a/src/kernel/device_manager.cpp b/src/kernel/device_manager.cpp index 9612f89..5b2b07d 100644 --- a/src/kernel/device_manager.cpp +++ b/src/kernel/device_manager.cpp @@ -52,6 +52,22 @@ acpi_table_header::validate(uint32_t expected_type) const return !expected_type || (expected_type == type); } + +pci_device::pci_device() : + m_base(nullptr), + m_bus_addr(0), + m_vendor(0), + m_device(0), + m_class(0), + m_subclass(0), + m_prog_if(0), + m_revision(0), + m_irq(isr::isrIgnoreF), + m_header_type(0) +{ +} + + device_manager::device_manager(const void *root_table) : m_lapic(nullptr), m_num_ioapics(0) @@ -210,63 +226,12 @@ device_manager::load_apic(const acpi_apic *apic) 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 %02d:%02d:%d of type %d.%d id %04x:%04x", - bus, dev, func, devclass, subclass, vendor, device); - - if (header == 0) { - log::debug(logs::devices, " Interrupt: %d", (base[15] >> 8) & 0xff); - } - - 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.set_size(count); + m_devices.set_capacity(16); page_manager *pm = page_manager::get(); @@ -286,6 +251,65 @@ device_manager::load_mcfg(const acpi_mcfg *mcfg) 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]); + } + + probe_pci(); +} + +/* +static bool +check_function(uint32_t *group, int bus, int dev, int func) +{ +} +*/ + +void +device_manager::probe_pci() +{ + for (auto &pci : m_pci) { + log::debug(logs::devices, "Probing PCI group at base %016lx", pci.base); + + for (int bus = pci.bus_start; bus <= pci.bus_end; ++bus) { + for (int dev = 0; dev < 32; ++dev) { + if (!pci.has_device(bus, dev, 0)) continue; + + auto &d0 = m_devices.emplace(pci, bus, dev, 0); + if (!d0.multi()) continue; + + for (int i = 1; i < 8; ++i) { + if (pci.has_device(bus, dev, i)) + m_devices.emplace(pci, bus, dev, i); + } + } + } + } +} + +bool +pci_group::has_device(uint8_t bus, uint8_t device, uint8_t func) +{ + return (*base_for(bus, device, func) & 0xffff) != 0xffff; +} + +pci_device::pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t func) : + m_base(group.base_for(bus, device, func)), + m_bus_addr(bus_addr(bus, device, func)), + m_irq(isr::isrIgnoreF) +{ + m_vendor = m_base[0] & 0xffff; + m_device = (m_base[0] >> 16) & 0xffff; + + m_revision = m_base[2] & 0xff; + m_subclass = (m_base[2] >> 16) & 0xff; + m_class = (m_base[2] >> 24) & 0xff; + + m_header_type = (m_base[3] >> 16) & 0x7f; + m_multi = ((m_base[3] >> 16) & 0x80) == 0x80; + + log::info(logs::devices, "Found PCIe device at %02d:%02d:%d of type %d.%d id %04x:%04x", + bus, device, func, m_class, m_subclass, m_vendor, m_device); + + if (m_header_type == 0) { + log::debug(logs::devices, " Interrupt: %d", (m_base[15] >> 8) & 0xff); } } diff --git a/src/kernel/device_manager.h b/src/kernel/device_manager.h index e23108a..d9abc71 100644 --- a/src/kernel/device_manager.h +++ b/src/kernel/device_manager.h @@ -7,10 +7,10 @@ struct acpi_xsdt; struct acpi_apic; struct acpi_mcfg; - class lapic; class ioapic; enum class isr : uint8_t; +struct pci_group; /// Information about a discovered PCIe device @@ -21,11 +21,25 @@ public: pci_device(); /// Constructor - /// \arg group The group number of this device's bus + /// \arg group The group of this device's bus /// \arg bus The bus number this device is on /// \arg device The device number of this device /// \arg func The function number of this device - pci_device(uint16_t group, uint8_t bus, uint8_t device, uint8_t func); + pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t func); + + /// Check if this device is multi-function. + /// \returns True if this device is multi-function + inline bool multi() const { return m_multi; } + + /// Get a bus address, given the bus/device/function numbers. + /// \arg bus Number of the bus + /// \arg device Index of the device on the bus + /// \arg func The function number within the device + /// \returns The computed bus_addr + static inline uint16_t bus_addr(uint8_t bus, uint8_t device, uint8_t func) + { + return bus << 8 | device << 3 | func; + } private: uint32_t *m_base; @@ -40,6 +54,7 @@ private: uint8_t m_subclass; uint8_t m_prog_if; uint8_t m_revision; + bool m_multi; // Might as well cache these to fill out the struct align isr m_irq; @@ -55,6 +70,24 @@ struct pci_group uint16_t bus_end; uint32_t *base; + + /// Get the base address of the MMIO configuration registers for a device + /// \arg bus The bus number of the device (relative to this group) + /// \arg device The device number on the given bus + /// \arg func The function number on the device + /// \returns A pointer to the memory-mapped configuration registers + inline uint32_t * base_for(uint8_t bus, uint8_t device, uint8_t func) + { + return kutil::offset_pointer(base, + pci_device::bus_addr(bus, device, func) << 12); + } + + /// Check if the given device function is present. + /// \arg bus The bus number of the device (relative to this group) + /// \arg device The device number on the given bus + /// \arg func The function number on the device + /// \returns True if the device function is present + bool has_device(uint8_t bus, uint8_t device, uint8_t func); }; diff --git a/src/modules/kutil/vector.h b/src/modules/kutil/vector.h index 855dc46..928454c 100644 --- a/src/modules/kutil/vector.h +++ b/src/modules/kutil/vector.h @@ -3,6 +3,7 @@ /// Definition of a simple dynamic vector collection for use in kernel space #include +#include #include "kutil/memory.h" namespace kutil { @@ -58,19 +59,50 @@ public: delete [] m_elements; } + /// Get the size of the array. + /// \returns The number of elements in the array + inline size_t count() const { return m_size; } + /// Access an element in the array. inline T & operator[] (size_t i) { return m_elements[i]; } /// Access an element in the array. inline const T & operator[] (size_t i) const { return m_elements[i]; } + /// Get a pointer to the beginning for iteration. + /// \returns A pointer to the beginning of the array + T * begin() { return m_elements; } + + /// Get a pointer to the beginning for iteration. + /// \returns A pointer to the beginning of the array + const T * begin() const { return m_elements; } + + /// Get a pointer to the end for iteration. + /// \returns A pointer to the end of the array + T * end() { return m_elements + m_size; } + + /// Get a pointer to the end for iteration. + /// \returns A pointer to the end of the array + const T * end() const { return m_elements + m_size; } + /// Add an item onto the array by copying it. - /// \arg item the item to add - void append(const T& item) + /// \arg item The item to add + /// \returns A reference to the added item + T & append(const T& item) { ensure_capacity(m_size + 1); m_elements[m_size] = item; - m_size += 1; + return m_elements[m_size++]; + } + + /// Construct an item in place onto the end of the array. + /// \returns A reference to the added item + template + T & emplace(Args&&... args) + { + ensure_capacity(m_size + 1); + new (&m_elements[m_size]) T(std::forward(args)...); + return m_elements[m_size++]; } /// Remove an item from the end of the array.