This document explains the out-of-tree Pigweed kernel targets for AST1060.
There are two AST1060 targets in this workspace:
| Target | Purpose | Console | Use Case |
|---|---|---|---|
ast1060 | QEMU emulation | Semihosting | Development, CI testing |
ast1060-evb | Physical hardware | UART | Real board testing |
bazel-stuff/ ├── target/ │ ├── ast1060/ # QEMU target │ │ ├── BUILD.bazel # Platform + rust_library targets │ │ ├── defs.bzl # TARGET_COMPATIBLE_WITH constraint │ │ ├── config.rs # KernelConfig (SysTick, MPU regions) │ │ ├── entry.rs # Reset handler + boot sequence │ │ ├── target.ld.tmpl # Linker script template │ │ └── threads/kernel/ # Threads test application │ │ ├── BUILD.bazel │ │ ├── system.json5 # Memory layout │ │ └── target.rs # Application entry point │ │ │ └── ast1060-evb/ # Physical board target │ ├── BUILD.bazel │ ├── defs.bzl │ ├── config.rs │ ├── entry.rs # Initializes UART before kernel │ ├── console_backend.rs # UART driver via aspeed-ddk │ ├── target.ld.tmpl │ └── threads/kernel/ │ ├── BUILD.bazel │ ├── system.json5 │ └── target.rs
BUILD.bazel)Each target defines a Bazel platform with CPU and OS constraints:
platform( name = "ast1060", constraint_values = [ "@platforms//cpu:armv7-m", "@platforms//os:none", "@pigweed//pw_kernel:os_freestanding", "//platform:ast1060", # Custom constraint ], )
The platform tells Bazel which toolchain to use (ARM Cortex-M cross-compiler).
config.rs)Provides hardware-specific settings to the kernel:
impl KernelConfig for Config { const SYSTICK_HZ: u32 = 12_000_000; // 12 MHz clock const ARM_V7_MPU_REGIONS: usize = 8; // MPU region count }
entry.rs)The reset handler that runs at power-on:
#[cortex_m_rt::entry] fn main() -> ! { // For ast1060-evb: Initialize UART here uart_init(); // Jump to kernel target target_common::enter_kernel_main() }
QEMU (ast1060): Uses ARM semihosting - debug output goes through QEMU to host terminal.
Physical Board (ast1060-evb): Uses UART via aspeed-ddk driver:
// console_backend.rs static UART: Mutex<RefCell<Option<Uart>>> = ...; pub fn uart_write(data: &[u8]) { critical_section::with(|cs| { if let Some(ref mut uart) = *UART.borrow_ref_mut(cs) { for byte in data { uart.write_byte(*byte); } } }); }
system.json5)Defines memory regions for the linker:
{ memory: { vector_table: { start: 0x00000000, size: 0x400 }, flash: { start: 0x00000400, size: 0x000ffc00 }, ram: { start: 0x80000000, size: 0x00100000 }, } }
target.ld.tmpl)Template processed by Bazel to generate final linker script with memory addresses from system.json5.
# Build bazelisk build //target/ast1060/threads/kernel:threads --config=k_qemu_ast1060 # Run in QEMU bazelisk run //target/ast1060/threads/kernel:threads --config=k_qemu_ast1060
# Build bazelisk build //target/ast1060-evb/threads/kernel:threads --config=k_ast1060_evb # The output binary is at: # bazel-bin/target/ast1060-evb/threads/kernel/threads.bin
| File | Header | Use Case |
|---|---|---|
threads.bin | No | OpenOCD/JTAG flashing, direct memory load |
threads_uart.bin | Yes (4-byte size) | UART bootloader upload |
The AST1060 UART bootloader requires a special header format:
This is automated via the uart_boot_image Bazel rule:
# Build the UART-bootable image bazelisk build //target/ast1060-evb/threads/kernel:threads_uart --config=k_ast1060_evb # Output file: # bazel-bin/target/ast1060-evb/threads/kernel/threads_uart.bin
The rule is defined in //target:uart_boot_image.bzl and used in BUILD.bazel:
load("//target:uart_boot_image.bzl", "uart_boot_image") uart_boot_image( name = "threads_uart", src = ":threads", # system_image target out = "threads_uart.bin", )
After building the ast1060-evb target:
# Using the UART boot image (with header) # Upload via serial bootloader tool uart_upload /dev/ttyUSB0 bazel-bin/target/ast1060-evb/threads/kernel/threads_uart.bin # Or using OpenOCD with raw binary (no header needed) openocd -f interface/cmsis-dap.cfg -f target/aspeed_ast1060.cfg \ -c "program bazel-bin/target/ast1060-evb/threads/kernel/threads.bin verify reset exit"
Connect to the AST1060-EVB serial port:
# Find the USB-UART device ls /dev/ttyUSB* # Connect at 115200 baud screen /dev/ttyUSB2 115200 # or picocom -b 115200 /dev/ttyUSB2
Expected output:
Hello from AST1060-EVB! === pw_kernel === ...
| Crate | Purpose |
|---|---|
@ast1060_pac | AST1060 Peripheral Access Crate (register definitions) |
aspeed-ddk | ASPEED device driver kit (UART driver) |
cortex-m-rt | Cortex-M runtime (reset handler, vector table) |
cortex-m-semihosting | ARM semihosting support |
.bazelrc Configs# QEMU config common:k_qemu_ast1060 --config=k_common common:k_qemu_ast1060 --platforms=//target/ast1060 run:k_qemu_ast1060 --run_under="@pigweed//pw_kernel/tooling:qemu ..." # Physical board config common:k_ast1060_evb --config=k_common common:k_ast1060_evb --platforms=//target/ast1060-evb
MODULE.bazel DependenciesThe AST1060 PAC is fetched via git:
ast1060_pac = use_extension("//third_party:ast1060_pac.bzl", "ast1060_pac") use_repo(ast1060_pac, "ast1060_pac")
| Aspect | ast1060 (QEMU) | ast1060-evb (Physical) |
|---|---|---|
| Console | Semihosting | UART @ 115200 |
| Exit | semihosting::exit() | Loop or reset |
| Clock | Emulated | Real 12 MHz |
| Debug | GDB via QEMU | JTAG/SWD |
| Build config | k_qemu_ast1060 | k_ast1060_evb |
“No matching toolchains found”
--platforms=//target/ast1060 is specified“unresolved import ast1060_pac”
cargo generate-lockfile in third_party/crates_io/Cargo.toml has the ast1060-pac dependencyNo UART output on physical board
QEMU hangs
cortex-m4 for ast1030-evb machine)