This is an automated email from the ASF dual-hosted git repository.

yuanz pushed a commit to branch main
in repository 
https://gitbox.apache.org/repos/asf/incubator-teaclave-trustzone-sdk.git


The following commit(s) were added to refs/heads/main by this push:
     new 0a0ab8a  optee-utee: Enable TA-to-TA Invocation
0a0ab8a is described below

commit 0a0ab8acd0d6f74b0994a782fc309bc11fe78a10
Author: Yuan Zhuang <[email protected]>
AuthorDate: Tue Apr 8 07:23:53 2025 +0000

    optee-utee: Enable TA-to-TA Invocation
    
    This commit provides the Rust API for GP API TEE_InvokeTACommand(),
    which enable the user TA calls another user TA or pseudo TA.
    
    - Add abstraction of TeeParameters and TaSession;
    - Add inter-ta example and test scripts.
    
    Signed-off-by: Yuan Zhuang <[email protected]>
    Reviewed-by: Zehui Chen <[email protected]>
---
 ci/ci.sh                                          |   1 +
 ci/ci.sh => examples/inter_ta-rs/Makefile         |  52 +--
 ci/ci.sh => examples/inter_ta-rs/host/Cargo.toml  |  52 +--
 ci/ci.sh => examples/inter_ta-rs/host/Makefile    |  60 ++--
 examples/inter_ta-rs/host/src/main.rs             |  32 ++
 ci/ci.sh => examples/inter_ta-rs/proto/Cargo.toml |  49 +--
 examples/inter_ta-rs/proto/src/lib.rs             |  57 ++++
 ci/ci.sh => examples/inter_ta-rs/ta/Cargo.toml    |  56 ++--
 examples/inter_ta-rs/ta/Makefile                  |  45 +++
 ci/ci.sh => examples/inter_ta-rs/ta/Xargo.toml    |  45 +--
 examples/inter_ta-rs/ta/build.rs                  |  26 ++
 examples/inter_ta-rs/ta/src/main.rs               | 152 +++++++++
 examples/inter_ta-rs/uuid.txt                     |   1 +
 optee-utee/src/error.rs                           | 199 ++++++++----
 optee-utee/src/lib.rs                             |  26 +-
 optee-utee/src/ta_session.rs                      | 146 +++++++++
 optee-utee/src/tee_parameter.rs                   | 372 ++++++++++++++++++++++
 ci/ci.sh => tests/test_inter_ta.sh                |  52 ++-
 18 files changed, 1085 insertions(+), 338 deletions(-)

diff --git a/ci/ci.sh b/ci/ci.sh
index 6f026bc..53ada6f 100755
--- a/ci/ci.sh
+++ b/ci/ci.sh
@@ -52,6 +52,7 @@ fi
 ./test_tcp_client.sh
 ./test_udp_socket.sh
 ./test_client_pool.sh
+./test_inter_ta.sh
 
 
 popd
diff --git a/ci/ci.sh b/examples/inter_ta-rs/Makefile
old mode 100755
new mode 100644
similarity index 50%
copy from ci/ci.sh
copy to examples/inter_ta-rs/Makefile
index 6f026bc..a7a3dec
--- a/ci/ci.sh
+++ b/examples/inter_ta-rs/Makefile
@@ -1,5 +1,3 @@
-#!/bin/bash
-
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -17,41 +15,25 @@
 # specific language governing permissions and limitations
 # under the License.
 
-set -xe
+# If _HOST or _TA specific compiler/target are not specified, then use common
+# compiler/target for both
+CROSS_COMPILE_HOST ?= aarch64-linux-gnu-
+CROSS_COMPILE_TA ?= aarch64-linux-gnu-
+TARGET_HOST ?= aarch64-unknown-linux-gnu
+TARGET_TA ?= aarch64-unknown-linux-gnu
 
-pushd ../tests
+.PHONY: host ta all clean
 
-# Prioritize running specialized test suites first, as they have a higher
-# probability of detecting failures early in the pipeline.
-# Run std only tests
-if [ "$STD" ]; then
-    ./test_serde.sh
-    ./test_message_passing_interface.sh
-    ./test_tls_client.sh
-    ./test_tls_server.sh
-    ./test_eth_wallet.sh
-    ./test_secure_db_abstraction.sh
-else
-    ./test_mnist_rs.sh
-fi
+all: host ta
 
-./test_hello_world.sh
-./test_random.sh
-./test_secure_storage.sh
-./test_aes.sh
-./test_hotp.sh
-./test_acipher.sh
-./test_big_int.sh
-./test_diffie_hellman.sh
-./test_digest.sh
-./test_authentication.sh
-./test_time.sh
-./test_signature_verification.sh
-./test_supp_plugin.sh
-./test_error_handling.sh
-./test_tcp_client.sh
-./test_udp_socket.sh
-./test_client_pool.sh
+host:
+       $(q)make -C host TARGET=$(TARGET_HOST) \
+               CROSS_COMPILE=$(CROSS_COMPILE_HOST)
 
+ta:
+       $(q)make -C ta TARGET=$(TARGET_TA) \
+               CROSS_COMPILE=$(CROSS_COMPILE_TA)
 
-popd
+clean:
+       $(q)make -C host clean
+       $(q)make -C ta clean
diff --git a/ci/ci.sh b/examples/inter_ta-rs/host/Cargo.toml
old mode 100755
new mode 100644
similarity index 50%
copy from ci/ci.sh
copy to examples/inter_ta-rs/host/Cargo.toml
index 6f026bc..c11c427
--- a/ci/ci.sh
+++ b/examples/inter_ta-rs/host/Cargo.toml
@@ -1,5 +1,3 @@
-#!/bin/bash
-
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -17,41 +15,19 @@
 # specific language governing permissions and limitations
 # under the License.
 
-set -xe
-
-pushd ../tests
-
-# Prioritize running specialized test suites first, as they have a higher
-# probability of detecting failures early in the pipeline.
-# Run std only tests
-if [ "$STD" ]; then
-    ./test_serde.sh
-    ./test_message_passing_interface.sh
-    ./test_tls_client.sh
-    ./test_tls_server.sh
-    ./test_eth_wallet.sh
-    ./test_secure_db_abstraction.sh
-else
-    ./test_mnist_rs.sh
-fi
-
-./test_hello_world.sh
-./test_random.sh
-./test_secure_storage.sh
-./test_aes.sh
-./test_hotp.sh
-./test_acipher.sh
-./test_big_int.sh
-./test_diffie_hellman.sh
-./test_digest.sh
-./test_authentication.sh
-./test_time.sh
-./test_signature_verification.sh
-./test_supp_plugin.sh
-./test_error_handling.sh
-./test_tcp_client.sh
-./test_udp_socket.sh
-./test_client_pool.sh
+[package]
+name = "inter_ta-rs"
+version = "0.4.0"
+authors = ["Teaclave Contributors <[email protected]>"]
+license = "Apache-2.0"
+repository = "https://github.com/apache/incubator-teaclave-trustzone-sdk.git";
+description = "An example of Rust OP-TEE TrustZone SDK."
+edition = "2018"
 
+[dependencies]
+libc = "0.2.48"
+proto = { path = "../proto" }
+optee-teec = { path = "../../../optee-teec" }
 
-popd
+[profile.release]
+lto = true
diff --git a/ci/ci.sh b/examples/inter_ta-rs/host/Makefile
old mode 100755
new mode 100644
similarity index 50%
copy from ci/ci.sh
copy to examples/inter_ta-rs/host/Makefile
index 6f026bc..55a5c7e
--- a/ci/ci.sh
+++ b/examples/inter_ta-rs/host/Makefile
@@ -1,5 +1,3 @@
-#!/bin/bash
-
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -17,41 +15,23 @@
 # specific language governing permissions and limitations
 # under the License.
 
