Skip to content
Open
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
169 changes: 169 additions & 0 deletions target/earlgrey/tests/uart/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# Licensed under the Apache-2.0 license
# SPDX-License-Identifier: Apache-2.0

load("@pigweed//pw_kernel/tooling:app_package.bzl", "app_package")
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/earlgrey:defs.bzl", "TARGET_COMPATIBLE_WITH")
load("//target/earlgrey/signing/keys:defs.bzl", "FPGA_ECDSA_KEY", "SILICON_ECDSA_KEY")
load("//target/earlgrey/tooling:opentitan_runner.bzl", "opentitan_test")

rust_binary(
name = "test_uart",
srcs = [
"test_uart.rs",
],
edition = "2024",
tags = ["kernel"],
visibility = ["//visibility:public"],
deps = [
":app_test_uart",
"//target/earlgrey/registers",
"@pigweed//pw_kernel/userspace",
"@pigweed//pw_log/rust:pw_log",
"@pigweed//pw_status/rust:pw_status",
],
)

app_package(
name = "app_test_uart",
app_name = "test_uart",
edition = "2024",
system_config = "@pigweed//pw_kernel/target:system_config_file",
tags = ["kernel"],
)

rust_binary(
name = "test_uart_listener",
srcs = [
"test_uart_listener.rs",
],
edition = "2024",
tags = ["kernel"],
visibility = ["//visibility:public"],
deps = [
":app_test_uart_listener",
"//target/earlgrey/registers",
"@pigweed//pw_kernel/lib/pw_assert",
"@pigweed//pw_kernel/syscall:syscall_user",
"@pigweed//pw_kernel/userspace",
"@pigweed//pw_log/rust:pw_log",
"@pigweed//pw_status/rust:pw_status",
],
)

app_package(
name = "app_test_uart_listener",
app_name = "test_uart_listener",
edition = "2024",
system_config = "@pigweed//pw_kernel/target:system_config_file",
tags = ["kernel"],
)

system_image(
name = "uart",
apps = [
":test_uart",
":test_uart_listener",
],
kernel = ":target",
platform = "//target/earlgrey",
system_config = ":system_config",
tags = ["kernel"],
)

target_linker_script(
name = "linker_script",
system_config = ":system_config",
tags = ["kernel"],
template = "//target/earlgrey:linker_script_template",
)

rust_binary_no_panics_test(
name = "no_panics_test",
binary = ":uart",
tags = [
# TODO(cfrantz): Fix this test.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add more details on why this test is disabled, and if possible, what steps are required to fix this?

"disabled",
"kernel",
],
)

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

target_codegen(
name = "codegen",
arch = "@pigweed//pw_kernel/arch/riscv:arch_riscv",
system_config = ":system_config",
)

rust_binary(
name = "target",
srcs = [
"target.rs",
],
edition = "2024",
tags = ["kernel"],
target_compatible_with = TARGET_COMPATIBLE_WITH,
deps = [
":codegen",
":linker_script",
"//target/earlgrey:entry",
"@pigweed//pw_kernel/arch/riscv:arch_riscv",
"@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",
],
)

opentitan_test(
name = "uart_verilator_test",
timeout = "eternal",
interface = "verilator",
tags = [
"nightly_test",
"verilator",
],
target = ":uart",
)

opentitan_test(
name = "uart_hyper310_test",
ecdsa_key = FPGA_ECDSA_KEY,
interface = "hyper310",
tags = [
"hardware",
"hyper310",
],
target = ":uart",
)

opentitan_test(
name = "uart_hyper340_test",
ecdsa_key = FPGA_ECDSA_KEY,
interface = "hyper340",
tags = [
"hardware",
"hyper340",
],
target = ":uart",
)

