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