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(feature = "inspect", inspect(hex, with = "|&x| u64::from(x)"))]
62    pub mpidr: MpidrEl1,
63    /// GIC Redistributor Address
64    #[cfg_attr(feature = "inspect", inspect(hex))]
65    pub gicr: u64,
66}
67
68impl AsRef<VpInfo> for Aarch64VpInfo {
69    fn as_ref(&self) -> &VpInfo {
70        &self.base
71    }
72}
73
74impl TopologyBuilder<Aarch64Topology> {
75    /// Returns a builder for creating an x86 processor topology.
76    pub fn new_aarch64(gic: GicInfo) -> Self {
77        Self {
78            vps_per_socket: 1,
79            smt_enabled: false,
80            arch: Aarch64TopologyBuilderState { gic },
81        }
82    }
83
84    /// Builds a processor topology with `proc_count` processors.
85    pub fn build(
86        &self,
87        proc_count: u32,
88    ) -> Result<ProcessorTopology<Aarch64Topology>, InvalidTopology> {
89        if proc_count >= 256 {
90            return Err(InvalidTopology::TooManyVps {
91                requested: proc_count,
92                max: u8::MAX.into(),
93            });
94        }
95        let mpidrs = (0..proc_count).map(|vp_index| {
96            // TODO: construct mpidr appropriately for the specified
97            // topology.
98            let uni_proc = proc_count == 1;
99            let mut aff = (0..4).map(|i| (vp_index >> (8 * i)) as u8);
100            MpidrEl1::new()
101                .with_res1_31(true)
102                .with_u(uni_proc)
103                .with_aff0(aff.next().unwrap())
104                .with_aff1(aff.next().unwrap())
105                .with_aff2(aff.next().unwrap())
106                .with_aff3(aff.next().unwrap())
107        });
108        self.build_with_vp_info(mpidrs.enumerate().map(|(id, mpidr)| Aarch64VpInfo {
109            base: VpInfo {
110                vp_index: VpIndex::new(id as u32),
111                vnode: 0,
112            },
113            mpidr,
114            gicr: self.arch.gic.gic_redistributors_base
115                + id as u64 * aarch64defs::GIC_REDISTRIBUTOR_SIZE,
116        }))
117    }
118
119    /// Builds a processor topology with processors with the specified information.
120    pub fn build_with_vp_info(
121        &self,
122        vps: impl IntoIterator<Item = Aarch64VpInfo>,
123    ) -> Result<ProcessorTopology<Aarch64Topology>, InvalidTopology> {
124        let vps = Vec::from_iter(vps);
125        let mut smt_enabled = false;
126        for (i, vp) in vps.iter().enumerate() {
127            if i != vp.base.vp_index.index() as usize {
128                return Err(InvalidTopology::InvalidVpIndices);
129            }
130
131            if vp.mpidr.mt() {
132                smt_enabled = true;
133            }
134        }
135
136        Ok(ProcessorTopology {
137            vps,
138            smt_enabled,
139            vps_per_socket: self.vps_per_socket,
140            arch: Aarch64Topology { gic: self.arch.gic },
141        })
142    }
143}
144
145impl ProcessorTopology<Aarch64Topology> {
146    /// Returns the GIC distributor base
147    pub fn gic_distributor_base(&self) -> u64 {
148        self.arch.gic.gic_distributor_base
149    }
150
151    /// Returns the GIC redistributors base
152    pub fn gic_redistributors_base(&self) -> u64 {
153        self.arch.gic.gic_redistributors_base
154    }
155}