Skip to content

Commit 35782e6

Browse files
committed
feat(test_runner): add new targets qemu_sifive_u_s_rv{32,64}
1 parent 11aa2d5 commit 35782e6

File tree

9 files changed

+224
-6
lines changed

9 files changed

+224
-6
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,10 @@ jobs:
214214
- { ty: riscv, runner_target: qemu_sifive_u_rv64, runner_args: --arch rv64i+m+a }
215215
# SiFive U, RV32GC
216216
- { ty: riscv, runner_target: qemu_sifive_u_rv32, runner_args: "" }
217+
# SiFive U, RV64GC, S-mode
218+
- { ty: riscv, runner_target: qemu_sifive_u_s_rv64, runner_args: "" }
219+
# SiFive U, RV32GC, S-mode
220+
- { ty: riscv, runner_target: qemu_sifive_u_s_rv32, runner_args: "" }
217221
# SiFive E, RV32IMAC
218222
- { ty: riscv, runner_target: qemu_sifive_e_rv32, runner_args: "" }
219223
# SiFive E, RV32IA

doc/testing.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ The following table shows how to run the kernel test suite for each target.
4141
| RV32GC | [SiFive U][] (QEMU) | `cargo r3test -t qemu_sifive_u_rv32` |
4242
| RV64IMAC | SiFive U (QEMU) | `cargo r3test -t qemu_sifive_u_rv64 -a rv64i+m+a+c` |
4343
| RV64GC | SiFive U (QEMU) | `cargo r3test -t qemu_sifive_u_rv64` |
44+
| RV64GC | SiFive U (S-mode, QEMU) | `cargo r3test -t qemu_sifive_u_s_rv64` |
4445
| RV32IMAC | [RED-V][] (SPI flash XIP) | `cargo r3test -t red_v` |
4546
| RV64GC | [Maix][] boards (UART ISP) | `cargo r3test -t maix` |
4647

src/r3_port_riscv_test_driver/Cargo.toml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,18 @@ run = [
1717
"log",
1818
]
1919

20+
# --------------------------------------------------------------------
21+
22+
# Minimal startup code that relies on a bootloader to
23+
# load all sections and assumes S-mode
24+
boot-minimal-s = []
25+
# Use `riscv-rt` for the startup code
2026
boot-rt = [
2127
"riscv-rt",
2228
]
2329

30+
# --------------------------------------------------------------------
31+
2432
output-rtt = [
2533
"rtt-target",
2634
]
@@ -39,12 +47,16 @@ output-k210-uart = [
3947
]
4048
output-uart = []
4149

50+
# --------------------------------------------------------------------
51+
4252
interrupt-e310x = [
4353
"e310x",
4454
]
4555
interrupt-u540-qemu = []
4656
interrupt-k210 = []
4757

