blob: 925fe44e1a5af90f06bd13b83e32804747cfaa0c [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.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100434 fn new(buf: &'a [u8], count: usize, offset: usize) -> Result<Self, Error> {
435 let Some(total_size) = count
436 .checked_mul(size_of::<constituent_memory_region_descriptor>())
437 .and_then(|x| x.checked_add(offset))
438 else {
439 return Err(Error::InvalidBufferSize);
440 };
441
442 if buf.len() < total_size {
443 return Err(Error::InvalidBufferSize);
444 }
445
446 Ok(Self { buf, offset, count })
447 }
448}
449
450impl Iterator for ConstituentMemRegionIterator<'_> {
451 type Item = Result<ConstituentMemRegion, Error>;
452
453 fn next(&mut self) -> Option<Self::Item> {
454 if self.count > 0 {
455 let offset = self.offset;
456 self.offset += size_of::<constituent_memory_region_descriptor>();
457 self.count -= 1;
458
459 let Ok(desc_raw) = constituent_memory_region_descriptor::ref_from_bytes(
460 &self.buf[offset..offset + size_of::<constituent_memory_region_descriptor>()],
461 ) else {
462 return Some(Err(Error::MalformedDescriptor));
463 };
464
465 let desc = ConstituentMemRegion {
466 address: desc_raw.address,
467 page_cnt: desc_raw.page_count,
468 };
469
470 return Some(Ok(desc));
471 }
472
473 None
474 }
475}
476
Balint Dobszaya5846852025-02-26 15:38:53 +0100477/// Flags of a memory management transaction.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100478#[derive(Debug, Default, Clone, Copy)]
479pub struct MemTransactionFlags(pub u32);
480
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200481impl MemTransactionFlags {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100482 pub const MEM_SHARE_MASK: u32 = 0b11;
483 pub const MEM_RETRIEVE_REQ_MASK: u32 = 0b11_1111_1111;
484 pub const MEM_RETRIEVE_RESP_MASK: u32 = 0b1_1111;
485 pub const ZERO_MEMORY: u32 = 0b1;
486 pub const TIME_SLICING: u32 = 0b1 << 1;
487 pub const ZERO_AFTER_RELINQ: u32 = 0b1 << 2;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200488 pub const TYPE_SHARE: u32 = 0b01 << 3;
Balint Dobszayc758dd42025-01-15 18:10:40 +0100489 pub const TYPE_LEND: u32 = 0b10 << 3;
490 pub const TYPE_DONATE: u32 = 0b11 << 3;
491 pub const ALIGN_HINT_MASK: u32 = 0b1111 << 5;
492 pub const HINT_VALID: u32 = 0b1 << 9;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200493}
494
Balint Dobszaya5846852025-02-26 15:38:53 +0100495/// Memory transaction decriptor. Used by an Owner/Lender and a Borrower/Receiver in a transaction
496/// to donate, lend or share a memory region.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200497#[derive(Debug, Default)]
498pub struct MemTransactionDesc {
499 pub sender_id: u16,
500 pub mem_region_attr: MemRegionAttributes,
501 pub flags: MemTransactionFlags,
502 pub handle: Handle,
503 pub tag: u64, // TODO
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200504}
505
506impl MemTransactionDesc {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100507 // Offset from the base of the memory transaction descriptor to the first element in the
508 // endpoint memory access descriptor array. Must be 16 byte aligned, but otherwise we're free to
509 // choose any value here. Let's just pack it right after the memory transaction descriptor.
510 const ENDPOINT_MEM_ACCESS_DESC_OFFSET: usize =
511 size_of::<memory_transaction_descriptor>().next_multiple_of(16);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200512
Balint Dobszayc758dd42025-01-15 18:10:40 +0100513 // The array of constituent memory region descriptors starts right after the composite memory
514 // region descriptor
515 const CONSTITUENT_ARRAY_OFFSET: usize = size_of::<composite_memory_region_descriptor>();
516
Balint Dobszaya5846852025-02-26 15:38:53 +0100517 /// Serialize a memory transaction descriptor and the related constituent memory region
518 /// descriptors and endpoint memory access permission descriptors into a buffer.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100519 pub fn pack(
520 &self,
521 constituents: &[ConstituentMemRegion],
522 access_descriptors: &[MemAccessPerm],
523 buf: &mut [u8],
524 ) -> usize {
525 let mem_access_desc_size = size_of::<endpoint_memory_access_descriptor>();
526 let mem_access_desc_cnt = access_descriptors.len();
527
528 let transaction_desc_raw = memory_transaction_descriptor {
529 sender_endpoint_id: self.sender_id,
530 memory_region_attributes: self.mem_region_attr.into(),
531 flags: self.flags.0,
532 handle: self.handle.0,
533 tag: self.tag,
534 endpoint_mem_access_desc_size: mem_access_desc_size as u32,
535 endpoint_mem_access_desc_count: mem_access_desc_cnt as u32,
536 endpoint_mem_access_desc_array_offset: Self::ENDPOINT_MEM_ACCESS_DESC_OFFSET as u32,
537 reserved1: 0,
538 reserved2: 0,
539 };
540
541 transaction_desc_raw.write_to_prefix(buf).unwrap();
542
543 // Offset from the base of the memory transaction descriptor to the composite memory region
544 // descriptor to which the endpoint access permissions apply.
545 let composite_offset = mem_access_desc_cnt
546 .checked_mul(mem_access_desc_size)
547 .unwrap()
548 .checked_add(Self::ENDPOINT_MEM_ACCESS_DESC_OFFSET)
549 .unwrap()
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200550 .next_multiple_of(8);
551
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200552 let mut offset = Self::ENDPOINT_MEM_ACCESS_DESC_OFFSET;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200553
Balint Dobszayc758dd42025-01-15 18:10:40 +0100554 for desc in access_descriptors {
555 let desc_raw = endpoint_memory_access_descriptor {
556 access_perm_desc: memory_access_permission_descriptor {
557 endpoint_id: desc.endpoint_id,
558 memory_access_permissions: desc.data_access as u8 | desc.instr_access as u8,
559 flags: desc.flags,
560 },
561 composite_offset: composite_offset as u32,
562 reserved: 0,
563 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200564
Balint Dobszayc758dd42025-01-15 18:10:40 +0100565 desc_raw.write_to_prefix(&mut buf[offset..]).unwrap();
566 offset += mem_access_desc_size;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200567 }
568
Balint Dobszayc758dd42025-01-15 18:10:40 +0100569 let mut total_page_count = 0;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200570
Balint Dobszayc758dd42025-01-15 18:10:40 +0100571 offset = composite_offset + Self::CONSTITUENT_ARRAY_OFFSET;
572 for constituent in constituents {
573 let constituent_raw = constituent_memory_region_descriptor {
574 address: constituent.address,
575 page_count: constituent.page_cnt,
576 reserved: 0,
577 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200578
Balint Dobszayc758dd42025-01-15 18:10:40 +0100579 constituent_raw.write_to_prefix(&mut buf[offset..]).unwrap();
580 offset += size_of::<constituent_memory_region_descriptor>();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200581
Balint Dobszayc758dd42025-01-15 18:10:40 +0100582 total_page_count += constituent_raw.page_count;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200583 }
584
Balint Dobszayc758dd42025-01-15 18:10:40 +0100585 let composite_desc_raw = composite_memory_region_descriptor {
586 total_page_count,
587 address_range_count: constituents.len() as u32,
588 reserved: 0,
589 };
590
591 composite_desc_raw
592 .write_to_prefix(&mut buf[composite_offset..])
593 .unwrap();
594
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200595 offset
596 }
597
Balint Dobszaya5846852025-02-26 15:38:53 +0100598 /// Deserialize a memory transaction descriptor from a buffer and return an interator of the
599 /// related endpoint memory access permission descriptors and constituent memory region
600 /// descriptors, if any.
Balint Dobszayc758dd42025-01-15 18:10:40 +0100601 pub fn unpack(
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200602 buf: &[u8],
Balint Dobszayc758dd42025-01-15 18:10:40 +0100603 ) -> Result<
604 (
605 MemTransactionDesc,
606 MemAccessPermIterator,
607 Option<ConstituentMemRegionIterator>,
608 ),
609 Error,
610 > {
611 let Some(transaction_desc_bytes) = buf.get(0..size_of::<memory_transaction_descriptor>())
612 else {
613 return Err(Error::InvalidBufferSize);
614 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200615
Balint Dobszayc758dd42025-01-15 18:10:40 +0100616 let Ok(transaction_desc_raw) =
617 memory_transaction_descriptor::ref_from_bytes(transaction_desc_bytes)
618 else {
619 return Err(Error::MalformedDescriptor);
620 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200621
Balint Dobszayc758dd42025-01-15 18:10:40 +0100622 if size_of::<endpoint_memory_access_descriptor>()
623 != transaction_desc_raw.endpoint_mem_access_desc_size as usize
624 {
625 return Err(Error::MalformedDescriptor);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200626 }
627
Balint Dobszayc758dd42025-01-15 18:10:40 +0100628 if transaction_desc_raw.endpoint_mem_access_desc_count == 0 {
629 return Err(Error::MalformedDescriptor);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200630 }
631
Balint Dobszayc758dd42025-01-15 18:10:40 +0100632 let Some(total_desc_size) = transaction_desc_raw
633 .endpoint_mem_access_desc_size
634 .checked_mul(transaction_desc_raw.endpoint_mem_access_desc_count)
635 .and_then(|x| {
636 x.checked_add(transaction_desc_raw.endpoint_mem_access_desc_array_offset)
637 })
638 else {
639 return Err(Error::InvalidBufferSize);
640 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200641
Balint Dobszayc758dd42025-01-15 18:10:40 +0100642 if buf.len() < total_desc_size as usize {
643 return Err(Error::InvalidBufferSize);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200644 }
645
Balint Dobszayc758dd42025-01-15 18:10:40 +0100646 let transaction_desc = MemTransactionDesc {
647 sender_id: transaction_desc_raw.sender_endpoint_id,
648 mem_region_attr: transaction_desc_raw.memory_region_attributes.try_into()?,
649 flags: MemTransactionFlags(transaction_desc_raw.flags),
650 handle: Handle(transaction_desc_raw.handle),
651 tag: transaction_desc_raw.tag,
652 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200653
Balint Dobszayc758dd42025-01-15 18:10:40 +0100654 let mut offset = transaction_desc_raw.endpoint_mem_access_desc_array_offset as usize;
655
656 let access_desc_iter = MemAccessPermIterator::new(
657 buf,
658 transaction_desc_raw.endpoint_mem_access_desc_count as usize,
659 offset,
660 )?;
661
662 // We have to check the first endpoint memory access descriptor to get the composite offset
663 let Ok(desc_raw) = endpoint_memory_access_descriptor::ref_from_bytes(
664 &buf[offset..offset + size_of::<endpoint_memory_access_descriptor>()],
665 ) else {
666 return Err(Error::MalformedDescriptor);
667 };
668
669 offset = desc_raw.composite_offset as usize;
670
671 // An offset value of 0 indicates that the endpoint access permissions apply to a memory
672 // region description identified by the Handle (i.e. there is no composite descriptor)
673 if offset == 0 {
674 return Ok((transaction_desc, access_desc_iter, None));
675 }
676
677 let Some(composite_desc_bytes) =
678 buf.get(offset..offset + size_of::<composite_memory_region_descriptor>())
679 else {
680 return Err(Error::InvalidBufferSize);
681 };
682
683 let Ok(composite_desc_raw) =
684 composite_memory_region_descriptor::ref_from_bytes(composite_desc_bytes)
685 else {
686 return Err(Error::MalformedDescriptor);
687 };
688
689 let constituent_iter = ConstituentMemRegionIterator::new(
690 buf,
691 composite_desc_raw.address_range_count as usize,
692 offset + Self::CONSTITUENT_ARRAY_OFFSET,
693 )?;
694
695 // TODO: add a sainty check to compare the composite descriptor's total page count and the
696 // sum of page counts from constituent memory regions (not sure if it's really valuable)
697
698 Ok((transaction_desc, access_desc_iter, Some(constituent_iter)))
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200699 }
700}
701
Balint Dobszaya5846852025-02-26 15:38:53 +0100702/// Descriptor to relinquish a memory region. Currently only supports specifying a single endpoint.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200703#[derive(Debug, Default)]
704pub struct MemRelinquishDesc {
705 pub handle: Handle,
706 pub flags: u32,
Balint Dobszayc758dd42025-01-15 18:10:40 +0100707 pub endpoint: u16,
708}
709
710impl TryFrom<&[u8]> for MemRelinquishDesc {
711 type Error = Error;
712
713 fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
714 let Some(desc_bytes) = buf.get(0..size_of::<memory_relinquish_descriptor>()) else {
715 return Err(Error::InvalidBufferSize);
716 };
717
718 let Ok(desc_raw) = memory_relinquish_descriptor::ref_from_bytes(desc_bytes) else {
719 return Err(Error::MalformedDescriptor);
720 };
721
722 let Some(total_desc_size) = (desc_raw.endpoint_count as usize)
723 .checked_mul(size_of::<u16>())
724 .and_then(|x| x.checked_add(Self::ENDPOINT_ARRAY_OFFSET))
725 else {
726 return Err(Error::InvalidBufferSize);
727 };
728
729 if buf.len() < total_desc_size {
730 return Err(Error::InvalidBufferSize);
731 }
732
733 // If the caller is a PE endpoint Borrower, then Endpoint count must equal 1. Currently only
734 // this case is supported. The array of endpoint IDs contains only a single element.
735 if desc_raw.endpoint_count != 1 {
736 return Err(Error::UnsupportedEndpointCount(desc_raw.endpoint_count));
737 }
738
739 let endpoint = u16::from_le_bytes([
740 buf[Self::ENDPOINT_ARRAY_OFFSET],
741 buf[Self::ENDPOINT_ARRAY_OFFSET + 1],
742 ]);
743
744 Ok(Self {
745 handle: Handle(desc_raw.handle),
746 flags: desc_raw.flags, // TODO: validate
747 endpoint,
748 })
749 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200750}
751
752impl MemRelinquishDesc {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100753 const ENDPOINT_ARRAY_OFFSET: usize = size_of::<memory_relinquish_descriptor>();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200754}
755
756#[cfg(test)]
757mod tests {
758 use super::*;
759
760 #[allow(dead_code)]
761 const MEM_SHARE_FROM_SP1: &[u8] = &[
762 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
764 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
765 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
766 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
767 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
768 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
769 ];
770
771 #[allow(dead_code)]
772 const MEM_SHARE_FROM_SP2: &[u8] = &[
773 0x06, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
774 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
775 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
776 0x00, 0x00, 0x00, 0x05, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
777 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
778 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x07, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
779 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
780 ];
781
782 #[allow(dead_code)]
783 const MEM_RETRIEVE_REQ_FROM_SP1: &[u8] = &[
784 0x05, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
785 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
786 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
787 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
788 0x00, 0x00, 0x00, 0x00,
789 ];
790
791 #[allow(dead_code)]
792 const MEM_RETRIEVE_REQ_FROM_SP2: &[u8] = &[
793 0x06, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
794 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
795 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
796 0x00, 0x00, 0x00, 0x05, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
797 0x00, 0x00, 0x00, 0x00,
798 ];
799
800 #[allow(dead_code)]
801 const MEM_SHARE_FROM_NWD: &[u8] = &[
802 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
803 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
804 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
805 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
806 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
807 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x22, 0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00,
808 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
809 ];
810
811 #[test]
812 fn mem_share() {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100813 let (transaction_desc, access_desc, constituents) =
814 MemTransactionDesc::unpack(MEM_SHARE_FROM_SP1).unwrap();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200815
816 println!("transaction desc: {:#x?}", transaction_desc);
Balint Dobszayc758dd42025-01-15 18:10:40 +0100817 access_desc.for_each(|d| println!("endpont desc: {d:#x?}"));
818 constituents
819 .unwrap()
820 .for_each(|c| println!("constituent desc: {c:#x?}"));
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200821 }
822}