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 | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 4 | //! Implementation of FF-A partition discovery data structures. |
| 5 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 6 | use crate::ffa_v1_1::partition_info_descriptor; |
| 7 | use thiserror::Error; |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 8 | use uuid::Uuid; |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 9 | use zerocopy::{FromBytes, IntoBytes}; |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 10 | |
Balint Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 11 | /// Rich error types returned by this module. Should be converted to [`crate::FfaError`] when used |
| 12 | /// with the `FFA_ERROR` interface. |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 13 | #[derive(Debug, Error)] |
| 14 | pub enum Error { |
| 15 | #[error("Invalid buffer size")] |
| 16 | InvalidBufferSize, |
| 17 | #[error("Malformed descriptor")] |
| 18 | MalformedDescriptor, |
| 19 | } |
| 20 | |
| 21 | impl From<Error> for crate::FfaError { |
| 22 | fn from(_value: Error) -> Self { |
| 23 | Self::InvalidParameters |
| 24 | } |
| 25 | } |
| 26 | |
Balint Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 27 | /// Type of partition identified by the partition ID. |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 28 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 29 | pub enum PartitionIdType { |
Balint Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 30 | /// Partition ID is a PE endpoint ID. Contains the number of execution contexts implemented by |
| 31 | /// this partition. |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 32 | PeEndpoint { execution_ctx_count: u16 }, |
Balint Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 33 | /// Partition ID is a SEPID for an independent peripheral device. |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 34 | SepidIndep, |
Balint Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 35 | /// Partition ID is a SEPID for an dependent peripheral device. Contains the ID of the proxy |
| 36 | /// endpoint for a dependent peripheral device. |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 37 | SepidDep { proxy_endpoint_id: u16 }, |
Balint Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 38 | /// Partition ID is an auxiliary ID. |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 39 | Aux, |
| 40 | } |
| 41 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 42 | impl 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 Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 51 | /// Properties of a partition. |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 52 | #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] |
| 53 | pub struct PartitionProperties { |
Balint Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 54 | /// The partition supports receipt of direct requests. |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 55 | pub support_direct_req_rec: bool, |
Balint Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 56 | /// The partition can send direct requests. |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 57 | pub support_direct_req_send: bool, |
Balint Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 58 | /// The partition can send and receive indirect messages. |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 59 | pub support_indirect_msg: bool, |
Balint Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 60 | /// The partition supports receipt of notifications. |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 61 | pub support_notif_rec: bool, |
Balint Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 62 | /// The partition must be informed about each VM that is created by the Hypervisor. |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 63 | pub subscribe_vm_created: bool, |
Balint Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 64 | /// The partition must be informed about each VM that is destroyed by the Hypervisor. |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 65 | pub subscribe_vm_destroyed: bool, |
Balint Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 66 | /// The partition runs in the AArch64 execution state. |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 67 | pub is_aarch64: bool, |
| 68 | } |
| 69 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 70 | impl 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 78 | } |
| 79 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 80 | struct PartPropWrapper(PartitionIdType, PartitionProperties); |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 81 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 82 | impl 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 92 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 93 | let mut props = match value.0 { |
| 94 | PartitionIdType::PeEndpoint { .. } => { |
| 95 | let mut p = PartitionIdType::PE_ENDPOINT << PartitionIdType::SHIFT; |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 96 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 97 | 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 102 | } |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 103 | 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 106 | } |
| 107 | } |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 108 | if value.1.support_direct_req_send { |
| 109 | p |= 1 << PartitionProperties::SUPPORT_DIRECT_REQ_SEND_SHIFT |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 110 | } |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 111 | if value.1.support_indirect_msg { |
| 112 | p |= 1 << PartitionProperties::SUPPORT_INDIRECT_MSG_SHIFT |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 113 | } |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 114 | 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 | |
| 135 | impl 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 163 | } |
| 164 | } |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 165 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 166 | 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 177 | } |
| 178 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 179 | 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 Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 187 | /// Partition information descriptor, returned by the `FFA_PARTITION_INFO_GET` interface. |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 188 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
| 189 | pub struct PartitionInfo { |
| 190 | pub uuid: Uuid, |
| 191 | pub partition_id: u16, |
| 192 | pub partition_id_type: PartitionIdType, |
| 193 | pub props: PartitionProperties, |
| 194 | } |
| 195 | |
| 196 | impl PartitionInfo { |
Balint Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 197 | const DESC_SIZE: usize = size_of::<partition_info_descriptor>(); |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 198 | |
Balint Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 199 | /// 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 Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 201 | 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 Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 225 | /// Iterator of partition information descriptors. |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 226 | pub struct PartitionInfoIterator<'a> { |
| 227 | buf: &'a [u8], |
| 228 | offset: usize, |
| 229 | count: usize, |
| 230 | } |
| 231 | |
| 232 | impl<'a> PartitionInfoIterator<'a> { |
Balint Dobszay | a584685 | 2025-02-26 15:38:53 +0100 | [diff] [blame^] | 233 | /// Create an iterator of partition information descriptors from a buffer. |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 234 | 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 | |
| 251 | impl 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 286 | } |
| 287 | } |
| 288 | |
| 289 | #[cfg(test)] |
| 290 | mod tests { |
| 291 | use super::*; |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 292 | use uuid::uuid; |
| 293 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 294 | // TODO: add tests with a known correct partition info blob |
| 295 | |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 296 | #[test] |
| 297 | fn part_info() { |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 298 | let desc1 = PartitionInfo { |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 299 | uuid: uuid!("12345678-1234-1234-1234-123456789abc"), |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 300 | 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 328 | }; |
| 329 | |
| 330 | let mut buf = [0u8; 0xff]; |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 331 | PartitionInfo::pack(&[desc1, desc2], &mut buf, true); |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 332 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 333 | 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 Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 336 | |
Balint Dobszay | 2338bd3 | 2024-12-19 19:00:14 +0100 | [diff] [blame] | 337 | assert_eq!(desc1, desc1_check); |
| 338 | assert_eq!(desc2, desc2_check); |
Balint Dobszay | 5bf492f | 2024-07-29 17:21:32 +0200 | [diff] [blame] | 339 | } |
| 340 | } |