blob: ddbab451bd898c10a0986c8014e46f143c2ce52e [file] [log] [blame]
//
// 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(&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_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));
}
}
}