Skip to content

Commit 25327d1

Browse files
committed
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"
1 parent 4e487d4 commit 25327d1

3 files changed

Lines changed: 186 additions & 0 deletions

File tree

docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ permalink: /trustzone-sdk-docs
88
* [Debugging OP-TEE TA](debugging-optee-ta.md)
99
* [Expanding TA Secure Memory on QEMUv8](expanding-ta-secure-memory-on-qemuv8.md)
1010
* [Building Rust CA as Android ELF](building-rust-ca-as-android-elf.md)
11+
* [Writing Rust TAs using optee-utee-build](writing-rust-tas-using-optee-utee-build.md)

docs/migrating-to-new-building-env.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
permalink: /trustzone-sdk-docs/migrating-to-new-building-env.md
33
---
44

5+
> 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.
6+
57
## Migration Guide: Moving from `master` to `main` Branch (Post-Oct 2024)
68

79
Since the `main` branch (after October 2024) introduces breaking changes
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
---
2+
permalink: /trustzone-sdk-docs/writing-rust-tas-using-optee-utee-build.md
3+
---
4+
5+
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.
6+
7+
# Minimal Example
8+
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.
9+
10+
Firstly, we should add `optee-utee-build` in `build-dependencies`:
11+
```shell
12+
cargo add --build optee-utee-build
13+
```
14+
15+
Secondly, we set a `ta_config` and call `optee-utee-build::build` with it in build.rs:
16+
```rust
17+
use proto;
18+
use optee_utee_build::{TAConfig, Error, RustEdition};
19+
20+
fn main() -> Result<(), Error> {
21+
let ta_config = TAConfig::new_standard_with_cargo_env(proto::UUID)?;
22+
optee_utee_build::build(RustEdition::Before2024, ta_config)
23+
}
24+
```
25+
It will generate a `user_ta_header.rs` file and setup all the required configurations of the linker of rustc.
26+
27+
Finally, we include the generated `user_ta_header.rs` in the source codes, normally we put it in `src/main.rs`
28+
```rust
29+
// src/main.rs
30+
include!(concat!(env!("OUT_DIR"), "/user_ta_header.rs"));
31+
```
32+
After that, everything finished, we can start building the TA now.
33+
34+
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)
35+
36+
# Explaination of Minimal Example
37+
38+
### 1. The TAConfig
39+
40+
This is a struct that use for the configuration of the TA we are developing, it has some public fields:
41+
42+
|Field Name|Description|
43+
|----|----|
44+
|uuid|the identifier of current TA|
45+
|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|
46+
|ta_data_size|defines the size in bytes of the TA allocation pool|
47+
|ta_stack_size|defines the size in bytes of the stack used for TA execution|
48+
|ta_version|a version string of current TA, should be in semver format|
49+
|ta_description|the desciption of current TA|
50+
|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|
51+
|trace_ext|an extra prefix string when output trace log|
52+
|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|
53+
|ext_properties|the extra custom properties that will be added|
54+
55+
We can construct the `TAConfig` by providing all of the public fields manually, or use our standard constructor.
56+
|Constructor|Description|
57+
|----|----|
58+
|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|
59+
|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|
60+
### 2. The RustEdition
61+
62+
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.
63+
64+
> #### What’s the difference?
65+
> 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)
66+
67+
# Customization
68+
69+
`optee-utee-build` provide some structs for flexible use.
70+
71+
### 1. Builder
72+
Expect calling `build` function directly, you can also use Builder for customization.
73+
74+
Usage:
75+
```Rust
76+
use proto;
77+
use optee_utee_build::{TAConfig, Builder, Error, RustEdition, LinkType};
78+
79+
fn main() -> Result<(), Error> {
80+
let ta_config = TAConfig::new_standard_with_cargo_env(proto::UUID)?;
81+
Builder::new(RustEdition::Before2024, ta_config)
82+
.out_dir("/tmp")
83+
.header_file_name("my_generated_user_ta_header.rs")
84+
.link_type(LinkType::CC)
85+
.build()
86+
}
87+
```
88+
As you can see from the codes, there are some customizations of the builder:
89+
|Configuration|Description|
90+
|----|----|
91+
|out_dir|change directory of output files, default to OUT_DIR by cargo|
92+
|header_file_name|change name of output header file. default to `user_ta_header.rs`|
93+
|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.|
94+
95+
### 2. Linker
96+
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.
97+
98+
Usage:
99+
``` rust
100+
use optee_utee_build::{Linker, Error};
101+
use std::env;
102+
103+
fn main() -> Result<(), Error> {
104+
let out_dir = env::var("OUT_DIR")?;
105+
Linker::auto().link_all(out_dir)?;
106+
Ok(())
107+
}
108+
```
109+
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.
110+
111+
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.
112+
```rust
113+
use optee_utee_build::{Linker, Error, LinkType};
114+
use std::env;
115+
116+
fn main() -> Result<(), Error> {
117+
let out_dir = env::var("OUT_DIR")?;
118+
Linker::new(LinkerType::CC).link_all(out_dir)?;
119+
Ok(())
120+
}
121+
```
122+
123+
### 3. HeaderFileGenerator
124+
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.
125+
126+
Usage:
127+
```rust
128+
use optee_utee_build::{HeaderFileGenerator, TAConfig, RustEdition, Error};
129+
130+
fn main() -> Result<(), Error> {
131+
const UUID: &str = "26509cec-4a2b-4935-87ab-762d89fbf0b0";
132+
let ta_config = TAConfig::new_standard(UUID, "0.1.0", "example")?;
133+
let codes = HeaderFileGenerator::new(RustEdition::Before2024).generate(&ta_config)?;
134+
Ok(std::io::Write("/tmp/user_ta_header.rs", codes.as_bytes())?)
135+
}
136+
137+
```
138+
139+
# Migration Guide
140+
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:
141+
142+
Firstly, add `optee-utee-build` as `build-dependencies`:
143+
```shell
144+
cargo add --build optee-utee-build
145+
```
146+
147+
Secondly, in `build.rs`, remove codes of `custom build scripts`, and use `optee_utee_build::build` instead:
148+
```rust
149+
// ... other imports
150+
use optee_utee_build::{TAConfig, Error}
151+
152+
fn main() -> Result<(), Error> {
153+
// should customize the ta_config with the same as const configuration values in your src/main.rs
154+
let ta_config = TAConfig::new_standard_with_cargo_env(proto::UUID)?
155+
.ta_stack_size(10 * 1024);
156+
optee_utee_build::build(RustEdition::Before2024, ta_config)?;
157+
158+
// ... other build scripts
159+
}
160+
```
161+
162+
Thirdly, remove `const configuration values` in `src/main.rs`, keep the line of `include user_ta_header.rs`
163+
```rust
164+
/// ... other codes in src/main.rs
165+
166+
/* remove const configuration values, move them to TAConfig in src/main.rs
167+
// TA configurations
168+
const TA_FLAGS: u32 = 0;
169+
const TA_DATA_SIZE: u32 = 32 * 1024;
170+
const TA_STACK_SIZE: u32 = 2 * 1024;
171+
const TA_VERSION: &[u8] = b"0.1\0";
172+
const TA_DESCRIPTION: &[u8] = b"This is a hello world example.\0";
173+
const EXT_PROP_VALUE_1: &[u8] = b"Hello World TA\0";
174+
const EXT_PROP_VALUE_2: u32 = 0x0010;
175+
const TRACE_LEVEL: i32 = 4;
176+
const TRACE_EXT_PREFIX: &[u8] = b"TA\0";
177+
const TA_FRAMEWORK_STACK_SIZE: u32 = 2048;
178+
*/
179+
180+
include!(concat!(env!("OUT_DIR"), "/user_ta_header.rs")); // keep this line
181+
```
182+
Finally, delete the useless `ta_static.rs` and start building now.
183+

0 commit comments

Comments
 (0)