diff --git a/.bazelrc b/.bazelrc index dd92fd3..669c58a 100644 --- a/.bazelrc +++ b/.bazelrc @@ -83,4 +83,20 @@ test:virt_ast10x0 --run_under="//target/ast10x0/harness:qemu_runner \ # Mirrors k_common's test_tag_filters and adds -hardware (physical-board-only tests). # Combined into one flag to avoid the Bazel 'expanded from multiple configs' warning # that fires when --test_tag_filters is set by both k_common and this config. -test:virt_ast10x0 --test_tag_filters=-integration,-do_not_build,-do_not_run_test,-kernel_doc_test,-hardware \ No newline at end of file +test:virt_ast10x0 --test_tag_filters=-integration,-do_not_build,-do_not_run_test,-kernel_doc_test,-hardware + +# Stress test configs — same platform/build flags as the base configs but with +# --timeout 0 in --run_under so the runner blocks indefinitely until FAIL. +common:stress_virt_ast10x0 --platforms=//target/ast10x0 +common:stress_virt_ast10x0 --//target/ast10x0:qemu=true +build:stress_virt_ast10x0 --build_tag_filters=-do_not_build,-kernel_doc_test +run:stress_virt_ast10x0 --run_under="//target/ast10x0/harness:qemu_runner \ + --timeout 0 --cpu cortex-m4 --machine ast1030-evb --image " +test:stress_virt_ast10x0 --run_under="//target/ast10x0/harness:qemu_runner \ + --timeout 0 --cpu cortex-m4 --machine ast1030-evb --image " +common:stress_k_ast1060_evb --platforms=//target/ast10x0 +build:stress_k_ast1060_evb --build_tag_filters=-do_not_build,-kernel_doc_test +test:stress_k_ast1060_evb --local_test_jobs=1 +test:stress_k_ast1060_evb --run_under="//target/ast10x0/harness:test_runner \ + --timeout 0 " +test:stress_k_ast1060_evb --test_env=AST1060_EVB_PI_HOST diff --git a/target/ast10x0/harness/qemu_runner.py b/target/ast10x0/harness/qemu_runner.py index 10fe61c..a00b525 100644 --- a/target/ast10x0/harness/qemu_runner.py +++ b/target/ast10x0/harness/qemu_runner.py @@ -41,7 +41,6 @@ PASS_SENTINEL = b"TEST_RESULT:PASS" FAIL_SENTINEL = b"TEST_RESULT:FAIL" -TIMEOUT_SECONDS = 30 def _parse_args(): @@ -55,6 +54,12 @@ def _parse_args(): parser.add_argument( "--qemu-args", nargs="*", help="Extra arguments to pass to qemu" ) + parser.add_argument( + "--timeout", + type=int, + default=30, + help="Seconds to wait for a test result sentinel (0 = no timeout, default: 30)", + ) return parser.parse_args() @@ -138,7 +143,9 @@ def _main(args) -> None: result = [None] # 0 = pass, 1 = fail, None = no sentinel found with tempfile.NamedTemporaryFile() as f: - with subprocess.Popen(args=qemu_args, stdout=f) as proc: + with subprocess.Popen( + args=qemu_args, stdout=f, stdin=subprocess.DEVNULL + ) as proc: qemu_finished = threading.Event() sentinel_thread = threading.Thread( target=_sentinel_watcher, @@ -154,11 +161,14 @@ def _main(args) -> None: stdout_thread.start() try: - proc.wait(timeout=TIMEOUT_SECONDS) + proc.wait(timeout=args.timeout if args.timeout > 0 else None) + except KeyboardInterrupt: + proc.kill() + proc.wait() except subprocess.TimeoutExpired: _LOG.error( "Test timed out after %ds — no sentinel detected", - TIMEOUT_SECONDS, + args.timeout, ) proc.kill() proc.wait() diff --git a/target/ast10x0/harness/stress_image_test.bzl b/target/ast10x0/harness/stress_image_test.bzl new file mode 100644 index 0000000..0e60d76 --- /dev/null +++ b/target/ast10x0/harness/stress_image_test.bzl @@ -0,0 +1,40 @@ +# Licensed under the Apache-2.0 license +# SPDX-License-Identifier: Apache-2.0 +"""Bazel rule for stress test images. + +Stress tests loop forever and only exit on TEST_RESULT:FAIL. This rule +produces a test target that relies on --run_under to supply the runner, +exactly like system_image_test. Use the stress_virt_ast10x0 or +stress_k_ast1060_evb configs which pass --no-timeout to the runner. +""" + +load("@pigweed//pw_kernel/tooling:system_image.bzl", "SystemImageInfo") + +def _stress_image_test_impl(ctx): + executable_symlink = ctx.actions.declare_file(ctx.label.name) + ctx.actions.symlink( + output = executable_symlink, + target_file = ctx.attr.image[SystemImageInfo].elf, + ) + + return [ + DefaultInfo( + executable = executable_symlink, + runfiles = ctx.attr.image[DefaultInfo].default_runfiles, + ), + ] + +stress_image_test = rule( + implementation = _stress_image_test_impl, + test = True, + attrs = { + "image": attr.label( + doc = "The system_image target to test.", + mandatory = True, + providers = [DefaultInfo, SystemImageInfo], + executable = True, + cfg = "target", + ), + }, + doc = "Defines a stress test for a system_image. Use with stress_virt_ast10x0 or stress_k_ast1060_evb config.", +) diff --git a/target/ast10x0/tests/stress/BUILD.bazel b/target/ast10x0/tests/stress/BUILD.bazel new file mode 100644 index 0000000..2831344 --- /dev/null +++ b/target/ast10x0/tests/stress/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/stress/README.md b/target/ast10x0/tests/stress/README.md new file mode 100644 index 0000000..510e3bf --- /dev/null +++ b/target/ast10x0/tests/stress/README.md @@ -0,0 +1,37 @@ +# AST10x0 Stress Tests + +Stress tests run forever and only exit on `TEST_RESULT:FAIL`. They are excluded +from CI and must be run manually using one of the configs below. + +## Tests + +| Target | What it stresses | +|---|---| +| `stress/mutex/kernel:mutex_stress_test` | Mutex contention across three kernel threads | +| `stress/ipc/user:ipc_stress_test` | IPC channel between initiator and handler processes | +| `stress/process_termination/user:process_termination_stress_test` | Repeated process termination and restart | + +## Running on QEMU + +``` +# Open-ended soak — runs until Ctrl-C or FAIL, no timeout. +# Target the system_image directly, not the _stress_test rule. +bazel run --config=stress_virt_ast10x0 //target/ast10x0/tests/stress/mutex/kernel:mutex + +# Timed run — Bazel kills after 3600s if no FAIL detected. +bazel test --config=stress_virt_ast10x0 //target/ast10x0/tests/stress/:*_stress_test +``` + +Use `bazel run` on the `system_image` target (`:mutex`, `:ipc`, `:process_termination`) +for open-ended soak testing — this runs QEMU directly with no wrappers. +`bazel test` targets the `_stress_test` rule and is bounded by Bazel's 3600s ceiling. + +## Running on hardware (EVB via Pi fixture) + +``` +AST1060_EVB_PI_HOST= bazel test --config=stress_k_ast1060_evb //target/ast10x0/tests/stress/ +``` + +`bazel run` is not supported for EVB — the Pi fixture is only wired into +`bazel test`. Tests run one at a time (`--local_test_jobs=1` is inherited from +`k_ast1060_evb`) and have no runner timeout. diff --git a/target/ast10x0/tests/stress/ipc/user/BUILD.bazel b/target/ast10x0/tests/stress/ipc/user/BUILD.bazel new file mode 100644 index 0000000..fc96ffb --- /dev/null +++ b/target/ast10x0/tests/stress/ipc/user/BUILD.bazel @@ -0,0 +1,79 @@ +# Licensed under the Apache-2.0 license +# SPDX-License-Identifier: Apache-2.0 + +load("@pigweed//pw_kernel/tooling:system_image.bzl", "system_image") +load("@pigweed//pw_kernel/tooling:target_codegen.bzl", "target_codegen") +load("@pigweed//pw_kernel/tooling:target_linker_script.bzl", "target_linker_script") +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:stress_image_test.bzl", "stress_image_test") + +system_image( + name = "ipc", + apps = [ + "@pigweed//pw_kernel/tests/stress/ipc/user:initiator", + "@pigweed//pw_kernel/tests/stress/ipc/user:handler", + ], + kernel = ":target", + platform = "//target/ast10x0", + system_config = ":system_config", + tags = ["kernel"], + target_compatible_with = TARGET_COMPATIBLE_WITH, +) + +rust_binary_no_panics_test( + name = "no_panics_test", + binary = ":ipc", + tags = ["kernel"], +) + +stress_image_test( + name = "ipc_stress_test", + timeout = "eternal", + image = ":ipc", + tags = [ + "do_not_run_test", + "kernel", + ], + target_compatible_with = TARGET_COMPATIBLE_WITH, +) + +filegroup( + name = "system_config", + srcs = ["system.json5"], +) + +target_codegen( + name = "codegen", + arch = "@pigweed//pw_kernel/arch/arm_cortex_m:arch_arm_cortex_m", + system_config = ":system_config", + target_compatible_with = TARGET_COMPATIBLE_WITH, +) + +target_linker_script( + name = "linker_script", + system_config = ":system_config", + tags = ["kernel"], + target_compatible_with = TARGET_COMPATIBLE_WITH, + template = "//target/ast10x0:linker_script_template", +) + +rust_binary( + name = "target", + srcs = ["target.rs"], + edition = "2024", + tags = ["kernel"], + target_compatible_with = TARGET_COMPATIBLE_WITH, + deps = [ + ":codegen", + ":linker_script", + "//target/ast10x0:entry", + "@pigweed//pw_kernel/arch/arm_cortex_m:arch_arm_cortex_m", + "@pigweed//pw_kernel/kernel", + "@pigweed//pw_kernel/subsys/console:console_backend", + "@pigweed//pw_kernel/target:target_common", + "@pigweed//pw_kernel/userspace", + "@pigweed//pw_log/rust:pw_log", + ], +) diff --git a/target/ast10x0/tests/stress/ipc/user/system.json5 b/target/ast10x0/tests/stress/ipc/user/system.json5 new file mode 100644 index 0000000..1349b8e --- /dev/null +++ b/target/ast10x0/tests/stress/ipc/user/system.json5 @@ -0,0 +1,75 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +// AST10x0 IPC Stress Test Configuration +// Two separate apps: initiator sends characters over IPC, handler uppercases +// and echoes them back. Both loop indefinitely. +// +// Memory layout: +// 0x00000000 - 0x00000500: Vector table (1280 bytes) +// 0x00000500 - 0x00020000: Kernel code (~126KB, ends at 128KB boundary) +// 0x00020000 - 0x00040000: initiator app flash (128KB) +// 0x00040000 - 0x00060000: handler app flash (128KB) +// 0x00060000 - 0x00080000: Kernel RAM (128KB) +// 0x00080000 - 0x000A0000: App RAM (2 x 64KB) +{ + arch: { + type: "armv7m", + vector_table_start_address: 0x00000000, + vector_table_size_bytes: 1280, // 0x500 + }, + kernel: { + flash_start_address: 0x00000500, + flash_size_bytes: 129792, // ~126KB (ends at 0x00020000) + ram_start_address: 0x00060000, + ram_size_bytes: 131072, // 128KB + }, + apps: [ + { + name: "initiator", + flash_size_bytes: 131072, // 128KB + processes: [ + { + name: "initiator_process", + ram_size_bytes: 65536, // 64KB + objects: [ + { + name: "ipc", + type: "channel_initiator", + handler_process: "handler_process", + handler_object_name: "ipc", + }, + ], + threads: [ + { + name: "initiator_thread", + kernel_stack_size_bytes: 2048, + }, + ], + }, + ], + }, + { + name: "handler", + flash_size_bytes: 131072, // 128KB + processes: [ + { + name: "handler_process", + ram_size_bytes: 65536, // 64KB + objects: [ + { + name: "ipc", + type: "channel_handler", + }, + ], + threads: [ + { + name: "handler_thread", + kernel_stack_size_bytes: 2048, + }, + ], + }, + ], + }, + ], +} diff --git a/target/ast10x0/tests/stress/ipc/user/target.rs b/target/ast10x0/tests/stress/ipc/user/target.rs new file mode 100644 index 0000000..c5a38b9 --- /dev/null +++ b/target/ast10x0/tests/stress/ipc/user/target.rs @@ -0,0 +1,31 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +#![no_std] +#![no_main] + +use console_backend::console_backend_write_all; +use entry as _; +use target_common::{TargetInterface, declare_target}; + +pub struct Target {} + +impl TargetInterface for Target { + const NAME: &'static str = "AST10x0 IPC Stress"; + + fn main() -> ! { + codegen::start(); + #[expect(clippy::empty_loop)] + loop {} + } + + fn shutdown(code: u32) -> ! { + if code != 0 { + let _ = console_backend_write_all(b"TEST_RESULT:FAIL\n"); + } + #[expect(clippy::empty_loop)] + loop {} + } +} + +declare_target!(Target); diff --git a/target/ast10x0/tests/stress/mutex/kernel/BUILD.bazel b/target/ast10x0/tests/stress/mutex/kernel/BUILD.bazel new file mode 100644 index 0000000..564a4c6 --- /dev/null +++ b/target/ast10x0/tests/stress/mutex/kernel/BUILD.bazel @@ -0,0 +1,68 @@ +# Licensed under the Apache-2.0 license +# SPDX-License-Identifier: Apache-2.0 + +load("@pigweed//pw_kernel/tooling:system_image.bzl", "system_image") +load("@pigweed//pw_kernel/tooling:target_linker_script.bzl", "target_linker_script") +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:stress_image_test.bzl", "stress_image_test") + +system_image( + name = "mutex", + kernel = ":target", + platform = "//target/ast10x0", + system_config = ":system_config", + tags = ["kernel"], + target_compatible_with = TARGET_COMPATIBLE_WITH, + userspace = False, +) + +rust_binary_no_panics_test( + name = "no_panics_test", + binary = ":mutex", + tags = ["kernel"], +) + +stress_image_test( + name = "mutex_stress_test", + timeout = "eternal", + image = ":mutex", + tags = [ + "do_not_run_test", + "kernel", + ], + target_compatible_with = TARGET_COMPATIBLE_WITH, +) + +filegroup( + name = "system_config", + srcs = ["system.json5"], +) + +target_linker_script( + name = "linker_script", + system_config = ":system_config", + tags = ["kernel"], + target_compatible_with = TARGET_COMPATIBLE_WITH, + template = "//target/ast10x0:linker_script_template", +) + +rust_binary( + name = "target", + srcs = ["target.rs"], + edition = "2024", + tags = ["kernel"], + target_compatible_with = TARGET_COMPATIBLE_WITH, + deps = [ + ":linker_script", + "//target/ast10x0:config", + "//target/ast10x0:console", + "//target/ast10x0:entry", + "@pigweed//pw_kernel/arch/arm_cortex_m:arch_arm_cortex_m", + "@pigweed//pw_kernel/kernel", + "@pigweed//pw_kernel/target:target_common", + "@pigweed//pw_kernel/tests/stress/mutex/kernel:mutex", + "@pigweed//pw_log/rust:pw_log", + ], +) diff --git a/target/ast10x0/tests/stress/mutex/kernel/system.json5 b/target/ast10x0/tests/stress/mutex/kernel/system.json5 new file mode 100644 index 0000000..56ff708 --- /dev/null +++ b/target/ast10x0/tests/stress/mutex/kernel/system.json5 @@ -0,0 +1,19 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +// AST10x0 Kernel Mutex Stress Test Configuration +// Kernel-only image; three threads contend on a single mutex indefinitely. +// Memory layout matches threads/kernel — kernel occupies all available RAM. +{ + arch: { + type: "armv7m", + vector_table_start_address: 0x00000000, + vector_table_size_bytes: 1280, // 0x500 (320 vectors) + }, + kernel: { + flash_start_address: 0x00000500, // After vector table + flash_size_bytes: 262144, // 256KB for kernel code + ram_start_address: 0x00040500, // RAM starts after code + ram_size_bytes: 393216, // 384KB for data + }, +} diff --git a/target/ast10x0/tests/stress/mutex/kernel/target.rs b/target/ast10x0/tests/stress/mutex/kernel/target.rs new file mode 100644 index 0000000..1d84fb9 --- /dev/null +++ b/target/ast10x0/tests/stress/mutex/kernel/target.rs @@ -0,0 +1,36 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +#![no_std] +#![no_main] + +use arch_arm_cortex_m::Arch; +use console_backend::console_backend_write_all; +use entry as _; +use target_common::{TargetInterface, declare_target}; + +pub struct Target {} + +impl TargetInterface for Target { + const NAME: &'static str = "AST10x0 Kernel Mutex Stress"; + + fn main() -> ! { + static mut APP_STATE: mutex::AppState = mutex::AppState::new(Arch); + // SAFETY: `main` is only executed once, so we never generate more + // than one `&mut` reference to `APP_STATE`. + #[expect(static_mut_refs)] + let _ = mutex::main(Arch, unsafe { &mut APP_STATE }); + #[expect(clippy::empty_loop)] + loop {} + } + + fn shutdown(code: u32) -> ! { + if code != 0 { + let _ = console_backend_write_all(b"TEST_RESULT:FAIL\n"); + } + #[expect(clippy::empty_loop)] + loop {} + } +} + +declare_target!(Target); diff --git a/target/ast10x0/tests/stress/process_termination/user/BUILD.bazel b/target/ast10x0/tests/stress/process_termination/user/BUILD.bazel new file mode 100644 index 0000000..431d503 --- /dev/null +++ b/target/ast10x0/tests/stress/process_termination/user/BUILD.bazel @@ -0,0 +1,79 @@ +# Licensed under the Apache-2.0 license +# SPDX-License-Identifier: Apache-2.0 + +load("@pigweed//pw_kernel/tooling:system_image.bzl", "system_image") +load("@pigweed//pw_kernel/tooling:target_codegen.bzl", "target_codegen") +load("@pigweed//pw_kernel/tooling:target_linker_script.bzl", "target_linker_script") +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:stress_image_test.bzl", "stress_image_test") + +system_image( + name = "process_termination", + apps = [ + "@pigweed//pw_kernel/tests/stress/process_termination/user:main", + "@pigweed//pw_kernel/tests/stress/process_termination/user:forced_exit", + ], + kernel = ":target", + platform = "//target/ast10x0", + system_config = ":system_config", + tags = ["kernel"], + target_compatible_with = TARGET_COMPATIBLE_WITH, +) + +rust_binary_no_panics_test( + name = "no_panics_test", + binary = ":process_termination", + tags = ["kernel"], +) + +stress_image_test( + name = "process_termination_stress_test", + timeout = "eternal", + image = ":process_termination", + tags = [ + "do_not_run_test", + "kernel", + ], + target_compatible_with = TARGET_COMPATIBLE_WITH, +) + +filegroup( + name = "system_config", + srcs = ["system.json5"], +) + +target_codegen( + name = "codegen", + arch = "@pigweed//pw_kernel/arch/arm_cortex_m:arch_arm_cortex_m", + system_config = ":system_config", + target_compatible_with = TARGET_COMPATIBLE_WITH, +) + +target_linker_script( + name = "linker_script", + system_config = ":system_config", + tags = ["kernel"], + target_compatible_with = TARGET_COMPATIBLE_WITH, + template = "//target/ast10x0:linker_script_template", +) + +rust_binary( + name = "target", + srcs = ["target.rs"], + edition = "2024", + tags = ["kernel"], + target_compatible_with = TARGET_COMPATIBLE_WITH, + deps = [ + ":codegen", + ":linker_script", + "//target/ast10x0:entry", + "@pigweed//pw_kernel/arch/arm_cortex_m:arch_arm_cortex_m", + "@pigweed//pw_kernel/kernel", + "@pigweed//pw_kernel/subsys/console:console_backend", + "@pigweed//pw_kernel/target:target_common", + "@pigweed//pw_kernel/userspace", + "@pigweed//pw_log/rust:pw_log", + ], +) diff --git a/target/ast10x0/tests/stress/process_termination/user/system.json5 b/target/ast10x0/tests/stress/process_termination/user/system.json5 new file mode 100644 index 0000000..c3485f6 --- /dev/null +++ b/target/ast10x0/tests/stress/process_termination/user/system.json5 @@ -0,0 +1,73 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +// AST10x0 Process Termination Stress Test Configuration +// Two apps: main repeatedly terminates and restarts forced_exit indefinitely. +// main holds a process handle to forced_exit's "extra" process, which is +// named to match the #[process_entry("extra")] in forced_exit.rs. +// +// Memory layout: +// 0x00000000 - 0x00000500: Vector table (1280 bytes) +// 0x00000500 - 0x00020000: Kernel code (~126KB, ends at 128KB boundary) +// 0x00020000 - 0x00040000: main app flash (128KB) +// 0x00040000 - 0x00060000: forced_exit app flash (128KB) +// 0x00060000 - 0x00080000: Kernel RAM (128KB) +// 0x00080000 - 0x000A0000: App RAM (main 64KB, forced_exit 64KB) +{ + arch: { + type: "armv7m", + vector_table_start_address: 0x00000000, + vector_table_size_bytes: 1280, // 0x500 + }, + kernel: { + flash_start_address: 0x00000500, + flash_size_bytes: 129792, // ~126KB (ends at 0x00020000) + ram_start_address: 0x00060000, + ram_size_bytes: 131072, // 128KB + }, + apps: [ + { + name: "main", + flash_size_bytes: 131072, // 128KB + processes: [ + { + name: "main_process", + ram_size_bytes: 65536, // 64KB + objects: [ + { + // Generates handle::FORCED_EXIT_PROCESS in main_codegen. + // linked_process must match the process name in the + // forced_exit app ("extra" from #[process_entry("extra")]). + name: "forced_exit_process", + type: "process", + linked_process: "extra", + }, + ], + threads: [ + { + name: "main_thread", + kernel_stack_size_bytes: 2048, + }, + ], + }, + ], + }, + { + name: "forced_exit", + flash_size_bytes: 131072, // 128KB + processes: [ + { + // Name must match #[process_entry("extra")] in forced_exit.rs. + name: "extra", + ram_size_bytes: 65536, // 64KB + threads: [ + { + name: "extra_thread", + kernel_stack_size_bytes: 2048, + }, + ], + }, + ], + }, + ], +} diff --git a/target/ast10x0/tests/stress/process_termination/user/target.rs b/target/ast10x0/tests/stress/process_termination/user/target.rs new file mode 100644 index 0000000..43af741 --- /dev/null +++ b/target/ast10x0/tests/stress/process_termination/user/target.rs @@ -0,0 +1,31 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +#![no_std] +#![no_main] + +use console_backend::console_backend_write_all; +use entry as _; +use target_common::{TargetInterface, declare_target}; + +pub struct Target {} + +impl TargetInterface for Target { + const NAME: &'static str = "AST10x0 Process Termination Stress"; + + fn main() -> ! { + codegen::start(); + #[expect(clippy::empty_loop)] + loop {} + } + + fn shutdown(code: u32) -> ! { + if code != 0 { + let _ = console_backend_write_all(b"TEST_RESULT:FAIL\n"); + } + #[expect(clippy::empty_loop)] + loop {} + } +} + +declare_target!(Target); diff --git a/workflows.json b/workflows.json index d1f1919..5d9ca2a 100644 --- a/workflows.json +++ b/workflows.json @@ -129,7 +129,7 @@ "args": [ "--keep_going", "--config=virt_ast10x0", - "--test_tag_filters=-hardware", + "--test_tag_filters=-hardware,-do_not_run_test", "--test_output=streamed" ], "driver_options": {