1use crate::{
16 ffa_v1_1::{
17 composite_memory_region_descriptor, constituent_memory_region_descriptor,
18 endpoint_memory_access_descriptor, memory_access_permission_descriptor,
19 memory_relinquish_descriptor, memory_transaction_descriptor,
20 },
21 interface_args::SuccessArgs,
22};
23use core::mem::size_of;
24use thiserror::Error;
25use zerocopy::{FromBytes, IntoBytes};
26
27#[derive(Debug, Error, PartialEq, Eq, Clone, Copy)]
30pub enum Error {
31 #[error("Invalid cacheability attribute {0}")]
32 InvalidCacheability(u16),
33 #[error("Invalid shareability attribute {0}")]
34 InvalidShareability(u16),
35 #[error("Invalid device memory attributes {0}")]
36 InvalidDevMemAttributes(u16),
37 #[error("Invalid instruction access permission {0}")]
38 InvalidInstrAccessPerm(u8),
39 #[error("Invalid instruction data permission {0}")]
40 InvalidDataAccessPerm(u8),
41 #[error("Invalid memory type {0}")]
42 InvalidMemType(u16),
43 #[error("Invalid memory attributes {0}")]
44 InvalidMemAttributes(u16),
45 #[error("Composite offset mismatch")]
46 CompositeOffsetMismatch,
47 #[error("Invalid endpoint count {0}")]
48 UnsupportedEndpointCount(u32),
49 #[error("Invalid buffer size")]
50 InvalidBufferSize,
51 #[error("Malformed descriptor")]
52 MalformedDescriptor,
53 #[error("Invalid get/set instruction access permission {0}")]
54 InvalidInstrAccessPermGetSet(u32),
55 #[error("Invalid get/set instruction data permission {0}")]
56 InvalidDataAccessPermGetSet(u32),
57 #[error("Invalid page count")]
58 InvalidPageCount,
59 #[error("Invalid memory reclaim flags {0}")]
60 InvalidMemReclaimFlags(u32),
61}
62
63impl From<Error> for crate::FfaError {
64 fn from(_value: Error) -> Self {
65 Self::InvalidParameters
66 }
67}
68
69#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
71pub struct Handle(pub u64);
72
73impl From<[u32; 2]> for Handle {
74 fn from(value: [u32; 2]) -> Self {
75 Self(((value[1] as u64) << 32) | value[0] as u64)
76 }
77}
78
79impl From<Handle> for [u32; 2] {
80 fn from(value: Handle) -> Self {
81 [value.0 as u32, (value.0 >> 32) as u32]
82 }
83}
84
85impl Handle {
86 pub const INVALID: u64 = 0xffff_ffff_ffff_ffff;
87}
88
89#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
91#[repr(u16)]
92pub enum Cacheability {
93 #[default]
94 NonCacheable = Self::NON_CACHEABLE << Self::SHIFT,
95 WriteBack = Self::WRITE_BACK << Self::SHIFT,
96}
97
98impl TryFrom<u16> for Cacheability {
99 type Error = Error;
100
101 fn try_from(value: u16) -> Result<Self, Self::Error> {
102 match (value >> Self::SHIFT) & Self::MASK {
103 Self::NON_CACHEABLE => Ok(Cacheability::NonCacheable),
104 Self::WRITE_BACK => Ok(Cacheability::WriteBack),
105 _ => Err(Error::InvalidCacheability(value)),
106 }
107 }
108}
109
110impl Cacheability {
111 const SHIFT: usize = 2;
112 const MASK: u16 = 0b11;
113 const NON_CACHEABLE: u16 = 0b01;
114 const WRITE_BACK: u16 = 0b11;
115}
116
117#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
119#[repr(u16)]
120pub enum Shareability {
121 #[default]
122 NonShareable = Self::NON_SHAREABLE << Self::SHIFT,
123 Outer = Self::OUTER << Self::SHIFT,
124 Inner = Self::INNER << Self::SHIFT,
125}
126
127impl TryFrom<u16> for Shareability {
128 type Error = Error;
129
130 fn try_from(value: u16) -> Result<Self, Self::Error> {
131 match (value >> Self::SHIFT) & Self::MASK {
132 Self::NON_SHAREABLE => Ok(Self::NonShareable),
133 Self::OUTER => Ok(Self::Outer),
134 Self::INNER => Ok(Self::Inner),
135 _ => Err(Error::InvalidShareability(value)),
136 }
137 }
138}
139
140impl Shareability {
141 const SHIFT: usize = 0;
142 const MASK: u16 = 0b11;
143 const NON_SHAREABLE: u16 = 0b00;
144 const OUTER: u16 = 0b10;
145 const INNER: u16 = 0b11;
146}
147
148#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
150#[repr(u16)]
151pub enum DeviceMemAttributes {
152 #[default]
153 DevnGnRnE = Self::DEV_NGNRNE << Self::SHIFT,
154 DevnGnRE = Self::DEV_NGNRE << Self::SHIFT,
155 DevnGRE = Self::DEV_NGRE << Self::SHIFT,
156 DevGRE = Self::DEV_GRE << Self::SHIFT,
157}
158
159impl TryFrom<u16> for DeviceMemAttributes {
160 type Error = Error;
161
162 fn try_from(value: u16) -> Result<Self, Self::Error> {
163 match (value >> Self::SHIFT) & Self::MASK {
164 Self::DEV_NGNRNE => Ok(Self::DevnGnRnE),
165 Self::DEV_NGNRE => Ok(Self::DevnGnRE),
166 Self::DEV_NGRE => Ok(Self::DevnGRE),
167 Self::DEV_GRE => Ok(Self::DevGRE),
168 _ => Err(Error::InvalidDevMemAttributes(value)),
169 }
170 }
171}
172
173impl DeviceMemAttributes {
174 const SHIFT: usize = 2;
175 const MASK: u16 = 0b11;
176 const DEV_NGNRNE: u16 = 0b00;
177 const DEV_NGNRE: u16 = 0b01;
178 const DEV_NGRE: u16 = 0b10;
179 const DEV_GRE: u16 = 0b11;
180}
181
182#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
184pub enum MemType {
185 #[default]
186 NotSpecified,
187 Device(DeviceMemAttributes),
188 Normal {
189 cacheability: Cacheability,
190 shareability: Shareability,
191 },
192}
193
194impl TryFrom<u16> for MemType {
195 type Error = Error;
196
197 fn try_from(value: u16) -> Result<Self, Self::Error> {
198 match (value >> Self::SHIFT) & Self::MASK {
199 Self::NOT_SPECIFIED => Ok(Self::NotSpecified),
200 Self::DEVICE => Ok(Self::Device(value.try_into()?)),
201 Self::NORMAL => Ok(Self::Normal {
202 cacheability: value.try_into()?,
203 shareability: value.try_into()?,
204 }),
205 _ => Err(Error::InvalidMemType(value)),
206 }
207 }
208}
209
210impl From<MemType> for u16 {
211 fn from(value: MemType) -> Self {
212 match value {
213 MemType::NotSpecified => MemType::NOT_SPECIFIED << MemType::SHIFT,
214 MemType::Device(attr) => attr as u16 | (MemType::DEVICE << MemType::SHIFT),
215 MemType::Normal {
216 cacheability,
217 shareability,
218 } => cacheability as u16 | shareability as u16 | (MemType::NORMAL << MemType::SHIFT),
219 }
220 }
221}
222
223impl MemType {
224 const SHIFT: usize = 4;
225 const MASK: u16 = 0b11;
226 const NOT_SPECIFIED: u16 = 0b00;
227 const DEVICE: u16 = 0b01;
228 const NORMAL: u16 = 0b10;
229}
230
231#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
233#[repr(u16)]
234pub enum MemRegionSecurity {
235 #[default]
236 Secure = Self::SECURE << Self::SHIFT,
237 NonSecure = Self::NON_SECURE << Self::SHIFT,
238}
239
240impl From<u16> for MemRegionSecurity {
241 fn from(value: u16) -> Self {
242 match (value >> Self::SHIFT) & Self::MASK {
243 Self::SECURE => Self::Secure,
244 Self::NON_SECURE => Self::NonSecure,
245 _ => panic!(), }
247 }
248}
249
250impl MemRegionSecurity {
251 const SHIFT: usize = 6;
252 const MASK: u16 = 0b1;
253 const SECURE: u16 = 0b0;
254 const NON_SECURE: u16 = 0b1;
255}
256
257#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
259pub struct MemRegionAttributes {
260 pub security: MemRegionSecurity,
261 pub mem_type: MemType,
262}
263
264impl TryFrom<u16> for MemRegionAttributes {
265 type Error = Error;
266
267 fn try_from(value: u16) -> Result<Self, Self::Error> {
268 if value >> 7 == 0 {
270 Ok(Self {
271 security: value.into(),
272 mem_type: value.try_into()?,
273 })
274 } else {
275 Err(Error::InvalidMemAttributes(value))
276 }
277 }
278}
279
280impl From<MemRegionAttributes> for u16 {
281 fn from(value: MemRegionAttributes) -> Self {
282 value.security as u16 | u16::from(value.mem_type)
283 }
284}
285
286#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
288#[repr(u8)]
289pub enum InstuctionAccessPerm {
290 #[default]
291 NotSpecified = Self::NOT_SPECIFIED << Self::SHIFT,
292 NotExecutable = Self::NOT_EXECUTABLE << Self::SHIFT,
293 Executable = Self::EXECUTABLE << Self::SHIFT,
294}
295
296impl TryFrom<u8> for InstuctionAccessPerm {
297 type Error = Error;
298
299 fn try_from(value: u8) -> Result<Self, Self::Error> {
300 match (value >> Self::SHIFT) & Self::MASK {
301 Self::NOT_SPECIFIED => Ok(Self::NotSpecified),
302 Self::NOT_EXECUTABLE => Ok(Self::NotExecutable),
303 Self::EXECUTABLE => Ok(Self::Executable),
304 _ => Err(Error::InvalidInstrAccessPerm(value)),
305 }
306 }
307}
308
309impl InstuctionAccessPerm {
310 const SHIFT: usize = 2;
311 const MASK: u8 = 0b11;
312 const NOT_SPECIFIED: u8 = 0b00;
313 const NOT_EXECUTABLE: u8 = 0b01;
314 const EXECUTABLE: u8 = 0b10;
315}
316
317#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
319#[repr(u8)]
320pub enum DataAccessPerm {
321 #[default]
322 NotSpecified = Self::NOT_SPECIFIED << Self::SHIFT,
323 ReadOnly = Self::READ_ONLY << Self::SHIFT,
324 ReadWrite = Self::READ_WRITE << Self::SHIFT,
325}
326
327impl TryFrom<u8> for DataAccessPerm {
328 type Error = Error;
329
330 fn try_from(value: u8) -> Result<Self, Self::Error> {
331 match (value >> Self::SHIFT) & Self::MASK {
332 Self::NOT_SPECIFIED => Ok(Self::NotSpecified),
333 Self::READ_ONLY => Ok(Self::ReadOnly),
334 Self::READ_WRITE => Ok(Self::ReadWrite),
335 _ => Err(Error::InvalidDataAccessPerm(value)),
336 }
337 }
338}
339
340impl DataAccessPerm {
341 const SHIFT: usize = 0;
342 const MASK: u8 = 0b11;
343 const NOT_SPECIFIED: u8 = 0b00;
344 const READ_ONLY: u8 = 0b01;
345 const READ_WRITE: u8 = 0b10;
346}
347
348#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
350pub struct MemAccessPerm {
351 pub endpoint_id: u16,
352 pub instr_access: InstuctionAccessPerm,
353 pub data_access: DataAccessPerm,
354 pub flags: u8, }
356
357pub struct MemAccessPermIterator<'a> {
359 buf: &'a [u8],
360 offset: usize,
361 count: usize,
362}
363
364impl<'a> MemAccessPermIterator<'a> {
365 fn new(buf: &'a [u8], count: usize, offset: usize) -> Result<Self, Error> {
367 let Some(total_size) = count
368 .checked_mul(size_of::<endpoint_memory_access_descriptor>())
369 .and_then(|x| x.checked_add(offset))
370 else {
371 return Err(Error::InvalidBufferSize);
372 };
373
374 if buf.len() < total_size {
375 return Err(Error::InvalidBufferSize);
376 }
377
378 Ok(Self { buf, offset, count })
379 }
380}
381
382impl Iterator for MemAccessPermIterator<'_> {
383 type Item = Result<MemAccessPerm, Error>;
384
385 fn next(&mut self) -> Option<Self::Item> {
386 if self.count > 0 {
387 let offset = self.offset;
388 self.offset += size_of::<endpoint_memory_access_descriptor>();
389 self.count -= 1;
390
391 let Ok(desc_raw) = endpoint_memory_access_descriptor::ref_from_bytes(
392 &self.buf[offset..offset + size_of::<endpoint_memory_access_descriptor>()],
393 ) else {
394 return Some(Err(Error::MalformedDescriptor));
395 };
396
397 let instr_access = match desc_raw
398 .access_perm_desc
399 .memory_access_permissions
400 .try_into()
401 {
402 Ok(v) => v,
403 Err(e) => return Some(Err(e)),
404 };
405
406 let data_access = match desc_raw
407 .access_perm_desc
408 .memory_access_permissions
409 .try_into()
410 {
411 Ok(v) => v,
412 Err(e) => return Some(Err(e)),
413 };
414
415 let desc = MemAccessPerm {
416 endpoint_id: desc_raw.access_perm_desc.endpoint_id,
417 instr_access,
418 data_access,
419 flags: desc_raw.access_perm_desc.flags,
420 };
421
422 return Some(Ok(desc));
423 }
424
425 None
426 }
427}
428
429#[derive(Debug, Default, Clone, Copy, PartialEq)]
431pub struct ConstituentMemRegion {
432 pub address: u64,
433 pub page_cnt: u32,
434}
435
436pub struct ConstituentMemRegionIterator<'a> {
438 buf: &'a [u8],
439 offset: usize,
440 count: usize,
441}
442
443impl<'a> ConstituentMemRegionIterator<'a> {
444 fn new(
446 buf: &'a [u8],
447 region_count: usize,
448 total_page_count: u32,
449 offset: usize,
450 ) -> Result<Self, Error> {
451 let descriptor_size = size_of::<constituent_memory_region_descriptor>();
452
453 let Some(total_size) = region_count
454 .checked_mul(descriptor_size)
455 .and_then(|x| x.checked_add(offset))
456 else {
457 return Err(Error::InvalidBufferSize);
458 };
459
460 if buf.len() < total_size {
461 return Err(Error::InvalidBufferSize);
462 }
463
464 let mut page_count_sum: u32 = 0;
467 for desc_offset in
468 (offset..offset + descriptor_size * region_count).step_by(descriptor_size)
469 {
470 let Ok(desc_raw) = constituent_memory_region_descriptor::ref_from_bytes(
471 &buf[desc_offset..desc_offset + descriptor_size],
472 ) else {
473 return Err(Error::MalformedDescriptor);
474 };
475
476 page_count_sum = page_count_sum
477 .checked_add(desc_raw.page_count)
478 .ok_or(Error::MalformedDescriptor)?;
479 }
480
481 if page_count_sum != total_page_count {
482 return Err(Error::MalformedDescriptor);
483 }
484
485 Ok(Self {
486 buf,
487 offset,
488 count: region_count,
489 })
490 }
491}
492
493impl Iterator for ConstituentMemRegionIterator<'_> {
494 type Item = Result<ConstituentMemRegion, Error>;
495
496 fn next(&mut self) -> Option<Self::Item> {
497 if self.count > 0 {
498 let offset = self.offset;
499 self.offset += size_of::<constituent_memory_region_descriptor>();
500 self.count -= 1;
501
502 let Ok(desc_raw) = constituent_memory_region_descriptor::ref_from_bytes(
503 &self.buf[offset..offset + size_of::<constituent_memory_region_descriptor>()],
504 ) else {
505 return Some(Err(Error::MalformedDescriptor));
506 };
507
508 let desc = ConstituentMemRegion {
509 address: desc_raw.address,
510 page_cnt: desc_raw.page_count,
511 };
512
513 return Some(Ok(desc));
514 }
515
516 None
517 }
518}
519
520#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
522pub struct MemTransactionFlags(pub u32);
523
524impl MemTransactionFlags {
525 pub const MEM_SHARE_MASK: u32 = 0b11;
526 pub const MEM_RETRIEVE_REQ_MASK: u32 = 0b11_1111_1111;
527 pub const MEM_RETRIEVE_RESP_MASK: u32 = 0b1_1111;
528 pub const ZERO_MEMORY: u32 = 0b1;
529 pub const TIME_SLICING: u32 = 0b1 << 1;
530 pub const ZERO_AFTER_RELINQ: u32 = 0b1 << 2;
531 pub const TYPE_SHARE: u32 = 0b01 << 3;
532 pub const TYPE_LEND: u32 = 0b10 << 3;
533 pub const TYPE_DONATE: u32 = 0b11 << 3;
534 pub const ALIGN_HINT_MASK: u32 = 0b1111 << 5;
535 pub const HINT_VALID: u32 = 0b1 << 9;
536}
537
538#[derive(Debug, Clone, Default, PartialEq, Eq)]
541pub struct MemTransactionDesc {
542 pub sender_id: u16,
543 pub mem_region_attr: MemRegionAttributes,
544 pub flags: MemTransactionFlags,
545 pub handle: Handle,
546 pub tag: u64, }
548
549impl MemTransactionDesc {
550 const ENDPOINT_MEM_ACCESS_DESC_OFFSET: usize =
554 size_of::<memory_transaction_descriptor>().next_multiple_of(16);
555
556 const CONSTITUENT_ARRAY_OFFSET: usize = size_of::<composite_memory_region_descriptor>();
559
560 pub fn pack(
563 &self,
564 constituents: &[ConstituentMemRegion],
565 access_descriptors: &[MemAccessPerm],
566 buf: &mut [u8],
567 ) -> usize {
568 let mem_access_desc_size = size_of::<endpoint_memory_access_descriptor>();
569 let mem_access_desc_cnt = access_descriptors.len();
570
571 let transaction_desc_raw = memory_transaction_descriptor {
572 sender_endpoint_id: self.sender_id,
573 memory_region_attributes: self.mem_region_attr.into(),
574 flags: self.flags.0,
575 handle: self.handle.0,
576 tag: self.tag,
577 endpoint_mem_access_desc_size: mem_access_desc_size as u32,
578 endpoint_mem_access_desc_count: mem_access_desc_cnt as u32,
579 endpoint_mem_access_desc_array_offset: Self::ENDPOINT_MEM_ACCESS_DESC_OFFSET as u32,
580 reserved1: 0,
581 reserved2: 0,
582 };
583
584 transaction_desc_raw.write_to_prefix(buf).unwrap();
585
586 let composite_offset = mem_access_desc_cnt
589 .checked_mul(mem_access_desc_size)
590 .unwrap()
591 .checked_add(Self::ENDPOINT_MEM_ACCESS_DESC_OFFSET)
592 .unwrap()
593 .next_multiple_of(8);
594
595 let mut offset = Self::ENDPOINT_MEM_ACCESS_DESC_OFFSET;
596
597 for desc in access_descriptors {
598 let desc_raw = endpoint_memory_access_descriptor {
599 access_perm_desc: memory_access_permission_descriptor {
600 endpoint_id: desc.endpoint_id,
601 memory_access_permissions: desc.data_access as u8 | desc.instr_access as u8,
602 flags: desc.flags,
603 },
604 composite_offset: composite_offset as u32,
605 reserved: 0,
606 };
607
608 desc_raw.write_to_prefix(&mut buf[offset..]).unwrap();
609 offset += mem_access_desc_size;
610 }
611
612 let mut total_page_count: u32 = 0;
613
614 offset = composite_offset + Self::CONSTITUENT_ARRAY_OFFSET;
615 for constituent in constituents {
616 let constituent_raw = constituent_memory_region_descriptor {
617 address: constituent.address,
618 page_count: constituent.page_cnt,
619 reserved: 0,
620 };
621
622 constituent_raw.write_to_prefix(&mut buf[offset..]).unwrap();
623 offset += size_of::<constituent_memory_region_descriptor>();
624
625 total_page_count = total_page_count
626 .checked_add(constituent_raw.page_count)
627 .expect("total_page_count overflow");
628 }
629
630 let composite_desc_raw = composite_memory_region_descriptor {
631 total_page_count,
632 address_range_count: constituents.len() as u32,
633 reserved: 0,
634 };
635
636 composite_desc_raw
637 .write_to_prefix(&mut buf[composite_offset..])
638 .unwrap();
639
640 offset
641 }
642
643 pub fn unpack(
647 buf: &[u8],
648 ) -> Result<
649 (
650 MemTransactionDesc,
651 MemAccessPermIterator<'_>,
652 Option<ConstituentMemRegionIterator<'_>>,
653 ),
654 Error,
655 > {
656 let Some(transaction_desc_bytes) = buf.get(0..size_of::<memory_transaction_descriptor>())
657 else {
658 return Err(Error::InvalidBufferSize);
659 };
660
661 let Ok(transaction_desc_raw) =
662 memory_transaction_descriptor::ref_from_bytes(transaction_desc_bytes)
663 else {
664 return Err(Error::MalformedDescriptor);
665 };
666
667 if transaction_desc_raw.endpoint_mem_access_desc_array_offset % 16 != 0 {
668 return Err(Error::MalformedDescriptor);
669 }
670
671 if size_of::<endpoint_memory_access_descriptor>()
672 != transaction_desc_raw.endpoint_mem_access_desc_size as usize
673 {
674 return Err(Error::MalformedDescriptor);
675 }
676
677 if transaction_desc_raw.endpoint_mem_access_desc_count == 0 {
678 return Err(Error::MalformedDescriptor);
679 }
680
681 let Some(total_desc_size) = transaction_desc_raw
682 .endpoint_mem_access_desc_size
683 .checked_mul(transaction_desc_raw.endpoint_mem_access_desc_count)
684 .and_then(|x| {
685 x.checked_add(transaction_desc_raw.endpoint_mem_access_desc_array_offset)
686 })
687 else {
688 return Err(Error::InvalidBufferSize);
689 };
690
691 if buf.len() < total_desc_size as usize {
692 return Err(Error::InvalidBufferSize);
693 }
694
695 let transaction_desc = MemTransactionDesc {
696 sender_id: transaction_desc_raw.sender_endpoint_id,
697 mem_region_attr: transaction_desc_raw.memory_region_attributes.try_into()?,
698 flags: MemTransactionFlags(transaction_desc_raw.flags),
699 handle: Handle(transaction_desc_raw.handle),
700 tag: transaction_desc_raw.tag,
701 };
702
703 let mut offset = transaction_desc_raw.endpoint_mem_access_desc_array_offset as usize;
704
705 let access_desc_iter = MemAccessPermIterator::new(
706 buf,
707 transaction_desc_raw.endpoint_mem_access_desc_count as usize,
708 offset,
709 )?;
710
711 let Ok(desc_raw) = endpoint_memory_access_descriptor::ref_from_bytes(
713 &buf[offset..offset + size_of::<endpoint_memory_access_descriptor>()],
714 ) else {
715 return Err(Error::MalformedDescriptor);
716 };
717
718 offset = desc_raw.composite_offset as usize;
719
720 if offset == 0 {
723 return Ok((transaction_desc, access_desc_iter, None));
724 }
725
726 let Some(composite_desc_bytes) =
727 buf.get(offset..offset + size_of::<composite_memory_region_descriptor>())
728 else {
729 return Err(Error::InvalidBufferSize);
730 };
731
732 let Ok(composite_desc_raw) =
733 composite_memory_region_descriptor::ref_from_bytes(composite_desc_bytes)
734 else {
735 return Err(Error::MalformedDescriptor);
736 };
737
738 let constituent_iter = ConstituentMemRegionIterator::new(
739 buf,
740 composite_desc_raw.address_range_count as usize,
741 composite_desc_raw.total_page_count,
742 offset + Self::CONSTITUENT_ARRAY_OFFSET,
743 )?;
744
745 Ok((transaction_desc, access_desc_iter, Some(constituent_iter)))
746 }
747}
748
749pub struct EndpointIterator<'a> {
751 buf: &'a [u8],
752 offset: usize,
753 count: usize,
754}
755
756impl<'a> EndpointIterator<'a> {
757 fn new(buf: &'a [u8], count: usize, offset: usize) -> Result<Self, Error> {
759 let Some(total_size) = count.checked_mul(size_of::<u16>()) else {
760 return Err(Error::InvalidBufferSize);
761 };
762
763 if buf.len() < total_size {
764 return Err(Error::InvalidBufferSize);
765 }
766
767 Ok(Self { buf, offset, count })
768 }
769}
770
771impl Iterator for EndpointIterator<'_> {
772 type Item = u16;
773
774 fn next(&mut self) -> Option<Self::Item> {
775 if self.count > 0 {
776 let offset = self.offset;
777 self.offset += size_of::<Self::Item>();
778 self.count -= 1;
779
780 let endpoint = u16::from_le_bytes([self.buf[offset], self.buf[offset + 1]]);
781 return Some(endpoint);
782 }
783
784 None
785 }
786}
787
788#[derive(Debug, Default, PartialEq, Eq, Clone)]
790pub struct MemRelinquishDesc {
791 pub handle: Handle,
792 pub flags: u32,
793}
794
795impl MemRelinquishDesc {
796 const ENDPOINT_ARRAY_OFFSET: usize = size_of::<memory_relinquish_descriptor>();
797
798 pub fn pack(&self, endpoints: &[u16], buf: &mut [u8]) -> usize {
800 if let Ok((desc_raw, endpoint_area)) = memory_relinquish_descriptor::mut_from_prefix(buf) {
801 desc_raw.handle = self.handle.0;
802 desc_raw.flags = self.flags;
803 desc_raw.endpoint_count = endpoints.len().try_into().unwrap();
804
805 for (endpoint, dest) in endpoints
806 .iter()
807 .zip(endpoint_area[..endpoints.len() * 2].chunks_exact_mut(2))
808 {
809 [dest[0], dest[1]] = u16::to_le_bytes(*endpoint);
810 }
811 }
812
813 Self::ENDPOINT_ARRAY_OFFSET + endpoints.len() * 2
814 }
815
816 pub fn unpack(buf: &[u8]) -> Result<(MemRelinquishDesc, EndpointIterator<'_>), Error> {
819 let Some(desc_bytes) = buf.get(0..size_of::<memory_relinquish_descriptor>()) else {
820 return Err(Error::InvalidBufferSize);
821 };
822
823 let Ok(desc_raw) = memory_relinquish_descriptor::ref_from_bytes(desc_bytes) else {
824 return Err(Error::MalformedDescriptor);
825 };
826
827 let Some(total_desc_size) = (desc_raw.endpoint_count as usize)
828 .checked_mul(size_of::<u16>())
829 .and_then(|x| x.checked_add(Self::ENDPOINT_ARRAY_OFFSET))
830 else {
831 return Err(Error::InvalidBufferSize);
832 };
833
834 if buf.len() < total_desc_size {
835 return Err(Error::InvalidBufferSize);
836 }
837
838 let iterator = EndpointIterator::new(
839 buf,
840 desc_raw.endpoint_count as usize,
841 Self::ENDPOINT_ARRAY_OFFSET,
842 )?;
843
844 Ok((
845 Self {
846 handle: Handle(desc_raw.handle),
847 flags: desc_raw.flags, },
849 iterator,
850 ))
851 }
852}
853
854#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
856pub struct MemReclaimFlags {
857 pub zero_memory: bool,
858 pub time_slicing: bool,
859}
860
861impl MemReclaimFlags {
862 pub const ZERO_MEMORY: u32 = 0b1 << 0;
863 pub const TIME_SLICING: u32 = 0b1 << 1;
864 const MBZ_BITS: u32 = 0xffff_fffc;
865}
866
867impl TryFrom<u32> for MemReclaimFlags {
868 type Error = Error;
869
870 fn try_from(val: u32) -> Result<Self, Self::Error> {
871 if (val & Self::MBZ_BITS) != 0 {
872 Err(Error::InvalidMemReclaimFlags(val))
873 } else {
874 Ok(MemReclaimFlags {
875 zero_memory: val & Self::ZERO_MEMORY != 0,
876 time_slicing: val & Self::TIME_SLICING != 0,
877 })
878 }
879 }
880}
881
882impl From<MemReclaimFlags> for u32 {
883 fn from(flags: MemReclaimFlags) -> Self {
884 let mut bits: u32 = 0;
885 if flags.zero_memory {
886 bits |= MemReclaimFlags::ZERO_MEMORY;
887 }
888 if flags.time_slicing {
889 bits |= MemReclaimFlags::TIME_SLICING;
890 }
891 bits
892 }
893}
894
895#[derive(Debug, Eq, PartialEq, Clone, Copy)]
897pub struct SuccessArgsMemOp {
898 pub handle: Handle,
899}
900
901impl From<SuccessArgsMemOp> for SuccessArgs {
902 fn from(value: SuccessArgsMemOp) -> Self {
903 let [handle_lo, handle_hi]: [u32; 2] = value.handle.into();
904 SuccessArgs::Args32([handle_lo, handle_hi, 0, 0, 0, 0])
905 }
906}
907
908impl TryFrom<SuccessArgs> for SuccessArgsMemOp {
909 type Error = crate::Error;
910
911 fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
912 let [handle_lo, handle_hi, ..] = value.try_get_args32()?;
913 Ok(Self {
914 handle: [handle_lo, handle_hi].into(),
915 })
916 }
917}
918
919#[derive(Debug, Clone, Copy, PartialEq, Eq)]
921#[repr(u32)]
922pub enum DataAccessPermGetSet {
923 NoAccess = Self::NO_ACCESS << Self::SHIFT,
924 ReadWrite = Self::READ_WRITE << Self::SHIFT,
925 ReadOnly = Self::READ_ONLY << Self::SHIFT,
926}
927
928impl DataAccessPermGetSet {
929 const SHIFT: usize = 0;
930 const MASK: u32 = 0b11;
931 const NO_ACCESS: u32 = 0b00;
932 const READ_WRITE: u32 = 0b01;
933 const READ_ONLY: u32 = 0b11;
934}
935
936impl TryFrom<u32> for DataAccessPermGetSet {
937 type Error = Error;
938
939 fn try_from(value: u32) -> Result<Self, Self::Error> {
940 match (value >> Self::SHIFT) & Self::MASK {
941 Self::NO_ACCESS => Ok(Self::NoAccess),
942 Self::READ_WRITE => Ok(Self::ReadWrite),
943 Self::READ_ONLY => Ok(Self::ReadOnly),
944 _ => Err(Error::InvalidDataAccessPermGetSet(value)),
945 }
946 }
947}
948
949#[derive(Debug, Clone, Copy, PartialEq, Eq)]
951#[repr(u32)]
952pub enum InstructionAccessPermGetSet {
953 Executable = Self::EXECUTABLE << Self::SHIFT,
954 NonExecutable = Self::NON_EXECUTABLE << Self::SHIFT,
955}
956
957impl InstructionAccessPermGetSet {
958 const SHIFT: usize = 2;
959 const MASK: u32 = 0b1;
960 const EXECUTABLE: u32 = 0b0;
961 const NON_EXECUTABLE: u32 = 0b1;
962}
963
964impl TryFrom<u32> for InstructionAccessPermGetSet {
965 type Error = Error;
966
967 fn try_from(value: u32) -> Result<Self, Self::Error> {
968 match (value >> Self::SHIFT) & Self::MASK {
969 Self::EXECUTABLE => Ok(Self::Executable),
970 Self::NON_EXECUTABLE => Ok(Self::NonExecutable),
971 _ => Err(Error::InvalidInstrAccessPermGetSet(value)),
972 }
973 }
974}
975
976#[derive(Debug, Clone, Copy, PartialEq, Eq)]
978pub struct MemPermissionsGetSet {
979 pub data_access: DataAccessPermGetSet,
980 pub instr_access: InstructionAccessPermGetSet,
981}
982
983impl TryFrom<u32> for MemPermissionsGetSet {
984 type Error = Error;
985
986 fn try_from(value: u32) -> Result<Self, Self::Error> {
987 Ok(Self {
988 data_access: value.try_into()?,
989 instr_access: value.try_into()?,
990 })
991 }
992}
993
994impl From<MemPermissionsGetSet> for u32 {
995 fn from(value: MemPermissionsGetSet) -> Self {
996 value.data_access as u32 | value.instr_access as u32
997 }
998}
999
1000#[derive(Debug, Eq, PartialEq, Clone, Copy)]
1002pub struct SuccessArgsMemPermGet {
1003 pub perm: MemPermissionsGetSet,
1004 pub page_cnt: u32,
1005}
1006
1007impl From<SuccessArgsMemPermGet> for SuccessArgs {
1008 fn from(value: SuccessArgsMemPermGet) -> Self {
1009 assert_ne!(value.page_cnt, 0);
1010 SuccessArgs::Args32([value.perm.into(), value.page_cnt - 1, 0, 0, 0, 0])
1011 }
1012}
1013
1014impl TryFrom<SuccessArgs> for SuccessArgsMemPermGet {
1015 type Error = crate::Error;
1016
1017 fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
1018 let [perm, page_cnt, ..] = value.try_get_args32()?;
1019 Ok(Self {
1020 perm: perm.try_into()?,
1021 page_cnt: page_cnt.checked_add(1).ok_or(Error::InvalidPageCount)?,
1022 })
1023 }
1024}
1025
1026#[cfg(test)]
1027mod tests {
1028 use crate::{
1029 Version,
1030 interface::Interface,
1031 interface_args::{MemAddr, MemOpBuf},
1032 tests::{test_args_serde, test_regs_serde},
1033 };
1034
1035 use super::*;
1036
1037 const MEM_SHARE_FROM_SP1: &[u8] = &[
1038 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56, 0x34,
1039 0x12, 0xef, 0xbe, 0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1040 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1041 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1042 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1043 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
1044 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1045 ];
1046
1047 const MEM_SHARE_FROM_SP2: &[u8] = &[
1048 0x06, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56, 0x34,
1049 0x12, 0xef, 0xbe, 0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1050 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1051 0x00, 0x00, 0x00, 0x05, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1052 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1053 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x07, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
1054 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1055 ];
1056
1057 macro_rules! test_memory_desc_packing {
1058 ($buf:expr, $desc:expr, $perms:expr, $constituents:expr) => {
1059 let (transaction_desc, access_desc, constituents) =
1060 MemTransactionDesc::unpack($buf).unwrap();
1061
1062 assert_eq!(transaction_desc, $desc);
1063
1064 let perms: Vec<_> = access_desc.map(|e| e.unwrap()).collect();
1065 assert_eq!(perms, &$perms);
1066
1067 let constituents = constituents.unwrap();
1068 let constituents: Vec<_> = constituents.map(|c| c.unwrap()).collect();
1069 assert_eq!(constituents, &$constituents);
1070
1071 let mut buf = [0x88; 4096];
1073 let size = $desc.pack(&$constituents, &$perms, &mut buf);
1074
1075 assert_eq!(size, $buf.len());
1076 assert_eq!(&buf[0..size], $buf);
1077 };
1078 }
1079
1080 #[test]
1081 fn mem_share_pack() {
1082 test_memory_desc_packing!(
1083 MEM_SHARE_FROM_SP1,
1084 MemTransactionDesc {
1085 sender_id: 0x8005,
1086 mem_region_attr: MemRegionAttributes {
1087 security: MemRegionSecurity::Secure,
1088 mem_type: MemType::Normal {
1089 cacheability: Cacheability::WriteBack,
1090 shareability: Shareability::Inner,
1091 },
1092 },
1093 flags: MemTransactionFlags(0),
1094 handle: Handle(0x1234_5678_90ab_cdef),
1095 tag: 0xdead_0000_beef,
1096 },
1097 [MemAccessPerm {
1098 endpoint_id: 0x8003,
1099 instr_access: InstuctionAccessPerm::NotSpecified,
1100 data_access: DataAccessPerm::ReadWrite,
1101 flags: 0x0,
1102 }],
1103 [ConstituentMemRegion {
1104 address: 0x4010f000,
1105 page_cnt: 0x1,
1106 }]
1107 );
1108
1109 test_memory_desc_packing!(
1110 MEM_SHARE_FROM_SP2,
1111 MemTransactionDesc {
1112 sender_id: 0x8006,
1113 mem_region_attr: MemRegionAttributes {
1114 security: MemRegionSecurity::Secure,
1115 mem_type: MemType::Normal {
1116 cacheability: Cacheability::WriteBack,
1117 shareability: Shareability::Inner,
1118 },
1119 },
1120 flags: MemTransactionFlags(0),
1121 handle: Handle(0x1234_5678_90ab_cdef),
1122 tag: 0xdead_0000_beef,
1123 },
1124 [MemAccessPerm {
1125 endpoint_id: 0x8005,
1126 instr_access: InstuctionAccessPerm::NotSpecified,
1127 data_access: DataAccessPerm::ReadWrite,
1128 flags: 0x0,
1129 }],
1130 [ConstituentMemRegion {
1131 address: 0x40074000,
1132 page_cnt: 0x1,
1133 }]
1134 );
1135 }
1136
1137 #[test]
1138 fn mem_tx_unpack_err1() {
1139 assert!(MemTransactionDesc::unpack(&[0; 3]).is_err());
1140 }
1141
1142 #[test]
1143 fn mem_tx_unpack_err2() {
1144 assert!(
1146 MemTransactionDesc::unpack(&[
1147 0x06, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20,
1148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1149 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1151 ])
1152 .is_err()
1153 );
1154 }
1155
1156 #[test]
1157 fn mem_tx_unpack_err3() {
1158 assert!(
1160 MemTransactionDesc::unpack(&[
1161 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56,
1162 0x34, 0x12, 0xef, 0xbe, 0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1163 0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1164 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x04, 0x80, 0x02, 0x00
1165 ])
1166 .is_err()
1167 );
1168 }
1169
1170 #[test]
1171 fn mem_tx_unpack_err4() {
1172 assert!(
1174 MemTransactionDesc::unpack(&[
1175 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56,
1176 0x34, 0x12, 0xef, 0xbe, 0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1177 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
1179 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1180 ])
1181 .is_err()
1182 );
1183 }
1184
1185 #[test]
1186 fn mem_tx_unpack_err5() {
1187 assert!(
1189 MemTransactionDesc::unpack(&[
1190 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56,
1191 0x34, 0x12, 0xef, 0xbe, 0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
1192 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1193 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
1194 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1195 0x00, 0x00
1196 ])
1197 .is_err()
1198 );
1199 }
1200
1201 #[test]
1202 fn mem_tx_unpack_err6() {
1203 assert!(
1205 MemTransactionDesc::unpack(&[
1206 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56,
1207 0x34, 0x12, 0xef, 0xbe, 0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1208 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1209 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1210 ])
1211 .is_err()
1212 );
1213 }
1214
1215 #[test]
1216 fn mem_tx_unpack_err7() {
1217 assert!(
1219 MemTransactionDesc::unpack(&[
1220 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56,
1221 0x34, 0x12, 0xef, 0xbe, 0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1222 0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1223 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
1224 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1225 ])
1226 .is_err()
1227 );
1228 }
1229
1230 #[test]
1231 fn mem_tx_unpack_err8() {
1232 assert!(
1234 MemTransactionDesc::unpack(&[
1235 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56,
1236 0x34, 0x12, 0xef, 0xbe, 0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1237 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1238 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x80, 0x00, 0x00, 0x00,
1239 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
1240 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x10, 0x40,
1241 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1242 ])
1243 .is_err()
1244 );
1245 }
1246
1247 #[test]
1248 fn mem_tx_unpack_err9() {
1249 assert!(
1251 MemTransactionDesc::unpack(&[
1252 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56,
1253 0x34, 0x12, 0xef, 0xbe, 0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1254 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1255 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00,
1256 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
1257 ])
1258 .is_err()
1259 );
1260 }
1261
1262 #[test]
1263 fn mem_tx_unpack_unaligned_offset() {
1264 let mut buf = MEM_SHARE_FROM_SP1.to_vec();
1266 buf[32] = 0x31;
1268 assert!(matches!(
1269 MemTransactionDesc::unpack(&buf),
1270 Err(Error::MalformedDescriptor)
1271 ));
1272 }
1273
1274 #[test]
1275 fn mem_relinquish_pack() {
1276 let expected_desc = MemRelinquishDesc {
1277 handle: Handle(0x1234_5678),
1278 flags: MemTransactionFlags::ZERO_MEMORY | MemTransactionFlags::TIME_SLICING,
1279 };
1280 let expected_endpoints: &[u16] = &[0x13, 0x1234, 0xbeef];
1281
1282 let expected_buf: &[u8] = &[
1283 0x78, 0x56, 0x34, 0x12, 0, 0, 0, 0, 0b11, 0, 0, 0, 0x3, 0, 0, 0, 0x13, 0, 0x34, 0x12,
1284 0xef, 0xbe,
1285 ];
1286
1287 let (actual_desc, actual_endpoints) = MemRelinquishDesc::unpack(expected_buf).unwrap();
1288 assert_eq!(actual_desc, expected_desc);
1289 assert_eq!(actual_endpoints.collect::<Vec<_>>(), expected_endpoints);
1290
1291 let mut buf = [0; 128];
1292 let size = expected_desc.pack(expected_endpoints, &mut buf);
1293
1294 println!("{buf:x?}");
1295
1296 assert_eq!(size, expected_buf.len());
1297 assert_eq!(&buf[0..size], expected_buf);
1298 }
1299
1300 #[test]
1301 fn mem_relinquish_unpack_err1() {
1302 assert!(MemRelinquishDesc::unpack(&[0; 4]).is_err());
1303 }
1304
1305 #[test]
1306 fn mem_relinquish_unpack_err2() {
1307 assert!(
1309 MemRelinquishDesc::unpack(&[
1310 0x78, 0x56, 0x34, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
1311 ])
1312 .is_err()
1313 );
1314 }
1315
1316 #[test]
1317 fn mem_relinquish_unpack_err3() {
1318 assert!(
1320 MemRelinquishDesc::unpack(&[
1321 0x78, 0x56, 0x34, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0,
1322 0xab, 0xcd,
1323 ])
1324 .is_err()
1325 );
1326 }
1327
1328 #[test]
1329 fn ffa_mem_donate_serde() {
1330 test_regs_serde!(
1331 Interface::MemDonate {
1332 total_len: 0x1234_5678,
1333 frag_len: 0xabcd,
1334 buf: None
1335 },
1336 [0x84000071, 0x1234_5678, 0xabcd]
1337 );
1338 test_regs_serde!(
1339 Interface::MemDonate {
1340 total_len: 0x1234_5678,
1341 frag_len: 0xabcd,
1342 buf: Some(MemOpBuf::Buf32 {
1343 addr: 0xdead_beef,
1344 page_cnt: 0x1000
1345 })
1346 },
1347 [0x84000071, 0x1234_5678, 0xabcd, 0xdead_beef, 0x1000]
1348 );
1349 test_regs_serde!(
1350 Interface::MemDonate {
1351 total_len: 0x1234_5678,
1352 frag_len: 0xabcd,
1353 buf: Some(MemOpBuf::Buf64 {
1354 addr: 0xdead_0000_beef,
1355 page_cnt: 0x1000
1356 })
1357 },
1358 [0xC4000071, 0x1234_5678, 0xabcd, 0xdead_0000_beef, 0x1000]
1359 );
1360 test_args_serde!(
1361 SuccessArgs::Args32([0x5678_def0, 0x1234_abcd, 0, 0, 0, 0]),
1362 SuccessArgsMemOp {
1363 handle: Handle(0x1234_abcd_5678_def0)
1364 }
1365 );
1366 }
1367
1368 #[test]
1369 fn ffa_mem_lend_serde() {
1370 test_regs_serde!(
1371 Interface::MemLend {
1372 total_len: 0x1234_0000,
1373 frag_len: 0x10_0000,
1374 buf: None
1375 },
1376 [0x84000072, 0x1234_0000, 0x10_0000]
1377 );
1378 test_regs_serde!(
1379 Interface::MemLend {
1380 total_len: 0x1234_0000,
1381 frag_len: 0x10_0000,
1382 buf: Some(MemOpBuf::Buf32 {
1383 addr: 0xffff_ffff,
1384 page_cnt: 0x1000
1385 })
1386 },
1387 [0x84000072, 0x1234_0000, 0x10_0000, 0xffff_ffff, 0x1000]
1388 );
1389 test_regs_serde!(
1390 Interface::MemLend {
1391 total_len: 0x1234_0000,
1392 frag_len: 0x10_0000,
1393 buf: Some(MemOpBuf::Buf64 {
1394 addr: 0xffff_1234_ffff,
1395 page_cnt: 0x1000
1396 })
1397 },
1398 [0xC4000072, 0x1234_0000, 0x10_0000, 0xffff_1234_ffff, 0x1000]
1399 );
1400 }
1401
1402 #[test]
1403 fn ffa_mem_share_serde() {
1404 test_regs_serde!(
1405 Interface::MemShare {
1406 total_len: 0x1234_0000,
1407 frag_len: 0x10_0000,
1408 buf: None
1409 },
1410 [0x84000073, 0x1234_0000, 0x10_0000]
1411 );
1412 test_regs_serde!(
1413 Interface::MemShare {
1414 total_len: 0x1234_0000,
1415 frag_len: 0x10_0000,
1416 buf: Some(MemOpBuf::Buf32 {
1417 addr: 0x1234_5678,
1418 page_cnt: 0x1000
1419 })
1420 },
1421 [0x84000073, 0x1234_0000, 0x10_0000, 0x1234_5678, 0x1000]
1422 );
1423 test_regs_serde!(
1424 Interface::MemShare {
1425 total_len: 0x1234_0000,
1426 frag_len: 0x10_0000,
1427 buf: Some(MemOpBuf::Buf64 {
1428 addr: 0xffff_1234_ffff,
1429 page_cnt: 0x1000
1430 })
1431 },
1432 [0xC4000073, 0x1234_0000, 0x10_0000, 0xffff_1234_ffff, 0x1000]
1433 );
1434 }
1435
1436 #[test]
1437 fn ffa_mem_retrieve_req_serde() {
1438 test_regs_serde!(
1439 Interface::MemRetrieveReq {
1440 total_len: 0x1234_5678,
1441 frag_len: 0xabcd,
1442 buf: None
1443 },
1444 [0x84000074, 0x1234_5678, 0xabcd]
1445 );
1446 test_regs_serde!(
1447 Interface::MemRetrieveReq {
1448 total_len: 0x1234_5678,
1449 frag_len: 0xabcd,
1450 buf: Some(MemOpBuf::Buf32 {
1451 addr: 0xdead_beef,
1452 page_cnt: 0x1000
1453 })
1454 },
1455 [0x84000074, 0x1234_5678, 0xabcd, 0xdead_beef, 0x1000]
1456 );
1457 test_regs_serde!(
1458 Interface::MemRetrieveReq {
1459 total_len: 0x1234_5678,
1460 frag_len: 0xabcd,
1461 buf: Some(MemOpBuf::Buf64 {
1462 addr: 0xdead_0000_beef,
1463 page_cnt: 0x1000
1464 })
1465 },
1466 [0xC4000074, 0x1234_5678, 0xabcd, 0xdead_0000_beef, 0x1000]
1467 );
1468 }
1469
1470 #[test]
1471 fn ffa_mem_retrieve_resp_serde() {
1472 test_regs_serde!(
1473 Interface::MemRetrieveResp {
1474 total_len: 0xaaaa_bbbb,
1475 frag_len: 0xaaaa_0000
1476 },
1477 [0x84000075, 0xaaaa_bbbb, 0xaaaa_0000]
1478 );
1479 }
1480
1481 #[test]
1482 fn ffa_mem_relinquish_serde() {
1483 test_regs_serde!(Interface::MemRelinquish, [0x84000076]);
1484 }
1485
1486 #[test]
1487 fn ffa_mem_reclaim_serde() {
1488 test_regs_serde!(
1489 Interface::MemReclaim {
1490 handle: Handle(0x1234_ffff_1234),
1491 flags: MemReclaimFlags {
1492 zero_memory: true,
1493 time_slicing: true
1494 }
1495 },
1496 [0x84000077, 0xffff_1234, 0x1234, 0b11]
1497 );
1498 }
1499
1500 #[test]
1501 fn ffa_mem_perm_get_serde() {
1502 test_regs_serde!(
1503 Interface::MemPermGet {
1504 addr: MemAddr::Addr32(0xdead_beef),
1505 page_cnt: 1
1506 },
1507 [0x84000088, 0xdead_beef]
1508 );
1509 test_args_serde!(
1510 SuccessArgs::Args32([0b001, 0x1234_abcd, 0, 0, 0, 0]),
1511 SuccessArgsMemPermGet {
1512 perm: MemPermissionsGetSet {
1513 data_access: DataAccessPermGetSet::ReadWrite,
1514 instr_access: InstructionAccessPermGetSet::Executable
1515 },
1516 page_cnt: 0x1234_abce
1517 }
1518 );
1519 }
1520
1521 #[test]
1522 fn ffa_mem_perm_set_serde() {
1523 test_regs_serde!(
1524 Interface::MemPermSet {
1525 addr: MemAddr::Addr64(0x1234_5678_abcd),
1526 page_cnt: 0x1000,
1527 mem_perm: MemPermissionsGetSet {
1528 data_access: DataAccessPermGetSet::ReadOnly,
1529 instr_access: InstructionAccessPermGetSet::NonExecutable
1530 }
1531 },
1532 [0xC4000089, 0x1234_5678_abcd, 0x1000, 0b111]
1533 );
1534 }
1535
1536 #[test]
1537 fn ffa_mem_op_pause_serde() {
1538 test_regs_serde!(
1539 Interface::MemOpPause {
1540 handle: Handle(0xaaaa_bbbb_cccc_dddd)
1541 },
1542 [0x84000078, 0xcccc_dddd, 0xaaaa_bbbb]
1543 );
1544 }
1545
1546 #[test]
1547 fn ffa_mem_op_resume_serde() {
1548 test_regs_serde!(
1549 Interface::MemOpResume {
1550 handle: Handle(0xaaaa_bbbb_cccc_dddd)
1551 },
1552 [0x84000079, 0xcccc_dddd, 0xaaaa_bbbb]
1553 );
1554 }
1555
1556 #[test]
1557 fn ffa_mem_frag_rx_serde() {
1558 test_regs_serde!(
1559 Interface::MemFragRx {
1560 handle: Handle(0xaaaa_bbbb_cccc_dddd),
1561 frag_offset: 0x1234_5678,
1562 endpoint_id: 0xabcd
1563 },
1564 [
1565 0x8400007A,
1566 0xcccc_dddd,
1567 0xaaaa_bbbb,
1568 0x1234_5678,
1569 0xabcd_0000
1570 ]
1571 );
1572 }
1573
1574 #[test]
1575 fn ffa_mem_frag_tx_serde() {
1576 test_regs_serde!(
1577 Interface::MemFragTx {
1578 handle: Handle(0xaaaa_bbbb_cccc_dddd),
1579 frag_len: 0x1234_5678,
1580 endpoint_id: 0xabcd
1581 },
1582 [
1583 0x8400007B,
1584 0xcccc_dddd,
1585 0xaaaa_bbbb,
1586 0x1234_5678,
1587 0xabcd_0000
1588 ]
1589 );
1590 }
1591
1592 #[test]
1593 fn parse_cacheability() {
1594 assert_eq!(
1595 Cacheability::try_from(0b0100),
1596 Ok(Cacheability::NonCacheable)
1597 );
1598 assert_eq!(Cacheability::try_from(0b1100), Ok(Cacheability::WriteBack));
1599
1600 assert!(Cacheability::try_from(0b1000).is_err());
1601 assert!(Cacheability::try_from(0b0000).is_err());
1602 }
1603
1604 #[test]
1605 fn parse_shareability() {
1606 assert_eq!(Shareability::try_from(0b00), Ok(Shareability::NonShareable));
1607 assert_eq!(Shareability::try_from(0b10), Ok(Shareability::Outer));
1608 assert_eq!(Shareability::try_from(0b11), Ok(Shareability::Inner));
1609
1610 assert!(Shareability::try_from(0b01).is_err());
1611 }
1612
1613 #[test]
1614 fn parse_device_memory_attributes() {
1615 assert_eq!(
1616 DeviceMemAttributes::try_from(0b0000),
1617 Ok(DeviceMemAttributes::DevnGnRnE)
1618 );
1619 assert_eq!(
1620 DeviceMemAttributes::try_from(0b0100),
1621 Ok(DeviceMemAttributes::DevnGnRE)
1622 );
1623 assert_eq!(
1624 DeviceMemAttributes::try_from(0b1000),
1625 Ok(DeviceMemAttributes::DevnGRE)
1626 );
1627 assert_eq!(
1628 DeviceMemAttributes::try_from(0b1100),
1629 Ok(DeviceMemAttributes::DevGRE)
1630 );
1631 }
1632
1633 #[test]
1634 fn parse_memory_type() {
1635 assert_eq!(MemType::try_from(0x00), Ok(MemType::NotSpecified));
1636 assert_eq!(
1637 MemType::try_from(0x10),
1638 Ok(MemType::Device(DeviceMemAttributes::DevnGnRnE))
1639 );
1640 assert_eq!(
1641 MemType::try_from(0x2f),
1642 Ok(MemType::Normal {
1643 cacheability: Cacheability::WriteBack,
1644 shareability: Shareability::Inner
1645 })
1646 );
1647
1648 assert!(MemType::try_from(0x30).is_err());
1649 }
1650
1651 #[test]
1652 fn parse_instruction_access_permissions() {
1653 assert_eq!(
1654 InstuctionAccessPerm::try_from(0b0000),
1655 Ok(InstuctionAccessPerm::NotSpecified)
1656 );
1657 assert_eq!(
1658 InstuctionAccessPerm::try_from(0b0100),
1659 Ok(InstuctionAccessPerm::NotExecutable)
1660 );
1661 assert_eq!(
1662 InstuctionAccessPerm::try_from(0b1000),
1663 Ok(InstuctionAccessPerm::Executable)
1664 );
1665
1666 assert!(InstuctionAccessPerm::try_from(0b1100).is_err());
1667 }
1668
1669 #[test]
1670 fn parse_data_access_permissions() {
1671 assert_eq!(
1672 DataAccessPerm::try_from(0b00),
1673 Ok(DataAccessPerm::NotSpecified)
1674 );
1675 assert_eq!(DataAccessPerm::try_from(0b01), Ok(DataAccessPerm::ReadOnly));
1676 assert_eq!(
1677 DataAccessPerm::try_from(0b10),
1678 Ok(DataAccessPerm::ReadWrite)
1679 );
1680
1681 assert!(DataAccessPerm::try_from(0b11).is_err());
1682 }
1683}