From 1d7ec68b5aa21a0de63025aeb4b19aad688cf322 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" 3. add description about the supported host machines in README.md Signed-off-by: ivila <390810839@qq.com> Reviewed-by: Sumit Garg Reviewed-by: Yuan Zhuang --- README.md | 3 + docs/README.md | 1 + docs/migrating-to-new-building-env.md | 5 + ...writing-rust-tas-using-optee-utee-build.md | 243 ++++++++++++++++++ 4 files changed, 252 insertions(+) create mode 100644 docs/writing-rust-tas-using-optee-utee-build.md diff --git a/README.md b/README.md index d821e5f3..8a0b00c4 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,9 @@ Prerequisites](https://optee.readthedocs.io/en/latest/building/prerequisites.htm ### Setup Building Environment +Currently, we support building on both `aarch64` and `x86_64` host machines, and + they share the same steps. + 1. Install the Rust environment and toolchains: ```sh 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..ce98ed63 100644 --- a/docs/migrating-to-new-building-env.md +++ b/docs/migrating-to-new-building-env.md @@ -2,6 +2,11 @@ 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](./writing-rust-tas-using-optee-utee-build.md) 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..4287a46d --- /dev/null +++ b/docs/writing-rust-tas-using-optee-utee-build.md @@ -0,0 +1,243 @@ +--- +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. + +* For legacy app structures migrating to use this crate, refer to [Migration + Guide](#migration-guide) +* If you're new to development, start with [Minimal Example](#minimal-example) +* To customize the build process, see [Customization](#customization) + +# 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_default_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: + +1. **uuid**: the identifier of TA. +2. **ta_flags**: combination of some bitflags. + for available values, you may check [user_ta_header.h in optee_os](https://github.com/OP-TEE/optee_os/blob/c2e42a8f03a5bb6b894ef85ae409f54760c1f50e/lib/libutee/include/user_ta_header.h#L13-L53) +3. **ta_data_size**: the size in bytes of the TA allocation pool. +4. **ta_stack_size**: the size in bytes of the stack used for TA execution. +5. **ta_version**: a version string of TA, should be in semver format. +6. **ta_description**: the desciption of TA. +7. **trace_level**: the default trace level of TA. + for available values, you may check [trace_levels.h in optee_os](https://github.com/OP-TEE/optee_os/blob/c2e42a8f03a5bb6b894ef85ae409f54760c1f50e/lib/libutils/ext/include/trace_levels.h#L26-L31) +8. **trace_ext**: an extra prefix string when output trace log. +9. **ta_framework_stack_size**: 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. +10. **ext_properties**: the extra custom properties. + +We can construct the `TaConfig` by providing all of the public fields manually, +or use our standard constructor: + +1. **new_default**: construct a default TaConfig by providing uuid, ta_version +and ta_description, with other configurations set to suggested values, you can +update those configurations later. +2. **new_default_with_cargo_env**: it's a constructor wrapped with new_default, +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 global +functions 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 structs for flexible use. + +### 1. Builder + +Instead of calling the `build` function directly, you can 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_default_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: +1. **out_dir**: change directory of output files. + default to OUT_DIR by cargo. +2. **header_file_name**: change name of output header file. + default to `user_ta_header.rs` +3. **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 developers who prefer to use a hand-written `user_ta_header.rs` and only +want `optee-utee-build` to handle the linking process, 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, used by linker) into out_dir 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 developers who prefer to do the linking themselves and only want +`optee-utee-build` to generate the header file, 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_default(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> { + // should customize the ta_config with the same as const configuration values + // in your src/main.rs + let ta_config = TaConfig::new_default_with_cargo_env(proto::UUID)? + .ta_stack_size(10 * 1024); + 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 start building now.