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)]
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 size_of::<endpoint_memory_access_descriptor>()
666 != transaction_desc_raw.endpoint_mem_access_desc_size as usize
667 {
668 return Err(Error::MalformedDescriptor);
669 }
670
671 if transaction_desc_raw.endpoint_mem_access_desc_count == 0 {
672 return Err(Error::MalformedDescriptor);
673 }
674
675 let Some(total_desc_size) = transaction_desc_raw
676 .endpoint_mem_access_desc_size
677 .checked_mul(transaction_desc_raw.endpoint_mem_access_desc_count)
678 .and_then(|x| {
679 x.checked_add(transaction_desc_raw.endpoint_mem_access_desc_array_offset)
680 })
681 else {
682 return Err(Error::InvalidBufferSize);
683 };
684
685 if buf.len() < total_desc_size as usize {
686 return Err(Error::InvalidBufferSize);
687 }
688
689 let transaction_desc = MemTransactionDesc {
690 sender_id: transaction_desc_raw.sender_endpoint_id,
691 mem_region_attr: transaction_desc_raw.memory_region_attributes.try_into()?,
692 flags: MemTransactionFlags(transaction_desc_raw.flags),
693 handle: Handle(transaction_desc_raw.handle),
694 tag: transaction_desc_raw.tag,
695 };
696
697 let mut offset = transaction_desc_raw.endpoint_mem_access_desc_array_offset as usize;
698
699 let access_desc_iter = MemAccessPermIterator::new(
700 buf,
701 transaction_desc_raw.endpoint_mem_access_desc_count as usize,
702 offset,
703 )?;
704
705 let Ok(desc_raw) = endpoint_memory_access_descriptor::ref_from_bytes(
707 &buf[offset..offset + size_of::<endpoint_memory_access_descriptor>()],
708 ) else {
709 return Err(Error::MalformedDescriptor);
710 };
711
712 offset = desc_raw.composite_offset as usize;
713
714 if offset == 0 {
717 return Ok((transaction_desc, access_desc_iter, None));
718 }
719
720 let Some(composite_desc_bytes) =
721 buf.get(offset..offset + size_of::<composite_memory_region_descriptor>())
722 else {
723 return Err(Error::InvalidBufferSize);
724 };
725
726 let Ok(composite_desc_raw) =
727 composite_memory_region_descriptor::ref_from_bytes(composite_desc_bytes)
728 else {
729 return Err(Error::MalformedDescriptor);
730 };
731
732 let constituent_iter = ConstituentMemRegionIterator::new(
733 buf,
734 composite_desc_raw.address_range_count as usize,
735 composite_desc_raw.total_page_count,
736 offset + Self::CONSTITUENT_ARRAY_OFFSET,
737 )?;
738
739 Ok((transaction_desc, access_desc_iter, Some(constituent_iter)))
740 }
741}
742
743pub struct EndpointIterator<'a> {
745 buf: &'a [u8],
746 offset: usize,
747 count: usize,
748}
749
750impl<'a> EndpointIterator<'a> {
751 fn new(buf: &'a [u8], count: usize, offset: usize) -> Result<Self, Error> {
753 let Some(total_size) = count.checked_mul(size_of::<u16>()) else {
754 return Err(Error::InvalidBufferSize);
755 };
756
757 if buf.len() < total_size {
758 return Err(Error::InvalidBufferSize);
759 }
760
761 Ok(Self { buf, offset, count })
762 }
763}
764
765impl Iterator for EndpointIterator<'_> {
766 type Item = u16;
767
768 fn next(&mut self) -> Option<Self::Item> {
769 if self.count > 0 {
770 let offset = self.offset;
771 self.offset += size_of::<Self::Item>();
772 self.count -= 1;
773
774 let endpoint = u16::from_le_bytes([self.buf[offset], self.buf[offset + 1]]);
775 return Some(endpoint);
776 }
777
778 None
779 }
780}
781
782#[derive(Debug, Default, PartialEq, Eq, Clone)]
784pub struct MemRelinquishDesc {
785 pub handle: Handle,
786 pub flags: u32,
787}
788
789impl MemRelinquishDesc {
790 const ENDPOINT_ARRAY_OFFSET: usize = size_of::<memory_relinquish_descriptor>();
791
792 pub fn pack(&self, endpoints: &[u16], buf: &mut [u8]) -> usize {
794 if let Ok((desc_raw, endpoint_area)) = memory_relinquish_descriptor::mut_from_prefix(buf) {
795 desc_raw.handle = self.handle.0;
796 desc_raw.flags = self.flags;
797 desc_raw.endpoint_count = endpoints.len().try_into().unwrap();
798
799 for (endpoint, dest) in endpoints
800 .iter()
801 .zip(endpoint_area[..endpoints.len() * 2].chunks_exact_mut(2))
802 {
803 [dest[0], dest[1]] = u16::to_le_bytes(*endpoint);
804 }
805 }
806
807 Self::ENDPOINT_ARRAY_OFFSET + endpoints.len() * 2
808 }
809
810 pub fn unpack(buf: &[u8]) -> Result<(MemRelinquishDesc, EndpointIterator<'_>), Error> {
813 let Some(desc_bytes) = buf.get(0..size_of::<memory_relinquish_descriptor>()) else {
814 return Err(Error::InvalidBufferSize);
815 };
816
817 let Ok(desc_raw) = memory_relinquish_descriptor::ref_from_bytes(desc_bytes) else {
818 return Err(Error::MalformedDescriptor);
819 };
820
821 let Some(total_desc_size) = (desc_raw.endpoint_count as usize)
822 .checked_mul(size_of::<u16>())
823 .and_then(|x| x.checked_add(Self::ENDPOINT_ARRAY_OFFSET))
824 else {
825 return Err(Error::InvalidBufferSize);
826 };
827
828 if buf.len() < total_desc_size {
829 return Err(Error::InvalidBufferSize);
830 }
831
832 let iterator = EndpointIterator::new(
833 buf,
834 desc_raw.endpoint_count as usize,
835 Self::ENDPOINT_ARRAY_OFFSET,
836 )?;
837
838 Ok((
839 Self {
840 handle: Handle(desc_raw.handle),
841 flags: desc_raw.flags, },
843 iterator,
844 ))
845 }
846}
847
848#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
850pub struct MemReclaimFlags {
851 pub zero_memory: bool,
852 pub time_slicing: bool,
853}
854
855impl MemReclaimFlags {
856 pub const ZERO_MEMORY: u32 = 0b1 << 0;
857 pub const TIME_SLICING: u32 = 0b1 << 1;
858 const MBZ_BITS: u32 = 0xffff_fffc;
859}
860
861impl TryFrom<u32> for MemReclaimFlags {
862 type Error = crate::Error;
863
864 fn try_from(val: u32) -> Result<Self, Self::Error> {
865 if (val & Self::MBZ_BITS) != 0 {
866 Err(crate::Error::InvalidMemReclaimFlags(val))
867 } else {
868 Ok(MemReclaimFlags {
869 zero_memory: val & Self::ZERO_MEMORY != 0,
870 time_slicing: val & Self::TIME_SLICING != 0,
871 })
872 }
873 }
874}
875
876impl From<MemReclaimFlags> for u32 {
877 fn from(flags: MemReclaimFlags) -> Self {
878 let mut bits: u32 = 0;
879 if flags.zero_memory {
880 bits |= MemReclaimFlags::ZERO_MEMORY;
881 }
882 if flags.time_slicing {
883 bits |= MemReclaimFlags::TIME_SLICING;
884 }
885 bits
886 }
887}
888
889#[derive(Debug, Eq, PartialEq, Clone, Copy)]
891pub struct SuccessArgsMemOp {
892 pub handle: Handle,
893}
894
895impl From<SuccessArgsMemOp> for SuccessArgs {
896 fn from(value: SuccessArgsMemOp) -> Self {
897 let [handle_lo, handle_hi]: [u32; 2] = value.handle.into();
898 SuccessArgs::Args32([handle_lo, handle_hi, 0, 0, 0, 0])
899 }
900}
901
902impl TryFrom<SuccessArgs> for SuccessArgsMemOp {
903 type Error = crate::Error;
904
905 fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
906 let [handle_lo, handle_hi, ..] = value.try_get_args32()?;
907 Ok(Self {
908 handle: [handle_lo, handle_hi].into(),
909 })
910 }
911}
912
913#[derive(Debug, Clone, Copy, PartialEq, Eq)]
915#[repr(u32)]
916pub enum DataAccessPermGetSet {
917 NoAccess = Self::NO_ACCESS << Self::SHIFT,
918 ReadWrite = Self::READ_WRITE << Self::SHIFT,
919 ReadOnly = Self::READ_ONLY << Self::SHIFT,
920}
921
922impl DataAccessPermGetSet {
923 const SHIFT: usize = 0;
924 const MASK: u32 = 0b11;
925 const NO_ACCESS: u32 = 0b00;
926 const READ_WRITE: u32 = 0b01;
927 const READ_ONLY: u32 = 0b11;
928}
929
930impl TryFrom<u32> for DataAccessPermGetSet {
931 type Error = Error;
932
933 fn try_from(value: u32) -> Result<Self, Self::Error> {
934 match (value >> Self::SHIFT) & Self::MASK {
935 Self::NO_ACCESS => Ok(Self::NoAccess),
936 Self::READ_WRITE => Ok(Self::ReadWrite),
937 Self::READ_ONLY => Ok(Self::ReadOnly),
938 _ => Err(Error::InvalidDataAccessPermGetSet(value)),
939 }
940 }
941}
942
943#[derive(Debug, Clone, Copy, PartialEq, Eq)]
945#[repr(u32)]
946pub enum InstructionAccessPermGetSet {
947 Executable = Self::EXECUTABLE << Self::SHIFT,
948 NonExecutable = Self::NON_EXECUTABLE << Self::SHIFT,
949}
950
951impl InstructionAccessPermGetSet {
952 const SHIFT: usize = 2;
953 const MASK: u32 = 0b1;
954 const EXECUTABLE: u32 = 0b0;
955 const NON_EXECUTABLE: u32 = 0b1;
956}
957
958impl TryFrom<u32> for InstructionAccessPermGetSet {
959 type Error = Error;
960
961 fn try_from(value: u32) -> Result<Self, Self::Error> {
962 match (value >> Self::SHIFT) & Self::MASK {
963 Self::EXECUTABLE => Ok(Self::Executable),
964 Self::NON_EXECUTABLE => Ok(Self::NonExecutable),
965 _ => Err(Error::InvalidInstrAccessPermGetSet(value)),
966 }
967 }
968}
969
970#[derive(Debug, Clone, Copy, PartialEq, Eq)]
972pub struct MemPermissionsGetSet {
973 pub data_access: DataAccessPermGetSet,
974 pub instr_access: InstructionAccessPermGetSet,
975}
976
977impl TryFrom<u32> for MemPermissionsGetSet {
978 type Error = Error;
979
980 fn try_from(value: u32) -> Result<Self, Self::Error> {
981 Ok(Self {
982 data_access: value.try_into()?,
983 instr_access: value.try_into()?,
984 })
985 }
986}
987
988impl From<MemPermissionsGetSet> for u32 {
989 fn from(value: MemPermissionsGetSet) -> Self {
990 value.data_access as u32 | value.instr_access as u32
991 }
992}
993
994#[derive(Debug, Eq, PartialEq, Clone, Copy)]
996pub struct SuccessArgsMemPermGet {
997 pub perm: MemPermissionsGetSet,
998 pub page_cnt: u32,
999}
1000
1001impl From<SuccessArgsMemPermGet> for SuccessArgs {
1002 fn from(value: SuccessArgsMemPermGet) -> Self {
1003 assert_ne!(value.page_cnt, 0);
1004 SuccessArgs::Args32([value.perm.into(), value.page_cnt - 1, 0, 0, 0, 0])
1005 }
1006}
1007
1008impl TryFrom<SuccessArgs> for SuccessArgsMemPermGet {
1009 type Error = crate::Error;
1010
1011 fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
1012 let [perm, page_cnt, ..] = value.try_get_args32()?;
1013 Ok(Self {
1014 perm: perm.try_into()?,
1015 page_cnt: page_cnt.checked_add(1).ok_or(Error::InvalidPageCount)?,
1016 })
1017 }
1018}
1019
1020#[cfg(test)]
1021mod tests {
1022 use crate::{
1023 tests::{test_args_serde, test_regs_serde},
1024 Interface, MemAddr, MemOpBuf, Version,
1025 };
1026
1027 use super::*;
1028
1029 const MEM_SHARE_FROM_SP1: &[u8] = &[
1030 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56, 0x34,
1031 0x12, 0xef, 0xbe, 0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1032 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1033 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1034 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1035 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
1036 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1037 ];
1038
1039 const MEM_SHARE_FROM_SP2: &[u8] = &[
1040 0x06, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56, 0x34,
1041 0x12, 0xef, 0xbe, 0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1042 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1043 0x00, 0x00, 0x00, 0x05, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1044 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1045 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x07, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
1046 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1047 ];
1048
1049 macro_rules! test_memory_desc_packing {
1050 ($buf:expr, $desc:expr, $perms:expr, $constituents:expr) => {
1051 let (transaction_desc, access_desc, constituents) =
1052 MemTransactionDesc::unpack($buf).unwrap();
1053
1054 assert_eq!(transaction_desc, $desc);
1055
1056 let perms: Vec<_> = access_desc.map(|e| e.unwrap()).collect();
1057 assert_eq!(perms, &$perms);
1058
1059 let constituents = constituents.unwrap();
1060 let constituents: Vec<_> = constituents.map(|c| c.unwrap()).collect();
1061 assert_eq!(constituents, &$constituents);
1062
1063 let mut buf = [0x88; 4096];
1065 let size = $desc.pack(&$constituents, &$perms, &mut buf);
1066
1067 assert_eq!(size, $buf.len());
1068 assert_eq!(&buf[0..size], $buf);
1069 };
1070 }
1071
1072 #[test]
1073 fn mem_share_pack() {
1074 test_memory_desc_packing!(
1075 MEM_SHARE_FROM_SP1,
1076 MemTransactionDesc {
1077 sender_id: 0x8005,
1078 mem_region_attr: MemRegionAttributes {
1079 security: MemRegionSecurity::Secure,
1080 mem_type: MemType::Normal {
1081 cacheability: Cacheability::WriteBack,
1082 shareability: Shareability::Inner,
1083 },
1084 },
1085 flags: MemTransactionFlags(0),
1086 handle: Handle(0x1234_5678_90ab_cdef),
1087 tag: 0xdead_0000_beef,
1088 },
1089 [MemAccessPerm {
1090 endpoint_id: 0x8003,
1091 instr_access: InstuctionAccessPerm::NotSpecified,
1092 data_access: DataAccessPerm::ReadWrite,
1093 flags: 0x0,
1094 }],
1095 [ConstituentMemRegion {
1096 address: 0x4010f000,
1097 page_cnt: 0x1,
1098 }]
1099 );
1100
1101 test_memory_desc_packing!(
1102 MEM_SHARE_FROM_SP2,
1103 MemTransactionDesc {
1104 sender_id: 0x8006,
1105 mem_region_attr: MemRegionAttributes {
1106 security: MemRegionSecurity::Secure,
1107 mem_type: MemType::Normal {
1108 cacheability: Cacheability::WriteBack,
1109 shareability: Shareability::Inner,
1110 },
1111 },
1112 flags: MemTransactionFlags(0),
1113 handle: Handle(0x1234_5678_90ab_cdef),
1114 tag: 0xdead_0000_beef,
1115 },
1116 [MemAccessPerm {
1117 endpoint_id: 0x8005,
1118 instr_access: InstuctionAccessPerm::NotSpecified,
1119 data_access: DataAccessPerm::ReadWrite,
1120 flags: 0x0,
1121 }],
1122 [ConstituentMemRegion {
1123 address: 0x40074000,
1124 page_cnt: 0x1,
1125 }]
1126 );
1127 }
1128
1129 #[test]
1130 fn mem_tx_unpack_err1() {
1131 assert!(MemTransactionDesc::unpack(&[0; 3]).is_err());
1132 }
1133
1134 #[test]
1135 fn mem_tx_unpack_err2() {
1136 assert!(MemTransactionDesc::unpack(&[
1138 0x06, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20,
1139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1140 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1142 ])
1143 .is_err());
1144 }
1145
1146 #[test]
1147 fn mem_tx_unpack_err3() {
1148 assert!(MemTransactionDesc::unpack(&[
1150 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56,
1151 0x34, 0x12, 0xef, 0xbe, 0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1152 0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x04, 0x80, 0x02, 0x00
1154 ])
1155 .is_err());
1156 }
1157
1158 #[test]
1159 fn mem_tx_unpack_err4() {
1160 assert!(MemTransactionDesc::unpack(&[
1162 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56,
1163 0x34, 0x12, 0xef, 0xbe, 0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1164 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
1166 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1167 ])
1168 .is_err());
1169 }
1170
1171 #[test]
1172 fn mem_tx_unpack_err5() {
1173 assert!(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, 0x18, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1180 0x00, 0x00
1181 ])
1182 .is_err());
1183 }
1184
1185 #[test]
1186 fn mem_tx_unpack_err6() {
1187 assert!(MemTransactionDesc::unpack(&[
1189 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56,
1190 0x34, 0x12, 0xef, 0xbe, 0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1191 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1192 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1193 ])
1194 .is_err());
1195 }
1196
1197 #[test]
1198 fn mem_tx_unpack_err7() {
1199 assert!(MemTransactionDesc::unpack(&[
1201 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56,
1202 0x34, 0x12, 0xef, 0xbe, 0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1203 0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1204 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
1205 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1206 ])
1207 .is_err());
1208 }
1209
1210 #[test]
1211 fn mem_tx_unpack_err8() {
1212 assert!(MemTransactionDesc::unpack(&[
1214 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56,
1215 0x34, 0x12, 0xef, 0xbe, 0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1216 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1217 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x80, 0x00, 0x00, 0x00,
1218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
1219 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x10, 0x40,
1220 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1221 ])
1222 .is_err());
1223 }
1224
1225 #[test]
1226 fn mem_tx_unpack_err9() {
1227 assert!(MemTransactionDesc::unpack(&[
1229 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56,
1230 0x34, 0x12, 0xef, 0xbe, 0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1231 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1232 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00,
1233 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
1234 ])
1235 .is_err());
1236 }
1237
1238 #[test]
1239 fn mem_relinquish_pack() {
1240 let expected_desc = MemRelinquishDesc {
1241 handle: Handle(0x1234_5678),
1242 flags: MemTransactionFlags::ZERO_MEMORY | MemTransactionFlags::TIME_SLICING,
1243 };
1244 let expected_endpoints: &[u16] = &[0x13, 0x1234, 0xbeef];
1245
1246 let expected_buf: &[u8] = &[
1247 0x78, 0x56, 0x34, 0x12, 0, 0, 0, 0, 0b11, 0, 0, 0, 0x3, 0, 0, 0, 0x13, 0, 0x34, 0x12,
1248 0xef, 0xbe,
1249 ];
1250
1251 let (actual_desc, actual_endpoints) = MemRelinquishDesc::unpack(expected_buf).unwrap();
1252 assert_eq!(actual_desc, expected_desc);
1253 assert_eq!(actual_endpoints.collect::<Vec<_>>(), expected_endpoints);
1254
1255 let mut buf = [0; 128];
1256 let size = expected_desc.pack(expected_endpoints, &mut buf);
1257
1258 println!("{buf:x?}");
1259
1260 assert_eq!(size, expected_buf.len());
1261 assert_eq!(&buf[0..size], expected_buf);
1262 }
1263
1264 #[test]
1265 fn mem_relinquish_unpack_err1() {
1266 assert!(MemRelinquishDesc::unpack(&[0; 4]).is_err());
1267 }
1268
1269 #[test]
1270 fn mem_relinquish_unpack_err2() {
1271 assert!(MemRelinquishDesc::unpack(&[
1273 0x78, 0x56, 0x34, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
1274 ])
1275 .is_err());
1276 }
1277
1278 #[test]
1279 fn mem_relinquish_unpack_err3() {
1280 assert!(MemRelinquishDesc::unpack(&[
1282 0x78, 0x56, 0x34, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0,
1283 0xab, 0xcd,
1284 ])
1285 .is_err());
1286 }
1287
1288 #[test]
1289 fn ffa_mem_donate_serde() {
1290 test_regs_serde!(
1291 Interface::MemDonate {
1292 total_len: 0x1234_5678,
1293 frag_len: 0xabcd,
1294 buf: None
1295 },
1296 [0x84000071, 0x1234_5678, 0xabcd]
1297 );
1298 test_regs_serde!(
1299 Interface::MemDonate {
1300 total_len: 0x1234_5678,
1301 frag_len: 0xabcd,
1302 buf: Some(MemOpBuf::Buf32 {
1303 addr: 0xdead_beef,
1304 page_cnt: 0x1000
1305 })
1306 },
1307 [0x84000071, 0x1234_5678, 0xabcd, 0xdead_beef, 0x1000]
1308 );
1309 test_regs_serde!(
1310 Interface::MemDonate {
1311 total_len: 0x1234_5678,
1312 frag_len: 0xabcd,
1313 buf: Some(MemOpBuf::Buf64 {
1314 addr: 0xdead_0000_beef,
1315 page_cnt: 0x1000
1316 })
1317 },
1318 [0xC4000071, 0x1234_5678, 0xabcd, 0xdead_0000_beef, 0x1000]
1319 );
1320 test_args_serde!(
1321 SuccessArgs::Args32([0x5678_def0, 0x1234_abcd, 0, 0, 0, 0]),
1322 SuccessArgsMemOp {
1323 handle: Handle(0x1234_abcd_5678_def0)
1324 }
1325 );
1326 }
1327
1328 #[test]
1329 fn ffa_mem_lend_serde() {
1330 test_regs_serde!(
1331 Interface::MemLend {
1332 total_len: 0x1234_0000,
1333 frag_len: 0x10_0000,
1334 buf: None
1335 },
1336 [0x84000072, 0x1234_0000, 0x10_0000]
1337 );
1338 test_regs_serde!(
1339 Interface::MemLend {
1340 total_len: 0x1234_0000,
1341 frag_len: 0x10_0000,
1342 buf: Some(MemOpBuf::Buf32 {
1343 addr: 0xffff_ffff,
1344 page_cnt: 0x1000
1345 })
1346 },
1347 [0x84000072, 0x1234_0000, 0x10_0000, 0xffff_ffff, 0x1000]
1348 );
1349 test_regs_serde!(
1350 Interface::MemLend {
1351 total_len: 0x1234_0000,
1352 frag_len: 0x10_0000,
1353 buf: Some(MemOpBuf::Buf64 {
1354 addr: 0xffff_1234_ffff,
1355 page_cnt: 0x1000
1356 })
1357 },
1358 [0xC4000072, 0x1234_0000, 0x10_0000, 0xffff_1234_ffff, 0x1000]
1359 );
1360 }
1361
1362 #[test]
1363 fn ffa_mem_share_serde() {
1364 test_regs_serde!(
1365 Interface::MemShare {
1366 total_len: 0x1234_0000,
1367 frag_len: 0x10_0000,
1368 buf: None
1369 },
1370 [0x84000073, 0x1234_0000, 0x10_0000]
1371 );
1372 test_regs_serde!(
1373 Interface::MemShare {
1374 total_len: 0x1234_0000,
1375 frag_len: 0x10_0000,
1376 buf: Some(MemOpBuf::Buf32 {
1377 addr: 0x1234_5678,
1378 page_cnt: 0x1000
1379 })
1380 },
1381 [0x84000073, 0x1234_0000, 0x10_0000, 0x1234_5678, 0x1000]
1382 );
1383 test_regs_serde!(
1384 Interface::MemShare {
1385 total_len: 0x1234_0000,
1386 frag_len: 0x10_0000,
1387 buf: Some(MemOpBuf::Buf64 {
1388 addr: 0xffff_1234_ffff,
1389 page_cnt: 0x1000
1390 })
1391 },
1392 [0xC4000073, 0x1234_0000, 0x10_0000, 0xffff_1234_ffff, 0x1000]
1393 );
1394 }
1395
1396 #[test]
1397 fn ffa_mem_retrieve_req_serde() {
1398 test_regs_serde!(
1399 Interface::MemRetrieveReq {
1400 total_len: 0x1234_5678,
1401 frag_len: 0xabcd,
1402 buf: None
1403 },
1404 [0x84000074, 0x1234_5678, 0xabcd]
1405 );
1406 test_regs_serde!(
1407 Interface::MemRetrieveReq {
1408 total_len: 0x1234_5678,
1409 frag_len: 0xabcd,
1410 buf: Some(MemOpBuf::Buf32 {
1411 addr: 0xdead_beef,
1412 page_cnt: 0x1000
1413 })
1414 },
1415 [0x84000074, 0x1234_5678, 0xabcd, 0xdead_beef, 0x1000]
1416 );
1417 test_regs_serde!(
1418 Interface::MemRetrieveReq {
1419 total_len: 0x1234_5678,
1420 frag_len: 0xabcd,
1421 buf: Some(MemOpBuf::Buf64 {
1422 addr: 0xdead_0000_beef,
1423 page_cnt: 0x1000
1424 })
1425 },
1426 [0xC4000074, 0x1234_5678, 0xabcd, 0xdead_0000_beef, 0x1000]
1427 );
1428 }
1429
1430 #[test]
1431 fn ffa_mem_retrieve_resp_serde() {
1432 test_regs_serde!(
1433 Interface::MemRetrieveResp {
1434 total_len: 0xaaaa_bbbb,
1435 frag_len: 0xaaaa_0000
1436 },
1437 [0x84000075, 0xaaaa_bbbb, 0xaaaa_0000]
1438 );
1439 }
1440
1441 #[test]
1442 fn ffa_mem_relinquish_serde() {
1443 test_regs_serde!(Interface::MemRelinquish, [0x84000076]);
1444 }
1445
1446 #[test]
1447 fn ffa_mem_reclaim_serde() {
1448 test_regs_serde!(
1449 Interface::MemReclaim {
1450 handle: Handle(0x1234_ffff_1234),
1451 flags: MemReclaimFlags {
1452 zero_memory: true,
1453 time_slicing: true
1454 }
1455 },
1456 [0x84000077, 0xffff_1234, 0x1234, 0b11]
1457 );
1458 }
1459
1460 #[test]
1461 fn ffa_mem_perm_get_serde() {
1462 test_regs_serde!(
1463 Interface::MemPermGet {
1464 addr: MemAddr::Addr32(0xdead_beef),
1465 page_cnt: 1
1466 },
1467 [0x84000088, 0xdead_beef]
1468 );
1469 test_args_serde!(
1470 SuccessArgs::Args32([0b001, 0x1234_abcd, 0, 0, 0, 0]),
1471 SuccessArgsMemPermGet {
1472 perm: MemPermissionsGetSet {
1473 data_access: DataAccessPermGetSet::ReadWrite,
1474 instr_access: InstructionAccessPermGetSet::Executable
1475 },
1476 page_cnt: 0x1234_abce
1477 }
1478 );
1479 }
1480
1481 #[test]
1482 fn ffa_mem_perm_set_serde() {
1483 test_regs_serde!(
1484 Interface::MemPermSet {
1485 addr: MemAddr::Addr64(0x1234_5678_abcd),
1486 page_cnt: 0x1000,
1487 mem_perm: MemPermissionsGetSet {
1488 data_access: DataAccessPermGetSet::ReadOnly,
1489 instr_access: InstructionAccessPermGetSet::NonExecutable
1490 }
1491 },
1492 [0xC4000089, 0x1234_5678_abcd, 0x1000, 0b111]
1493 );
1494 }
1495
1496 #[test]
1497 fn ffa_mem_op_pause_serde() {
1498 test_regs_serde!(
1499 Interface::MemOpPause {
1500 handle: Handle(0xaaaa_bbbb_cccc_dddd)
1501 },
1502 [0x84000078, 0xcccc_dddd, 0xaaaa_bbbb]
1503 );
1504 }
1505
1506 #[test]
1507 fn ffa_mem_op_resume_serde() {
1508 test_regs_serde!(
1509 Interface::MemOpResume {
1510 handle: Handle(0xaaaa_bbbb_cccc_dddd)
1511 },
1512 [0x84000079, 0xcccc_dddd, 0xaaaa_bbbb]
1513 );
1514 }
1515
1516 #[test]
1517 fn ffa_mem_frag_rx_serde() {
1518 test_regs_serde!(
1519 Interface::MemFragRx {
1520 handle: Handle(0xaaaa_bbbb_cccc_dddd),
1521 frag_offset: 0x1234_5678,
1522 endpoint_id: 0xabcd
1523 },
1524 [
1525 0x8400007A,
1526 0xcccc_dddd,
1527 0xaaaa_bbbb,
1528 0x1234_5678,
1529 0xabcd_0000
1530 ]
1531 );
1532 }
1533
1534 #[test]
1535 fn ffa_mem_frag_tx_serde() {
1536 test_regs_serde!(
1537 Interface::MemFragTx {
1538 handle: Handle(0xaaaa_bbbb_cccc_dddd),
1539 frag_len: 0x1234_5678,
1540 endpoint_id: 0xabcd
1541 },
1542 [
1543 0x8400007B,
1544 0xcccc_dddd,
1545 0xaaaa_bbbb,
1546 0x1234_5678,
1547 0xabcd_0000
1548 ]
1549 );
1550 }
1551
1552 #[test]
1553 fn parse_cacheability() {
1554 assert_eq!(
1555 Cacheability::try_from(0b0100),
1556 Ok(Cacheability::NonCacheable)
1557 );
1558 assert_eq!(Cacheability::try_from(0b1100), Ok(Cacheability::WriteBack));
1559
1560 assert!(Cacheability::try_from(0b1000).is_err());
1561 assert!(Cacheability::try_from(0b0000).is_err());
1562 }
1563
1564 #[test]
1565 fn parse_shareability() {
1566 assert_eq!(Shareability::try_from(0b00), Ok(Shareability::NonShareable));
1567 assert_eq!(Shareability::try_from(0b10), Ok(Shareability::Outer));
1568 assert_eq!(Shareability::try_from(0b11), Ok(Shareability::Inner));
1569
1570 assert!(Shareability::try_from(0b01).is_err());
1571 }
1572
1573 #[test]
1574 fn parse_device_memory_attributes() {
1575 assert_eq!(
1576 DeviceMemAttributes::try_from(0b0000),
1577 Ok(DeviceMemAttributes::DevnGnRnE)
1578 );
1579 assert_eq!(
1580 DeviceMemAttributes::try_from(0b0100),
1581 Ok(DeviceMemAttributes::DevnGnRE)
1582 );
1583 assert_eq!(
1584 DeviceMemAttributes::try_from(0b1000),
1585 Ok(DeviceMemAttributes::DevnGRE)
1586 );
1587 assert_eq!(
1588 DeviceMemAttributes::try_from(0b1100),
1589 Ok(DeviceMemAttributes::DevGRE)
1590 );
1591 }
1592
1593 #[test]
1594 fn parse_memory_type() {
1595 assert_eq!(MemType::try_from(0x00), Ok(MemType::NotSpecified));
1596 assert_eq!(
1597 MemType::try_from(0x10),
1598 Ok(MemType::Device(DeviceMemAttributes::DevnGnRnE))
1599 );
1600 assert_eq!(
1601 MemType::try_from(0x2f),
1602 Ok(MemType::Normal {
1603 cacheability: Cacheability::WriteBack,
1604 shareability: Shareability::Inner
1605 })
1606 );
1607
1608 assert!(MemType::try_from(0x30).is_err());
1609 }
1610
1611 #[test]
1612 fn parse_instruction_access_permissions() {
1613 assert_eq!(
1614 InstuctionAccessPerm::try_from(0b0000),
1615 Ok(InstuctionAccessPerm::NotSpecified)
1616 );
1617 assert_eq!(
1618 InstuctionAccessPerm::try_from(0b0100),
1619 Ok(InstuctionAccessPerm::NotExecutable)
1620 );
1621 assert_eq!(
1622 InstuctionAccessPerm::try_from(0b1000),
1623 Ok(InstuctionAccessPerm::Executable)
1624 );
1625
1626 assert!(InstuctionAccessPerm::try_from(0b1100).is_err());
1627 }
1628
1629 #[test]
1630 fn parse_data_access_permissions() {
1631 assert_eq!(
1632 DataAccessPerm::try_from(0b00),
1633 Ok(DataAccessPerm::NotSpecified)
1634 );
1635 assert_eq!(DataAccessPerm::try_from(0b01), Ok(DataAccessPerm::ReadOnly));
1636 assert_eq!(
1637 DataAccessPerm::try_from(0b10),
1638 Ok(DataAccessPerm::ReadWrite)
1639 );
1640
1641 assert!(DataAccessPerm::try_from(0b11).is_err());
1642 }
1643}