-set -xe
-
-pushd ../tests
-
-# Prioritize running specialized test suites first, as they have a higher
-# probability of detecting failures early in the pipeline.
-# Run std only tests
-if [ "$STD" ]; then
-    ./test_serde.sh
-    ./test_message_passing_interface.sh
-    ./test_tls_client.sh
-    ./test_tls_server.sh
-    ./test_eth_wallet.sh
-    ./test_secure_db_abstraction.sh
-else
-    ./test_mnist_rs.sh
-fi
-
-./test_hello_world.sh
-./test_random.sh
-./test_secure_storage.sh
-./test_aes.sh
-./test_hotp.sh
-./test_acipher.sh
-./test_big_int.sh
-./test_diffie_hellman.sh
-./test_digest.sh
-./test_authentication.sh
-./test_time.sh
-./test_signature_verification.sh
-./test_supp_plugin.sh
-./test_error_handling.sh
-./test_tcp_client.sh
-./test_udp_socket.sh
-./test_client_pool.sh
-
-
-popd
+NAME := inter_ta-rs
+
+TARGET ?= aarch64-unknown-linux-gnu
+CROSS_COMPILE ?= aarch64-linux-gnu-
+OBJCOPY := $(CROSS_COMPILE)objcopy
+LINKER_CFG := target.$(TARGET).linker=\"$(CROSS_COMPILE)gcc\"
+
+OUT_DIR := $(CURDIR)/target/$(TARGET)/release
+
+
+all: host strip
+
+host:
+       @cargo build --target $(TARGET_HOST) --release --config $(LINKER_CFG)
+
+strip: host
+       @$(OBJCOPY) --strip-unneeded $(OUT_DIR)/$(NAME) $(OUT_DIR)/$(NAME)
+
+clean:
+       @cargo clean
diff --git a/examples/inter_ta-rs/host/src/main.rs 
b/examples/inter_ta-rs/host/src/main.rs
new file mode 100644
index 0000000..1647efd
--- /dev/null
+++ b/examples/inter_ta-rs/host/src/main.rs
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use optee_teec::{Context, ErrorKind, Operation, ParamNone, Uuid};
+use proto::{Command, UUID};
+
+fn main() -> optee_teec::Result<()> {
+    let mut ctx = Context::new()?;
+    let uuid =
+        Uuid::parse_str(UUID).map_err(|_| 
optee_teec::Error::from(ErrorKind::BadParameters))?;
+    let mut session = ctx.open_session(uuid)?;
+    let mut operation = Operation::new(0, ParamNone, ParamNone, ParamNone, 
ParamNone);
+
+    // Nothing to send, just invoke the Test command
+    session.invoke_command(Command::Test as u32, &mut operation)?;
+    println!("Success");
+    Ok(())
+}
diff --git a/ci/ci.sh b/examples/inter_ta-rs/proto/Cargo.toml
old mode 100755
new mode 100644
similarity index 50%
copy from ci/ci.sh
copy to examples/inter_ta-rs/proto/Cargo.toml
index 6f026bc..91066a3
--- a/ci/ci.sh
+++ b/examples/inter_ta-rs/proto/Cargo.toml
@@ -1,5 +1,3 @@
-#!/bin/bash
-
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -17,41 +15,14 @@
 # specific language governing permissions and limitations
 # under the License.
 
-set -xe
-
-pushd ../tests
-
-# Prioritize running specialized test suites first, as they have a higher
-# probability of detecting failures early in the pipeline.
-# Run std only tests
-if [ "$STD" ]; then
-    ./test_serde.sh
-    ./test_message_passing_interface.sh
-    ./test_tls_client.sh
-    ./test_tls_server.sh
-    ./test_eth_wallet.sh
-    ./test_secure_db_abstraction.sh
-else
-    ./test_mnist_rs.sh
-fi
-
-./test_hello_world.sh
-./test_random.sh
-./test_secure_storage.sh
-./test_aes.sh
-./test_hotp.sh
-./test_acipher.sh
-./test_big_int.sh
-./test_diffie_hellman.sh
-./test_digest.sh
-./test_authentication.sh
-./test_time.sh
-./test_signature_verification.sh
-./test_supp_plugin.sh
-./test_error_handling.sh
-./test_tcp_client.sh
-./test_udp_socket.sh
-./test_client_pool.sh
-
+[package]
+name = "proto"
+version = "0.4.0"
+authors = ["Teaclave Contributors <[email protected]>"]
+license = "Apache-2.0"
+repository = "https://github.com/apache/incubator-teaclave-trustzone-sdk.git";
+description = "Data structures and functions shared by host and TA."
+edition = "2018"
 
-popd
+[dependencies]
+num_enum = { version = "0.7.3", default-features = false }
diff --git a/examples/inter_ta-rs/proto/src/lib.rs 
b/examples/inter_ta-rs/proto/src/lib.rs
new file mode 100644
index 0000000..44583ba
--- /dev/null
+++ b/examples/inter_ta-rs/proto/src/lib.rs
@@ -0,0 +1,57 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#![no_std]
+use num_enum::{FromPrimitive, IntoPrimitive};
+
+// For CA-TA invocation:
+#[derive(FromPrimitive, IntoPrimitive)]
+#[repr(u32)]
+pub enum Command {
+    Test,
+    #[default]
+    Unknown,
+}
+
+// If Uuid::parse_str() returns an InvalidLength error, there may be an extra
+// newline in your uuid.txt file. You can remove it by running
+// `truncate -s 36 uuid.txt`.
+pub const UUID: &str = &include_str!("../../uuid.txt");
+
+// For TA-TA invocation testcases:
+#[derive(FromPrimitive, IntoPrimitive)]
+#[repr(u32)]
+pub enum SystemPtaCommand {
+    AddRngEntropy,
+    DeriveTaUniqueKey,
+    // We omit other commands here.
+    // Full definitions can be found in optee_os system_pta.h.
+    #[default]
+    Unknown,
+}
+
+#[derive(FromPrimitive, IntoPrimitive)]
+#[repr(u32)]
+pub enum HelloWorldTaCommand {
+    IncValue,
+    DecValue,
+    #[default]
+    Unknown,
+}
+
+pub const SYSTEM_PTA_UUID: &str = "3a2f8978-5dc0-11e8-9c2d-fa7ae01bbebc";
+pub const HELLO_WORLD_USER_TA_UUID: &str = 
"133af0ca-bdab-11eb-9130-43bf7873bf67";
diff --git a/ci/ci.sh b/examples/inter_ta-rs/ta/Cargo.toml
old mode 100755
new mode 100644
similarity index 50%
copy from ci/ci.sh
copy to examples/inter_ta-rs/ta/Cargo.toml
index 6f026bc..4a0f9d2
--- a/ci/ci.sh
+++ b/examples/inter_ta-rs/ta/Cargo.toml
@@ -1,5 +1,3 @@
-#!/bin/bash
-
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -17,41 +15,25 @@
 # specific language governing permissions and limitations
 # under the License.
 
-set -xe
-
-pushd ../tests
-
-# Prioritize running specialized test suites first, as they have a higher
-# probability of detecting failures early in the pipeline.
-# Run std only tests
-if [ "$STD" ]; then
-    ./test_serde.sh
-    ./test_message_passing_interface.sh
-    ./test_tls_client.sh
-    ./test_tls_server.sh
-    ./test_eth_wallet.sh
-    ./test_secure_db_abstraction.sh
-else
-    ./test_mnist_rs.sh
-fi
+[package]
+name = "ta"
+version = "0.4.0"
+authors = ["Teaclave Contributors <[email protected]>"]
+license = "Apache-2.0"
+repository = "https://github.com/apache/incubator-teaclave-trustzone-sdk.git";
+description = "An example of Rust OP-TEE TrustZone SDK."
+edition = "2018"
 
