Skip to content

Commit 55ef7c4

Browse files
committed
feat(sbi): 支持可恢复挂起
1 parent 9d28338 commit 55ef7c4

File tree

4 files changed

+89
-37
lines changed

4 files changed

+89
-37
lines changed

rustsbi-qemu/src/execute/mod.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
use crate::{clint, hart_id, Supervisor};
1+
use crate::{
2+
clint, hart_id,
3+
qemu_hsm::{QemuHsm, SUSPEND_RETENTIVE},
4+
Supervisor,
5+
};
26

37
mod context;
48
mod transfer_trap;
59

610
use context::Context;
711

8-
pub(crate) fn execute_supervisor(supervisor: Supervisor) {
12+
pub(crate) fn execute_supervisor(hsm: &QemuHsm, supervisor: Supervisor) {
913
use core::arch::asm;
1014
use riscv::register::{medeleg, mie, mstatus};
1115

@@ -26,13 +30,14 @@ pub(crate) fn execute_supervisor(supervisor: Supervisor) {
2630
medeleg::clear_supervisor_env_call();
2731
medeleg::clear_machine_env_call();
2832

29-
crate::set_mtcev(s_to_m as usize);
33+
crate::set_mtvec(s_to_m as usize);
3034
mie::set_mext();
3135
mie::set_msoft();
3236
}
3337

38+
hsm.record_current_start_finished();
3439
loop {
35-
use crate::qemu_hsm::{EID_HSM, FID_HART_STOP, FID_HART_SUSPEND, SUSPEND_NON_RETENTIVE};
40+
use crate::qemu_hsm::{EID_HSM, FID_HART_STOP, FID_HART_SUSPEND};
3641
use riscv::register::{
3742
mcause::{self, Exception as E, Interrupt as I, Trap as T},
3843
mip,
@@ -57,11 +62,10 @@ pub(crate) fn execute_supervisor(supervisor: Supervisor) {
5762
let param = [ctx.a(0), ctx.a(1), ctx.a(2), ctx.a(3), ctx.a(4), ctx.a(5)];
5863
let ans = rustsbi::ecall(ctx.a(7), ctx.a(6), param);
5964
if ctx.a(7) == EID_HSM && ans.error == 0 {
60-
if ctx.a(6) == FID_HART_STOP {
61-
return;
62-
}
63-
if ctx.a(6) == FID_HART_SUSPEND && ctx.a(0) == SUSPEND_NON_RETENTIVE as usize {
64-
return;
65+
match ctx.a(6) {
66+
FID_HART_STOP => return,
67+
FID_HART_SUSPEND if ctx.a(0) == SUSPEND_RETENTIVE => return,
68+
_ => {}
6569
}
6670
}
6771
*ctx.a_mut(0) = ans.error;

rustsbi-qemu/src/linker64.ld

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ SECTIONS
1111
.text : {
1212
*(.text.entry)
1313
. = ALIGN(4);
14+
*(.text.early_trap)
15+
. = ALIGN(4);
1416
*(.text.trap_handler)
1517
. = ALIGN(4);
16-
*(.text.early_trap)
18+
*(.text.awaker)
1719
*(.text .text.*)
1820
}
1921

rustsbi-qemu/src/main.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ static SMP: AtomicUsize = AtomicUsize::new(0);
119119

120120
/// rust 入口。
121121
extern "C" fn rust_main(_hartid: usize, opaque: usize) {
122-
unsafe { set_mtcev(early_trap as _) };
122+
unsafe { set_mtvec(early_trap as _) };
123123

124124
#[link_section = ".bss.uninit"]
125125
static GENESIS: AtomicBool = AtomicBool::new(false);
@@ -176,8 +176,7 @@ extern "C" fn rust_main(_hartid: usize, opaque: usize) {
176176
let hsm = HSM.wait();
177177
if let Some(supervisor) = hsm.take_supervisor() {
178178
set_pmp();
179-
hsm.record_current_start_finished();
180-
execute::execute_supervisor(supervisor);
179+
execute::execute_supervisor(hsm, supervisor);
181180
}
182181
}
183182

@@ -236,7 +235,7 @@ fn hart_id() -> usize {
236235
}
237236

238237
#[inline(always)]
239-
unsafe fn set_mtcev(trap_handler: usize) {
238+
unsafe fn set_mtvec(trap_handler: usize) {
240239
use riscv::register::mtvec;
241240
mtvec::write(trap_handler, mtvec::TrapMode::Direct);
242241
}

rustsbi-qemu/src/qemu_hsm.rs

Lines changed: 70 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
//! Hart state monitor designed for QEMU
22
3-
use crate::{clint::Clint, entry, hart_id, set_mtcev, Supervisor, NUM_HART_MAX, SUPERVISOR_ENTRY};
3+
use crate::{clint::Clint, entry, hart_id, set_mtvec, Supervisor, NUM_HART_MAX, SUPERVISOR_ENTRY};
44
use core::{mem::MaybeUninit, sync::atomic::AtomicU8};
55
use rustsbi::SbiRet;
66
use spin::Mutex;
77

8-
pub(crate) const SUSPEND_RETENTIVE: u32 = 0x00000000;
9-
pub(crate) const SUSPEND_NON_RETENTIVE: u32 = 0x80000000;
8+
pub(crate) const SUSPEND_RETENTIVE: usize = 0x00000000;
9+
pub(crate) const SUSPEND_NON_RETENTIVE: usize = 0x80000000;
1010
pub(crate) const EID_HSM: usize = 0x48534D;
1111
pub(crate) const FID_HART_STOP: usize = 1;
1212
pub(crate) const FID_HART_SUSPEND: usize = 3;
@@ -94,6 +94,23 @@ impl QemuHsm {
9494
}
9595
}
9696

97+
/// 初始化完成,转移到运行状态。
98+
pub fn record_current_start_finished(&self) {
99+
use core::sync::atomic::Ordering::Release;
100+
self.state[hart_id()].store(STARTED, Release);
101+
}
102+
103+
/// 如果一个核可以接受 ipi,返回 `true`。
104+
///
105+
/// 运行状态的核可以接受权限低于 SBI 软件的核间中断,将转交给特权软件。
106+
/// 挂起状态的核可以接受核间中断以恢复运行。
107+
pub fn is_ipi_allowed(&self, hart_id: usize) -> bool {
108+
use core::sync::atomic::Ordering::Acquire;
109+
self.state
110+
.get(hart_id)
111+
.map_or(false, |s| matches!(s.load(Acquire), STARTED | SUSPEND))
112+
}
113+
97114
/// 为硬件线程准备休眠或关闭。
98115
///
99116
/// 此时核状态必然是不可干预的 Pending 状态,中断业已关闭。
@@ -120,32 +137,59 @@ impl QemuHsm {
120137
// 通过软件中断重启
121138
unsafe {
122139
mie::set_msoft();
123-
set_mtcev(entry as _)
140+
set_mtvec(entry as _);
124141
};
125142
// 转移状态
126143
if let Err(unexpected) = state.compare_exchange(current, new, AcqRel, Acquire) {
127144
panic!("failed to reboot for a race {current:?} => {unexpected:?}")
128145
}
129146
}
130147

131-
/// Record that current hart id is marked as `Started` state.
132-
/// It is used when hart stop command is received in interrupt handler.
133-
/// The target hart (when in interrupt handler) is prepared to start, it marks itself into 'started',
134-
/// and should jump to target address right away.
135-
pub fn record_current_start_finished(&self) {
136-
use core::sync::atomic::Ordering::Release;
137-
self.state[hart_id()].store(STARTED, Release);
138-
}
148+
/// 可恢复挂起。
149+
fn retentive_suspend(&self) {
150+
use core::{
151+
arch::asm,
152+
sync::atomic::Ordering::{AcqRel, Acquire},
153+
};
154+
use riscv::{interrupt, register::mtvec};
139155

140-
/// 如果一个核可以接受 ipi,返回 `true`。
141-
///
142-
/// 运行状态的核可以接受权限低于 SBI 软件的核间中断,将转交给特权软件。
143-
/// 挂起状态的核可以接受核间中断以恢复运行。
144-
pub fn is_ipi_allowed(&self, hart_id: usize) -> bool {
145-
use core::sync::atomic::Ordering::Acquire;
146-
self.state
147-
.get(hart_id)
148-
.map_or(false, |s| matches!(s.load(Acquire), STARTED | SUSPEND))
156+
/// 挂起,使用 call 进入以链接 ra
157+
#[naked]
158+
unsafe extern "C" fn suspend() {
159+
asm!("1: wfi", "j 1b", options(noreturn))
160+
}
161+
162+
/// 恢复,利用 ra 回到挂起前位置
163+
#[naked]
164+
#[link_section = ".text.awaker"]
165+
unsafe extern "C" fn resume() {
166+
asm!("ret", options(noreturn))
167+
}
168+
169+
let state = &self.state[hart_id()];
170+
let mtvec = mtvec::read().address();
171+
172+
// 转移状态
173+
if let Err(unexpected) = state.compare_exchange(SUSPEND_PENDING, SUSPEND, AcqRel, Acquire) {
174+
panic!("failed to suspend by wrong state: {unexpected:?}")
175+
}
176+
// 调整中断,休眠
177+
unsafe {
178+
// 支持软中断或外部中断唤醒
179+
let mut mie: usize = (1 << 11) | (1 << 3);
180+
181+
set_mtvec(resume as _);
182+
asm!("csrrw {0}, mie, {0}", inlateout(reg) mie);
183+
interrupt::enable();
184+
suspend();
185+
interrupt::disable();
186+
asm!("csrw mie, {mie}", mie = in(reg) mie);
187+
set_mtvec(mtvec);
188+
}
189+
// 恢复状态
190+
if let Err(unexpected) = state.compare_exchange(SUSPEND, STARTED, AcqRel, Acquire) {
191+
panic!("failed to resume by wrong state: {unexpected:?}")
192+
}
149193
}
150194
}
151195

@@ -214,8 +258,11 @@ impl rustsbi::Hsm for &'static QemuHsm {
214258
fn hart_suspend(&self, suspend_type: u32, resume_addr: usize, opaque: usize) -> SbiRet {
215259
use core::sync::atomic::Ordering::{AcqRel, Acquire};
216260
match self.state[hart_id()].compare_exchange(STARTED, SUSPEND_PENDING, AcqRel, Acquire) {
217-
Ok(_) => match suspend_type {
218-
SUSPEND_RETENTIVE => todo!(),
261+
Ok(_) => match suspend_type as usize {
262+
SUSPEND_RETENTIVE => {
263+
self.retentive_suspend();
264+
SbiRet::ok(0)
265+
}
219266
SUSPEND_NON_RETENTIVE => {
220267
*self.supervisor[hart_id()].lock() = Some(Supervisor {
221268
start_addr: resume_addr,

0 commit comments

Comments
 (0)