blob: a8025b3f90a388fc8f503b8bf8db7c8650c4d7c5 [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 Dobszay2338bd32024-12-19 19:00:14 +01004use crate::ffa_v1_1::partition_info_descriptor;
5use thiserror::Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +02006use uuid::Uuid;
Balint Dobszay2338bd32024-12-19 19:00:14 +01007use zerocopy::{FromBytes, IntoBytes};
Balint Dobszay5bf492f2024-07-29 17:21:32 +02008
Balint Dobszay2338bd32024-12-19 19:00:14 +01009#[derive(Debug, Error)]
10pub enum Error {
11 #[error("Invalid buffer size")]
12 InvalidBufferSize,
13 #[error("Malformed descriptor")]
14 MalformedDescriptor,
15}
16
17impl From<Error> for crate::FfaError {
18 fn from(_value: Error) -> Self {
19 Self::InvalidParameters
20 }
21}
22
23#[derive(Clone, Copy, Debug, PartialEq, Eq)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020024pub enum PartitionIdType {
Balint Dobszay2338bd32024-12-19 19:00:14 +010025 PeEndpoint { execution_ctx_count: u16 },
Balint Dobszay5bf492f2024-07-29 17:21:32 +020026 SepidIndep,
Balint Dobszay2338bd32024-12-19 19:00:14 +010027 SepidDep { proxy_endpoint_id: u16 },
Balint Dobszay5bf492f2024-07-29 17:21:32 +020028 Aux,
29}
30
Balint Dobszay2338bd32024-12-19 19:00:14 +010031impl PartitionIdType {
32 const SHIFT: usize = 4;
33 const MASK: u32 = 0b11;
34 const PE_ENDPOINT: u32 = 0b00;
35 const SEPID_INDEP: u32 = 0b01;
36 const SEPID_DEP: u32 = 0b10;
37 const AUX: u32 = 0b11;
38}
39
40#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
41pub struct PartitionProperties {
42 /// Supports receipt of direct requests
Balint Dobszay5bf492f2024-07-29 17:21:32 +020043 pub support_direct_req_rec: bool,
Balint Dobszay2338bd32024-12-19 19:00:14 +010044 /// Can send direct requests
Balint Dobszay5bf492f2024-07-29 17:21:32 +020045 pub support_direct_req_send: bool,
Balint Dobszay2338bd32024-12-19 19:00:14 +010046 /// Can send and receive indirect messages
Balint Dobszay5bf492f2024-07-29 17:21:32 +020047 pub support_indirect_msg: bool,
Balint Dobszay2338bd32024-12-19 19:00:14 +010048 /// Supports receipt of notifications
Balint Dobszay5bf492f2024-07-29 17:21:32 +020049 pub support_notif_rec: bool,
Balint Dobszay2338bd32024-12-19 19:00:14 +010050 /// Must be informed about each VM that is created by the Hypervisor
Balint Dobszay5bf492f2024-07-29 17:21:32 +020051 pub subscribe_vm_created: bool,
Balint Dobszay2338bd32024-12-19 19:00:14 +010052 /// Must be informed about each VM that is destroyed by the Hypervisor
Balint Dobszay5bf492f2024-07-29 17:21:32 +020053 pub subscribe_vm_destroyed: bool,
Balint Dobszay2338bd32024-12-19 19:00:14 +010054 /// Partition runs in the AArch64 execution state
Balint Dobszay5bf492f2024-07-29 17:21:32 +020055 pub is_aarch64: bool,
56}
57
Balint Dobszay2338bd32024-12-19 19:00:14 +010058impl PartitionProperties {
59 const SUPPORT_DIRECT_REQ_REC_SHIFT: usize = 0;
60 const SUPPORT_DIRECT_REQ_SEND_SHIFT: usize = 1;
61 const SUPPORT_INDIRECT_MSG_SHIFT: usize = 2;
62 const SUPPORT_NOTIF_REC_SHIFT: usize = 3;
63 const SUBSCRIBE_VM_CREATED_SHIFT: usize = 6;
64 const SUBSCRIBE_VM_DESTROYED_SHIFT: usize = 7;
65 const IS_AARCH64_SHIFT: usize = 8;
Balint Dobszay5bf492f2024-07-29 17:21:32 +020066}
67
Balint Dobszay2338bd32024-12-19 19:00:14 +010068struct PartPropWrapper(PartitionIdType, PartitionProperties);
Balint Dobszay5bf492f2024-07-29 17:21:32 +020069
Balint Dobszay2338bd32024-12-19 19:00:14 +010070impl From<PartPropWrapper> for (u32, u16) {
71 fn from(value: PartPropWrapper) -> Self {
72 let exec_ctx_count_or_proxy_id = match value.0 {
73 PartitionIdType::PeEndpoint {
74 execution_ctx_count,
75 } => execution_ctx_count,
76 PartitionIdType::SepidIndep => 0,
77 PartitionIdType::SepidDep { proxy_endpoint_id } => proxy_endpoint_id,
78 PartitionIdType::Aux => 0,
79 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +020080
Balint Dobszay2338bd32024-12-19 19:00:14 +010081 let mut props = match value.0 {
82 PartitionIdType::PeEndpoint { .. } => {
83 let mut p = PartitionIdType::PE_ENDPOINT << PartitionIdType::SHIFT;
Balint Dobszay5bf492f2024-07-29 17:21:32 +020084
Balint Dobszay2338bd32024-12-19 19:00:14 +010085 if value.1.support_direct_req_rec {
86 p |= 1 << PartitionProperties::SUPPORT_DIRECT_REQ_REC_SHIFT;
87 if value.1.subscribe_vm_created {
88 // TODO: how to handle if ABI is invoked at NS phys instance?
89 p |= 1 << PartitionProperties::SUBSCRIBE_VM_CREATED_SHIFT
Balint Dobszay5bf492f2024-07-29 17:21:32 +020090 }
Balint Dobszay2338bd32024-12-19 19:00:14 +010091 if value.1.subscribe_vm_destroyed {
92 // TODO: how to handle if ABI is invoked at NS phys instance?
93 p |= 1 << PartitionProperties::SUBSCRIBE_VM_DESTROYED_SHIFT
Balint Dobszay5bf492f2024-07-29 17:21:32 +020094 }
95 }
Balint Dobszay2338bd32024-12-19 19:00:14 +010096 if value.1.support_direct_req_send {
97 p |= 1 << PartitionProperties::SUPPORT_DIRECT_REQ_SEND_SHIFT
Balint Dobszay5bf492f2024-07-29 17:21:32 +020098 }
Balint Dobszay2338bd32024-12-19 19:00:14 +010099 if value.1.support_indirect_msg {
100 p |= 1 << PartitionProperties::SUPPORT_INDIRECT_MSG_SHIFT
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200101 }
Balint Dobszay2338bd32024-12-19 19:00:14 +0100102 if value.1.support_notif_rec {
103 p |= 1 << PartitionProperties::SUPPORT_NOTIF_REC_SHIFT
104 }
105
106 p
107 }
108 PartitionIdType::SepidIndep => PartitionIdType::SEPID_INDEP << PartitionIdType::SHIFT,
109 PartitionIdType::SepidDep { .. } => {
110 PartitionIdType::SEPID_DEP << PartitionIdType::SHIFT
111 }
112 PartitionIdType::Aux => PartitionIdType::AUX << PartitionIdType::SHIFT,
113 };
114
115 if value.1.is_aarch64 {
116 props |= 1 << PartitionProperties::IS_AARCH64_SHIFT
117 }
118
119 (props, exec_ctx_count_or_proxy_id)
120 }
121}
122
123impl From<(u32, u16)> for PartPropWrapper {
124 fn from(value: (u32, u16)) -> Self {
125 let part_id_type = match (value.0 >> PartitionIdType::SHIFT) & PartitionIdType::MASK {
126 PartitionIdType::PE_ENDPOINT => PartitionIdType::PeEndpoint {
127 execution_ctx_count: value.1,
128 },
129 PartitionIdType::SEPID_INDEP => PartitionIdType::SepidIndep,
130 PartitionIdType::SEPID_DEP => PartitionIdType::SepidDep {
131 proxy_endpoint_id: value.1,
132 },
133 PartitionIdType::AUX => PartitionIdType::Aux,
134 _ => panic!(), // The match is exhaustive for a 2-bit value
135 };
136
137 let mut part_props = PartitionProperties::default();
138
139 if (value.0 >> PartitionIdType::SHIFT) & PartitionIdType::MASK
140 == PartitionIdType::PE_ENDPOINT
141 {
142 if (value.0 >> PartitionProperties::SUPPORT_DIRECT_REQ_REC_SHIFT) & 0b1 == 1 {
143 part_props.support_direct_req_rec = true;
144
145 if (value.0 >> PartitionProperties::SUBSCRIBE_VM_CREATED_SHIFT) & 0b1 == 1 {
146 part_props.subscribe_vm_created = true;
147 }
148
149 if (value.0 >> PartitionProperties::SUBSCRIBE_VM_DESTROYED_SHIFT) & 0b1 == 1 {
150 part_props.subscribe_vm_destroyed = true;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200151 }
152 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200153
Balint Dobszay2338bd32024-12-19 19:00:14 +0100154 if (value.0 >> PartitionProperties::SUPPORT_DIRECT_REQ_SEND_SHIFT) & 0b1 == 1 {
155 part_props.support_direct_req_send = true;
156 }
157
158 if (value.0 >> PartitionProperties::SUPPORT_INDIRECT_MSG_SHIFT) & 0b1 == 1 {
159 part_props.support_indirect_msg = true;
160 }
161
162 if (value.0 >> PartitionProperties::SUPPORT_NOTIF_REC_SHIFT) & 0b1 == 1 {
163 part_props.support_notif_rec = true;
164 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200165 }
166
Balint Dobszay2338bd32024-12-19 19:00:14 +0100167 if (value.0 >> PartitionProperties::IS_AARCH64_SHIFT) & 0b1 == 1 {
168 part_props.is_aarch64 = true;
169 }
170
171 PartPropWrapper(part_id_type, part_props)
172 }
173}
174
175#[derive(Clone, Copy, Debug, PartialEq, Eq)]
176pub struct PartitionInfo {
177 pub uuid: Uuid,
178 pub partition_id: u16,
179 pub partition_id_type: PartitionIdType,
180 pub props: PartitionProperties,
181}
182
183impl PartitionInfo {
184 pub const DESC_SIZE: usize = size_of::<partition_info_descriptor>();
185
186 pub fn pack(descriptors: &[PartitionInfo], buf: &mut [u8], fill_uuid: bool) {
187 let mut offset = 0;
188
189 for desc in descriptors {
190 let mut desc_raw = partition_info_descriptor {
191 partition_id: desc.partition_id,
192 ..Default::default()
193 };
194
195 (
196 desc_raw.partition_props,
197 desc_raw.exec_ctx_count_or_proxy_id,
198 ) = PartPropWrapper(desc.partition_id_type, desc.props).into();
199
200 if fill_uuid {
201 desc_raw.uuid.copy_from_slice(desc.uuid.as_bytes());
202 }
203
204 desc_raw.write_to_prefix(&mut buf[offset..]).unwrap();
205 offset += Self::DESC_SIZE;
206 }
207 }
208}
209
210pub struct PartitionInfoIterator<'a> {
211 buf: &'a [u8],
212 offset: usize,
213 count: usize,
214}
215
216impl<'a> PartitionInfoIterator<'a> {
217 pub fn new(buf: &'a [u8], count: usize) -> Result<Self, Error> {
218 let Some(total_size) = count.checked_mul(PartitionInfo::DESC_SIZE) else {
219 return Err(Error::InvalidBufferSize);
220 };
221
222 if buf.len() < total_size {
223 return Err(Error::InvalidBufferSize);
224 }
225
226 Ok(Self {
227 buf,
228 offset: 0,
229 count,
230 })
231 }
232}
233
234impl Iterator for PartitionInfoIterator<'_> {
235 type Item = Result<PartitionInfo, Error>;
236
237 fn next(&mut self) -> Option<Self::Item> {
238 if self.count > 0 {
239 let offset = self.offset;
240 self.offset += PartitionInfo::DESC_SIZE;
241 self.count -= 1;
242
243 let Ok(desc_raw) = partition_info_descriptor::ref_from_bytes(
244 &self.buf[offset..offset + PartitionInfo::DESC_SIZE],
245 ) else {
246 return Some(Err(Error::MalformedDescriptor));
247 };
248
249 let partition_id = desc_raw.partition_id;
250
251 let wrapper = PartPropWrapper::from((
252 desc_raw.partition_props,
253 desc_raw.exec_ctx_count_or_proxy_id,
254 ));
255
256 let uuid = Uuid::from_bytes(desc_raw.uuid);
257
258 let desc = PartitionInfo {
259 uuid,
260 partition_id,
261 partition_id_type: wrapper.0,
262 props: wrapper.1,
263 };
264
265 return Some(Ok(desc));
266 }
267
268 None
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200269 }
270}
271
272#[cfg(test)]
273mod tests {
274 use super::*;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200275 use uuid::uuid;
276
Balint Dobszay2338bd32024-12-19 19:00:14 +0100277 // TODO: add tests with a known correct partition info blob
278
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200279 #[test]
280 fn part_info() {
Balint Dobszay2338bd32024-12-19 19:00:14 +0100281 let desc1 = PartitionInfo {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200282 uuid: uuid!("12345678-1234-1234-1234-123456789abc"),
Balint Dobszay2338bd32024-12-19 19:00:14 +0100283 partition_id: 0x8001,
284 partition_id_type: PartitionIdType::PeEndpoint {
285 execution_ctx_count: 1,
286 },
287 props: PartitionProperties {
288 support_direct_req_rec: true,
289 support_direct_req_send: true,
290 support_indirect_msg: false,
291 support_notif_rec: false,
292 subscribe_vm_created: true,
293 subscribe_vm_destroyed: true,
294 is_aarch64: true,
295 },
296 };
297
298 let desc2 = PartitionInfo {
299 uuid: uuid!("abcdef00-abcd-dcba-1234-abcdef012345"),
300 partition_id: 0x8002,
301 partition_id_type: PartitionIdType::SepidIndep,
302 props: PartitionProperties {
303 support_direct_req_rec: false,
304 support_direct_req_send: false,
305 support_indirect_msg: false,
306 support_notif_rec: false,
307 subscribe_vm_created: false,
308 subscribe_vm_destroyed: false,
309 is_aarch64: true,
310 },
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200311 };
312
313 let mut buf = [0u8; 0xff];
Balint Dobszay2338bd32024-12-19 19:00:14 +0100314 PartitionInfo::pack(&[desc1, desc2], &mut buf, true);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200315
Balint Dobszay2338bd32024-12-19 19:00:14 +0100316 let mut descriptors = PartitionInfoIterator::new(&buf, 2).unwrap();
317 let desc1_check = descriptors.next().unwrap().unwrap();
318 let desc2_check = descriptors.next().unwrap().unwrap();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200319
Balint Dobszay2338bd32024-12-19 19:00:14 +0100320 assert_eq!(desc1, desc1_check);
321 assert_eq!(desc2, desc2_check);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200322 }
323}