Skip to main content

cc_teec/
cc-teec.rs

1//! rust-libteec CA 示例程序
2//!
3//! 演示如何使用 rust-libteec 库与 TEE Trusted Application 进行交互
4//! 展示所有 TEEC 参数类型的使用方法
5
6#![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    // VALUE 类型
28    ValueInputOutput = 0, // VALUE_INPUT + VALUE_OUTPUT
29    ValueInout = 1,       // VALUE_INOUT
30
31    // MEMREF TEMP 类型
32    MemrefTempInputOutput = 10, // TEMP_INPUT + TEMP_OUTPUT
33    MemrefTempInout = 11,       // TEMP_INOUT
34
35    // MEMREF WHOLE 类型
36    MemrefWholeInputOutput = 20, // WHOLE_INPUT + WHOLE_OUTPUT
37    MemrefWholeInout = 21,       // WHOLE_INOUT
38
39    // MEMREF PARTIAL 类型
40    MemrefPartialInputOutput = 30, // PARTIAL_INPUT + PARTIAL_OUTPUT
41    MemrefPartialInout = 31,       // PARTIAL_INOUT
42
43    // 混合参数
44    MixedParams = 100,
45
46    #[default]
47    Unknown = 0xFF,
48}
49
50type Result<T> = std::result::Result<T, Error>;
51
52/// TEE 客户端会话封装结构
53///
54/// 使用 RAII 模式管理 TEE Context 和 Session 的生命周期,确保资源正确释放。
55struct Client_Session {
56    /// TEE 上下文指针,使用 Box 包裹的原因:
57    /// 1. TEEC_InitializeContext 需要可变指针,Box 提供稳定的内存地址
58    /// 2. Box 确保 ctx 在堆上分配,避免栈上的生命周期问题
59    /// 3. Drop 实现中需要调用 TEEC_FinalizeContext,Box 保证指针有效性
60    ctx: Box<raw::TEEC_Context>,
61    /// TEE 会话结构,由 TEEC_OpenSession 初始化
62    session: raw::TEEC_Session,
63}
64
65impl Client_Session {
66    fn new(uuid: &raw::TEEC_UUID) -> Result<Self> {
67        // SAFETY: `TEEC_Context` 和 `TEEC_Session` 是 POD 类型,没有无效的位模式。
68        // `mem::zeroed()` 在这里是安全的,因为这些结构体只包含整数和指针。
69        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    /// 获取 TEE Context 的可变引用
108    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
135// VALUE 类型演示
136fn value_types(session: &Client_Session) -> Result<()> {
137    println!("\nVALUE 参数类型");
138
139    // VALUE_INPUT + VALUE_OUTPUT: 计算两数之和
140    {
141        // SAFETY: `TEEC_Operation` 是 POD 类型,零初始化是有效的。
142        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        // SAFETY: `InvokeCommand` 成功后,`params[1]` 包含有效的 VALUE 输出。
156        // TA 保证为 VALUE_OUTPUT 命令写入 `value.a`。
157        let result = unsafe { op.params[1].value.a };
158        println!("  VALUE_INPUT+OUTPUT: {} + {} = {}", 100, 200, result);
159    }
160
161    // VALUE_INOUT: 数值翻倍
162    {
163        // SAFETY: `TEEC_Operation` 是 POD 类型,零初始化是有效的。
164        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        // SAFETY: `InvokeCommand` 成功后,`params[0]` 包含有效的 VALUE 输出。
178        // TA 保证将翻倍后的值写入 `value.a` 和 `value.b`。
179        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
187// MEMREF TEMP 类型演示
188fn memref_temp_types(session: &Client_Session) -> Result<()> {
189    println!("\nMEMREF TEMP 参数类型");
190
191    // TEMP_INPUT + TEMP_OUTPUT: 输入数据,TA 返回递增序列
192    {
193        let input_data = vec![1u8, 2, 3, 4, 5];
194        let mut output_data = vec![0u8; 16];
195
196        // SAFETY: `TEEC_Operation` 是 POD 类型,零初始化是有效的。
197        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    // TEMP_INOUT: 按位取反
220    {
221        let mut inout_data: Vec<u8> = vec![0xAA, 0xBB, 0xCC, 0xDD];
222
223        // SAFETY: `TEEC_Operation` 是 POD 类型,零初始化是有效的。
224        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
246// MEMREF WHOLE INPUT + OUTPUT 演示
247fn 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    // 分配输入共享内存
252    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    // 分配输出共享内存
257    let mut output_shm =
258        allocate_shared_memory(session.context_mut(), output_size, raw::TEEC_MEM_OUTPUT)?;
259
260    // 创建操作:参数0为INPUT,参数1为OUTPUT
261    // SAFETY: `TEEC_Operation` 是 POD 类型,零初始化是有效的。
262    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
285// MEMREF WHOLE INOUT 演示(使用 AllocateSharedMemory)
286fn 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
307// MEMREF WHOLE INOUT 演示(使用 RegisterSharedMemory)
308fn 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    // 注册栈上分配的缓冲区为共享内存
314    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    // RegisterSharedMemory 直接操作 CA 的栈内存,TA 修改后数据应自动可见
325    // 但通过 vsock-manager 通信时,数据经过序列化/反序列化,需要手动同步
326    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    // SAFETY: `TEEC_SharedMemory` 是 POD 类型,零初始化是有效的。
349    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
361// 注册已有的内存块为共享内存
362fn 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    // SAFETY: `TEEC_SharedMemory` 是 POD 类型,零初始化是有效的。
369    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
382// 复制数据到共享内存
383fn copy_to_shm(data: &[u8], shm: &raw::TEEC_SharedMemory) {
384    // SAFETY:
385    // - `data.as_ptr()` 对读取 `data.len()` 字节有效(来自 slice 保证)
386    // - `shm.buffer` 对写入有效(由 TEEC_AllocateSharedMemory 分配或注册)
387    // - 源和目标不重叠(不同的内存区域)
388    unsafe {
389        ptr::copy_nonoverlapping(data.as_ptr(), shm.buffer as *mut u8, data.len());
390    }
391}
392
393// 从共享内存复制数据到缓冲区
394fn copy_from_shm(shm: &raw::TEEC_SharedMemory, data: &mut [u8]) {
395    // SAFETY:
396    // - `shm.buffer` 对读取有效(已分配/注册的共享内存)
397    // - `data.as_mut_ptr()` 对写入 `data.len()` 字节有效(来自可变 slice)
398    // - 源和目标不重叠
399    unsafe {
400        ptr::copy_nonoverlapping(shm.buffer as *const u8, data.as_mut_ptr(), data.len());
401    }
402}
403
404// 从共享内存读取数据
405fn read_from_shm(shm: &raw::TEEC_SharedMemory, size: usize) -> Vec<u8> {
406    let mut data = vec![0u8; size];
407    // SAFETY:
408    // - `shm.buffer` 对读取 `size` 字节有效(共享内存保证)
409    // - `data.as_mut_ptr()` 对写入有效(新分配的 Vec)
410    // - 源和目标不重叠
411    unsafe {
412        ptr::copy_nonoverlapping(shm.buffer as *const u8, data.as_mut_ptr(), size);
413    }
414    data
415}
416
417// 从共享内存指定偏移量读取数据
418fn read_from_shm_offset(shm: &raw::TEEC_SharedMemory, offset: usize, size: usize) -> Vec<u8> {
419    let mut data = vec![0u8; size];
420    // SAFETY:
421    // - `(shm.buffer as *const u8).add(offset)` 在边界内(调用者确保 offset + size <= shm.size)
422    // - `data.as_mut_ptr()` 对写入有效(新分配的 Vec)
423    // - 源和目标不重叠
424    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
434// 复制数据到共享内存指定偏移量
435fn copy_to_shm_offset(data: &[u8], shm: &raw::TEEC_SharedMemory, offset: usize) {
436    // SAFETY:
437    // - `data.as_ptr()` 对读取有效(来自 slice 保证)
438    // - `(shm.buffer as *mut u8).add(offset)` 在边界内(调用者确保 offset + data.len() <= shm.size)
439    // - 源和目标不重叠
440    unsafe {
441        ptr::copy_nonoverlapping(
442            data.as_ptr(),
443            (shm.buffer as *mut u8).add(offset),
444            data.len(),
445        );
446    }
447}
448
449// 创建 MEMREF 操作参数
450fn create_memref_operation(shm: &mut raw::TEEC_SharedMemory, size: usize) -> raw::TEEC_Operation {
451    // SAFETY: `TEEC_Operation` 是 POD 类型,零初始化是有效的。
452    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
464// MEMREF PARTIAL INPUT + OUTPUT 演示
465fn 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; // 使用共享内存的起始区域
473    let output_offset = page_size; // 使用共享内存的第 2 个页(偏移 4096)
474
475    // 将输入数据复制到共享内存的指定偏移位置
476    copy_to_shm_offset(&input_data, shm, input_offset);
477
478    // SAFETY: `TEEC_Operation` 是 POD 类型,零初始化是有效的。
479    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    // 参数 0: PARTIAL INPUT
487    op.params[0].memref.parent = shm;
488    op.params[0].memref.offset = input_offset;
489    op.params[0].memref.size = input_data.len();
490    // 参数 1: PARTIAL OUTPUT
491    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    // 从共享内存的指定偏移位置读取结果
498    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
507// MEMREF PARTIAL INOUT 演示
508fn 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; // 使用共享内存的第 3 个页(偏移 8192)
518
519    // 将数据复制到共享内存的指定偏移位置
520    copy_to_shm_offset(&data, shm, offset);
521
522    // SAFETY: `TEEC_Operation` 是 POD 类型,零初始化是有效的。
523    let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
524
525    // 混合参数:VALUE_INPUT + MEMREF_PARTIAL_INOUT
526    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    // PARTIAL 参数:只引用共享内存的一部分
534    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    // 从共享内存的指定偏移位置读取 XOR 加密后的结果
541    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    // 分配共享内存(需要足够大以支持多个 PARTIAL 引用)
553    // 内存布局:
554    //   [0 ~ 4095]       : PARTIAL INPUT 使用的区域
555    //   [4096 ~ 8191]    : PARTIAL OUTPUT 使用的区域
556    //   [8192 ~ 12287]   : PARTIAL INOUT 使用的区域
557    //   [12288 ~ 32767]  : 未使用
558    let page_size = 4096;
559    let shm_size = 8 * page_size; // 32KB
560    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
574// 混合参数演示
575fn 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    // SAFETY: `TEEC_Operation` 是 POD 类型,零初始化是有效的。
581    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; // counter
590    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}