blob: 23e4c06b2aa1e5ddfc7dfc52665c5149c88a7dbd [file] [log] [blame]
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001// SPDX-FileCopyrightText: Copyright 2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
Balint Dobszaya5846852025-02-26 15:38:53 +01004//! Implementation of FF-A partition discovery data structures.
5
Balint Dobszay2338bd32024-12-19 19:00:14 +01006use thiserror::Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +02007use uuid::Uuid;
Balint Dobszay2338bd32024-12-19 19:00:14 +01008use zerocopy::{FromBytes, IntoBytes};
Balint Dobszay5bf492f2024-07-29 17:21:32 +02009
Balint Dobszayde0dc802025-02-28 14:16:52 +010010// This module uses FF-A v1.1 types by default.
11// FF-A v1.2 specified some previously reserved bits in the partition info properties field, but
12// this doesn't change the descriptor format.
13use crate::{ffa_v1_1::partition_info_descriptor, Version};
14
15// Sanity check to catch if the descriptor format is changed.
16const _: () = assert!(
17 size_of::<crate::ffa_v1_1::partition_info_descriptor>()
18 == size_of::<crate::ffa_v1_2::partition_info_descriptor>()
19);
20
Balint Dobszaya5846852025-02-26 15:38:53 +010021/// Rich error types returned by this module. Should be converted to [`crate::FfaError`] when used
22/// with the `FFA_ERROR` interface.
Balint Dobszay2338bd32024-12-19 19:00:14 +010023#[derive(Debug, Error)]
24pub enum Error {
25 #[error("Invalid buffer size")]
26 InvalidBufferSize,
27 #[error("Malformed descriptor")]
28 MalformedDescriptor,
29}
30
31impl From<Error> for crate::FfaError {
32 fn from(_value: Error) -> Self {
33 Self::InvalidParameters
34 }
35}
36
Balint Dobszaya5846852025-02-26 15:38:53 +010037/// Type of partition identified by the partition ID.
Balint Dobszay2338bd32024-12-19 19:00:14 +010038#[derive(Clone, Copy, Debug, PartialEq, Eq)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020039pub enum PartitionIdType {
Balint Dobszaya5846852025-02-26 15:38:53 +010040 /// Partition ID is a PE endpoint ID. Contains the number of execution contexts implemented by
41 /// this partition.
Balint Dobszay2338bd32024-12-19 19:00:14 +010042 PeEndpoint { execution_ctx_count: u16 },
Balint Dobszaya5846852025-02-26 15:38:53 +010043 /// Partition ID is a SEPID for an independent peripheral device.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020044 SepidIndep,
Balint Dobszaya5846852025-02-26 15:38:53 +010045 /// Partition ID is a SEPID for an dependent peripheral device. Contains the ID of the proxy
46 /// endpoint for a dependent peripheral device.
Balint Dobszay2338bd32024-12-19 19:00:14 +010047 SepidDep { proxy_endpoint_id: u16 },
Balint Dobszaya5846852025-02-26 15:38:53 +010048 /// Partition ID is an auxiliary ID.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020049 Aux,
50}
51
Balint Dobszay2338bd32024-12-19 19:00:14 +010052impl PartitionIdType {
53 const SHIFT: usize = 4;
54 const MASK: u32 = 0b11;
55 const PE_ENDPOINT: u32 = 0b00;
56 const SEPID_INDEP: u32 = 0b01;
57 const SEPID_DEP: u32 = 0b10;
58 const AUX: u32 = 0b11;
59}
60
Balint Dobszaya5846852025-02-26 15:38:53 +010061/// Properties of a partition.
Balint Dobszay2338bd32024-12-19 19:00:14 +010062#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
63pub struct PartitionProperties {
Balint Dobszaya5846852025-02-26 15:38:53 +010064 /// The partition supports receipt of direct requests.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020065 pub support_direct_req_rec: bool,
Balint Dobszaya5846852025-02-26 15:38:53 +010066 /// The partition can send direct requests.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020067 pub support_direct_req_send: bool,
Balint Dobszayde0dc802025-02-28 14:16:52 +010068 /// The partition supports receipt of direct requests via the FFA_MSG_SEND_DIRECT_REQ2 ABI.
69 /// Added in FF-A v1.2
70 pub support_direct_req2_rec: Option<bool>,
71 /// The partition can send direct requests via the FFA_MSG_SEND_DIRECT_REQ2 ABI.
72 /// Added in FF-A v1.2
73 pub support_direct_req2_send: Option<bool>,
Balint Dobszaya5846852025-02-26 15:38:53 +010074 /// The partition can send and receive indirect messages.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020075 pub support_indirect_msg: bool,
Balint Dobszaya5846852025-02-26 15:38:53 +010076 /// The partition supports receipt of notifications.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020077 pub support_notif_rec: bool,
Balint Dobszaya5846852025-02-26 15:38:53 +010078 /// The partition must be informed about each VM that is created by the Hypervisor.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020079 pub subscribe_vm_created: bool,
Balint Dobszaya5846852025-02-26 15:38:53 +010080 /// The partition must be informed about each VM that is destroyed by the Hypervisor.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020081 pub subscribe_vm_destroyed: bool,
Balint Dobszaya5846852025-02-26 15:38:53 +010082 /// The partition runs in the AArch64 execution state.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020083 pub is_aarch64: bool,
84}
85
Balint Dobszay2338bd32024-12-19 19:00:14 +010086impl PartitionProperties {
87 const SUPPORT_DIRECT_REQ_REC_SHIFT: usize = 0;
88 const SUPPORT_DIRECT_REQ_SEND_SHIFT: usize = 1;
89 const SUPPORT_INDIRECT_MSG_SHIFT: usize = 2;
90 const SUPPORT_NOTIF_REC_SHIFT: usize = 3;
91 const SUBSCRIBE_VM_CREATED_SHIFT: usize = 6;
92 const SUBSCRIBE_VM_DESTROYED_SHIFT: usize = 7;
93 const IS_AARCH64_SHIFT: usize = 8;
Balint Dobszayde0dc802025-02-28 14:16:52 +010094 const SUPPORT_DIRECT_REQ2_REC_SHIFT: usize = 9;
95 const SUPPORT_DIRECT_REQ2_SEND_SHIFT: usize = 10;
Balint Dobszay5bf492f2024-07-29 17:21:32 +020096}
97
Balint Dobszayde0dc802025-02-28 14:16:52 +010098fn create_partition_properties(
99 version: Version,
100 id_type: PartitionIdType,
101 properties: PartitionProperties,
102) -> (u32, u16) {
103 let exec_ctx_count_or_proxy_id = match id_type {
104 PartitionIdType::PeEndpoint {
105 execution_ctx_count,
106 } => execution_ctx_count,
107 PartitionIdType::SepidIndep => 0,
108 PartitionIdType::SepidDep { proxy_endpoint_id } => proxy_endpoint_id,
109 PartitionIdType::Aux => 0,
110 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200111
Balint Dobszayde0dc802025-02-28 14:16:52 +0100112 let mut prop_bits = match id_type {
113 PartitionIdType::PeEndpoint { .. } => {
114 let mut p = PartitionIdType::PE_ENDPOINT << PartitionIdType::SHIFT;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200115
Balint Dobszayde0dc802025-02-28 14:16:52 +0100116 if properties.support_direct_req_rec {
117 p |= 1 << PartitionProperties::SUPPORT_DIRECT_REQ_REC_SHIFT;
118 if properties.subscribe_vm_created {
119 // TODO: how to handle if ABI is invoked at NS phys instance?
120 p |= 1 << PartitionProperties::SUBSCRIBE_VM_CREATED_SHIFT
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200121 }
Balint Dobszayde0dc802025-02-28 14:16:52 +0100122 if properties.subscribe_vm_destroyed {
123 // TODO: how to handle if ABI is invoked at NS phys instance?
124 p |= 1 << PartitionProperties::SUBSCRIBE_VM_DESTROYED_SHIFT
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200125 }
Balint Dobszay2338bd32024-12-19 19:00:14 +0100126 }
Balint Dobszay2338bd32024-12-19 19:00:14 +0100127
Balint Dobszayde0dc802025-02-28 14:16:52 +0100128 if properties.support_direct_req_send {
129 p |= 1 << PartitionProperties::SUPPORT_DIRECT_REQ_SEND_SHIFT
130 }
131
132 // For v1.2 and later it's mandatory to specify these properties
133 if version >= Version(1, 2) {
134 if properties.support_direct_req2_rec.unwrap() {
135 p |= 1 << PartitionProperties::SUPPORT_DIRECT_REQ2_REC_SHIFT
136 }
137
138 if properties.support_direct_req2_send.unwrap() {
139 p |= 1 << PartitionProperties::SUPPORT_DIRECT_REQ2_SEND_SHIFT
140 }
141 }
142
143 if properties.support_indirect_msg {
144 p |= 1 << PartitionProperties::SUPPORT_INDIRECT_MSG_SHIFT
145 }
146
147 if properties.support_notif_rec {
148 p |= 1 << PartitionProperties::SUPPORT_NOTIF_REC_SHIFT
149 }
150
151 p
Balint Dobszay2338bd32024-12-19 19:00:14 +0100152 }
Balint Dobszayde0dc802025-02-28 14:16:52 +0100153 PartitionIdType::SepidIndep => PartitionIdType::SEPID_INDEP << PartitionIdType::SHIFT,
154 PartitionIdType::SepidDep { .. } => PartitionIdType::SEPID_DEP << PartitionIdType::SHIFT,
155 PartitionIdType::Aux => PartitionIdType::AUX << PartitionIdType::SHIFT,
156 };
Balint Dobszay2338bd32024-12-19 19:00:14 +0100157
Balint Dobszayde0dc802025-02-28 14:16:52 +0100158 if properties.is_aarch64 {
159 prop_bits |= 1 << PartitionProperties::IS_AARCH64_SHIFT
Balint Dobszay2338bd32024-12-19 19:00:14 +0100160 }
Balint Dobszayde0dc802025-02-28 14:16:52 +0100161
162 (prop_bits, exec_ctx_count_or_proxy_id)
Balint Dobszay2338bd32024-12-19 19:00:14 +0100163}
164
Balint Dobszayde0dc802025-02-28 14:16:52 +0100165fn parse_partition_properties(
166 version: Version,
167 prop_bits: u32,
168 id_type: u16,
169) -> (PartitionIdType, PartitionProperties) {
170 let part_id_type = match (prop_bits >> PartitionIdType::SHIFT) & PartitionIdType::MASK {
171 PartitionIdType::PE_ENDPOINT => PartitionIdType::PeEndpoint {
172 execution_ctx_count: id_type,
173 },
174 PartitionIdType::SEPID_INDEP => PartitionIdType::SepidIndep,
175 PartitionIdType::SEPID_DEP => PartitionIdType::SepidDep {
176 proxy_endpoint_id: id_type,
177 },
178 PartitionIdType::AUX => PartitionIdType::Aux,
179 _ => panic!(), // The match is exhaustive for a 2-bit value
180 };
Balint Dobszay2338bd32024-12-19 19:00:14 +0100181
Balint Dobszayde0dc802025-02-28 14:16:52 +0100182 let mut part_props = PartitionProperties::default();
Balint Dobszay2338bd32024-12-19 19:00:14 +0100183
Balint Dobszayde0dc802025-02-28 14:16:52 +0100184 if matches!(part_id_type, PartitionIdType::PeEndpoint { .. }) {
185 if (prop_bits >> PartitionProperties::SUPPORT_DIRECT_REQ_REC_SHIFT) & 0b1 == 1 {
186 part_props.support_direct_req_rec = true;
Balint Dobszay2338bd32024-12-19 19:00:14 +0100187
Balint Dobszayde0dc802025-02-28 14:16:52 +0100188 if (prop_bits >> PartitionProperties::SUBSCRIBE_VM_CREATED_SHIFT) & 0b1 == 1 {
189 part_props.subscribe_vm_created = true;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200190 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200191
Balint Dobszayde0dc802025-02-28 14:16:52 +0100192 if (prop_bits >> PartitionProperties::SUBSCRIBE_VM_DESTROYED_SHIFT) & 0b1 == 1 {
193 part_props.subscribe_vm_destroyed = true;
Balint Dobszay2338bd32024-12-19 19:00:14 +0100194 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200195 }
196
Balint Dobszayde0dc802025-02-28 14:16:52 +0100197 if (prop_bits >> PartitionProperties::SUPPORT_DIRECT_REQ_SEND_SHIFT) & 0b1 == 1 {
198 part_props.support_direct_req_send = true;
Balint Dobszay2338bd32024-12-19 19:00:14 +0100199 }
200
Balint Dobszayde0dc802025-02-28 14:16:52 +0100201 if version >= Version(1, 2) {
202 part_props.support_direct_req2_rec =
203 Some((prop_bits >> PartitionProperties::SUPPORT_DIRECT_REQ2_REC_SHIFT) & 0b1 == 1);
204 part_props.support_direct_req2_send =
205 Some((prop_bits >> PartitionProperties::SUPPORT_DIRECT_REQ2_SEND_SHIFT) & 0b1 == 1);
206 }
207
208 if (prop_bits >> PartitionProperties::SUPPORT_INDIRECT_MSG_SHIFT) & 0b1 == 1 {
209 part_props.support_indirect_msg = true;
210 }
211
212 if (prop_bits >> PartitionProperties::SUPPORT_NOTIF_REC_SHIFT) & 0b1 == 1 {
213 part_props.support_notif_rec = true;
214 }
Balint Dobszay2338bd32024-12-19 19:00:14 +0100215 }
Balint Dobszayde0dc802025-02-28 14:16:52 +0100216
217 if (prop_bits >> PartitionProperties::IS_AARCH64_SHIFT) & 0b1 == 1 {
218 part_props.is_aarch64 = true;
219 }
220
221 (part_id_type, part_props)
Balint Dobszay2338bd32024-12-19 19:00:14 +0100222}
223
Balint Dobszaya5846852025-02-26 15:38:53 +0100224/// Partition information descriptor, returned by the `FFA_PARTITION_INFO_GET` interface.
Balint Dobszay2338bd32024-12-19 19:00:14 +0100225#[derive(Clone, Copy, Debug, PartialEq, Eq)]
226pub struct PartitionInfo {
227 pub uuid: Uuid,
228 pub partition_id: u16,
229 pub partition_id_type: PartitionIdType,
230 pub props: PartitionProperties,
231}
232
233impl PartitionInfo {
Balint Dobszayde0dc802025-02-28 14:16:52 +0100234 pub const DESC_SIZE: usize = size_of::<partition_info_descriptor>();
Balint Dobszay2338bd32024-12-19 19:00:14 +0100235
Balint Dobszaya5846852025-02-26 15:38:53 +0100236 /// Serialize a list of partition information descriptors into a buffer. The `fill_uuid`
237 /// parameter controls whether the UUID field of the descriptor will be filled.
Balint Dobszayde0dc802025-02-28 14:16:52 +0100238 pub fn pack(version: Version, descriptors: &[PartitionInfo], buf: &mut [u8], fill_uuid: bool) {
239 assert!((Version(1, 1)..=Version(1, 2)).contains(&version));
240
Balint Dobszay2338bd32024-12-19 19:00:14 +0100241 let mut offset = 0;
242
243 for desc in descriptors {
244 let mut desc_raw = partition_info_descriptor {
245 partition_id: desc.partition_id,
246 ..Default::default()
247 };
248
249 (
250 desc_raw.partition_props,
251 desc_raw.exec_ctx_count_or_proxy_id,
Balint Dobszayde0dc802025-02-28 14:16:52 +0100252 ) = create_partition_properties(version, desc.partition_id_type, desc.props);
Balint Dobszay2338bd32024-12-19 19:00:14 +0100253
254 if fill_uuid {
255 desc_raw.uuid.copy_from_slice(desc.uuid.as_bytes());
256 }
257
258 desc_raw.write_to_prefix(&mut buf[offset..]).unwrap();
259 offset += Self::DESC_SIZE;
260 }
261 }
262}
263
Balint Dobszaya5846852025-02-26 15:38:53 +0100264/// Iterator of partition information descriptors.
Balint Dobszay2338bd32024-12-19 19:00:14 +0100265pub struct PartitionInfoIterator<'a> {
Balint Dobszayde0dc802025-02-28 14:16:52 +0100266 version: Version,
Balint Dobszay2338bd32024-12-19 19:00:14 +0100267 buf: &'a [u8],
268 offset: usize,
269 count: usize,
270}
271
272impl<'a> PartitionInfoIterator<'a> {
Balint Dobszaya5846852025-02-26 15:38:53 +0100273 /// Create an iterator of partition information descriptors from a buffer.
Balint Dobszayde0dc802025-02-28 14:16:52 +0100274 pub fn new(version: Version, buf: &'a [u8], count: usize) -> Result<Self, Error> {
275 assert!((Version(1, 1)..=Version(1, 2)).contains(&version));
276
Balint Dobszay2338bd32024-12-19 19:00:14 +0100277 let Some(total_size) = count.checked_mul(PartitionInfo::DESC_SIZE) else {
278 return Err(Error::InvalidBufferSize);
279 };
280
281 if buf.len() < total_size {
282 return Err(Error::InvalidBufferSize);
283 }
284
285 Ok(Self {
Balint Dobszayde0dc802025-02-28 14:16:52 +0100286 version,
Balint Dobszay2338bd32024-12-19 19:00:14 +0100287 buf,
288 offset: 0,
289 count,
290 })
291 }
292}
293
294impl Iterator for PartitionInfoIterator<'_> {
295 type Item = Result<PartitionInfo, Error>;
296
297 fn next(&mut self) -> Option<Self::Item> {
298 if self.count > 0 {
299 let offset = self.offset;
300 self.offset += PartitionInfo::DESC_SIZE;
301 self.count -= 1;
302
303 let Ok(desc_raw) = partition_info_descriptor::ref_from_bytes(
304 &self.buf[offset..offset + PartitionInfo::DESC_SIZE],
305 ) else {
306 return Some(Err(Error::MalformedDescriptor));
307 };
308
309 let partition_id = desc_raw.partition_id;
310
Balint Dobszayde0dc802025-02-28 14:16:52 +0100311 let (partition_id_type, props) = parse_partition_properties(
312 self.version,
Balint Dobszay2338bd32024-12-19 19:00:14 +0100313 desc_raw.partition_props,
314 desc_raw.exec_ctx_count_or_proxy_id,
Balint Dobszayde0dc802025-02-28 14:16:52 +0100315 );
Balint Dobszay2338bd32024-12-19 19:00:14 +0100316
317 let uuid = Uuid::from_bytes(desc_raw.uuid);
318
319 let desc = PartitionInfo {
320 uuid,
321 partition_id,
Balint Dobszayde0dc802025-02-28 14:16:52 +0100322 partition_id_type,
323 props,
Balint Dobszay2338bd32024-12-19 19:00:14 +0100324 };
325
326 return Some(Ok(desc));
327 }
328
329 None
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200330 }
331}
332
333#[cfg(test)]
334mod tests {
335 use super::*;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200336 use uuid::uuid;
337
Balint Dobszay2338bd32024-12-19 19:00:14 +0100338 // TODO: add tests with a known correct partition info blob
339
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200340 #[test]
341 fn part_info() {
Balint Dobszay2338bd32024-12-19 19:00:14 +0100342 let desc1 = PartitionInfo {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200343 uuid: uuid!("12345678-1234-1234-1234-123456789abc"),
Balint Dobszay2338bd32024-12-19 19:00:14 +0100344 partition_id: 0x8001,
345 partition_id_type: PartitionIdType::PeEndpoint {
346 execution_ctx_count: 1,
347 },
348 props: PartitionProperties {
349 support_direct_req_rec: true,
350 support_direct_req_send: true,
351 support_indirect_msg: false,
352 support_notif_rec: false,
353 subscribe_vm_created: true,
354 subscribe_vm_destroyed: true,
355 is_aarch64: true,
Balint Dobszayde0dc802025-02-28 14:16:52 +0100356 support_direct_req2_rec: Some(true),
357 support_direct_req2_send: Some(true),
Balint Dobszay2338bd32024-12-19 19:00:14 +0100358 },
359 };
360
361 let desc2 = PartitionInfo {
362 uuid: uuid!("abcdef00-abcd-dcba-1234-abcdef012345"),
363 partition_id: 0x8002,
364 partition_id_type: PartitionIdType::SepidIndep,
365 props: PartitionProperties {
366 support_direct_req_rec: false,
367 support_direct_req_send: false,
368 support_indirect_msg: false,
369 support_notif_rec: false,
370 subscribe_vm_created: false,
371 subscribe_vm_destroyed: false,
372 is_aarch64: true,
Balint Dobszayde0dc802025-02-28 14:16:52 +0100373 support_direct_req2_rec: None,
374 support_direct_req2_send: None,
Balint Dobszay2338bd32024-12-19 19:00:14 +0100375 },
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200376 };
377
378 let mut buf = [0u8; 0xff];
Balint Dobszayde0dc802025-02-28 14:16:52 +0100379 PartitionInfo::pack(Version(1, 2), &[desc1, desc2], &mut buf, true);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200380
Balint Dobszayde0dc802025-02-28 14:16:52 +0100381 let mut descriptors = PartitionInfoIterator::new(Version(1, 2), &buf, 2).unwrap();
Balint Dobszay2338bd32024-12-19 19:00:14 +0100382 let desc1_check = descriptors.next().unwrap().unwrap();
383 let desc2_check = descriptors.next().unwrap().unwrap();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200384
Balint Dobszay2338bd32024-12-19 19:00:14 +0100385 assert_eq!(desc1, desc1_check);
386 assert_eq!(desc2, desc2_check);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200387 }
388}