-
Notifications
You must be signed in to change notification settings - Fork 10
earlgrey: Add a uart loopback test #128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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. | ||
| "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", | ||
| ) | ||
| 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 }, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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, | ||
| }, | ||
| ], | ||
| }, | ||
| }, | ||
| ], | ||
| } | ||
| 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); |
| 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 {} | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it ok for tests to log error if panic is triggered? |
||
| } | ||
There was a problem hiding this comment.
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?