forked from apache/incubator-teaclave-trustzone-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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"
- Loading branch information
Showing
3 changed files
with
185 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. <br/>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. | ||
|