arm_ffa/
memory_management.rs

1// SPDX-FileCopyrightText: Copyright The arm-ffa Contributors.
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Implementation of the FF-A Memory Management protocol.
5//!
6//! FF-A describes mechanisms and interfaces that enable FF-A components to manage access and
7//! ownership of memory regions in the physical address space. FF-A components can use a combination
8//! of Framework and Partition messages to manage memory regions in the following ways:
9//! - The Owner of a memory region can transfer its ownership to another FF-A endpoint.
10//! - The Owner of a memory region can transfer its access to one or more FF-A endpoints.
11//! - The Owner of a memory region can share access to it with one or more FF-A endpoints.
12//! - The Owner can reclaim access to a memory region after the FF-A endpoints that were granted
13//!   access to that memory region have relinquished their access.
14
15use 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/// Rich error types returned by this module. Should be converted to [`crate::FfaError`] when used
28/// with the `FFA_ERROR` interface.
29#[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/// Memory region handle, used to identify a composite memory region description.
68#[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/// Cacheability attribute of a memory region. Only valid for normal memory.
88#[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/// Shareability attribute of a memory region. Only valid for normal memory.
116#[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/// Device memory attributes.
147#[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/// Memory region type.
181#[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/// Memory region security attribute.
230#[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!(), // The match is exhaustive for a 1-bit value
244        }
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/// Memory region attributes descriptor.
256#[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        // bits[15:7]: Reserved (MBZ)
267        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/// Instruction access permissions of a memory region.
285#[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/// Data access permissions of a memory region.
316#[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/// Endpoint memory access permissions descriptor.
347#[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, // TODO
353}
354
355/// Iterator of endpoint memory access permission descriptors.
356pub struct MemAccessPermIterator<'a> {
357    buf: &'a [u8],
358    offset: usize,
359    count: usize,
360}
361
362impl<'a> MemAccessPermIterator<'a> {
363    /// Create an iterator of endpoint memory access permission descriptors from a buffer.
364    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/// Constituent memory region descriptor.
428#[derive(Debug, Default, Clone, Copy, PartialEq)]
429pub struct ConstituentMemRegion {
430    pub address: u64,
431    pub page_cnt: u32,
432}
433
434/// Iterator of constituent memory region descriptors.
435pub struct ConstituentMemRegionIterator<'a> {
436    buf: &'a [u8],
437    offset: usize,
438    count: usize,
439}
440
441impl<'a> ConstituentMemRegionIterator<'a> {
442    /// Create an iterator of constituent memory region descriptors from a buffer.
443    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        // Check if the sum of of page counts in the constituent_memory_region_descriptors matches
463        // the total_page_count field of the composite_memory_region_descriptor.
464        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/// Flags of a memory management transaction.
519#[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/// Memory transaction decriptor. Used by an Owner/Lender and a Borrower/Receiver in a transaction
537/// to donate, lend or share a memory region.
538#[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, // TODO
545}
546
547impl MemTransactionDesc {
548    // Offset from the base of the memory transaction descriptor to the first element in the
549    // endpoint memory access descriptor array. Must be 16 byte aligned, but otherwise we're free to
550    // choose any value here. Let's just pack it right after the memory transaction descriptor.
551    const ENDPOINT_MEM_ACCESS_DESC_OFFSET: usize =
552        size_of::<memory_transaction_descriptor>().next_multiple_of(16);
553
554    // The array of constituent memory region descriptors starts right after the composite memory
555    // region descriptor
556    const CONSTITUENT_ARRAY_OFFSET: usize = size_of::<composite_memory_region_descriptor>();
557
558    /// Serialize a memory transaction descriptor and the related constituent memory region
559    /// descriptors and endpoint memory access permission descriptors into a buffer.
560    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        // Offset from the base of the memory transaction descriptor to the composite memory region
585        // descriptor to which the endpoint access permissions apply.
586        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    /// Deserialize a memory transaction descriptor from a buffer and return an interator of the
642    /// related endpoint memory access permission descriptors and constituent memory region
643    /// descriptors, if any.
644    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        // We have to check the first endpoint memory access descriptor to get the composite offset
706        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        // An offset value of 0 indicates that the endpoint access permissions apply to a memory
715        // region description identified by the Handle (i.e. there is no composite descriptor)
716        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
743/// Iterator of endpoint IDs.
744pub struct EndpointIterator<'a> {
745    buf: &'a [u8],
746    offset: usize,
747    count: usize,
748}
749
750impl<'a> EndpointIterator<'a> {
751    /// Create an iterator of endpoint IDs from a buffer.
752    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/// Descriptor to relinquish a memory region. Currently only supports specifying a single endpoint.
783#[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    /// Serialize memory relinquish descriptor and the endpoint IDs into a buffer.
793    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    /// Deserialize a memory relinquish descriptor from a buffer and return an iterator to the
811    /// endpoint IDs.
812    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, // TODO: validate
842            },
843            iterator,
844        ))
845    }
846}
847
848/// Flags field of the FFA_MEM_RECLAIM interface.
849#[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/// Success argument structure for `FFA_MEM_DONATE`, `FFA_MEM_LEND` and `FFA_MEM_SHARE`.
890#[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/// Data access permission enum for `FFA_MEM_PERM_GET` and `FFA_MEM_PERM_SET` calls.
914#[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/// Instructions access permission enum for `FFA_MEM_PERM_GET` and `FFA_MEM_PERM_SET` calls.
944#[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/// Memory permission structure for `FFA_MEM_PERM_GET` and `FFA_MEM_PERM_SET` calls.
971#[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/// Success argument structure for `FFA_MEM_PERM_GET`.
995#[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            // Non-null initial value to ensure that empty/reserved fields are set.
1064            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        // Indicates one endpoint but the array is empty.
1137        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        // Indicates three endpoints but the array is two.
1149        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        // Endpoint array offset out of bounds.
1161        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        // Invalid enpoint desc size
1174        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        // Empty endpoint array
1188        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        // Overflow when computing size.
1200        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        // Composite entry offset out of range.
1213        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        // Incomplete composite entry.
1228        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        // Indicates one entrypoint but array is empty.
1272        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        // Indicates two entrypoint but array is one.
1281        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}