1
1
//! Hart state monitor designed for QEMU
2
2
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 } ;
4
4
use core:: { mem:: MaybeUninit , sync:: atomic:: AtomicU8 } ;
5
5
use rustsbi:: SbiRet ;
6
6
use spin:: Mutex ;
7
7
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 ;
10
10
pub ( crate ) const EID_HSM : usize = 0x48534D ;
11
11
pub ( crate ) const FID_HART_STOP : usize = 1 ;
12
12
pub ( crate ) const FID_HART_SUSPEND : usize = 3 ;
@@ -94,6 +94,23 @@ impl QemuHsm {
94
94
}
95
95
}
96
96
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
+
97
114
/// 为硬件线程准备休眠或关闭。
98
115
///
99
116
/// 此时核状态必然是不可干预的 Pending 状态,中断业已关闭。
@@ -120,32 +137,59 @@ impl QemuHsm {
120
137
// 通过软件中断重启
121
138
unsafe {
122
139
mie:: set_msoft ( ) ;
123
- set_mtcev ( entry as _ )
140
+ set_mtvec ( entry as _ ) ;
124
141
} ;
125
142
// 转移状态
126
143
if let Err ( unexpected) = state. compare_exchange ( current, new, AcqRel , Acquire ) {
127
144
panic ! ( "failed to reboot for a race {current:?} => {unexpected:?}" )
128
145
}
129
146
}
130
147
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} ;
139
155
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
+ }
149
193
}
150
194
}
151
195
@@ -214,8 +258,11 @@ impl rustsbi::Hsm for &'static QemuHsm {
214
258
fn hart_suspend ( & self , suspend_type : u32 , resume_addr : usize , opaque : usize ) -> SbiRet {
215
259
use core:: sync:: atomic:: Ordering :: { AcqRel , Acquire } ;
216
260
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
+ }
219
266
SUSPEND_NON_RETENTIVE => {
220
267
* self . supervisor [ hart_id ( ) ] . lock ( ) = Some ( Supervisor {
221
268
start_addr : resume_addr,
0 commit comments