Files
jsix_import/src/kernel/pci.h
Justin C. Miller c1d9b35e7c [bootproto] Create new bootproto lib
This is a rather large commit that is widely focused on cleaning things
out of the 'junk drawer' that is src/include. Most notably, several
things that were put in there because they needed somewhere where both
the kernel, boot, and init could read them have been moved to a new lib,
'bootproto'.

- Moved kernel_args.h and init_args.h to bootproto as kernel.h and
  init.h, respectively.

- Moved counted.h and pointer_manipulation.h into util, renaming the
  latter to util/pointers.h.

- Created a new src/include/arch for very arch-dependent definitions,
  and moved some kernel_memory.h constants like frame size, page table
  entry count, etc to arch/amd64/memory.h. Also created arch/memory.h
  which detects platform and includes the former.

- Got rid of kernel_memory.h entirely in favor of a new, cog-based
  approach. The new definitions/memory_layout.csv lists memory regions
  in descending order from the top of memory, their sizes, and whether
  they are shared outside the kernel (ie, boot needs to know them). The
  new header bootproto/memory.h exposes the addresses of the shared
  regions, while the kernel's memory.h gains the start and size of all
  the regions. Also renamed the badly-named page-offset area the linear
  area.

- The python build scripts got a few new features: the ability to parse
  the csv mentioned above in a new memory.py module; the ability to add
  dependencies to existing source files (The list of files that I had to
  pull out of the main list just to add them with the dependency on
  memory.h was getting too large. So I put them back into the sources
  list, and added the dependency post-hoc.); and the ability to
  reference 'source_root', 'build_root', and 'module_root' variables in
  .module files.

- Some utility functions that were in the kernel's memory.h got moved to
  util/pointers.h and util/misc.h, and misc.h's byteswap was renamed
  byteswap32 to be more specific.
2022-01-03 17:44:13 -08:00

142 lines
4.2 KiB
C++

#pragma once
/// \file pci.h
/// PCI devices and groups
#include <stdint.h>
#include <util/pointers.h>
struct pci_group;
enum class isr : uint8_t;
struct pci_cap
{
enum class type : uint8_t
{
msi = 0x05,
msix = 0x11
};
type id;
uint8_t next;
} __attribute__ ((packed));
/// 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);
/// Write to the MSI registers
/// \arg addr The address to write to the MSI address registers
/// \arg data The value to write to the MSI data register
void write_msi_regs(uintptr_t addr, uint16_t data);
/// 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;
pci_cap *m_msi;
/// 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 util::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);
};