Skip to main content

arm_ffa/
interface_args.rs

1// SPDX-FileCopyrightText: Copyright The arm-ffa Contributors.
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Data structures for describing the parameters of the various FF-A interfaces.
5
6use crate::{Error, FfaError, FuncId, Version, memory_management};
7use num_enum::{IntoPrimitive, TryFromPrimitive};
8use zerocopy::{FromBytes, Immutable, IntoBytes};
9
10/// Endpoint ID and vCPU ID pair, used by `FFA_ERROR`, `FFA_INTERRUPT` and `FFA_RUN` interfaces.
11#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
12pub struct TargetInfo {
13    pub endpoint_id: u16,
14    pub vcpu_id: u16,
15}
16
17impl From<u32> for TargetInfo {
18    fn from(value: u32) -> Self {
19        Self {
20            endpoint_id: (value >> 16) as u16,
21            vcpu_id: value as u16,
22        }
23    }
24}
25
26impl From<TargetInfo> for u32 {
27    fn from(value: TargetInfo) -> Self {
28        ((value.endpoint_id as u32) << 16) | value.vcpu_id as u32
29    }
30}
31
32/// Generic arguments of the `FFA_SUCCESS` interface. The interpretation of the arguments depends on
33/// the interface that initiated the request. The application code has knowledge of the request, so
34/// it has to convert `SuccessArgs` into/from a specific success args structure that matches the
35/// request.
36///
37/// The current specialized success arguments types are:
38/// * `FFA_FEATURES` - [`SuccessArgsFeatures`]
39/// * `FFA_ID_GET` - [`SuccessArgsIdGet`]
40/// * `FFA_SPM_ID_GET` - [`SuccessArgsSpmIdGet`]
41/// * `FFA_PARTITION_INFO_GET` - [`crate::partition_info::SuccessArgsPartitionInfoGet`]
42/// * `FFA_PARTITION_INFO_GET_REGS` - [`crate::partition_info::SuccessArgsPartitionInfoGetRegs`]
43/// * `FFA_NOTIFICATION_GET` - [`crate::notification::SuccessArgsNotificationGet`]
44/// * `FFA_NOTIFICATION_INFO_GET_32` - [`crate::notification::SuccessArgsNotificationInfoGet32`]
45/// * `FFA_NOTIFICATION_INFO_GET_64` - [`crate::notification::SuccessArgsNotificationInfoGet64`]
46#[derive(Debug, Eq, PartialEq, Clone, Copy)]
47pub enum SuccessArgs {
48    Args32([u32; 6]),
49    Args64([u64; 16]),
50}
51
52impl SuccessArgs {
53    pub(crate) fn try_get_args32(self) -> Result<[u32; 6], Error> {
54        match self {
55            SuccessArgs::Args32(args) => Ok(args),
56            SuccessArgs::Args64(_) => Err(Error::InvalidSuccessArgsVariant),
57        }
58    }
59
60    pub(crate) fn try_get_args64(self) -> Result<[u64; 16], Error> {
61        match self {
62            SuccessArgs::Args64(args) => Ok(args),
63            SuccessArgs::Args32(_) => Err(Error::InvalidSuccessArgsVariant),
64        }
65    }
66}
67
68/// Entrypoint address argument for `FFA_SECONDARY_EP_REGISTER` interface.
69#[derive(Debug, Eq, PartialEq, Clone, Copy)]
70pub enum SecondaryEpRegisterAddr {
71    Addr32(u32),
72    Addr64(u64),
73}
74
75/// Feature IDs used by the `FFA_FEATURES` interface.
76#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
77#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedFeatureId))]
78#[repr(u8)]
79pub enum FeatureId {
80    NotificationPendingInterrupt = 0x1,
81    ScheduleReceiverInterrupt = 0x2,
82    ManagedExitInterrupt = 0x3,
83}
84
85/// Arguments for the `FFA_FEATURES` interface.
86#[derive(Debug, Eq, PartialEq, Clone, Copy)]
87pub enum Feature {
88    FuncId(FuncId),
89    FeatureId(FeatureId),
90    Unknown(u32),
91}
92
93impl From<u32> for Feature {
94    fn from(value: u32) -> Self {
95        // Bit[31] is set for all valid FF-A function IDs so we don't have to check it separately
96        if let Ok(func_id) = value.try_into() {
97            Self::FuncId(func_id)
98        } else if let Ok(feat_id) = (value as u8).try_into() {
99            Self::FeatureId(feat_id)
100        } else {
101            Self::Unknown(value)
102        }
103    }
104}
105
106impl From<Feature> for u32 {
107    fn from(value: Feature) -> Self {
108        match value {
109            Feature::FuncId(func_id) => (1 << 31) | func_id as u32,
110            Feature::FeatureId(feature_id) => feature_id as u32,
111            Feature::Unknown(id) => id,
112        }
113    }
114}
115
116/// `FFA_FEATURES` specific success argument structure. This type needs further specialization based
117/// on 'FF-A function ID or Feature ID' field of the preceeding `FFA_FEATURES` request.
118#[derive(Debug, Eq, Default, PartialEq, Clone, Copy)]
119pub struct SuccessArgsFeatures {
120    pub properties: [u32; 2],
121}
122
123impl From<SuccessArgsFeatures> for SuccessArgs {
124    fn from(value: SuccessArgsFeatures) -> Self {
125        Self::Args32([value.properties[0], value.properties[1], 0, 0, 0, 0])
126    }
127}
128
129impl TryFrom<SuccessArgs> for SuccessArgsFeatures {
130    type Error = Error;
131
132    fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
133        let args = value.try_get_args32()?;
134
135        Ok(Self {
136            properties: [args[0], args[1]],
137        })
138    }
139}
140
141/// Version query types for the `FFA_VERSION` interface.
142#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
143#[num_enum(error_type(name = Error, constructor = Error::InvalidVersionQueryType))]
144#[repr(u8)]
145pub enum VersionQueryType {
146    /// Request to negotiate version specified in Input version number.
147    Negotiate = 0b00,
148    /// Request to query whether the callee implements a version that is compatible with the version
149    /// specified in the Input version number by the caller.
150    QueryCompatibility = 0b01,
151    /// Request to query the negotiated version for the caller.
152    QueryNegotiated = 0b10,
153}
154
155/// Flags for the `FFA_VERSION` interface.
156#[derive(Clone, Copy, Debug, Eq, PartialEq)]
157pub struct VersionFlags {
158    pub query_type: VersionQueryType,
159}
160
161impl VersionFlags {
162    const QUERY_TYPE_MASK: u32 = 0b11;
163    const MBZ_BITS: u32 = 0xffff_fffc;
164}
165
166impl TryFrom<u32> for VersionFlags {
167    type Error = Error;
168
169    fn try_from(val: u32) -> Result<Self, Self::Error> {
170        if (val & Self::MBZ_BITS) != 0 {
171            Err(Error::InvalidVersionFlags(val))
172        } else {
173            Ok(Self {
174                query_type: VersionQueryType::try_from((val & Self::QUERY_TYPE_MASK) as u8)?,
175            })
176        }
177    }
178}
179
180impl From<VersionFlags> for u32 {
181    fn from(flags: VersionFlags) -> Self {
182        flags.query_type as u32
183    }
184}
185
186/// RXTX buffer descriptor, used by `FFA_RXTX_MAP`.
187#[derive(Debug, Eq, PartialEq, Clone, Copy)]
188pub enum RxTxAddr {
189    Addr32 { rx: u32, tx: u32 },
190    Addr64 { rx: u64, tx: u64 },
191}
192
193/// `FFA_ID_GET` specific success argument structure.
194#[derive(Debug, Eq, PartialEq, Clone, Copy)]
195pub struct SuccessArgsIdGet {
196    pub id: u16,
197}
198
199impl From<SuccessArgsIdGet> for SuccessArgs {
200    fn from(value: SuccessArgsIdGet) -> Self {
201        SuccessArgs::Args32([value.id as u32, 0, 0, 0, 0, 0])
202    }
203}
204
205impl TryFrom<SuccessArgs> for SuccessArgsIdGet {
206    type Error = Error;
207
208    fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
209        let args = value.try_get_args32()?;
210        Ok(Self { id: args[0] as u16 })
211    }
212}
213
214/// `FFA_SPM_ID_GET` specific success argument structure.
215#[derive(Debug, Eq, PartialEq, Clone, Copy)]
216pub struct SuccessArgsSpmIdGet {
217    pub id: u16,
218}
219
220impl From<SuccessArgsSpmIdGet> for SuccessArgs {
221    fn from(value: SuccessArgsSpmIdGet) -> Self {
222        SuccessArgs::Args32([value.id as u32, 0, 0, 0, 0, 0])
223    }
224}
225
226impl TryFrom<SuccessArgs> for SuccessArgsSpmIdGet {
227    type Error = Error;
228
229    fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
230        let args = value.try_get_args32()?;
231        Ok(Self { id: args[0] as u16 })
232    }
233}
234
235/// Flags field of the `FFA_MSG_SEND2` interface.
236#[derive(Debug, Eq, Default, PartialEq, Clone, Copy)]
237pub struct MsgSend2Flags {
238    pub delay_schedule_receiver: bool,
239}
240
241impl MsgSend2Flags {
242    const DELAY_SCHEDULE_RECEIVER: u32 = 1 << 1;
243    const MBZ_BITS: u32 = 0xffff_fffd;
244}
245
246impl TryFrom<u32> for MsgSend2Flags {
247    type Error = Error;
248
249    fn try_from(val: u32) -> Result<Self, Self::Error> {
250        if (val & Self::MBZ_BITS) != 0 {
251            Err(Error::InvalidMsgSend2Flag(val))
252        } else {
253            Ok(MsgSend2Flags {
254                delay_schedule_receiver: val & Self::DELAY_SCHEDULE_RECEIVER != 0,
255            })
256        }
257    }
258}
259
260impl From<MsgSend2Flags> for u32 {
261    fn from(flags: MsgSend2Flags) -> Self {
262        let mut bits: u32 = 0;
263        if flags.delay_schedule_receiver {
264            bits |= MsgSend2Flags::DELAY_SCHEDULE_RECEIVER;
265        }
266        bits
267    }
268}
269
270/// Composite type for capturing success and error return codes for the VM availability messages.
271///
272/// Error codes are handled by the `FfaError` type. Having a separate type for errors helps using
273/// `Result<(), FfaError>`. If a single type would include both success and error values,
274/// then `Err(FfaError::Success)` would be incomprehensible.
275#[derive(Debug, Eq, PartialEq, Clone, Copy)]
276pub enum VmAvailabilityStatus {
277    Success,
278    Error(FfaError),
279}
280
281impl TryFrom<i32> for VmAvailabilityStatus {
282    type Error = Error;
283    fn try_from(value: i32) -> Result<Self, <Self as TryFrom<i32>>::Error> {
284        Ok(match value {
285            0 => Self::Success,
286            error_code => Self::Error(FfaError::try_from(error_code)?),
287        })
288    }
289}
290
291impl From<VmAvailabilityStatus> for i32 {
292    fn from(value: VmAvailabilityStatus) -> Self {
293        match value {
294            VmAvailabilityStatus::Success => 0,
295            VmAvailabilityStatus::Error(error_code) => error_code.into(),
296        }
297    }
298}
299
300/// Arguments for the Power Warm Boot `FFA_MSG_SEND_DIRECT_REQ` interface.
301#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
302#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedWarmBootType))]
303#[repr(u32)]
304pub enum WarmBootType {
305    ExitFromSuspendToRam = 0,
306    // Corresponds to an exit from any low power state shallower than suspend to RAM.
307    ExitFromLowPower = 1,
308}
309
310impl WarmBootType {
311    #[allow(non_upper_case_globals)]
312    #[deprecated = "Ambiguous name. Please use ExitFromSuspendToRam."]
313    pub const ExitFromSuspend: WarmBootType = WarmBootType::ExitFromSuspendToRam;
314}
315
316/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}` interfaces.
317#[derive(Debug, Eq, PartialEq, Clone, Copy)]
318pub enum DirectMsgArgs {
319    Args32([u32; 5]),
320    Args64([u64; 15]),
321    /// Message for forwarding FFA_VERSION call from Normal world to the SPMC
322    VersionReq {
323        version: Version,
324        flags: VersionFlags,
325    },
326    /// Response message to forwarded FFA_VERSION call from the Normal world
327    /// Contains the version returned by the SPMC or None
328    VersionResp {
329        version: Option<Version>,
330    },
331    /// Message for a power management operation initiated by a PSCI function
332    PowerPsciReq32 {
333        // params[i]: Input parameter in w[i] in PSCI function invocation at EL3.
334        // params[0]: Function ID.
335        params: [u32; 4],
336    },
337    /// Message for a power management operation initiated by a PSCI function
338    PowerPsciReq64 {
339        // params[i]: Input parameter in x[i] in PSCI function invocation at EL3.
340        // params[0]: Function ID.
341        params: [u64; 4],
342    },
343    /// Message for a warm boot
344    PowerWarmBootReq {
345        boot_type: WarmBootType,
346    },
347    /// Response message to indicate return status of the last power management request message
348    /// Return error code SUCCESS or DENIED as defined in PSCI spec. Caller is left to do the
349    /// parsing of the return status.
350    PowerPsciResp {
351        psci_status: i32,
352    },
353    /// Message to signal creation of a VM
354    VmCreated {
355        // Globally unique Handle to identify a memory region that contains IMPLEMENTATION DEFINED
356        // information associated with the created VM.
357        // The invalid memory region handle must be specified by the Hypervisor if this field is not
358        //  used.
359        handle: memory_management::Handle,
360        vm_id: u16,
361    },
362    /// Message to acknowledge creation of a VM
363    VmCreatedAck {
364        sp_status: VmAvailabilityStatus,
365    },
366    /// Message to signal destruction of a VM
367    VmDestructed {
368        // Globally unique Handle to identify a memory region that contains IMPLEMENTATION DEFINED
369        // information associated with the created VM.
370        // The invalid memory region handle must be specified by the Hypervisor if this field is not
371        //  used.
372        handle: memory_management::Handle,
373        vm_id: u16,
374    },
375    /// Message to acknowledge destruction of a VM
376    VmDestructedAck {
377        sp_status: VmAvailabilityStatus,
378    },
379}
380
381impl DirectMsgArgs {
382    // Flags for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}` interfaces.
383
384    pub(crate) const FWK_MSG_BITS: u32 = 1 << 31;
385    pub(crate) const VERSION_REQ: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b1000;
386    pub(crate) const VERSION_RESP: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b1001;
387    pub(crate) const POWER_PSCI_REQ: u32 = DirectMsgArgs::FWK_MSG_BITS;
388    pub(crate) const POWER_WARM_BOOT_REQ: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0001;
389    pub(crate) const POWER_PSCI_RESP: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0010;
390    pub(crate) const VM_CREATED: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0100;
391    pub(crate) const VM_CREATED_ACK: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0101;
392    pub(crate) const VM_DESTRUCTED: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0110;
393    pub(crate) const VM_DESTRUCTED_ACK: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0111;
394}
395
396/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}2` interfaces.
397#[derive(Debug, Eq, PartialEq, Clone, Copy)]
398pub struct DirectMsg2Args(pub [u64; 14]);
399
400/// Flags field of the `FFA_MSG_WAIT` interface.
401#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
402pub struct MsgWaitFlags {
403    pub retain_rx_buffer: bool,
404}
405
406impl MsgWaitFlags {
407    const RETAIN_RX_BUFFER: u32 = 0x01;
408    const MBZ_BITS: u32 = 0xfffe;
409}
410
411impl TryFrom<u32> for MsgWaitFlags {
412    type Error = Error;
413
414    fn try_from(val: u32) -> Result<Self, Self::Error> {
415        if (val & Self::MBZ_BITS) != 0 {
416            Err(Error::InvalidMsgWaitFlag(val))
417        } else {
418            Ok(MsgWaitFlags {
419                retain_rx_buffer: val & Self::RETAIN_RX_BUFFER != 0,
420            })
421        }
422    }
423}
424
425impl From<MsgWaitFlags> for u32 {
426    fn from(flags: MsgWaitFlags) -> Self {
427        let mut bits: u32 = 0;
428        if flags.retain_rx_buffer {
429            bits |= MsgWaitFlags::RETAIN_RX_BUFFER;
430        }
431        bits
432    }
433}
434
435/// Descriptor for a dynamically allocated memory buffer that contains the memory transaction
436/// descriptor.
437///
438/// Used by `FFA_MEM_{DONATE,LEND,SHARE,RETRIEVE_REQ}` interfaces, only when the TX buffer is not
439/// used to transmit the transaction descriptor.
440#[derive(Debug, Eq, PartialEq, Clone, Copy)]
441pub enum MemOpBuf {
442    Buf32 { addr: u32, page_cnt: u32 },
443    Buf64 { addr: u64, page_cnt: u32 },
444}
445
446/// Memory address argument for `FFA_MEM_PERM_{GET,SET}` interfaces.
447#[derive(Debug, Eq, PartialEq, Clone, Copy)]
448pub enum MemAddr {
449    Addr32(u32),
450    Addr64(u64),
451}
452
453impl MemAddr {
454    /// Returns the contained address.
455    pub fn address(&self) -> u64 {
456        match self {
457            MemAddr::Addr32(a) => (*a).into(),
458            MemAddr::Addr64(a) => *a,
459        }
460    }
461}
462
463/// Argument for the `FFA_CONSOLE_LOG` interface.
464#[derive(Debug, Eq, PartialEq, Clone, Copy)]
465pub enum ConsoleLogChars {
466    Chars32(ConsoleLogChars32),
467    Chars64(ConsoleLogChars64),
468}
469
470/// Generic type for storing `FFA_CONSOLE_LOG` character payload and its length in bytes.
471#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
472pub struct LogChars<T>
473where
474    T: IntoBytes + FromBytes + Immutable,
475{
476    pub(crate) char_cnt: u8,
477    pub(crate) char_lists: T,
478}
479
480impl<T> LogChars<T>
481where
482    T: IntoBytes + FromBytes + Immutable,
483{
484    pub(crate) const MAX_LENGTH: u8 = core::mem::size_of::<T>() as u8;
485
486    /// Returns true if there are no characters in the structure.
487    pub fn empty(&self) -> bool {
488        self.char_cnt == 0
489    }
490
491    /// Returns true if the structure is full.
492    pub fn full(&self) -> bool {
493        self.char_cnt as usize >= core::mem::size_of::<T>()
494    }
495
496    /// Returns the payload bytes.
497    pub fn bytes(&self) -> &[u8] {
498        &self.char_lists.as_bytes()[..self.char_cnt as usize]
499    }
500
501    /// Append byte slice to the end of the characters.
502    pub fn push(&mut self, source: &[u8]) -> usize {
503        let empty_area = &mut self.char_lists.as_mut_bytes()[self.char_cnt.into()..];
504        let len = empty_area.len().min(source.len());
505
506        empty_area[..len].copy_from_slice(&source[..len]);
507        self.char_cnt += len as u8;
508
509        len
510    }
511}
512
513/// Specialized type for 32-bit `FFA_CONSOLE_LOG` payload.
514pub type ConsoleLogChars32 = LogChars<[u32; 6]>;
515
516/// Specialized type for 64-bit `FFA_CONSOLE_LOG` payload.
517pub type ConsoleLogChars64 = LogChars<[u64; 16]>;
518
519#[cfg(test)]
520mod tests {
521    use super::*;
522
523    #[test]
524    fn log_chars_empty() {
525        assert!(
526            ConsoleLogChars64 {
527                char_cnt: 0,
528                char_lists: [0; 16]
529            }
530            .empty()
531        )
532    }
533
534    #[test]
535    fn log_chars_push() {
536        let mut console = ConsoleLogChars64 {
537            char_cnt: 0,
538            char_lists: [0; 16],
539        };
540
541        assert_eq!(console.push("hello world!".as_bytes()), 12);
542
543        assert_eq!(console.char_cnt, 12);
544        assert_eq!(&console.bytes()[0..12], "hello world!".as_bytes());
545        assert!(!console.empty());
546    }
547
548    #[test]
549    fn log_chars_full() {
550        let mut console = ConsoleLogChars64 {
551            char_cnt: 0,
552            char_lists: [0; 16],
553        };
554
555        assert_eq!(console.push(&[97; 128]), 128);
556
557        assert!(console.full());
558    }
559
560    #[test]
561    fn success_args_invalid_variants() {
562        assert!(SuccessArgs::Args32([0; 6]).try_get_args64().is_err());
563        assert!(SuccessArgs::Args64([0; 16]).try_get_args32().is_err());
564    }
565}