Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 1 | // 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 Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 4 | use crate::ffa_v1_1::partition_info_descriptor; |
| 5 | use thiserror::Error; |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 6 | use uuid::Uuid; |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 7 | use zerocopy::{FromBytes, IntoBytes}; |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 8 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 9 | #[derive(Debug, Error)] |
| 10 | pub enum Error { |
| 11 | #[error("Invalid buffer size")] |
| 12 | InvalidBufferSize, |
| 13 | #[error("Malformed descriptor")] |
| 14 | MalformedDescriptor, |
| 15 | } |
| 16 | |
| 17 | impl 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 24 | pub enum PartitionIdType { |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 25 | PeEndpoint { execution_ctx_count: u16 }, |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 26 | SepidIndep, |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 27 | SepidDep { proxy_endpoint_id: u16 }, |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 28 | Aux, |
| 29 | } |
| 30 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 31 | impl 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)] |
| 41 | pub struct PartitionProperties { |
| 42 | /// Supports receipt of direct requests |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 43 | pub support_direct_req_rec: bool, |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 44 | /// Can send direct requests |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 45 | pub support_direct_req_send: bool, |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 46 | /// Can send and receive indirect messages |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 47 | pub support_indirect_msg: bool, |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 48 | /// Supports receipt of notifications |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 49 | pub support_notif_rec: bool, |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 50 | /// Must be informed about each VM that is created by the Hypervisor |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 51 | pub subscribe_vm_created: bool, |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 52 | /// Must be informed about each VM that is destroyed by the Hypervisor |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 53 | pub subscribe_vm_destroyed: bool, |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 54 | /// Partition runs in the AArch64 execution state |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 55 | pub is_aarch64: bool, |
| 56 | } |
| 57 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 58 | impl 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 66 | } |
| 67 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 68 | struct PartPropWrapper(PartitionIdType, PartitionProperties); |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 69 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 70 | impl 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 80 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 81 | let mut props = match value.0 { |
| 82 | PartitionIdType::PeEndpoint { .. } => { |
| 83 | let mut p = PartitionIdType::PE_ENDPOINT << PartitionIdType::SHIFT; |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 84 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 85 | 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 90 | } |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 91 | 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 94 | } |
| 95 | } |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 96 | if value.1.support_direct_req_send { |
| 97 | p |= 1 << PartitionProperties::SUPPORT_DIRECT_REQ_SEND_SHIFT |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 98 | } |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 99 | if value.1.support_indirect_msg { |
| 100 | p |= 1 << PartitionProperties::SUPPORT_INDIRECT_MSG_SHIFT |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 101 | } |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 102 | 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 | |
| 123 | impl 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 151 | } |
| 152 | } |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 153 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 154 | 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 165 | } |
| 166 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 167 | 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)] |
| 176 | pub struct PartitionInfo { |
| 177 | pub uuid: Uuid, |
| 178 | pub partition_id: u16, |
| 179 | pub partition_id_type: PartitionIdType, |
| 180 | pub props: PartitionProperties, |
| 181 | } |
| 182 | |
| 183 | impl 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 | |
| 210 | pub struct PartitionInfoIterator<'a> { |
| 211 | buf: &'a [u8], |
| 212 | offset: usize, |
| 213 | count: usize, |
| 214 | } |
| 215 | |
| 216 | impl<'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 | |
| 234 | impl 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 269 | } |
| 270 | } |
| 271 | |
| 272 | #[cfg(test)] |
| 273 | mod tests { |
| 274 | use super::*; |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 275 | use uuid::uuid; |
| 276 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 277 | // TODO: add tests with a known correct partition info blob |
| 278 | |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 279 | #[test] |
| 280 | fn part_info() { |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 281 | let desc1 = PartitionInfo { |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 282 | uuid: uuid!("12345678-1234-1234-1234-123456789abc"), |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 283 | 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 311 | }; |
| 312 | |
| 313 | let mut buf = [0u8; 0xff]; |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 314 | PartitionInfo::pack(&[desc1, desc2], &mut buf, true); |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 315 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 316 | 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 319 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame^] | 320 | assert_eq!(desc1, desc1_check); |
| 321 | assert_eq!(desc2, desc2_check); |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 322 | } |
| 323 | } |