1#![allow(non_camel_case_types)]
7
8use std::{
9 ffi::c_void,
10 io::{Error, ErrorKind},
11 mem, ptr,
12};
13
14use num_enum::{FromPrimitive, IntoPrimitive};
15use uuid::Uuid;
16
17use cc_teec::{
18 TEEC_AllocateSharedMemory, TEEC_CloseSession, TEEC_FinalizeContext, TEEC_InitializeContext,
19 TEEC_InvokeCommand, TEEC_OpenSession, TEEC_RegisterSharedMemory, TEEC_ReleaseSharedMemory, raw,
20};
21
22const EXAMPLE_TA_UUID: &str = "9b28392f-39d2-497d-91af-b6600e3d6a3e";
23
24#[derive(FromPrimitive, IntoPrimitive)]
25#[repr(u32)]
26pub enum Command {
27 ValueInputOutput = 0, ValueInout = 1, MemrefTempInputOutput = 10, MemrefTempInout = 11, MemrefWholeInputOutput = 20, MemrefWholeInout = 21, MemrefPartialInputOutput = 30, MemrefPartialInout = 31, MixedParams = 100,
45
46 #[default]
47 Unknown = 0xFF,
48}
49
50type Result<T> = std::result::Result<T, Error>;
51
52struct Client_Session {
56 ctx: Box<raw::TEEC_Context>,
61 session: raw::TEEC_Session,
63}
64
65impl Client_Session {
66 fn new(uuid: &raw::TEEC_UUID) -> Result<Self> {
67 let mut ctx: Box<raw::TEEC_Context> = Box::new(unsafe { mem::zeroed() });
70 let mut session: raw::TEEC_Session = unsafe { mem::zeroed() };
71 let mut origin = 0_u32;
72
73 let res = TEEC_InitializeContext(ptr::null(), ctx.as_mut());
74 if res != raw::TEEC_SUCCESS {
75 return Err(Error::from_raw_os_error(res as i32));
76 }
77
78 let res = TEEC_OpenSession(
79 ctx.as_mut(),
80 &mut session,
81 uuid,
82 raw::TEEC_LOGIN_PUBLIC,
83 ptr::null(),
84 ptr::null_mut(),
85 &mut origin,
86 );
87
88 if res != raw::TEEC_SUCCESS {
89 TEEC_FinalizeContext(ctx.as_mut());
90 return Err(Error::from_raw_os_error(res as i32));
91 }
92
93 Ok(Self { ctx, session })
94 }
95
96 fn invoke_command(&self, cmd_id: u32, op: &mut raw::TEEC_Operation) -> Result<()> {
97 let mut origin = 0_u32;
98 let res = TEEC_InvokeCommand(&self.session as *const _ as *mut _, cmd_id, op, &mut origin);
99
100 if res != raw::TEEC_SUCCESS {
101 return Err(Error::from_raw_os_error(res as i32));
102 }
103
104 Ok(())
105 }
106
107 fn context_mut(&mut self) -> &mut raw::TEEC_Context {
109 self.ctx.as_mut()
110 }
111}
112
113impl Drop for Client_Session {
114 fn drop(&mut self) {
115 TEEC_CloseSession(&mut self.session);
116 TEEC_FinalizeContext(self.ctx.as_mut());
117 }
118}
119
120fn main() -> Result<()> {
121 let uuid = Uuid::parse_str(EXAMPLE_TA_UUID)
122 .map_err(|_| Error::new(ErrorKind::InvalidInput, "无效 UUID"))?;
123 let teec_uuid = uuid_to_teec_uuid(&uuid)?;
124 let mut session = Client_Session::new(&teec_uuid)?;
125
126 value_types(&session)?;
127 memref_temp_types(&session)?;
128 memref_whole(&mut session)?;
129 memref_partial(&mut session)?;
130 mixed_params(&session)?;
131
132 Ok(())
133}
134
135fn value_types(session: &Client_Session) -> Result<()> {
137 println!("\nVALUE 参数类型");
138
139 {
141 let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
143
144 op.paramTypes = raw::TEEC_PARAM_TYPES(
145 raw::TEEC_VALUE_INPUT,
146 raw::TEEC_VALUE_OUTPUT,
147 raw::TEEC_NONE,
148 raw::TEEC_NONE,
149 );
150 op.params[0].value.a = 100;
151 op.params[0].value.b = 200;
152
153 session.invoke_command(Command::ValueInputOutput.into(), &mut op)?;
154
155 let result = unsafe { op.params[1].value.a };
158 println!(" VALUE_INPUT+OUTPUT: {} + {} = {}", 100, 200, result);
159 }
160
161 {
163 let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
165
166 op.paramTypes = raw::TEEC_PARAM_TYPES(
167 raw::TEEC_VALUE_INOUT,
168 raw::TEEC_NONE,
169 raw::TEEC_NONE,
170 raw::TEEC_NONE,
171 );
172 op.params[0].value.a = 42;
173 op.params[0].value.b = 99;
174
175 session.invoke_command(Command::ValueInout.into(), &mut op)?;
176
177 let a_out = unsafe { op.params[0].value.a };
180 let b_out = unsafe { op.params[0].value.b };
181 println!(" VALUE_INOUT: (42, 99) → ({}, {})", a_out, b_out);
182 }
183
184 Ok(())
185}
186
187fn memref_temp_types(session: &Client_Session) -> Result<()> {
189 println!("\nMEMREF TEMP 参数类型");
190
191 {
193 let input_data = vec![1u8, 2, 3, 4, 5];
194 let mut output_data = vec![0u8; 16];
195
196 let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
198
199 op.paramTypes = raw::TEEC_PARAM_TYPES(
200 raw::TEEC_MEMREF_TEMP_INPUT,
201 raw::TEEC_MEMREF_TEMP_OUTPUT,
202 raw::TEEC_NONE,
203 raw::TEEC_NONE,
204 );
205 op.params[0].tmpref.buffer = input_data.as_ptr() as *mut _;
206 op.params[0].tmpref.size = input_data.len();
207 op.params[1].tmpref.buffer = output_data.as_mut_ptr() as *mut _;
208 op.params[1].tmpref.size = output_data.len();
209
210 session.invoke_command(Command::MemrefTempInputOutput.into(), &mut op)?;
211
212 println!(
213 " TEMP_INPUT+OUTPUT: {:?} → {:?}",
214 input_data,
215 &output_data[..8]
216 );
217 }
218
219 {
221 let mut inout_data: Vec<u8> = vec![0xAA, 0xBB, 0xCC, 0xDD];
222
223 let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
225
226 op.paramTypes = raw::TEEC_PARAM_TYPES(
227 raw::TEEC_MEMREF_TEMP_INOUT,
228 raw::TEEC_NONE,
229 raw::TEEC_NONE,
230 raw::TEEC_NONE,
231 );
232 op.params[0].tmpref.buffer = inout_data.as_mut_ptr() as *mut _;
233 op.params[0].tmpref.size = inout_data.len();
234
235 session.invoke_command(Command::MemrefTempInout.into(), &mut op)?;
236 println!(
237 " TEMP_INOUT: {:?} → {:?}",
238 &[0xAA, 0xBB, 0xCC, 0xDD],
239 inout_data
240 );
241 }
242
243 Ok(())
244}
245
246fn memref_whole_input_output(session: &mut Client_Session) -> Result<()> {
248 let input_data = vec![1u8, 2, 3, 4, 5, 6, 7, 8];
249 let output_size = 8;
250
251 let mut input_shm =
253 allocate_shared_memory(session.context_mut(), input_data.len(), raw::TEEC_MEM_INPUT)?;
254 copy_to_shm(&input_data, &input_shm);
255
256 let mut output_shm =
258 allocate_shared_memory(session.context_mut(), output_size, raw::TEEC_MEM_OUTPUT)?;
259
260 let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
263 op.paramTypes = raw::TEEC_PARAM_TYPES(
264 raw::TEEC_MEMREF_WHOLE,
265 raw::TEEC_MEMREF_WHOLE,
266 raw::TEEC_NONE,
267 raw::TEEC_NONE,
268 );
269 op.params[0].memref.parent = &mut input_shm as *mut _;
270 op.params[0].memref.size = input_data.len();
271 op.params[1].memref.parent = &mut output_shm as *mut _;
272 op.params[1].memref.size = output_size;
273
274 session.invoke_command(Command::MemrefWholeInputOutput.into(), &mut op)?;
275
276 let output_data = read_from_shm(&output_shm, output_size);
277 println!(" WHOLE_INPUT+OUTPUT: {:?} → {:?}", input_data, output_data);
278
279 TEEC_ReleaseSharedMemory(&mut input_shm);
280 TEEC_ReleaseSharedMemory(&mut output_shm);
281
282 Ok(())
283}
284
285fn memref_whole_inout_allocated(session: &mut Client_Session) -> Result<()> {
287 let mut data = vec![1u8, 2, 3, 4, 5, 6, 7, 8];
288 let original = data.clone();
289 let flags = raw::TEEC_MEM_INPUT | raw::TEEC_MEM_OUTPUT;
290 let mut shm = allocate_shared_memory(session.context_mut(), data.len(), flags)?;
291
292 copy_to_shm(&data, &shm);
293
294 let mut op = create_memref_operation(&mut shm, data.len());
295
296 session.invoke_command(Command::MemrefWholeInout.into(), &mut op)?;
297
298 copy_from_shm(&shm, &mut data);
299
300 println!(" WHOLE_INOUT (Alloc): {:?} → {:?}", original, data);
301
302 TEEC_ReleaseSharedMemory(&mut shm);
303
304 Ok(())
305}
306
307fn memref_whole_inout_registered(session: &mut Client_Session) -> Result<()> {
309 let mut data = vec![1u8, 2, 3, 4, 5, 6, 7, 8];
310 let original = data.clone();
311 let flags = raw::TEEC_MEM_INPUT | raw::TEEC_MEM_OUTPUT;
312
313 let mut shm = register_shared_memory(
315 session.context_mut(),
316 data.as_mut_ptr() as *mut c_void,
317 data.len(),
318 flags,
319 )?;
320
321 let mut op = create_memref_operation(&mut shm, data.len());
322 session.invoke_command(Command::MemrefWholeInout.into(), &mut op)?;
323
324 copy_from_shm(&shm, &mut data);
327
328 println!(" WHOLE_INOUT (Register): {:?} → {:?}", original, data);
329
330 TEEC_ReleaseSharedMemory(&mut shm);
331
332 Ok(())
333}
334
335fn memref_whole(session: &mut Client_Session) -> Result<()> {
336 println!("\nMEMREF WHOLE 参数类型");
337 memref_whole_input_output(session)?;
338 memref_whole_inout_allocated(session)?;
339 memref_whole_inout_registered(session)?;
340 Ok(())
341}
342
343fn allocate_shared_memory(
344 ctx: &mut raw::TEEC_Context,
345 size: usize,
346 flags: u32,
347) -> Result<raw::TEEC_SharedMemory> {
348 let mut shm: raw::TEEC_SharedMemory = unsafe { mem::zeroed() };
350 shm.size = size;
351 shm.flags = flags;
352
353 let res = TEEC_AllocateSharedMemory(ctx, &mut shm);
354 if res != raw::TEEC_SUCCESS {
355 return Err(Error::from_raw_os_error(res as i32));
356 }
357
358 Ok(shm)
359}
360
361fn register_shared_memory(
363 ctx: &mut raw::TEEC_Context,
364 buffer: *mut c_void,
365 size: usize,
366 flags: u32,
367) -> Result<raw::TEEC_SharedMemory> {
368 let mut shm: raw::TEEC_SharedMemory = unsafe { mem::zeroed() };
370 shm.buffer = buffer;
371 shm.size = size;
372 shm.flags = flags;
373
374 let res = TEEC_RegisterSharedMemory(ctx, &mut shm);
375 if res != raw::TEEC_SUCCESS {
376 return Err(Error::from_raw_os_error(res as i32));
377 }
378
379 Ok(shm)
380}
381
382fn copy_to_shm(data: &[u8], shm: &raw::TEEC_SharedMemory) {
384 unsafe {
389 ptr::copy_nonoverlapping(data.as_ptr(), shm.buffer as *mut u8, data.len());
390 }
391}
392
393fn copy_from_shm(shm: &raw::TEEC_SharedMemory, data: &mut [u8]) {
395 unsafe {
400 ptr::copy_nonoverlapping(shm.buffer as *const u8, data.as_mut_ptr(), data.len());
401 }
402}
403
404fn read_from_shm(shm: &raw::TEEC_SharedMemory, size: usize) -> Vec<u8> {
406 let mut data = vec![0u8; size];
407 unsafe {
412 ptr::copy_nonoverlapping(shm.buffer as *const u8, data.as_mut_ptr(), size);
413 }
414 data
415}
416
417fn read_from_shm_offset(shm: &raw::TEEC_SharedMemory, offset: usize, size: usize) -> Vec<u8> {
419 let mut data = vec![0u8; size];
420 unsafe {
425 ptr::copy_nonoverlapping(
426 (shm.buffer as *const u8).add(offset),
427 data.as_mut_ptr(),
428 size,
429 );
430 }
431 data
432}
433
434fn copy_to_shm_offset(data: &[u8], shm: &raw::TEEC_SharedMemory, offset: usize) {
436 unsafe {
441 ptr::copy_nonoverlapping(
442 data.as_ptr(),
443 (shm.buffer as *mut u8).add(offset),
444 data.len(),
445 );
446 }
447}
448
449fn create_memref_operation(shm: &mut raw::TEEC_SharedMemory, size: usize) -> raw::TEEC_Operation {
451 let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
453 op.paramTypes = raw::TEEC_PARAM_TYPES(
454 raw::TEEC_MEMREF_WHOLE,
455 raw::TEEC_NONE,
456 raw::TEEC_NONE,
457 raw::TEEC_NONE,
458 );
459 op.params[0].memref.parent = shm;
460 op.params[0].memref.size = size;
461 op
462}
463
464fn memref_partial_input_output(
466 session: &mut Client_Session,
467 shm: &mut raw::TEEC_SharedMemory,
468 page_size: usize,
469) -> Result<()> {
470 let input_data = vec![0x10, 0x20, 0x30, 0x40];
471 let output_size = 8;
472 let input_offset = 0; let output_offset = page_size; copy_to_shm_offset(&input_data, shm, input_offset);
477
478 let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
480 op.paramTypes = raw::TEEC_PARAM_TYPES(
481 raw::TEEC_MEMREF_PARTIAL_INPUT,
482 raw::TEEC_MEMREF_PARTIAL_OUTPUT,
483 raw::TEEC_NONE,
484 raw::TEEC_NONE,
485 );
486 op.params[0].memref.parent = shm;
488 op.params[0].memref.offset = input_offset;
489 op.params[0].memref.size = input_data.len();
490 op.params[1].memref.parent = shm;
492 op.params[1].memref.offset = output_offset;
493 op.params[1].memref.size = output_size;
494
495 session.invoke_command(Command::MemrefPartialInputOutput.into(), &mut op)?;
496
497 let output_data = read_from_shm_offset(shm, output_offset, output_size);
499 println!(
500 " PARTIAL_INPUT+OUTPUT:\toffset[0]={:?} → offset[{}]={:?}",
501 input_data, output_offset, output_data
502 );
503
504 Ok(())
505}
506
507fn memref_partial_inout(
509 session: &mut Client_Session,
510 shm: &mut raw::TEEC_SharedMemory,
511 page_size: usize,
512) -> Result<()> {
513 let data = vec![0x01, 0x02, 0x03, 0x04];
514 let key = 0x55u8;
515 let original = data.clone();
516
517 let offset = 2 * page_size; copy_to_shm_offset(&data, shm, offset);
521
522 let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
524
525 op.paramTypes = raw::TEEC_PARAM_TYPES(
527 raw::TEEC_VALUE_INPUT,
528 raw::TEEC_MEMREF_PARTIAL_INOUT,
529 raw::TEEC_NONE,
530 raw::TEEC_NONE,
531 );
532 op.params[0].value.a = key as u32;
533 op.params[1].memref.parent = shm;
535 op.params[1].memref.offset = offset;
536 op.params[1].memref.size = data.len();
537
538 session.invoke_command(Command::MemrefPartialInout.into(), &mut op)?;
539
540 let result = read_from_shm_offset(shm, offset, data.len());
542 println!(
543 " PARTIAL_INOUT: offset[{}]={:?} ^ 0x{:02X} → {:?}",
544 offset, original, key, result
545 );
546
547 Ok(())
548}
549
550fn memref_partial(session: &mut Client_Session) -> Result<()> {
551 println!("\nMEMREF PARTIAL 参数类型");
552 let page_size = 4096;
559 let shm_size = 8 * page_size; let mut shm = allocate_shared_memory(
561 session.context_mut(),
562 shm_size,
563 raw::TEEC_MEM_INPUT | raw::TEEC_MEM_OUTPUT,
564 )?;
565
566 memref_partial_input_output(session, &mut shm, page_size)?;
567 memref_partial_inout(session, &mut shm, page_size)?;
568
569 TEEC_ReleaseSharedMemory(&mut shm);
570
571 Ok(())
572}
573
574fn mixed_params(session: &Client_Session) -> Result<()> {
576 println!("\n混合参数示例");
577 let input_data = vec![10u8, 20, 30, 40, 50];
578 let mut output_hash = vec![0u8; 4];
579
580 let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
582 op.paramTypes = raw::TEEC_PARAM_TYPES(
583 raw::TEEC_VALUE_INOUT,
584 raw::TEEC_MEMREF_TEMP_INPUT,
585 raw::TEEC_MEMREF_TEMP_OUTPUT,
586 raw::TEEC_VALUE_OUTPUT,
587 );
588
589 op.params[0].value.a = 7; op.params[1].tmpref.buffer = input_data.as_ptr() as *mut _;
591 op.params[1].tmpref.size = input_data.len();
592 op.params[2].tmpref.buffer = output_hash.as_mut_ptr() as *mut _;
593 op.params[2].tmpref.size = output_hash.len();
594
595 session.invoke_command(Command::MixedParams.into(), &mut op)?;
596
597 let counter = unsafe { op.params[0].value.a };
598 let status = unsafe { op.params[3].value.a };
599 let processed = unsafe { op.params[3].value.b };
600
601 println!(" 输入: counter={}, data={:?}", 7, input_data);
602 println!(
603 " 输出: counter={}, hash=0x{:02X}{:02X}{:02X}{:02X}, status=0x{:08X}, bytes={}",
604 counter, output_hash[3], output_hash[2], output_hash[1], output_hash[0], status, processed
605 );
606
607 Ok(())
608}
609
610fn uuid_to_teec_uuid(uuid: &Uuid) -> Result<raw::TEEC_UUID> {
611 let (time_low, time_mid, time_hi_and_version, clock_seq_and_node) = uuid.as_fields();
612
613 Ok(raw::TEEC_UUID {
614 timeLow: time_low,
615 timeMid: time_mid,
616 timeHiAndVersion: time_hi_and_version,
617 clockSeqAndNode: *clock_seq_and_node,
618 })
619}