blob: 777a39910a9acaaa57c0318b207fbc3eaa126368 [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 Dobszayc758dd42025-01-15 18:10:40 +01004use crate::ffa_v1_1::{
5 composite_memory_region_descriptor, constituent_memory_region_descriptor,
6 endpoint_memory_access_descriptor, memory_access_permission_descriptor,
7 memory_relinquish_descriptor, memory_transaction_descriptor,
8};
9use core::mem::size_of;
10use thiserror::Error;
11use zerocopy::{FromBytes, IntoBytes};
12
13#[derive(Debug, Error)]
14pub enum Error {
15 #[error("Invalid cacheability attribute {0}")]
16 InvalidCacheability(u16),
17 #[error("Invalid shareability attribute {0}")]
18 InvalidShareability(u16),
19 #[error("Invalid device memory attributes {0}")]
20 InvalidDevMemAttributes(u16),
21 #[error("Invalid instruction access permission {0}")]
22 InvalidInstrAccessPerm(u8),
23 #[error("Invalid instruction data permission {0}")]
24 InvalidDataAccessPerm(u8),
25 #[error("Invalid memory type {0}")]
26 InvalidMemType(u16),
27 #[error("Invalid memory attributes {0}")]
28 InvalidMemAttributes(u16),
29 #[error("Composite offset mismatch")]
30 CompositeOffsetMismatch,
31 #[error("Invalid endpoint count {0}")]
32 UnsupportedEndpointCount(u32),
33 #[error("Invalid buffer size")]
34 InvalidBufferSize,
35 #[error("Malformed descriptor")]
36 MalformedDescriptor,
37}
38
39impl From<Error> for crate::FfaError {
40 fn from(_value: Error) -> Self {
41 Self::InvalidParameters
42 }
43}
Balint Dobszay5bf492f2024-07-29 17:21:32 +020044
45#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
46pub struct Handle(pub u64);
47
48impl From<[u32; 2]> for Handle {
49 fn from(value: [u32; 2]) -> Self {
50 Self((value[1] as u64) << 32 | value[0] as u64)
51 }
52}
53
54impl From<Handle> for [u32; 2] {
55 fn from(value: Handle) -> Self {
56 [value.0 as u32, (value.0 >> 32) as u32]
57 }
58}
59
60impl Handle {
61 pub const INVALID: u64 = 0xffff_ffff_ffff_ffff;
62}
63
64#[derive(Debug, Default, Clone, Copy, PartialEq)]
65#[repr(u16)]
66pub enum Cacheability {
67 #[default]
68 NonCacheable = Self::NON_CACHEABLE << Self::SHIFT,
69 WriteBack = Self::WRITE_BACK << Self::SHIFT,
70}
71
72impl TryFrom<u16> for Cacheability {
Balint Dobszayc758dd42025-01-15 18:10:40 +010073 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +020074
75 fn try_from(value: u16) -> Result<Self, Self::Error> {
76 match (value >> Self::SHIFT) & Self::MASK {
77 Self::NON_CACHEABLE => Ok(Cacheability::NonCacheable),
78 Self::WRITE_BACK => Ok(Cacheability::WriteBack),
Balint Dobszayc758dd42025-01-15 18:10:40 +010079 _ => Err(Error::InvalidCacheability(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +020080 }
81 }
82}
83
84impl Cacheability {
85 const SHIFT: usize = 2;
86 const MASK: u16 = 0b11;
87 const NON_CACHEABLE: u16 = 0b01;
88 const WRITE_BACK: u16 = 0b11;
89}
90
91#[derive(Debug, Default, Clone, Copy, PartialEq)]
92#[repr(u16)]
93pub enum Shareability {
94 #[default]
95 NonShareable = Self::NON_SHAREABLE << Self::SHIFT,
96 Outer = Self::OUTER << Self::SHIFT,
97 Inner = Self::INNER << Self::SHIFT,
98}
99
100impl TryFrom<u16> for Shareability {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100101 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200102
103 fn try_from(value: u16) -> Result<Self, Self::Error> {
104 match (value >> Self::SHIFT) & Self::MASK {
105 Self::NON_SHAREABLE => Ok(Self::NonShareable),
106 Self::OUTER => Ok(Self::Outer),
107 Self::INNER => Ok(Self::Inner),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100108 _ => Err(Error::InvalidShareability(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200109 }
110 }
111}
112
113impl Shareability {
114 const SHIFT: usize = 0;
115 const MASK: u16 = 0b11;
116 const NON_SHAREABLE: u16 = 0b00;
117 const OUTER: u16 = 0b10;
118 const INNER: u16 = 0b11;
119}
120
121#[derive(Debug, Default, Clone, Copy)]
122#[repr(u16)]
123pub enum DeviceMemAttributes {
124 #[default]
125 DevnGnRnE = Self::DEV_NGNRNE << Self::SHIFT,
126 DevnGnRE = Self::DEV_NGNRE << Self::SHIFT,
127 DevnGRE = Self::DEV_NGRE << Self::SHIFT,
128 DevGRE = Self::DEV_GRE << Self::SHIFT,
129}
130
131impl TryFrom<u16> for DeviceMemAttributes {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100132 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200133
134 fn try_from(value: u16) -> Result<Self, Self::Error> {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200135 match (value >> Self::SHIFT) & Self::MASK {
136 Self::DEV_NGNRNE => Ok(Self::DevnGnRnE),
137 Self::DEV_NGNRE => Ok(Self::DevnGnRE),
138 Self::DEV_NGRE => Ok(Self::DevnGRE),
139 Self::DEV_GRE => Ok(Self::DevGRE),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100140 _ => Err(Error::InvalidDevMemAttributes(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200141 }
142 }
143}
144
145impl DeviceMemAttributes {
146 const SHIFT: usize = 2;
147 const MASK: u16 = 0b11;
148 const DEV_NGNRNE: u16 = 0b00;
149 const DEV_NGNRE: u16 = 0b01;
150 const DEV_NGRE: u16 = 0b10;
151 const DEV_GRE: u16 = 0b11;
152}
153
154#[derive(Debug, Default, Clone, Copy)]
155pub enum MemType {
156 #[default]
157 NotSpecified,
158 Device(DeviceMemAttributes),
159 Normal {
160 cacheability: Cacheability,
161 shareability: Shareability,
162 },
163}
164
165impl TryFrom<u16> for MemType {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100166 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200167
168 fn try_from(value: u16) -> Result<Self, Self::Error> {
169 match (value >> Self::SHIFT) & Self::MASK {
170 Self::NOT_SPECIFIED => Ok(Self::NotSpecified),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100171 Self::DEVICE => Ok(Self::Device(value.try_into()?)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200172 Self::NORMAL => Ok(Self::Normal {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100173 cacheability: value.try_into()?,
174 shareability: value.try_into()?,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200175 }),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100176 _ => Err(Error::InvalidMemType(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200177 }
178 }
179}
180
181impl From<MemType> for u16 {
182 fn from(value: MemType) -> Self {
183 match value {
184 MemType::NotSpecified => MemType::NOT_SPECIFIED << MemType::SHIFT,
185 MemType::Device(attr) => attr as u16 | MemType::DEVICE << MemType::SHIFT,
186 MemType::Normal {
187 cacheability,
188 shareability,
189 } => cacheability as u16 | shareability as u16 | MemType::NORMAL << MemType::SHIFT,
190 }
191 }
192}
193
194impl MemType {
195 const SHIFT: usize = 4;
196 const MASK: u16 = 0b11;
197 const NOT_SPECIFIED: u16 = 0b00;
198 const DEVICE: u16 = 0b01;
199 const NORMAL: u16 = 0b10;
200}
201
202#[derive(Debug, Default, Clone, Copy, PartialEq)]
203#[repr(u16)]
204pub enum MemRegionSecurity {
205 #[default]
206 Secure = Self::SECURE << Self::SHIFT,
207 NonSecure = Self::NON_SECURE << Self::SHIFT,
208}
209
Balint Dobszayc758dd42025-01-15 18:10:40 +0100210impl From<u16> for MemRegionSecurity {
211 fn from(value: u16) -> Self {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200212 match (value >> Self::SHIFT) & Self::MASK {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100213 Self::SECURE => Self::Secure,
214 Self::NON_SECURE => Self::NonSecure,
215 _ => panic!(), // The match is exhaustive for a 1-bit value
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200216 }
217 }
218}
219
220impl MemRegionSecurity {
221 const SHIFT: usize = 6;
222 const MASK: u16 = 0b1;
223 const SECURE: u16 = 0b0;
224 const NON_SECURE: u16 = 0b1;
225}
226
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200227#[derive(Debug, Default, Clone, Copy)]
228pub struct MemRegionAttributes {
229 pub security: MemRegionSecurity,
230 pub mem_type: MemType,
231}
232
233impl TryFrom<u16> for MemRegionAttributes {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100234 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200235
236 fn try_from(value: u16) -> Result<Self, Self::Error> {
237 // bits[15:7]: Reserved (MBZ)
Balint Dobszayc758dd42025-01-15 18:10:40 +0100238 if value >> 7 == 0 {
239 Ok(Self {
240 security: value.into(),
241 mem_type: value.try_into()?,
242 })
243 } else {
244 Err(Error::InvalidMemAttributes(value))
245 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200246 }
247}
248
249impl From<MemRegionAttributes> for u16 {
250 fn from(value: MemRegionAttributes) -> Self {
251 value.security as u16 | u16::from(value.mem_type)
252 }
253}
254
255#[derive(Debug, Default, Clone, Copy)]
256#[repr(u8)]
257pub enum InstuctionAccessPerm {
258 #[default]
259 NotSpecified = Self::NOT_SPECIFIED << Self::SHIFT,
260 NotExecutable = Self::NOT_EXECUTABLE << Self::SHIFT,
261 Executable = Self::EXECUTABLE << Self::SHIFT,
262}
263
264impl TryFrom<u8> for InstuctionAccessPerm {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100265 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200266
267 fn try_from(value: u8) -> Result<Self, Self::Error> {
268 match (value >> Self::SHIFT) & Self::MASK {
269 Self::NOT_SPECIFIED => Ok(Self::NotSpecified),
270 Self::NOT_EXECUTABLE => Ok(Self::NotExecutable),
271 Self::EXECUTABLE => Ok(Self::Executable),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100272 _ => Err(Error::InvalidInstrAccessPerm(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200273 }
274 }
275}
276
277impl InstuctionAccessPerm {
278 const SHIFT: usize = 2;
279 const MASK: u8 = 0b11;
280 const NOT_SPECIFIED: u8 = 0b00;
281 const NOT_EXECUTABLE: u8 = 0b01;
282 const EXECUTABLE: u8 = 0b10;
283}
284
285#[derive(Debug, Default, Clone, Copy)]
286#[repr(u8)]
287pub enum DataAccessPerm {
288 #[default]
289 NotSpecified = Self::NOT_SPECIFIED << Self::SHIFT,
290 ReadOnly = Self::READ_ONLY << Self::SHIFT,
291 ReadWrite = Self::READ_WRITE << Self::SHIFT,
292}
293
294impl TryFrom<u8> for DataAccessPerm {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100295 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200296
297 fn try_from(value: u8) -> Result<Self, Self::Error> {
298 match (value >> Self::SHIFT) & Self::MASK {
299 Self::NOT_SPECIFIED => Ok(Self::NotSpecified),
300 Self::READ_ONLY => Ok(Self::ReadOnly),
301 Self::READ_WRITE => Ok(Self::ReadWrite),
Balint Dobszayc758dd42025-01-15 18:10:40 +0100302 _ => Err(Error::InvalidDataAccessPerm(value)),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200303 }
304 }
305}
306
307impl DataAccessPerm {
308 const SHIFT: usize = 0;
309 const MASK: u8 = 0b11;
310 const NOT_SPECIFIED: u8 = 0b00;
311 const READ_ONLY: u8 = 0b01;
312 const READ_WRITE: u8 = 0b10;
313}
314
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200315#[derive(Debug, Default, Clone, Copy)]
Balint Dobszayc758dd42025-01-15 18:10:40 +0100316pub struct MemAccessPerm {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200317 pub endpoint_id: u16,
318 pub instr_access: InstuctionAccessPerm,
319 pub data_access: DataAccessPerm,
320 pub flags: u8, // TODO
321}
322
Balint Dobszayc758dd42025-01-15 18:10:40 +0100323pub struct MemAccessPermIterator<'a> {
324 buf: &'a [u8],
325 offset: usize,
326 count: usize,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200327}
328
Balint Dobszayc758dd42025-01-15 18:10:40 +0100329impl<'a> MemAccessPermIterator<'a> {
330 fn new(buf: &'a [u8], count: usize, offset: usize) -> Result<Self, Error> {
331 let Some(total_size) = count
332 .checked_mul(size_of::<endpoint_memory_access_descriptor>())
333 .and_then(|x| x.checked_add(offset))
334 else {
335 return Err(Error::InvalidBufferSize);
336 };
337
338 if buf.len() < total_size {
339 return Err(Error::InvalidBufferSize);
340 }
341
342 Ok(Self { buf, offset, count })
343 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200344}
345
Balint Dobszayc758dd42025-01-15 18:10:40 +0100346impl Iterator for MemAccessPermIterator<'_> {
347 type Item = Result<MemAccessPerm, Error>;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200348
Balint Dobszayc758dd42025-01-15 18:10:40 +0100349 fn next(&mut self) -> Option<Self::Item> {
350 if self.count > 0 {
351 let offset = self.offset;
352 self.offset += size_of::<endpoint_memory_access_descriptor>();
353 self.count -= 1;
354
355 let Ok(desc_raw) = endpoint_memory_access_descriptor::ref_from_bytes(
356 &self.buf[offset..offset + size_of::<endpoint_memory_access_descriptor>()],
357 ) else {
358 return Some(Err(Error::MalformedDescriptor));
359 };
360
361 let instr_access = match desc_raw
362 .access_perm_desc
363 .memory_access_permissions
364 .try_into()
365 {
366 Ok(v) => v,
367 Err(e) => return Some(Err(e)),
368 };
369
370 let data_access = match desc_raw
371 .access_perm_desc
372 .memory_access_permissions
373 .try_into()
374 {
375 Ok(v) => v,
376 Err(e) => return Some(Err(e)),
377 };
378
379 let desc = MemAccessPerm {
380 endpoint_id: desc_raw.access_perm_desc.endpoint_id,
381 instr_access,
382 data_access,
383 flags: desc_raw.access_perm_desc.flags,
384 };
385
386 return Some(Ok(desc));
387 }
388
389 None
390 }
391}
392
393#[derive(Debug, Default, Clone, Copy)]
394pub struct ConstituentMemRegion {
395 pub address: u64,
396 pub page_cnt: u32,
397}
398
399pub struct ConstituentMemRegionIterator<'a> {
400 buf: &'a [u8],
401 offset: usize,
402 count: usize,
403}
404
405impl<'a> ConstituentMemRegionIterator<'a> {
406 fn new(buf: &'a [u8], count: usize, offset: usize) -> Result<Self, Error> {
407 let Some(total_size) = count
408 .checked_mul(size_of::<constituent_memory_region_descriptor>())
409 .and_then(|x| x.checked_add(offset))
410 else {
411 return Err(Error::InvalidBufferSize);
412 };
413
414 if buf.len() < total_size {
415 return Err(Error::InvalidBufferSize);
416 }
417
418 Ok(Self { buf, offset, count })
419 }
420}
421
422impl Iterator for ConstituentMemRegionIterator<'_> {
423 type Item = Result<ConstituentMemRegion, Error>;
424
425 fn next(&mut self) -> Option<Self::Item> {
426 if self.count > 0 {
427 let offset = self.offset;
428 self.offset += size_of::<constituent_memory_region_descriptor>();
429 self.count -= 1;
430
431 let Ok(desc_raw) = constituent_memory_region_descriptor::ref_from_bytes(
432 &self.buf[offset..offset + size_of::<constituent_memory_region_descriptor>()],
433 ) else {
434 return Some(Err(Error::MalformedDescriptor));
435 };
436
437 let desc = ConstituentMemRegion {
438 address: desc_raw.address,
439 page_cnt: desc_raw.page_count,
440 };
441
442 return Some(Ok(desc));
443 }
444
445 None
446 }
447}
448
449#[derive(Debug, Default, Clone, Copy)]
450pub struct MemTransactionFlags(pub u32);
451
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200452impl MemTransactionFlags {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100453 pub const MEM_SHARE_MASK: u32 = 0b11;
454 pub const MEM_RETRIEVE_REQ_MASK: u32 = 0b11_1111_1111;
455 pub const MEM_RETRIEVE_RESP_MASK: u32 = 0b1_1111;
456 pub const ZERO_MEMORY: u32 = 0b1;
457 pub const TIME_SLICING: u32 = 0b1 << 1;
458 pub const ZERO_AFTER_RELINQ: u32 = 0b1 << 2;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200459 pub const TYPE_SHARE: u32 = 0b01 << 3;
Balint Dobszayc758dd42025-01-15 18:10:40 +0100460 pub const TYPE_LEND: u32 = 0b10 << 3;
461 pub const TYPE_DONATE: u32 = 0b11 << 3;
462 pub const ALIGN_HINT_MASK: u32 = 0b1111 << 5;
463 pub const HINT_VALID: u32 = 0b1 << 9;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200464}
465
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200466#[derive(Debug, Default)]
467pub struct MemTransactionDesc {
468 pub sender_id: u16,
469 pub mem_region_attr: MemRegionAttributes,
470 pub flags: MemTransactionFlags,
471 pub handle: Handle,
472 pub tag: u64, // TODO
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200473}
474
475impl MemTransactionDesc {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100476 // Offset from the base of the memory transaction descriptor to the first element in the
477 // endpoint memory access descriptor array. Must be 16 byte aligned, but otherwise we're free to
478 // choose any value here. Let's just pack it right after the memory transaction descriptor.
479 const ENDPOINT_MEM_ACCESS_DESC_OFFSET: usize =
480 size_of::<memory_transaction_descriptor>().next_multiple_of(16);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200481
Balint Dobszayc758dd42025-01-15 18:10:40 +0100482 // The array of constituent memory region descriptors starts right after the composite memory
483 // region descriptor
484 const CONSTITUENT_ARRAY_OFFSET: usize = size_of::<composite_memory_region_descriptor>();
485
486 pub fn pack(
487 &self,
488 constituents: &[ConstituentMemRegion],
489 access_descriptors: &[MemAccessPerm],
490 buf: &mut [u8],
491 ) -> usize {
492 let mem_access_desc_size = size_of::<endpoint_memory_access_descriptor>();
493 let mem_access_desc_cnt = access_descriptors.len();
494
495 let transaction_desc_raw = memory_transaction_descriptor {
496 sender_endpoint_id: self.sender_id,
497 memory_region_attributes: self.mem_region_attr.into(),
498 flags: self.flags.0,
499 handle: self.handle.0,
500 tag: self.tag,
501 endpoint_mem_access_desc_size: mem_access_desc_size as u32,
502 endpoint_mem_access_desc_count: mem_access_desc_cnt as u32,
503 endpoint_mem_access_desc_array_offset: Self::ENDPOINT_MEM_ACCESS_DESC_OFFSET as u32,
504 reserved1: 0,
505 reserved2: 0,
506 };
507
508 transaction_desc_raw.write_to_prefix(buf).unwrap();
509
510 // Offset from the base of the memory transaction descriptor to the composite memory region
511 // descriptor to which the endpoint access permissions apply.
512 let composite_offset = mem_access_desc_cnt
513 .checked_mul(mem_access_desc_size)
514 .unwrap()
515 .checked_add(Self::ENDPOINT_MEM_ACCESS_DESC_OFFSET)
516 .unwrap()
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200517 .next_multiple_of(8);
518
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200519 let mut offset = Self::ENDPOINT_MEM_ACCESS_DESC_OFFSET;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200520
Balint Dobszayc758dd42025-01-15 18:10:40 +0100521 for desc in access_descriptors {
522 let desc_raw = endpoint_memory_access_descriptor {
523 access_perm_desc: memory_access_permission_descriptor {
524 endpoint_id: desc.endpoint_id,
525 memory_access_permissions: desc.data_access as u8 | desc.instr_access as u8,
526 flags: desc.flags,
527 },
528 composite_offset: composite_offset as u32,
529 reserved: 0,
530 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200531
Balint Dobszayc758dd42025-01-15 18:10:40 +0100532 desc_raw.write_to_prefix(&mut buf[offset..]).unwrap();
533 offset += mem_access_desc_size;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200534 }
535
Balint Dobszayc758dd42025-01-15 18:10:40 +0100536 let mut total_page_count = 0;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200537
Balint Dobszayc758dd42025-01-15 18:10:40 +0100538 offset = composite_offset + Self::CONSTITUENT_ARRAY_OFFSET;
539 for constituent in constituents {
540 let constituent_raw = constituent_memory_region_descriptor {
541 address: constituent.address,
542 page_count: constituent.page_cnt,
543 reserved: 0,
544 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200545
Balint Dobszayc758dd42025-01-15 18:10:40 +0100546 constituent_raw.write_to_prefix(&mut buf[offset..]).unwrap();
547 offset += size_of::<constituent_memory_region_descriptor>();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200548
Balint Dobszayc758dd42025-01-15 18:10:40 +0100549 total_page_count += constituent_raw.page_count;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200550 }
551
Balint Dobszayc758dd42025-01-15 18:10:40 +0100552 let composite_desc_raw = composite_memory_region_descriptor {
553 total_page_count,
554 address_range_count: constituents.len() as u32,
555 reserved: 0,
556 };
557
558 composite_desc_raw
559 .write_to_prefix(&mut buf[composite_offset..])
560 .unwrap();
561
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200562 offset
563 }
564
Balint Dobszayc758dd42025-01-15 18:10:40 +0100565 pub fn unpack(
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200566 buf: &[u8],
Balint Dobszayc758dd42025-01-15 18:10:40 +0100567 ) -> Result<
568 (
569 MemTransactionDesc,
570 MemAccessPermIterator,
571 Option<ConstituentMemRegionIterator>,
572 ),
573 Error,
574 > {
575 let Some(transaction_desc_bytes) = buf.get(0..size_of::<memory_transaction_descriptor>())
576 else {
577 return Err(Error::InvalidBufferSize);
578 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200579
Balint Dobszayc758dd42025-01-15 18:10:40 +0100580 let Ok(transaction_desc_raw) =
581 memory_transaction_descriptor::ref_from_bytes(transaction_desc_bytes)
582 else {
583 return Err(Error::MalformedDescriptor);
584 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200585
Balint Dobszayc758dd42025-01-15 18:10:40 +0100586 if size_of::<endpoint_memory_access_descriptor>()
587 != transaction_desc_raw.endpoint_mem_access_desc_size as usize
588 {
589 return Err(Error::MalformedDescriptor);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200590 }
591
Balint Dobszayc758dd42025-01-15 18:10:40 +0100592 if transaction_desc_raw.endpoint_mem_access_desc_count == 0 {
593 return Err(Error::MalformedDescriptor);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200594 }
595
Balint Dobszayc758dd42025-01-15 18:10:40 +0100596 let Some(total_desc_size) = transaction_desc_raw
597 .endpoint_mem_access_desc_size
598 .checked_mul(transaction_desc_raw.endpoint_mem_access_desc_count)
599 .and_then(|x| {
600 x.checked_add(transaction_desc_raw.endpoint_mem_access_desc_array_offset)
601 })
602 else {
603 return Err(Error::InvalidBufferSize);
604 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200605
Balint Dobszayc758dd42025-01-15 18:10:40 +0100606 if buf.len() < total_desc_size as usize {
607 return Err(Error::InvalidBufferSize);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200608 }
609
Balint Dobszayc758dd42025-01-15 18:10:40 +0100610 let transaction_desc = MemTransactionDesc {
611 sender_id: transaction_desc_raw.sender_endpoint_id,
612 mem_region_attr: transaction_desc_raw.memory_region_attributes.try_into()?,
613 flags: MemTransactionFlags(transaction_desc_raw.flags),
614 handle: Handle(transaction_desc_raw.handle),
615 tag: transaction_desc_raw.tag,
616 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200617
Balint Dobszayc758dd42025-01-15 18:10:40 +0100618 let mut offset = transaction_desc_raw.endpoint_mem_access_desc_array_offset as usize;
619
620 let access_desc_iter = MemAccessPermIterator::new(
621 buf,
622 transaction_desc_raw.endpoint_mem_access_desc_count as usize,
623 offset,
624 )?;
625
626 // We have to check the first endpoint memory access descriptor to get the composite offset
627 let Ok(desc_raw) = endpoint_memory_access_descriptor::ref_from_bytes(
628 &buf[offset..offset + size_of::<endpoint_memory_access_descriptor>()],
629 ) else {
630 return Err(Error::MalformedDescriptor);
631 };
632
633 offset = desc_raw.composite_offset as usize;
634
635 // An offset value of 0 indicates that the endpoint access permissions apply to a memory
636 // region description identified by the Handle (i.e. there is no composite descriptor)
637 if offset == 0 {
638 return Ok((transaction_desc, access_desc_iter, None));
639 }
640
641 let Some(composite_desc_bytes) =
642 buf.get(offset..offset + size_of::<composite_memory_region_descriptor>())
643 else {
644 return Err(Error::InvalidBufferSize);
645 };
646
647 let Ok(composite_desc_raw) =
648 composite_memory_region_descriptor::ref_from_bytes(composite_desc_bytes)
649 else {
650 return Err(Error::MalformedDescriptor);
651 };
652
653 let constituent_iter = ConstituentMemRegionIterator::new(
654 buf,
655 composite_desc_raw.address_range_count as usize,
656 offset + Self::CONSTITUENT_ARRAY_OFFSET,
657 )?;
658
659 // TODO: add a sainty check to compare the composite descriptor's total page count and the
660 // sum of page counts from constituent memory regions (not sure if it's really valuable)
661
662 Ok((transaction_desc, access_desc_iter, Some(constituent_iter)))
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200663 }
664}
665
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200666#[derive(Debug, Default)]
667pub struct MemRelinquishDesc {
668 pub handle: Handle,
669 pub flags: u32,
Balint Dobszayc758dd42025-01-15 18:10:40 +0100670 pub endpoint: u16,
671}
672
673impl TryFrom<&[u8]> for MemRelinquishDesc {
674 type Error = Error;
675
676 fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
677 let Some(desc_bytes) = buf.get(0..size_of::<memory_relinquish_descriptor>()) else {
678 return Err(Error::InvalidBufferSize);
679 };
680
681 let Ok(desc_raw) = memory_relinquish_descriptor::ref_from_bytes(desc_bytes) else {
682 return Err(Error::MalformedDescriptor);
683 };
684
685 let Some(total_desc_size) = (desc_raw.endpoint_count as usize)
686 .checked_mul(size_of::<u16>())
687 .and_then(|x| x.checked_add(Self::ENDPOINT_ARRAY_OFFSET))
688 else {
689 return Err(Error::InvalidBufferSize);
690 };
691
692 if buf.len() < total_desc_size {
693 return Err(Error::InvalidBufferSize);
694 }
695
696 // If the caller is a PE endpoint Borrower, then Endpoint count must equal 1. Currently only
697 // this case is supported. The array of endpoint IDs contains only a single element.
698 if desc_raw.endpoint_count != 1 {
699 return Err(Error::UnsupportedEndpointCount(desc_raw.endpoint_count));
700 }
701
702 let endpoint = u16::from_le_bytes([
703 buf[Self::ENDPOINT_ARRAY_OFFSET],
704 buf[Self::ENDPOINT_ARRAY_OFFSET + 1],
705 ]);
706
707 Ok(Self {
708 handle: Handle(desc_raw.handle),
709 flags: desc_raw.flags, // TODO: validate
710 endpoint,
711 })
712 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200713}
714
715impl MemRelinquishDesc {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100716 const ENDPOINT_ARRAY_OFFSET: usize = size_of::<memory_relinquish_descriptor>();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200717}
718
719#[cfg(test)]
720mod tests {
721 use super::*;
722
723 #[allow(dead_code)]
724 const MEM_SHARE_FROM_SP1: &[u8] = &[
725 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
726 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
727 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
728 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
729 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
730 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
731 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
732 ];
733
734 #[allow(dead_code)]
735 const MEM_SHARE_FROM_SP2: &[u8] = &[
736 0x06, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
737 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
738 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
739 0x00, 0x00, 0x00, 0x05, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
740 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
741 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x07, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
742 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
743 ];
744
745 #[allow(dead_code)]
746 const MEM_RETRIEVE_REQ_FROM_SP1: &[u8] = &[
747 0x05, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
748 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
749 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
750 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
751 0x00, 0x00, 0x00, 0x00,
752 ];
753
754 #[allow(dead_code)]
755 const MEM_RETRIEVE_REQ_FROM_SP2: &[u8] = &[
756 0x06, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
758 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
759 0x00, 0x00, 0x00, 0x05, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
760 0x00, 0x00, 0x00, 0x00,
761 ];
762
763 #[allow(dead_code)]
764 const MEM_SHARE_FROM_NWD: &[u8] = &[
765 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
767 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
768 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
769 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
770 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x22, 0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00,
771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
772 ];
773
774 #[test]
775 fn mem_share() {
Balint Dobszayc758dd42025-01-15 18:10:40 +0100776 let (transaction_desc, access_desc, constituents) =
777 MemTransactionDesc::unpack(MEM_SHARE_FROM_SP1).unwrap();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200778
779 println!("transaction desc: {:#x?}", transaction_desc);
Balint Dobszayc758dd42025-01-15 18:10:40 +0100780 access_desc.for_each(|d| println!("endpont desc: {d:#x?}"));
781 constituents
782 .unwrap()
783 .for_each(|c| println!("constituent desc: {c:#x?}"));
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200784 }
785}