-./test_hello_world.sh
-./test_random.sh
-./test_secure_storage.sh
-./test_aes.sh
-./test_hotp.sh
-./test_acipher.sh
-./test_big_int.sh
-./test_diffie_hellman.sh
-./test_digest.sh
-./test_authentication.sh
-./test_time.sh
-./test_signature_verification.sh
-./test_supp_plugin.sh
-./test_error_handling.sh
-./test_tcp_client.sh
-./test_udp_socket.sh
-./test_client_pool.sh
+[dependencies]
+proto = { path = "../proto" }
+optee-utee-sys = { path = "../../../optee-utee/optee-utee-sys" }
+optee-utee = { path = "../../../optee-utee" }
 
+[build-dependencies]
+proto = { path = "../proto" }
+optee-utee-build = { path = "../../../optee-utee-build" }
 
-popd
+[profile.release]
+panic = "abort"
+lto = true
+opt-level = 1
diff --git a/examples/inter_ta-rs/ta/Makefile b/examples/inter_ta-rs/ta/Makefile
new file mode 100644
index 0000000..029e66d
--- /dev/null
+++ b/examples/inter_ta-rs/ta/Makefile
@@ -0,0 +1,45 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+UUID ?= $(shell cat "../uuid.txt")
+
+TARGET ?= aarch64-unknown-linux-gnu
+CROSS_COMPILE ?= aarch64-linux-gnu-
+OBJCOPY := $(CROSS_COMPILE)objcopy
+# Configure the linker to use GCC, which works on both cross-compilation and 
ARM machines
+LINKER_CFG := target.$(TARGET).linker=\"$(CROSS_COMPILE)gcc\"
+
+TA_SIGN_KEY ?= $(TA_DEV_KIT_DIR)/keys/default_ta.pem
+SIGN := $(TA_DEV_KIT_DIR)/scripts/sign_encrypt.py
+OUT_DIR := $(CURDIR)/target/$(TARGET)/release
+
+BUILDER = $(if $(STD),xargo,cargo)
+
+all: ta strip sign
+
+ta:
+       @$(BUILDER) build --target $(TARGET) --release --config $(LINKER_CFG)
+
+strip: ta
+       @$(OBJCOPY) --strip-unneeded $(OUT_DIR)/ta $(OUT_DIR)/stripped_ta
+
+sign: strip
+       @$(SIGN) --uuid $(UUID) --key $(TA_SIGN_KEY) --in 
$(OUT_DIR)/stripped_ta --out $(OUT_DIR)/$(UUID).ta
+       @echo "SIGN =>  ${UUID}"
+
+clean:
+       @cargo clean
diff --git a/ci/ci.sh b/examples/inter_ta-rs/ta/Xargo.toml
old mode 100755
new mode 100644
similarity index 50%
copy from ci/ci.sh
copy to examples/inter_ta-rs/ta/Xargo.toml
index 6f026bc..1b1a113
--- a/ci/ci.sh
+++ b/examples/inter_ta-rs/ta/Xargo.toml
@@ -1,5 +1,3 @@
-#!/bin/bash
-
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -17,41 +15,10 @@
 # specific language governing permissions and limitations
 # under the License.
 
-set -xe
-
-pushd ../tests
-
-# Prioritize running specialized test suites first, as they have a higher
-# probability of detecting failures early in the pipeline.
-# Run std only tests
-if [ "$STD" ]; then
-    ./test_serde.sh
-    ./test_message_passing_interface.sh
-    ./test_tls_client.sh
-    ./test_tls_server.sh
-    ./test_eth_wallet.sh
-    ./test_secure_db_abstraction.sh
-else
-    ./test_mnist_rs.sh
-fi
-
-./test_hello_world.sh
-./test_random.sh
-./test_secure_storage.sh
-./test_aes.sh
-./test_hotp.sh
-./test_acipher.sh
-./test_big_int.sh
-./test_diffie_hellman.sh
-./test_digest.sh
-./test_authentication.sh
-./test_time.sh
-./test_signature_verification.sh
-./test_supp_plugin.sh
-./test_error_handling.sh
-./test_tcp_client.sh
-./test_udp_socket.sh
-./test_client_pool.sh
-
+[dependencies.std]
+path = "../../../rust/rust/library/std"
 
