Port image-header and test executor to ast10x0-bundle
diff --git a/.bazelrc b/.bazelrc index bf0267e..45cc761 100644 --- a/.bazelrc +++ b/.bazelrc
@@ -58,6 +58,7 @@ # AST1060-EVB physical board (no QEMU, flash directly) common:k_ast1060_evb --config=k_common common:k_ast1060_evb --platforms=//target/ast10x0 +common:k_ast1060_evb --//target/ast10x0:uart_boot_header=true # `bazel {build,test,run} --config=virt_ast10x0 //target/ast10x0/...` # launches the AST10x0 system images under QEMU's ast1030-evb machine
diff --git a/target/ast10x0/BUILD.bazel b/target/ast10x0/BUILD.bazel index 76aa365..bb7ccaf 100644 --- a/target/ast10x0/BUILD.bazel +++ b/target/ast10x0/BUILD.bazel
@@ -17,6 +17,11 @@ build_setting_default = False, ) +bool_flag( + name = "uart_boot_header", + build_setting_default = False, +) + config_setting( name = "qemu_enabled", flag_values = {":qemu": "true"},
diff --git a/target/ast10x0/console_backend.rs b/target/ast10x0/console_backend.rs index 5abf4db..121a3fb 100644 --- a/target/ast10x0/console_backend.rs +++ b/target/ast10x0/console_backend.rs
@@ -16,13 +16,13 @@ /// MMIO base address of UART5 on the AST10x0 SoC (AST1060 TRM §28, Table 28-1). const UART5_BASE: *const device::uart::RegisterBlock = 0x7e78_4000 as *const _; -// SAFETY: UART5_BASE is the UART5 MMIO base on AST10x0. This static is the -// sole owner of the peripheral; the SpinLock ensures exclusive access. -static UART: SpinLock<arch_arm_cortex_m::Arch, Usart> = - SpinLock::new(unsafe { Usart::new(UART5_BASE) }); +// Global console lock to serialize UART register access. +static UART_LOCK: SpinLock<arch_arm_cortex_m::Arch, ()> = SpinLock::new(()); #[unsafe(no_mangle)] pub fn console_backend_write_all(buf: &[u8]) -> Result<()> { - let mut uart = UART.lock(arch_arm_cortex_m::Arch); + let _lock = UART_LOCK.lock(arch_arm_cortex_m::Arch); + // UART is configured by ROM/bootloader before firmware starts. + let mut uart = unsafe { Usart::new_uninit(UART5_BASE) }; uart.write_all(buf).map_err(|_| Error::DataLoss) }
diff --git a/target/ast10x0/harness/uart_upload_test.bzl b/target/ast10x0/harness/uart_upload_test.bzl index aebf7ee..9f14ed0 100644 --- a/target/ast10x0/harness/uart_upload_test.bzl +++ b/target/ast10x0/harness/uart_upload_test.bzl
@@ -6,18 +6,82 @@ """ load( + "@bazel_skylib//rules:common_settings.bzl", + "BuildSettingInfo", +) + +load( "@pigweed//pw_kernel/tooling:system_image.bzl", "SystemImageInfo", ) +def _firmware_bin(ctx): + if SystemImageInfo in ctx.attr.image: + return ctx.attr.image[SystemImageInfo].bin + return ctx.file.image + +def _declare_uart_boot_image(ctx, firmware_bin, name): + output = ctx.actions.declare_file(name + ".bin") + ctx.actions.run_shell( + inputs = [firmware_bin], + outputs = [output], + arguments = [firmware_bin.path, output.path], + mnemonic = "Ast10x0UartBootImage", + command = """set -eu +input=\"$1\" +output=\"$2\" +size=$(wc -c < \"$input\") +aligned=$(( (size + 3) & ~3 )) + +emit_byte() { + printf '%b' "$(printf '\\%03o' \"$1\")" +} + +{ + emit_byte $((aligned & 255)) + emit_byte $(((aligned >> 8) & 255)) + emit_byte $(((aligned >> 16) & 255)) + emit_byte $(((aligned >> 24) & 255)) + cat \"$input\" + padding=$((aligned - size)) + if [ \"$padding\" -gt 0 ]; then + dd if=/dev/zero bs=1 count=\"$padding\" status=none + fi +} > \"$output\" +""", + ) + return output + +def _uart_boot_image_impl(ctx): + firmware_bin = _firmware_bin(ctx) + if ctx.attr._uart_boot_header[BuildSettingInfo].value: + output = _declare_uart_boot_image(ctx, firmware_bin, ctx.label.name) + else: + output = firmware_bin + return [ + DefaultInfo(files = depset([output])), + ] + +uart_boot_image = rule( + implementation = _uart_boot_image_impl, + attrs = { + "image": attr.label( + mandatory = True, + doc = "system_image or binary target to wrap with the AST10x0 UART boot header", + ), + "_uart_boot_header": attr.label( + default = "//target/ast10x0:uart_boot_header", + providers = [BuildSettingInfo], + ), + }, + doc = "Generate an AST10x0 UART boot image by prepending the 4-byte size header when enabled by config.", +) + def _uart_upload_test_impl(ctx): """Implementation of uart_upload_test rule.""" # Get the firmware binary - if SystemImageInfo in ctx.attr.image: - firmware_bin = ctx.attr.image[SystemImageInfo].bin - else: - firmware_bin = ctx.file.image + firmware_bin = _firmware_bin(ctx) # Create test script test_script = ctx.actions.declare_file(ctx.label.name + "_test.sh") @@ -147,7 +211,7 @@ doc = "Upload firmware only, skip test monitoring", ), "_uart_test_exec": attr.label( - default = "//target/ast1060-evb/harness:uart_test_exec.py", + default = "//target/ast10x0/harness:uart_test_exec.py", allow_single_file = [".py"], ), }, @@ -163,11 +227,21 @@ - SKIP_DEVICE_CHECK: Skip device existence check (for CI) Usage: - load("//target/ast1060-evb/harness:uart_upload_test.bzl", "uart_upload_test") + load( + "//target/ast10x0/harness:uart_upload_test.bzl", + "uart_boot_image", + "uart_upload_test", + ) + + # AST1030-EVB UART boot expects the 4-byte size header. + uart_boot_image( + name = "threads_uart", + image = ":threads", + ) uart_upload_test( name = "threads_uart_test", - image = ":threads_uart", # uart_boot_image target + image = ":threads_uart", test_timeout = 300, ) @@ -181,10 +255,7 @@ """Implementation of uart_upload rule (non-test, just upload).""" # Get the firmware binary - if SystemImageInfo in ctx.attr.image: - firmware_bin = ctx.attr.image[SystemImageInfo].bin - else: - firmware_bin = ctx.file.image + firmware_bin = _firmware_bin(ctx) # Create upload script upload_script = ctx.actions.declare_file(ctx.label.name + "_upload.sh") @@ -282,11 +353,11 @@ doc = "Skip GPIO operations", ), "_uart_test_exec": attr.label( - default = "//target/ast1060-evb/harness:uart_test_exec.py", + default = "//target/ast10x0/harness:uart_test_exec.py", allow_single_file = [".py"], ), }, - doc = """Upload firmware to AST1060 hardware via UART. + doc = """Upload firmware to AST10x0 hardware via UART. This is a non-test rule that just uploads firmware without monitoring.
diff --git a/target/ast10x0/peripherals/uart/mod.rs b/target/ast10x0/peripherals/uart/mod.rs index ba5f96d..cec8ab1 100644 --- a/target/ast10x0/peripherals/uart/mod.rs +++ b/target/ast10x0/peripherals/uart/mod.rs
@@ -3,8 +3,6 @@ use ast1060_pac as device; use bitflags::bitflags; -use core::cell::UnsafeCell; -use core::marker::PhantomData; use embedded_hal_nb::serial as serial_nb; use embedded_io::{Read, Write}; @@ -102,7 +100,6 @@ } pub struct Usart { usart: *const device::uart::RegisterBlock, - _not_sync: PhantomData<UnsafeCell<()>>, // makes Usart !Sync } impl embedded_io::ErrorType for Usart { @@ -245,6 +242,20 @@ } } + /// Create an uninitialized USART instance without writing to registers. + /// + /// This const function creates a Usart struct pointing to the register block + /// but does not perform any hardware initialization. Use this for static + /// initializers and call `new()` or follow with hardware initialization. + /// + /// # Safety + /// + /// - `usart` must be a valid, non-null pointer to the AST1060 UART register block. + /// - The pointed register block must remain valid for the lifetime of this `Usart`. + pub const unsafe fn new_uninit(usart: *const device::uart::RegisterBlock) -> Self { + Self { usart } + } + /// Create a new USART instance from a raw register-block pointer. /// /// Configures RX/TX FIFO, 8 byte RX trigger level, 1.5MBaud, 8n1, and @@ -259,7 +270,6 @@ pub unsafe fn new(usart: *const device::uart::RegisterBlock) -> Self { let this = Self { usart, - _not_sync: PhantomData, }; unsafe {
diff --git a/target/ast10x0/tests/BUILD.bazel b/target/ast10x0/tests/BUILD.bazel new file mode 100644 index 0000000..2831344 --- /dev/null +++ b/target/ast10x0/tests/BUILD.bazel
@@ -0,0 +1,4 @@ +# Licensed under the Apache-2.0 license +# SPDX-License-Identifier: Apache-2.0 + +package(default_visibility = ["//visibility:public"])
diff --git a/target/ast10x0/tests/interrupts/kernel/BUILD.bazel b/target/ast10x0/tests/interrupts/kernel/BUILD.bazel index e5f1ba4..2b3dd08 100644 --- a/target/ast10x0/tests/interrupts/kernel/BUILD.bazel +++ b/target/ast10x0/tests/interrupts/kernel/BUILD.bazel
@@ -7,6 +7,7 @@ load("@pigweed//pw_kernel/tooling/panic_detector:rust_binary_no_panics_test.bzl", "rust_binary_no_panics_test") load("@rules_rust//rust:defs.bzl", "rust_binary") load("//target/ast10x0:defs.bzl", "TARGET_COMPATIBLE_WITH") +load("//target/ast10x0/harness:uart_upload_test.bzl", "uart_boot_image", "uart_upload_test") system_image( name = "interrupts", @@ -17,6 +18,17 @@ userspace = False, ) +uart_boot_image( + name = "interrupts_uart_image", + image = ":interrupts", +) + +uart_upload_test( + name = "interrupts_uart_upload_test", + image = ":interrupts_uart_image", + test_timeout = 300, +) + system_image_test( name = "interrupts_test", image = ":interrupts",
diff --git a/target/ast10x0/tests/interrupts/user/BUILD.bazel b/target/ast10x0/tests/interrupts/user/BUILD.bazel index af34475..0517efb 100644 --- a/target/ast10x0/tests/interrupts/user/BUILD.bazel +++ b/target/ast10x0/tests/interrupts/user/BUILD.bazel
@@ -7,6 +7,7 @@ load("@pigweed//pw_kernel/tooling/panic_detector:rust_binary_no_panics_test.bzl", "rust_binary_no_panics_test") load("@rules_rust//rust:defs.bzl", "rust_binary") load("//target/ast10x0:defs.bzl", "TARGET_COMPATIBLE_WITH") +load("//target/ast10x0/harness:uart_upload_test.bzl", "uart_boot_image", "uart_upload_test") system_image( name = "interrupts", @@ -20,6 +21,17 @@ tags = ["kernel"], ) +uart_boot_image( + name = "interrupts_uart_image", + image = ":interrupts", +) + +uart_upload_test( + name = "interrupts_uart_upload_test", + image = ":interrupts_uart_image", + test_timeout = 300, +) + system_image_test( name = "interrupts_test", image = ":interrupts",
diff --git a/target/ast10x0/tests/ipc/user/BUILD.bazel b/target/ast10x0/tests/ipc/user/BUILD.bazel index fc1c562..6aac1fd 100644 --- a/target/ast10x0/tests/ipc/user/BUILD.bazel +++ b/target/ast10x0/tests/ipc/user/BUILD.bazel
@@ -7,6 +7,7 @@ load("@pigweed//pw_kernel/tooling/panic_detector:rust_binary_no_panics_test.bzl", "rust_binary_no_panics_test") load("@rules_rust//rust:defs.bzl", "rust_binary") load("//target/ast10x0:defs.bzl", "TARGET_COMPATIBLE_WITH") +load("//target/ast10x0/harness:uart_upload_test.bzl", "uart_boot_image", "uart_upload_test") system_image( name = "ipc", @@ -18,6 +19,17 @@ target_compatible_with = TARGET_COMPATIBLE_WITH, ) +uart_boot_image( + name = "ipc_uart_image", + image = ":ipc", +) + +uart_upload_test( + name = "ipc_uart_upload_test", + image = ":ipc_uart_image", + test_timeout = 300, +) + system_image_test( name = "ipc_test", image = ":ipc",
diff --git a/target/ast10x0/tests/threads/BUILD.bazel b/target/ast10x0/tests/threads/BUILD.bazel new file mode 100644 index 0000000..2831344 --- /dev/null +++ b/target/ast10x0/tests/threads/BUILD.bazel
@@ -0,0 +1,4 @@ +# Licensed under the Apache-2.0 license +# SPDX-License-Identifier: Apache-2.0 + +package(default_visibility = ["//visibility:public"])
diff --git a/target/ast10x0/tests/threads/kernel/BUILD.bazel b/target/ast10x0/tests/threads/kernel/BUILD.bazel index 63ffd23..4504994 100644 --- a/target/ast10x0/tests/threads/kernel/BUILD.bazel +++ b/target/ast10x0/tests/threads/kernel/BUILD.bazel
@@ -6,6 +6,7 @@ load("@pigweed//pw_kernel/tooling/panic_detector:rust_binary_no_panics_test.bzl", "rust_binary_no_panics_test") load("@rules_rust//rust:defs.bzl", "rust_binary") load("//target/ast10x0:defs.bzl", "TARGET_COMPATIBLE_WITH") +load("//target/ast10x0/harness:uart_upload_test.bzl", "uart_boot_image", "uart_upload_test") system_image( name = "threads", @@ -22,6 +23,17 @@ target_compatible_with = TARGET_COMPATIBLE_WITH, ) +uart_boot_image( + name = "threads_uart_image", + image = ":threads", +) + +uart_upload_test( + name = "threads_uart_upload_test", + image = ":threads_uart_image", + test_timeout = 300, +) + rust_binary_no_panics_test( name = "no_panics_test", binary = ":threads",
diff --git a/target/ast10x0/tests/usart/BUILD.bazel b/target/ast10x0/tests/usart/BUILD.bazel index 7ab85fd..20ab68e 100644 --- a/target/ast10x0/tests/usart/BUILD.bazel +++ b/target/ast10x0/tests/usart/BUILD.bazel
@@ -8,6 +8,7 @@ load("@pigweed//pw_kernel/tooling/panic_detector:rust_binary_no_panics_test.bzl", "rust_binary_no_panics_test") load("@rules_rust//rust:defs.bzl", "rust_binary") load("//target/ast10x0:defs.bzl", "TARGET_COMPATIBLE_WITH") +load("//target/ast10x0/harness:uart_upload_test.bzl", "uart_boot_image", "uart_upload_test") filegroup( name = "system_config", @@ -110,6 +111,17 @@ visibility = ["//visibility:public"], ) +uart_boot_image( + name = "usart_uart_image", + image = ":usart", +) + +uart_upload_test( + name = "usart_uart_upload_test", + image = ":usart_uart_image", + test_timeout = 300, +) + system_image_test( name = "usart_test", image = ":usart",