blob: 8b398248071fd700f293edafd81fc60f5bcd4f10 [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 the FF-A Memory Management protocol.
5//!
6//! FF-A describes mechanisms and interfaces that enable FF-A components to manage access and
7//! ownership of memory regions in the physical address space. FF-A components can use a combination
8//! of Framework and Partition messages to manage memory regions in the following ways:
9//! - The Owner of a memory region can transfer its ownership to another FF-A endpoint.
10//! - The Owner of a memory region can transfer its access to one or more FF-A endpoints.
11//! - The Owner of a memory region can share access to it with one or more FF-A endpoints.
12//! - The Owner can reclaim access to a memory region after the FF-A endpoints that were granted
13//! access to that memory region have relinquished their access.
14
Imre Kisa0122692025-06-05 17:09:28 +020015use crate::{
16 ffa_v1_1::{
17 composite_memory_region_descriptor, constituent_memory_region_descriptor,
18 endpoint_memory_access_descriptor, memory_access_permission_descriptor,
19 memory_relinquish_descriptor, memory_transaction_descriptor,
20 },
21 SuccessArgs,
Balint Dobszayc758dd42025-01-15 18:10:40 +010022};
23use core::mem::size_of;
24use thiserror::Error;
25use zerocopy::{FromBytes, IntoBytes};
26
Balint Dobszaya5846852025-02-26 15:38:53 +010027/// Rich error types returned by this module. Should be converted to [`crate::FfaError`] when used
28/// with the `FFA_ERROR` interface.
Imre Kisdcb7df22025-06-06 15:24:40 +020029#[derive(Debug, Error, PartialEq, Eq)]
Balint Dobszayc758dd42025-01-15 18:10:40 +010030pub enum Error {
31 #[error("Invalid cacheability attribute {0}")]
32 InvalidCacheability(u16),
33 #[error("Invalid shareability attribute {0}")]
34 InvalidShareability(u16),
35 #[error("Invalid device memory attributes {0}")]
36 InvalidDevMemAttributes(u16),
37 #[error("Invalid instruction access permission {0}")]
38 InvalidInstrAccessPerm(u8),
39 #[error("Invalid instruction data permission {0}")]
40 InvalidDataAccessPerm(u8),
41 #[error("Invalid memory type {0}")]
42 InvalidMemType(u16),
43 #[error("Invalid memory attributes {0}")]
44 InvalidMemAttributes(u16),
45 #[error("Composite offset mismatch")]
46 CompositeOffsetMismatch,
47 #[error("Invalid endpoint count {0}")]
48 UnsupportedEndpointCount(u32),
49 #[error("Invalid buffer size")]
50 InvalidBufferSize,
51 #[error("Malformed descriptor")]
52 MalformedDescriptor,
Imre Kisdcb7df22025-06-06 15:24:40 +020053 #[error("Invalid get/set instruction access permission {0}")]
54 InvalidInstrAccessPermGetSet(u32),
55 #[error("Invalid get/set instruction data permission {0}")]
56 InvalidDataAccessPermGetSet(u32),
57 #[error("Invalid page count")]
58 InvalidPageCount,
Balint Dobszayc758dd42025-01-15 18:10:40 +010059}
60
61impl From<Error> for crate::FfaError {
62 fn from(_value: Error) -> Self {
63 Self::InvalidParameters
64 }
65}
Balint Dobszay5bf492f2024-07-29 17:21:32 +020066
Balint Dobszaya5846852025-02-26 15:38:53 +010067/// Memory region handle, used to identify a composite memory region description.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020068#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
69pub struct Handle(pub u64);
70
71impl From<[u32; 2]> for Handle {
72 fn from(value: [u32; 2]) -> Self {
Balint Dobszaye9a3e762025-02-26 17:29:57 +010073 Self(((value[1] as u64) << 32) | value[0] as u64)
Balint Dobszay5bf492f2024-07-29 17:21:32 +020074 }
75}
76
77impl From<Handle> for [u32; 2] {
78 fn from(value: Handle) -> Self {
79 [value.0 as u32, (value.0 >> 32) as u32]
80 }
81}
82
83impl Handle {
84 pub const INVALID: u64 = 0xffff_ffff_ffff_ffff;
85}
86
Balint Dobszaya5846852025-02-26 15:38:53 +010087/// Cacheability attribute of a memory region. Only valid for normal memory.
Imre Kise0bbd092025-06-12 09:39:12 +020088#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020089#[repr(u16)]
90pub enum Cacheability {
91 #[default]
92 NonCacheable = Self::NON_CACHEABLE << Self::SHIFT,
93 WriteBack = Self::WRITE_BACK << Self::SHIFT,
94}
95
96impl TryFrom<u16> for Cacheability {
Balint Dobszayc758dd42025-01-15 18:10:40 +010097 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +020098
99 fn try_from(value: u16) -> Result<Self, Self::Error> {
100 match (value >> Self::SHIFT) & Self::MASK {
101 Self::NON_CACHEABLE => Ok(Cacheability::NonCacheable),
102 Self::WRITE_BACK => Ok(Cacheability::WriteBack),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100103 _ => Err(Error::InvalidCacheability(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200104 }
105 }
106}
107
108impl Cacheability {
109 const SHIFT: usize = 2;
110 const MASK: u16 = 0b11;
111 const NON_CACHEABLE: u16 = 0b01;
112 const WRITE_BACK: u16 = 0b11;
113}
114
Balint Dobszaya5846852025-02-26 15:38:53 +0100115/// Shareability attribute of a memory region. Only valid for normal memory.
Imre Kise0bbd092025-06-12 09:39:12 +0200116#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200117#[repr(u16)]
118pub enum Shareability {
119 #[default]
120 NonShareable = Self::NON_SHAREABLE << Self::SHIFT,
121 Outer = Self::OUTER << Self::SHIFT,
122 Inner = Self::INNER << Self::SHIFT,
123}
124
125impl TryFrom<u16> for Shareability {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100126 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200127
128 fn try_from(value: u16) -> Result<Self, Self::Error> {
129 match (value >> Self::SHIFT) & Self::MASK {
130 Self::NON_SHAREABLE => Ok(Self::NonShareable),
131 Self::OUTER => Ok(Self::Outer),
132 Self::INNER => Ok(Self::Inner),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100133 _ => Err(Error::InvalidShareability(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200134 }
135 }
136}
137
138impl Shareability {
139 const SHIFT: usize = 0;
140 const MASK: u16 = 0b11;
141 const NON_SHAREABLE: u16 = 0b00;
142 const OUTER: u16 = 0b10;
143 const INNER: u16 = 0b11;
144}
145
Balint Dobszaya5846852025-02-26 15:38:53 +0100146/// Device memory attributes.
Imre Kise0bbd092025-06-12 09:39:12 +0200147#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200148#[repr(u16)]
149pub enum DeviceMemAttributes {
150 #[default]
151 DevnGnRnE = Self::DEV_NGNRNE << Self::SHIFT,
152 DevnGnRE = Self::DEV_NGNRE << Self::SHIFT,
153 DevnGRE = Self::DEV_NGRE << Self::SHIFT,
154 DevGRE = Self::DEV_GRE << Self::SHIFT,
155}
156
157impl TryFrom<u16> for DeviceMemAttributes {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100158 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200159
160 fn try_from(value: u16) -> Result<Self, Self::Error> {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200161 match (value >> Self::SHIFT) & Self::MASK {
162 Self::DEV_NGNRNE => Ok(Self::DevnGnRnE),
163 Self::DEV_NGNRE => Ok(Self::DevnGnRE),
164 Self::DEV_NGRE => Ok(Self::DevnGRE),
165 Self::DEV_GRE => Ok(Self::DevGRE),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100166 _ => Err(Error::InvalidDevMemAttributes(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200167 }
168 }
169}
170
171impl DeviceMemAttributes {
172 const SHIFT: usize = 2;
173 const MASK: u16 = 0b11;
174 const DEV_NGNRNE: u16 = 0b00;
175 const DEV_NGNRE: u16 = 0b01;
176 const DEV_NGRE: u16 = 0b10;
177 const DEV_GRE: u16 = 0b11;
178}
179
Balint Dobszaya5846852025-02-26 15:38:53 +0100180/// Memory region type.
Imre Kise0bbd092025-06-12 09:39:12 +0200181#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200182pub enum MemType {
183 #[default]
184 NotSpecified,
185 Device(DeviceMemAttributes),
186 Normal {
187 cacheability: Cacheability,
188 shareability: Shareability,
189 },
190}
191
192impl TryFrom<u16> for MemType {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100193 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200194
195 fn try_from(value: u16) -> Result<Self, Self::Error> {
196 match (value >> Self::SHIFT) & Self::MASK {
197 Self::NOT_SPECIFIED => Ok(Self::NotSpecified),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100198 Self::DEVICE => Ok(Self::Device(value.try_into()?)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200199 Self::NORMAL => Ok(Self::Normal {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100200 cacheability: value.try_into()?,
201 shareability: value.try_into()?,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200202 }),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100203 _ => Err(Error::InvalidMemType(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200204 }
205 }
206}
207
208impl From<MemType> for u16 {
209 fn from(value: MemType) -> Self {
210 match value {
211 MemType::NotSpecified => MemType::NOT_SPECIFIED << MemType::SHIFT,
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100212 MemType::Device(attr) => attr as u16 | (MemType::DEVICE << MemType::SHIFT),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200213 MemType::Normal {
214 cacheability,
215 shareability,
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100216 } => cacheability as u16 | shareability as u16 | (MemType::NORMAL << MemType::SHIFT),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200217 }
218 }
219}
220
221impl MemType {
222 const SHIFT: usize = 4;
223 const MASK: u16 = 0b11;
224 const NOT_SPECIFIED: u16 = 0b00;
225 const DEVICE: u16 = 0b01;
226 const NORMAL: u16 = 0b10;
227}
228
Balint Dobszaya5846852025-02-26 15:38:53 +0100229/// Memory region security attribute.
Imre Kise0bbd092025-06-12 09:39:12 +0200230#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200231#[repr(u16)]
232pub enum MemRegionSecurity {
233 #[default]
234 Secure = Self::SECURE << Self::SHIFT,
235 NonSecure = Self::NON_SECURE << Self::SHIFT,
236}
237
Balint Dobszayc758dd42025-01-15 18:10:40 +0100238impl From<u16> for MemRegionSecurity {
239 fn from(value: u16) -> Self {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200240 match (value >> Self::SHIFT) & Self::MASK {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100241 Self::SECURE => Self::Secure,
242 Self::NON_SECURE => Self::NonSecure,
243 _ => panic!(), // The match is exhaustive for a 1-bit value
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200244 }
245 }
246}
247
248impl MemRegionSecurity {
249 const SHIFT: usize = 6;
250 const MASK: u16 = 0b1;
251 const SECURE: u16 = 0b0;
252 const NON_SECURE: u16 = 0b1;
253}
254
Balint Dobszaya5846852025-02-26 15:38:53 +0100255/// Memory region attributes descriptor.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200256#[derive(Debug, Default, Clone, Copy)]
257pub struct MemRegionAttributes {
258 pub security: MemRegionSecurity,
259 pub mem_type: MemType,
260}
261
262impl TryFrom<u16> for MemRegionAttributes {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100263 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200264
265 fn try_from(value: u16) -> Result<Self, Self::Error> {
266 // bits[15:7]: Reserved (MBZ)
Balint Dobszayc758dd42025-01-15 18:10:40 +0100267 if value >> 7 == 0 {
268 Ok(Self {
269 security: value.into(),
270 mem_type: value.try_into()?,
271 })
272 } else {
273 Err(Error::InvalidMemAttributes(value))
274 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200275 }
276}
277
278impl From<MemRegionAttributes> for u16 {
279 fn from(value: MemRegionAttributes) -> Self {
280 value.security as u16 | u16::from(value.mem_type)
281 }
282}
283
Balint Dobszaya5846852025-02-26 15:38:53 +0100284/// Instruction access permissions of a memory region.
Imre Kise0bbd092025-06-12 09:39:12 +0200285#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200286#[repr(u8)]
287pub enum InstuctionAccessPerm {
288 #[default]
289 NotSpecified = Self::NOT_SPECIFIED << Self::SHIFT,
290 NotExecutable = Self::NOT_EXECUTABLE << Self::SHIFT,
291 Executable = Self::EXECUTABLE << Self::SHIFT,
292}
293
294impl TryFrom<u8> for InstuctionAccessPerm {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100295 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200296
297 fn try_from(value: u8) -> Result<Self, Self::Error> {
298 match (value >> Self::SHIFT) & Self::MASK {
299 Self::NOT_SPECIFIED => Ok(Self::NotSpecified),
300 Self::NOT_EXECUTABLE => Ok(Self::NotExecutable),
301 Self::EXECUTABLE => Ok(Self::Executable),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100302 _ => Err(Error::InvalidInstrAccessPerm(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200303 }
304 }
305}
306
307impl InstuctionAccessPerm {
308 const SHIFT: usize = 2;
309 const MASK: u8 = 0b11;
310 const NOT_SPECIFIED: u8 = 0b00;
311 const NOT_EXECUTABLE: u8 = 0b01;
312 const EXECUTABLE: u8 = 0b10;
313}
314
Balint Dobszaya5846852025-02-26 15:38:53 +0100315/// Data access permissions of a memory region.
Imre Kise0bbd092025-06-12 09:39:12 +0200316#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200317#[repr(u8)]
318pub enum DataAccessPerm {
319 #[default]
320 NotSpecified = Self::NOT_SPECIFIED << Self::SHIFT,
321 ReadOnly = Self::READ_ONLY << Self::SHIFT,
322 ReadWrite = Self::READ_WRITE << Self::SHIFT,
323}
324
325impl TryFrom<u8> for DataAccessPerm {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100326 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200327
328 fn try_from(value: u8) -> Result<Self, Self::Error> {
329 match (value >> Self::SHIFT) & Self::MASK {
330 Self::NOT_SPECIFIED => Ok(Self::NotSpecified),
331 Self::READ_ONLY => Ok(Self::ReadOnly),
332 Self::READ_WRITE => Ok(Self::ReadWrite),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100333 _ => Err(Error::InvalidDataAccessPerm(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200334 }
335 }
336}
337
338impl DataAccessPerm {
339 const SHIFT: usize = 0;
340 const MASK: u8 = 0b11;
341 const NOT_SPECIFIED: u8 = 0b00;
342 const READ_ONLY: u8 = 0b01;
343 const READ_WRITE: u8 = 0b10;
344}
345
Balint Dobszaya5846852025-02-26 15:38:53 +0100346/// Endpoint memory access permissions descriptor.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200347#[derive(Debug, Default, Clone, Copy)]
Balint Dobszayc758dd42025-01-15 18:10:40 +0100348pub struct MemAccessPerm {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200349 pub endpoint_id: u16,
350 pub instr_access: InstuctionAccessPerm,
351 pub data_access: DataAccessPerm,
352 pub flags: u8, // TODO
353}
354
Balint Dobszaya5846852025-02-26 15:38:53 +0100355/// Iterator of endpoint memory access permission descriptors.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100356pub struct MemAccessPermIterator<'a> {
357 buf: &'a [u8],
358 offset: usize,
359 count: usize,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200360}
361
Balint Dobszayc758dd42025-01-15 18:10:40 +0100362impl<'a> MemAccessPermIterator<'a> {
Balint Dobszaya5846852025-02-26 15:38:53 +0100363 /// Create an iterator of endpoint memory access permission descriptors from a buffer.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100364 fn new(buf: &'a [u8], count: usize, offset: usize) -> Result<Self, Error> {
365 let Some(total_size) = count
366 .checked_mul(size_of::<endpoint_memory_access_descriptor>())
367 .and_then(|x| x.checked_add(offset))
368 else {
369 return Err(Error::InvalidBufferSize);
370 };
371
372 if buf.len() < total_size {
373 return Err(Error::InvalidBufferSize);
374 }
375
376 Ok(Self { buf, offset, count })
377 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200378}
379
Balint Dobszayc758dd42025-01-15 18:10:40 +0100380impl Iterator for MemAccessPermIterator<'_> {
381 type Item = Result<MemAccessPerm, Error>;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200382
Balint Dobszayc758dd42025-01-15 18:10:40 +0100383 fn next(&mut self) -> Option<Self::Item> {
384 if self.count > 0 {
385 let offset = self.offset;
386 self.offset += size_of::<endpoint_memory_access_descriptor>();
387 self.count -= 1;
388
389 let Ok(desc_raw) = endpoint_memory_access_descriptor::ref_from_bytes(
390 &self.buf[offset..offset + size_of::<endpoint_memory_access_descriptor>()],
391 ) else {
392 return Some(Err(Error::MalformedDescriptor));
393 };
394
395 let instr_access = match desc_raw
396 .access_perm_desc
397 .memory_access_permissions
398 .try_into()
399 {
400 Ok(v) => v,
401 Err(e) => return Some(Err(e)),
402 };
403
404 let data_access = match desc_raw
405 .access_perm_desc
406 .memory_access_permissions
407 .try_into()
408 {
409 Ok(v) => v,
410 Err(e) => return Some(Err(e)),
411 };
412
413 let desc = MemAccessPerm {
414 endpoint_id: desc_raw.access_perm_desc.endpoint_id,
415 instr_access,
416 data_access,
417 flags: desc_raw.access_perm_desc.flags,
418 };
419
420 return Some(Ok(desc));
421 }
422
423 None
424 }
425}
426
Balint Dobszaya5846852025-02-26 15:38:53 +0100427/// Constituent memory region descriptor.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100428#[derive(Debug, Default, Clone, Copy)]
429pub struct ConstituentMemRegion {
430 pub address: u64,
431 pub page_cnt: u32,
432}
433
Balint Dobszaya5846852025-02-26 15:38:53 +0100434/// Iterator of constituent memory region descriptors.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100435pub struct ConstituentMemRegionIterator<'a> {
436 buf: &'a [u8],
437 offset: usize,
438 count: usize,
439}
440
441impl<'a> ConstituentMemRegionIterator<'a> {
Balint Dobszaya5846852025-02-26 15:38:53 +0100442 /// Create an iterator of constituent memory region descriptors from a buffer.
Imre Kis1a4abbe2025-04-11 17:08:51 +0200443 fn new(
444 buf: &'a [u8],
445 region_count: usize,
446 total_page_count: u32,
447 offset: usize,
448 ) -> Result<Self, Error> {
449 let descriptor_size = size_of::<constituent_memory_region_descriptor>();
450
451 let Some(total_size) = region_count
452 .checked_mul(descriptor_size)
Balint Dobszayc758dd42025-01-15 18:10:40 +0100453 .and_then(|x| x.checked_add(offset))
454 else {
455 return Err(Error::InvalidBufferSize);
456 };
457
458 if buf.len() < total_size {
459 return Err(Error::InvalidBufferSize);
460 }
461
Imre Kis1a4abbe2025-04-11 17:08:51 +0200462 // Check if the sum of of page counts in the constituent_memory_region_descriptors matches
463 // the total_page_count field of the composite_memory_region_descriptor.
464 let mut page_count_sum: u32 = 0;
465 for desc_offset in
466 (offset..offset + descriptor_size * region_count).step_by(descriptor_size)
467 {
468 let Ok(desc_raw) = constituent_memory_region_descriptor::ref_from_bytes(
469 &buf[desc_offset..desc_offset + descriptor_size],
470 ) else {
471 return Err(Error::MalformedDescriptor);
472 };
473
474 page_count_sum = page_count_sum
475 .checked_add(desc_raw.page_count)
476 .ok_or(Error::MalformedDescriptor)?;
477 }
478
479 if page_count_sum != total_page_count {
480 return Err(Error::MalformedDescriptor);
481 }
482
483 Ok(Self {
484 buf,
485 offset,
486 count: region_count,
487 })
Balint Dobszayc758dd42025-01-15 18:10:40 +0100488 }
489}
490
491impl Iterator for ConstituentMemRegionIterator<'_> {
492 type Item = Result<ConstituentMemRegion, Error>;
493
494 fn next(&mut self) -> Option<Self::Item> {
495 if self.count > 0 {
496 let offset = self.offset;
497 self.offset += size_of::<constituent_memory_region_descriptor>();
498 self.count -= 1;
499
500 let Ok(desc_raw) = constituent_memory_region_descriptor::ref_from_bytes(
501 &self.buf[offset..offset + size_of::<constituent_memory_region_descriptor>()],
502 ) else {
503 return Some(Err(Error::MalformedDescriptor));
504 };
505
506 let desc = ConstituentMemRegion {
507 address: desc_raw.address,
508 page_cnt: desc_raw.page_count,
509 };
510
511 return Some(Ok(desc));
512 }
513
514 None
515 }
516}
517
Balint Dobszaya5846852025-02-26 15:38:53 +0100518/// Flags of a memory management transaction.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100519#[derive(Debug, Default, Clone, Copy)]
520pub struct MemTransactionFlags(pub u32);
521
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200522impl MemTransactionFlags {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100523 pub const MEM_SHARE_MASK: u32 = 0b11;
524 pub const MEM_RETRIEVE_REQ_MASK: u32 = 0b11_1111_1111;
525 pub const MEM_RETRIEVE_RESP_MASK: u32 = 0b1_1111;
526 pub const ZERO_MEMORY: u32 = 0b1;
527 pub const TIME_SLICING: u32 = 0b1 << 1;
528 pub const ZERO_AFTER_RELINQ: u32 = 0b1 << 2;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200529 pub const TYPE_SHARE: u32 = 0b01 << 3;
Balint Dobszayc758dd42025-01-15 18:10:40 +0100530 pub const TYPE_LEND: u32 = 0b10 << 3;
531 pub const TYPE_DONATE: u32 = 0b11 << 3;
532 pub const ALIGN_HINT_MASK: u32 = 0b1111 << 5;
533 pub const HINT_VALID: u32 = 0b1 << 9;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200534}
535
Balint Dobszaya5846852025-02-26 15:38:53 +0100536/// Memory transaction decriptor. Used by an Owner/Lender and a Borrower/Receiver in a transaction
537/// to donate, lend or share a memory region.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200538#[derive(Debug, Default)]
539pub struct MemTransactionDesc {
540 pub sender_id: u16,
541 pub mem_region_attr: MemRegionAttributes,
542 pub flags: MemTransactionFlags,
543 pub handle: Handle,
544 pub tag: u64, // TODO
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200545}
546
547impl MemTransactionDesc {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100548 // Offset from the base of the memory transaction descriptor to the first element in the
549 // endpoint memory access descriptor array. Must be 16 byte aligned, but otherwise we're free to
550 // choose any value here. Let's just pack it right after the memory transaction descriptor.
551 const ENDPOINT_MEM_ACCESS_DESC_OFFSET: usize =
552 size_of::<memory_transaction_descriptor>().next_multiple_of(16);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200553
Balint Dobszayc758dd42025-01-15 18:10:40 +0100554 // The array of constituent memory region descriptors starts right after the composite memory
555 // region descriptor
556 const CONSTITUENT_ARRAY_OFFSET: usize = size_of::<composite_memory_region_descriptor>();
557
Balint Dobszaya5846852025-02-26 15:38:53 +0100558 /// Serialize a memory transaction descriptor and the related constituent memory region
559 /// descriptors and endpoint memory access permission descriptors into a buffer.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100560 pub fn pack(
561 &self,
562 constituents: &[ConstituentMemRegion],
563 access_descriptors: &[MemAccessPerm],
564 buf: &mut [u8],
565 ) -> usize {
566 let mem_access_desc_size = size_of::<endpoint_memory_access_descriptor>();
567 let mem_access_desc_cnt = access_descriptors.len();
568
569 let transaction_desc_raw = memory_transaction_descriptor {
570 sender_endpoint_id: self.sender_id,
571 memory_region_attributes: self.mem_region_attr.into(),
572 flags: self.flags.0,
573 handle: self.handle.0,
574 tag: self.tag,
575 endpoint_mem_access_desc_size: mem_access_desc_size as u32,
576 endpoint_mem_access_desc_count: mem_access_desc_cnt as u32,
577 endpoint_mem_access_desc_array_offset: Self::ENDPOINT_MEM_ACCESS_DESC_OFFSET as u32,
578 reserved1: 0,
579 reserved2: 0,
580 };
581
582 transaction_desc_raw.write_to_prefix(buf).unwrap();
583
584 // Offset from the base of the memory transaction descriptor to the composite memory region
585 // descriptor to which the endpoint access permissions apply.
586 let composite_offset = mem_access_desc_cnt
587 .checked_mul(mem_access_desc_size)
588 .unwrap()
589 .checked_add(Self::ENDPOINT_MEM_ACCESS_DESC_OFFSET)
590 .unwrap()
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200591 .next_multiple_of(8);
592
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200593 let mut offset = Self::ENDPOINT_MEM_ACCESS_DESC_OFFSET;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200594
Balint Dobszayc758dd42025-01-15 18:10:40 +0100595 for desc in access_descriptors {
596 let desc_raw = endpoint_memory_access_descriptor {
597 access_perm_desc: memory_access_permission_descriptor {
598 endpoint_id: desc.endpoint_id,
599 memory_access_permissions: desc.data_access as u8 | desc.instr_access as u8,
600 flags: desc.flags,
601 },
602 composite_offset: composite_offset as u32,
603 reserved: 0,
604 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200605
Balint Dobszayc758dd42025-01-15 18:10:40 +0100606 desc_raw.write_to_prefix(&mut buf[offset..]).unwrap();
607 offset += mem_access_desc_size;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200608 }
609
Imre Kis1a4abbe2025-04-11 17:08:51 +0200610 let mut total_page_count: u32 = 0;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200611
Balint Dobszayc758dd42025-01-15 18:10:40 +0100612 offset = composite_offset + Self::CONSTITUENT_ARRAY_OFFSET;
613 for constituent in constituents {
614 let constituent_raw = constituent_memory_region_descriptor {
615 address: constituent.address,
616 page_count: constituent.page_cnt,
617 reserved: 0,
618 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200619
Balint Dobszayc758dd42025-01-15 18:10:40 +0100620 constituent_raw.write_to_prefix(&mut buf[offset..]).unwrap();
621 offset += size_of::<constituent_memory_region_descriptor>();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200622
Imre Kis1a4abbe2025-04-11 17:08:51 +0200623 total_page_count = total_page_count
624 .checked_add(constituent_raw.page_count)
625 .expect("total_page_count overflow");
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200626 }
627
Balint Dobszayc758dd42025-01-15 18:10:40 +0100628 let composite_desc_raw = composite_memory_region_descriptor {
629 total_page_count,
630 address_range_count: constituents.len() as u32,
631 reserved: 0,
632 };
633
634 composite_desc_raw
635 .write_to_prefix(&mut buf[composite_offset..])
636 .unwrap();
637
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200638 offset
639 }
640
Balint Dobszaya5846852025-02-26 15:38:53 +0100641 /// Deserialize a memory transaction descriptor from a buffer and return an interator of the
642 /// related endpoint memory access permission descriptors and constituent memory region
643 /// descriptors, if any.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100644 pub fn unpack(
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200645 buf: &[u8],
Balint Dobszayc758dd42025-01-15 18:10:40 +0100646 ) -> Result<
647 (
648 MemTransactionDesc,
649 MemAccessPermIterator,
650 Option<ConstituentMemRegionIterator>,
651 ),
652 Error,
653 > {
654 let Some(transaction_desc_bytes) = buf.get(0..size_of::<memory_transaction_descriptor>())
655 else {
656 return Err(Error::InvalidBufferSize);
657 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200658
Balint Dobszayc758dd42025-01-15 18:10:40 +0100659 let Ok(transaction_desc_raw) =
660 memory_transaction_descriptor::ref_from_bytes(transaction_desc_bytes)
661 else {
662 return Err(Error::MalformedDescriptor);
663 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200664
Balint Dobszayc758dd42025-01-15 18:10:40 +0100665 if size_of::<endpoint_memory_access_descriptor>()
666 != transaction_desc_raw.endpoint_mem_access_desc_size as usize
667 {
668 return Err(Error::MalformedDescriptor);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200669 }
670
Balint Dobszayc758dd42025-01-15 18:10:40 +0100671 if transaction_desc_raw.endpoint_mem_access_desc_count == 0 {
672 return Err(Error::MalformedDescriptor);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200673 }
674
Balint Dobszayc758dd42025-01-15 18:10:40 +0100675 let Some(total_desc_size) = transaction_desc_raw
676 .endpoint_mem_access_desc_size
677 .checked_mul(transaction_desc_raw.endpoint_mem_access_desc_count)
678 .and_then(|x| {
679 x.checked_add(transaction_desc_raw.endpoint_mem_access_desc_array_offset)
680 })
681 else {
682 return Err(Error::InvalidBufferSize);
683 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200684
Balint Dobszayc758dd42025-01-15 18:10:40 +0100685 if buf.len() < total_desc_size as usize {
686 return Err(Error::InvalidBufferSize);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200687 }
688
Balint Dobszayc758dd42025-01-15 18:10:40 +0100689 let transaction_desc = MemTransactionDesc {
690 sender_id: transaction_desc_raw.sender_endpoint_id,
691 mem_region_attr: transaction_desc_raw.memory_region_attributes.try_into()?,
692 flags: MemTransactionFlags(transaction_desc_raw.flags),
693 handle: Handle(transaction_desc_raw.handle),
694 tag: transaction_desc_raw.tag,
695 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200696
Balint Dobszayc758dd42025-01-15 18:10:40 +0100697 let mut offset = transaction_desc_raw.endpoint_mem_access_desc_array_offset as usize;
698
699 let access_desc_iter = MemAccessPermIterator::new(
700 buf,
701 transaction_desc_raw.endpoint_mem_access_desc_count as usize,
702 offset,
703 )?;
704
705 // We have to check the first endpoint memory access descriptor to get the composite offset
706 let Ok(desc_raw) = endpoint_memory_access_descriptor::ref_from_bytes(
707 &buf[offset..offset + size_of::<endpoint_memory_access_descriptor>()],
708 ) else {
709 return Err(Error::MalformedDescriptor);
710 };
711
712 offset = desc_raw.composite_offset as usize;
713
714 // An offset value of 0 indicates that the endpoint access permissions apply to a memory
715 // region description identified by the Handle (i.e. there is no composite descriptor)
716 if offset == 0 {
717 return Ok((transaction_desc, access_desc_iter, None));
718 }
719
720 let Some(composite_desc_bytes) =
721 buf.get(offset..offset + size_of::<composite_memory_region_descriptor>())
722 else {
723 return Err(Error::InvalidBufferSize);
724 };
725
726 let Ok(composite_desc_raw) =
727 composite_memory_region_descriptor::ref_from_bytes(composite_desc_bytes)
728 else {
729 return Err(Error::MalformedDescriptor);
730 };
731
732 let constituent_iter = ConstituentMemRegionIterator::new(
733 buf,
734 composite_desc_raw.address_range_count as usize,
Imre Kis1a4abbe2025-04-11 17:08:51 +0200735 composite_desc_raw.total_page_count,
Balint Dobszayc758dd42025-01-15 18:10:40 +0100736 offset + Self::CONSTITUENT_ARRAY_OFFSET,
737 )?;
738
Balint Dobszayc758dd42025-01-15 18:10:40 +0100739 Ok((transaction_desc, access_desc_iter, Some(constituent_iter)))
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200740 }
741}
742
Imre Kis042c2942025-06-12 09:49:20 +0200743/// Iterator of endpoint IDs.
744pub struct EndpointIterator<'a> {
745 buf: &'a [u8],
746 offset: usize,
747 count: usize,
748}
749
750impl<'a> EndpointIterator<'a> {
751 /// Create an iterator of endpoint IDs from a buffer.
752 fn new(buf: &'a [u8], count: usize, offset: usize) -> Result<Self, Error> {
753 let Some(total_size) = count.checked_mul(size_of::<u16>()) else {
754 return Err(Error::InvalidBufferSize);
755 };
756
757 if buf.len() < total_size {
758 return Err(Error::InvalidBufferSize);
759 }
760
761 Ok(Self { buf, offset, count })
762 }
763}
764
765impl Iterator for EndpointIterator<'_> {
766 type Item = u16;
767
768 fn next(&mut self) -> Option<Self::Item> {
769 if self.count > 0 {
770 let offset = self.offset;
771 self.offset += size_of::<Self::Item>();
772 self.count -= 1;
773
774 let endpoint = u16::from_le_bytes([self.buf[offset], self.buf[offset + 1]]);
775 return Some(endpoint);
776 }
777
778 None
779 }
780}
781
Balint Dobszaya5846852025-02-26 15:38:53 +0100782/// Descriptor to relinquish a memory region. Currently only supports specifying a single endpoint.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200783#[derive(Debug, Default)]
784pub struct MemRelinquishDesc {
785 pub handle: Handle,
786 pub flags: u32,
Balint Dobszayc758dd42025-01-15 18:10:40 +0100787}
788
Imre Kis042c2942025-06-12 09:49:20 +0200789impl MemRelinquishDesc {
790 const ENDPOINT_ARRAY_OFFSET: usize = size_of::<memory_relinquish_descriptor>();
Balint Dobszayc758dd42025-01-15 18:10:40 +0100791
Imre Kis042c2942025-06-12 09:49:20 +0200792 /// Serialize memory relinquish descriptor and the endpoint IDs into a buffer.
793 pub fn pack(&self, endpoints: &[u16], buf: &mut [u8]) -> usize {
794 if let Ok(desc_raw) = memory_relinquish_descriptor::mut_from_bytes(buf) {
795 desc_raw.handle = self.handle.0;
796 desc_raw.flags = self.flags;
797 desc_raw.endpoint_count = endpoints.len().try_into().unwrap();
798
799 let endpoint_area = &mut buf[Self::ENDPOINT_ARRAY_OFFSET..];
800
801 for (endpoint, dest) in endpoints
802 .iter()
803 .zip(endpoint_area[..endpoints.len() * 2].chunks_exact_mut(2))
804 {
805 [dest[0], dest[1]] = u16::to_le_bytes(*endpoint);
806 }
807 }
808
809 Self::ENDPOINT_ARRAY_OFFSET + endpoints.len() * 2
810 }
811
812 /// Deserialize a memory relinquish descriptor from a buffer and return an iterator to the
813 /// endpoint IDs.
814 pub fn unpack(buf: &[u8]) -> Result<(MemRelinquishDesc, EndpointIterator), Error> {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100815 let Some(desc_bytes) = buf.get(0..size_of::<memory_relinquish_descriptor>()) else {
816 return Err(Error::InvalidBufferSize);
817 };
818
819 let Ok(desc_raw) = memory_relinquish_descriptor::ref_from_bytes(desc_bytes) else {
820 return Err(Error::MalformedDescriptor);
821 };
822
823 let Some(total_desc_size) = (desc_raw.endpoint_count as usize)
824 .checked_mul(size_of::<u16>())
825 .and_then(|x| x.checked_add(Self::ENDPOINT_ARRAY_OFFSET))
826 else {
827 return Err(Error::InvalidBufferSize);
828 };
829
830 if buf.len() < total_desc_size {
831 return Err(Error::InvalidBufferSize);
832 }
833
Imre Kis042c2942025-06-12 09:49:20 +0200834 let iterator = EndpointIterator::new(
835 buf,
836 desc_raw.endpoint_count as usize,
837 Self::ENDPOINT_ARRAY_OFFSET,
838 )?;
Balint Dobszayc758dd42025-01-15 18:10:40 +0100839
Imre Kis042c2942025-06-12 09:49:20 +0200840 Ok((
841 Self {
842 handle: Handle(desc_raw.handle),
843 flags: desc_raw.flags, // TODO: validate
844 },
845 iterator,
846 ))
Balint Dobszayc758dd42025-01-15 18:10:40 +0100847 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200848}
849
Imre Kis356395d2025-06-13 13:49:06 +0200850/// Flags field of the FFA_MEM_RECLAIM interface.
Imre Kisa9e544c2025-06-13 15:57:54 +0200851#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
Imre Kis356395d2025-06-13 13:49:06 +0200852pub struct MemReclaimFlags {
853 pub zero_memory: bool,
854 pub time_slicing: bool,
855}
856
857impl MemReclaimFlags {
858 pub const ZERO_MEMORY: u32 = 0b1 << 0;
859 pub const TIME_SLICING: u32 = 0b1 << 1;
860 const MBZ_BITS: u32 = 0xffff_fffc;
861}
862
863impl TryFrom<u32> for MemReclaimFlags {
864 type Error = crate::Error;
865
866 fn try_from(val: u32) -> Result<Self, Self::Error> {
867 if (val & Self::MBZ_BITS) != 0 {
868 Err(crate::Error::InvalidMemReclaimFlags(val))
869 } else {
870 Ok(MemReclaimFlags {
871 zero_memory: val & Self::ZERO_MEMORY != 0,
872 time_slicing: val & Self::TIME_SLICING != 0,
873 })
874 }
875 }
876}
877
878impl From<MemReclaimFlags> for u32 {
879 fn from(flags: MemReclaimFlags) -> Self {
880 let mut bits: u32 = 0;
881 if flags.zero_memory {
882 bits |= MemReclaimFlags::ZERO_MEMORY;
883 }
884 if flags.time_slicing {
885 bits |= MemReclaimFlags::TIME_SLICING;
886 }
887 bits
888 }
889}
890
Imre Kisa0122692025-06-05 17:09:28 +0200891/// Success argument structure for `FFA_MEM_DONATE`, `FFA_MEM_LEND` and `FFA_MEM_SHARE`.
Imre Kisa9e544c2025-06-13 15:57:54 +0200892#[derive(Debug, Eq, PartialEq, Clone, Copy)]
Imre Kisa0122692025-06-05 17:09:28 +0200893pub struct SuccessArgsMemOp {
894 pub handle: Handle,
895}
896
897impl From<SuccessArgsMemOp> for SuccessArgs {
898 fn from(value: SuccessArgsMemOp) -> Self {
899 let [handle_lo, handle_hi]: [u32; 2] = value.handle.into();
900 SuccessArgs::Args32([handle_lo, handle_hi, 0, 0, 0, 0])
901 }
902}
903
904impl TryFrom<SuccessArgs> for SuccessArgsMemOp {
905 type Error = crate::Error;
906
907 fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
908 let [handle_lo, handle_hi, ..] = value.try_get_args32()?;
909 Ok(Self {
910 handle: [handle_lo, handle_hi].into(),
911 })
912 }
913}
914
Imre Kisdcb7df22025-06-06 15:24:40 +0200915/// Data access permission enum for `FFA_MEM_PERM_GET` and `FFA_MEM_PERM_SET` calls.
916#[derive(Debug, Clone, Copy, PartialEq, Eq)]
917#[repr(u32)]
918pub enum DataAccessPermGetSet {
919 NoAccess = Self::NO_ACCESS << Self::SHIFT,
920 ReadWrite = Self::READ_WRITE << Self::SHIFT,
921 ReadOnly = Self::READ_ONLY << Self::SHIFT,
922}
923
924impl DataAccessPermGetSet {
925 const SHIFT: usize = 0;
926 const MASK: u32 = 0b11;
927 const NO_ACCESS: u32 = 0b00;
928 const READ_WRITE: u32 = 0b01;
929 const READ_ONLY: u32 = 0b11;
930}
931
932impl TryFrom<u32> for DataAccessPermGetSet {
933 type Error = Error;
934
935 fn try_from(value: u32) -> Result<Self, Self::Error> {
936 match (value >> Self::SHIFT) & Self::MASK {
937 Self::NO_ACCESS => Ok(Self::NoAccess),
938 Self::READ_WRITE => Ok(Self::ReadWrite),
939 Self::READ_ONLY => Ok(Self::ReadOnly),
940 _ => Err(Error::InvalidDataAccessPermGetSet(value)),
941 }
942 }
943}
944
945/// Instructions access permission enum for `FFA_MEM_PERM_GET` and `FFA_MEM_PERM_SET` calls.
946#[derive(Debug, Clone, Copy, PartialEq, Eq)]
947#[repr(u32)]
948pub enum InstructionAccessPermGetSet {
949 Executable = Self::EXECUTABLE << Self::SHIFT,
950 NonExecutable = Self::NON_EXECUTABLE << Self::SHIFT,
951}
952
953impl InstructionAccessPermGetSet {
954 const SHIFT: usize = 2;
955 const MASK: u32 = 0b1;
956 const EXECUTABLE: u32 = 0b0;
957 const NON_EXECUTABLE: u32 = 0b1;
958}
959
960impl TryFrom<u32> for InstructionAccessPermGetSet {
961 type Error = Error;
962
963 fn try_from(value: u32) -> Result<Self, Self::Error> {
964 match (value >> Self::SHIFT) & Self::MASK {
965 Self::EXECUTABLE => Ok(Self::Executable),
966 Self::NON_EXECUTABLE => Ok(Self::NonExecutable),
967 _ => Err(Error::InvalidInstrAccessPermGetSet(value)),
968 }
969 }
970}
971
972/// Memory permission structure for `FFA_MEM_PERM_GET` and `FFA_MEM_PERM_SET` calls.
973#[derive(Debug, Clone, Copy, PartialEq, Eq)]
974pub struct MemPermissionsGetSet {
975 pub data_access: DataAccessPermGetSet,
976 pub instr_access: InstructionAccessPermGetSet,
977}
978
979impl TryFrom<u32> for MemPermissionsGetSet {
980 type Error = Error;
981
982 fn try_from(value: u32) -> Result<Self, Self::Error> {
983 Ok(Self {
984 data_access: value.try_into()?,
985 instr_access: value.try_into()?,
986 })
987 }
988}
989
990impl From<MemPermissionsGetSet> for u32 {
991 fn from(value: MemPermissionsGetSet) -> Self {
992 value.data_access as u32 | value.instr_access as u32
993 }
994}
995
996/// Success argument structure for `FFA_MEM_PERM_GET`.
Imre Kisa9e544c2025-06-13 15:57:54 +0200997#[derive(Debug, Eq, PartialEq, Clone, Copy)]
Imre Kisdcb7df22025-06-06 15:24:40 +0200998pub struct SuccessArgsMemPermGet {
999 pub perm: MemPermissionsGetSet,
1000 pub page_cnt: u32,
1001}
1002
1003impl From<SuccessArgsMemPermGet> for SuccessArgs {
1004 fn from(value: SuccessArgsMemPermGet) -> Self {
1005 assert_ne!(value.page_cnt, 0);
1006 SuccessArgs::Args32([value.perm.into(), value.page_cnt - 1, 0, 0, 0, 0])
1007 }
1008}
1009
1010impl TryFrom<SuccessArgs> for SuccessArgsMemPermGet {
1011 type Error = crate::Error;
1012
1013 fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
1014 let [perm, page_cnt, ..] = value.try_get_args32()?;
1015 Ok(Self {
1016 perm: perm.try_into()?,
1017 page_cnt: page_cnt.checked_add(1).ok_or(Error::InvalidPageCount)?,
1018 })
1019 }
1020}
1021
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001022#[cfg(test)]
1023mod tests {
1024 use super::*;
1025
1026 #[allow(dead_code)]
1027 const MEM_SHARE_FROM_SP1: &[u8] = &[
1028 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1029 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1030 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1031 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1032 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1033 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
1034 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1035 ];
1036
1037 #[allow(dead_code)]
1038 const MEM_SHARE_FROM_SP2: &[u8] = &[
1039 0x06, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1040 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1041 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1042 0x00, 0x00, 0x00, 0x05, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1043 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1044 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x07, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
1045 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1046 ];
1047
1048 #[allow(dead_code)]
1049 const MEM_RETRIEVE_REQ_FROM_SP1: &[u8] = &[
1050 0x05, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
1051 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1052 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1053 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1054 0x00, 0x00, 0x00, 0x00,
1055 ];
1056
1057 #[allow(dead_code)]
1058 const MEM_RETRIEVE_REQ_FROM_SP2: &[u8] = &[
1059 0x06, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
1060 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1061 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1062 0x00, 0x00, 0x00, 0x05, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1063 0x00, 0x00, 0x00, 0x00,
1064 ];
1065
1066 #[allow(dead_code)]
1067 const MEM_SHARE_FROM_NWD: &[u8] = &[
1068 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1069 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1070 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1071 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1072 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1073 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x22, 0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00,
1074 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1075 ];
1076
1077 #[test]
1078 fn mem_share() {
Balint Dobszayc758dd42025-01-15 18:10:40 +01001079 let (transaction_desc, access_desc, constituents) =
1080 MemTransactionDesc::unpack(MEM_SHARE_FROM_SP1).unwrap();
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001081
1082 println!("transaction desc: {:#x?}", transaction_desc);
Balint Dobszayc758dd42025-01-15 18:10:40 +01001083 access_desc.for_each(|d| println!("endpont desc: {d:#x?}"));
1084 constituents
1085 .unwrap()
1086 .for_each(|c| println!("constituent desc: {c:#x?}"));
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001087 }
1088}