-popd
+[patch.crates-io]
+libc =  { path = "../../../rust/libc" }
+rustc-std-workspace-core = { path = 
"../../../rust/rust/library/rustc-std-workspace-core" }
+rustc-std-workspace-alloc = { path = 
"../../../rust/rust/library/rustc-std-workspace-alloc" }
diff --git a/examples/inter_ta-rs/ta/build.rs b/examples/inter_ta-rs/ta/build.rs
new file mode 100644
index 0000000..d492383
--- /dev/null
+++ b/examples/inter_ta-rs/ta/build.rs
@@ -0,0 +1,26 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use optee_utee_build::{Error, RustEdition, TaConfig};
+use proto;
+
+fn main() -> Result<(), Error> {
+    let config = TaConfig::new_default_with_cargo_env(proto::UUID)?
+        .ta_data_size(1 * 1024 * 1024)
+        .ta_stack_size(1 * 1024 * 1024);
+    optee_utee_build::build(RustEdition::Before2024, config)
+}
diff --git a/examples/inter_ta-rs/ta/src/main.rs 
b/examples/inter_ta-rs/ta/src/main.rs
new file mode 100644
index 0000000..fe2f6d1
--- /dev/null
+++ b/examples/inter_ta-rs/ta/src/main.rs
@@ -0,0 +1,152 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#![no_std]
+#![no_main]
+
+use optee_utee::{
+    ta_close_session, ta_create, ta_destroy, ta_invoke_command, 
ta_open_session, trace_println,
+};
+use optee_utee::{Error, ErrorKind, Parameters, Result, Uuid};
+use optee_utee::{ParamIndex, TaSessionBuilder, TeeParams};
+use proto::{
+    Command, HelloWorldTaCommand, SystemPtaCommand, HELLO_WORLD_USER_TA_UUID, 
SYSTEM_PTA_UUID,
+};
+
+#[ta_create]
+fn create() -> Result<()> {
+    trace_println!("[+] TA create");
+    Ok(())
+}
+
+#[ta_open_session]
+fn open_session(_params: &mut Parameters) -> Result<()> {
+    trace_println!("[+] TA open session");
+    Ok(())
+}
+
+#[ta_close_session]
+fn close_session() {
+    trace_println!("[+] TA close session");
+}
+
+#[ta_destroy]
+fn destroy() {
+    trace_println!("[+] TA destroy");
+}
+
+fn test_invoke_system_pta() -> Result<()> {
+    let system_pta_uuid =
+        Uuid::parse_str(SYSTEM_PTA_UUID).map_err(|_| 
Error::from(ErrorKind::BadFormat))?;
+    // Open a session using the default timeout (TEE_TIMEOUT_INFINITE, meaning 
no timeout), and no parameters:
+    let mut session = TaSessionBuilder::new(system_pta_uuid).build()?;
+    trace_println!("[+] TA open PTA session success");
+
+    let input: [u8; 32] = [0; 32];
+    let mut output: [u8; 32] = [0; 32];
+
+    // Construct parameters using chained method calls, max 4 parameters:
+    let mut params = TeeParams::new()
+        .with_memref_in(ParamIndex::Arg0, &input)
+        .with_memref_out(ParamIndex::Arg1, &mut output);
+
+    // Invoke the command using the default timeout, meaning no timeout:
+    session.invoke_command(SystemPtaCommand::DeriveTaUniqueKey as u32, &mut 
params)?;
+
+    // Get the output buffer through written_slice():
+    // Note: written_slice() returns a slice of the original output buffer, 
with the length
+    // adjusted to the actual size written by the TA.
+    let written_slice = params[ParamIndex::Arg1]
+        .written_slice()
+        .ok_or(Error::new(ErrorKind::BadParameters))?;
+
+    trace_println!("[+] TA invoke PTA command, output: {:?}", written_slice);
+
+    // Check if the output is not all zeroes and has the expected length:
+    if written_slice.len() != 32 {
+        trace_println!(
+            "[-] TA invoke PTA command failed, wrong output length: {:?}",
+            written_slice.len()
+        );
+        return Err(Error::new(ErrorKind::Generic));
+    }
+
+    if written_slice.iter().all(|&x| x == 0) {
+        trace_println!("[-] TA invoke PTA command failed, output is all 0");
+        return Err(Error::new(ErrorKind::Generic));
+    }
+
+    trace_println!("[+] TA invoke System PTA command success");
+
+    Ok(())
+}
+
+fn test_invoke_hello_world_user_ta() -> Result<()> {
+    let hello_world_user_ta_uuid =
+        Uuid::parse_str(HELLO_WORLD_USER_TA_UUID).map_err(|_| 
Error::from(ErrorKind::BadFormat))?;
+    // Open a session with a specified timeout in milliseconds (10 seconds).
+    // To pass parameters during session opening, use `.with_params(xxx)`.
+    let mut session = TaSessionBuilder::new(hello_world_user_ta_uuid)
+        .with_timeout(10000)
+        .build()?;
+    trace_println!("[+] TA open user TA session success");
+
+    let mut params = TeeParams::new().with_value_inout(ParamIndex::Arg0, 29, 
0);
+    // Invoke the command with a specified timeout in milliseconds (10 
seconds).
+    session.invoke_command_with_timeout(
+        HelloWorldTaCommand::IncValue as u32,
+        &mut params,
+        10000,
+    )?;
+
+    // Get the output value pair through output_value():
+    let (value_a, _value_b) = params[ParamIndex::Arg0]
+        .output_value()
+        .ok_or(Error::new(ErrorKind::BadParameters))?;
+
+    // Check if the output value is as expected:
+    if value_a != 129 {
+        trace_println!(
+            "[-] TA invoke user TA command failed, wrong output value: {:?}",
+            value_a
+        );
+        return Err(Error::new(ErrorKind::Generic));
+    }
+
+    trace_println!("[+] TA invoke hello world TA command success.");
+
+    Ok(())
+}
+
+#[ta_invoke_command]
+fn invoke_command(cmd_id: u32, _params: &mut Parameters) -> Result<()> {
+    trace_println!("[+] TA invoke command");
+    match Command::from(cmd_id) {
+        Command::Test => {
+            test_invoke_system_pta()?;
+            test_invoke_hello_world_user_ta()?;
+
+            trace_println!("[+] Test passed");
+            Ok(())
+        }
+        _ => {
+            return Err(Error::new(ErrorKind::NotSupported));
+        }
+    }
+}
+
+include!(concat!(env!("OUT_DIR"), "/user_ta_header.rs"));
diff --git a/examples/inter_ta-rs/uuid.txt b/examples/inter_ta-rs/uuid.txt
new file mode 100644
index 0000000..6c50099
--- /dev/null
+++ b/examples/inter_ta-rs/uuid.txt
@@ -0,0 +1 @@
+fa9ea860-ef3b-4d59-8457-5564a60c0379
\ No newline at end of file
diff --git a/optee-utee/src/error.rs b/optee-utee/src/error.rs
index b71c4f5..97ea941 100644
--- a/optee-utee/src/error.rs
+++ b/optee-utee/src/error.rs
@@ -15,12 +15,12 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use optee_utee_sys as raw;
+#[cfg(not(target_os = "optee"))]
+use core::error;
 use core::{fmt, result};
+use optee_utee_sys as raw;
 #[cfg(target_os = "optee")]
 use std::error;
-#[cfg(not(target_os = "optee"))]
-use core::error;
 
 /// A specialized 
[`Result`](https://doc.rust-lang.org/std/result/enum.Result.html)
 /// type for TEE operations.
@@ -34,76 +34,79 @@ use core::error;
 /// ````
 pub type Result<T> = result::Result<T, Error>;
 
+#[derive(Clone)]
 pub struct Error {
-    code: u32,
+    kind: ErrorKind,
+    origin: Option<ErrorOrigin>,
 }
 
 /// A list specifying general categories of TEE error and its corresponding 
code
 /// in OP-TEE OS.
-#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
 #[repr(u32)]
 pub enum ErrorKind {
     /// Object corruption.
-    CorruptObject = 0xF0100001,
+    CorruptObject = raw::TEE_ERROR_CORRUPT_OBJECT,
     /// Persistent object corruption.
-    CorruptObject2 = 0xF0100002,
+    CorruptObject2 = raw::TEE_ERROR_CORRUPT_OBJECT_2,
     /// Object storage is not available.
-    StorageNotAvailable = 0xF0100003,
+    StorageNotAvailable = raw::TEE_ERROR_STORAGE_NOT_AVAILABLE,
     /// Persistent object storage is not available.
-    StorageNotAvailable2 = 0xF0100004,
+    StorageNotAvailable2 = raw::TEE_ERROR_STORAGE_NOT_AVAILABLE_2,
     /// Non-specific cause.
-    Generic = 0xFFFF0000,
+    Generic = raw::TEE_ERROR_GENERIC,
     /// Access privileges are not sufficient.
-    AccessDenied = 0xFFFF0001,
+    AccessDenied = raw::TEE_ERROR_ACCESS_DENIED,
     /// The operation was canceled.
-    Cancel = 0xFFFF0002,
+    Cancel = raw::TEE_ERROR_CANCEL,
     /// Concurrent accesses caused conflict.
-    AccessConflict = 0xFFFF0003,
+    AccessConflict = raw::TEE_ERROR_ACCESS_CONFLICT,
     /// Too much data for the requested operation was passed.
-    ExcessData = 0xFFFF0004,
+    ExcessData = raw::TEE_ERROR_EXCESS_DATA,
     /// Input data was of invalid format.
-    BadFormat = 0xFFFF0005,
+    BadFormat = raw::TEE_ERROR_BAD_FORMAT,
     /// Input parameters were invalid.
-    BadParameters = 0xFFFF0006,
+    BadParameters = raw::TEE_ERROR_BAD_PARAMETERS,
     /// Operation is not valid in the current state.
-    BadState = 0xFFFF0007,
+    BadState = raw::TEE_ERROR_BAD_STATE,
     /// The requested data item is not found.
-    ItemNotFound = 0xFFFF0008,
+    ItemNotFound = raw::TEE_ERROR_ITEM_NOT_FOUND,
     /// The requested operation should exist but is not yet implemented.
-    NotImplemented = 0xFFFF0009,
+    NotImplemented = raw::TEE_ERROR_NOT_IMPLEMENTED,
     /// The requested operation is valid but is not supported in this 
implementation.
-    NotSupported = 0xFFFF000A,
+    NotSupported = raw::TEE_ERROR_NOT_SUPPORTED,
     /// Expected data was missing.
-    NoData = 0xFFFF000B,
+    NoData = raw::TEE_ERROR_NO_DATA,
     /// System ran out of resources.
-    OutOfMemory = 0xFFFF000C,
+    OutOfMemory = raw::TEE_ERROR_OUT_OF_MEMORY,
     /// The system is busy working on something else.
-    Busy = 0xFFFF000D,
+    Busy = raw::TEE_ERROR_BUSY,
     /// Communication with a remote party failed.
-    Communication = 0xFFFF000E,
+    Communication = raw::TEE_ERROR_COMMUNICATION,
     /// A security fault was detected.
-    Security = 0xFFFF000F,
+    Security = raw::TEE_ERROR_SECURITY,
     /// The supplied buffer is too short for the generated output.
-    ShortBuffer = 0xFFFF0010,
+    ShortBuffer = raw::TEE_ERROR_SHORT_BUFFER,
     /// The operation has been cancelled by an external event which occurred in
     /// the REE while the function was in progress.
-    ExternalCancel = 0xFFFF0011,
+    ExternalCancel = raw::TEE_ERROR_EXTERNAL_CANCEL,
     /// Data overflow.
-    Overflow = 0xFFFF300F,
+    Overflow = raw::TEE_ERROR_OVERFLOW,
     /// Trusted Application has panicked during the operation.
-    TargetDead = 0xFFFF3024,
+    TargetDead = raw::TEE_ERROR_TARGET_DEAD,
     /// Insufficient space is available.
-    StorageNoSpace = 0xFFFF3041,
+    StorageNoSpace = raw::TEE_ERROR_STORAGE_NO_SPACE,
     /// MAC is invalid.
-    MacInvalid = 0xFFFF3071,
+    MacInvalid = raw::TEE_ERROR_MAC_INVALID,
     /// Signature is invalid.
-    SignatureInvalid = 0xFFFF3072,
+    SignatureInvalid = raw::TEE_ERROR_SIGNATURE_INVALID,
     /// The persistent time has not been set.
-    TimeNotSet = 0xFFFF5000,
+    TimeNotSet = raw::TEE_ERROR_TIME_NOT_SET,
     /// The persistent time has been set but may have been corrupted and SHALL
     /// no longer be trusted.
-    TimeNeedsReset = 0xFFFF5001,
+    TimeNeedsReset = raw::TEE_ERROR_TIME_NEEDS_RESET,
     /// Unknown error.
+    #[default]
     Unknown,
 }
 
@@ -150,36 +153,15 @@ impl ErrorKind {
     }
 }
 
