Skip to main content

Command Palette

Search for a command to run...

Yocto blueprint

Updated
β€’14 min read
Yocto blueprint

Just some helpers/notes to start a new project with some passionate opinions.

Here's the complete setup process:

Step 1: Initial Repository Setup

mkdir meta-forte && cd meta-forte && git init -b main

Step 2: Create Directory Structure

mkdir -p layers/meta-forte/conf/{machine,distro} && mkdir -p layers/meta-forte/recipes-{kernel/linux,security/optee,core/images,apps/hello-trustzone} && mkdir -p kas docs scripts

You can check using tree command:

πŸ“¦[aviler@yocto-box meta-forte]$ tree
.
β”œβ”€β”€ docs
β”œβ”€β”€ kas
β”œβ”€β”€ layers
β”‚   └── meta-forte
β”‚       β”œβ”€β”€ conf
β”‚       β”‚   β”œβ”€β”€ distro
β”‚       β”‚   └── machine
β”‚       β”œβ”€β”€ recipes-apps
β”‚       β”‚   └── hello-trustzone
β”‚       β”œβ”€β”€ recipes-core
β”‚       β”‚   └── images
β”‚       β”œβ”€β”€ recipes-kernel
β”‚       β”‚   └── linux
β”‚       └── recipes-security
β”‚           └── optee
└── scripts

16 directories, 0 files

Step 3: Create .gitignore

cat > .gitignore << 'EOF'
# Kas artifacts
sources/

# Build outputs
build/
downloads/
sstate-cache/
tmp/

# Editor files
*.swp
*~
.vscode/
.idea/

# Python
__pycache__/
*.pyc
EOF

Step 4: Create Main kas.yml

cat > kas.yml << 'EOF'
header:
  version: 14

machine: beagley-ai
distro: forte-distro

repos:
  poky:
    url: https://git.yoctoproject.org/git/poky
    branch: scarthgap
    layers:
      meta:
      meta-poky:

  meta-openembedded:
    url: git@github.com:openembedded/meta-openembedded.git
    branch: scarthgap
    layers:
      meta-oe:
      meta-python:
      meta-networking:

  meta-arm:
    url: https://git.yoctoproject.org/git/meta-arm
    branch: scarthgap
    layers:
      meta-arm:
      meta-arm-toolchain:

  meta-ti:
    url: git@github.com:TexasInstruments/meta-ti.git
    branch: scarthgap
    layers:
      meta-ti-bsp:
      meta-ti-extras:

  meta-forte:
    path: layers/meta-forte

bblayers_conf_header:
  forte: |
    # Forte BeagleY-AI TrustZone Build Configuration
    BBMASK += ""

local_conf_header:
  forte: |
    # Build optimizations
    BB_NUMBER_THREADS = "8"
    PARALLEL_MAKE = "-j 8"

    # Package management
    PACKAGE_CLASSES = "package_ipk"

    # Base features
    EXTRA_IMAGE_FEATURES += "ssh-server-openssh tools-debug"

    # TrustZone/OP-TEE support (CORREÇÃO: hardware-specific)
    MACHINE_FEATURES += "optee"
    PREFERRED_PROVIDER_virtual/crypt = "optee-os"
    ARM_TF_FLAGS += "TRUSTED_BOARD_BOOT=1"

    # TI AM62x specific
    MACHINE_ESSENTIAL_EXTRA_RDEPENDS += "ti-sci-fw"

target:
  - forte-image
EOF
Updates on the kas.yml
The key refspec was deprecated so replaced with branch to avoid warning messages. Removed deprecated meta-beagle layer. Update github URLS to fix authenticate issues with HTTPS.

Step 5: Create Kas Variants

cat > kas/dev.yml << 'EOF'
header:
  version: 14
  includes:
    - ../kas.yml

local_conf_header:
  dev: |
    # Development build settings
    EXTRA_IMAGE_FEATURES += "debug-tweaks tools-sdk tools-debug"

    # Enable core dumps and debug symbols
    IMAGE_FEATURES += "dbg-pkgs dev-pkgs"

    # Keep debug info
    INHIBIT_PACKAGE_STRIP = "1"

    # Serial console access
    SERIAL_CONSOLES = "115200;ttyS0"
