Skip to content

Commit

Permalink
Doc: add tutorial about how to use optee-utee-build
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Sumit Garg <[email protected]>
Reviewed-by: Yuan Zhuang <[email protected]>
  • Loading branch information
ivila authored and DemesneGH committed Dec 31, 2024
1 parent 80b8747 commit 131a55a
Show file tree
Hide file tree
Showing 4 changed files with 252 additions and 0 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
5 changes: 5 additions & 0 deletions docs/migrating-to-new-building-env.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
243 changes: 243 additions & 0 deletions docs/writing-rust-tas-using-optee-utee-build.md
Original file line number Diff line number Diff line change
@@ -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.

0 comments on commit 131a55a

Please sign in to comment.