Skip to main content

cc_teec/
cc-teec.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2025-2026 KylinSoft Co., Ltd. <https://www.kylinos.cn/>
3// See LICENSES for license details.
4
5//! rust-libteec CA 示例程序
6//!
7//! 演示如何使用 rust-libteec 库与 TEE Trusted Application 进行交互
8//! 展示所有 TEEC 参数类型的使用方法
9
10#![allow(non_camel_case_types)]
11
12use std::{
13    ffi::c_void,
14    io::{Error, ErrorKind},
15    mem, ptr,
16};
17
18use num_enum::{FromPrimitive, IntoPrimitive};
19use uuid::Uuid;
20
21use cc_teec::{
22    TEEC_AllocateSharedMemory, TEEC_CloseSession, TEEC_FinalizeContext, TEEC_InitializeContext,
23    TEEC_InvokeCommand, TEEC_OpenSession, TEEC_RegisterSharedMemory, TEEC_ReleaseSharedMemory, raw,
24};
25
26const EXAMPLE_TA_UUID: &str = "9b28392f-39d2-497d-91af-b6600e3d6a3e";
27
28#[derive(FromPrimitive, IntoPrimitive)]
29#[repr(u32)]
30pub enum Command {
31    // VALUE 类型
32    ValueInputOutput = 0, // VALUE_INPUT + VALUE_OUTPUT
33    ValueInout = 1,       // VALUE_INOUT
34
35    // MEMREF TEMP 类型
36    MemrefTempInputOutput = 10, // TEMP_INPUT + TEMP_OUTPUT
37    MemrefTempInout = 11,       // TEMP_INOUT
38
39    // MEMREF WHOLE 类型
40    MemrefWholeInputOutput = 20, // WHOLE_INPUT + WHOLE_OUTPUT
41    MemrefWholeInout = 21,       // WHOLE_INOUT
42
43    // MEMREF PARTIAL 类型
44    MemrefPartialInputOutput = 30, // PARTIAL_INPUT + PARTIAL_OUTPUT
45    MemrefPartialInout = 31,       // PARTIAL_INOUT
46
47    // 混合参数
48    MixedParams = 100,
49
50    #[default]
51    Unknown = 0xFF,
52}
53
54type Result<T> = std::result::Result<T, Error>;
55
56/// TEE 客户端会话封装结构
57///
58/// 使用 RAII 模式管理 TEE Context 和 Session 的生命周期,确保资源正确释放。
59struct Client_Session {
60    /// TEE 上下文指针,使用 Box 包裹的原因:
61    /// 1. TEEC_InitializeContext 需要可变指针,Box 提供稳定的内存地址
62    /// 2. Box 确保 ctx 在堆上分配,避免栈上的生命周期问题
63    /// 3. Drop 实现中需要调用 TEEC_FinalizeContext,Box 保证指针有效性
64    ctx: Box<raw::TEEC_Context>,
65    /// TEE 会话结构,由 TEEC_OpenSession 初始化
66    session: raw::TEEC_Session,
67}
68
69impl Client_Session {
70    fn new(uuid: &raw::TEEC_UUID) -> Result<Self> {
71        // SAFETY: `TEEC_Context` 和 `TEEC_Session` 是 POD 类型,没有无效的位模式。
72        // `mem::zeroed()` 在这里是安全的,因为这些结构体只包含整数和指针。
73        let mut ctx: Box<raw::TEEC_Context> = Box::new(unsafe { mem::zeroed() });
74        let mut session: raw::TEEC_Session = unsafe { mem::zeroed() };
75        let mut origin = 0_u32;
76
77        let res = TEEC_InitializeContext(ptr::null(), ctx.as_mut());
78        if res != raw::TEEC_SUCCESS {
79            return Err(Error::from_raw_os_error(res as i32));
80        }
81
82        let res = TEEC_OpenSession(
83            ctx.as_mut(),
84            &mut session,
85            uuid,
86            raw::TEEC_LOGIN_PUBLIC,
87            ptr::null(),
88            ptr::null_mut(),
89            &mut origin,
90        );
91
92        if res != raw::TEEC_SUCCESS {
93            TEEC_FinalizeContext(ctx.as_mut());
94            return Err(Error::from_raw_os_error(res as i32));
95        }
96
97        Ok(Self { ctx, session })
98    }
99
100    fn invoke_command(&self, cmd_id: u32, op: &mut raw::TEEC_Operation) -> Result<()> {
101        let mut origin = 0_u32;
102        let res = TEEC_InvokeCommand(&self.session as *const _ as *mut _, cmd_id, op, &mut origin);
103
104        if res != raw::TEEC_SUCCESS {
105            return Err(Error::from_raw_os_error(res as i32));
106        }
107
108        Ok(())
109    }
110
111    /// 获取 TEE Context 的可变引用
112    fn context_mut(&mut self) -> &mut raw::TEEC_Context {
113        self.ctx.as_mut()
114    }
115}
116
117impl Drop for Client_Session {
118    fn drop(&mut self) {
119        TEEC_CloseSession(&mut self.session);
120        TEEC_FinalizeContext(self.ctx.as_mut());
121    }
122}
123
124fn main() -> Result<()> {
125    let uuid = Uuid::parse_str(EXAMPLE_TA_UUID)
126        .map_err(|_| Error::new(ErrorKind::InvalidInput, "无效 UUID"))?;
127    let teec_uuid = uuid_to_teec_uuid(&uuid)?;
128    let mut session = Client_Session::new(&teec_uuid)?;
129
130    value_types(&session)?;
131    memref_temp_types(&session)?;
132    memref_whole(&mut session)?;
133    memref_partial(&mut session)?;
134    mixed_params(&session)?;
135
136    Ok(())
137}
138
139// VALUE 类型演示
140fn value_types(session: &Client_Session) -> Result<()> {
141    println!("\nVALUE 参数类型");
142
143    // VALUE_INPUT + VALUE_OUTPUT: 计算两数之和
144    {
145        // SAFETY: `TEEC_Operation` 是 POD 类型,零初始化是有效的。
146        let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
147
148        op.paramTypes = raw::TEEC_PARAM_TYPES(
149            raw::TEEC_VALUE_INPUT,
150            raw::TEEC_VALUE_OUTPUT,
151            raw::TEEC_NONE,
152            raw::TEEC_NONE,
153        );
154        op.params[0].value.a = 100;
155        op.params[0].value.b = 200;
156
157        session.invoke_command(Command::ValueInputOutput.into(), &mut op)?;
158
159        // SAFETY: `InvokeCommand` 成功后,`params[1]` 包含有效的 VALUE 输出。
160        // TA 保证为 VALUE_OUTPUT 命令写入 `value.a`。
161        let result = unsafe { op.params[1].value.a };
162        println!("  VALUE_INPUT+OUTPUT: {} + {} = {}", 100, 200, result);
163    }
164
165    // VALUE_INOUT: 数值翻倍
166    {
167        // SAFETY: `TEEC_Operation` 是 POD 类型,零初始化是有效的。
168        let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
169
170        op.paramTypes = raw::TEEC_PARAM_TYPES(
171            raw::TEEC_VALUE_INOUT,
172            raw::TEEC_NONE,
173            raw::TEEC_NONE,
174            raw::TEEC_NONE,
175        );
176        op.params[0].value.a = 42;
177        op.params[0].value.b = 99;
178
179        session.invoke_command(Command::ValueInout.into(), &mut op)?;
180
181        // SAFETY: `InvokeCommand` 成功后,`params[0]` 包含有效的 VALUE 输出。
182        // TA 保证将翻倍后的值写入 `value.a` 和 `value.b`。
183        let a_out = unsafe { op.params[0].value.a };
184        let b_out = unsafe { op.params[0].value.b };
185        println!("  VALUE_INOUT: (42, 99) → ({}, {})", a_out, b_out);
186    }
187
188    Ok(())
189}
190
191// MEMREF TEMP 类型演示
192fn memref_temp_types(session: &Client_Session) -> Result<()> {
193    println!("\nMEMREF TEMP 参数类型");
194
195    // TEMP_INPUT + TEMP_OUTPUT: 输入数据,TA 返回递增序列
196    {
197        let input_data = vec![1u8, 2, 3, 4, 5];
198        let mut output_data = vec![0u8; 16];
199
200        // SAFETY: `TEEC_Operation` 是 POD 类型,零初始化是有效的。
201        let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
202
203        op.paramTypes = raw::TEEC_PARAM_TYPES(
204            raw::TEEC_MEMREF_TEMP_INPUT,
205            raw::TEEC_MEMREF_TEMP_OUTPUT,
206            raw::TEEC_NONE,
207            raw::TEEC_NONE,
208        );
209        op.params[0].tmpref.buffer = input_data.as_ptr() as *mut _;
210        op.params[0].tmpref.size = input_data.len();
211        op.params[1].tmpref.buffer = output_data.as_mut_ptr() as *mut _;
212        op.params[1].tmpref.size = output_data.len();
213
214        session.invoke_command(Command::MemrefTempInputOutput.into(), &mut op)?;
215
216        println!(
217            "  TEMP_INPUT+OUTPUT: {:?} → {:?}",
218            input_data,
219            &output_data[..8]
220        );
221    }
222
223    // TEMP_INOUT: 按位取反
224    {
225        let mut inout_data: Vec<u8> = vec![0xAA, 0xBB, 0xCC, 0xDD];
226
227        // SAFETY: `TEEC_Operation` 是 POD 类型,零初始化是有效的。
228        let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
229
230        op.paramTypes = raw::TEEC_PARAM_TYPES(
231            raw::TEEC_MEMREF_TEMP_INOUT,
232            raw::TEEC_NONE,
233            raw::TEEC_NONE,
234            raw::TEEC_NONE,
235        );
236        op.params[0].tmpref.buffer = inout_data.as_mut_ptr() as *mut _;
237        op.params[0].tmpref.size = inout_data.len();
238
239        session.invoke_command(Command::MemrefTempInout.into(), &mut op)?;
240        println!(
241            "  TEMP_INOUT: {:?} → {:?}",
242            &[0xAA, 0xBB, 0xCC, 0xDD],
243            inout_data
244        );
245    }
246
247    Ok(())
248}
249
250// MEMREF WHOLE INPUT + OUTPUT 演示
251fn memref_whole_input_output(session: &mut Client_Session) -> Result<()> {
252    let input_data = vec![1u8, 2, 3, 4, 5, 6, 7, 8];
253    let output_size = 8;
254
255    // 分配输入共享内存
256    let mut input_shm =
257        allocate_shared_memory(session.context_mut(), input_data.len(), raw::TEEC_MEM_INPUT)?;
258    copy_to_shm(&input_data, &input_shm);
259
260    // 分配输出共享内存
261    let mut output_shm =
262        allocate_shared_memory(session.context_mut(), output_size, raw::TEEC_MEM_OUTPUT)?;
263
264    // 创建操作:参数0为INPUT,参数1为OUTPUT
265    // SAFETY: `TEEC_Operation` 是 POD 类型,零初始化是有效的。
266    let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
267    op.paramTypes = raw::TEEC_PARAM_TYPES(
268        raw::TEEC_MEMREF_WHOLE,
269        raw::TEEC_MEMREF_WHOLE,
270        raw::TEEC_NONE,
271        raw::TEEC_NONE,
272    );
273    op.params[0].memref.parent = &mut input_shm as *mut _;
274    op.params[0].memref.size = input_data.len();
275    op.params[1].memref.parent = &mut output_shm as *mut _;
276    op.params[1].memref.size = output_size;
277
278    session.invoke_command(Command::MemrefWholeInputOutput.into(), &mut op)?;
279
280    let output_data = read_from_shm(&output_shm, output_size);
281    println!("  WHOLE_INPUT+OUTPUT: {:?} → {:?}", input_data, output_data);
282
283    TEEC_ReleaseSharedMemory(&mut input_shm);
284    TEEC_ReleaseSharedMemory(&mut output_shm);
285
286    Ok(())
287}
288
289// MEMREF WHOLE INOUT 演示(使用 AllocateSharedMemory)
290fn memref_whole_inout_allocated(session: &mut Client_Session) -> Result<()> {
291    let mut data = vec![1u8, 2, 3, 4, 5, 6, 7, 8];
292    let original = data.clone();
293    let flags = raw::TEEC_MEM_INPUT | raw::TEEC_MEM_OUTPUT;
294    let mut shm = allocate_shared_memory(session.context_mut(), data.len(), flags)?;
295
296    copy_to_shm(&data, &shm);
297
298    let mut op = create_memref_operation(&mut shm, data.len());
299
300    session.invoke_command(Command::MemrefWholeInout.into(), &mut op)?;
301
302    copy_from_shm(&shm, &mut data);
303
304    println!("  WHOLE_INOUT (Alloc): {:?} → {:?}", original, data);
305
306    TEEC_ReleaseSharedMemory(&mut shm);
307
308    Ok(())
309}
310
311// MEMREF WHOLE INOUT 演示(使用 RegisterSharedMemory)
312fn memref_whole_inout_registered(session: &mut Client_Session) -> Result<()> {
313    let mut data = vec![1u8, 2, 3, 4, 5, 6, 7, 8];
314    let original = data.clone();
315    let flags = raw::TEEC_MEM_INPUT | raw::TEEC_MEM_OUTPUT;
316
317    // 注册栈上分配的缓冲区为共享内存
318    let mut shm = register_shared_memory(
319        session.context_mut(),
320        data.as_mut_ptr() as *mut c_void,
321        data.len(),
322        flags,
323    )?;
324
325    let mut op = create_memref_operation(&mut shm, data.len());
326    session.invoke_command(Command::MemrefWholeInout.into(), &mut op)?;
327
328    // RegisterSharedMemory 直接操作 CA 的栈内存,TA 修改后数据应自动可见
329    // 但通过 vsock-manager 通信时,数据经过序列化/反序列化,需要手动同步
330    copy_from_shm(&shm, &mut data);
331
332    println!("  WHOLE_INOUT (Register): {:?} → {:?}", original, data);
333
334    TEEC_ReleaseSharedMemory(&mut shm);
335
336    Ok(())
337}
338
339fn memref_whole(session: &mut Client_Session) -> Result<()> {
340    println!("\nMEMREF WHOLE 参数类型");
341    memref_whole_input_output(session)?;
342    memref_whole_inout_allocated(session)?;
343    memref_whole_inout_registered(session)?;
344    Ok(())
345}
346
347fn allocate_shared_memory(
348    ctx: &mut raw::TEEC_Context,
349    size: usize,
350    flags: u32,
351) -> Result<raw::TEEC_SharedMemory> {
352    // SAFETY: `TEEC_SharedMemory` 是 POD 类型,零初始化是有效的。
353    let mut shm: raw::TEEC_SharedMemory = unsafe { mem::zeroed() };
354    shm.size = size;
355    shm.flags = flags;
356
357    let res = TEEC_AllocateSharedMemory(ctx, &mut shm);
358    if res != raw::TEEC_SUCCESS {
359        return Err(Error::from_raw_os_error(res as i32));
360    }
361
362    Ok(shm)
363}
364
365// 注册已有的内存块为共享内存
366fn register_shared_memory(
367    ctx: &mut raw::TEEC_Context,
368    buffer: *mut c_void,
369    size: usize,
370    flags: u32,
371) -> Result<raw::TEEC_SharedMemory> {
372    // SAFETY: `TEEC_SharedMemory` 是 POD 类型,零初始化是有效的。
373    let mut shm: raw::TEEC_SharedMemory = unsafe { mem::zeroed() };
374    shm.buffer = buffer;
375    shm.size = size;
376    shm.flags = flags;
377
378    let res = TEEC_RegisterSharedMemory(ctx, &mut shm);
379    if res != raw::TEEC_SUCCESS {
380        return Err(Error::from_raw_os_error(res as i32));
381    }
382
383    Ok(shm)
384}
385
386// 复制数据到共享内存
387fn copy_to_shm(data: &[u8], shm: &raw::TEEC_SharedMemory) {
388    // SAFETY:
389    // - `data.as_ptr()` 对读取 `data.len()` 字节有效(来自 slice 保证)
390    // - `shm.buffer` 对写入有效(由 TEEC_AllocateSharedMemory 分配或注册)
391    // - 源和目标不重叠(不同的内存区域)
392    unsafe {
393        ptr::copy_nonoverlapping(data.as_ptr(), shm.buffer as *mut u8, data.len());
394    }
395}
396
397// 从共享内存复制数据到缓冲区
398fn copy_from_shm(shm: &raw::TEEC_SharedMemory, data: &mut [u8]) {
399    // SAFETY:
400    // - `shm.buffer` 对读取有效(已分配/注册的共享内存)
401    // - `data.as_mut_ptr()` 对写入 `data.len()` 字节有效(来自可变 slice)
402    // - 源和目标不重叠
403    unsafe {
404        ptr::copy_nonoverlapping(shm.buffer as *const u8, data.as_mut_ptr(), data.len());
405    }
406}
407
408// 从共享内存读取数据
409fn read_from_shm(shm: &raw::TEEC_SharedMemory, size: usize) -> Vec<u8> {
410    let mut data = vec![0u8; size];
411    // SAFETY:
412    // - `shm.buffer` 对读取 `size` 字节有效(共享内存保证)
413    // - `data.as_mut_ptr()` 对写入有效(新分配的 Vec)
414    // - 源和目标不重叠
415    unsafe {
416        ptr::copy_nonoverlapping(shm.buffer as *const u8, data.as_mut_ptr(), size);
417    }
418    data
419}
420
421// 从共享内存指定偏移量读取数据
422fn read_from_shm_offset(shm: &raw::TEEC_SharedMemory, offset: usize, size: usize) -> Vec<u8> {
423    let mut data = vec![0u8; size];
424    // SAFETY:
425    // - `(shm.buffer as *const u8).add(offset)` 在边界内(调用者确保 offset + size <= shm.size)
426    // - `data.as_mut_ptr()` 对写入有效(新分配的 Vec)
427    // - 源和目标不重叠
428    unsafe {
429        ptr::copy_nonoverlapping(
430            (shm.buffer as *const u8).add(offset),
431            data.as_mut_ptr(),
432            size,
433        );
434    }
435    data
436}
437
438// 复制数据到共享内存指定偏移量
439fn copy_to_shm_offset(data: &[u8], shm: &raw::TEEC_SharedMemory, offset: usize) {
440    // SAFETY:
441    // - `data.as_ptr()` 对读取有效(来自 slice 保证)
442    // - `(shm.buffer as *mut u8).add(offset)` 在边界内(调用者确保 offset + data.len() <= shm.size)
443    // - 源和目标不重叠
444    unsafe {
445        ptr::copy_nonoverlapping(
446            data.as_ptr(),
447            (shm.buffer as *mut u8).add(offset),
448            data.len(),
449        );
450    }
451}
452
453// 创建 MEMREF 操作参数
454fn create_memref_operation(shm: &mut raw::TEEC_SharedMemory, size: usize) -> raw::TEEC_Operation {
455    // SAFETY: `TEEC_Operation` 是 POD 类型,零初始化是有效的。
456    let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
457    op.paramTypes = raw::TEEC_PARAM_TYPES(
458        raw::TEEC_MEMREF_WHOLE,
459        raw::TEEC_NONE,
460        raw::TEEC_NONE,
461        raw::TEEC_NONE,
462    );
463    op.params[0].memref.parent = shm;
464    op.params[0].memref.size = size;
465    op
466}
467
468// MEMREF PARTIAL INPUT + OUTPUT 演示
469fn memref_partial_input_output(
470    session: &mut Client_Session,
471    shm: &mut raw::TEEC_SharedMemory,
472    page_size: usize,
473) -> Result<()> {
474    let input_data = vec![0x10, 0x20, 0x30, 0x40];
475    let output_size = 8;
476    let input_offset = 0; // 使用共享内存的起始区域
477    let output_offset = page_size; // 使用共享内存的第 2 个页(偏移 4096)
478
479    // 将输入数据复制到共享内存的指定偏移位置
480    copy_to_shm_offset(&input_data, shm, input_offset);
481
482    // SAFETY: `TEEC_Operation` 是 POD 类型,零初始化是有效的。
483    let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
484    op.paramTypes = raw::TEEC_PARAM_TYPES(
485        raw::TEEC_MEMREF_PARTIAL_INPUT,
486        raw::TEEC_MEMREF_PARTIAL_OUTPUT,
487        raw::TEEC_NONE,
488        raw::TEEC_NONE,
489    );
490    // 参数 0: PARTIAL INPUT
491    op.params[0].memref.parent = shm;
492    op.params[0].memref.offset = input_offset;
493    op.params[0].memref.size = input_data.len();
494    // 参数 1: PARTIAL OUTPUT
495    op.params[1].memref.parent = shm;
496    op.params[1].memref.offset = output_offset;
497    op.params[1].memref.size = output_size;
498
499    session.invoke_command(Command::MemrefPartialInputOutput.into(), &mut op)?;
500
501    // 从共享内存的指定偏移位置读取结果
502    let output_data = read_from_shm_offset(shm, output_offset, output_size);
503    println!(
504        "  PARTIAL_INPUT+OUTPUT:\toffset[0]={:?} → offset[{}]={:?}",
505        input_data, output_offset, output_data
506    );
507
508    Ok(())
509}
510
511// MEMREF PARTIAL INOUT 演示
512fn memref_partial_inout(
513    session: &mut Client_Session,
514    shm: &mut raw::TEEC_SharedMemory,
515    page_size: usize,
516) -> Result<()> {
517    let data = vec![0x01, 0x02, 0x03, 0x04];
518    let key = 0x55u8;
519    let original = data.clone();
520
521    let offset = 2 * page_size; // 使用共享内存的第 3 个页(偏移 8192)
522
523    // 将数据复制到共享内存的指定偏移位置
524    copy_to_shm_offset(&data, shm, offset);
525
526    // SAFETY: `TEEC_Operation` 是 POD 类型,零初始化是有效的。
527    let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
528
529    // 混合参数:VALUE_INPUT + MEMREF_PARTIAL_INOUT
530    op.paramTypes = raw::TEEC_PARAM_TYPES(
531        raw::TEEC_VALUE_INPUT,
532        raw::TEEC_MEMREF_PARTIAL_INOUT,
533        raw::TEEC_NONE,
534        raw::TEEC_NONE,
535    );
536    op.params[0].value.a = key as u32;
537    // PARTIAL 参数:只引用共享内存的一部分
538    op.params[1].memref.parent = shm;
539    op.params[1].memref.offset = offset;
540    op.params[1].memref.size = data.len();
541
542    session.invoke_command(Command::MemrefPartialInout.into(), &mut op)?;
543
544    // 从共享内存的指定偏移位置读取 XOR 加密后的结果
545    let result = read_from_shm_offset(shm, offset, data.len());
546    println!(
547        "  PARTIAL_INOUT: offset[{}]={:?} ^ 0x{:02X} → {:?}",
548        offset, original, key, result
549    );
550
551    Ok(())
552}
553
554fn memref_partial(session: &mut Client_Session) -> Result<()> {
555    println!("\nMEMREF PARTIAL 参数类型");
556    // 分配共享内存(需要足够大以支持多个 PARTIAL 引用)
557    // 内存布局:
558    //   [0 ~ 4095]       : PARTIAL INPUT 使用的区域
559    //   [4096 ~ 8191]    : PARTIAL OUTPUT 使用的区域
560    //   [8192 ~ 12287]   : PARTIAL INOUT 使用的区域
561    //   [12288 ~ 32767]  : 未使用
562    let page_size = 4096;
563    let shm_size = 8 * page_size; // 32KB
564    let mut shm = allocate_shared_memory(
565        session.context_mut(),
566        shm_size,
567        raw::TEEC_MEM_INPUT | raw::TEEC_MEM_OUTPUT,
568    )?;
569
570    memref_partial_input_output(session, &mut shm, page_size)?;
571    memref_partial_inout(session, &mut shm, page_size)?;
572
573    TEEC_ReleaseSharedMemory(&mut shm);
574
575    Ok(())
576}
577
578// 混合参数演示
579fn mixed_params(session: &Client_Session) -> Result<()> {
580    println!("\n混合参数示例");
581    let input_data = vec![10u8, 20, 30, 40, 50];
582    let mut output_hash = vec![0u8; 4];
583
584    // SAFETY: `TEEC_Operation` 是 POD 类型,零初始化是有效的。
585    let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
586    op.paramTypes = raw::TEEC_PARAM_TYPES(
587        raw::TEEC_VALUE_INOUT,
588        raw::TEEC_MEMREF_TEMP_INPUT,
589        raw::TEEC_MEMREF_TEMP_OUTPUT,
590        raw::TEEC_VALUE_OUTPUT,
591    );
592
593    op.params[0].value.a = 7; // counter
594    op.params[1].tmpref.buffer = input_data.as_ptr() as *mut _;
595    op.params[1].tmpref.size = input_data.len();
596    op.params[2].tmpref.buffer = output_hash.as_mut_ptr() as *mut _;
597    op.params[2].tmpref.size = output_hash.len();
598
599    session.invoke_command(Command::MixedParams.into(), &mut op)?;
600
601    let counter = unsafe { op.params[0].value.a };
602    let status = unsafe { op.params[3].value.a };
603    let processed = unsafe { op.params[3].value.b };
604
605    println!("  输入: counter={}, data={:?}", 7, input_data);
606    println!(
607        "  输出: counter={}, hash=0x{:02X}{:02X}{:02X}{:02X}, status=0x{:08X}, bytes={}",
608        counter, output_hash[3], output_hash[2], output_hash[1], output_hash[0], status, processed
609    );
610
611    Ok(())
612}
613
614fn uuid_to_teec_uuid(uuid: &Uuid) -> Result<raw::TEEC_UUID> {
615    let (time_low, time_mid, time_hi_and_version, clock_seq_and_node) = uuid.as_fields();
616
617    Ok(raw::TEEC_UUID {
618        timeLow: time_low,
619        timeMid: time_mid,
620        timeHiAndVersion: time_hi_and_version,
621        clockSeqAndNode: *clock_seq_and_node,
622    })
623}