blob: a21d361e0190dca6d8f71b25f7002c2845f78879 [file] [log] [blame]
// Copyright 2024 The Fuchsia Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::{collections::BTreeMap, ops::AddAssign};
use crate::params::TEEParams;
use crate::ta_loader::{SessionContext, TAInterface};
use anyhow::Error;
use fidl_fuchsia_tee::{OpResult, Parameter, ReturnOrigin};
use tee_internal_impl::binding::TEE_SUCCESS;
// This structure stores the entry points to the TA and application-specific
// state like sessions.
pub struct TrustedApp<T: TAInterface> {
interface: T,
sessions: BTreeMap<u32, SessionContext>,
next_session_id: u32,
}
impl<T: TAInterface> TrustedApp<T> {
pub fn new(interface: T) -> Result<Self, Error> {
let result = interface.create();
if result != TEE_SUCCESS {
anyhow::bail!("Create callback failed: {result:?}");
}
Ok(Self { interface, sessions: BTreeMap::new(), next_session_id: 1 })
}
fn allocate_session_id(&mut self) -> u32 {
let session_id = self.next_session_id;
self.next_session_id.add_assign(1);
session_id
}
// TODO(https://fxbug.dev/332956721): We're supposed to consult the property
// `gpd.ta.multiSession` on the TA before asking it to open a second
// session. If this property isn't set, opening a second session is a
// client error.
pub fn open_session(
&mut self,
parameter_set: Vec<Parameter>,
) -> Result<(u32, OpResult), Error> {
let mut session_context = std::ptr::null_mut();
let mut tee_params = TEEParams::new();
let (param_types, mut params) = tee_params.import_from_fidl(parameter_set)?;
let ta_result =
self.interface.open_session(param_types, params.as_mut_ptr(), &mut session_context);
let return_params = vec![]; // TODO: export 'params' to FIDL types to return to the caller.
let session_id = self.allocate_session_id();
let _ = self.sessions.insert(session_id, session_context);
let op_result = OpResult {
return_code: Some(ta_result as u64),
return_origin: Some(ReturnOrigin::TrustedApplication),
parameter_set: Some(return_params),
..Default::default()
};
Ok((session_id, op_result))
}
pub fn close_session(&mut self, session_id: u32) -> Result<(), Error> {
match self.sessions.remove(&session_id) {
Some(session_context) => {
self.interface.close_session(session_context);
Ok(())
}
None => anyhow::bail!("Invalid session id"),
}
}
pub fn invoke_command(
&mut self,
session_id: u32,
command: u32,
parameter_set: Vec<Parameter>,
) -> Result<OpResult, Error> {
let session_context = match self.sessions.get_mut(&session_id) {
Some(session_context) => session_context,
None => anyhow::bail!("Invalid session id"),
};
let mut tee_params = TEEParams::new();
let (param_types, mut params) = tee_params.import_from_fidl(parameter_set)?;
let ta_result = self.interface.invoke_command(
*session_context,
command,
param_types,
params.as_mut_ptr(),
);
let return_params = vec![]; // TODO: export 'params' to FIDL type to return to caller.
let op_result = OpResult {
return_code: Some(ta_result as u64),
return_origin: Some(ReturnOrigin::TrustedApplication),
parameter_set: Some(return_params),
..Default::default()
};
Ok(op_result)
}
pub fn destroy(&self) {
self.interface.destroy()
}
}