Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 124 additions & 0 deletions target/ast10x0/tests/util_ipc/async_transaction/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Licensed under the Apache-2.0 license
# SPDX-License-Identifier: Apache-2.0

load("@pigweed//pw_kernel/tooling:rust_app.bzl", "rust_app")
load("@pigweed//pw_kernel/tooling:system_image.bzl", "system_image", "system_image_test")
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")

# ── System configuration ───────────────────────────────────────────────────────

filegroup(
name = "system_config",
srcs = ["system.json5"],
)

# ── Kernel image ───────────────────────────────────────────────────────────────

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",
],
)

# ── Handler app ─────────────────────────────────────────────────────────────────
# Exercises util_ipc::IpcHandler; increments the byte it's sent.

rust_app(
name = "handler",
srcs = ["handler_main.rs"],
codegen_crate_name = "app_handler",
edition = "2024",
system_config = ":system_config",
tags = ["kernel"],
target_compatible_with = TARGET_COMPATIBLE_WITH,
deps = [
"//util/ipc",
"@pigweed//pw_kernel/userspace",
"@pigweed//pw_status/rust:pw_status",
],
)

# ── Initiator app ───────────────────────────────────────────────────────────────
# Exercises util_ipc::IpcInitiator and util_ipc::AsyncTransaction; calls
# debug_shutdown(Ok|Err) to report the result.

rust_app(
name = "initiator",
srcs = ["initiator_main.rs"],
codegen_crate_name = "app_initiator",
edition = "2024",
system_config = ":system_config",
tags = ["kernel"],
target_compatible_with = TARGET_COMPATIBLE_WITH,
deps = [
"//util/ipc",
"@pigweed//pw_kernel/userspace",
"@pigweed//pw_log/rust:pw_log",
"@pigweed//pw_status/rust:pw_status",
],
)

# ── System image ───────────────────────────────────────────────────────────────

system_image(
name = "async_transaction_image",
apps = [
":handler",
":initiator",
],
kernel = ":target",
platform = "//target/ast10x0",
system_config = ":system_config",
tags = ["kernel"],
target_compatible_with = TARGET_COMPATIBLE_WITH,
visibility = ["//visibility:public"],
)

# ── Test target ────────────────────────────────────────────────────────────────
# Run with:
# bazel test --config=virt_ast10x0 //target/ast10x0/tests/util_ipc/async_transaction:async_transaction_qemu_test

system_image_test(
name = "async_transaction_qemu_test",
image = ":async_transaction_image",
tags = ["qemu_only"],
target_compatible_with = TARGET_COMPATIBLE_WITH,
)

rust_binary_no_panics_test(
name = "no_panics_test",
binary = ":async_transaction_image",
tags = ["kernel"],
)
62 changes: 62 additions & 0 deletions target/ast10x0/tests/util_ipc/async_transaction/handler_main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Licensed under the Apache-2.0 license
// SPDX-License-Identifier: Apache-2.0

//! Handler side of the util/ipc AsyncTransaction QEMU test.
//!
//! Exercises `util_ipc::IpcHandler`: waits for a request, reads it, and
//! responds with the request byte incremented by one. A request of
//! `GATED_REQUEST` is held until the initiator raises Signals::USER.

#![no_main]
#![no_std]

use app_handler::handle;
use pw_status::Error;
use userspace::entry;
use userspace::syscall::{self, Signals};
use userspace::time::Instant;
use util_ipc::{IpcHandle, IpcHandler};

/// Request byte that parks the handler instead of responding: it raises
/// Signals::USER on the initiator to say it is parked, then waits for the
/// initiator to raise USER back before responding. The parked signal is
/// what makes the initiator's "pending" observation deterministic.
const GATED_REQUEST: u8 = 0x40;

#[entry]
fn entry() {
let ipc = IpcHandle::new(handle::IPC);

loop {
if syscall::object_wait(handle::IPC, Signals::READABLE, Instant::MAX).is_err() {
continue;
}

let mut buf = [0u8; 1];
match ipc.read(0, &mut buf) {
Ok(1) => {
if buf[0] == GATED_REQUEST {
// Tell the initiator we are parked, wait for its
// release, then lower the parked signal again.
if ipc.set_peer_user_signal(true).is_err()
|| syscall::object_wait(handle::IPC, Signals::USER, Instant::MAX).is_err()
{
continue;
}
let _ = ipc.set_peer_user_signal(false);
}
buf[0] = buf[0].wrapping_add(1);
let _ = ipc.respond(&buf);
}
// Transaction was cancelled by the initiator while we were
// waking up; go back to waiting for the next one.
Ok(_) | Err(Error::Unavailable) => continue,
Err(_) => continue,
}
}
}

#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}
Loading
Loading