opentitan_test(
name = "uart_silicon_test",
ecdsa_key = SILICON_ECDSA_KEY,
interface = "teacup",
tags = [
"earlgrey_silicon",
"hardware",
],
target = ":uart",
)
91 changes: 91 additions & 0 deletions target/earlgrey/tests/uart/system.json5
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Licensed under the Apache-2.0 license
// SPDX-License-Identifier: Apache-2.0
{
arch: {
type: "riscv",
},
kernel: {
flash_start_address: 0xA0010000,
flash_size_bytes: 65536,
ram_start_address: 0x10000000,
ram_size_bytes: 32768,
interrupt_table: {
table: {}
},
},
apps: [
{
name: "test_uart",
flash_size_bytes: 16384,
ram_size_bytes: 4096,
process: {
name: "test_uart process",
objects: [
{
name: "ipc",
type: "channel_handler",
},
],
memory_mappings: [
{
name: "uart1",
type: "device",
start_address: 0x40010000,
size_bytes: 0x40,
}
],
threads: [
{
name: "uart thread",
stack_size_bytes: 2048,
},
],
},
},
{
name: "test_uart_listener",
flash_size_bytes: 16384,
ram_size_bytes: 4096,
process: {
name: "test_uart_listener process",
objects: [
{
name: "uart_interrupts",
type: "interrupt",
irqs: [
{ name: "uart1_tx_watermark", number: 10 },
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these interrupt numbers eventually going to be available in a bzl config file once we migrate the static configuration to Bazel?

{ name: "uart1_rx_watermark", number: 11 },
{ name: "uart1_tx_done", number: 12 },
{ name: "uart1_rx_overflow", number: 13 },
{ name: "uart1_rx_frame_err", number: 14 },
{ name: "uart1_rx_break_err", number: 15 },
{ name: "uart1_rx_timeout", number: 16 },
{ name: "uart1_rx_parity_err", number: 17 },
{ name: "uart1_tx_empty", number: 18 },
],
},
{
name: "ipc",
type: "channel_initiator",
handler_app: "test_uart",
handler_object_name: "ipc",
},
],
memory_mappings: [
{
name: "uart1",
type: "device",
start_address: 0x40010000,
size_bytes: 0x40,
}
],
threads: [
{
name: "uart thread",
stack_size_bytes: 2048,
},
],
},
},
],
}
29 changes: 29 additions & 0 deletions target/earlgrey/tests/uart/target.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Licensed under the Apache-2.0 license
// SPDX-License-Identifier: Apache-2.0

#![no_std]
#![no_main]
use target_common::{declare_target, TargetInterface};
use {console_backend as _, entry as _};

pub struct Target {}

impl TargetInterface for Target {
const NAME: &'static str = "Earlgrey Userspace UART";

fn main() -> ! {
codegen::start();
loop {}
}

fn shutdown(code: u32) -> ! {
pw_log::info!("Shutting down with code {}", code as u32);
match code {
0 => pw_log::info!("PASS"),
_ => pw_log::info!("FAIL: {}", code as u32),
};
loop {}
}
}

declare_target!(Target);
82 changes: 82 additions & 0 deletions target/earlgrey/tests/uart/test_uart.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Licensed under the Apache-2.0 license
// SPDX-License-Identifier: Apache-2.0

#![no_std]
#![no_main]
use app_test_uart::handle;
use pw_status::{Error, Result, StatusCode};
use userspace::syscall::Signals;
use userspace::time::Instant;
use userspace::{entry, syscall};

use registers::uart::*;

fn read_expected_value(expected_value: u8) -> Result<()> {
// the UART listener responds on IPC with the value written to the UART.
let wait_return = syscall::object_wait(handle::IPC, Signals::READABLE, Instant::MAX)?;

if !wait_return.pending_signals.contains(Signals::READABLE) || wait_return.user_data != 0 {
return Err(Error::Internal);
}

let mut buffer = [0u8; 1];
let len = syscall::channel_read(handle::IPC, 0, &mut buffer)?;
if len != 1 {
return Err(Error::OutOfRange);
};

if buffer[0] != expected_value {
pw_log::error!(
"UART read() wrong value {} (expected {})",
buffer[0] as u8,
expected_value as u8
);
return Err(Error::Internal);
}

let response_buffer = [0u8; 0];
syscall::channel_respond(handle::IPC, &response_buffer)?;

Ok(())
}

fn test_uart_interrupts() -> Result<()> {
let mut uart1 = unsafe { Uart1::new() };
let regs = uart1.regs_mut();

regs.ctrl()
.modify(|ctrl| ctrl.tx(true).rx(true).slpbk(true).nco(0xffff));

while !regs.status().read().rxempty() {
let _ = regs.rdata();
}

for txval in 65..91 {
regs.wdata().write(|w| w.wdata(txval as u32));
read_expected_value(txval)?;
}

Ok(())
}

#[entry]
fn entry() -> ! {
pw_log::info!("🔄 RUNNING");
let ret = test_uart_interrupts();

// Log that an error occurred so that the app that caused the shutdown is logged.
if ret.is_err() {
pw_log::error!("❌ FAILED: {}", ret.status_code() as u32);
} else {
pw_log::info!("✅ PASSED");
}

// Since this is written as a test, shut down with the return status from `main()`.
let _ = syscall::debug_shutdown(ret);
loop {}
}

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it ok for tests to log error if panic is triggered?

}
Loading
Loading