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