From be20664c26e405fe3ad419397dab5eb24adf2845 Mon Sep 17 00:00:00 2001 From: ivila <390810839@qq.com> Date: Mon, 23 Dec 2024 11:04:31 +0800 Subject: [PATCH] Doc: add tutorial about how to use optee-utee-build 1. add document "Writing Rust TAs using optee-utee-build" 2. suggest developers using optee-utee-build in "Migrating to new building env" --- docs/README.md | 1 + docs/migrating-to-new-building-env.md | 2 + ...writing-rust-tas-using-optee-utee-build.md | 182 ++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 docs/writing-rust-tas-using-optee-utee-build.md diff --git a/docs/README.md b/docs/README.md index 368f799c..db83a9fd 100644 --- a/docs/README.md +++ b/docs/README.md @@ -8,3 +8,4 @@ permalink: /trustzone-sdk-docs * [Debugging OP-TEE TA](debugging-optee-ta.md) * [Expanding TA Secure Memory on QEMUv8](expanding-ta-secure-memory-on-qemuv8.md) * [Building Rust CA as Android ELF](building-rust-ca-as-android-elf.md) +* [Writing Rust TAs using optee-utee-build](writing-rust-tas-using-optee-utee-build.md) diff --git a/docs/migrating-to-new-building-env.md b/docs/migrating-to-new-building-env.md index 3b79ba85..6d1b9f16 100644 --- a/docs/migrating-to-new-building-env.md +++ b/docs/migrating-to-new-building-env.md @@ -2,6 +2,8 @@ permalink: /trustzone-sdk-docs/migrating-to-new-building-env.md --- +> After optee-utee-build release, this doc is keeping for developers who intend to know the detail of building process, we suggest use optee-utee-build for building instead. + ## Migration Guide: Moving from `master` to `main` Branch (Post-Oct 2024) Since the `main` branch (after October 2024) introduces breaking changes diff --git a/docs/writing-rust-tas-using-optee-utee-build.md b/docs/writing-rust-tas-using-optee-utee-build.md new file mode 100644 index 00000000..721f7962 --- /dev/null +++ b/docs/writing-rust-tas-using-optee-utee-build.md @@ -0,0 +1,182 @@ +--- +permalink: /trustzone-sdk-docs/writing-rust-tas-using-optee-utee-build.md +--- + +Currently we provide a `optee-utee-build` crate to simplify the compilcated building process of TA, and we recommend everyone use it in future developement. + +# Minimal Example +Assuming currently we are developing a `hello_world` TA, and we want to build it with `optee-utee-build` crate, we can do it by following steps. + +Firstly, we should add `optee-utee-build` in `build-dependencies`: +```shell +cargo add --build optee-utee-build +``` + +Secondly, we set a `ta_config` and call `optee-utee-build::build` with it in build.rs: +```rust +use proto; +use optee_utee_build::{TAConfig, Error, RustEdition}; + +fn main() -> Result<(), Error> { + let ta_config = TAConfig::new_standard_with_cargo_env(proto::UUID)?; + optee_utee_build::build(RustEdition::Before2024, ta_config) +} +``` +It will generate a `user_ta_header.rs` file and setup all the required configurations of the linker of rustc. + +Finally, we include the generated `user_ta_header.rs` in the source codes, normally we put it in `src/main.rs` +```rust +// src/main.rs +include!(concat!(env!("OUT_DIR"), "/user_ta_header.rs")); +``` +After that, everything finished, we can start building the TA now. + +For full codes, you can check the [`hello_world-rs example`](https://github.com/apache/incubator-teaclave-trustzone-sdk/tree/main/examples/hello_world-rs/ta) + +# Explaination of Minimal Example + +### 1. The TAConfig + +This is a struct that use for the configuration of the TA we are developing, it has some public fields: + +|Field Name|Description| +|----|----| +|uuid|the identifier of current TA| +|ta_flags|combination of some bitflags, check [this](https://github.com/OP-TEE/optee_os/blob/c2e42a8f03a5bb6b894ef85ae409f54760c1f50e/lib/libutee/include/user_ta_header.h#L13-L53) for available values| +|ta_data_size|defines the size in bytes of the TA allocation pool| +|ta_stack_size|defines the size in bytes of the stack used for TA execution| +|ta_version|a version string of current TA, must be in semver format| +|ta_description|the desciption of current TA| +|trace_level|the default trace level of current TA, check [this](https://github.com/OP-TEE/optee_os/blob/c2e42a8f03a5bb6b894ef85ae409f54760c1f50e/lib/libutils/ext/include/trace_levels.h#L26-L31) for available values| +|trace_ext|an extra prefix string when output trace log| +|ta_framework_stack_size|defines the size in bytes of the stack used for Trusted Core Framework, currently used for trace framework and invoke command, should not be less than 2048| +|ext_properties|the extra custom properties that will be added| + +We can construct the `TAConfig` by providing all of the public fields manually, or use our standard constructor. +|Constructor|Description| +|----|----| +|new_standard|construct a standard TAConfig by providing uuid, ta_version and ta_description, with other configurations set to suggested values, you can update those configurations later| +|new_standard_with_cargo_env|it's a constructor wrapped with new_standard, but take `version` and `description` from cargo.toml so simply providing a uuid as parameter is enough| +### 2. The RustEdition + +The generated `user_ta_header.rs` must be different between `edition of 2024` and `edition before 2024`, and currently there is no official stable way to know what edition we are compiling with, so we provide a argument to set with. + +> #### What’s the difference? +> the generated `user_ta_header.rs` file include some const variables and methods tagged with `no_mangle` and `link_section`, start from rust edition of 2024, they must be wrapped with unsafe, or rustc will output a compilation error(while before edition of 2024 it must not, or rustc will output a syntax error) + +# Customization + +`optee-utee-build` provide some struct for flexible use. + +### 1. Builder +Expect calling `build` function directly, you can also use Builder for customization. + +Usage: +```Rust +use proto; +use optee_utee_build::{TAConfig, Builder, Error, RustEdition, LinkType}; + +fn main() -> Result<(), Error> { + let ta_config = TAConfig::new_standard_with_cargo_env(proto::UUID)?; + Builder::new(RustEdition::Before2024, ta_config) + .out_dir("/tmp") + .header_file_name("my_generated_user_ta_header.rs") + .link_type(LinkType::CC) + .build() +} +``` +As you can see from the codes, there are some customizations of the builder: +|Configuration|Description| +|----|----| +|out_dir|change directory of output files, default to OUT_DIR by cargo| +|header_file_name|change name of output header file. default to `user_ta_header.rs`| +|link_type|set link_type manually.
there are some difference in parameters in linkers between `CC` and `LD` types, for example, `--sort-section` in `CC` types of linkers changes to `-Wl,--sort-section`, we will try to detect current linker that cargo using, you can use this function to set it manually if you think our detection mismatch.| + +### 2. Linker +For some developers who want to use a hand-written `user_ta_header.rs` and just want `optee-utee-build` to handle the building stuff only, they can use the `Linker`, otherwise, try `Builder` instead. + +Usage: +``` rust +use optee_utee_build::{Linker, Error}; +use std::env; + +fn main() -> Result<(), Error> { + let out_dir = env::var("OUT_DIR")?; + Linker::auto().link_all(out_dir)?; + Ok(()) +} +``` +When linking manually, developers construct a `Linker` and calling the `link_all` method by providing the out_dir, and linker will generate some required files (link script, etc) and handle all the linking stuff. + +In above codes, we use `auto` to construct the linker, it will detect current linker that cargo using automatically, you can use `new` function to construct the linker manually if you think our detection mismatch. +```rust +use optee_utee_build::{Linker, Error, LinkType}; +use std::env; + +fn main() -> Result<(), Error> { + let out_dir = env::var("OUT_DIR")?; + Linker::new(LinkerType::CC).link_all(out_dir)?; + Ok(()) +} +``` + +### 3. HeaderFileGenerator +For some developers who want to do the linking themselves and just want `optee-utee-build` to generate a header file only, they can use the `HeaderFileGenerator`, otherwise, try `Builder` instead. + +Usage: +```rust +use optee_utee_build::{HeaderFileGenerator, TAConfig, RustEdition, Error}; + +fn main() -> Result<(), Error> { + const UUID: &str = "26509cec-4a2b-4935-87ab-762d89fbf0b0"; + let ta_config = TAConfig::new_standard(UUID, "0.1.0", "example")?; + let codes = HeaderFileGenerator::new(RustEdition::Before2024).generate(&ta_config)?; + Ok(std::io::Write("/tmp/user_ta_header.rs", codes.as_bytes())?) +} + +``` + +# Migration Guide +For developers still using `const configuration values` in `src/main.rs` and `custom build scripts` in `build.rs` (described in [\[migrating-to-new-building-env\]](https://github.com/apache/incubator-teaclave-trustzone-sdk/blob/main/docs/migrating-to-new-building-env.md)), they can upgrade to `optee-utee-build` by following step: + +Firstly, add `optee-utee-build` as `build-dependencies`: +```shell +cargo add --build optee-utee-build +``` + +Secondly, in `build.rs`, remove codes of `custom build scripts`, and use `optee_utee_build::build` instead: +```rust +// ... other imports +use optee_utee_build::{TAConfig, Error} + +fn main() -> Result<(), Error> { + let ta_config = TAConfig::new_standard_with_cargo_env(proto::UUID)? + .ta_stack_size(10 * 1024); // should customize it with the const configuration values in your src/main.rs + optee_utee_build::build(RustEdition::Before2024, ta_config)?; + + // ... other build scripts +} +``` + +Thirdly, remove `const configuration values` in `src/main.rs`, keep the line of `include user_ta_header.rs` +```rust +/// ... other codes in src/main.rs + +/* remove const configuration values, move them to TAConfig in src/main.rs +// TA configurations +const TA_FLAGS: u32 = 0; +const TA_DATA_SIZE: u32 = 32 * 1024; +const TA_STACK_SIZE: u32 = 2 * 1024; +const TA_VERSION: &[u8] = b"0.1\0"; +const TA_DESCRIPTION: &[u8] = b"This is a hello world example.\0"; +const EXT_PROP_VALUE_1: &[u8] = b"Hello World TA\0"; +const EXT_PROP_VALUE_2: u32 = 0x0010; +const TRACE_LEVEL: i32 = 4; +const TRACE_EXT_PREFIX: &[u8] = b"TA\0"; +const TA_FRAMEWORK_STACK_SIZE: u32 = 2048; +*/ + +include!(concat!(env!("OUT_DIR"), "/user_ta_header.rs")); // keep this line +``` +Finally, delete the useless `ta_static.rs` and can start building now. +