Skip to main content

optee_utee/parameter/
mod.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! TEE parameter handling: conversion from raw OP-TEE parameter types into
19//! type-safe Rust wrappers.
20//!
21//! # Overview
22//!
23//! OP-TEE passes up to four parameters between the host (Normal World) and
24//! the TA (Trusted Application). Each parameter has an associated *type* tag
25//! (e.g. value, memref) and a raw `TEE_Param` union. This module provides:
26//!
27//! * **`FromRawParameter`** – single-parameter conversion from a raw
28//!   `TEE_Param` into a typed Rust wrapper.
29//! * **`FromRawParameters`** – batch conversion of all four parameters at once
30//!   (implemented for 4-tuples of `FromRawParameter` types).
31//! * **Typed wrappers** – `ParameterNone`, `ParameterValueInput`,
32//!   `ParameterMemrefInput`, etc.
33//! * **Type-erased wrapper** – [`ParameterAny`] for scenarios where the
34//!   developer cannot know the parameter type at compile time.
35//! * **Legacy compatibility** – [`deprecated`] provides the old unsafe
36//!   pointer-based API; new code should use the typed wrappers instead.
37//!
38//! # Migration from the deprecated API
39//!
40//! If you currently use [`deprecated::Parameters`] and [`deprecated::Parameter`]:
41//!
42//! | Old pattern | New pattern |
43//! |---|---|
44//! | `params.0.as_value()?.a()` | `param.get_a()` via [`ParameterValueRead`](crate::ParameterValueRead] |
45//! | `params.0.as_memref()?.buffer()` | `param.read_to_vec()` / `param.read_at()` via [`crate::ParameterMemrefRead`], or `param.set_output()` / `param.write_at()` via [`crate::ParameterMemrefWrite`] |
46//! | `params.0.set_updated_size(n)` | `param.set_updated_size(n)` via [`crate::ParameterMemrefWrite`] |
47//!
48//! See the [`deprecated`] module for per-type migration notes.
49
50use crate::{ErrorKind, Result, raw};
51
52pub mod deprecated;
53pub mod memref;
54pub mod none;
55pub mod value;
56
57/// Raw parameter-type tag as passed by the TEE runtime.
58/// Each of the four slots carries a 4-bit type-identifier. Use
59/// `TEE_PARAM_TYPE_GET(raw_types, idx)` to extract one slot from
60/// the `RawParamTypes` bit-field.
61pub type RawParamType = u32;
62
63/// Together with a [`RawParams`] array this describes the name *and* content
64/// of all four TEE parameters.
65pub type RawParamTypes = u32;
66
67/// Array of four raw `TEE_Param` unions.
68///
69/// Corresponds to the four parameter slots passed to every TA entry-point.
70pub type RawParams = [raw::TEE_Param; raw::TEE_NUM_PARAMS as usize];
71
72/// Convert a single raw parameter into a type-safe Rust wrapper.
73///
74/// # Safety
75///
76/// Implementors must validate that `raw_type` matches the expected parameter
77/// type and that `raw_param` has been correctly initialized by the TEE
78/// runtime before reading any fields.
79pub trait FromRawParameter<'a>: Sized {
80    /// Construct `Self` from a raw parameter.
81    ///
82    /// # Safety
83    ///
84    /// Caller must ensure `raw_type` and `raw_param` are a consistent pair
85    /// delivered by a TEE entry-point invocation (e.g. `TA_InvokeCommandEntryPoint`).
86    #[allow(clippy::missing_safety_doc)]
87    unsafe fn from_raw(raw_type: RawParamType, raw_param: &'a mut raw::TEE_Param) -> Result<Self>;
88}
89
90/// Convert all four raw parameters at once into a typed tuple.
91///
92/// # Safety
93///
94/// The same safety constraints as [`FromRawParameter`] apply to each slot.
95pub trait FromRawParameters<'a>: Sized {
96    /// Construct `Self` from the full parameter array.
97    ///
98    /// # Safety
99    ///
100    /// Caller must ensure `raw_types` and `raw_param` come from the same
101    /// TEE entry-point invocation.
102    #[allow(clippy::missing_safety_doc)]
103    unsafe fn from_raw(raw_types: RawParamTypes, raw_params: &'a mut RawParams) -> Result<Self>;
104}
105
106impl<
107    'a,
108    A: FromRawParameter<'a>,
109    B: FromRawParameter<'a>,
110    C: FromRawParameter<'a>,
111    D: FromRawParameter<'a>,
112> FromRawParameters<'a> for (A, B, C, D)
113{
114    unsafe fn from_raw(raw_types: RawParamTypes, raw_params: &'a mut RawParams) -> Result<Self> {
115        Ok(unsafe {
116            let [p0, p1, p2, p3] = raw_params;
117            (
118                A::from_raw(raw::TEE_PARAM_TYPE_GET(raw_types, 0), p0)?,
119                B::from_raw(raw::TEE_PARAM_TYPE_GET(raw_types, 1), p1)?,
120                C::from_raw(raw::TEE_PARAM_TYPE_GET(raw_types, 2), p2)?,
121                D::from_raw(raw::TEE_PARAM_TYPE_GET(raw_types, 3), p3)?,
122            )
123        })
124    }
125}
126
127/// Enumerates the seven standard TEE parameter types.
128///
129/// This is the Rust-side mirror of the `TEE_PARAM_TYPE_*` constants defined
130/// in the C header. The `Unknown(u32)` variant catches any
131/// implementation-defined or invalid type tags.
132#[derive(Copy, Clone, num_enum::FromPrimitive, num_enum::IntoPrimitive)]
133#[repr(u32)]
134pub enum ParamType {
135    None = raw::TEE_PARAM_TYPE_NONE,
136    ValueInput = raw::TEE_PARAM_TYPE_VALUE_INPUT,
137    ValueOutput = raw::TEE_PARAM_TYPE_VALUE_OUTPUT,
138    ValueInout = raw::TEE_PARAM_TYPE_VALUE_INOUT,
139    MemrefInput = raw::TEE_PARAM_TYPE_MEMREF_INPUT,
140    MemrefOutput = raw::TEE_PARAM_TYPE_MEMREF_OUTPUT,
141    MemrefInout = raw::TEE_PARAM_TYPE_MEMREF_INOUT,
142    #[num_enum(catch_all)]
143    Unknown(u32),
144}
145
146fn check_type_is(raw_type: RawParamType, exp_type: ParamType) -> Result<()> {
147    let exp_type: u32 = exp_type.into();
148    if raw_type != exp_type {
149        return Err(ErrorKind::BadParameters.into());
150    }
151    Ok(())
152}
153
154/// A type-erased parameter that dispatches to the correct concrete wrapper
155/// based on the runtime type tag.
156///
157/// # When to use
158///
159/// Use `ParameterAny` when the parameter type is **not known at compile time**
160/// and must be determined at runtime. Typical scenarios:
161///
162/// * The command semantics allow multiple parameter types for the same slot
163///   (e.g. "slot 0 may be `None` or `MemrefInput` depending on the command").
164/// * A library helper is designed to inspect parameters generically without
165///   fixing the types in its signature.
166///
167/// If you already know the expected type for a slot, prefer the concrete
168/// wrappers from [`value`] and [`memref`] instead—they provide methods
169/// specific to that type and avoid the match ceremony.
170///
171/// # Example
172///
173/// ```rust,ignore
174/// use optee_utee::parameter::{ParameterAny, FromRawParameter};
175///
176/// match param {
177///     ParameterAny::None => { /* no parameter */ }
178///     ParameterAny::MemrefInput(p) => {
179///         let data: alloc::vec::Vec<u8> = p.read_to_vec();
180///         // validate and use the TA-owned `data` ...
181///     }
182///     ParameterAny::ValueInput(p) => {
183///         let a = p.get_a();
184///         let b = p.get_b();
185///         // use a, b ...
186///     }
187///     _ => return Err(ErrorKind::BadParameters.into()),
188/// }
189/// ```
190pub enum ParameterAny<'a> {
191    None,
192    ValueInput(value::ParameterValueInput),
193    ValueInout(value::ParameterValueInout<'a>),
194    ValueOutput(value::ParameterValueOutput<'a>),
195    MemrefInput(memref::ParameterMemrefInput<'a>),
196    MemrefInout(memref::ParameterMemrefInout<'a>),
197    MemrefOutput(memref::ParameterMemrefOutput<'a>),
198    /// Unrecognized or implementation-defined type tag.
199    ///
200    /// Carries the raw `RawParamType` and a mutable reference to the
201    /// underlying `TEE_Param` so that the caller can handle it manually.
202    Unknown(RawParamType, &'a mut raw::TEE_Param),
203}
204
205impl<'a> ParameterAny<'a> {
206    pub fn as_value_input(&self) -> Result<&value::ParameterValueInput> {
207        match &self {
208            Self::ValueInput(p) => Ok(p),
209            _ => Err(ErrorKind::BadParameters.into()),
210        }
211    }
212    pub fn as_value_output(&mut self) -> Result<&mut value::ParameterValueOutput<'a>> {
213        match self {
214            Self::ValueOutput(p) => Ok(p),
215            _ => Err(ErrorKind::BadParameters.into()),
216        }
217    }
218    pub fn as_value_inout(&mut self) -> Result<&mut value::ParameterValueInout<'a>> {
219        match self {
220            Self::ValueInout(p) => Ok(p),
221            _ => Err(ErrorKind::BadParameters.into()),
222        }
223    }
224    pub fn as_memref_input(&self) -> Result<&memref::ParameterMemrefInput<'a>> {
225        match self {
226            Self::MemrefInput(p) => Ok(p),
227            _ => Err(ErrorKind::BadParameters.into()),
228        }
229    }
230    pub fn as_memref_inout(&mut self) -> Result<&mut memref::ParameterMemrefInout<'a>> {
231        match self {
232            Self::MemrefInout(p) => Ok(p),
233            _ => Err(ErrorKind::BadParameters.into()),
234        }
235    }
236    pub fn as_memref_output(&mut self) -> Result<&mut memref::ParameterMemrefOutput<'a>> {
237        match self {
238            Self::MemrefOutput(p) => Ok(p),
239            _ => Err(ErrorKind::BadParameters.into()),
240        }
241    }
242    pub fn as_none(&self) -> Result<()> {
243        match self {
244            Self::None => Ok(()),
245            _ => Err(ErrorKind::BadParameters.into()),
246        }
247    }
248}
249
250impl<'a> FromRawParameter<'a> for ParameterAny<'a> {
251    unsafe fn from_raw(raw_type: RawParamType, raw_param: &'a mut raw::TEE_Param) -> Result<Self> {
252        unsafe {
253            match raw_type {
254                raw::TEE_PARAM_TYPE_NONE => Ok(Self::None),
255                raw::TEE_PARAM_TYPE_VALUE_INPUT => Ok(Self::ValueInput(
256                    value::ParameterValueInput::from_raw(raw_type, raw_param)?,
257                )),
258                raw::TEE_PARAM_TYPE_VALUE_INOUT => Ok(Self::ValueInout(
259                    value::ParameterValueInout::from_raw(raw_type, raw_param)?,
260                )),
261                raw::TEE_PARAM_TYPE_VALUE_OUTPUT => Ok(Self::ValueOutput(
262                    value::ParameterValueOutput::from_raw(raw_type, raw_param)?,
263                )),
264                raw::TEE_PARAM_TYPE_MEMREF_INPUT => Ok(Self::MemrefInput(
265                    memref::ParameterMemrefInput::from_raw(raw_type, raw_param)?,
266                )),
267                raw::TEE_PARAM_TYPE_MEMREF_INOUT => Ok(Self::MemrefInout(
268                    memref::ParameterMemrefInout::from_raw(raw_type, raw_param)?,
269                )),
270                raw::TEE_PARAM_TYPE_MEMREF_OUTPUT => Ok(Self::MemrefOutput(
271                    memref::ParameterMemrefOutput::from_raw(raw_type, raw_param)?,
272                )),
273                _ => Ok(Self::Unknown(raw_type, raw_param)),
274            }
275        }
276    }
277}
278
279pub type ParametersAny<'a> = (
280    ParameterAny<'a>,
281    ParameterAny<'a>,
282    ParameterAny<'a>,
283    ParameterAny<'a>,
284);
285pub type ParametersNone = (
286    none::ParameterNone,
287    none::ParameterNone,
288    none::ParameterNone,
289    none::ParameterNone,
290);