blob: dc0fc417dae0480947adc03fb800bddba8590d52 [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
Balint Dobszayc758dd42025-01-15 18:10:40 +010015use crate::ffa_v1_1::{
16 composite_memory_region_descriptor, constituent_memory_region_descriptor,
17 endpoint_memory_access_descriptor, memory_access_permission_descriptor,
18 memory_relinquish_descriptor, memory_transaction_descriptor,
19};
20use core::mem::size_of;
21use thiserror::Error;
22use zerocopy::{FromBytes, IntoBytes};
23
Balint Dobszaya5846852025-02-26 15:38:53 +010024/// Rich error types returned by this module. Should be converted to [`crate::FfaError`] when used
25/// with the `FFA_ERROR` interface.
Balint Dobszayc758dd42025-01-15 18:10:40 +010026#[derive(Debug, Error)]
27pub enum Error {
28 #[error("Invalid cacheability attribute {0}")]
29 InvalidCacheability(u16),
30 #[error("Invalid shareability attribute {0}")]
31 InvalidShareability(u16),
32 #[error("Invalid device memory attributes {0}")]
33 InvalidDevMemAttributes(u16),
34 #[error("Invalid instruction access permission {0}")]
35 InvalidInstrAccessPerm(u8),
36 #[error("Invalid instruction data permission {0}")]
37 InvalidDataAccessPerm(u8),
38 #[error("Invalid memory type {0}")]
39 InvalidMemType(u16),
40 #[error("Invalid memory attributes {0}")]
41 InvalidMemAttributes(u16),
42 #[error("Composite offset mismatch")]
43 CompositeOffsetMismatch,
44 #[error("Invalid endpoint count {0}")]
45 UnsupportedEndpointCount(u32),
46 #[error("Invalid buffer size")]
47 InvalidBufferSize,
48 #[error("Malformed descriptor")]
49 MalformedDescriptor,
50}
51
52impl From<Error> for crate::FfaError {
53 fn from(_value: Error) -> Self {
54 Self::InvalidParameters
55 }
56}
Balint Dobszay5bf492f2024-07-29 17:21:32 +020057
Balint Dobszaya5846852025-02-26 15:38:53 +010058/// Memory region handle, used to identify a composite memory region description.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020059#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
60pub struct Handle(pub u64);
61
62impl From<[u32; 2]> for Handle {
63 fn from(value: [u32; 2]) -> Self {
Balint Dobszaye9a3e762025-02-26 17:29:57 +010064 Self(((value[1] as u64) << 32) | value[0] as u64)
Balint Dobszay5bf492f2024-07-29 17:21:32 +020065 }
66}
67
68impl From<Handle> for [u32; 2] {
69 fn from(value: Handle) -> Self {
70 [value.0 as u32, (value.0 >> 32) as u32]
71 }
72}
73
74impl Handle {
75 pub const INVALID: u64 = 0xffff_ffff_ffff_ffff;
76}
77
Balint Dobszaya5846852025-02-26 15:38:53 +010078/// Cacheability attribute of a memory region. Only valid for normal memory.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020079#[derive(Debug, Default, Clone, Copy, PartialEq)]
80#[repr(u16)]
81pub enum Cacheability {
82 #[default]
83 NonCacheable = Self::NON_CACHEABLE << Self::SHIFT,
84 WriteBack = Self::WRITE_BACK << Self::SHIFT,
85}
86
87impl TryFrom<u16> for Cacheability {
Balint Dobszayc758dd42025-01-15 18:10:40 +010088 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +020089
90 fn try_from(value: u16) -> Result<Self, Self::Error> {
91 match (value >> Self::SHIFT) & Self::MASK {
92 Self::NON_CACHEABLE => Ok(Cacheability::NonCacheable),
93 Self::WRITE_BACK => Ok(Cacheability::WriteBack),
Balint Dobszayc758dd42025-01-15 18:10:40 +010094 _ => Err(Error::InvalidCacheability(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +020095 }
96 }
97}
98
99impl Cacheability {
100 const SHIFT: usize = 2;
101 const MASK: u16 = 0b11;
102 const NON_CACHEABLE: u16 = 0b01;
103 const WRITE_BACK: u16 = 0b11;
104}
105
Balint Dobszaya5846852025-02-26 15:38:53 +0100106/// Shareability attribute of a memory region. Only valid for normal memory.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200107#[derive(Debug, Default, Clone, Copy, PartialEq)]
108#[repr(u16)]
109pub enum Shareability {
110 #[default]
111 NonShareable = Self::NON_SHAREABLE << Self::SHIFT,
112 Outer = Self::OUTER << Self::SHIFT,
113 Inner = Self::INNER << Self::SHIFT,
114}
115
116impl TryFrom<u16> for Shareability {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100117 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200118
119 fn try_from(value: u16) -> Result<Self, Self::Error> {
120 match (value >> Self::SHIFT) & Self::MASK {
121 Self::NON_SHAREABLE => Ok(Self::NonShareable),
122 Self::OUTER => Ok(Self::Outer),
123 Self::INNER => Ok(Self::Inner),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100124 _ => Err(Error::InvalidShareability(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200125 }
126 }
127}
128
129impl Shareability {
130 const SHIFT: usize = 0;
131 const MASK: u16 = 0b11;
132 const NON_SHAREABLE: u16 = 0b00;
133 const OUTER: u16 = 0b10;
134 const INNER: u16 = 0b11;
135}
136
Balint Dobszaya5846852025-02-26 15:38:53 +0100137/// Device memory attributes.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200138#[derive(Debug, Default, Clone, Copy)]
139#[repr(u16)]
140pub enum DeviceMemAttributes {
141 #[default]
142 DevnGnRnE = Self::DEV_NGNRNE << Self::SHIFT,
143 DevnGnRE = Self::DEV_NGNRE << Self::SHIFT,
144 DevnGRE = Self::DEV_NGRE << Self::SHIFT,
145 DevGRE = Self::DEV_GRE << Self::SHIFT,
146}
147
148impl TryFrom<u16> for DeviceMemAttributes {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100149 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200150
151 fn try_from(value: u16) -> Result<Self, Self::Error> {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200152 match (value >> Self::SHIFT) & Self::MASK {
153 Self::DEV_NGNRNE => Ok(Self::DevnGnRnE),
154 Self::DEV_NGNRE => Ok(Self::DevnGnRE),
155 Self::DEV_NGRE => Ok(Self::DevnGRE),
156 Self::DEV_GRE => Ok(Self::DevGRE),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100157 _ => Err(Error::InvalidDevMemAttributes(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200158 }
159 }
160}
161
162impl DeviceMemAttributes {
163 const SHIFT: usize = 2;
164 const MASK: u16 = 0b11;
165 const DEV_NGNRNE: u16 = 0b00;
166 const DEV_NGNRE: u16 = 0b01;
167 const DEV_NGRE: u16 = 0b10;
168 const DEV_GRE: u16 = 0b11;
169}
170
Balint Dobszaya5846852025-02-26 15:38:53 +0100171/// Memory region type.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200172#[derive(Debug, Default, Clone, Copy)]
173pub enum MemType {
174 #[default]
175 NotSpecified,
176 Device(DeviceMemAttributes),
177 Normal {
178 cacheability: Cacheability,
179 shareability: Shareability,
180 },
181}
182
183impl TryFrom<u16> for MemType {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100184 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200185
186 fn try_from(value: u16) -> Result<Self, Self::Error> {
187 match (value >> Self::SHIFT) & Self::MASK {
188 Self::NOT_SPECIFIED => Ok(Self::NotSpecified),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100189 Self::DEVICE => Ok(Self::Device(value.try_into()?)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200190 Self::NORMAL => Ok(Self::Normal {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100191 cacheability: value.try_into()?,
192 shareability: value.try_into()?,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200193 }),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100194 _ => Err(Error::InvalidMemType(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200195 }
196 }
197}
198
199impl From<MemType> for u16 {
200 fn from(value: MemType) -> Self {
201 match value {
202 MemType::NotSpecified => MemType::NOT_SPECIFIED << MemType::SHIFT,
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100203 MemType::Device(attr) => attr as u16 | (MemType::DEVICE << MemType::SHIFT),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200204 MemType::Normal {
205 cacheability,
206 shareability,
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100207 } => cacheability as u16 | shareability as u16 | (MemType::NORMAL << MemType::SHIFT),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200208 }
209 }
210}
211
212impl MemType {
213 const SHIFT: usize = 4;
214 const MASK: u16 = 0b11;
215 const NOT_SPECIFIED: u16 = 0b00;
216 const DEVICE: u16 = 0b01;
217 const NORMAL: u16 = 0b10;
218}
219
Balint Dobszaya5846852025-02-26 15:38:53 +0100220/// Memory region security attribute.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200221#[derive(Debug, Default, Clone, Copy, PartialEq)]
222#[repr(u16)]
223pub enum MemRegionSecurity {
224 #[default]
225 Secure = Self::SECURE << Self::SHIFT,
226 NonSecure = Self::NON_SECURE << Self::SHIFT,
227}
228
Balint Dobszayc758dd42025-01-15 18:10:40 +0100229impl From<u16> for MemRegionSecurity {
230 fn from(value: u16) -> Self {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200231 match (value >> Self::SHIFT) & Self::MASK {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100232 Self::SECURE => Self::Secure,
233 Self::NON_SECURE => Self::NonSecure,
234 _ => panic!(), // The match is exhaustive for a 1-bit value
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200235 }
236 }
237}
238
239impl MemRegionSecurity {
240 const SHIFT: usize = 6;
241 const MASK: u16 = 0b1;
242 const SECURE: u16 = 0b0;
243 const NON_SECURE: u16 = 0b1;
244}
245
Balint Dobszaya5846852025-02-26 15:38:53 +0100246/// Memory region attributes descriptor.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200247#[derive(Debug, Default, Clone, Copy)]
248pub struct MemRegionAttributes {
249 pub security: MemRegionSecurity,
250 pub mem_type: MemType,
251}
252
253impl TryFrom<u16> for MemRegionAttributes {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100254 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200255
256 fn try_from(value: u16) -> Result<Self, Self::Error> {
257 // bits[15:7]: Reserved (MBZ)
Balint Dobszayc758dd42025-01-15 18:10:40 +0100258 if value >> 7 == 0 {
259 Ok(Self {
260 security: value.into(),
261 mem_type: value.try_into()?,
262 })
263 } else {
264 Err(Error::InvalidMemAttributes(value))
265 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200266 }
267}
268
269impl From<MemRegionAttributes> for u16 {
270 fn from(value: MemRegionAttributes) -> Self {
271 value.security as u16 | u16::from(value.mem_type)
272 }
273}
274
Balint Dobszaya5846852025-02-26 15:38:53 +0100275/// Instruction access permissions of a memory region.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200276#[derive(Debug, Default, Clone, Copy)]
277#[repr(u8)]
278pub enum InstuctionAccessPerm {
279 #[default]
280 NotSpecified = Self::NOT_SPECIFIED << Self::SHIFT,
281 NotExecutable = Self::NOT_EXECUTABLE << Self::SHIFT,
282 Executable = Self::EXECUTABLE << Self::SHIFT,
283}
284
285impl TryFrom<u8> for InstuctionAccessPerm {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100286 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200287
288 fn try_from(value: u8) -> Result<Self, Self::Error> {
289 match (value >> Self::SHIFT) & Self::MASK {
290 Self::NOT_SPECIFIED => Ok(Self::NotSpecified),
291 Self::NOT_EXECUTABLE => Ok(Self::NotExecutable),
292 Self::EXECUTABLE => Ok(Self::Executable),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100293 _ => Err(Error::InvalidInstrAccessPerm(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200294 }
295 }
296}
297
298impl InstuctionAccessPerm {
299 const SHIFT: usize = 2;
300 const MASK: u8 = 0b11;
301 const NOT_SPECIFIED: u8 = 0b00;
302 const NOT_EXECUTABLE: u8 = 0b01;
303 const EXECUTABLE: u8 = 0b10;
304}
305
Balint Dobszaya5846852025-02-26 15:38:53 +0100306/// Data access permissions of a memory region.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200307#[derive(Debug, Default, Clone, Copy)]
308#[repr(u8)]
309pub enum DataAccessPerm {
310 #[default]
311 NotSpecified = Self::NOT_SPECIFIED << Self::SHIFT,
312 ReadOnly = Self::READ_ONLY << Self::SHIFT,
313 ReadWrite = Self::READ_WRITE << Self::SHIFT,
314}
315
316impl TryFrom<u8> for DataAccessPerm {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100317 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200318
319 fn try_from(value: u8) -> Result<Self, Self::Error> {
320 match (value >> Self::SHIFT) & Self::MASK {
321 Self::NOT_SPECIFIED => Ok(Self::NotSpecified),
322 Self::READ_ONLY => Ok(Self::ReadOnly),
323 Self::READ_WRITE => Ok(Self::ReadWrite),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100324 _ => Err(Error::InvalidDataAccessPerm(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200325 }
326 }
327}
328
329impl DataAccessPerm {
330 const SHIFT: usize = 0;
331 const MASK: u8 = 0b11;
332 const NOT_SPECIFIED: u8 = 0b00;
333 const READ_ONLY: u8 = 0b01;
334 const READ_WRITE: u8 = 0b10;
335}
336
Balint Dobszaya5846852025-02-26 15:38:53 +0100337/// Endpoint memory access permissions descriptor.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200338#[derive(Debug, Default, Clone, Copy)]
Balint Dobszayc758dd42025-01-15 18:10:40 +0100339pub struct MemAccessPerm {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200340 pub endpoint_id: u16,
341 pub instr_access: InstuctionAccessPerm,
342 pub data_access: DataAccessPerm,
343 pub flags: u8, // TODO
344}
345
Balint Dobszaya5846852025-02-26 15:38:53 +0100346/// Iterator of endpoint memory access permission descriptors.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100347pub struct MemAccessPermIterator<'a> {
348 buf: &'a [u8],
349 offset: usize,
350 count: usize,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200351}
352
Balint Dobszayc758dd42025-01-15 18:10:40 +0100353impl<'a> MemAccessPermIterator<'a> {
Balint Dobszaya5846852025-02-26 15:38:53 +0100354 /// Create an iterator of endpoint memory access permission descriptors from a buffer.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100355 fn new(buf: &'a [u8], count: usize, offset: usize) -> Result<Self, Error> {
356 let Some(total_size) = count
357 .checked_mul(size_of::<endpoint_memory_access_descriptor>())
358 .and_then(|x| x.checked_add(offset))
359 else {
360 return Err(Error::InvalidBufferSize);
361 };
362
363 if buf.len() < total_size {
364 return Err(Error::InvalidBufferSize);
365 }
366
367 Ok(Self { buf, offset, count })
368 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200369}
370
Balint Dobszayc758dd42025-01-15 18:10:40 +0100371impl Iterator for MemAccessPermIterator<'_> {
372 type Item = Result<MemAccessPerm, Error>;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200373
Balint Dobszayc758dd42025-01-15 18:10:40 +0100374 fn next(&mut self) -> Option<Self::Item> {
375 if self.count > 0 {
376 let offset = self.offset;
377 self.offset += size_of::<endpoint_memory_access_descriptor>();
378 self.count -= 1;
379
380 let Ok(desc_raw) = endpoint_memory_access_descriptor::ref_from_bytes(
381 &self.buf[offset..offset + size_of::<endpoint_memory_access_descriptor>()],
382 ) else {
383 return Some(Err(Error::MalformedDescriptor));
384 };
385
386 let instr_access = match desc_raw
387 .access_perm_desc
388 .memory_access_permissions
389 .try_into()
390 {
391 Ok(v) => v,
392 Err(e) => return Some(Err(e)),
393 };
394
395 let data_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 desc = MemAccessPerm {
405 endpoint_id: desc_raw.access_perm_desc.endpoint_id,
406 instr_access,
407 data_access,
408 flags: desc_raw.access_perm_desc.flags,
409 };
410
411 return Some(Ok(desc));
412 }
413
414 None
415 }
416}
417
Balint Dobszaya5846852025-02-26 15:38:53 +0100418/// Constituent memory region descriptor.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100419#[derive(Debug, Default, Clone, Copy)]
420pub struct ConstituentMemRegion {
421 pub address: u64,
422 pub page_cnt: u32,
423}
424
Balint Dobszaya5846852025-02-26 15:38:53 +0100425/// Iterator of constituent memory region descriptors.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100426pub struct ConstituentMemRegionIterator<'a> {
427 buf: &'a [u8],
428 offset: usize,
429 count: usize,
430}
431
432impl<'a> ConstituentMemRegionIterator<'a> {
Balint Dobszaya5846852025-02-26 15:38:53 +0100433 /// Create an iterator of constituent memory region descriptors from a buffer.
Imre Kis1a4abbe2025-04-11 17:08:51 +0200434 fn new(
435 buf: &'a [u8],
436 region_count: usize,
437 total_page_count: u32,
438 offset: usize,
439 ) -> Result<Self, Error> {
440 let descriptor_size = size_of::<constituent_memory_region_descriptor>();
441
442 let Some(total_size) = region_count
443 .checked_mul(descriptor_size)
Balint Dobszayc758dd42025-01-15 18:10:40 +0100444 .and_then(|x| x.checked_add(offset))
445 else {
446 return Err(Error::InvalidBufferSize);
447 };
448
449 if buf.len() < total_size {
450 return Err(Error::InvalidBufferSize);
451 }
452
Imre Kis1a4abbe2025-04-11 17:08:51 +0200453 // Check if the sum of of page counts in the constituent_memory_region_descriptors matches
454 // the total_page_count field of the composite_memory_region_descriptor.
455 let mut page_count_sum: u32 = 0;
456 for desc_offset in
457 (offset..offset + descriptor_size * region_count).step_by(descriptor_size)
458 {
459 let Ok(desc_raw) = constituent_memory_region_descriptor::ref_from_bytes(
460 &buf[desc_offset..desc_offset + descriptor_size],
461 ) else {
462 return Err(Error::MalformedDescriptor);
463 };
464
465 page_count_sum = page_count_sum
466 .checked_add(desc_raw.page_count)
467 .ok_or(Error::MalformedDescriptor)?;
468 }
469
470 if page_count_sum != total_page_count {
471 return Err(Error::MalformedDescriptor);
472 }
473
474 Ok(Self {
475 buf,
476 offset,
477 count: region_count,
478 })
Balint Dobszayc758dd42025-01-15 18:10:40 +0100479 }
480}
481
482impl Iterator for ConstituentMemRegionIterator<'_> {
483 type Item = Result<ConstituentMemRegion, Error>;
484
485 fn next(&mut self) -> Option<Self::Item> {
486 if self.count > 0 {
487 let offset = self.offset;
488 self.offset += size_of::<constituent_memory_region_descriptor>();
489 self.count -= 1;
490
491 let Ok(desc_raw) = constituent_memory_region_descriptor::ref_from_bytes(
492 &self.buf[offset..offset + size_of::<constituent_memory_region_descriptor>()],
493 ) else {
494 return Some(Err(Error::MalformedDescriptor));
495 };
496
497 let desc = ConstituentMemRegion {
498 address: desc_raw.address,
499 page_cnt: desc_raw.page_count,
500 };
501
502 return Some(Ok(desc));
503 }
504
505 None
506 }
507}
508
Balint Dobszaya5846852025-02-26 15:38:53 +0100509/// Flags of a memory management transaction.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100510#[derive(Debug, Default, Clone, Copy)]
511pub struct MemTransactionFlags(pub u32);
512
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200513impl MemTransactionFlags {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100514 pub const MEM_SHARE_MASK: u32 = 0b11;
515 pub const MEM_RETRIEVE_REQ_MASK: u32 = 0b11_1111_1111;
516 pub const MEM_RETRIEVE_RESP_MASK: u32 = 0b1_1111;
517 pub const ZERO_MEMORY: u32 = 0b1;
518 pub const TIME_SLICING: u32 = 0b1 << 1;
519 pub const ZERO_AFTER_RELINQ: u32 = 0b1 << 2;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200520 pub const TYPE_SHARE: u32 = 0b01 << 3;
Balint Dobszayc758dd42025-01-15 18:10:40 +0100521 pub const TYPE_LEND: u32 = 0b10 << 3;
522 pub const TYPE_DONATE: u32 = 0b11 << 3;
523 pub const ALIGN_HINT_MASK: u32 = 0b1111 << 5;
524 pub const HINT_VALID: u32 = 0b1 << 9;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200525}
526
Balint Dobszaya5846852025-02-26 15:38:53 +0100527/// Memory transaction decriptor. Used by an Owner/Lender and a Borrower/Receiver in a transaction
528/// to donate, lend or share a memory region.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200529#[derive(Debug, Default)]
530pub struct MemTransactionDesc {
531 pub sender_id: u16,
532 pub mem_region_attr: MemRegionAttributes,
533 pub flags: MemTransactionFlags,
534 pub handle: Handle,
535 pub tag: u64, // TODO
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200536}
537
538impl MemTransactionDesc {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100539 // Offset from the base of the memory transaction descriptor to the first element in the
540 // endpoint memory access descriptor array. Must be 16 byte aligned, but otherwise we're free to
541 // choose any value here. Let's just pack it right after the memory transaction descriptor.
542 const ENDPOINT_MEM_ACCESS_DESC_OFFSET: usize =
543 size_of::<memory_transaction_descriptor>().next_multiple_of(16);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200544
Balint Dobszayc758dd42025-01-15 18:10:40 +0100545 // The array of constituent memory region descriptors starts right after the composite memory
546 // region descriptor
547 const CONSTITUENT_ARRAY_OFFSET: usize = size_of::<composite_memory_region_descriptor>();
548
Balint Dobszaya5846852025-02-26 15:38:53 +0100549 /// Serialize a memory transaction descriptor and the related constituent memory region
550 /// descriptors and endpoint memory access permission descriptors into a buffer.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100551 pub fn pack(
552 &self,
553 constituents: &[ConstituentMemRegion],
554 access_descriptors: &[MemAccessPerm],
555 buf: &mut [u8],
556 ) -> usize {
557 let mem_access_desc_size = size_of::<endpoint_memory_access_descriptor>();
558 let mem_access_desc_cnt = access_descriptors.len();
559
560 let transaction_desc_raw = memory_transaction_descriptor {
561 sender_endpoint_id: self.sender_id,
562 memory_region_attributes: self.mem_region_attr.into(),
563 flags: self.flags.0,
564 handle: self.handle.0,
565 tag: self.tag,
566 endpoint_mem_access_desc_size: mem_access_desc_size as u32,
567 endpoint_mem_access_desc_count: mem_access_desc_cnt as u32,
568 endpoint_mem_access_desc_array_offset: Self::ENDPOINT_MEM_ACCESS_DESC_OFFSET as u32,
569 reserved1: 0,
570 reserved2: 0,
571 };
572
573 transaction_desc_raw.write_to_prefix(buf).unwrap();
574
575 // Offset from the base of the memory transaction descriptor to the composite memory region
576 // descriptor to which the endpoint access permissions apply.
577 let composite_offset = mem_access_desc_cnt
578 .checked_mul(mem_access_desc_size)
579 .unwrap()
580 .checked_add(Self::ENDPOINT_MEM_ACCESS_DESC_OFFSET)
581 .unwrap()
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200582 .next_multiple_of(8);
583
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200584 let mut offset = Self::ENDPOINT_MEM_ACCESS_DESC_OFFSET;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200585
Balint Dobszayc758dd42025-01-15 18:10:40 +0100586 for desc in access_descriptors {
587 let desc_raw = endpoint_memory_access_descriptor {
588 access_perm_desc: memory_access_permission_descriptor {
589 endpoint_id: desc.endpoint_id,
590 memory_access_permissions: desc.data_access as u8 | desc.instr_access as u8,
591 flags: desc.flags,
592 },
593 composite_offset: composite_offset as u32,
594 reserved: 0,
595 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200596
Balint Dobszayc758dd42025-01-15 18:10:40 +0100597 desc_raw.write_to_prefix(&mut buf[offset..]).unwrap();
598 offset += mem_access_desc_size;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200599 }
600
Imre Kis1a4abbe2025-04-11 17:08:51 +0200601 let mut total_page_count: u32 = 0;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200602
Balint Dobszayc758dd42025-01-15 18:10:40 +0100603 offset = composite_offset + Self::CONSTITUENT_ARRAY_OFFSET;
604 for constituent in constituents {
605 let constituent_raw = constituent_memory_region_descriptor {
606 address: constituent.address,
607 page_count: constituent.page_cnt,
608 reserved: 0,
609 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200610
Balint Dobszayc758dd42025-01-15 18:10:40 +0100611 constituent_raw.write_to_prefix(&mut buf[offset..]).unwrap();
612 offset += size_of::<constituent_memory_region_descriptor>();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200613
Imre Kis1a4abbe2025-04-11 17:08:51 +0200614 total_page_count = total_page_count
615 .checked_add(constituent_raw.page_count)
616 .expect("total_page_count overflow");
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200617 }
618
Balint Dobszayc758dd42025-01-15 18:10:40 +0100619 let composite_desc_raw = composite_memory_region_descriptor {
620 total_page_count,
621 address_range_count: constituents.len() as u32,
622 reserved: 0,
623 };
624
625 composite_desc_raw
626 .write_to_prefix(&mut buf[composite_offset..])
627 .unwrap();
628
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200629 offset
630 }
631
Balint Dobszaya5846852025-02-26 15:38:53 +0100632 /// Deserialize a memory transaction descriptor from a buffer and return an interator of the
633 /// related endpoint memory access permission descriptors and constituent memory region
634 /// descriptors, if any.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100635 pub fn unpack(
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200636 buf: &[u8],
Balint Dobszayc758dd42025-01-15 18:10:40 +0100637 ) -> Result<
638 (
639 MemTransactionDesc,
640 MemAccessPermIterator,
641 Option<ConstituentMemRegionIterator>,
642 ),
643 Error,
644 > {
645 let Some(transaction_desc_bytes) = buf.get(0..size_of::<memory_transaction_descriptor>())
646 else {
647 return Err(Error::InvalidBufferSize);
648 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200649
Balint Dobszayc758dd42025-01-15 18:10:40 +0100650 let Ok(transaction_desc_raw) =
651 memory_transaction_descriptor::ref_from_bytes(transaction_desc_bytes)
652 else {
653 return Err(Error::MalformedDescriptor);
654 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200655
Balint Dobszayc758dd42025-01-15 18:10:40 +0100656 if size_of::<endpoint_memory_access_descriptor>()
657 != transaction_desc_raw.endpoint_mem_access_desc_size as usize
658 {
659 return Err(Error::MalformedDescriptor);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200660 }
661
Balint Dobszayc758dd42025-01-15 18:10:40 +0100662 if transaction_desc_raw.endpoint_mem_access_desc_count == 0 {
663 return Err(Error::MalformedDescriptor);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200664 }
665
Balint Dobszayc758dd42025-01-15 18:10:40 +0100666 let Some(total_desc_size) = transaction_desc_raw
667 .endpoint_mem_access_desc_size
668 .checked_mul(transaction_desc_raw.endpoint_mem_access_desc_count)
669 .and_then(|x| {
670 x.checked_add(transaction_desc_raw.endpoint_mem_access_desc_array_offset)
671 })
672 else {
673 return Err(Error::InvalidBufferSize);
674 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200675
Balint Dobszayc758dd42025-01-15 18:10:40 +0100676 if buf.len() < total_desc_size as usize {
677 return Err(Error::InvalidBufferSize);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200678 }
679
Balint Dobszayc758dd42025-01-15 18:10:40 +0100680 let transaction_desc = MemTransactionDesc {
681 sender_id: transaction_desc_raw.sender_endpoint_id,
682 mem_region_attr: transaction_desc_raw.memory_region_attributes.try_into()?,
683 flags: MemTransactionFlags(transaction_desc_raw.flags),
684 handle: Handle(transaction_desc_raw.handle),
685 tag: transaction_desc_raw.tag,
686 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200687
Balint Dobszayc758dd42025-01-15 18:10:40 +0100688 let mut offset = transaction_desc_raw.endpoint_mem_access_desc_array_offset as usize;
689
690 let access_desc_iter = MemAccessPermIterator::new(
691 buf,
692 transaction_desc_raw.endpoint_mem_access_desc_count as usize,
693 offset,
694 )?;
695
696 // We have to check the first endpoint memory access descriptor to get the composite offset
697 let Ok(desc_raw) = endpoint_memory_access_descriptor::ref_from_bytes(
698 &buf[offset..offset + size_of::<endpoint_memory_access_descriptor>()],
699 ) else {
700 return Err(Error::MalformedDescriptor);
701 };
702
703 offset = desc_raw.composite_offset as usize;
704
705 // An offset value of 0 indicates that the endpoint access permissions apply to a memory
706 // region description identified by the Handle (i.e. there is no composite descriptor)
707 if offset == 0 {
708 return Ok((transaction_desc, access_desc_iter, None));
709 }
710
711 let Some(composite_desc_bytes) =
712 buf.get(offset..offset + size_of::<composite_memory_region_descriptor>())
713 else {
714 return Err(Error::InvalidBufferSize);
715 };
716
717 let Ok(composite_desc_raw) =
718 composite_memory_region_descriptor::ref_from_bytes(composite_desc_bytes)
719 else {
720 return Err(Error::MalformedDescriptor);
721 };
722
723 let constituent_iter = ConstituentMemRegionIterator::new(
724 buf,
725 composite_desc_raw.address_range_count as usize,
Imre Kis1a4abbe2025-04-11 17:08:51 +0200726 composite_desc_raw.total_page_count,
Balint Dobszayc758dd42025-01-15 18:10:40 +0100727 offset + Self::CONSTITUENT_ARRAY_OFFSET,
728 )?;
729
Balint Dobszayc758dd42025-01-15 18:10:40 +0100730 Ok((transaction_desc, access_desc_iter, Some(constituent_iter)))
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200731 }
732}
733
Balint Dobszaya5846852025-02-26 15:38:53 +0100734/// Descriptor to relinquish a memory region. Currently only supports specifying a single endpoint.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200735#[derive(Debug, Default)]
736pub struct MemRelinquishDesc {
737 pub handle: Handle,
738 pub flags: u32,
Balint Dobszayc758dd42025-01-15 18:10:40 +0100739 pub endpoint: u16,
740}
741
742impl TryFrom<&[u8]> for MemRelinquishDesc {
743 type Error = Error;
744
745 fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
746 let Some(desc_bytes) = buf.get(0..size_of::<memory_relinquish_descriptor>()) else {
747 return Err(Error::InvalidBufferSize);
748 };
749
750 let Ok(desc_raw) = memory_relinquish_descriptor::ref_from_bytes(desc_bytes) else {
751 return Err(Error::MalformedDescriptor);
752 };
753
754 let Some(total_desc_size) = (desc_raw.endpoint_count as usize)
755 .checked_mul(size_of::<u16>())
756 .and_then(|x| x.checked_add(Self::ENDPOINT_ARRAY_OFFSET))
757 else {
758 return Err(Error::InvalidBufferSize);
759 };
760
761 if buf.len() < total_desc_size {
762 return Err(Error::InvalidBufferSize);
763 }
764
765 // If the caller is a PE endpoint Borrower, then Endpoint count must equal 1. Currently only
766 // this case is supported. The array of endpoint IDs contains only a single element.
767 if desc_raw.endpoint_count != 1 {
768 return Err(Error::UnsupportedEndpointCount(desc_raw.endpoint_count));
769 }
770
771 let endpoint = u16::from_le_bytes([
772 buf[Self::ENDPOINT_ARRAY_OFFSET],
773 buf[Self::ENDPOINT_ARRAY_OFFSET + 1],
774 ]);
775
776 Ok(Self {
777 handle: Handle(desc_raw.handle),
778 flags: desc_raw.flags, // TODO: validate
779 endpoint,
780 })
781 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200782}
783
784impl MemRelinquishDesc {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100785 const ENDPOINT_ARRAY_OFFSET: usize = size_of::<memory_relinquish_descriptor>();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200786}
787
788#[cfg(test)]
789mod tests {
790 use super::*;
791
792 #[allow(dead_code)]
793 const MEM_SHARE_FROM_SP1: &[u8] = &[
794 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
795 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
796 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
797 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
798 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
799 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
800 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
801 ];
802
803 #[allow(dead_code)]
804 const MEM_SHARE_FROM_SP2: &[u8] = &[
805 0x06, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
806 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
807 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
808 0x00, 0x00, 0x00, 0x05, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
809 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x07, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
811 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
812 ];
813
814 #[allow(dead_code)]
815 const MEM_RETRIEVE_REQ_FROM_SP1: &[u8] = &[
816 0x05, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
817 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
818 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
819 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
820 0x00, 0x00, 0x00, 0x00,
821 ];
822
823 #[allow(dead_code)]
824 const MEM_RETRIEVE_REQ_FROM_SP2: &[u8] = &[
825 0x06, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
826 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
827 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
828 0x00, 0x00, 0x00, 0x05, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
829 0x00, 0x00, 0x00, 0x00,
830 ];
831
832 #[allow(dead_code)]
833 const MEM_SHARE_FROM_NWD: &[u8] = &[
834 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
835 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
836 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
837 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
838 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
839 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x22, 0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00,
840 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
841 ];
842
843 #[test]
844 fn mem_share() {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100845 let (transaction_desc, access_desc, constituents) =
846 MemTransactionDesc::unpack(MEM_SHARE_FROM_SP1).unwrap();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200847
848 println!("transaction desc: {:#x?}", transaction_desc);
Balint Dobszayc758dd42025-01-15 18:10:40 +0100849 access_desc.for_each(|d| println!("endpont desc: {d:#x?}"));
850 constituents
851 .unwrap()
852 .for_each(|c| println!("constituent desc: {c:#x?}"));
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200853 }
854}