EOF
cat > kas/prod.yml << 'EOF'
header:
  version: 14
  includes:
    - ../kas.yml

local_conf_header:
  prod: |
    # Production build settings
    EXTRA_IMAGE_FEATURES:remove = "debug-tweaks"

    # Size optimization
    IMAGE_FEATURES += "read-only-rootfs"

    # Strip debug symbols
    INHIBIT_PACKAGE_DEBUG_SPLIT = "1"

    # Security hardening
    EXTRA_IMAGE_FEATURES += "secure-core-image"
EOF
cat > kas/sdk.yml << 'EOF'
header:
  version: 14
  includes:
    - ../kas.yml

target:
  - forte-image
  - meta-toolchain
EOF

Step 6: Create Layer Configuration

cat > layers/meta-forte/conf/layer.conf << 'EOF'
# We have a conf and classes directory, add to BBPATH
BBPATH .= ":${LAYERDIR}"

# We have recipes-* directories, add to BBFILES
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
            ${LAYERDIR}/recipes-*/*/*.bbappend"

BBFILE_COLLECTIONS += "meta-forte"
BBFILE_PATTERN_meta-forte = "^${LAYERDIR}/"
BBFILE_PRIORITY_meta-forte = "10"

# CORREÇÃO ESSENCIAL: dependΓͺncias explΓ­citas
LAYERDEPENDS_meta-forte = "poky meta-arm meta-ti meta-beagle meta-openembedded"
LAYERSERIES_COMPAT_meta-forte = "scarthgap"
EOF

Step 7: Create Distro Configuration

cat > layers/meta-forte/conf/distro/forte-distro.conf << 'EOF'
require conf/distro/poky.conf

DISTRO = "forte-distro"
DISTRO_NAME = "Forte Linux (Yocto Project based Distro)"
DISTRO_VERSION = "1.0"
DISTRO_CODENAME = "scarthgap"

MAINTAINER = "Oliver M. Batista <code.monitor759@aleeas.com>"

# TrustZone/OP-TEE support
DISTRO_FEATURES:append = " optee"

# TI-specific optimizations
DISTRO_FEATURES:append = " sgx"  # GPU acceleration
DISTRO_FEATURES:append = " virtualization" # KVM support

# TI SDK compatibility
PREFERRED_PROVIDER_virtual/mesa = "mesa-pvr"
PREFERRED_PROVIDER_virtual/libgles1 = "ti-sgx-ddk-um"
PREFERRED_PROVIDER_virtual/libgles2 = "ti-sgx-ddk-um"
PREFERRED_PROVIDER_virtual/egl = "ti-sgx-ddk-um"

# Systemd preferred
VIRTUAL-RUNTIME_init_manager = "systemd"
EOF

Step 7.5: Create machine configuration

cat > layers/meta-forte/conf/machine/beagley-ai.conf << 'EOF'
# @NAME: BeagleY-AI Machine Configuration
include conf/machine/include/ti-am62x.inc

MACHINE = "beagley-ai"
MACHINE_FEATURES += "screen gpu wifi bluetooth cryptoprocessor"

# Firmware requirements
MACHINE_ESSENTIAL_EXTRA_RDEPENDS += " \
    trustzone-standalonefw \
    optee-os-ti \
"

# Device tree and kernel config
KERNEL_DEVICETREE = "ti/k3-am625-beagley-a1.dtb"
UBOOT_MACHINE = "am62x_evm_a53_defconfig"

# TrustZone specific
OPTEE_PLATFORM = "k3-am62x"
OPTEE_EXTRA_BUILDARGS = "PLATFORM=ti-k3"
EOF

Step 8: Create Minimal Image Recipe

cat > layers/meta-forte/recipes-core/images/forte-image.bb << 'EOF'
SUMMARY = "Forte minimal image with TrustZone support"
LICENSE = "MIT"

inherit core-image

# Base image features
IMAGE_INSTALL:append = " \
    kernel-modules \
    openssh \
    optee-os-ti \                 # TI-specific
    optee-client \
    optee-test \
    ti-sgx-ddk-um \               # GPU drivers
    trustzone-standalonefw \      # TrustZone
    ti-sci-fw \                   # Firmware management
"

# Security packages
IMAGE_INSTALL:append = " \
    packagegroup-security-optee \
    tpm2-tools \
    swtpm \
"

# Root filesystem extra space (MB)
IMAGE_ROOTFS_EXTRA_SPACE = "500"

# Image types (WB: Beagle-specific)
IMAGE_FSTYPES = "wic wic.bmap tar.xz"
WKS_FILE = "beaglebone-yocto.wks"
EOF

Step 9: Create Layer README

cat > layers/meta-forte/README.md << 'EOF'
# meta-forte Layer

Custom Yocto layer for BeagleY-AI with TrustZone/OP-TEE support.

## Layer Dependencies
- meta (poky)
- meta-arm
- meta-ti
- meta-beagle
- meta-oe (meta-openembedded)

## Recipes
- **recipes-core/images**: Custom image definitions
- **recipes-kernel/linux**: Kernel patches and configurations
- **recipes-security/optee**: OP-TEE trusted applications
- **recipes-apps**: Example applications

## Distro
- **forte-distro**: Custom distribution with TrustZone support

## Machine
- **beagley-ai**: BeagleY-AI board configuration (uses meta-beagle defaults)

## Verification Commands
```bash
bitbake-layers show-layers | grep "meta-forte"
bitbake-layers show-recipes "optee-*"
```

## Secure Boot Flow (need to verify)
- ARM TF-A (BL1/BL2) in secure world
- OP-TEE OS initializes secure partitions
- U-Boot (BL33 in non-secure world)
- Linux kernel with OP-TEE drivers
EOF

Step 10: Create Main README

cat > README.md << 'EOF'
# BeagleY-AI TrustZone Yocto Study Project

Study project demonstrating a custom Yocto build for BeagleY-AI with 
TrustZone/OP-TEE integration using modern, scalable practices.

## 🎯 Objectives
- Learn Yocto with professional approach
- Custom build for BeagleY-AI (TI AM62x)
- TrustZone/OP-TEE security integration
- Kas integration for reproducibility
- Document complete process

## πŸš€ Quick Start

### Prerequisites
```bash
# Install Kas
pip3 install kas

# Install dependencies (Ubuntu/Debian)
sudo apt-get install gawk wget git diffstat unzip texinfo \
  gcc build-essential chrpath socat cpio python3 python3-pip \
  python3-pexpect xz-utils debianutils iputils-ping python3-git \
  python3-jinja2 libegl1-mesa libsdl1.2-dev pylint xterm \
  python3-subunit mesa-common-dev zstd liblz4-tool
```

### Build Commands
```bash
# Clone repository
git clone https://github.com/aviler/meta-forte.git
cd meta-forte

# Development build
kas build kas.yml:kas/dev.yml

# Production build
kas build kas.yml:kas/prod.yml

# Generate SDK
kas build kas.yml:kas/sdk.yml
```

### Flash to SD Card
```bash
# Find your SD card device (e.g., /dev/sdX)
lsblk

# Flash image (replace sdX with your device)
sudo dd if=build/tmp/deploy/images/beagley-ai/forte-image-beagley-ai.wic \
        of=/dev/sdX bs=4M status=progress && sync
```

## πŸ—οΈ Architecture

### Layer Stack
```
meta-forte (custom)
    ↓
meta-beagle (BeagleBoard configs)
    ↓
meta-ti (TI AM62x BSP)
    ↓
meta-arm (ARM architecture + TrustZone)
    ↓
meta-openembedded (additional recipes)
    ↓
poky (base Yocto)
```

### Key Technologies
- **Yocto Project**: Embedded Linux build system
- **Kas**: Declarative build configuration
- **OP-TEE**: Trusted Execution Environment
- **TI AM62x**: ARM Cortex-A53 + Cortex-M4F processor
- **BeagleY-AI**: Development board

## πŸ“š Documentation
- [Setup Guide](docs/01-setup.md) - Initial environment setup
- [Build Process](docs/02-build-process.md) - Understanding the build
- [TrustZone Integration](docs/03-trustzone-integration.md) - OP-TEE setup

## πŸ“ Key Learnings
- Modern Kas approach vs traditional git submodules
- Custom layer structuring and dependencies
- BSP integration for TI AM62x platform
- TrustZone/OP-TEE security architecture
- Build variant management (dev/prod/sdk)
- Reproducible build environments

## πŸ‘€ Author
Oliver M. Batista - [Blog](https://olivermbatista.com) - [LinkedIn](https://www.linkedin.com/in/oliver-batista/)
EOF

Step 12: Create Helper Scripts

cat > scripts/setup.sh << 'EOF'
#!/bin/bash
# Quick setup script

echo "Installing Kas..."
pip3 install --user kas

echo "Checking dependencies..."
kas --version

echo "Setup complete! Run 'kas build kas.yml:kas/dev.yml' to build"
EOF
chmod +x scripts/setup.sh
cat > scripts/flash-image.sh << 'EOF'
#!/bin/bash
# Flash image to SD card

if [ -z "$1" ]; then
    echo "Usage: $0 /dev/sdX"
    echo "Available devices:"
    lsblk -d -o NAME,SIZE,TYPE | grep disk
    exit 1
fi

IMAGE="build/tmp/deploy/images/beagley-ai/forte-image-beagley-ai.wic"

if [ ! -f "$IMAGE" ]; then
    echo "Error: Image not found at $IMAGE"
    echo "Run a build first: kas build kas.yml:kas/dev.yml"
    exit 1
fi

echo "Flashing $IMAGE to $1..."
sudo dd if=$IMAGE of=$1 bs=4M status=progress && sync
echo "Done!"
EOF
chmod +x scripts/flash-image.sh

Step 13: Initial Git Commit

git add . && git commit -m "Initial project structure with Kas configuration"

Had to branch out another article because I tried the command above on a super fresh new machine missing some git configuration, check it here Git inside Distrobox.

Step 14: Verify Structure

tree -L 3 -a

Step 15: Install and check Kas Configuration

Oh snap, forgot to install kas:

pip3 install kas
Update
The comand below would initialy bring some issues with repository addresses declared on the kas.yml file I already update file contents above. I’ll leave a image here that show the issue. Added meta-beagle layer to meta-ti.
kas dump kas.yml

We should see that everything went good and in the end of the log kas just rewrites the kas.yml file.

What Kas Will Populate

When you run kas build kas.yml, Kas will automatically:

  1. Clone all repositories into sources/:

    • poky

    • meta-arm

    • meta-ti

    • meta-openembedded

  2. Create build directory with:

    • build/conf/local.conf (from your kas.yml config)

    • build/conf/bblayers.conf (from layer definitions)

    • build/tmp/ (build artifacts)

  3. Download sources into downloads/

  4. Create sstate cache in sstate-cache/

Final Structure After First Build

meta-forte/
β”œβ”€β”€ layers/meta-forte/        (you created)
β”œβ”€β”€ kas.yml                    (you created)
β”œβ”€β”€ kas/                       (you created)
β”œβ”€β”€ docs/                      (you created)
β”œβ”€β”€ scripts/                   (you created)
β”œβ”€β”€ sources/                   (Kas clones this)
β”œβ”€β”€ build/                     (Kas creates this)
β”œβ”€β”€ downloads/                 (Kas creates this)
└── sstate-cache/             (Kas creates this)

Summary of Manual vs Automated

You create manually (Steps 1-13):

  • Directory structure

  • Configuration files (kas.yml, layer.conf, etc.)

  • Your custom recipes

  • Documentation

  • Helper scripts

Kas creates automatically (when you run kas build):

  • sources/ - All dependency layers

  • build/ - Build configuration and outputs

  • downloads/ - Source tarballs

  • sstate-cache/ - Shared state cache

This gives you a production-ready project structure that's fully reproducible! πŸš€


Follow up from steps above

Just created all the files required and run it kas dump kas.yml with success. I mean with still some small issues that I recorded above. Let’s try to build now.

The building attempts have resulted in the errors below

This is a summary of the recent BitBake errors encountered and the corresponding fixes:

Error #DescriptionRoot CauseResolution
1 (ParseError)BitBake failed to parse forte-distro.conf.An inline comment (# GPU acceleration) was placed on the same line as a variable assignment (DISTRO_FEATURES:append = ...). BitBake requires comments to be on separate lines.The comment was moved or removed from the assignment line.
2 (Host Tool Missing)BitBake failed to start due to missing system tools.The essential host utility file (specified by HOSTTOOLS) was not found in the host system's $PATH.The file utility package was installed on the host operating system.
3 (Layer Dependency)meta-forte reported dependency errors (e.g., "depends on layer 'poky', but this layer is not enabled").The layers were enabled in bblayers.conf, but the local layer (meta-forte/conf/layer.conf) used the wrong dependency names (full repository names like poky or meta-ti).The dependency definition (LAYERDEPENDS_meta-forte) was corrected to use the required short collection names (e.g., core, meta-oe, ti-bsp) found in each sublayer's conf/layer.conf.

Let’s try again

Ok, oh by the way, today we are searching with Deepseek R1T2 Chimera. The errors were about dependencies declared in meta-forte/conf/layer.conf but missing from the kas config.

Ok had a new error because I was adding yocto to the key/value below from meta-forte/conf/layer.conf

LAYERDEPENDS_meta-forte = "yocto core meta-ti-extras meta-ti-bsp meta-beagle meta-python openembedded-layer networking-layer arm-toolchain meta-arm"

Thing is that we are creating a custom meta-layer and in this sense yocto in LAYERDEPENDS_ is wrong. The meta-poky is a reference/example layer, it can’t be used as dependency for other custom layers like how we are creating meta-forte to be. We don’t need meta-poky as dependency for meta-forte layer but we still need to declare it in the kas.yml file so we use some base configurations in our distro. We define a distro ourselves atmeta-forte/layers/meta-forte/conf/distro/forte-distro.conf.

Well the error message changed:

After researching I have a guess that this might be related with my attempt to create a custom machine to wrapper the official one. Made some mistakes in the file meta-forte/conf/machine/beagley-ai.conf and will try to make the changes below and try again.

require conf/machine/beagley-ai.conf

# @NAME: BeagleY-AI Machine Configuration

# No need to define we get it from the requite in the top of this file
#MACHINE = "beagley-ai"
MACHINE_FEATURES += "screen gpu wifi bluetooth cryptoprocessor"

# Rest of the file remains how it was

New error during build

And also some weird behaviour from this blog editor from hashnode.com πŸ˜’ I guess I need to go back to old habits like typing CTRL+S every 3-5 words. So I am facing this bundle of warnings ending in as error and it’s all related.

Is a Python RecursionError generated by this endless loop of self include in the layers/meta-forte/conf/machine/beagley-ai.conf we let it happen. The file requires a beagly-ai.conf. Then bitbake go search this file. It finds the same but includes anyways, repeting until it reaches its limit. So I removed the β€œself” inclusion, added two new require entries and did some cleaning compared to the original.

# layers/meta-forte/conf/machine/beagley-ai.conf

# Get the base for BeagleY-AI (SoC J722S)
require conf/machine/include/j722s.inc
require conf/machine/include/beagle-bsp.inc

# Add desired features
MACHINE_FEATURES += "screen gpu wifi bluetooth cryptoprocessor"

# Add firmware dependency for TrustZone/OP-TEE
MACHINE_ESSENTIAL_EXTRA_RDEPENDS += " \
    trustzone-standalonefw \
    optee-os-ti \
"

# TrustZone specific
# Still need to check if these values are correct
OPTEE_PLATFORM = "k3-am62x"
OPTEE_EXTRA_BUILDARGS = "PLATFORM=ti-k3"

And it worked because at least the layer resolution got solved by bitbake and now I see some sort of parsing issue.

ERROR: /var/home/aviler/Code/meta-forte/build/../poky/meta/recipes-core/packagegroups/packagegroup-rust-cross-canadian.bb: Please ensure that your setting of VIRTUAL-RUNTIME_init_manager (systemd) matches the entries enabled in DISTRO_FEATURES
ERROR: /var/home/aviler/Code/meta-forte/build/../poky/meta/recipes-core/packagegroups/packagegroup-core-ssh-dropbear.bb: Please ensure that your setting of VIRTUAL-RUNTIME_init_manager (systemd) matches the entries enabled in DISTRO_FEATURES

Summary: There were 58 ERROR messages, returning a non-zero exit code.
2025-11-09 21:58:34 - ERROR    - Command "/var/home/aviler/Code/meta-forte/poky/bitbake/bin/bitbake -c build forte-image" failed with error 1
πŸ“¦[aviler@yocto-box meta-forte]$

The amazing thing about Yocto is that you not only need many files but you also need to be consistent in between configuration files. So, I wanted to have systemd so I added the key VIRTUAL-RUNTIME_init_manager = "systemd", but for this to work, I also need to explicitly ask for the feature with DISTRO_FEATURES:append = " systemd". And, that solves. Ok! Next error πŸ˜‚

And I fall again for the misplaced # comment in files:

ERROR: ParseError at .../forte-image.bb:10: unparsed line: 'IMAGE_INSTALL:append = " ... optee-os-ti \ # TI-specific'

Just went to forte-image.bb file and removed the comments written in the end of the line. I can say it worked because my laptop fans are going crazy parsing the recipes here. All recipes parsed but still other errors, let’s fix it!

And we are back at it

The above error list is about a missing UBOOT_MACHINE declaration. I thought the previously added dependencies would define it, but I was wrong.

Still don’t get why we can’t just β€œinclude” this file and accept whatever it says and on our custom layer we just declare things that we would like to override. So, I added the UBOOT_MACHINE config and that fix it.

The optee things are not on the meta-ti layer but in the meta-arm one. Will update package name from optee-os-ti to optee-os at the files forte-image.bb and in our custom machine definition beagley-ai.conf.

Ok, so my first draft for this project was based on beaglebone-black examples which of course would not work with beagley-ai. I am removing references of ti-sgx-ddk-um and other graphics related. Hopefully, a correct configuration will be finded by bitbake if not is ok since I don’t need any graphics related stuff for now.

Another wrong package name, replacing trustzone-standalonefw with arm-trusted-firmware. It didn’t work, same error but now about arm-trusted-firmware.

Removed more clutter like below. Beagley-ai has no TPM components so I got a bulding error about the tpm2-tools package/feature so I just removed the whole section below:

# Security packages
IMAGE_INSTALL:append = " \
    tpm2-tools \
    swtpm \
"

After some more tries

I had to solve more issues with outdated package names, removing features completely because my board can’t support TPM πŸ˜…, and other details. The building process seems to be happening.

So yeah, this is the real deal. And it is even slowing me down while typing this paragraph. The laptop fans are singing the song of their people.

πŸ€–
BEGIN AI Summary

When you see BitBake starting to execute tasks like this, it means:

  1. All configurations are valid.

  2. All layers are correctly loaded.

  3. All dependencies have been successfully resolved.

  4. BitBake now has a complete, valid plan to build your entire Linux distribution from source.

What's Happening Now?

You are now in the actual build phase. BitBake is executing tasks in order for hundreds of packages. You'll see it go through stages for each package:

  • do_fetch (downloading source code)

  • do_unpack

  • do_patch

  • do_configure

  • do_compile (This is the long part)

  • do_install

  • do_package

A Word of Warning: The very first build from scratch is a marathon. Depending on your machine's CPU, RAM, and internet speed, this will take a long timeβ€”anywhere from an hour to several hours.

πŸ€–
END AI Summary

Conclusion?

This article started as just notes to draft a blueprint for a YOCTO project. It started with too big goals, maybe, but here we are. Great learning challenge so far. But now it is making me suffer by making it impossible to use this laptop. I need to buy β€œserver”… yeah this distrobox should be a VPS on someone else's computer. It would be a good topic for a follow-up article.