vm_topology/processor/
aarch64.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! ARM64-specific topology definitions.
5
6use super::ArchTopology;
7use super::InvalidTopology;
8use super::ProcessorTopology;
9use super::TopologyBuilder;
10use super::VpIndex;
11use super::VpInfo;
12use super::VpTopologyInfo;
13use aarch64defs::MpidrEl1;
14
15/// ARM64-specific topology information.
16#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
17#[derive(Debug, Copy, Clone)]
18#[non_exhaustive]
19pub struct Aarch64Topology {
20    gic: GicInfo,
21    /// Performance Interrupt GSIV (PMU)
22    #[cfg_attr(feature = "inspect", inspect(hex))]
23    pmu_gsiv: u32,
24}
25
26impl ArchTopology for Aarch64Topology {
27    type ArchVpInfo = Aarch64VpInfo;
28    type BuilderState = Aarch64TopologyBuilderState;
29
30    fn vp_topology(_topology: &ProcessorTopology<Self>, info: &Self::ArchVpInfo) -> VpTopologyInfo {
31        VpTopologyInfo {
32            socket: info.mpidr.aff2().into(),
33            core: info.mpidr.aff1().into(),
34            thread: info.mpidr.aff0().into(),
35        }
36    }
37}
38
39/// Aarch64-specific [`TopologyBuilder`] state.
40pub struct Aarch64TopologyBuilderState {
41    gic: GicInfo,
42    pmu_gsiv: u32,
43}
44
45/// GIC information
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
48pub struct GicInfo {
49    /// GIC distributor base
50    #[cfg_attr(feature = "inspect", inspect(hex))]
51    pub gic_distributor_base: u64,
52    /// GIC redistributors base
53    #[cfg_attr(feature = "inspect", inspect(hex))]
54    pub gic_redistributors_base: u64,
55}
56
57/// ARM64 specific VP info.
58#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
59#[derive(Debug, Copy, Clone)]
60pub struct Aarch64VpInfo {
61    /// The base info.
62    #[cfg_attr(feature = "inspect", inspect(flatten))]
63    pub base: VpInfo,
64    /// The MPIDR_EL1 value of the processor.
65    #[cfg_attr(feature = "inspect", inspect(hex, with = "|&x| u64::from(x)"))]
66    pub mpidr: MpidrEl1,
67    /// GIC Redistributor Address
68    #[cfg_attr(feature = "inspect", inspect(hex))]
69    pub gicr: u64,
70    /// Performance Interrupt GSIV (PMU)
71    #[cfg_attr(feature = "inspect", inspect(hex))]
72    pub pmu_gsiv: u32,
73}
74
75impl AsRef<VpInfo> for Aarch64VpInfo {
76    fn as_ref(&self) -> &VpInfo {
77        &self.base
78    }
79}
80
81impl TopologyBuilder<Aarch64Topology> {
82    /// Returns a builder for creating an x86 processor topology.
83    pub fn new_aarch64(gic: GicInfo, pmu_gsiv: u32) -> Self {
84        Self {
85            vps_per_socket: 1,
86            smt_enabled: false,
87            arch: Aarch64TopologyBuilderState { gic, pmu_gsiv },
88        }
89    }
90
91    /// Builds a processor topology with `proc_count` processors.
92    pub fn build(
93        &self,
94        proc_count: u32,
95    ) -> Result<ProcessorTopology<Aarch64Topology>, InvalidTopology> {
96        if proc_count >= 256 {
97            return Err(InvalidTopology::TooManyVps {
98                requested: proc_count,
99                max: u8::MAX.into(),
100            });
101        }
102        let mpidrs = (0..proc_count).map(|vp_index| {
103            // TODO: construct mpidr appropriately for the specified
104            // topology.
105            let uni_proc = proc_count == 1;
106            let mut aff = (0..4).map(|i| (vp_index >> (8 * i)) as u8);
107            MpidrEl1::new()
108                .with_res1_31(true)
109                .with_u(uni_proc)
110                .with_aff0(aff.next().unwrap())
111                .with_aff1(aff.next().unwrap())
112                .with_aff2(aff.next().unwrap())
113                .with_aff3(aff.next().unwrap())
114        });
115        self.build_with_vp_info(mpidrs.enumerate().map(|(id, mpidr)| Aarch64VpInfo {
116            base: VpInfo {
117                vp_index: VpIndex::new(id as u32),
118                vnode: 0,
119            },
120            mpidr,
121            gicr: self.arch.gic.gic_redistributors_base
122                + id as u64 * aarch64defs::GIC_REDISTRIBUTOR_SIZE,
123            pmu_gsiv: self.arch.pmu_gsiv,
124        }))
125    }
126
127    /// Builds a processor topology with processors with the specified information.
128    pub fn build_with_vp_info(
129        &self,
130        vps: impl IntoIterator<Item = Aarch64VpInfo>,
131    ) -> Result<ProcessorTopology<Aarch64Topology>, InvalidTopology> {
132        let vps = Vec::from_iter(vps);
133        let mut smt_enabled = false;
134        for (i, vp) in vps.iter().enumerate() {
135            if i != vp.base.vp_index.index() as usize {
136                return Err(InvalidTopology::InvalidVpIndices);
137            }
138
139            if vp.mpidr.mt() {
140                smt_enabled = true;
141            }
142        }
143
144        Ok(ProcessorTopology {
145            vps,
146            smt_enabled,
147            vps_per_socket: self.vps_per_socket,
148            arch: Aarch64Topology {
149                gic: self.arch.gic,
150                pmu_gsiv: self.arch.pmu_gsiv,
151            },
152        })
153    }
154}
155
156impl ProcessorTopology<Aarch64Topology> {
157    /// Returns the GIC distributor base
158    pub fn gic_distributor_base(&self) -> u64 {
159        self.arch.gic.gic_distributor_base
160    }
161
162    /// Returns the GIC redistributors base
163    pub fn gic_redistributors_base(&self) -> u64 {
164        self.arch.gic.gic_redistributors_base
165    }
166
167    /// Returns the PMU GSIV
168    pub fn pmu_gsiv(&self) -> u32 {
169        self.arch.pmu_gsiv
170    }
171}