58+
# --------------------------------------------------------------------
59+
4860
board-e310x-red-v = [
4961
"e310x-hal",
5062
]
@@ -54,6 +66,13 @@ board-e310x-qemu = [
5466
board-u540-qemu = []
5567
board-maix = []
5668

69+
# --------------------------------------------------------------------
70+
71+
timer-clint = []
72+
timer-sbi = []
73+
74+
# --------------------------------------------------------------------
75+
5776
[dependencies]
5877
r3_port_riscv = { path = "../r3_port_riscv", optional = true }
5978
r3_portkit = { path = "../r3_portkit", optional = true }

src/r3_port_riscv_test_driver/src/main.rs

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,53 @@ macro_rules! instantiate_test {
7878

7979
type System = r3_kernel::System<SystemTraits>;
8080
port::use_port!(unsafe struct SystemTraits);
81+
82+
#[cfg(feature = "timer-clint")]
83+
port::use_mtime!(unsafe impl PortTimer for SystemTraits);
84+
#[cfg(feature = "timer-sbi")]
85+
port::use_sbi_timer!(unsafe impl PortTimer for SystemTraits);
86+
87+
impl port::ThreadingOptions for SystemTraits {
88+
#[cfg(feature = "boot-minimal-s")]
89+
const PRIVILEGE_LEVEL: u8 = port::PRIVILEGE_LEVEL_SUPERVISOR;
90+
}
91+
8192
#[cfg(feature = "boot-rt")]
8293
port::use_rt!(unsafe SystemTraits);
83-
port::use_mtime!(unsafe impl PortTimer for SystemTraits);
8494

85-
impl port::ThreadingOptions for SystemTraits {}
95+
#[cfg(feature = "boot-minimal-s")]
96+
#[no_mangle]
97+
#[naked]
98+
extern "C" fn start() {
99+
unsafe {
100+
core::arch::asm!(
101+
"
102+
# Configure the initial stack
103+
la a0, {MAIN_STACK}
104+
li a1, 8192
105+
andi a0, a0, -16
106+
add sp, a0, a1
107+
108+
call {start_kernel}
109+
",
110+
start_kernel = sym start_kernel,
111+
MAIN_STACK = sym MAIN_STACK,
112+
options(noreturn)
113+
);
114+
}
115+
116+
static MAIN_STACK: core::mem::MaybeUninit<[u8; 8192]> = core::mem::MaybeUninit::uninit();
117+
118+
extern "C" fn start_kernel() {
119+
unsafe {
120+
core::arch::asm!(
121+
"csrw stvec, {}",
122+
in(reg) <SystemTraits as port::EntryPoint>::TRAP_HANDLER,
123+
);
124+
<SystemTraits as port::EntryPoint>::start();
125+
}
126+
}
127+
}
86128

87129
#[cfg(feature = "interrupt-e310x")]
88130
use_interrupt_e310x!(unsafe impl InterruptController for SystemTraits);
@@ -107,6 +149,7 @@ macro_rules! instantiate_test {
107149
const CONTEXT: usize = 0;
108150
}
109151

152+
#[cfg(feature = "timer-clint")]
110153
impl port::MtimeOptions for SystemTraits {
111154
const MTIME_PTR: usize = 0x0200_bff8;
112155

@@ -130,6 +173,12 @@ macro_rules! instantiate_test {
130173
const RESET_MTIME: bool = false;
131174
}
132175

176+
#[cfg(feature = "timer-sbi")]
177+
impl port::SbiTimerOptions for SystemTraits {
178+
#[cfg(feature = "board-u540-qemu")]
179+
const FREQUENCY: u64 = u540::MTIME_FREQUENCY;
180+
}
181+
133182
struct Driver;
134183

135184
#[cfg(feature = "kernel_benchmarks")]
@@ -241,6 +290,23 @@ macro_rules! instantiate_test {
241290

242291
test_case::App::new::<_, Driver>(b)
243292
}
293+
294+
/// Like `riscv::interrupt::free` but uses the correct CSR for the
295+
/// application's privilege level
296+
#[inline]
297+
fn with_cpu_lock(f: impl FnOnce()) {
298+
use r3::{prelude::*, kernel::CpuLockError};
299+
struct Guard(Result<(), CpuLockError>);
300+
let _guard = Guard(System::acquire_cpu_lock());
301+
f();
302+
impl Drop for Guard {
303+
fn drop(&mut self) {
304+
if self.0.is_ok() {
305+
let _ = unsafe { System::release_cpu_lock() };
306+
}
307+
}
308+
}
309+
}
244310
};
245311

246312
() => {}
@@ -272,3 +338,14 @@ mod driver_kernel_tests {
272338
fn main() {
273339
panic!("This executable should not be invoked directly");
274340
}
341+
342+
// Wildcard imports take less precedence
343+
#[allow(unused_imports)]
344+
use default_impl::*;
345+
#[allow(dead_code)]
346+
mod default_impl {
347+
#[track_caller]
348+
fn with_cpu_lock(_: impl FnOnce()) {
349+
unreachable!();
350+
}
351+
}

src/r3_port_riscv_test_driver/src/uart_u540.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
//! The UART driver compatible with QEMU `sifive_u` machine
22
//! (RISC-V Board compatible with SiFive U SDK).
33
use core::fmt::{self, Write};
4-
use riscv::interrupt;
54

65
pub fn stdout_write_str(s: &str) {
7-
interrupt::free(|_| {
6+
crate::with_cpu_lock(|| {
87
let _ = SerialWrapper(0x10010000 as *mut u32).write_str(s);
98
});
109
}
1110

1211
pub fn stdout_write_fmt(args: fmt::Arguments<'_>) {
13-
interrupt::free(|_| {
12+
crate::with_cpu_lock(|| {
1413
let _ = SerialWrapper(0x10010000 as *mut u32).write_fmt(args);
1514
});
1615
}
1716

1817
pub fn stderr_write_fmt(args: fmt::Arguments<'_>) {
19-
interrupt::free(|_| {
18+
crate::with_cpu_lock(|| {
2019
let _ = SerialWrapper(0x10011000 as *mut u32).write_fmt(args);
2120
});
2221
}

src/r3_test_runner/src/targets.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,57 @@ impl LinkerScripts {
6767
generated_files: vec![("memory.x".to_owned(), memory_definition)],
6868
}
6969
}
70+
71+
/// Create `LinkerScripts` to define some standard sections, which are to
72+
/// be included in the final image header and initialized by a section-aware
73+
/// loader. Symbol `start` is treated as the entry point.
74+
fn standard(base_address: u64) -> Self {
75+
let link = r#"
76+
ENTRY(start);
77+
78+
SECTIONS
79+
{
80+
. = BASE_ADDRESS;
81+
82+
.text :
83+
{
84+
*(.text .text.*);
85+
. = ALIGN(4);
86+
__etext = .;
87+
}
88+
89+
.rodata __etext : ALIGN(4)
90+
{
91+
*(.rodata .rodata.*);
92+
. = ALIGN(4);
93+
}
94+
95+
.data : ALIGN(4)
96+
{
97+
*(.data .data.*);
98+
. = ALIGN(4);
99+
}
100+
101+
__sidata = LOADADDR(.data);
102+
103+
.bss : ALIGN(4)
104+
{
105+
__sbss = .;
106+
*(.bss .bss.*);
107+
. = ALIGN(4);
108+
__ebss = .;
109+
}
110+
}
111+
"#
112+
.to_owned();
113+
114+
let link = link.replace("BASE_ADDRESS", &base_address.to_string());
115+
116+
Self {
117+
inputs: vec!["link.x".to_owned()],
118+
generated_files: vec![("link.x".to_owned(), link)],
119+
}
120+
}
70121
}
71122

72123
pub trait DebugProbe: Send {
@@ -90,6 +141,14 @@ pub static TARGETS: &[(&str, &dyn Target)] = &[
90141
("qemu_sifive_e_rv64", &qemu::riscv::QemuSiFiveE(Xlen::_64)),
91142
("qemu_sifive_u_rv32", &qemu::riscv::QemuSiFiveU(Xlen::_32)),
92143
("qemu_sifive_u_rv64", &qemu::riscv::QemuSiFiveU(Xlen::_64)),
144+
(
145+
"qemu_sifive_u_s_rv32",
146+
&qemu::riscv::QemuSiFiveUModeS(Xlen::_32),
147+
),
148+
(
149+
"qemu_sifive_u_s_rv64",
150+
&qemu::riscv::QemuSiFiveUModeS(Xlen::_64),
151+
),
93152
("red_v", &jlink::RedV),
94153
("maix", &kflash::Maix),
95154
("rp_pico", &rp_pico::RaspberryPiPico),

src/r3_test_runner/src/targets/jlink.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ impl Target for RedV {
3131
"boot-rt".to_owned(),
3232
"output-rtt".to_owned(),
3333
"interrupt-e310x".to_owned(),
34+
"timer-clint".to_owned(),
3435
"board-e310x-red-v".to_owned(),
3536
"r3_port_riscv/emulate-lr-sc".to_owned(),
3637
]

src/r3_test_runner/src/targets/kflash.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ impl Target for Maix {
3030
"boot-rt".to_owned(),
3131
"output-k210-uart".to_owned(),
3232
"interrupt-k210".to_owned(),
33+
"timer-clint".to_owned(),
3334
"board-maix".to_owned(),
3435
"r3_port_riscv/maintain-pie".to_owned(),
3536
]

src/r3_test_runner/src/targets/qemu/riscv.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ impl Target for QemuSiFiveE {
2222
"boot-rt".to_owned(),
2323
"output-e310x-uart".to_owned(),
2424
"interrupt-e310x".to_owned(),
25+
"timer-clint".to_owned(),
2526
"board-e310x-qemu".to_owned(),
2627
]
2728
}
@@ -92,6 +93,7 @@ impl Target for QemuSiFiveU {
9293
"boot-rt".to_owned(),
9394
"output-u540-uart".to_owned(),
9495
"interrupt-u540-qemu".to_owned(),
96+
"timer-clint".to_owned(),
9597
"board-u540-qemu".to_owned(),
9698
]
9799
}
@@ -117,6 +119,7 @@ impl Target for QemuSiFiveU {
117119
.to_owned(),
118120
)
119121
}
122+
120123
fn connect(&self) -> Pin<Box<dyn Future<Output = Result<Box<dyn DebugProbe>>>>> {
121124
let xlen = self.0;
122125
Box::pin(async move {
@@ -144,3 +147,57 @@ impl Target for QemuSiFiveU {
144147
})
145148
}
146149
}
150+
151+
/// The RISC-V board compatible with SiFive U SDK on QEMU, using a bootloader to
152+
/// run the kernel in S-mode
153+
pub struct QemuSiFiveUModeS(pub Xlen);
154+
155+
impl Target for QemuSiFiveUModeS {
156+
fn target_arch(&self) -> Arch {
157+
match self.0 {
158+
Xlen::_32 => Arch::RV32GC,
159+
Xlen::_64 => Arch::RV64GC,
160+
}
161+
}
162+
163+
fn cargo_features(&self) -> Vec<String> {
164+
vec![
165+
"boot-minimal-s".to_owned(),
166+
"output-u540-uart".to_owned(),
167+
"interrupt-u540-qemu".to_owned(),
168+
"timer-sbi".to_owned(),
169+
"board-u540-qemu".to_owned(),
170+
]
171+
}
172+
173+
fn linker_scripts(&self) -> LinkerScripts {
174+
// Somewhere near `0x80000000` is occupied by the bootloader (the
175+
// default `-bios`), so avoid that
176+
LinkerScripts::standard(0x80100000)
177+
}
178+
179+
fn connect(&self) -> Pin<Box<dyn Future<Output = Result<Box<dyn DebugProbe>>>>> {
180+
let xlen = self.0;
181+
Box::pin(async move {
182+
Ok(Box::new(QemuDebugProbe::new(
183+
match xlen {
184+
Xlen::_32 => "qemu-system-riscv32",
185+
Xlen::_64 => "qemu-system-riscv64",
186+
},
187+
&[
188+
"-machine",
189+
"sifive_u",
190+
// UART0 → stdout
191+
"-serial",
192+
"file:/dev/stdout",
193+
// UART1 → stderr
194+
"-serial",
195+
"file:/dev/stderr",
196+
// Disable monitor
197+
"-monitor",
198+
"none",
199+
],
200+
)) as Box<dyn DebugProbe>)
201+
})
202+
}
203+
}

0 commit comments

Comments
 (0)