From b389e75d33955974d87dbdb1ca07d77be56b2c23 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Wed, 9 May 2018 01:21:30 -0700 Subject: [PATCH] Move PCI classes to separate files --- src/kernel/device_manager.cpp | 80 ++++++---------------- src/kernel/device_manager.h | 92 ++----------------------- src/kernel/log.cpp | 1 + src/kernel/log.h | 3 +- src/kernel/main.cpp | 5 +- src/kernel/pci.cpp | 74 +++++++++++++++++++++ src/kernel/pci.h | 122 ++++++++++++++++++++++++++++++++++ 7 files changed, 231 insertions(+), 146 deletions(-) create mode 100644 src/kernel/pci.cpp create mode 100644 src/kernel/pci.h diff --git a/src/kernel/device_manager.cpp b/src/kernel/device_manager.cpp index 1b98c11..4dd508e 100644 --- a/src/kernel/device_manager.cpp +++ b/src/kernel/device_manager.cpp @@ -53,29 +53,12 @@ acpi_table_header::validate(uint32_t expected_type) const } -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) + m_lapic(nullptr) { kassert(root_table != 0, "ACPI root table pointer is null."); - kutil::memset(m_ioapics, 0, sizeof(m_ioapics)); - const acpi1_rsdp *acpi1 = reinterpret_cast(root_table); @@ -100,7 +83,7 @@ device_manager::device_manager(const void *root_table) : ioapic * device_manager::get_ioapic(int i) { - return (i < m_num_ioapics) ? m_ioapics[i] : nullptr; + return (i < m_ioapics.count()) ? m_ioapics[i] : nullptr; } static void @@ -115,17 +98,17 @@ device_manager::load_xsdt(const acpi_xsdt *xsdt) kassert(xsdt && acpi_validate(xsdt), "Invalid ACPI XSDT."); char sig[5] = {0,0,0,0,0}; - log::info(logs::devices, "ACPI 2.0+ tables loading"); + log::info(logs::device, "ACPI 2.0+ tables loading"); put_sig(sig, xsdt->header.type); - log::debug(logs::devices, " Found table %s", sig); + log::debug(logs::device, " Found table %s", sig); size_t num_tables = acpi_table_entries(xsdt, sizeof(void*)); for (size_t i = 0; i < num_tables; ++i) { const acpi_table_header *header = xsdt->headers[i]; put_sig(sig, header->type); - log::debug(logs::devices, " Found table %s", sig); + log::debug(logs::device, " Found table %s", sig); kassert(header->validate(), "Table failed validation."); @@ -162,7 +145,7 @@ device_manager::load_apic(const acpi_apic *apic) if (type == 1) { uint32_t *base = reinterpret_cast(kutil::read_from(p+4)); uint32_t base_gsr = kutil::read_from(p+8); - m_ioapics[m_num_ioapics++] = new ioapic(base, base_gsr); + m_ioapics.append(new ioapic(base, base_gsr)); } p += length; } @@ -183,7 +166,7 @@ device_manager::load_apic(const acpi_apic *apic) isr gsi = isr::irq00 + kutil::read_from(p+4); uint16_t flags = kutil::read_from(p+8); - log::debug(logs::devices, " Intr source override IRQ %d -> %d Pol %d Tri %d", + log::debug(logs::device, " Intr source override IRQ %d -> %d Pol %d Tri %d", source, gsi, (flags & 0x3), ((flags >> 2) & 0x3)); // TODO: in a multiple-IOAPIC system this might be elsewhere @@ -196,7 +179,7 @@ device_manager::load_apic(const acpi_apic *apic) uint8_t num = kutil::read_from(p + 5); uint16_t flags = kutil::read_from(p + 3); - log::debug(logs::devices, " LAPIC NMI Proc %d LINT%d Pol %d Tri %d", + log::debug(logs::device, " LAPIC NMI Proc %d LINT%d Pol %d Tri %d", kutil::read_from(p+2), kutil::read_from(p+5), kutil::read_from(p+3) & 0x3, @@ -207,7 +190,7 @@ device_manager::load_apic(const acpi_apic *apic) break; default: - log::debug(logs::devices, " APIC entry type %d", type); + log::debug(logs::device, " APIC entry type %d", type); } p += length; @@ -249,25 +232,18 @@ device_manager::load_mcfg(const acpi_mcfg *mcfg) pm->map_offset_pointer(reinterpret_cast(&m_pci[i].base), (num_busses << 20)); - log::debug(logs::devices, " Found MCFG entry: base %lx group %d bus %d-%d", + log::debug(logs::device, " Found MCFG entry: base %lx group %d bus %d-%d", mcfge.base, mcfge.group, mcfge.bus_start, mcfge.bus_end); } 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); + log::debug(logs::device, "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) { @@ -285,31 +261,19 @@ device_manager::probe_pci() } } -bool -pci_group::has_device(uint8_t bus, uint8_t device, uint8_t func) +void +device_manager::init_drivers() { - return (*base_for(bus, device, func) & 0xffff) != 0xffff; -} + // Eventually this should be e.g. a lookup into a loadable driver list + // for now, just look for AHCI devices + for (auto &device : m_devices) { + if (device.devclass() != 1 || device.subclass() != 6) + continue; -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; + if (device.progif() != 1) { + log::warn(logs::device, "Found SATA device %d:%d:%d, but not an AHCI interface.", + device.bus(), device.device(), device.function()); + } - 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 d9abc71..e16ec23 100644 --- a/src/kernel/device_manager.h +++ b/src/kernel/device_manager.h @@ -1,94 +1,14 @@ #pragma once /// \file device_manager.h -/// The device manager and related device classes. -#include +/// The device manager definition #include "kutil/vector.h" +#include "pci.h" 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 -class pci_device -{ -public: - /// Default constructor creates an empty object. - pci_device(); - - /// Constructor - /// \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(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; - - /// Bus address: 15:8 bus, 7:3 device, 2:0 device - uint16_t m_bus_addr; - - uint16_t m_vendor; - uint16_t m_device; - - uint8_t m_class; - 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; - uint8_t m_header_type; -}; - - -/// Represents data about a PCI bus group from the ACPI MCFG -struct pci_group -{ - uint16_t group; - uint16_t bus_start; - 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); -}; /// Manager for all system hardware devices @@ -109,6 +29,9 @@ public: /// otherwise nullptr. ioapic * get_ioapic(int i); + /// Intialize drivers for the current device list. + void init_drivers(); + private: /// Parse the ACPI XSDT and load relevant sub-tables. /// \arg xsdt Pointer to the XSDT from the firmware @@ -127,10 +50,7 @@ private: void probe_pci(); lapic *m_lapic; - - static const int max_ioapics = 16; - ioapic *m_ioapics[16]; - int m_num_ioapics; + kutil::vector m_ioapics; kutil::vector m_pci; kutil::vector m_devices; diff --git a/src/kernel/log.cpp b/src/kernel/log.cpp index c1b6231..e0ca21c 100644 --- a/src/kernel/log.cpp +++ b/src/kernel/log.cpp @@ -14,6 +14,7 @@ static const char *areas[] = { "mem ", "apic", "dev ", + "driv", nullptr }; diff --git a/src/kernel/log.h b/src/kernel/log.h index 0695fd6..f175edc 100644 --- a/src/kernel/log.h +++ b/src/kernel/log.h @@ -10,7 +10,8 @@ enum class logs boot, memory, apic, - devices, + device, + driver, max }; diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index 40266a7..74ce5be 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -50,7 +50,8 @@ init_console(const popcorn_data *header) log::init(cons); log::enable(logs::apic, log::level::info); - log::enable(logs::devices, log::level::debug); + log::enable(logs::device, log::level::debug); + log::enable(logs::driver, log::level::debug); log::enable(logs::memory, log::level::debug); } @@ -86,6 +87,8 @@ kernel_main(popcorn_data *header) log::info(logs::boot, "CPU Family %x Model %x Stepping %x", cpu.family(), cpu.model(), cpu.stepping()); + devices.init_drivers(); + // do_error_1(); // __asm__ __volatile__("int $15"); diff --git a/src/kernel/pci.cpp b/src/kernel/pci.cpp new file mode 100644 index 0000000..3f14029 --- /dev/null +++ b/src/kernel/pci.cpp @@ -0,0 +1,74 @@ +#include "kutil/assert.h" +#include "log.h" +#include "interrupts.h" +#include "pci.h" + + +pci_device::pci_device() : + m_base(nullptr), + m_bus_addr(0), + m_vendor(0), + m_device(0), + m_class(0), + m_subclass(0), + m_progif(0), + m_revision(0), + m_irq(isr::isrIgnoreF), + m_header_type(0) +{ +} + +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_progif = (m_base[2] >> 8) & 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::device, "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); +} + +uint32_t +pci_device::get_bar(unsigned i) +{ + if (m_header_type == 0) { + kassert(i < 6, "Requested BAR >5 for PCI device"); + } else if (m_header_type == 1) { + kassert(i < 2, "Requested BAR >1 for PCI bridge"); + } else { + kassert(0, "Requested BAR for other PCI device type"); + } + + return m_base[4+i]; +} + +void +pci_device::set_bar(unsigned i, uint32_t val) +{ + if (m_header_type == 0) { + kassert(i < 6, "Requested BAR >5 for PCI device"); + } else if (m_header_type == 1) { + kassert(i < 2, "Requested BAR >1 for PCI bridge"); + } else { + kassert(0, "Requested BAR for other PCI device type"); + } + + m_base[4+i] = val; +} + + +bool +pci_group::has_device(uint8_t bus, uint8_t device, uint8_t func) +{ + return (*base_for(bus, device, func) & 0xffff) != 0xffff; +} diff --git a/src/kernel/pci.h b/src/kernel/pci.h new file mode 100644 index 0000000..a0ba480 --- /dev/null +++ b/src/kernel/pci.h @@ -0,0 +1,122 @@ +#pragma once +/// \file pci.h +/// PCI devices and groups +#include +#include "kutil/memory.h" + +struct pci_group; +enum class isr : uint8_t; + + +/// Information about a discovered PCIe device +class pci_device +{ +public: + /// Default constructor creates an empty object. + pci_device(); + + /// Constructor + /// \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(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 the bus number this device is on. + /// \returns The bus number + inline uint8_t bus() const { return (m_bus_addr >> 8); } + + /// Get the device number of this device on its bus + /// \returns The device number + inline uint8_t device() const { return (m_bus_addr >> 3) & 0x1f; } + + /// Get the function number of this device on its device + /// \returns The function number + inline uint8_t function() const { return m_bus_addr & 0x7; } + + /// Get the device class + /// \returns The PCI device class + inline uint8_t devclass() const { return m_class; } + + /// Get the device subclass + /// \returns The PCI device subclass + inline uint8_t subclass() const { return m_subclass; } + + /// Get the device program interface + /// \returns The PCI device program interface + inline uint8_t progif() const { return m_progif; } + + /// Read one of the device's Base Address Registers + /// \arg i Which BAR to read (up to 5 for non-bridges) + /// \returns The contents of the BAR + uint32_t get_bar(unsigned i); + + /// Write one of the device's Base Address Registers + /// \arg i Which BAR to read (up to 5 for non-bridges) + /// \arg val The value to write + void set_bar(unsigned i, uint32_t val); + + /// 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; + + /// Bus address: 15:8 bus, 7:3 device, 2:0 device + uint16_t m_bus_addr; + + uint16_t m_vendor; + uint16_t m_device; + + uint8_t m_class; + uint8_t m_subclass; + uint8_t m_progif; + uint8_t m_revision; + bool m_multi; + + // Might as well cache these to fill out the struct align + isr m_irq; + uint8_t m_header_type; +}; + + +/// Represents data about a PCI bus group from the ACPI MCFG +struct pci_group +{ + uint16_t group; + uint16_t bus_start; + 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); +}; + +