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