system_update_configurator/bridge/vx_ta/
mod.rs1mod tee_client_api;
6
7use self::tee_client_api::*;
8use log::debug;
9use std::fmt::Debug;
10use std::{fmt, mem, ptr};
11use thiserror::Error;
12
13use self::tee_client_api::{TEEC_Operation as TeecOperation, TEEC_Value as TeecValue};
14
15use self::tee_client_api::TEEC_Parameter as TeecParameter;
16
17const TA_VX_CMD_OTA_CONFIG_SET: u32 = 24;
18const TA_VX_CMD_OTA_CONFIG_GET: u32 = 25;
19
20#[derive(Debug, Error)]
22#[allow(missing_docs)]
23pub enum TeeError {
24 General(u32),
25 Busy,
26}
27
28impl fmt::Display for TeeError {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 write!(f, "{self:?}")
31 }
32}
33
34pub fn ota_config_get(default_value: u32) -> Result<u32, TeeError> {
35 let param_type = teec_param_types(TEEC_VALUE_INPUT, TEEC_VALUE_OUTPUT, TEEC_NONE, TEEC_NONE);
36 let params = [
37 get_value_parameter(default_value, 0),
38 get_value_parameter(0, 0),
39 get_zero_parameter(),
40 get_zero_parameter(),
41 ];
42 let mut op = create_operation(param_type, params);
43 unsafe { call_command(&mut op, TA_VX_CMD_OTA_CONFIG_GET).map_err(map_tee_error)? };
46 let value = unsafe { op.params[1].value.a };
49 Ok(value)
50}
51
52pub fn ota_config_set(value: u32) -> Result<(), TeeError> {
53 let param_type = teec_param_types(TEEC_VALUE_INPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
54 let params = [
55 get_value_parameter(value, 0),
56 get_zero_parameter(),
57 get_zero_parameter(),
58 get_zero_parameter(),
59 ];
60 let mut op = create_operation(param_type, params);
61 unsafe { call_command(&mut op, TA_VX_CMD_OTA_CONFIG_SET).map_err(map_tee_error) }
64}
65
66fn map_tee_error(error_code: u32) -> TeeError {
67 match error_code {
68 TEEC_ERROR_BUSY => TeeError::Busy,
69 _ => TeeError::General(error_code),
70 }
71}
72
73static VX_TA_UUID: TEEC_UUID = TEEC_UUID {
75 timeLow: 0x99dc95b2,
76 timeMid: 0x938e,
77 timeHiAndVersion: 0x47eb,
78 clockSeqAndNode: [0x80, 0xe8, 0x94, 0x04, 0xae, 0x8a, 0x13, 0x85],
79};
80
81fn get_zero_parameter() -> TeecParameter {
83 let zero_parameter: TeecParameter = unsafe { mem::zeroed() };
85 zero_parameter
86}
87
88fn get_value_parameter(a: u32, b: u32) -> TeecParameter {
90 TeecParameter { value: TeecValue { a, b } }
91}
92
93fn create_operation(param_type: u32, params: [TeecParameter; 4]) -> TeecOperation {
95 TeecOperation {
96 started: 0,
97 paramTypes: param_type,
98 params,
99 imp: teec_operation_impl { reserved: 0 as ::std::os::raw::c_char },
100 }
101}
102
103fn teec_param_types(param0_type: u32, param1_type: u32, param2_type: u32, param3_type: u32) -> u32 {
105 (param0_type & 0xF)
106 | ((param1_type & 0xF) << 4)
107 | ((param2_type & 0xF) << 8)
108 | ((param3_type & 0xF) << 12)
109}
110
111unsafe fn call_command(op: &mut TeecOperation, command_id: u32) -> Result<(), u32> {
122 let mut tee_context = TeeContext::new()?;
123 let mut tee_session = unsafe { tee_context.new_session()? };
125 let mut return_origin: u32 = 0;
126 unsafe { tee_session.invoke_command(command_id, op, &mut return_origin) }
128}
129
130struct TeeContext {
131 context: TEEC_Context,
132}
133
134impl TeeContext {
135 pub fn new() -> Result<Self, u32> {
136 let mut context: TEEC_Context = unsafe { mem::zeroed() };
138 let result = unsafe { TEEC_InitializeContext(ptr::null(), &mut context) };
141 if result != TEEC_SUCCESS {
142 debug!("Failed to initialize context: {:?}", result);
143 return Err(result);
144 }
145 Ok(TeeContext { context })
146 }
147
148 pub unsafe fn new_session(&mut self) -> Result<TeeSession, u32> {
153 let mut session: TEEC_Session = unsafe { mem::zeroed() };
155
156 let mut return_origin: u32 = 0;
157 let result = unsafe {
164 TEEC_OpenSession(
165 &mut self.context,
166 &mut session,
167 &VX_TA_UUID,
168 TEEC_LOGIN_PUBLIC,
169 ptr::null_mut(),
170 ptr::null_mut(),
171 &mut return_origin,
172 )
173 };
174 if result != TEEC_SUCCESS {
175 debug!("Failed to open session ({:?})\n", result);
176 return Err(result);
177 }
178 Ok(TeeSession { session })
179 }
180}
181
182impl Drop for TeeContext {
183 fn drop(&mut self) {
184 unsafe { TEEC_FinalizeContext(&mut self.context) };
186 }
187}
188
189struct TeeSession {
190 session: TEEC_Session,
191}
192
193impl TeeSession {
194 pub unsafe fn invoke_command(
204 &mut self,
205 command_id: u32,
206 operation: *mut TEEC_Operation,
207 return_origin: *mut u32,
208 ) -> Result<(), u32> {
209 let result =
215 unsafe { TEEC_InvokeCommand(&mut self.session, command_id, operation, return_origin) };
216 if result != TEEC_SUCCESS {
217 debug!("TEEC_InvokeCommand failed with code {:?}", result);
218 return Err(result);
219 }
220 Ok(())
221 }
222}
223
224impl Drop for TeeSession {
225 fn drop(&mut self) {
226 unsafe { TEEC_CloseSession(&mut self.session) };
228 }
229}
230
231#[cfg(test)]
232mod tests {
233 use super::*;
234 use assert_matches::assert_matches;
235
236 #[fuchsia::test]
237 async fn no_tee_connection_test() {
238 let rc = ota_config_get(0);
239 assert_matches!(rc, Err(TeeError::General(TEEC_ERROR_NOT_SUPPORTED)));
240
241 let rc = ota_config_set(0);
242 assert_matches!(rc, Err(TeeError::General(TEEC_ERROR_NOT_SUPPORTED)));
243 }
244}