| // |
| // Copyright (C) 2024 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| use crate::error::Error; |
| use alloc::boxed::Box; |
| use core::marker::PhantomData; |
| use core::ptr; |
| use optee_utee::{ParamType, Uuid}; |
| use optee_utee_sys::{ |
| Memref, TEE_CloseTASession, TEE_InvokeTACommand, TEE_OpenTASession, TEE_Param, |
| TEE_TASessionHandle, Value, TEE_SUCCESS, TEE_TIMEOUT_INFINITE, |
| }; |
| |
| // Matches optee_os/lib/libutee/include/pta_system.h |
| pub const PTA_SYSTEM_ADD_RNG_ENTROPY: u32 = 0; |
| #[allow(dead_code)] |
| pub const PTA_SYSTEM_DERIVE_TA_UNIQUE_KEY: u32 = 1; |
| pub const PTA_SYSTEM_UUID: &'static str = "3a2f8978-5dc0-11e8-9c2d-fa7ae01bbebc"; |
| |
| #[allow(dead_code)] |
| pub enum Direction { |
| In, |
| Out, |
| Both, |
| } |
| |
| pub struct Param<'a> { |
| raw: TEE_Param, |
| param_type: ParamType, |
| phantom: PhantomData<&'a mut i32>, |
| } |
| |
| impl<'a> Param<'a> { |
| pub fn empty() -> Params<'a> { |
| Params(Param::none(), Param::none(), Param::none(), Param::none()) |
| } |
| |
| pub fn none() -> Param<'a> { |
| Param { |
| raw: TEE_Param { value: Value { a: 0, b: 0 } }, |
| param_type: ParamType::None, |
| phantom: PhantomData, |
| } |
| } |
| |
| pub fn from_mut_slice(data: &'a mut [u8], direction: Direction) -> Param<'a> { |
| Param { |
| raw: TEE_Param { memref: Memref { buffer: data.as_mut_ptr() as _, size: data.len() } }, |
| param_type: match direction { |
| Direction::In => ParamType::MemrefInput, |
| Direction::Out => ParamType::MemrefOutput, |
| Direction::Both => ParamType::MemrefInout, |
| }, |
| phantom: PhantomData, |
| } |
| } |
| |
| pub fn from_slice(data: &'a [u8]) -> Param<'a> { |
| Param { |
| raw: TEE_Param { memref: Memref { buffer: data.as_ptr() as _, size: data.len() } }, |
| param_type: ParamType::MemrefInput, |
| phantom: PhantomData, |
| } |
| } |
| |
| #[allow(dead_code)] |
| pub fn from_value(a: u32, b: u32, direction: Direction) -> Param<'a> { |
| Param { |
| raw: TEE_Param { value: Value { a: a, b: b } }, |
| param_type: match direction { |
| Direction::In => ParamType::ValueInput, |
| Direction::Out => ParamType::ValueOutput, |
| Direction::Both => ParamType::ValueInout, |
| }, |
| phantom: PhantomData, |
| } |
| } |
| } |
| |
| pub struct Params<'a>(pub Param<'a>, pub Param<'a>, pub Param<'a>, pub Param<'a>); |
| |
| pub struct Ta; |
| |
| impl Ta { |
| pub fn open(uuid: &Uuid, params: &Params) -> Result<Session, kmr_common::Error> { |
| let raw_handle: *mut TEE_TASessionHandle = Box::into_raw(Box::new(ptr::null_mut())); |
| let types = Ta::to_types(¶ms); |
| let parambuf: [TEE_Param; 4] = [params.0.raw, params.1.raw, params.2.raw, params.3.raw]; |
| let mut origin: u32 = 0; |
| |
| // SAFETY: pointers are valid during the function call. |
| match unsafe { |
| TEE_OpenTASession( |
| uuid.as_raw_ptr(), |
| TEE_TIMEOUT_INFINITE, |
| types, |
| parambuf.as_ptr() as _, |
| raw_handle, |
| &mut origin, |
| ) |
| } { |
| TEE_SUCCESS => Ok(Session { handle: raw_handle, origin: origin }), |
| code => Err(optee_utee::Error::from_raw_error(code)).map_err(Error::kmerr), |
| } |
| } |
| |
| pub fn open_system_pta(params: &Params) -> Result<Session, kmr_common::Error> { |
| let uuid = Uuid::parse_str(PTA_SYSTEM_UUID).map_err(Error::kmerr)?; |
| Ta::open(&uuid, params) |
| } |
| |
| fn to_types(params: &Params) -> u32 { |
| (params.0.param_type as u32 & 0xf) |
| | ((params.1.param_type as u32 & 0xf) << 4) |
| | ((params.2.param_type as u32 & 0xf) << 8) |
| | ((params.3.param_type as u32 & 0xf) << 12) |
| } |
| } |
| |
| pub struct Session { |
| handle: *mut TEE_TASessionHandle, |
| #[allow(dead_code)] |
| pub origin: u32, |
| } |
| |
| impl Session { |
| pub fn invoke(&self, command: u32, params: &Params) -> Result<u32, kmr_common::Error> { |
| let types = Ta::to_types(params); |
| let parambuf: [TEE_Param; 4] = [params.0.raw, params.1.raw, params.2.raw, params.3.raw]; |
| let mut origin: u32 = 0; |
| |
| // SAFETY: pointers are valid during the function call. |
| match unsafe { |
| TEE_InvokeTACommand( |
| *self.handle, |
| TEE_TIMEOUT_INFINITE, |
| command, |
| types, |
| parambuf.as_ptr() as _, |
| &mut origin, |
| ) |
| } { |
| TEE_SUCCESS => Ok(origin), |
| code => Err(optee_utee::Error::from_raw_error(code)).map_err(Error::kmerr), |
| } |
| } |
| } |
| |
| impl Drop for Session { |
| fn drop(&mut self) { |
| unsafe { |
| if self.handle != ptr::null_mut() { |
| TEE_CloseTASession(*self.handle); |
| } |
| drop(Box::from_raw(self.handle)); |
| } |
| } |
| } |