-impl Error {
-    pub fn new(kind: ErrorKind) -> Error {
-        Error { code: kind as u32 }
-    }
-
-    /// Creates a new instance of an `Error` from a particular TEE error code.
-    ///
-    /// # Examples
-    ///
-    /// ``` no_run
-    /// use optee_utee;
-    ///
-    /// let error = optee_utee::Error::from_raw_error(0xFFFF000F);
-    /// assert_eq!(error.kind(), optee_utee::ErrorKind::Security);
-    /// ```
-    pub fn from_raw_error(code: u32) -> Error {
-        Error { code }
+impl From<ErrorKind> for u32 {
+    fn from(kind: ErrorKind) -> u32 {
+        kind as u32
     }
+}
 
-    /// Returns the corresponding `ErrorKind` for this error.
-    ///
-    /// # Examples
-    ///
-    /// ``` no_run
-    /// use optee_utee;
-    ///
-    /// let error = optee_utee::Error::new(optee_utee::ErrorKind::Security);
-    /// ```
-    pub fn kind(&self) -> ErrorKind {
-        match self.code {
+impl From<u32> for ErrorKind {
+    fn from(code: u32) -> ErrorKind {
+        match code {
             raw::TEE_ERROR_CORRUPT_OBJECT => ErrorKind::CorruptObject,
             raw::TEE_ERROR_CORRUPT_OBJECT_2 => ErrorKind::CorruptObject2,
             raw::TEE_ERROR_STORAGE_NOT_AVAILABLE => 
ErrorKind::StorageNotAvailable,
@@ -212,11 +194,59 @@ impl Error {
             _ => ErrorKind::Unknown,
         }
     }
+}
+
+impl Error {
+    pub fn new(kind: ErrorKind) -> Error {
+        Error { kind, origin: None }
+    }
+
+    /// Creates a new instance of an `Error` from a particular TEE error code.
+    ///
+    /// # Examples
+    ///
+    /// ``` no_run
+    /// use optee_utee;
+    ///
+    /// let error = optee_utee::Error::from_raw_error(0xFFFF000F);
+    /// assert_eq!(error.kind(), optee_utee::ErrorKind::Security);
+    /// ```
+    pub fn from_raw_error(code: u32) -> Error {
+        Error {
+            kind: ErrorKind::from(code),
+            origin: None,
+        }
+    }
 
+    pub fn with_origin(mut self, origin: ErrorOrigin) -> Self {
+        self.origin = Some(origin);
+        self
+    }
+
+    /// Returns the corresponding `ErrorKind` for this error.
+    ///
+    /// # Examples
+    ///
+    /// ``` no_run
+    /// use optee_utee;
+    ///
+    /// let error = optee_utee::Error::new(optee_utee::ErrorKind::Security);
+    /// ```
+    pub fn kind(&self) -> ErrorKind {
+        self.kind
+    }
+
+    /// Returns the origin of this error.
+    pub fn origin(&self) -> Option<ErrorOrigin> {
+        self.origin.clone()
+    }
+
+    /// Returns raw code of this error.
     pub fn raw_code(&self) -> u32 {
-        self.code
+        self.kind.into()
     }
 
+    /// Returns corresponding error message of this error.
     pub fn message(&self) -> &str {
         self.kind().as_str()
     }
@@ -224,13 +254,19 @@ impl Error {
 
 impl fmt::Debug for Error {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        write!(fmt, "{} (error code 0x{:x})", self.message(), self.code)
+        write!(
+            fmt,
+            "{} (error code 0x{:x}, origin 0x{:x})",
+            self.message(),
+            self.raw_code(),
+            self.origin().map(|v| v.into()).unwrap_or(0_u32),
+        )
     }
 }
 
 impl fmt::Display for Error {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        write!(fmt, "{} (error code 0x{:x})", self.message(), self.code)
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(self, f)
     }
 }
 
@@ -243,6 +279,35 @@ impl error::Error for Error {
 impl From<ErrorKind> for Error {
     #[inline]
     fn from(kind: ErrorKind) -> Error {
-        Error { code: kind as u32 }
+        Error { kind, origin: None }
+    }
+}
+
+#[derive(Clone, Debug, Default, Eq, PartialEq)]
+#[repr(u32)]
+pub enum ErrorOrigin {
+    API = raw::TEE_ORIGIN_API,
+    COMMS = raw::TEE_ORIGIN_COMMS,
+    TEE = raw::TEE_ORIGIN_TEE,
+    TA = raw::TEE_ORIGIN_TRUSTED_APP,
+    #[default]
+    UNKNOWN,
+}
+
+impl From<ErrorOrigin> for u32 {
+    fn from(origin: ErrorOrigin) -> u32 {
+        origin as u32
+    }
+}
+
+impl From<u32> for ErrorOrigin {
+    fn from(code: u32) -> ErrorOrigin {
+        match code {
+            raw::TEE_ORIGIN_API => ErrorOrigin::API,
+            raw::TEE_ORIGIN_COMMS => ErrorOrigin::COMMS,
+            raw::TEE_ORIGIN_TEE => ErrorOrigin::TEE,
+            raw::TEE_ORIGIN_TRUSTED_APP => ErrorOrigin::TA,
+            _ => ErrorOrigin::UNKNOWN,
+        }
     }
 }
diff --git a/optee-utee/src/lib.rs b/optee-utee/src/lib.rs
index af65778..795c5ca 100644
--- a/optee-utee/src/lib.rs
+++ b/optee-utee/src/lib.rs
@@ -37,18 +37,22 @@ use optee_utee_sys as raw;
 #[cfg(all(not(target_os = "optee"), not(feature = "no_panic_handler")))]
 #[panic_handler]
 fn panic(_info: &PanicInfo) -> ! {
-    unsafe { raw::TEE_Panic(0); }
+    unsafe {
+        raw::TEE_Panic(0);
+    }
     loop {}
 }
 
+pub use self::arithmetical::*;
+pub use self::crypto_op::*;
 pub use self::error::{Error, ErrorKind, Result};
+pub use self::extension::*;
 pub use self::object::*;
-pub use self::crypto_op::*;
+pub use self::parameter::{ParamType, ParamTypes, Parameter, Parameters};
+pub use self::ta_session::{TaSession, TaSessionBuilder};
+pub use self::tee_parameter::{ParamIndex, TeeParams};
 pub use self::time::*;
-pub use self::arithmetical::*;
-pub use self::extension::*;
 pub use self::uuid::*;
-pub use self::parameter::{ParamType, ParamTypes, Parameter, Parameters};
 pub use optee_utee_macros::{
     ta_close_session, ta_create, ta_destroy, ta_invoke_command, 
ta_open_session,
 };
@@ -56,12 +60,14 @@ pub use optee_utee_macros::{
 pub mod trace;
 #[macro_use]
 mod macros;
+pub mod arithmetical;
+pub mod crypto_op;
 mod error;
-mod parameter;
+pub mod extension;
+pub mod net;
 pub mod object;
-pub mod crypto_op;
+mod parameter;
+mod ta_session;
+mod tee_parameter;
 pub mod time;
-pub mod arithmetical;
-pub mod extension;
 pub mod uuid;
-pub mod net;
diff --git a/optee-utee/src/ta_session.rs b/optee-utee/src/ta_session.rs
new file mode 100644
index 0000000..f50a59a
--- /dev/null
+++ b/optee-utee/src/ta_session.rs
@@ -0,0 +1,146 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use crate::{Error, Result, TeeParams, Uuid};
+use optee_utee_sys as raw;
+
+pub struct TaSessionBuilder<'a> {
+    target_uuid: Uuid,
+    timeout: u32,
+    params: Option<TeeParams<'a>>,
+}
+
+impl<'a> TaSessionBuilder<'a> {
+    /// Creates a new builder for the given TA UUID.
+    pub fn new(uuid: Uuid) -> Self {
+        Self {
+            target_uuid: uuid,
+            timeout: raw::TEE_TIMEOUT_INFINITE,
+            params: None,
+        }
+    }
+
+    /// Sets a custom timeout for the session opening.
+    pub fn with_timeout(mut self, timeout: u32) -> Self {
+        self.timeout = timeout;
+        self
+    }
+
+    /// Sets the parameters to be passed during session opening.
+    pub fn with_params(mut self, params: TeeParams<'a>) -> Self {
+        self.params = Some(params);
+        self
+    }
+
+    /// Builds and opens the `TaSession`. Returns an error if the session 
fails to open.
+    pub fn build(mut self) -> Result<TaSession> {
+        let mut err_origin: u32 = 0;
+        let mut raw_session: raw::TEE_TASessionHandle = core::ptr::null_mut();
+        // Check if the parameters are provided and prepare them for the C API 
call.
+        let (raw_param_types, raw_params_ptr, raw_params_opt) =
+            if let Some(params) = &mut self.params {
+                let mut raw_params = params.as_raw();
+                let raw_ptr = raw_params.as_mut_ptr();
+                (params.raw_param_types(), raw_ptr, Some(raw_params))
+            } else {
+                (0, core::ptr::null_mut(), None)
+            };
+
+        // SAFETY:
+        // self.target_uuid.as_raw_ptr() provides a valid pointer to the UUID.
+        // raw_params.as_mut_ptr() provides a valid pointer to the parameters.
+        // The remaining arguments are either valid values or null/mut 
pointers as expected by the C API.
+        // For parameters that are intended to be modified by the call, the 
buffer constraints are checked later in update_from_raw().
+        match unsafe {
+            raw::TEE_OpenTASession(
+                self.target_uuid.as_raw_ptr(),
+                self.timeout,
+                raw_param_types,
+                raw_params_ptr,
+                &mut raw_session,
+                &mut err_origin,
+            )
+        } {
+            raw::TEE_SUCCESS => {
+                if let (Some(params), Some(raw_params)) = (&mut self.params, 
raw_params_opt) {
+                    params.update_from_raw(&raw_params)?;
+                }
+
+                Ok(TaSession { raw: raw_session })
+            }
+            code => 
Err(Error::from_raw_error(code).with_origin(err_origin.into())),
+        }
+    }
+}
+
+pub struct TaSession {
+    raw: raw::TEE_TASessionHandle,
+}
+
+impl TaSession {
+    /// Invokes a command with the provided parameters using the session's 
default timeout.
+    /// Returns the result directly without allowing further method chaining.
+    pub fn invoke_command(&mut self, command_id: u32, params: &mut TeeParams) 
-> Result<()> {
+        self.invoke_command_with_timeout(command_id, params, 
raw::TEE_TIMEOUT_INFINITE)
+    }
+
+    pub fn invoke_command_with_timeout(
+        &mut self,
+        command_id: u32,
+        params: &mut TeeParams,
+        timeout: u32,
+    ) -> Result<()> {
+        let mut err_origin: u32 = 0;
+        let mut raw_params = params.as_raw();
+        let param_types = params.raw_param_types();
+
+        // SAFETY:
+        // self.raw is a valid pointer to an active session handle.
+        // raw_params.as_mut_ptr() yields a valid mutable pointer to the 
parameters array.
+        // The remaining arguments are either valid values or null/mutable 
pointers, as expected by the C API.
+        // For parameters that are intended to be modified by the call, the 
buffer constraints are checked later in update_from_raw().
+        match unsafe {
+            raw::TEE_InvokeTACommand(
+                self.raw,
+                timeout,
+                command_id,
+                param_types,
+                raw_params.as_mut_ptr(),
+                &mut err_origin,
+            )
+        } {
+            raw::TEE_SUCCESS => {
+                // Update the parameters with the results
+                params.update_from_raw(&raw_params)?;
+                Ok(())
+            }
+            code => 
Err(Error::from_raw_error(code).with_origin(err_origin.into())),
+        }
+    }
+}
+
+// Drop implementation to close the session
+impl Drop for TaSession {
+    fn drop(&mut self) {
+        // SAFETY:
+        // self.raw is a valid pointer to an active session handle.
+        // The function call is expected to clean up the session resources.
+        unsafe {
+            raw::TEE_CloseTASession(self.raw);
+        }
+    }
+}
diff --git a/optee-utee/src/tee_parameter.rs b/optee-utee/src/tee_parameter.rs
new file mode 100644
index 0000000..7c91d19
--- /dev/null
+++ b/optee-utee/src/tee_parameter.rs
@@ -0,0 +1,372 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use crate::{Error, ErrorKind, ParamType, Result};
+use core::ops::{Index, IndexMut};
+use optee_utee_sys as raw;
+
+#[derive(Copy, Clone, Debug)]
+pub enum ParamIndex {
+    Arg0,
+    Arg1,
+    Arg2,
+    Arg3,
+}
+
+impl ParamIndex {
+    fn to_usize(self) -> usize {
+        match self {
+            ParamIndex::Arg0 => 0,
+            ParamIndex::Arg1 => 1,
+            ParamIndex::Arg2 => 2,
+            ParamIndex::Arg3 => 3,
+        }
+    }
+}
+
+enum ParamContent<'a> {
+    None,
+    MemrefInput {
+        buffer: &'a [u8],
+    },
+    MemrefOutput {
+        buffer: &'a mut [u8],
+        written: usize,
+    },
+    MemrefInout {
+        buffer: &'a mut [u8],
+        written: usize,
+    },
+    ValueInput {
+        a: u32,
+        b: u32,
+    },
+    ValueOutput {
+        a: u32,
+        b: u32,
+    },
+    ValueInout {
+        a: u32,
+        b: u32,
+    },
+}
+
+pub struct Param<'a> {
+    content: ParamContent<'a>,
+}
+
+impl<'a> Param<'a> {
+    fn new() -> Self {
+        Self {
+            content: ParamContent::None,
+        }
+    }
+
+    /// Returns the written slice if available (for `MemrefOutput` or 
`MemrefInout`).
+    /// Returns `None` for other types. Developers can decide whether to treat 
absence as an error.
+    pub fn written_slice(&self) -> Option<&[u8]> {
+        match &self.content {
+            ParamContent::MemrefOutput { buffer, written } => 
Some(&buffer[..*written]),
+            ParamContent::MemrefInout { buffer, written } => 
Some(&buffer[..*written]),
+            _ => None,
+        }
+    }
+
+    /// Returns the output values if available (for `ValueOutput` or 
`ValueInout`).
+    /// Returns `None` for other types. Caller decides how to handle missing 
values.
+    pub fn output_value(&self) -> Option<(u32, u32)> {
+        match &self.content {
+            ParamContent::ValueOutput { a, b } => Some((*a, *b)),
+            ParamContent::ValueInout { a, b } => Some((*a, *b)),
+            _ => None,
+        }
+    }
+
+    fn get_type(&self) -> ParamType {
+        match &self.content {
+            ParamContent::None => ParamType::None,
+            ParamContent::MemrefInput { .. } => ParamType::MemrefInput,
+            ParamContent::MemrefOutput { .. } => ParamType::MemrefOutput,
+            ParamContent::MemrefInout { .. } => ParamType::MemrefInout,
+            ParamContent::ValueInput { .. } => ParamType::ValueInput,
+            ParamContent::ValueOutput { .. } => ParamType::ValueOutput,
+            ParamContent::ValueInout { .. } => ParamType::ValueInout,
+        }
+    }
+
+    fn get_raw_type(&self) -> u32 {
+        self.get_type() as u32
+    }
+
+    fn as_raw(&mut self) -> raw::TEE_Param {
+        match &mut self.content {
+            ParamContent::None => raw::TEE_Param {
+                memref: raw::Memref {
+                    buffer: core::ptr::null_mut(),
+                    size: 0,
+                },
+            },
+            ParamContent::MemrefInput { buffer } => raw::TEE_Param {
+                memref: raw::Memref {
+                    buffer: (*buffer).as_ptr() as *mut core::ffi::c_void,
+                    size: buffer.len(),
+                },
+            },
+            ParamContent::MemrefOutput { buffer, written: _ } => 
raw::TEE_Param {
+                memref: raw::Memref {
+                    buffer: (*buffer).as_mut_ptr() as *mut core::ffi::c_void,
+                    size: buffer.len(),
+                },
+            },
+            ParamContent::MemrefInout { buffer, written: _ } => raw::TEE_Param 
{
+                memref: raw::Memref {
+                    buffer: (*buffer).as_mut_ptr() as *mut core::ffi::c_void,
+                    size: buffer.len(),
+                },
+            },
+            ParamContent::ValueInput { a, b } => raw::TEE_Param {
+                value: raw::Value { a: *a, b: *b },
+            },
+            ParamContent::ValueInout { a, b } => raw::TEE_Param {
+                value: raw::Value { a: *a, b: *b },
+            },
+            ParamContent::ValueOutput { a, b } => raw::TEE_Param {
+                value: raw::Value { a: *a, b: *b },
+            },
+        }
+    }
+
+    fn update_size_from_raw(&mut self, raw_param: &raw::TEE_Param) -> 
Result<()> {
+        match &mut self.content {
+            ParamContent::MemrefOutput { buffer, written } => {
+                // SAFETY:
+                // The caller must ensure this param is of memref type and 
properly initialized.
+                // This is enforced by the variant match on 
`ParamContent::MemrefOutput`.
+                // Accessing `raw_param.memref.size` is safe under these 
assumptions.
+                let new_size = unsafe { raw_param.memref.size };
+                if new_size > (*buffer).len() {
+                    return Err(Error::new(ErrorKind::BadParameters));
+                }
+                *written = new_size;
+                Ok(())
+            }
+            ParamContent::MemrefInout { buffer, written } => {
+                // SAFETY:
+                // The caller must ensure this param is of memref type and 
properly initialized.
+                // This is enforced by the variant match on 
`ParamContent::MemrefOutput`.
+                // Accessing `raw_param.memref.size` is safe under these 
assumptions.
+                let new_size = unsafe { raw_param.memref.size };
+                if new_size > (*buffer).len() {
+                    return Err(Error::new(ErrorKind::BadParameters));
+                }
+                *written = new_size;
+                Ok(())
+            }
+            _ => {
+                return Err(Error::new(ErrorKind::BadFormat));
+            }
+        }
+    }
+
+    fn update_value_from_raw(&mut self, raw_param: &raw::TEE_Param) {
+        match &mut self.content {
+            ParamContent::ValueInout { a, b } => {
+                // SAFETY:
+                // The caller must ensure this param is of value type and 
properly initialized.
+                // This is guaranteed by matching against 
`ParamContent::ValueInout`.
+                // Accessing `raw_param.value.a` is safe under above 
assumption.
+                *a = unsafe { raw_param.value.a };
+                // SAFETY:
+                // Accessing `raw_param.value.b` is safe under above 
assumption.
+                *b = unsafe { raw_param.value.b };
+            }
+            ParamContent::ValueOutput { a, b } => {
+                // SAFETY:
+                // The caller must ensure this param is of value type and 
properly initialized.
+                // This is guaranteed by matching against 
`ParamContent::ValueInout`.
+                // Accessing `raw_param.value.a` is safe under above 
assumption.
+                *a = unsafe { raw_param.value.a };
+                // SAFETY:
+                // Accessing `raw_param.value.b` is safe under above 
assumption.
+                *b = unsafe { raw_param.value.b };
+            }
+            _ => {}
+        }
+    }
+}
+
+/// The TeeParams struct is used to manage the parameters for TEE commands.
+pub struct TeeParams<'a> {
+    params: [Param<'a>; 4],
+}
+
+impl<'a> TeeParams<'a> {
+    pub fn new() -> Self {
+        Self {
+            params: [Param::new(), Param::new(), Param::new(), Param::new()],
+        }
+    }
+
+    /// These functions allow for method-chaining to easily configure multiple 
parameters at once.
+    ///
+    /// The following methods can be chained:
+    /// - `with_memref_in`: Sets a memory reference input parameter.
+    /// - `with_memref_out`: Sets a memory reference output parameter.
+    /// - `with_memref_inout`: Sets a memory reference inout parameter.
+    /// - `with_value_in`: Sets a value input parameter.
+    /// - `with_value_out`: Sets a value output parameter.
+    /// - `with_value_inout`: Sets a value inout parameter.
+    ///
+    /// Example usage:
+    /// ``` no_run
+    /// let params = TeeParams::new()
+    ///     .with_memref_in(ParamIndex::Arg0, &input_buffer)
+    ///     .with_memref_out(ParamIndex::Arg1, &mut output_buffer)
+    ///     .with_value_in(ParamIndex::Arg2, 42, 0)
+    ///     .with_value_out(ParamIndex::Arg3, 0, 0);
+    /// ```
+    pub fn with_memref_in(mut self, idx: ParamIndex, buffer: &'a [u8]) -> Self 
{
+        self[idx].content = ParamContent::MemrefInput { buffer };
+        self
+    }
+
+    pub fn with_memref_out(mut self, idx: ParamIndex, buffer: &'a mut [u8]) -> 
Self {
+        self[idx].content = ParamContent::MemrefOutput { buffer, written: 0 };
+        self
+    }
+
+    pub fn with_memref_inout(mut self, idx: ParamIndex, buffer: &'a mut [u8]) 
-> Self {
+        self[idx].content = ParamContent::MemrefInout { buffer, written: 0 };
+        self
+    }
+
+    pub fn with_value_in(mut self, idx: ParamIndex, a: u32, b: u32) -> Self {
+        self[idx].content = ParamContent::ValueInput { a, b };
+        self
+    }
+
+    pub fn with_value_out(mut self, idx: ParamIndex, a: u32, b: u32) -> Self {
+        self[idx].content = ParamContent::ValueOutput { a, b };
+        self
+    }
+
+    pub fn with_value_inout(mut self, idx: ParamIndex, a: u32, b: u32) -> Self 
{
+        self[idx].content = ParamContent::ValueInout { a, b };
+        self
+    }
+
+    /// These methods allow the user to set the content at a specific index.
+    ///
+    /// Example usage:
+    /// ``` no_run
+    /// let mut params = TeeParams::new();
+    /// params.set_memref_in(ParamIndex::Arg0, &input_buffer);
+    /// params.set_memref_out(ParamIndex::Arg1, &mut output_buffer);
+    /// params.set_value_in(ParamIndex::Arg2, 42, 0);
+    /// params.set_value_out(ParamIndex::Arg3, 0, 0);
+    /// ```
+    pub fn set_memref_in(&mut self, idx: ParamIndex, buffer: &'a [u8]) -> &mut 
Self {
+        self[idx].content = ParamContent::MemrefInput { buffer };
+        self
+    }
+
+    pub fn set_memref_out(&mut self, idx: ParamIndex, buffer: &'a mut [u8]) -> 
&mut Self {
+        self[idx].content = ParamContent::MemrefOutput { buffer, written: 0 };
+        self
+    }
+
+    pub fn set_memref_inout(&mut self, idx: ParamIndex, buffer: &'a mut [u8]) 
-> &mut Self {
+        self[idx].content = ParamContent::MemrefInout { buffer, written: 0 };
+        self
+    }
+
+    pub fn set_value_in(&mut self, idx: ParamIndex, a: u32, b: u32) -> &mut 
Self {
+        self[idx].content = ParamContent::ValueInput { a, b };
+        self
+    }
+
+    pub fn set_value_out(&mut self, idx: ParamIndex, a: u32, b: u32) -> &mut 
Self {
+        self[idx].content = ParamContent::ValueOutput { a, b };
+        self
+    }
+
+    pub fn set_value_inout(&mut self, idx: ParamIndex, a: u32, b: u32) -> &mut 
Self {
+        self[idx].content = ParamContent::ValueInout { a, b };
+        self
+    }
+
+    pub(crate) fn raw_param_types(&self) -> u32 {
+        let mut param_types = 0;
+        for (i, param) in self.params.iter().enumerate() {
+            param_types |= param.get_raw_type() << (i * 4);
+        }
+        param_types
+    }
+
+    pub(crate) fn as_raw(&mut self) -> [raw::TEE_Param; 4] {
+        [
+            self.params[0].as_raw(),
+            self.params[1].as_raw(),
+            self.params[2].as_raw(),
+            self.params[3].as_raw(),
+        ]
+    }
+
+    /// Updates the parameters with results after each TEE call.
+    ///
+    /// This function updates the content of parameters for `MemrefInout`, 
`MemrefOutput`, `ValueInout`, and `ValueOutput`.
+    /// Parameters of other types are not modified.
+    pub(crate) fn update_from_raw(&mut self, raw_params: &[raw::TEE_Param; 4]) 
-> Result<()> {
+        // update the content for memref inout/out, and value inout/out
+        for (i, param) in self.params.iter_mut().enumerate() {
+            let raw_param = &raw_params[i];
+            match param.get_type() {
+                ParamType::MemrefOutput => {
+                    param.update_size_from_raw(raw_param)?;
+                }
+                ParamType::MemrefInout => {
+                    param.update_size_from_raw(raw_param)?;
+                }
+                ParamType::ValueOutput => {
+                    param.update_value_from_raw(raw_param);
+                }
+                ParamType::ValueInout => {
+                    param.update_value_from_raw(raw_param);
+                }
+                _ => {
+                    // No action needed for other types
+                }
+            }
+        }
+        Ok(())
+    }
+}
+
+// Index trait implementations for direct parameter access
+impl<'a> Index<ParamIndex> for TeeParams<'a> {
+    type Output = Param<'a>;
+
+    fn index(&self, index: ParamIndex) -> &Self::Output {
+        &self.params[index.to_usize()]
+    }
+}
+
+impl<'a> IndexMut<ParamIndex> for TeeParams<'a> {
+    fn index_mut(&mut self, index: ParamIndex) -> &mut Self::Output {
+        &mut self.params[index.to_usize()]
+    }
+}
diff --git a/ci/ci.sh b/tests/test_inter_ta.sh
similarity index 51%
copy from ci/ci.sh
copy to tests/test_inter_ta.sh
index 6f026bc..390ecb1 100755
--- a/ci/ci.sh
+++ b/tests/test_inter_ta.sh
@@ -19,39 +19,25 @@
 
 set -xe
 
-pushd ../tests
+# Include base script
+source setup.sh
 
-# Prioritize running specialized test suites first, as they have a higher
-# probability of detecting failures early in the pipeline.
-# Run std only tests
-if [ "$STD" ]; then
-    ./test_serde.sh
-    ./test_message_passing_interface.sh
-    ./test_tls_client.sh
-    ./test_tls_server.sh
-    ./test_eth_wallet.sh
-    ./test_secure_db_abstraction.sh
-else
-    ./test_mnist_rs.sh
-fi
+# Copy hello_world-rs TA for testing
+cp ../examples/hello_world-rs/ta/target/$TARGET_TA/release/*.ta shared
+# Copy TA and host binary
+cp ../examples/inter_ta-rs/host/target/$TARGET_HOST/release/inter_ta-rs shared
+cp ../examples/inter_ta-rs/ta/target/$TARGET_TA/release/*.ta shared
 
-./test_hello_world.sh
-./test_random.sh
-./test_secure_storage.sh
-./test_aes.sh
-./test_hotp.sh
-./test_acipher.sh
-./test_big_int.sh
-./test_diffie_hellman.sh
-./test_digest.sh
-./test_authentication.sh
-./test_time.sh
-./test_signature_verification.sh
-./test_supp_plugin.sh
-./test_error_handling.sh
-./test_tcp_client.sh
-./test_udp_socket.sh
-./test_client_pool.sh
+# Run script specific commands in QEMU
+run_in_qemu "cp *.ta /lib/optee_armtz/\n"
+run_in_qemu "./inter_ta-rs\n"
+run_in_qemu "^C"
 
-
-popd
+# Script specific checks
+{
+    grep -q "Success" screenlog.0
+} || {
+    cat -v screenlog.0
+    cat -v /tmp/serial.log
+    false
+}
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to