blob: 781f299dbcd9568ab1202407381e3006c5e6f530 [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 crate::ffa_v1_1::partition_info_descriptor;
7use thiserror::Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +02008use uuid::Uuid;
Balint Dobszay2338bd32024-12-19 19:00:14 +01009use zerocopy::{FromBytes, IntoBytes};
Balint Dobszay5bf492f2024-07-29 17:21:32 +020010
Balint Dobszaya5846852025-02-26 15:38:53 +010011/// Rich error types returned by this module. Should be converted to [`crate::FfaError`] when used
12/// with the `FFA_ERROR` interface.
Balint Dobszay2338bd32024-12-19 19:00:14 +010013#[derive(Debug, Error)]
14pub enum Error {
15 #[error("Invalid buffer size")]
16 InvalidBufferSize,
17 #[error("Malformed descriptor")]
18 MalformedDescriptor,
19}
20
21impl From<Error> for crate::FfaError {
22 fn from(_value: Error) -> Self {
23 Self::InvalidParameters
24 }
25}
26
Balint Dobszaya5846852025-02-26 15:38:53 +010027/// Type of partition identified by the partition ID.
Balint Dobszay2338bd32024-12-19 19:00:14 +010028#[derive(Clone, Copy, Debug, PartialEq, Eq)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020029pub enum PartitionIdType {
Balint Dobszaya5846852025-02-26 15:38:53 +010030 /// Partition ID is a PE endpoint ID. Contains the number of execution contexts implemented by
31 /// this partition.
Balint Dobszay2338bd32024-12-19 19:00:14 +010032 PeEndpoint { execution_ctx_count: u16 },
Balint Dobszaya5846852025-02-26 15:38:53 +010033 /// Partition ID is a SEPID for an independent peripheral device.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020034 SepidIndep,
Balint Dobszaya5846852025-02-26 15:38:53 +010035 /// Partition ID is a SEPID for an dependent peripheral device. Contains the ID of the proxy
36 /// endpoint for a dependent peripheral device.
Balint Dobszay2338bd32024-12-19 19:00:14 +010037 SepidDep { proxy_endpoint_id: u16 },
Balint Dobszaya5846852025-02-26 15:38:53 +010038 /// Partition ID is an auxiliary ID.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020039 Aux,
40}
41
Balint Dobszay2338bd32024-12-19 19:00:14 +010042impl PartitionIdType {
43 const SHIFT: usize = 4;
44 const MASK: u32 = 0b11;
45 const PE_ENDPOINT: u32 = 0b00;
46 const SEPID_INDEP: u32 = 0b01;
47 const SEPID_DEP: u32 = 0b10;
48 const AUX: u32 = 0b11;
49}
50
Balint Dobszaya5846852025-02-26 15:38:53 +010051/// Properties of a partition.
Balint Dobszay2338bd32024-12-19 19:00:14 +010052#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
53pub struct PartitionProperties {
Balint Dobszaya5846852025-02-26 15:38:53 +010054 /// The partition supports receipt of direct requests.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020055 pub support_direct_req_rec: bool,
Balint Dobszaya5846852025-02-26 15:38:53 +010056 /// The partition can send direct requests.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020057 pub support_direct_req_send: bool,
Balint Dobszaya5846852025-02-26 15:38:53 +010058 /// The partition can send and receive indirect messages.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020059 pub support_indirect_msg: bool,
Balint Dobszaya5846852025-02-26 15:38:53 +010060 /// The partition supports receipt of notifications.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020061 pub support_notif_rec: bool,
Balint Dobszaya5846852025-02-26 15:38:53 +010062 /// The partition must be informed about each VM that is created by the Hypervisor.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020063 pub subscribe_vm_created: bool,
Balint Dobszaya5846852025-02-26 15:38:53 +010064 /// The partition must be informed about each VM that is destroyed by the Hypervisor.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020065 pub subscribe_vm_destroyed: bool,
Balint Dobszaya5846852025-02-26 15:38:53 +010066 /// The partition runs in the AArch64 execution state.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020067 pub is_aarch64: bool,
68}
69
Balint Dobszay2338bd32024-12-19 19:00:14 +010070impl PartitionProperties {
71 const SUPPORT_DIRECT_REQ_REC_SHIFT: usize = 0;
72 const SUPPORT_DIRECT_REQ_SEND_SHIFT: usize = 1;
73 const SUPPORT_INDIRECT_MSG_SHIFT: usize = 2;
74 const SUPPORT_NOTIF_REC_SHIFT: usize = 3;
75 const SUBSCRIBE_VM_CREATED_SHIFT: usize = 6;
76 const SUBSCRIBE_VM_DESTROYED_SHIFT: usize = 7;
77 const IS_AARCH64_SHIFT: usize = 8;
Balint Dobszay5bf492f2024-07-29 17:21:32 +020078}
79
Balint Dobszay2338bd32024-12-19 19:00:14 +010080struct PartPropWrapper(PartitionIdType, PartitionProperties);
Balint Dobszay5bf492f2024-07-29 17:21:32 +020081
Balint Dobszay2338bd32024-12-19 19:00:14 +010082impl From<PartPropWrapper> for (u32, u16) {
83 fn from(value: PartPropWrapper) -> Self {
84 let exec_ctx_count_or_proxy_id = match value.0 {
85 PartitionIdType::PeEndpoint {
86 execution_ctx_count,
87 } => execution_ctx_count,
88 PartitionIdType::SepidIndep => 0,
89 PartitionIdType::SepidDep { proxy_endpoint_id } => proxy_endpoint_id,
90 PartitionIdType::Aux => 0,
91 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +020092
Balint Dobszay2338bd32024-12-19 19:00:14 +010093 let mut props = match value.0 {
94 PartitionIdType::PeEndpoint { .. } => {
95 let mut p = PartitionIdType::PE_ENDPOINT << PartitionIdType::SHIFT;
Balint Dobszay5bf492f2024-07-29 17:21:32 +020096
Balint Dobszay2338bd32024-12-19 19:00:14 +010097 if value.1.support_direct_req_rec {
98 p |= 1 << PartitionProperties::SUPPORT_DIRECT_REQ_REC_SHIFT;
99 if value.1.subscribe_vm_created {
100 // TODO: how to handle if ABI is invoked at NS phys instance?
101 p |= 1 << PartitionProperties::SUBSCRIBE_VM_CREATED_SHIFT
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200102 }
Balint Dobszay2338bd32024-12-19 19:00:14 +0100103 if value.1.subscribe_vm_destroyed {
104 // TODO: how to handle if ABI is invoked at NS phys instance?
105 p |= 1 << PartitionProperties::SUBSCRIBE_VM_DESTROYED_SHIFT
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200106 }
107 }
Balint Dobszay2338bd32024-12-19 19:00:14 +0100108 if value.1.support_direct_req_send {
109 p |= 1 << PartitionProperties::SUPPORT_DIRECT_REQ_SEND_SHIFT
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200110 }
Balint Dobszay2338bd32024-12-19 19:00:14 +0100111 if value.1.support_indirect_msg {
112 p |= 1 << PartitionProperties::SUPPORT_INDIRECT_MSG_SHIFT
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200113 }
Balint Dobszay2338bd32024-12-19 19:00:14 +0100114 if value.1.support_notif_rec {
115 p |= 1 << PartitionProperties::SUPPORT_NOTIF_REC_SHIFT
116 }
117
118 p
119 }
120 PartitionIdType::SepidIndep => PartitionIdType::SEPID_INDEP << PartitionIdType::SHIFT,
121 PartitionIdType::SepidDep { .. } => {
122 PartitionIdType::SEPID_DEP << PartitionIdType::SHIFT
123 }
124 PartitionIdType::Aux => PartitionIdType::AUX << PartitionIdType::SHIFT,
125 };
126
127 if value.1.is_aarch64 {
128 props |= 1 << PartitionProperties::IS_AARCH64_SHIFT
129 }
130
131 (props, exec_ctx_count_or_proxy_id)
132 }
133}
134
135impl From<(u32, u16)> for PartPropWrapper {
136 fn from(value: (u32, u16)) -> Self {
137 let part_id_type = match (value.0 >> PartitionIdType::SHIFT) & PartitionIdType::MASK {
138 PartitionIdType::PE_ENDPOINT => PartitionIdType::PeEndpoint {
139 execution_ctx_count: value.1,
140 },
141 PartitionIdType::SEPID_INDEP => PartitionIdType::SepidIndep,
142 PartitionIdType::SEPID_DEP => PartitionIdType::SepidDep {
143 proxy_endpoint_id: value.1,
144 },
145 PartitionIdType::AUX => PartitionIdType::Aux,
146 _ => panic!(), // The match is exhaustive for a 2-bit value
147 };
148
149 let mut part_props = PartitionProperties::default();
150
151 if (value.0 >> PartitionIdType::SHIFT) & PartitionIdType::MASK
152 == PartitionIdType::PE_ENDPOINT
153 {
154 if (value.0 >> PartitionProperties::SUPPORT_DIRECT_REQ_REC_SHIFT) & 0b1 == 1 {
155 part_props.support_direct_req_rec = true;
156
157 if (value.0 >> PartitionProperties::SUBSCRIBE_VM_CREATED_SHIFT) & 0b1 == 1 {
158 part_props.subscribe_vm_created = true;
159 }
160
161 if (value.0 >> PartitionProperties::SUBSCRIBE_VM_DESTROYED_SHIFT) & 0b1 == 1 {
162 part_props.subscribe_vm_destroyed = true;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200163 }
164 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200165
Balint Dobszay2338bd32024-12-19 19:00:14 +0100166 if (value.0 >> PartitionProperties::SUPPORT_DIRECT_REQ_SEND_SHIFT) & 0b1 == 1 {
167 part_props.support_direct_req_send = true;
168 }
169
170 if (value.0 >> PartitionProperties::SUPPORT_INDIRECT_MSG_SHIFT) & 0b1 == 1 {
171 part_props.support_indirect_msg = true;
172 }
173
174 if (value.0 >> PartitionProperties::SUPPORT_NOTIF_REC_SHIFT) & 0b1 == 1 {
175 part_props.support_notif_rec = true;
176 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200177 }
178
Balint Dobszay2338bd32024-12-19 19:00:14 +0100179 if (value.0 >> PartitionProperties::IS_AARCH64_SHIFT) & 0b1 == 1 {
180 part_props.is_aarch64 = true;
181 }
182
183 PartPropWrapper(part_id_type, part_props)
184 }
185}
186
Balint Dobszaya5846852025-02-26 15:38:53 +0100187/// Partition information descriptor, returned by the `FFA_PARTITION_INFO_GET` interface.
Balint Dobszay2338bd32024-12-19 19:00:14 +0100188#[derive(Clone, Copy, Debug, PartialEq, Eq)]
189pub struct PartitionInfo {
190 pub uuid: Uuid,
191 pub partition_id: u16,
192 pub partition_id_type: PartitionIdType,
193 pub props: PartitionProperties,
194}
195
196impl PartitionInfo {
Balint Dobszaya5846852025-02-26 15:38:53 +0100197 const DESC_SIZE: usize = size_of::<partition_info_descriptor>();
Balint Dobszay2338bd32024-12-19 19:00:14 +0100198
Balint Dobszaya5846852025-02-26 15:38:53 +0100199 /// Serialize a list of partition information descriptors into a buffer. The `fill_uuid`
200 /// parameter controls whether the UUID field of the descriptor will be filled.
Balint Dobszay2338bd32024-12-19 19:00:14 +0100201 pub fn pack(descriptors: &[PartitionInfo], buf: &mut [u8], fill_uuid: bool) {
202 let mut offset = 0;
203
204 for desc in descriptors {
205 let mut desc_raw = partition_info_descriptor {
206 partition_id: desc.partition_id,
207 ..Default::default()
208 };
209
210 (
211 desc_raw.partition_props,
212 desc_raw.exec_ctx_count_or_proxy_id,
213 ) = PartPropWrapper(desc.partition_id_type, desc.props).into();
214
215 if fill_uuid {
216 desc_raw.uuid.copy_from_slice(desc.uuid.as_bytes());
217 }
218
219 desc_raw.write_to_prefix(&mut buf[offset..]).unwrap();
220 offset += Self::DESC_SIZE;
221 }
222 }
223}
224
Balint Dobszaya5846852025-02-26 15:38:53 +0100225/// Iterator of partition information descriptors.
Balint Dobszay2338bd32024-12-19 19:00:14 +0100226pub struct PartitionInfoIterator<'a> {
227 buf: &'a [u8],
228 offset: usize,
229 count: usize,
230}
231
232impl<'a> PartitionInfoIterator<'a> {
Balint Dobszaya5846852025-02-26 15:38:53 +0100233 /// Create an iterator of partition information descriptors from a buffer.
Balint Dobszay2338bd32024-12-19 19:00:14 +0100234 pub fn new(buf: &'a [u8], count: usize) -> Result<Self, Error> {
235 let Some(total_size) = count.checked_mul(PartitionInfo::DESC_SIZE) else {
236 return Err(Error::InvalidBufferSize);
237 };
238
239 if buf.len() < total_size {
240 return Err(Error::InvalidBufferSize);
241 }
242
243 Ok(Self {
244 buf,
245 offset: 0,
246 count,
247 })
248 }
249}
250
251impl Iterator for PartitionInfoIterator<'_> {
252 type Item = Result<PartitionInfo, Error>;
253
254 fn next(&mut self) -> Option<Self::Item> {
255 if self.count > 0 {
256 let offset = self.offset;
257 self.offset += PartitionInfo::DESC_SIZE;
258 self.count -= 1;
259
260 let Ok(desc_raw) = partition_info_descriptor::ref_from_bytes(
261 &self.buf[offset..offset + PartitionInfo::DESC_SIZE],
262 ) else {
263 return Some(Err(Error::MalformedDescriptor));
264 };
265
266 let partition_id = desc_raw.partition_id;
267
268 let wrapper = PartPropWrapper::from((
269 desc_raw.partition_props,
270 desc_raw.exec_ctx_count_or_proxy_id,
271 ));
272
273 let uuid = Uuid::from_bytes(desc_raw.uuid);
274
275 let desc = PartitionInfo {
276 uuid,
277 partition_id,
278 partition_id_type: wrapper.0,
279 props: wrapper.1,
280 };
281
282 return Some(Ok(desc));
283 }
284
285 None
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200286 }
287}
288
289#[cfg(test)]
290mod tests {
291 use super::*;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200292 use uuid::uuid;
293
Balint Dobszay2338bd32024-12-19 19:00:14 +0100294 // TODO: add tests with a known correct partition info blob
295
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200296 #[test]
297 fn part_info() {
Balint Dobszay2338bd32024-12-19 19:00:14 +0100298 let desc1 = PartitionInfo {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200299 uuid: uuid!("12345678-1234-1234-1234-123456789abc"),
Balint Dobszay2338bd32024-12-19 19:00:14 +0100300 partition_id: 0x8001,
301 partition_id_type: PartitionIdType::PeEndpoint {
302 execution_ctx_count: 1,
303 },
304 props: PartitionProperties {
305 support_direct_req_rec: true,
306 support_direct_req_send: true,
307 support_indirect_msg: false,
308 support_notif_rec: false,
309 subscribe_vm_created: true,
310 subscribe_vm_destroyed: true,
311 is_aarch64: true,
312 },
313 };
314
315 let desc2 = PartitionInfo {
316 uuid: uuid!("abcdef00-abcd-dcba-1234-abcdef012345"),
317 partition_id: 0x8002,
318 partition_id_type: PartitionIdType::SepidIndep,
319 props: PartitionProperties {
320 support_direct_req_rec: false,
321 support_direct_req_send: false,
322 support_indirect_msg: false,
323 support_notif_rec: false,
324 subscribe_vm_created: false,
325 subscribe_vm_destroyed: false,
326 is_aarch64: true,
327 },
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200328 };
329
330 let mut buf = [0u8; 0xff];
Balint Dobszay2338bd32024-12-19 19:00:14 +0100331 PartitionInfo::pack(&[desc1, desc2], &mut buf, true);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200332
Balint Dobszay2338bd32024-12-19 19:00:14 +0100333 let mut descriptors = PartitionInfoIterator::new(&buf, 2).unwrap();
334 let desc1_check = descriptors.next().unwrap().unwrap();
335 let desc2_check = descriptors.next().unwrap().unwrap();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200336
Balint Dobszay2338bd32024-12-19 19:00:14 +0100337 assert_eq!(desc1, desc1_check);
338 assert_eq!(desc2, desc2_check);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200339 }
340}