blob: 1302f8224926cd949b8d8ee58ae4305d3825557f [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.
Balint Dobszayc758dd42025-01-15 18:10:40 +010029#[derive(Debug, Error)]
30pub 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,
53}
54
55impl From<Error> for crate::FfaError {
56 fn from(_value: Error) -> Self {
57 Self::InvalidParameters
58 }
59}
Balint Dobszay5bf492f2024-07-29 17:21:32 +020060
Balint Dobszaya5846852025-02-26 15:38:53 +010061/// Memory region handle, used to identify a composite memory region description.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020062#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
63pub struct Handle(pub u64);
64
65impl From<[u32; 2]> for Handle {
66 fn from(value: [u32; 2]) -> Self {
Balint Dobszaye9a3e762025-02-26 17:29:57 +010067 Self(((value[1] as u64) << 32) | value[0] as u64)
Balint Dobszay5bf492f2024-07-29 17:21:32 +020068 }
69}
70
71impl From<Handle> for [u32; 2] {
72 fn from(value: Handle) -> Self {
73 [value.0 as u32, (value.0 >> 32) as u32]
74 }
75}
76
77impl Handle {
78 pub const INVALID: u64 = 0xffff_ffff_ffff_ffff;
79}
80
Balint Dobszaya5846852025-02-26 15:38:53 +010081/// Cacheability attribute of a memory region. Only valid for normal memory.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020082#[derive(Debug, Default, Clone, Copy, PartialEq)]
83#[repr(u16)]
84pub enum Cacheability {
85 #[default]
86 NonCacheable = Self::NON_CACHEABLE << Self::SHIFT,
87 WriteBack = Self::WRITE_BACK << Self::SHIFT,
88}
89
90impl TryFrom<u16> for Cacheability {
Balint Dobszayc758dd42025-01-15 18:10:40 +010091 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +020092
93 fn try_from(value: u16) -> Result<Self, Self::Error> {
94 match (value >> Self::SHIFT) & Self::MASK {
95 Self::NON_CACHEABLE => Ok(Cacheability::NonCacheable),
96 Self::WRITE_BACK => Ok(Cacheability::WriteBack),
Balint Dobszayc758dd42025-01-15 18:10:40 +010097 _ => Err(Error::InvalidCacheability(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +020098 }
99 }
100}
101
102impl Cacheability {
103 const SHIFT: usize = 2;
104 const MASK: u16 = 0b11;
105 const NON_CACHEABLE: u16 = 0b01;
106 const WRITE_BACK: u16 = 0b11;
107}
108
Balint Dobszaya5846852025-02-26 15:38:53 +0100109/// Shareability attribute of a memory region. Only valid for normal memory.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200110#[derive(Debug, Default, Clone, Copy, PartialEq)]
111#[repr(u16)]
112pub enum Shareability {
113 #[default]
114 NonShareable = Self::NON_SHAREABLE << Self::SHIFT,
115 Outer = Self::OUTER << Self::SHIFT,
116 Inner = Self::INNER << Self::SHIFT,
117}
118
119impl TryFrom<u16> for Shareability {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100120 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200121
122 fn try_from(value: u16) -> Result<Self, Self::Error> {
123 match (value >> Self::SHIFT) & Self::MASK {
124 Self::NON_SHAREABLE => Ok(Self::NonShareable),
125 Self::OUTER => Ok(Self::Outer),
126 Self::INNER => Ok(Self::Inner),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100127 _ => Err(Error::InvalidShareability(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200128 }
129 }
130}
131
132impl Shareability {
133 const SHIFT: usize = 0;
134 const MASK: u16 = 0b11;
135 const NON_SHAREABLE: u16 = 0b00;
136 const OUTER: u16 = 0b10;
137 const INNER: u16 = 0b11;
138}
139
Balint Dobszaya5846852025-02-26 15:38:53 +0100140/// Device memory attributes.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200141#[derive(Debug, Default, Clone, Copy)]
142#[repr(u16)]
143pub enum DeviceMemAttributes {
144 #[default]
145 DevnGnRnE = Self::DEV_NGNRNE << Self::SHIFT,
146 DevnGnRE = Self::DEV_NGNRE << Self::SHIFT,
147 DevnGRE = Self::DEV_NGRE << Self::SHIFT,
148 DevGRE = Self::DEV_GRE << Self::SHIFT,
149}
150
151impl TryFrom<u16> for DeviceMemAttributes {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100152 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200153
154 fn try_from(value: u16) -> Result<Self, Self::Error> {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200155 match (value >> Self::SHIFT) & Self::MASK {
156 Self::DEV_NGNRNE => Ok(Self::DevnGnRnE),
157 Self::DEV_NGNRE => Ok(Self::DevnGnRE),
158 Self::DEV_NGRE => Ok(Self::DevnGRE),
159 Self::DEV_GRE => Ok(Self::DevGRE),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100160 _ => Err(Error::InvalidDevMemAttributes(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200161 }
162 }
163}
164
165impl DeviceMemAttributes {
166 const SHIFT: usize = 2;
167 const MASK: u16 = 0b11;
168 const DEV_NGNRNE: u16 = 0b00;
169 const DEV_NGNRE: u16 = 0b01;
170 const DEV_NGRE: u16 = 0b10;
171 const DEV_GRE: u16 = 0b11;
172}
173
Balint Dobszaya5846852025-02-26 15:38:53 +0100174/// Memory region type.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200175#[derive(Debug, Default, Clone, Copy)]
176pub enum MemType {
177 #[default]
178 NotSpecified,
179 Device(DeviceMemAttributes),
180 Normal {
181 cacheability: Cacheability,
182 shareability: Shareability,
183 },
184}
185
186impl TryFrom<u16> for MemType {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100187 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200188
189 fn try_from(value: u16) -> Result<Self, Self::Error> {
190 match (value >> Self::SHIFT) & Self::MASK {
191 Self::NOT_SPECIFIED => Ok(Self::NotSpecified),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100192 Self::DEVICE => Ok(Self::Device(value.try_into()?)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200193 Self::NORMAL => Ok(Self::Normal {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100194 cacheability: value.try_into()?,
195 shareability: value.try_into()?,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200196 }),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100197 _ => Err(Error::InvalidMemType(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200198 }
199 }
200}
201
202impl From<MemType> for u16 {
203 fn from(value: MemType) -> Self {
204 match value {
205 MemType::NotSpecified => MemType::NOT_SPECIFIED << MemType::SHIFT,
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100206 MemType::Device(attr) => attr as u16 | (MemType::DEVICE << MemType::SHIFT),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200207 MemType::Normal {
208 cacheability,
209 shareability,
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100210 } => cacheability as u16 | shareability as u16 | (MemType::NORMAL << MemType::SHIFT),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200211 }
212 }
213}
214
215impl MemType {
216 const SHIFT: usize = 4;
217 const MASK: u16 = 0b11;
218 const NOT_SPECIFIED: u16 = 0b00;
219 const DEVICE: u16 = 0b01;
220 const NORMAL: u16 = 0b10;
221}
222
Balint Dobszaya5846852025-02-26 15:38:53 +0100223/// Memory region security attribute.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200224#[derive(Debug, Default, Clone, Copy, PartialEq)]
225#[repr(u16)]
226pub enum MemRegionSecurity {
227 #[default]
228 Secure = Self::SECURE << Self::SHIFT,
229 NonSecure = Self::NON_SECURE << Self::SHIFT,
230}
231
Balint Dobszayc758dd42025-01-15 18:10:40 +0100232impl From<u16> for MemRegionSecurity {
233 fn from(value: u16) -> Self {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200234 match (value >> Self::SHIFT) & Self::MASK {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100235 Self::SECURE => Self::Secure,
236 Self::NON_SECURE => Self::NonSecure,
237 _ => panic!(), // The match is exhaustive for a 1-bit value
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200238 }
239 }
240}
241
242impl MemRegionSecurity {
243 const SHIFT: usize = 6;
244 const MASK: u16 = 0b1;
245 const SECURE: u16 = 0b0;
246 const NON_SECURE: u16 = 0b1;
247}
248
Balint Dobszaya5846852025-02-26 15:38:53 +0100249/// Memory region attributes descriptor.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200250#[derive(Debug, Default, Clone, Copy)]
251pub struct MemRegionAttributes {
252 pub security: MemRegionSecurity,
253 pub mem_type: MemType,
254}
255
256impl TryFrom<u16> for MemRegionAttributes {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100257 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200258
259 fn try_from(value: u16) -> Result<Self, Self::Error> {
260 // bits[15:7]: Reserved (MBZ)
Balint Dobszayc758dd42025-01-15 18:10:40 +0100261 if value >> 7 == 0 {
262 Ok(Self {
263 security: value.into(),
264 mem_type: value.try_into()?,
265 })
266 } else {
267 Err(Error::InvalidMemAttributes(value))
268 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200269 }
270}
271
272impl From<MemRegionAttributes> for u16 {
273 fn from(value: MemRegionAttributes) -> Self {
274 value.security as u16 | u16::from(value.mem_type)
275 }
276}
277
Balint Dobszaya5846852025-02-26 15:38:53 +0100278/// Instruction access permissions of a memory region.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200279#[derive(Debug, Default, Clone, Copy)]
280#[repr(u8)]
281pub enum InstuctionAccessPerm {
282 #[default]
283 NotSpecified = Self::NOT_SPECIFIED << Self::SHIFT,
284 NotExecutable = Self::NOT_EXECUTABLE << Self::SHIFT,
285 Executable = Self::EXECUTABLE << Self::SHIFT,
286}
287
288impl TryFrom<u8> for InstuctionAccessPerm {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100289 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200290
291 fn try_from(value: u8) -> Result<Self, Self::Error> {
292 match (value >> Self::SHIFT) & Self::MASK {
293 Self::NOT_SPECIFIED => Ok(Self::NotSpecified),
294 Self::NOT_EXECUTABLE => Ok(Self::NotExecutable),
295 Self::EXECUTABLE => Ok(Self::Executable),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100296 _ => Err(Error::InvalidInstrAccessPerm(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200297 }
298 }
299}
300
301impl InstuctionAccessPerm {
302 const SHIFT: usize = 2;
303 const MASK: u8 = 0b11;
304 const NOT_SPECIFIED: u8 = 0b00;
305 const NOT_EXECUTABLE: u8 = 0b01;
306 const EXECUTABLE: u8 = 0b10;
307}
308
Balint Dobszaya5846852025-02-26 15:38:53 +0100309/// Data access permissions of a memory region.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200310#[derive(Debug, Default, Clone, Copy)]
311#[repr(u8)]
312pub enum DataAccessPerm {
313 #[default]
314 NotSpecified = Self::NOT_SPECIFIED << Self::SHIFT,
315 ReadOnly = Self::READ_ONLY << Self::SHIFT,
316 ReadWrite = Self::READ_WRITE << Self::SHIFT,
317}
318
319impl TryFrom<u8> for DataAccessPerm {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100320 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200321
322 fn try_from(value: u8) -> Result<Self, Self::Error> {
323 match (value >> Self::SHIFT) & Self::MASK {
324 Self::NOT_SPECIFIED => Ok(Self::NotSpecified),
325 Self::READ_ONLY => Ok(Self::ReadOnly),
326 Self::READ_WRITE => Ok(Self::ReadWrite),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100327 _ => Err(Error::InvalidDataAccessPerm(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200328 }
329 }
330}
331
332impl DataAccessPerm {
333 const SHIFT: usize = 0;
334 const MASK: u8 = 0b11;
335 const NOT_SPECIFIED: u8 = 0b00;
336 const READ_ONLY: u8 = 0b01;
337 const READ_WRITE: u8 = 0b10;
338}
339
Balint Dobszaya5846852025-02-26 15:38:53 +0100340/// Endpoint memory access permissions descriptor.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200341#[derive(Debug, Default, Clone, Copy)]
Balint Dobszayc758dd42025-01-15 18:10:40 +0100342pub struct MemAccessPerm {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200343 pub endpoint_id: u16,
344 pub instr_access: InstuctionAccessPerm,
345 pub data_access: DataAccessPerm,
346 pub flags: u8, // TODO
347}
348
Balint Dobszaya5846852025-02-26 15:38:53 +0100349/// Iterator of endpoint memory access permission descriptors.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100350pub struct MemAccessPermIterator<'a> {
351 buf: &'a [u8],
352 offset: usize,
353 count: usize,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200354}
355
Balint Dobszayc758dd42025-01-15 18:10:40 +0100356impl<'a> MemAccessPermIterator<'a> {
Balint Dobszaya5846852025-02-26 15:38:53 +0100357 /// Create an iterator of endpoint memory access permission descriptors from a buffer.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100358 fn new(buf: &'a [u8], count: usize, offset: usize) -> Result<Self, Error> {
359 let Some(total_size) = count
360 .checked_mul(size_of::<endpoint_memory_access_descriptor>())
361 .and_then(|x| x.checked_add(offset))
362 else {
363 return Err(Error::InvalidBufferSize);
364 };
365
366 if buf.len() < total_size {
367 return Err(Error::InvalidBufferSize);
368 }
369
370 Ok(Self { buf, offset, count })
371 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200372}
373
Balint Dobszayc758dd42025-01-15 18:10:40 +0100374impl Iterator for MemAccessPermIterator<'_> {
375 type Item = Result<MemAccessPerm, Error>;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200376
Balint Dobszayc758dd42025-01-15 18:10:40 +0100377 fn next(&mut self) -> Option<Self::Item> {
378 if self.count > 0 {
379 let offset = self.offset;
380 self.offset += size_of::<endpoint_memory_access_descriptor>();
381 self.count -= 1;
382
383 let Ok(desc_raw) = endpoint_memory_access_descriptor::ref_from_bytes(
384 &self.buf[offset..offset + size_of::<endpoint_memory_access_descriptor>()],
385 ) else {
386 return Some(Err(Error::MalformedDescriptor));
387 };
388
389 let instr_access = match desc_raw
390 .access_perm_desc
391 .memory_access_permissions
392 .try_into()
393 {
394 Ok(v) => v,
395 Err(e) => return Some(Err(e)),
396 };
397
398 let data_access = match desc_raw
399 .access_perm_desc
400 .memory_access_permissions
401 .try_into()
402 {
403 Ok(v) => v,
404 Err(e) => return Some(Err(e)),
405 };
406
407 let desc = MemAccessPerm {
408 endpoint_id: desc_raw.access_perm_desc.endpoint_id,
409 instr_access,
410 data_access,
411 flags: desc_raw.access_perm_desc.flags,
412 };
413
414 return Some(Ok(desc));
415 }
416
417 None
418 }
419}
420
Balint Dobszaya5846852025-02-26 15:38:53 +0100421/// Constituent memory region descriptor.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100422#[derive(Debug, Default, Clone, Copy)]
423pub struct ConstituentMemRegion {
424 pub address: u64,
425 pub page_cnt: u32,
426}
427
Balint Dobszaya5846852025-02-26 15:38:53 +0100428/// Iterator of constituent memory region descriptors.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100429pub struct ConstituentMemRegionIterator<'a> {
430 buf: &'a [u8],
431 offset: usize,
432 count: usize,
433}
434
435impl<'a> ConstituentMemRegionIterator<'a> {
Balint Dobszaya5846852025-02-26 15:38:53 +0100436 /// Create an iterator of constituent memory region descriptors from a buffer.
Imre Kis1a4abbe2025-04-11 17:08:51 +0200437 fn new(
438 buf: &'a [u8],
439 region_count: usize,
440 total_page_count: u32,
441 offset: usize,
442 ) -> Result<Self, Error> {
443 let descriptor_size = size_of::<constituent_memory_region_descriptor>();
444
445 let Some(total_size) = region_count
446 .checked_mul(descriptor_size)
Balint Dobszayc758dd42025-01-15 18:10:40 +0100447 .and_then(|x| x.checked_add(offset))
448 else {
449 return Err(Error::InvalidBufferSize);
450 };
451
452 if buf.len() < total_size {
453 return Err(Error::InvalidBufferSize);
454 }
455
Imre Kis1a4abbe2025-04-11 17:08:51 +0200456 // Check if the sum of of page counts in the constituent_memory_region_descriptors matches
457 // the total_page_count field of the composite_memory_region_descriptor.
458 let mut page_count_sum: u32 = 0;
459 for desc_offset in
460 (offset..offset + descriptor_size * region_count).step_by(descriptor_size)
461 {
462 let Ok(desc_raw) = constituent_memory_region_descriptor::ref_from_bytes(
463 &buf[desc_offset..desc_offset + descriptor_size],
464 ) else {
465 return Err(Error::MalformedDescriptor);
466 };
467
468 page_count_sum = page_count_sum
469 .checked_add(desc_raw.page_count)
470 .ok_or(Error::MalformedDescriptor)?;
471 }
472
473 if page_count_sum != total_page_count {
474 return Err(Error::MalformedDescriptor);
475 }
476
477 Ok(Self {
478 buf,
479 offset,
480 count: region_count,
481 })
Balint Dobszayc758dd42025-01-15 18:10:40 +0100482 }
483}
484
485impl Iterator for ConstituentMemRegionIterator<'_> {
486 type Item = Result<ConstituentMemRegion, Error>;
487
488 fn next(&mut self) -> Option<Self::Item> {
489 if self.count > 0 {
490 let offset = self.offset;
491 self.offset += size_of::<constituent_memory_region_descriptor>();
492 self.count -= 1;
493
494 let Ok(desc_raw) = constituent_memory_region_descriptor::ref_from_bytes(
495 &self.buf[offset..offset + size_of::<constituent_memory_region_descriptor>()],
496 ) else {
497 return Some(Err(Error::MalformedDescriptor));
498 };
499
500 let desc = ConstituentMemRegion {
501 address: desc_raw.address,
502 page_cnt: desc_raw.page_count,
503 };
504
505 return Some(Ok(desc));
506 }
507
508 None
509 }
510}
511
Balint Dobszaya5846852025-02-26 15:38:53 +0100512/// Flags of a memory management transaction.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100513#[derive(Debug, Default, Clone, Copy)]
514pub struct MemTransactionFlags(pub u32);
515
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200516impl MemTransactionFlags {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100517 pub const MEM_SHARE_MASK: u32 = 0b11;
518 pub const MEM_RETRIEVE_REQ_MASK: u32 = 0b11_1111_1111;
519 pub const MEM_RETRIEVE_RESP_MASK: u32 = 0b1_1111;
520 pub const ZERO_MEMORY: u32 = 0b1;
521 pub const TIME_SLICING: u32 = 0b1 << 1;
522 pub const ZERO_AFTER_RELINQ: u32 = 0b1 << 2;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200523 pub const TYPE_SHARE: u32 = 0b01 << 3;
Balint Dobszayc758dd42025-01-15 18:10:40 +0100524 pub const TYPE_LEND: u32 = 0b10 << 3;
525 pub const TYPE_DONATE: u32 = 0b11 << 3;
526 pub const ALIGN_HINT_MASK: u32 = 0b1111 << 5;
527 pub const HINT_VALID: u32 = 0b1 << 9;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200528}
529
Balint Dobszaya5846852025-02-26 15:38:53 +0100530/// Memory transaction decriptor. Used by an Owner/Lender and a Borrower/Receiver in a transaction
531/// to donate, lend or share a memory region.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200532#[derive(Debug, Default)]
533pub struct MemTransactionDesc {
534 pub sender_id: u16,
535 pub mem_region_attr: MemRegionAttributes,
536 pub flags: MemTransactionFlags,
537 pub handle: Handle,
538 pub tag: u64, // TODO
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200539}
540
541impl MemTransactionDesc {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100542 // Offset from the base of the memory transaction descriptor to the first element in the
543 // endpoint memory access descriptor array. Must be 16 byte aligned, but otherwise we're free to
544 // choose any value here. Let's just pack it right after the memory transaction descriptor.
545 const ENDPOINT_MEM_ACCESS_DESC_OFFSET: usize =
546 size_of::<memory_transaction_descriptor>().next_multiple_of(16);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200547
Balint Dobszayc758dd42025-01-15 18:10:40 +0100548 // The array of constituent memory region descriptors starts right after the composite memory
549 // region descriptor
550 const CONSTITUENT_ARRAY_OFFSET: usize = size_of::<composite_memory_region_descriptor>();
551
Balint Dobszaya5846852025-02-26 15:38:53 +0100552 /// Serialize a memory transaction descriptor and the related constituent memory region
553 /// descriptors and endpoint memory access permission descriptors into a buffer.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100554 pub fn pack(
555 &self,
556 constituents: &[ConstituentMemRegion],
557 access_descriptors: &[MemAccessPerm],
558 buf: &mut [u8],
559 ) -> usize {
560 let mem_access_desc_size = size_of::<endpoint_memory_access_descriptor>();
561 let mem_access_desc_cnt = access_descriptors.len();
562
563 let transaction_desc_raw = memory_transaction_descriptor {
564 sender_endpoint_id: self.sender_id,
565 memory_region_attributes: self.mem_region_attr.into(),
566 flags: self.flags.0,
567 handle: self.handle.0,
568 tag: self.tag,
569 endpoint_mem_access_desc_size: mem_access_desc_size as u32,
570 endpoint_mem_access_desc_count: mem_access_desc_cnt as u32,
571 endpoint_mem_access_desc_array_offset: Self::ENDPOINT_MEM_ACCESS_DESC_OFFSET as u32,
572 reserved1: 0,
573 reserved2: 0,
574 };
575
576 transaction_desc_raw.write_to_prefix(buf).unwrap();
577
578 // Offset from the base of the memory transaction descriptor to the composite memory region
579 // descriptor to which the endpoint access permissions apply.
580 let composite_offset = mem_access_desc_cnt
581 .checked_mul(mem_access_desc_size)
582 .unwrap()
583 .checked_add(Self::ENDPOINT_MEM_ACCESS_DESC_OFFSET)
584 .unwrap()
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200585 .next_multiple_of(8);
586
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200587 let mut offset = Self::ENDPOINT_MEM_ACCESS_DESC_OFFSET;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200588
Balint Dobszayc758dd42025-01-15 18:10:40 +0100589 for desc in access_descriptors {
590 let desc_raw = endpoint_memory_access_descriptor {
591 access_perm_desc: memory_access_permission_descriptor {
592 endpoint_id: desc.endpoint_id,
593 memory_access_permissions: desc.data_access as u8 | desc.instr_access as u8,
594 flags: desc.flags,
595 },
596 composite_offset: composite_offset as u32,
597 reserved: 0,
598 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200599
Balint Dobszayc758dd42025-01-15 18:10:40 +0100600 desc_raw.write_to_prefix(&mut buf[offset..]).unwrap();
601 offset += mem_access_desc_size;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200602 }
603
Imre Kis1a4abbe2025-04-11 17:08:51 +0200604 let mut total_page_count: u32 = 0;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200605
Balint Dobszayc758dd42025-01-15 18:10:40 +0100606 offset = composite_offset + Self::CONSTITUENT_ARRAY_OFFSET;
607 for constituent in constituents {
608 let constituent_raw = constituent_memory_region_descriptor {
609 address: constituent.address,
610 page_count: constituent.page_cnt,
611 reserved: 0,
612 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200613
Balint Dobszayc758dd42025-01-15 18:10:40 +0100614 constituent_raw.write_to_prefix(&mut buf[offset..]).unwrap();
615 offset += size_of::<constituent_memory_region_descriptor>();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200616
Imre Kis1a4abbe2025-04-11 17:08:51 +0200617 total_page_count = total_page_count
618 .checked_add(constituent_raw.page_count)
619 .expect("total_page_count overflow");
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200620 }
621
Balint Dobszayc758dd42025-01-15 18:10:40 +0100622 let composite_desc_raw = composite_memory_region_descriptor {
623 total_page_count,
624 address_range_count: constituents.len() as u32,
625 reserved: 0,
626 };
627
628 composite_desc_raw
629 .write_to_prefix(&mut buf[composite_offset..])
630 .unwrap();
631
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200632 offset
633 }
634
Balint Dobszaya5846852025-02-26 15:38:53 +0100635 /// Deserialize a memory transaction descriptor from a buffer and return an interator of the
636 /// related endpoint memory access permission descriptors and constituent memory region
637 /// descriptors, if any.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100638 pub fn unpack(
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200639 buf: &[u8],
Balint Dobszayc758dd42025-01-15 18:10:40 +0100640 ) -> Result<
641 (
642 MemTransactionDesc,
643 MemAccessPermIterator,
644 Option<ConstituentMemRegionIterator>,
645 ),
646 Error,
647 > {
648 let Some(transaction_desc_bytes) = buf.get(0..size_of::<memory_transaction_descriptor>())
649 else {
650 return Err(Error::InvalidBufferSize);
651 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200652
Balint Dobszayc758dd42025-01-15 18:10:40 +0100653 let Ok(transaction_desc_raw) =
654 memory_transaction_descriptor::ref_from_bytes(transaction_desc_bytes)
655 else {
656 return Err(Error::MalformedDescriptor);
657 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200658
Balint Dobszayc758dd42025-01-15 18:10:40 +0100659 if size_of::<endpoint_memory_access_descriptor>()
660 != transaction_desc_raw.endpoint_mem_access_desc_size as usize
661 {
662 return Err(Error::MalformedDescriptor);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200663 }
664
Balint Dobszayc758dd42025-01-15 18:10:40 +0100665 if transaction_desc_raw.endpoint_mem_access_desc_count == 0 {
666 return Err(Error::MalformedDescriptor);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200667 }
668
Balint Dobszayc758dd42025-01-15 18:10:40 +0100669 let Some(total_desc_size) = transaction_desc_raw
670 .endpoint_mem_access_desc_size
671 .checked_mul(transaction_desc_raw.endpoint_mem_access_desc_count)
672 .and_then(|x| {
673 x.checked_add(transaction_desc_raw.endpoint_mem_access_desc_array_offset)
674 })
675 else {
676 return Err(Error::InvalidBufferSize);
677 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200678
Balint Dobszayc758dd42025-01-15 18:10:40 +0100679 if buf.len() < total_desc_size as usize {
680 return Err(Error::InvalidBufferSize);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200681 }
682
Balint Dobszayc758dd42025-01-15 18:10:40 +0100683 let transaction_desc = MemTransactionDesc {
684 sender_id: transaction_desc_raw.sender_endpoint_id,
685 mem_region_attr: transaction_desc_raw.memory_region_attributes.try_into()?,
686 flags: MemTransactionFlags(transaction_desc_raw.flags),
687 handle: Handle(transaction_desc_raw.handle),
688 tag: transaction_desc_raw.tag,
689 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200690
Balint Dobszayc758dd42025-01-15 18:10:40 +0100691 let mut offset = transaction_desc_raw.endpoint_mem_access_desc_array_offset as usize;
692
693 let access_desc_iter = MemAccessPermIterator::new(
694 buf,
695 transaction_desc_raw.endpoint_mem_access_desc_count as usize,
696 offset,
697 )?;
698
699 // We have to check the first endpoint memory access descriptor to get the composite offset
700 let Ok(desc_raw) = endpoint_memory_access_descriptor::ref_from_bytes(
701 &buf[offset..offset + size_of::<endpoint_memory_access_descriptor>()],
702 ) else {
703 return Err(Error::MalformedDescriptor);
704 };
705
706 offset = desc_raw.composite_offset as usize;
707
708 // An offset value of 0 indicates that the endpoint access permissions apply to a memory
709 // region description identified by the Handle (i.e. there is no composite descriptor)
710 if offset == 0 {
711 return Ok((transaction_desc, access_desc_iter, None));
712 }
713
714 let Some(composite_desc_bytes) =
715 buf.get(offset..offset + size_of::<composite_memory_region_descriptor>())
716 else {
717 return Err(Error::InvalidBufferSize);
718 };
719
720 let Ok(composite_desc_raw) =
721 composite_memory_region_descriptor::ref_from_bytes(composite_desc_bytes)
722 else {
723 return Err(Error::MalformedDescriptor);
724 };
725
726 let constituent_iter = ConstituentMemRegionIterator::new(
727 buf,
728 composite_desc_raw.address_range_count as usize,
Imre Kis1a4abbe2025-04-11 17:08:51 +0200729 composite_desc_raw.total_page_count,
Balint Dobszayc758dd42025-01-15 18:10:40 +0100730 offset + Self::CONSTITUENT_ARRAY_OFFSET,
731 )?;
732
Balint Dobszayc758dd42025-01-15 18:10:40 +0100733 Ok((transaction_desc, access_desc_iter, Some(constituent_iter)))
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200734 }
735}
736
Balint Dobszaya5846852025-02-26 15:38:53 +0100737/// Descriptor to relinquish a memory region. Currently only supports specifying a single endpoint.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200738#[derive(Debug, Default)]
739pub struct MemRelinquishDesc {
740 pub handle: Handle,
741 pub flags: u32,
Balint Dobszayc758dd42025-01-15 18:10:40 +0100742 pub endpoint: u16,
743}
744
745impl TryFrom<&[u8]> for MemRelinquishDesc {
746 type Error = Error;
747
748 fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
749 let Some(desc_bytes) = buf.get(0..size_of::<memory_relinquish_descriptor>()) else {
750 return Err(Error::InvalidBufferSize);
751 };
752
753 let Ok(desc_raw) = memory_relinquish_descriptor::ref_from_bytes(desc_bytes) else {
754 return Err(Error::MalformedDescriptor);
755 };
756
757 let Some(total_desc_size) = (desc_raw.endpoint_count as usize)
758 .checked_mul(size_of::<u16>())
759 .and_then(|x| x.checked_add(Self::ENDPOINT_ARRAY_OFFSET))
760 else {
761 return Err(Error::InvalidBufferSize);
762 };
763
764 if buf.len() < total_desc_size {
765 return Err(Error::InvalidBufferSize);
766 }
767
768 // If the caller is a PE endpoint Borrower, then Endpoint count must equal 1. Currently only
769 // this case is supported. The array of endpoint IDs contains only a single element.
770 if desc_raw.endpoint_count != 1 {
771 return Err(Error::UnsupportedEndpointCount(desc_raw.endpoint_count));
772 }
773
774 let endpoint = u16::from_le_bytes([
775 buf[Self::ENDPOINT_ARRAY_OFFSET],
776 buf[Self::ENDPOINT_ARRAY_OFFSET + 1],
777 ]);
778
779 Ok(Self {
780 handle: Handle(desc_raw.handle),
781 flags: desc_raw.flags, // TODO: validate
782 endpoint,
783 })
784 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200785}
786
787impl MemRelinquishDesc {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100788 const ENDPOINT_ARRAY_OFFSET: usize = size_of::<memory_relinquish_descriptor>();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200789}
790
Imre Kisa0122692025-06-05 17:09:28 +0200791/// Success argument structure for `FFA_MEM_DONATE`, `FFA_MEM_LEND` and `FFA_MEM_SHARE`.
792pub struct SuccessArgsMemOp {
793 pub handle: Handle,
794}
795
796impl From<SuccessArgsMemOp> for SuccessArgs {
797 fn from(value: SuccessArgsMemOp) -> Self {
798 let [handle_lo, handle_hi]: [u32; 2] = value.handle.into();
799 SuccessArgs::Args32([handle_lo, handle_hi, 0, 0, 0, 0])
800 }
801}
802
803impl TryFrom<SuccessArgs> for SuccessArgsMemOp {
804 type Error = crate::Error;
805
806 fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
807 let [handle_lo, handle_hi, ..] = value.try_get_args32()?;
808 Ok(Self {
809 handle: [handle_lo, handle_hi].into(),
810 })
811 }
812}
813
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200814#[cfg(test)]
815mod tests {
816 use super::*;
817
818 #[allow(dead_code)]
819 const MEM_SHARE_FROM_SP1: &[u8] = &[
820 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
821 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
822 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
823 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
824 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
825 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
826 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
827 ];
828
829 #[allow(dead_code)]
830 const MEM_SHARE_FROM_SP2: &[u8] = &[
831 0x06, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
832 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
833 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
834 0x00, 0x00, 0x00, 0x05, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
835 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
836 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x07, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
837 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
838 ];
839
840 #[allow(dead_code)]
841 const MEM_RETRIEVE_REQ_FROM_SP1: &[u8] = &[
842 0x05, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
843 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
844 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
845 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
846 0x00, 0x00, 0x00, 0x00,
847 ];
848
849 #[allow(dead_code)]
850 const MEM_RETRIEVE_REQ_FROM_SP2: &[u8] = &[
851 0x06, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
852 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
853 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
854 0x00, 0x00, 0x00, 0x05, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
855 0x00, 0x00, 0x00, 0x00,
856 ];
857
858 #[allow(dead_code)]
859 const MEM_SHARE_FROM_NWD: &[u8] = &[
860 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
861 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
862 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
863 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
864 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
865 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x22, 0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00,
866 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
867 ];
868
869 #[test]
870 fn mem_share() {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100871 let (transaction_desc, access_desc, constituents) =
872 MemTransactionDesc::unpack(MEM_SHARE_FROM_SP1).unwrap();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200873
874 println!("transaction desc: {:#x?}", transaction_desc);
Balint Dobszayc758dd42025-01-15 18:10:40 +0100875 access_desc.for_each(|d| println!("endpont desc: {d:#x?}"));
876 constituents
877 .unwrap()
878 .for_each(|c| println!("constituent desc: {c:#x?}"));
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200879 }
880}