Copilot commented on code in PR #263: URL: https://github.com/apache/teaclave-trustzone-sdk/pull/263#discussion_r2621946490
########## ci/build.sh: ########## @@ -0,0 +1,435 @@ +#!/bin/bash + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +set -e + +# Show usage +show_usage() { + cat << EOF +Usage: TA_DEV_KIT_DIR=<path> OPTEE_CLIENT_EXPORT=<path> $0 [OPTIONS] + +Required environment variables: + TA_DEV_KIT_DIR Path to OP-TEE OS TA dev kit directory + OPTEE_CLIENT_EXPORT Path to OP-TEE client export directory + +Options: + --ta <arch> TA architecture: aarch64 or arm (default: aarch64) + --host <arch> Host architecture for CA and plugins: aarch64 or arm (default: aarch64) + --std Install with std support (default: no-std) + --ta-install-dir <path> TA installation directory (default: ./tests/shared) + --ca-install-dir <path> CA installation directory (default: ./tests/shared) + --plugin-install-dir <path> Plugin installation directory (default: ./tests/shared) + --help Show this help message + +Examples: + # Install for aarch64 in no-std mode + TA_DEV_KIT_DIR=/path/to/export-ta_arm64 OPTEE_CLIENT_EXPORT=/path/to/export ./build.sh + + # Install for ARM32 in std mode with custom directories + TA_DEV_KIT_DIR=/path/to/export-ta_arm32 OPTEE_CLIENT_EXPORT=/path/to/export ./build.sh --ta arm --host arm --std --ta-install-dir /target/lib/optee_armtz --ca-install-dir /target/usr/bin + +Note: Binaries are installed to './tests/shared' directory by default. +EOF +} + +# Parse command line arguments +ARCH_TA="aarch64" # Default: aarch64 +ARCH_HOST="aarch64" # Default: aarch64 +STD="" # Default: empty (no-std) +TA_INSTALL_DIR="" # Default: will be set to ./tests/shared if not specified +CA_INSTALL_DIR="" # Default: will be set to ./tests/shared if not specified +PLUGIN_INSTALL_DIR="" # Default: will be set to ./tests/shared if not specified + +# Parse arguments (support both positional and flag-style) +while [[ $# -gt 0 ]]; do + case "$1" in + --help|-h) + show_usage + exit 0 + ;; + --ta) + ARCH_TA="$2" + shift 2 + ;; + --host) + ARCH_HOST="$2" + shift 2 + ;; + --std) + STD="std" + shift + ;; + --ta-install-dir) + TA_INSTALL_DIR="$2" + shift 2 + ;; + --ca-install-dir) + CA_INSTALL_DIR="$2" + shift 2 + ;; + --plugin-install-dir) + PLUGIN_INSTALL_DIR="$2" + shift 2 + ;; + *) + # Positional arguments (backward compatibility) + if [[ -z "${ARCH_TA_SET:-}" ]]; then + ARCH_TA="$1" + ARCH_TA_SET=1 + elif [[ -z "${ARCH_HOST_SET:-}" ]]; then + ARCH_HOST="$1" + ARCH_HOST_SET=1 + elif [[ "$1" == "std" ]]; then + STD="std" + fi + shift + ;; + esac +done + +# Validate architecture +if [[ "$ARCH_TA" != "aarch64" && "$ARCH_TA" != "arm" ]]; then + echo "Error: ARCH_TA must be 'aarch64' or 'arm'" + exit 1 +fi + +if [[ "$ARCH_HOST" != "aarch64" && "$ARCH_HOST" != "arm" ]]; then + echo "Error: ARCH_HOST must be 'aarch64' or 'arm'" + exit 1 +fi + +# Check required environment variables +if [ -z "$TA_DEV_KIT_DIR" ]; then + echo "Error: TA_DEV_KIT_DIR environment variable is not set" + exit 1 +fi + +if [ -z "$OPTEE_CLIENT_EXPORT" ]; then + echo "Error: OPTEE_CLIENT_EXPORT environment variable is not set" + exit 1 +fi + +echo "===========================================" +echo "Installing with configuration:" +echo " ARCH_TA: $ARCH_TA" +echo " ARCH_HOST: $ARCH_HOST" +echo " STD: ${STD:-no-std}" +echo " TA_DEV_KIT_DIR: $TA_DEV_KIT_DIR" +echo " OPTEE_CLIENT_EXPORT: $OPTEE_CLIENT_EXPORT" +echo "===========================================" + +# Step 1: Build cargo-optee tool +echo "" +echo "Step 1: Building cargo-optee tool..." +cd cargo-optee +cargo build --release +CARGO_OPTEE="$(pwd)/target/release/cargo-optee" +cd .. + +if [ ! -f "$CARGO_OPTEE" ]; then + echo "Error: Failed to build cargo-optee" + exit 1 +fi + +echo "cargo-optee built successfully: $CARGO_OPTEE" + +# Prepare std flag for cargo-optee +STD_FLAG="" +if [ -n "$STD" ]; then + STD_FLAG="--std" +fi + +# Step 2: Install all examples to shared directory +echo "" +echo "Step 2: Installing all examples..." + +# Set up installation directories +# Each directory defaults to ./tests/shared if not specified +if [ -z "$TA_INSTALL_DIR" ]; then + TA_INSTALL_DIR="$(pwd)/tests/shared" +fi + +if [ -z "$CA_INSTALL_DIR" ]; then + CA_INSTALL_DIR="$(pwd)/tests/shared" +fi + +if [ -z "$PLUGIN_INSTALL_DIR" ]; then + PLUGIN_INSTALL_DIR="$(pwd)/tests/shared" +fi + +# Create all directories +mkdir -p "$TA_INSTALL_DIR" +mkdir -p "$CA_INSTALL_DIR" +mkdir -p "$PLUGIN_INSTALL_DIR" + +echo "Installing binaries to:" +echo " TAs: $TA_INSTALL_DIR" +echo " CAs: $CA_INSTALL_DIR" +echo " Plugins: $PLUGIN_INSTALL_DIR" + +EXAMPLES_DIR="$(pwd)/examples" +METADATA_JSON="$EXAMPLES_DIR/metadata.json" + +if [ ! -f "$METADATA_JSON" ]; then + echo "Error: $METADATA_JSON not found" + exit 1 +fi + +# Check if jq is available for JSON parsing +if ! command -v jq &> /dev/null; then + echo "Error: jq is required to parse metadata.json" + echo "Please install jq: apt-get install jq" + exit 1 +fi + +echo "Loading example metadata from $METADATA_JSON..." + +# Get all example names +ALL_EXAMPLES=($(jq -r '.examples | keys[]' "$METADATA_JSON")) + +if [ -n "$STD" ]; then + echo "Building in STD mode (std-only + common examples)" +else + echo "Building in NO-STD mode (no-std-only + common examples)" +fi + +CURRENT=0 +FAILED_EXAMPLES="" + +# Build examples +for EXAMPLE_NAME in "${ALL_EXAMPLES[@]}"; do + CATEGORY=$(jq -r ".examples[\"$EXAMPLE_NAME\"].category" "$METADATA_JSON") + + # Determine if we should build this example + SHOULD_BUILD=false + if [ -n "$STD" ]; then + # STD mode: build std-only and common + if [[ "$CATEGORY" == "std-only" || "$CATEGORY" == "common" ]]; then + SHOULD_BUILD=true + fi + else + # NO-STD mode: build no-std-only and common + if [[ "$CATEGORY" == "no-std-only" || "$CATEGORY" == "common" ]]; then + SHOULD_BUILD=true + fi + fi + + if [ "$SHOULD_BUILD" = false ]; then + continue + fi + + CURRENT=$((CURRENT + 1)) + EXAMPLE_DIR="$EXAMPLES_DIR/$EXAMPLE_NAME" + + if [ ! -d "$EXAMPLE_DIR" ]; then + echo "ERROR: Example directory not found: $EXAMPLE_DIR" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME" + continue + fi + + echo "" + echo "==========================================" + echo "[$CURRENT] Building: $EXAMPLE_NAME ($CATEGORY)" + echo "==========================================" + + # Get TA, CA, and Plugin directories from metadata + TAS_JSON=$(jq -c ".examples[\"$EXAMPLE_NAME\"].tas" "$METADATA_JSON") + CAS_JSON=$(jq -c ".examples[\"$EXAMPLE_NAME\"].cas" "$METADATA_JSON") + PLUGINS_JSON=$(jq -c ".examples[\"$EXAMPLE_NAME\"].plugins // []" "$METADATA_JSON") + + # Build all TAs for this example + TA_COUNT=$(echo "$TAS_JSON" | jq 'length') + CA_COUNT=$(echo "$CAS_JSON" | jq 'length') + PLUGIN_COUNT=$(echo "$PLUGINS_JSON" | jq 'length') + + echo "→ Found $TA_COUNT TA(s), $CA_COUNT CA(s), and $PLUGIN_COUNT Plugin(s)" + + if [ "$TA_COUNT" -gt 0 ]; then + for ((i=0; i<$TA_COUNT; i++)); do + TA_DIR=$(echo "$TAS_JSON" | jq -r ".[$i]") + TA_DIR_FULL_PATH="$EXAMPLES_DIR/$TA_DIR" + + if [ ! -d "$TA_DIR_FULL_PATH" ]; then + echo "ERROR: TA directory not found: $TA_DIR_FULL_PATH" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME ($TA_DIR)" + continue + fi + + if [ ! -f "$TA_DIR_FULL_PATH/Cargo.toml" ]; then + echo "ERROR: Cargo.toml not found in TA directory: $TA_DIR_FULL_PATH" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME ($TA_DIR)" + continue + fi + + echo "" + echo "→ Building TA [$((i+1))/$TA_COUNT]: $TA_DIR" + + # Determine STD_FLAG for TA + TA_STD_FLAG="" + if [ -n "$STD" ]; then + # In std mode: always pass --std flag to cargo-optee + TA_STD_FLAG="--std" + fi + + # Change to TA directory and run cargo-optee without --manifest-path + cd "$TA_DIR_FULL_PATH" + + # Run cargo-optee install and capture both stdout and stderr + if $CARGO_OPTEE install ta \ + --target-dir "$TA_INSTALL_DIR" \ + --ta-dev-kit-dir "$TA_DEV_KIT_DIR" \ + --arch "$ARCH_TA" \ + $TA_STD_FLAG; then + echo " ✓ TA installed successfully" + # Clean up build artifacts + $CARGO_OPTEE clean + else + echo " ✗ ERROR: Failed to install TA: $TA_DIR" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME ($TA_DIR)" + cd "$EXAMPLES_DIR" # Return to examples directory + continue + fi + + # Return to examples directory + cd "$EXAMPLES_DIR" + done + else + echo "WARNING: No TAs defined for $EXAMPLE_NAME" + fi + + # Build each CA + CA_INDEX=0 + while [[ "$CA_INDEX" -lt "$CA_COUNT" ]]; do + CA_DIR=$(echo "$CAS_JSON" | jq -r ".[$CA_INDEX]") + CA_DIR_FULL_PATH="$EXAMPLES_DIR/$CA_DIR" + + echo "" + echo "→ Building CA [$((CA_INDEX+1))/$CA_COUNT]: $CA_DIR" + + if [ ! -d "$CA_DIR_FULL_PATH" ]; then + echo "ERROR: CA directory not found: $CA_DIR_FULL_PATH" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME ($CA_DIR)" + CA_INDEX=$((CA_INDEX + 1)) + continue + fi + + if [ ! -f "$CA_DIR_FULL_PATH/Cargo.toml" ]; then + echo "ERROR: Cargo.toml not found in CA directory: $CA_DIR_FULL_PATH" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME ($CA_DIR)" + CA_INDEX=$((CA_INDEX + 1)) + continue + fi + + # Change to CA directory and run cargo-optee without --manifest-path + cd "$CA_DIR_FULL_PATH" + + if $CARGO_OPTEE install ca \ + --target-dir "$CA_INSTALL_DIR" \ + --optee-client-export "$OPTEE_CLIENT_EXPORT" \ + --arch "$ARCH_HOST"; then + echo " ✓ CA installed successfully" + # Clean up build artifacts + $CARGO_OPTEE clean + else + echo " ✗ ERROR: Failed to install CA: $CA_DIR" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME ($CA_DIR)" + cd "$EXAMPLES_DIR" # Return to examples directory + CA_INDEX=$((CA_INDEX + 1)) + continue + fi + + # Return to examples directory + cd "$EXAMPLES_DIR" + CA_INDEX=$((CA_INDEX + 1)) + done + + # Build each Plugin + PLUGIN_INDEX=0 + while [[ "$PLUGIN_INDEX" -lt "$PLUGIN_COUNT" ]]; do + PLUGIN_DIR=$(echo "$PLUGINS_JSON" | jq -r ".[$PLUGIN_INDEX]") + PLUGIN_DIR_FULL_PATH="$EXAMPLES_DIR/$PLUGIN_DIR" + + echo "" + echo "→ Building Plugin [$((PLUGIN_INDEX+1))/$PLUGIN_COUNT]: $PLUGIN_DIR" + + if [ ! -d "$PLUGIN_DIR_FULL_PATH" ]; then + echo "ERROR: Plugin directory not found: $PLUGIN_DIR_FULL_PATH" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME ($PLUGIN_DIR)" + PLUGIN_INDEX=$((PLUGIN_INDEX + 1)) + continue + fi + + if [ ! -f "$PLUGIN_DIR_FULL_PATH/Cargo.toml" ]; then + echo "ERROR: Cargo.toml not found in Plugin directory: $PLUGIN_DIR_FULL_PATH" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME ($PLUGIN_DIR)" + PLUGIN_INDEX=$((PLUGIN_INDEX + 1)) + continue + fi + + # Change to Plugin directory and run cargo-optee without --manifest-path + cd "$PLUGIN_DIR_FULL_PATH" + + if $CARGO_OPTEE install plugin \ + --target-dir "$PLUGIN_INSTALL_DIR" \ + --optee-client-export "$OPTEE_CLIENT_EXPORT" \ + --arch "$ARCH_HOST"; then + echo " ✓ Plugin installed successfully" + # Clean up build artifacts + $CARGO_OPTEE clean + else + echo " ✗ ERROR: Failed to install Plugin: $PLUGIN_DIR" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME ($PLUGIN_DIR)" + cd "$EXAMPLES_DIR" # Return to examples directory + PLUGIN_INDEX=$((PLUGIN_INDEX + 1)) + continue + fi + + # Return to examples directory + cd "$EXAMPLES_DIR" + PLUGIN_INDEX=$((PLUGIN_INDEX + 1)) + done + + echo "" + echo "✓ Example $EXAMPLE_NAME completed successfully" +done + +# Summary +echo "" +echo "===========================================" +echo " INSTALL SUMMARY" +echo "===========================================" +echo "" +echo "Mode: ${STD:-no-std}" +echo "Architecture: TA=$ARCH_TA, CA=$ARCH_CA" Review Comment: The variable ARCH_CA is referenced but never defined. Based on the context, this should be ARCH_HOST instead, which is defined at line 52. ```suggestion echo "Architecture: TA=$ARCH_TA, CA=$ARCH_HOST" ``` ########## cargo-optee/README.md: ########## @@ -0,0 +1,567 @@ +# cargo-optee + +A Cargo subcommand for building OP-TEE Trusted Applications (TAs) and Client Applications (CAs) in Rust. + +## Overview + +`cargo-optee` simplifies the development workflow for OP-TEE applications by replacing complex Makefiles with a unified, type-safe command-line interface. It handles cross-compilation, custom target specifications, environment setup, and signing automatically. + +## High-Level Design + +### Architecture + +``` + ┌──────────────────┐ + │ TA Developer │ + │ (CLI input) │ + └────────┬─────────┘ + │ + ▼ + ┌──────────────────────────────────────────────┐ + │ cargo-optee (this tool) │ + │ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 1. Parse CLI & Validate Parameters │ │ + │ │ - Architecture (aarch64/arm) │ │ + │ │ - Build mode (std/no-std) │ │ + │ │ - Build type (TA/CA/PLUGIN) │ │ + │ └──────────────────┬─────────────────────┘ │ + │ │ │ + │ ┌──────────────────▼─────────────────────┐ │ + │ │ 2. Setup Build Environment │ │ + │ │ - Set environment variables │ │ + │ │ - Configure cross-compiler │ │ + │ └──────────────────┬─────────────────────┘ │ + │ │ │ + │ ┌──────────────────▼─────────────────────┐ │ + │ │ 3. Execute Build Pipeline │ │ + │ │ - Run clippy (linting) │ │ + │ │ - Build binary: cargo/xargo + gcc │ │ + │ │ - Strip symbols: objcopy │ │ + │ │ - Sign TA: Python script (TA only) │ │ + │ └──────────────────┬─────────────────────┘ │ + │ │ │ + └─────────────────────┼────────────────────────┘ + │ + ▼ + ┌──────────────────────────────────────────────┐ + │ Low-Level Tools (dependencies) │ + │ │ + │ - cargo/xargo: Rust compilation │ + │ - gcc: Linking with OP-TEE libraries │ + │ - objcopy: Symbol stripping │ + │ - Python script: TA signing (TA only) │ + │ │ + └──────────────────────────────────────────────┘ +``` + +## Quick Start + +### Installation + +Assume developers have Rust, Cargo, and the gcc toolchain installed and added to PATH (the guide is in future plan). Then install `cargo-optee` using Cargo: + +```bash +cargo install cargo-optee +``` + +## Configuration System + +`cargo-optee` uses a flexible configuration system with the following priority (highest to lowest): + +1. **Command Line Arguments** - Direct CLI flags override everything +2. **Cargo.toml Metadata** - Project-specific configuration in `[package.metadata.optee.*]` sections +3. **Defaults** - Built-in sensible defaults + +This allows projects to define their standard configuration in `Cargo.toml` while still permitting CLI overrides for specific builds. + +### Metadata Configuration + +#### Trusted Application (TA) Metadata + +Configure TA builds in your `Cargo.toml`: + +```toml +[package.metadata.optee.ta] +arch = "aarch64" # Target architecture: "aarch64" | "arm" (optional, default: "aarch64") +debug = false # Debug build: true | false (optional, default: false) +std = false # Use std library: true | false (optional, default: false) +uuid-path = "../uuid.txt" # Path to UUID file (optional, default: "../uuid.txt") +# Architecture-specific configuration (omitted architectures default to null/unsupported) +ta-dev-kit-dir = { aarch64 = "/opt/optee/export-ta_arm64", arm = "/opt/optee/export-ta_arm32" } +signing-key = "/path/to/key.pem" # Path to signing key (optional, defaults to ta-dev-kit/keys/default_ta.pem) +``` + +**Allowed entries:** +- `arch`: Target architecture (`"aarch64"` or `"arm"`) +- `debug`: Build in debug mode (`true` or `false`) +- `std`: Enable std library support (`true` or `false`) +- `uuid-path`: Relative or absolute path to UUID file +- `ta-dev-kit-dir`: Architecture-specific paths to TA development kit (required) +- `signing-key`: Path to signing key file + +#### Client Application (CA) Metadata + +Configure CA builds in your `Cargo.toml`: + +```toml +[package.metadata.optee.ca] +arch = "aarch64" # Target architecture: "aarch64" | "arm" (optional, default: "aarch64") +debug = false # Debug build: true | false (optional, default: false) +# Architecture-specific configuration +# if your CA only supports aarch64, you can omit arm +optee-client-export = { aarch64 = "/opt/optee/export-client_arm64" } +``` + +**Allowed entries:** +- `arch`: Target architecture (`"aarch64"` or `"arm"`) +- `debug`: Build in debug mode (`true` or `false`) +- `optee-client-export`: Architecture-specific paths to OP-TEE client export (required) + +#### Plugin Metadata + +Configure plugin builds in your `Cargo.toml`: + +```toml +[package.metadata.optee.plugin] +arch = "aarch64" # Target architecture: "aarch64" | "arm" (optional, default: "aarch64") +debug = false # Debug build: true | false (optional, default: false) +uuid-path = "../plugin_uuid.txt" # Path to UUID file (required for plugins) +# Architecture-specific configuration +optee-client-export = { aarch64 = "/opt/optee/export-client_arm64", arm = "/opt/optee/export-client_arm32" } +``` + +**Allowed entries:** +- `arch`: Target architecture (`"aarch64"` or `"arm"`) +- `debug`: Build in debug mode (`true` or `false`) +- `uuid-path`: Relative or absolute path to UUID file (required for plugins) +- `optee-client-export`: Architecture-specific paths to OP-TEE client export (required) + +### Project Structure + +Cargo-optee expects the following project structure by default. + +``` +project/ +├── uuid.txt # TA UUID +├── ta/ # Trusted Application +│ ├── Cargo.toml +│ ├── src/ +│ │ └── main.rs +│ └── build.rs # Build script +├── host/ # Client Application (host) +│ ├── Cargo.toml +│ ├── src/ +│ │ └── main.rs +└── proto/ # Shared definitions such as TA command IDs and TA UUID + ├── Cargo.toml + └── src/ + └── lib.rs +``` + +See examples in the SDK for reference, such as `hello_world-rs`. +The `cargo new` command (planned, not yet available) will generate a project template with this structure. For now, copy an existing example as a starting point. + +### Build Commands + +#### Build Trusted Application (TA) + +```bash +cargo-optee build ta \ + --ta-dev-kit-dir <PATH> \ + [--manifest-path <PATH>] \ + [--arch aarch64|arm] \ + [--std] \ + [--no-std] \ + [--signing-key <PATH>] \ + [--uuid-path <PATH>] \ + [--debug] +``` + +**Required:** +- `--ta-dev-kit-dir <PATH>`: Path to OP-TEE TA development kit (available after building OP-TEE OS), user must provide this for building TAs. + +**Optional:** +- `--manifest-path <PATH>`: Path to Cargo.toml manifest file +- `--arch <ARCH>`: Target architecture (default: `aarch64`) + - `aarch64`: ARM 64-bit architecture + - `arm`: ARM 32-bit architecture +- `--std`: Build with std support (uses xargo and custom target) +- `--no-std`: Build without std support (uses cargo, mutually exclusive with --std) +- `--signing-key <PATH>`: Path to signing key (default: `<ta-dev-kit-dir>/keys/default_ta.pem`) +- `--uuid-path <PATH>`: Path to UUID file (default: `../uuid.txt`) +- `--debug`: Build in debug mode (default: release mode) + +**Example:** +```bash +# Build aarch64 TA with std support +cargo-optee build ta \ + --ta-dev-kit-dir /opt/optee/export-ta_arm64 \ + --manifest-path ./examples/hello_world-rs/ta/Cargo.toml \ + --arch aarch64 \ + --std + +# Build arm TA without std (no-std) +cargo-optee build ta \ + --ta-dev-kit-dir /opt/optee/export-ta_arm32 \ + --manifest-path ./ta/Cargo.toml \ + --arch arm + --no-std + +# Build TA with Cargo.toml metadata configuration +# Note: ta-dev-kit-dir must be configured in Cargo.toml for this work +cargo-optee build ta \ + --manifest-path ./ta/Cargo.toml +``` + +**Output:** +- TA binary: `target/<target-triple>/release/<uuid>.ta` +- Intermediate files in `target/` directory + +#### Build Client Application (CA) + +```bash +cargo-optee build ca \ + --optee-client-export <PATH> \ + [--manifest-path <PATH>] \ + [--arch aarch64|arm] \ + [--debug] +``` + +**Required:** +- `--optee-client-export <PATH>`: Path to OP-TEE client library directory (available after building OP-TEE client), user must provide this for building CAs. + +**Optional:** +- `--manifest-path <PATH>`: Path to Cargo.toml manifest file +- `--arch <ARCH>`: Target architecture (default: `aarch64`) +- `--debug`: Build in debug mode (default: release mode) + +**Example:** +```bash +# Build aarch64 client application +cargo-optee build ca \ + --optee-client-export /opt/optee/export-client \ + --manifest-path ./examples/hello_world-rs/host/Cargo.toml \ + --arch aarch64 +``` + +**Output:** +- CA binary: `target/<target-triple>/release/<binary-name>` + +#### Build Plugin + +We have one example for plugin: `supp_plugin-rs/plugin`. + +```bash +cargo-optee build plugin \ + --optee-client-export <PATH> \ + --uuid-path <PATH> \ + [--manifest-path <PATH>] \ + [--arch aarch64|arm] \ + [--debug] +``` + +**Required:** +- `--optee-client-export <PATH>`: Path to OP-TEE client library directory (available after building OP-TEE client), user must provide this for building plugins. +- `--uuid-path <PATH>`: Path to UUID file for naming the plugin + +**Optional:** +- `--manifest-path <PATH>`: Path to Cargo.toml manifest file +- `--arch <ARCH>`: Target architecture (default: `aarch64`) +- `--debug`: Build in debug mode (default: release mode) + +**Example:** +```bash +# Build aarch64 plugin +cargo-optee build plugin \ + --optee-client-export /opt/optee/export-client \ + --manifest-path ./examples/supp_plugin-rs/plugin/Cargo.toml \ + --uuid-path ./examples/supp_plugin-rs/plugin_uuid.txt \ + --arch aarch64 +``` + +**Output:** +- Plugin binary: `target/<target-triple>/release/<uuid>.plugin.so` + +### Usage Workflows (including future design) + +#### Development/Emulation Environment + +For development and emulation, developers would like to build the one project and deploy to a target filesystem (e.g. QEMU shared folder) quickly. Frequent builds and quick rebuilds are common. + +**Using CLI arguments:** +```bash +# 1. Create new project (future) +cargo-optee new my_app +cd my_app + +# 2. Build TA and CA +cargo-optee build ta \ + --ta-dev-kit-dir $TA_DEV_KIT_DIR \ + --manifest-path ./ta/Cargo.toml \ + --arch aarch64 \ + --std + +cargo-optee build ca \ + --optee-client-export $OPTEE_CLIENT_EXPORT \ + --manifest-path ./host/Cargo.toml \ + --arch aarch64 + +# 3. Install to specific folder (future), e.g. QEMU shared folder for emulation +cargo-optee install --target /tmp/qemu-shared-folder +``` + +**Using metadata configuration:** +```bash +# 1. Configure once in Cargo.toml files, then simple builds +cd ta && cargo-optee build ta +cd ../host && cargo-optee build ca + +# 2. Override specific parameters when needed +cd ta && cargo-optee build ta --debug # Override to debug build +cd host && cargo-optee build ca --arch arm # Override architecture +``` + +#### Production/CI Environment + +For production and CI environments, artifacts should be cleaned up after successful builds. It can help to avoid storage issues on CI runners. + +**Automated Build Pipeline:** +```bash +#!/bin/bash +# CI build script + +set -e + +# Build TA (release mode) +cargo-optee build ta \ + --ta-dev-kit-dir $TA_DEV_KIT_DIR \ + --manifest-path ./ta/Cargo.toml \ + --arch aarch64 \ + --std \ + --signing-key ./keys/production.pem + +# Build CA (release mode) +cargo-optee build ca \ + --optee-client-export $OPTEE_CLIENT_EXPORT \ + --manifest-path ./host/Cargo.toml \ + --arch aarch64 + +# Install to staging area (future) +cargo-optee install --target ./dist + +# Clean build artifacts to save space (future) +cargo-optee clean --all +``` + +## Implementation Status + +| Feature | Status | Notes | +|---------|--------|-------| +| `build ta` | ✅ Implemented | Supports aarch64/arm, std/no-std | +| `build ca` | ✅ Implemented | Supports aarch64/arm | +| `build plugin` | ✅ Implemented | Supports aarch64/arm, builds shared library plugins | +| `new` | ⏳ Planned | Project scaffolding | +| `install` | ⏳ Planned | Deploy to target filesystem | +| `clean` | ⏳ Planned | Remove build artifacts | +| `clean` | ⏳ Planned | Remove build artifacts | Review Comment: The "clean" feature is listed twice in the table - once at line 366 and again at line 367. One of these duplicate entries should be removed. ```suggestion ``` ########## cargo-optee/src/ta_builder.rs: ########## @@ -0,0 +1,505 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use anyhow::{bail, Result}; +use std::env; +use std::fs; +use std::path::Path; +use std::path::PathBuf; +use std::process::Command; +use tempfile::TempDir; +use toml::Value; + +use crate::common::{print_cargo_command, print_output_and_bail, read_uuid_from_file, Arch}; + +// Embed the target JSON files at compile time +const AARCH64_TARGET_JSON: &str = include_str!("../aarch64-unknown-optee.json"); +const ARM_TARGET_JSON: &str = include_str!("../arm-unknown-optee.json"); + +// Target configurations for different architectures and std modes +const TARGET_CONFIGS: [(Arch, bool, &str, &str); 4] = [ + // (Architecture, has_std, target, cross_compile_prefix) + ( + Arch::Arm, + false, + "arm-unknown-linux-gnueabihf", + "arm-linux-gnueabihf-", + ), + (Arch::Arm, true, "arm-unknown-optee", "arm-linux-gnueabihf-"), + ( + Arch::Aarch64, + false, + "aarch64-unknown-linux-gnu", + "aarch64-linux-gnu-", + ), + ( + Arch::Aarch64, + true, + "aarch64-unknown-optee", + "aarch64-linux-gnu-", + ), +]; + +/// Check if the required cross-compile toolchain is available +fn check_toolchain_exists(cross_compile_prefix: &str) -> Result<()> { + let gcc_command = format!("{}gcc", cross_compile_prefix); + let objcopy_command = format!("{}objcopy", cross_compile_prefix); + + // Check if gcc exists + let gcc_check = Command::new("which").arg(&gcc_command).output(); + + // Check if objcopy exists + let objcopy_check = Command::new("which").arg(&objcopy_command).output(); + + let gcc_exists = gcc_check.map_or(false, |output| output.status.success()); + let objcopy_exists = objcopy_check.map_or(false, |output| output.status.success()); + + if !gcc_exists || !objcopy_exists { + let missing_tools: Vec<&str> = [ + if !gcc_exists { + Some(gcc_command.as_str()) + } else { + None + }, + if !objcopy_exists { + Some(objcopy_command.as_str()) + } else { + None + }, + ] + .iter() + .filter_map(|&x| x) + .collect(); + + eprintln!("Error: Required cross-compile toolchain not found!"); + eprintln!("Missing tools: {}", missing_tools.join(", ")); + eprintln!(); + eprintln!("Please install the required toolchain:"); + eprintln!(); + eprintln!("# For aarch64 host (ARM64 machine):"); + eprintln!("apt update && apt -y install gcc gcc-arm-linux-gnueabihf"); + eprintln!(); + eprintln!("# For x86_64 host (Intel/AMD machine):"); + eprintln!("apt update && apt -y install gcc-aarch64-linux-gnu gcc-arm-linux-gnueabihf"); + eprintln!(); + eprintln!("Or manually install the cross-compilation tools for your target architecture."); + + bail!("Cross-compile toolchain not available"); + } + + Ok(()) +} + +#[derive(Clone)] +pub struct TaBuildConfig { + pub arch: Arch, // Architecture + pub std: bool, // Enable std feature + pub ta_dev_kit_dir: PathBuf, // Path to TA dev kit + pub signing_key: PathBuf, // Path to signing key + pub debug: bool, // Debug mode (default false = release) + pub path: PathBuf, // Path to TA directory + pub uuid_path: PathBuf, // Path to UUID file + // Customized variables + pub env: Vec<(String, String)>, // Custom environment variables for cargo build + pub no_default_features: bool, // Disable default features + pub features: Option<String>, // Additional features to enable +} + +// Helper function to derive target and cross-compile from arch and std +fn get_target_and_cross_compile(arch: Arch, std: bool) -> Result<(String, String)> { + for &(config_arch, config_std, target, cross_compile_prefix) in &TARGET_CONFIGS { + if config_arch == arch && config_std == std { + return Ok((target.to_string(), cross_compile_prefix.to_string())); + } + } + + bail!( + "No target configuration found for arch: {:?}, std: {}", + arch, + std + ); +} + +// Helper function to setup custom target JSONs for std builds +// Returns TempDir to keep it alive during the build +fn setup_custom_targets() -> Result<TempDir> { + let temp_dir = TempDir::new()?; + + // Write the embedded target JSON files + let aarch64_path = temp_dir.path().join("aarch64-unknown-optee.json"); + let arm_path = temp_dir.path().join("arm-unknown-optee.json"); + + fs::write(aarch64_path, AARCH64_TARGET_JSON)?; + fs::write(arm_path, ARM_TARGET_JSON)?; + + Ok(temp_dir) +} + +// Helper function to setup base command with common environment variables +fn setup_build_command( + config: &TaBuildConfig, + command: &str, +) -> Result<(Command, Option<TempDir>)> { + // Determine target and cross-compile based on arch + let (target, _cross_compile) = get_target_and_cross_compile(config.arch, config.std)?; + + // Determine builder (cargo or xargo) + let builder = if config.std { "xargo" } else { "cargo" }; + + // Setup custom targets if using std - keep TempDir alive + let temp_dir = if config.std { + Some(setup_custom_targets()?) + } else { + None + }; + + let mut cmd = Command::new(builder); + cmd.arg(command); + cmd.arg("--target").arg(&target); + + // Add --no-default-features if specified + if config.no_default_features { + cmd.arg("--no-default-features"); + } + + // Build features list + let mut features = Vec::new(); + if config.std { + features.push("std".to_string()); + } + if let Some(ref custom_features) = config.features { + // Split custom features by comma and add them + for feature in custom_features.split(',') { + let feature = feature.trim(); + if !feature.is_empty() { + features.push(feature.to_string()); + } + } + } + + // Add features if any are specified + if !features.is_empty() { + cmd.arg("--features").arg(features.join(",")); + } + + // Add no-std specific flags to avoid the linking error of _Unwind_Resume + if !config.std { + cmd.arg("-Z").arg("build-std=core,alloc"); + cmd.arg("-Z") + .arg("build-std-features=panic_immediate_abort"); + } + + // Set RUSTFLAGS - preserve existing ones and add panic=abort + let mut rustflags = env::var("RUSTFLAGS").unwrap_or_default(); + if !rustflags.is_empty() { + rustflags.push(' '); + } + rustflags.push_str("-C panic=abort"); + cmd.env("RUSTFLAGS", &rustflags); + + // Apply custom environment variables + for (key, value) in &config.env { + cmd.env(key, value); + } + + // Set TA_DEV_KIT_DIR environment variable (use absolute path) + let absolute_ta_dev_kit_dir = config + .ta_dev_kit_dir + .canonicalize() + .unwrap_or_else(|_| config.ta_dev_kit_dir.clone()); + cmd.env("TA_DEV_KIT_DIR", &absolute_ta_dev_kit_dir); + + // Set RUST_TARGET_PATH for custom targets when using std + if let Some(ref temp_dir_ref) = temp_dir { + cmd.env("RUST_TARGET_PATH", temp_dir_ref.path()); + } + + Ok((cmd, temp_dir)) +} + +// Main function to build the TA, optionally installing to a target directory +pub fn build_ta(config: TaBuildConfig, install_dir: Option<&Path>) -> Result<()> { + // Check if required cross-compile toolchain is available + let (_, cross_compile_prefix) = get_target_and_cross_compile(config.arch, config.std)?; + check_toolchain_exists(&cross_compile_prefix)?; + + // Verify we're in a valid Rust project directory + let manifest_path = config.path.join("Cargo.toml"); + if !manifest_path.exists() { + bail!( + "No Cargo.toml found in TA project directory: {:?}\n\ + Please run cargo-optee from a TA project directory or specify --manifest-path", + config.path + ); + } + // Get the absolute path for better clarity + let absolute_path = std::fs::canonicalize(&config.path).unwrap_or_else(|_| config.path.clone()); + println!("Building TA in directory: {}", absolute_path.display()); + + // Step 1: Run clippy for code quality checks + run_clippy(&config, &manifest_path)?; + + // Step 2: Build the TA + build_binary(&config, &manifest_path)?; + + // Step 3: Strip the binary + let (stripped_path, target_dir) = strip_binary(&config, &manifest_path)?; + + // Step 4: Sign the TA + sign_ta(&config, &stripped_path, &target_dir)?; + + // Step 5: Install if requested + if let Some(install_dir) = install_dir { + // Check if install directory exists + if !install_dir.exists() { + bail!("Install directory does not exist: {:?}", install_dir); + } + + let uuid = read_uuid_from_file(&config.uuid_path)?; + let ta_file = target_dir.join(format!("{}.ta", uuid)); + + if !ta_file.exists() { + bail!("Signed TA file not found at {:?}", ta_file); + } + + let dest_path = install_dir.join(format!("{}.ta", uuid)); + fs::copy(&ta_file, &dest_path)?; + + println!( + "TA installed to: {:?}", + dest_path.canonicalize().unwrap_or(dest_path) + ); + } + + println!("TA build successfully!"); + + Ok(()) +} + +fn run_clippy(config: &TaBuildConfig, manifest_path: &Path) -> Result<()> { + println!("Running cargo fmt and clippy..."); + + // Get the project directory from manifest path + let project_dir = manifest_path + .parent() + .ok_or_else(|| anyhow::anyhow!("Invalid manifest path: {:?}", manifest_path))?; + + // Change to project directory to respect rust-toolchain.toml + let original_dir = std::env::current_dir()?; + std::env::set_current_dir(project_dir)?; + + // Run cargo fmt (without --manifest-path since we're in the project dir) + let mut fmt_cmd = Command::new("cargo"); + fmt_cmd.arg("fmt"); + let fmt_output = fmt_cmd.output(); + + // Restore original directory before checking results + std::env::set_current_dir(&original_dir)?; + + let fmt_output = fmt_output?; + if !fmt_output.status.success() { + print_output_and_bail("cargo fmt", &fmt_output)?; + } + + // Change back to project directory for clippy + std::env::set_current_dir(project_dir)?; + + // Setup clippy command with common environment (without --manifest-path) + let (mut clippy_cmd, _temp_dir) = setup_build_command(config, "clippy")?; + + clippy_cmd.arg("--"); + clippy_cmd.arg("-D").arg("warnings"); + clippy_cmd.arg("-D").arg("clippy::unwrap_used"); + clippy_cmd.arg("-D").arg("clippy::expect_used"); + clippy_cmd.arg("-D").arg("clippy::panic"); + + let clippy_output = clippy_cmd.output(); + + // Restore original directory before checking results + std::env::set_current_dir(&original_dir)?; + + let clippy_output = clippy_output?; + if !clippy_output.status.success() { + print_output_and_bail("clippy", &clippy_output)?; + } + + Ok(()) +} + +fn build_binary(config: &TaBuildConfig, manifest_path: &Path) -> Result<()> { + // Get the project directory from manifest path + let project_dir = manifest_path + .parent() + .ok_or_else(|| anyhow::anyhow!("Invalid manifest path: {:?}", manifest_path))?; + + // Change to project directory to respect rust-toolchain.toml + let original_dir = std::env::current_dir()?; + std::env::set_current_dir(project_dir)?; + + // Determine target and cross-compile based on arch + let (target, cross_compile) = get_target_and_cross_compile(config.arch, config.std)?; + + // Setup build command with common environment (without --manifest-path) + let (mut build_cmd, _temp_dir) = setup_build_command(config, "build")?; + + if !config.debug { + build_cmd.arg("--release"); + } + + // Configure linker + let linker = format!("{}gcc", cross_compile); + let linker_cfg = format!("target.{}.linker=\"{}\"", target, linker); + build_cmd.arg("--config").arg(&linker_cfg); + + // Print the full cargo build command for debugging + print_cargo_command(&build_cmd, "Building TA binary"); + + let build_output = build_cmd.output(); + + // Restore original directory before checking results + std::env::set_current_dir(original_dir)?; + + let build_output = build_output?; + if !build_output.status.success() { + print_output_and_bail("build", &build_output)?; + } + + Ok(()) +} + +fn get_package_name(manifest_path: &Path) -> Result<String> { + if !manifest_path.exists() { + bail!("Cargo.toml not found at: {:?}", manifest_path); + } + + let cargo_toml_content = fs::read_to_string(manifest_path)?; + let cargo_toml: Value = toml::from_str(&cargo_toml_content)?; + + let package_name = cargo_toml + .get("package") + .and_then(|p| p.get("name")) + .and_then(|n| n.as_str()) + .ok_or_else(|| anyhow::anyhow!("Could not find package name in Cargo.toml"))?; + + Ok(package_name.to_string()) +} + +fn strip_binary(config: &TaBuildConfig, manifest_path: &Path) -> Result<(PathBuf, PathBuf)> { + println!("Stripping binary..."); + + // Determine target based on arch + let (target, cross_compile) = get_target_and_cross_compile(config.arch, config.std)?; + + let profile = if config.debug { "debug" } else { "release" }; + + // Get the actual package name from Cargo.toml + let package_name = get_package_name(manifest_path)?; + + // Use cargo metadata to get the target directory that cargo is actually using + let output = Command::new("cargo") + .arg("metadata") + .arg("--manifest-path") + .arg(manifest_path) + .arg("--format-version") + .arg("1") + .arg("--no-deps") + .output()?; + + if !output.status.success() { + bail!("Failed to get cargo metadata"); + } + + let metadata: serde_json::Value = serde_json::from_slice(&output.stdout)?; + let target_directory = metadata + .get("target_directory") + .and_then(|v| v.as_str()) + .ok_or_else(|| anyhow::anyhow!("Could not get target directory from cargo metadata"))?; + + let target_dir = PathBuf::from(target_directory); + let profile_dir = target_dir.join(target).join(profile); + let binary_path = profile_dir.join(&package_name); + + if !binary_path.exists() { + bail!("Binary not found at {:?}", binary_path); + } + + let stripped_path = profile_dir.join(format!("stripped_{}", package_name)); + + if !binary_path.exists() { + bail!("Binary not found at {:?}", binary_path); + } + Review Comment: This existence check is duplicated - it appears again at line 436. The second check at line 442 should be removed as it's redundant. ```suggestion ``` ########## cargo-optee/aarch64-unknown-optee.json: ########## @@ -0,0 +1,21 @@ +{ + "arch": "aarch64", + "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", + "features": "+strict-align", + "dynamic-linking": false, + "executables": true, + "has-rpath": true, + "linker-flavor": "ld", + "linker-is-gnu": true, + "llvm-target": "aarch64-unknown-linux-gnu", + "max-atomic-width": 128, + "os": "optee", + "position-independent-executables": true, + "relro-level": "full", + "target-c-int-width": "32", + "target-endian": "little", + "target-pointer-width": "64", + "vendor": "unknown", + "panic-strategy": "abort" + } Review Comment: The JSON file has inconsistent indentation - most of the file uses 4 spaces (lines 2-19) but this line uses 2 spaces. For consistency, this line should use 4 spaces like the rest of the file. ```suggestion } ``` ########## ci/build.sh: ########## @@ -0,0 +1,435 @@ +#!/bin/bash + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +set -e + +# Show usage +show_usage() { + cat << EOF +Usage: TA_DEV_KIT_DIR=<path> OPTEE_CLIENT_EXPORT=<path> $0 [OPTIONS] + +Required environment variables: + TA_DEV_KIT_DIR Path to OP-TEE OS TA dev kit directory + OPTEE_CLIENT_EXPORT Path to OP-TEE client export directory + +Options: + --ta <arch> TA architecture: aarch64 or arm (default: aarch64) + --host <arch> Host architecture for CA and plugins: aarch64 or arm (default: aarch64) + --std Install with std support (default: no-std) + --ta-install-dir <path> TA installation directory (default: ./tests/shared) + --ca-install-dir <path> CA installation directory (default: ./tests/shared) + --plugin-install-dir <path> Plugin installation directory (default: ./tests/shared) + --help Show this help message + +Examples: + # Install for aarch64 in no-std mode + TA_DEV_KIT_DIR=/path/to/export-ta_arm64 OPTEE_CLIENT_EXPORT=/path/to/export ./build.sh + + # Install for ARM32 in std mode with custom directories + TA_DEV_KIT_DIR=/path/to/export-ta_arm32 OPTEE_CLIENT_EXPORT=/path/to/export ./build.sh --ta arm --host arm --std --ta-install-dir /target/lib/optee_armtz --ca-install-dir /target/usr/bin + +Note: Binaries are installed to './tests/shared' directory by default. +EOF +} + +# Parse command line arguments +ARCH_TA="aarch64" # Default: aarch64 +ARCH_HOST="aarch64" # Default: aarch64 +STD="" # Default: empty (no-std) +TA_INSTALL_DIR="" # Default: will be set to ./tests/shared if not specified +CA_INSTALL_DIR="" # Default: will be set to ./tests/shared if not specified +PLUGIN_INSTALL_DIR="" # Default: will be set to ./tests/shared if not specified + +# Parse arguments (support both positional and flag-style) +while [[ $# -gt 0 ]]; do + case "$1" in + --help|-h) + show_usage + exit 0 + ;; + --ta) + ARCH_TA="$2" + shift 2 + ;; + --host) + ARCH_HOST="$2" + shift 2 + ;; + --std) + STD="std" + shift + ;; + --ta-install-dir) + TA_INSTALL_DIR="$2" + shift 2 + ;; + --ca-install-dir) + CA_INSTALL_DIR="$2" + shift 2 + ;; + --plugin-install-dir) + PLUGIN_INSTALL_DIR="$2" + shift 2 + ;; + *) + # Positional arguments (backward compatibility) + if [[ -z "${ARCH_TA_SET:-}" ]]; then + ARCH_TA="$1" + ARCH_TA_SET=1 + elif [[ -z "${ARCH_HOST_SET:-}" ]]; then + ARCH_HOST="$1" + ARCH_HOST_SET=1 + elif [[ "$1" == "std" ]]; then + STD="std" + fi + shift + ;; + esac +done + +# Validate architecture +if [[ "$ARCH_TA" != "aarch64" && "$ARCH_TA" != "arm" ]]; then + echo "Error: ARCH_TA must be 'aarch64' or 'arm'" + exit 1 +fi + +if [[ "$ARCH_HOST" != "aarch64" && "$ARCH_HOST" != "arm" ]]; then + echo "Error: ARCH_HOST must be 'aarch64' or 'arm'" + exit 1 +fi + +# Check required environment variables +if [ -z "$TA_DEV_KIT_DIR" ]; then + echo "Error: TA_DEV_KIT_DIR environment variable is not set" + exit 1 +fi + +if [ -z "$OPTEE_CLIENT_EXPORT" ]; then + echo "Error: OPTEE_CLIENT_EXPORT environment variable is not set" + exit 1 +fi + +echo "===========================================" +echo "Installing with configuration:" +echo " ARCH_TA: $ARCH_TA" +echo " ARCH_HOST: $ARCH_HOST" +echo " STD: ${STD:-no-std}" +echo " TA_DEV_KIT_DIR: $TA_DEV_KIT_DIR" +echo " OPTEE_CLIENT_EXPORT: $OPTEE_CLIENT_EXPORT" +echo "===========================================" + +# Step 1: Build cargo-optee tool +echo "" +echo "Step 1: Building cargo-optee tool..." +cd cargo-optee +cargo build --release +CARGO_OPTEE="$(pwd)/target/release/cargo-optee" +cd .. + +if [ ! -f "$CARGO_OPTEE" ]; then + echo "Error: Failed to build cargo-optee" + exit 1 +fi + +echo "cargo-optee built successfully: $CARGO_OPTEE" + +# Prepare std flag for cargo-optee +STD_FLAG="" +if [ -n "$STD" ]; then + STD_FLAG="--std" +fi + +# Step 2: Install all examples to shared directory +echo "" +echo "Step 2: Installing all examples..." + +# Set up installation directories +# Each directory defaults to ./tests/shared if not specified +if [ -z "$TA_INSTALL_DIR" ]; then + TA_INSTALL_DIR="$(pwd)/tests/shared" +fi + +if [ -z "$CA_INSTALL_DIR" ]; then + CA_INSTALL_DIR="$(pwd)/tests/shared" +fi + +if [ -z "$PLUGIN_INSTALL_DIR" ]; then + PLUGIN_INSTALL_DIR="$(pwd)/tests/shared" +fi + +# Create all directories +mkdir -p "$TA_INSTALL_DIR" +mkdir -p "$CA_INSTALL_DIR" +mkdir -p "$PLUGIN_INSTALL_DIR" + +echo "Installing binaries to:" +echo " TAs: $TA_INSTALL_DIR" +echo " CAs: $CA_INSTALL_DIR" +echo " Plugins: $PLUGIN_INSTALL_DIR" + +EXAMPLES_DIR="$(pwd)/examples" +METADATA_JSON="$EXAMPLES_DIR/metadata.json" + +if [ ! -f "$METADATA_JSON" ]; then + echo "Error: $METADATA_JSON not found" + exit 1 +fi + +# Check if jq is available for JSON parsing +if ! command -v jq &> /dev/null; then + echo "Error: jq is required to parse metadata.json" + echo "Please install jq: apt-get install jq" + exit 1 +fi + +echo "Loading example metadata from $METADATA_JSON..." + +# Get all example names +ALL_EXAMPLES=($(jq -r '.examples | keys[]' "$METADATA_JSON")) + +if [ -n "$STD" ]; then + echo "Building in STD mode (std-only + common examples)" +else + echo "Building in NO-STD mode (no-std-only + common examples)" +fi + +CURRENT=0 +FAILED_EXAMPLES="" + +# Build examples +for EXAMPLE_NAME in "${ALL_EXAMPLES[@]}"; do + CATEGORY=$(jq -r ".examples[\"$EXAMPLE_NAME\"].category" "$METADATA_JSON") + + # Determine if we should build this example + SHOULD_BUILD=false + if [ -n "$STD" ]; then + # STD mode: build std-only and common + if [[ "$CATEGORY" == "std-only" || "$CATEGORY" == "common" ]]; then + SHOULD_BUILD=true + fi + else + # NO-STD mode: build no-std-only and common + if [[ "$CATEGORY" == "no-std-only" || "$CATEGORY" == "common" ]]; then + SHOULD_BUILD=true + fi + fi + + if [ "$SHOULD_BUILD" = false ]; then + continue + fi + + CURRENT=$((CURRENT + 1)) + EXAMPLE_DIR="$EXAMPLES_DIR/$EXAMPLE_NAME" + + if [ ! -d "$EXAMPLE_DIR" ]; then + echo "ERROR: Example directory not found: $EXAMPLE_DIR" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME" + continue + fi + + echo "" + echo "==========================================" + echo "[$CURRENT] Building: $EXAMPLE_NAME ($CATEGORY)" + echo "==========================================" + + # Get TA, CA, and Plugin directories from metadata + TAS_JSON=$(jq -c ".examples[\"$EXAMPLE_NAME\"].tas" "$METADATA_JSON") + CAS_JSON=$(jq -c ".examples[\"$EXAMPLE_NAME\"].cas" "$METADATA_JSON") + PLUGINS_JSON=$(jq -c ".examples[\"$EXAMPLE_NAME\"].plugins // []" "$METADATA_JSON") + + # Build all TAs for this example + TA_COUNT=$(echo "$TAS_JSON" | jq 'length') + CA_COUNT=$(echo "$CAS_JSON" | jq 'length') + PLUGIN_COUNT=$(echo "$PLUGINS_JSON" | jq 'length') + + echo "→ Found $TA_COUNT TA(s), $CA_COUNT CA(s), and $PLUGIN_COUNT Plugin(s)" + + if [ "$TA_COUNT" -gt 0 ]; then + for ((i=0; i<$TA_COUNT; i++)); do + TA_DIR=$(echo "$TAS_JSON" | jq -r ".[$i]") + TA_DIR_FULL_PATH="$EXAMPLES_DIR/$TA_DIR" + + if [ ! -d "$TA_DIR_FULL_PATH" ]; then + echo "ERROR: TA directory not found: $TA_DIR_FULL_PATH" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME ($TA_DIR)" + continue + fi + + if [ ! -f "$TA_DIR_FULL_PATH/Cargo.toml" ]; then + echo "ERROR: Cargo.toml not found in TA directory: $TA_DIR_FULL_PATH" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME ($TA_DIR)" + continue + fi + + echo "" + echo "→ Building TA [$((i+1))/$TA_COUNT]: $TA_DIR" + + # Determine STD_FLAG for TA + TA_STD_FLAG="" + if [ -n "$STD" ]; then + # In std mode: always pass --std flag to cargo-optee + TA_STD_FLAG="--std" + fi + + # Change to TA directory and run cargo-optee without --manifest-path + cd "$TA_DIR_FULL_PATH" + + # Run cargo-optee install and capture both stdout and stderr + if $CARGO_OPTEE install ta \ + --target-dir "$TA_INSTALL_DIR" \ + --ta-dev-kit-dir "$TA_DEV_KIT_DIR" \ + --arch "$ARCH_TA" \ + $TA_STD_FLAG; then + echo " ✓ TA installed successfully" + # Clean up build artifacts + $CARGO_OPTEE clean + else + echo " ✗ ERROR: Failed to install TA: $TA_DIR" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME ($TA_DIR)" + cd "$EXAMPLES_DIR" # Return to examples directory + continue + fi + + # Return to examples directory + cd "$EXAMPLES_DIR" + done + else + echo "WARNING: No TAs defined for $EXAMPLE_NAME" + fi + + # Build each CA + CA_INDEX=0 + while [[ "$CA_INDEX" -lt "$CA_COUNT" ]]; do + CA_DIR=$(echo "$CAS_JSON" | jq -r ".[$CA_INDEX]") + CA_DIR_FULL_PATH="$EXAMPLES_DIR/$CA_DIR" + + echo "" + echo "→ Building CA [$((CA_INDEX+1))/$CA_COUNT]: $CA_DIR" + + if [ ! -d "$CA_DIR_FULL_PATH" ]; then + echo "ERROR: CA directory not found: $CA_DIR_FULL_PATH" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME ($CA_DIR)" + CA_INDEX=$((CA_INDEX + 1)) + continue + fi + + if [ ! -f "$CA_DIR_FULL_PATH/Cargo.toml" ]; then + echo "ERROR: Cargo.toml not found in CA directory: $CA_DIR_FULL_PATH" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME ($CA_DIR)" + CA_INDEX=$((CA_INDEX + 1)) + continue + fi + + # Change to CA directory and run cargo-optee without --manifest-path + cd "$CA_DIR_FULL_PATH" + + if $CARGO_OPTEE install ca \ + --target-dir "$CA_INSTALL_DIR" \ + --optee-client-export "$OPTEE_CLIENT_EXPORT" \ + --arch "$ARCH_HOST"; then + echo " ✓ CA installed successfully" + # Clean up build artifacts + $CARGO_OPTEE clean + else + echo " ✗ ERROR: Failed to install CA: $CA_DIR" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME ($CA_DIR)" + cd "$EXAMPLES_DIR" # Return to examples directory + CA_INDEX=$((CA_INDEX + 1)) + continue + fi + + # Return to examples directory + cd "$EXAMPLES_DIR" + CA_INDEX=$((CA_INDEX + 1)) + done + + # Build each Plugin + PLUGIN_INDEX=0 + while [[ "$PLUGIN_INDEX" -lt "$PLUGIN_COUNT" ]]; do + PLUGIN_DIR=$(echo "$PLUGINS_JSON" | jq -r ".[$PLUGIN_INDEX]") + PLUGIN_DIR_FULL_PATH="$EXAMPLES_DIR/$PLUGIN_DIR" + + echo "" + echo "→ Building Plugin [$((PLUGIN_INDEX+1))/$PLUGIN_COUNT]: $PLUGIN_DIR" + + if [ ! -d "$PLUGIN_DIR_FULL_PATH" ]; then + echo "ERROR: Plugin directory not found: $PLUGIN_DIR_FULL_PATH" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME ($PLUGIN_DIR)" + PLUGIN_INDEX=$((PLUGIN_INDEX + 1)) + continue + fi + + if [ ! -f "$PLUGIN_DIR_FULL_PATH/Cargo.toml" ]; then + echo "ERROR: Cargo.toml not found in Plugin directory: $PLUGIN_DIR_FULL_PATH" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME ($PLUGIN_DIR)" + PLUGIN_INDEX=$((PLUGIN_INDEX + 1)) + continue + fi + + # Change to Plugin directory and run cargo-optee without --manifest-path + cd "$PLUGIN_DIR_FULL_PATH" + + if $CARGO_OPTEE install plugin \ + --target-dir "$PLUGIN_INSTALL_DIR" \ + --optee-client-export "$OPTEE_CLIENT_EXPORT" \ + --arch "$ARCH_HOST"; then + echo " ✓ Plugin installed successfully" + # Clean up build artifacts + $CARGO_OPTEE clean + else + echo " ✗ ERROR: Failed to install Plugin: $PLUGIN_DIR" + FAILED_EXAMPLES="$FAILED_EXAMPLES\n - $EXAMPLE_NAME ($PLUGIN_DIR)" + cd "$EXAMPLES_DIR" # Return to examples directory + PLUGIN_INDEX=$((PLUGIN_INDEX + 1)) + continue + fi + + # Return to examples directory + cd "$EXAMPLES_DIR" + PLUGIN_INDEX=$((PLUGIN_INDEX + 1)) + done + + echo "" + echo "✓ Example $EXAMPLE_NAME completed successfully" +done + +# Summary +echo "" +echo "===========================================" +echo " INSTALL SUMMARY" +echo "===========================================" +echo "" +echo "Mode: ${STD:-no-std}" +echo "Architecture: TA=$ARCH_TA, CA=$ARCH_CA" +echo "Examples: $CURRENT installed" +echo "Target dir: $SHARED_DIR" Review Comment: The variable SHARED_DIR is referenced but never defined. Based on the installation logic earlier in the script (lines 164-184), this should likely be one of TA_INSTALL_DIR, CA_INSTALL_DIR, or PLUGIN_INSTALL_DIR, or perhaps just removed from the summary output. ```suggestion echo "TA install dir: $TA_INSTALL_DIR" echo "CA install dir: $CA_INSTALL_DIR" echo "Plugin install dir: $PLUGIN_INSTALL_DIR" ``` ########## cargo-optee/aarch64-unknown-optee.json: ########## @@ -0,0 +1,21 @@ +{ + "arch": "aarch64", + "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", + "features": "+strict-align", + "dynamic-linking": false, + "executables": true, + "has-rpath": true, + "linker-flavor": "ld", + "linker-is-gnu": true, + "llvm-target": "aarch64-unknown-linux-gnu", + "max-atomic-width": 128, + "os": "optee", + "position-independent-executables": true, + "relro-level": "full", + "target-c-int-width": "32", + "target-endian": "little", + "target-pointer-width": "64", + "vendor": "unknown", + "panic-strategy": "abort" + } + Review Comment: The file ends with extra whitespace after the closing brace. This trailing whitespace should be removed for cleaner file formatting. ```suggestion } ``` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
