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)]
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)]
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)]
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)]
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, Default)]
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)]
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) = memory_relinquish_descriptor::mut_from_bytes(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 let endpoint_area = &mut buf[Self::ENDPOINT_ARRAY_OFFSET..];
800
801 for (endpoint, dest) in endpoints
802 .iter()
803 .zip(endpoint_area[..endpoints.len() * 2].chunks_exact_mut(2))
804 {
805 [dest[0], dest[1]] = u16::to_le_bytes(*endpoint);
806 }
807 }
808
809 Self::ENDPOINT_ARRAY_OFFSET + endpoints.len() * 2
810 }
811
812 pub fn unpack(buf: &[u8]) -> Result<(MemRelinquishDesc, EndpointIterator), Error> {
815 let Some(desc_bytes) = buf.get(0..size_of::<memory_relinquish_descriptor>()) else {
816 return Err(Error::InvalidBufferSize);
817 };
818
819 let Ok(desc_raw) = memory_relinquish_descriptor::ref_from_bytes(desc_bytes) else {
820 return Err(Error::MalformedDescriptor);
821 };
822
823 let Some(total_desc_size) = (desc_raw.endpoint_count as usize)
824 .checked_mul(size_of::<u16>())
825 .and_then(|x| x.checked_add(Self::ENDPOINT_ARRAY_OFFSET))
826 else {
827 return Err(Error::InvalidBufferSize);
828 };
829
830 if buf.len() < total_desc_size {
831 return Err(Error::InvalidBufferSize);
832 }
833
834 let iterator = EndpointIterator::new(
835 buf,
836 desc_raw.endpoint_count as usize,
837 Self::ENDPOINT_ARRAY_OFFSET,
838 )?;
839
840 Ok((
841 Self {
842 handle: Handle(desc_raw.handle),
843 flags: desc_raw.flags, },
845 iterator,
846 ))
847 }
848}
849
850#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
852pub struct MemReclaimFlags {
853 pub zero_memory: bool,
854 pub time_slicing: bool,
855}
856
857impl MemReclaimFlags {
858 pub const ZERO_MEMORY: u32 = 0b1 << 0;
859 pub const TIME_SLICING: u32 = 0b1 << 1;
860 const MBZ_BITS: u32 = 0xffff_fffc;
861}
862
863impl TryFrom<u32> for MemReclaimFlags {
864 type Error = crate::Error;
865
866 fn try_from(val: u32) -> Result<Self, Self::Error> {
867 if (val & Self::MBZ_BITS) != 0 {
868 Err(crate::Error::InvalidMemReclaimFlags(val))
869 } else {
870 Ok(MemReclaimFlags {
871 zero_memory: val & Self::ZERO_MEMORY != 0,
872 time_slicing: val & Self::TIME_SLICING != 0,
873 })
874 }
875 }
876}
877
878impl From<MemReclaimFlags> for u32 {
879 fn from(flags: MemReclaimFlags) -> Self {
880 let mut bits: u32 = 0;
881 if flags.zero_memory {
882 bits |= MemReclaimFlags::ZERO_MEMORY;
883 }
884 if flags.time_slicing {
885 bits |= MemReclaimFlags::TIME_SLICING;
886 }
887 bits
888 }
889}
890
891#[derive(Debug, Eq, PartialEq, Clone, Copy)]
893pub struct SuccessArgsMemOp {
894 pub handle: Handle,
895}
896
897impl From<SuccessArgsMemOp> for SuccessArgs {
898 fn from(value: SuccessArgsMemOp) -> Self {
899 let [handle_lo, handle_hi]: [u32; 2] = value.handle.into();
900 SuccessArgs::Args32([handle_lo, handle_hi, 0, 0, 0, 0])
901 }
902}
903
904impl TryFrom<SuccessArgs> for SuccessArgsMemOp {
905 type Error = crate::Error;
906
907 fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
908 let [handle_lo, handle_hi, ..] = value.try_get_args32()?;
909 Ok(Self {
910 handle: [handle_lo, handle_hi].into(),
911 })
912 }
913}
914
915#[derive(Debug, Clone, Copy, PartialEq, Eq)]
917#[repr(u32)]
918pub enum DataAccessPermGetSet {
919 NoAccess = Self::NO_ACCESS << Self::SHIFT,
920 ReadWrite = Self::READ_WRITE << Self::SHIFT,
921 ReadOnly = Self::READ_ONLY << Self::SHIFT,
922}
923
924impl DataAccessPermGetSet {
925 const SHIFT: usize = 0;
926 const MASK: u32 = 0b11;
927 const NO_ACCESS: u32 = 0b00;
928 const READ_WRITE: u32 = 0b01;
929 const READ_ONLY: u32 = 0b11;
930}
931
932impl TryFrom<u32> for DataAccessPermGetSet {
933 type Error = Error;
934
935 fn try_from(value: u32) -> Result<Self, Self::Error> {
936 match (value >> Self::SHIFT) & Self::MASK {
937 Self::NO_ACCESS => Ok(Self::NoAccess),
938 Self::READ_WRITE => Ok(Self::ReadWrite),
939 Self::READ_ONLY => Ok(Self::ReadOnly),
940 _ => Err(Error::InvalidDataAccessPermGetSet(value)),
941 }
942 }
943}
944
945#[derive(Debug, Clone, Copy, PartialEq, Eq)]
947#[repr(u32)]
948pub enum InstructionAccessPermGetSet {
949 Executable = Self::EXECUTABLE << Self::SHIFT,
950 NonExecutable = Self::NON_EXECUTABLE << Self::SHIFT,
951}
952
953impl InstructionAccessPermGetSet {
954 const SHIFT: usize = 2;
955 const MASK: u32 = 0b1;
956 const EXECUTABLE: u32 = 0b0;
957 const NON_EXECUTABLE: u32 = 0b1;
958}
959
960impl TryFrom<u32> for InstructionAccessPermGetSet {
961 type Error = Error;
962
963 fn try_from(value: u32) -> Result<Self, Self::Error> {
964 match (value >> Self::SHIFT) & Self::MASK {
965 Self::EXECUTABLE => Ok(Self::Executable),
966 Self::NON_EXECUTABLE => Ok(Self::NonExecutable),
967 _ => Err(Error::InvalidInstrAccessPermGetSet(value)),
968 }
969 }
970}
971
972#[derive(Debug, Clone, Copy, PartialEq, Eq)]
974pub struct MemPermissionsGetSet {
975 pub data_access: DataAccessPermGetSet,
976 pub instr_access: InstructionAccessPermGetSet,
977}
978
979impl TryFrom<u32> for MemPermissionsGetSet {
980 type Error = Error;
981
982 fn try_from(value: u32) -> Result<Self, Self::Error> {
983 Ok(Self {
984 data_access: value.try_into()?,
985 instr_access: value.try_into()?,
986 })
987 }
988}
989
990impl From<MemPermissionsGetSet> for u32 {
991 fn from(value: MemPermissionsGetSet) -> Self {
992 value.data_access as u32 | value.instr_access as u32
993 }
994}
995
996#[derive(Debug, Eq, PartialEq, Clone, Copy)]
998pub struct SuccessArgsMemPermGet {
999 pub perm: MemPermissionsGetSet,
1000 pub page_cnt: u32,
1001}
1002
1003impl From<SuccessArgsMemPermGet> for SuccessArgs {
1004 fn from(value: SuccessArgsMemPermGet) -> Self {
1005 assert_ne!(value.page_cnt, 0);
1006 SuccessArgs::Args32([value.perm.into(), value.page_cnt - 1, 0, 0, 0, 0])
1007 }
1008}
1009
1010impl TryFrom<SuccessArgs> for SuccessArgsMemPermGet {
1011 type Error = crate::Error;
1012
1013 fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
1014 let [perm, page_cnt, ..] = value.try_get_args32()?;
1015 Ok(Self {
1016 perm: perm.try_into()?,
1017 page_cnt: page_cnt.checked_add(1).ok_or(Error::InvalidPageCount)?,
1018 })
1019 }
1020}
1021
1022#[cfg(test)]
1023mod tests {
1024 use super::*;
1025
1026 #[allow(dead_code)]
1027 const MEM_SHARE_FROM_SP1: &[u8] = &[
1028 0x05, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1029 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1030 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1031 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1032 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1033 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
1034 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1035 ];
1036
1037 #[allow(dead_code)]
1038 const MEM_SHARE_FROM_SP2: &[u8] = &[
1039 0x06, 0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1040 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1041 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1042 0x00, 0x00, 0x00, 0x05, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1043 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1044 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x07, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
1045 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1046 ];
1047
1048 #[allow(dead_code)]
1049 const MEM_RETRIEVE_REQ_FROM_SP1: &[u8] = &[
1050 0x05, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
1051 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1052 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1053 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1054 0x00, 0x00, 0x00, 0x00,
1055 ];
1056
1057 #[allow(dead_code)]
1058 const MEM_RETRIEVE_REQ_FROM_SP2: &[u8] = &[
1059 0x06, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
1060 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1061 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1062 0x00, 0x00, 0x00, 0x05, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1063 0x00, 0x00, 0x00, 0x00,
1064 ];
1065
1066 #[allow(dead_code)]
1067 const MEM_SHARE_FROM_NWD: &[u8] = &[
1068 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1069 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1070 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1071 0x00, 0x00, 0x00, 0x03, 0x80, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1072 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1073 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x22, 0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00,
1074 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1075 ];
1076
1077 #[test]
1078 fn mem_share() {
1079 let (transaction_desc, access_desc, constituents) =
1080 MemTransactionDesc::unpack(MEM_SHARE_FROM_SP1).unwrap();
1081
1082 println!("transaction desc: {:#x?}", transaction_desc);
1083 access_desc.for_each(|d| println!("endpont desc: {d:#x?}"));
1084 constituents
1085 .unwrap()
1086 .for_each(|c| println!("constituent desc: {c:#x?}"));
1087 }
1088}