mcfg.rs 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. use crate::{handler::PhysicalMapping, sdt::SdtHeader, Acpi, AcpiError};
  2. use alloc::vec::Vec;
  3. use core::{mem, slice};
  4. /// Describes a set of regions of physical memory used to access the PCI-E configuration space. A
  5. /// region is created for each entry in the MCFG. Given the segment group, bus, device number, and
  6. /// function of a PCI-E device, the `physical_address` method on this will give you the physical
  7. /// address of the start of that device function's configuration space (each function has 4096
  8. /// bytes of configuration space in PCI-E).
  9. #[derive(Debug)]
  10. pub struct PciConfigRegions {
  11. regions: Vec<McfgEntry>,
  12. }
  13. impl PciConfigRegions {
  14. /// Get the physical address of the start of the configuration space for a given PCI-E device
  15. /// function. Returns `None` if there isn't an entry in the MCFG that manages that device.
  16. pub fn physical_address(&self, segment_group_no: u16, bus: u8, device: u8, function: u8) -> Option<u64> {
  17. // First, find the memory region that handles this segment and bus. This method is fine
  18. // because there should only be one region that handles each segment group + bus
  19. // combination.
  20. let region = self.regions.iter().find(|region| {
  21. region.pci_segment_group == segment_group_no
  22. && (region.bus_number_start..=region.bus_number_end).contains(&bus)
  23. })?;
  24. Some(
  25. region.base_address
  26. + ((u64::from(bus - region.bus_number_start) << 20)
  27. | (u64::from(device) << 15)
  28. | (u64::from(function) << 12)),
  29. )
  30. }
  31. }
  32. #[repr(C, packed)]
  33. pub(crate) struct Mcfg {
  34. header: SdtHeader,
  35. _reserved: u64,
  36. // Followed by `n` entries with format `McfgEntry`
  37. }
  38. impl Mcfg {
  39. fn entries(&self) -> &[McfgEntry] {
  40. let length = self.header.length as usize - mem::size_of::<Mcfg>();
  41. // intentionally round down in case length isn't an exact multiple of McfgEntry size
  42. let num_entries = length / mem::size_of::<McfgEntry>();
  43. unsafe {
  44. let pointer =
  45. (self as *const Mcfg as *const u8).offset(mem::size_of::<Mcfg>() as isize) as *const McfgEntry;
  46. slice::from_raw_parts(pointer, num_entries)
  47. }
  48. }
  49. }
  50. #[derive(Clone, Copy, Debug)]
  51. #[repr(C, packed)]
  52. struct McfgEntry {
  53. base_address: u64,
  54. pci_segment_group: u16,
  55. bus_number_start: u8,
  56. bus_number_end: u8,
  57. _reserved: u32,
  58. }
  59. pub(crate) fn parse_mcfg(acpi: &mut Acpi, mapping: &PhysicalMapping<Mcfg>) -> Result<(), AcpiError> {
  60. (*mapping).header.validate(crate::sdt::Signature::MCFG)?;
  61. acpi.pci_config_regions =
  62. Some(PciConfigRegions { regions: mapping.entries().iter().map(|&entry| entry).collect() });
  63. Ok(())
  64. }