vm_topology/processor/
aarch64.rs1use 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#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
17#[derive(Debug, Copy, Clone)]
18#[non_exhaustive]
19pub struct Aarch64Topology {
20 platform: Aarch64PlatformConfig,
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
36pub struct Aarch64TopologyBuilderState {
38 platform: Aarch64PlatformConfig,
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
44#[cfg_attr(feature = "inspect", inspect(external_tag))]
45pub enum GicVersion {
46 V2 {
49 #[cfg_attr(feature = "inspect", inspect(hex))]
51 cpu_interface_base: u64,
52 },
53 V3 {
55 #[cfg_attr(feature = "inspect", inspect(hex))]
57 redistributors_base: u64,
58 },
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
67#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
68pub struct Aarch64PlatformConfig {
69 #[cfg_attr(feature = "inspect", inspect(hex))]
71 pub gic_distributor_base: u64,
72 pub gic_version: GicVersion,
74 pub gic_v2m: Option<GicV2mInfo>,
76 pub pmu_gsiv: Option<u32>,
78 pub virt_timer_ppi: u32,
80 pub gic_nr_irqs: u32,
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
90pub struct GicV2mInfo {
91 #[cfg_attr(feature = "inspect", inspect(hex))]
93 pub frame_base: u64,
94 pub spi_base: u32,
96 pub spi_count: u32,
98}
99
100#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
102#[derive(Debug, Copy, Clone)]
103pub struct Aarch64VpInfo {
104 #[cfg_attr(feature = "inspect", inspect(flatten))]
106 pub base: VpInfo,
107 #[cfg_attr(feature = "inspect", inspect(hex, with = "|&x| u64::from(x)"))]
109 pub mpidr: MpidrEl1,
110 #[cfg_attr(feature = "inspect", inspect(hex))]
112 pub gicr: Option<u64>,
113 #[cfg_attr(feature = "inspect", inspect(hex))]
115 pub pmu_gsiv: Option<u32>,
116}
117
118impl AsRef<VpInfo> for Aarch64VpInfo {
119 fn as_ref(&self) -> &VpInfo {
120 &self.base
121 }
122}
123
124impl TopologyBuilder<Aarch64Topology> {
125 pub fn new_aarch64(platform: Aarch64PlatformConfig) -> Self {
127 Self {
128 vps_per_socket: 1,
129 smt_enabled: false,
130 arch: Aarch64TopologyBuilderState { platform },
131 }
132 }
133
134 pub fn build(
136 &self,
137 proc_count: u32,
138 ) -> Result<ProcessorTopology<Aarch64Topology>, InvalidTopology> {
139 if proc_count >= 256 {
140 return Err(InvalidTopology::TooManyVps {
141 requested: proc_count,
142 max: u8::MAX.into(),
143 });
144 }
145 if let GicVersion::V2 { .. } = self.arch.platform.gic_version {
146 if proc_count > 8 {
147 return Err(InvalidTopology::TooManyCpusForGicV2(proc_count));
148 }
149 }
150 if !(16..32).contains(&self.arch.platform.virt_timer_ppi) {
151 return Err(InvalidTopology::InvalidPpiIntid(
152 self.arch.platform.virt_timer_ppi,
153 ));
154 }
155 if let Some(gsiv) = self.arch.platform.pmu_gsiv {
156 if !(16..32).contains(&gsiv) {
157 return Err(InvalidTopology::InvalidPpiIntid(gsiv));
158 }
159 }
160 let nr = self.arch.platform.gic_nr_irqs;
161 if !(64..=992).contains(&nr) || !nr.is_multiple_of(32) {
162 return Err(InvalidTopology::InvalidGicNrIrqs(nr));
163 }
164 let mpidrs = (0..proc_count).map(|vp_index| {
165 let uni_proc = proc_count == 1;
168 let mut aff = (0..4).map(|i| (vp_index >> (8 * i)) as u8);
169 MpidrEl1::new()
170 .with_res1_31(true)
171 .with_u(uni_proc)
172 .with_aff0(aff.next().unwrap())
173 .with_aff1(aff.next().unwrap())
174 .with_aff2(aff.next().unwrap())
175 .with_aff3(aff.next().unwrap())
176 });
177 let gic_version = self.arch.platform.gic_version;
178 self.build_with_vp_info(mpidrs.enumerate().map(move |(id, mpidr)| {
179 let gicr = match gic_version {
182 GicVersion::V3 {
183 redistributors_base,
184 } => Some(redistributors_base + id as u64 * aarch64defs::GIC_REDISTRIBUTOR_SIZE),
185 GicVersion::V2 { .. } => None,
186 };
187 Aarch64VpInfo {
188 base: VpInfo {
189 vp_index: VpIndex::new(id as u32),
190 vnode: 0,
191 },
192 mpidr,
193 gicr,
194 pmu_gsiv: self.arch.platform.pmu_gsiv,
195 }
196 }))
197 }
198
199 pub fn build_with_vp_info(
201 &self,
202 vps: impl IntoIterator<Item = Aarch64VpInfo>,
203 ) -> Result<ProcessorTopology<Aarch64Topology>, InvalidTopology> {
204 let vps = Vec::from_iter(vps);
205 let mut smt_enabled = false;
206 for (i, vp) in vps.iter().enumerate() {
207 if i != vp.base.vp_index.index() as usize {
208 return Err(InvalidTopology::InvalidVpIndices);
209 }
210
211 if vp.mpidr.mt() {
212 smt_enabled = true;
213 }
214 }
215
216 Ok(ProcessorTopology {
217 vps,
218 smt_enabled,
219 vps_per_socket: self.vps_per_socket,
220 arch: Aarch64Topology {
221 platform: self.arch.platform,
222 },
223 })
224 }
225}
226
227impl ProcessorTopology<Aarch64Topology> {
228 pub fn gic_version(&self) -> GicVersion {
230 self.arch.platform.gic_version
231 }
232
233 pub fn gic_distributor_base(&self) -> u64 {
235 self.arch.platform.gic_distributor_base
236 }
237
238 pub fn pmu_gsiv(&self) -> Option<u32> {
240 self.arch.platform.pmu_gsiv
241 }
242
243 pub fn gic_v2m(&self) -> Option<GicV2mInfo> {
245 self.arch.platform.gic_v2m
246 }
247
248 pub fn virt_timer_ppi(&self) -> u32 {
250 self.arch.platform.virt_timer_ppi
251 }
252
253 pub fn gic_nr_irqs(&self) -> u32 {
255 self.arch.platform.gic_nr_irqs
256 }
257}