Skip to main content

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