1
1
//! Hart state monitor designed for QEMU
2
2
3
- use hashbrown:: HashMap ;
4
- use rustsbi:: SbiRet ;
5
- use core:: sync:: atomic:: { AtomicU8 , Ordering } ;
6
3
use alloc:: sync:: Arc ;
4
+ use core:: sync:: atomic:: { AtomicU8 , Ordering } ;
5
+ use hashbrown:: HashMap ;
7
6
use riscv:: register:: mstatus:: { self , MPP } ;
7
+ use rustsbi:: SbiRet ;
8
8
9
9
// RISC-V SBI Hart State Monitor states
10
10
#[ allow( unused) ]
@@ -13,22 +13,22 @@ use riscv::register::mstatus::{self, MPP};
13
13
enum HsmState {
14
14
/// The hart is physically powered-up and executing normally.
15
15
Started = 0 ,
16
- /// The hart is not executing in supervisor-mode or any lower privilege mode.
17
- /// It is probably powered-down by the SBI implementation if the underlying platform has a mechanism
16
+ /// The hart is not executing in supervisor-mode or any lower privilege mode.
17
+ /// It is probably powered-down by the SBI implementation if the underlying platform has a mechanism
18
18
/// to physically power-down harts.
19
19
Stopped = 1 ,
20
- /// Some other hart has requested to start (or power-up) the hart from the STOPPED state
20
+ /// Some other hart has requested to start (or power-up) the hart from the STOPPED state
21
21
/// and the SBI implementation is still working to get the hart in the STARTED state.
22
22
StartPending = 2 ,
23
- /// The hart has requested to stop (or power-down) itself from the STARTED state
23
+ /// The hart has requested to stop (or power-down) itself from the STARTED state
24
24
/// and the SBI implementation is still working to get the hart in the STOPPED state.
25
25
StopPending = 3 ,
26
26
/// This hart is in a platform specific suspend (or low power) state.
27
27
Suspended = 4 ,
28
- /// The hart has requested to put itself in a platform specific low power state from the STARTED state
28
+ /// The hart has requested to put itself in a platform specific low power state from the STARTED state
29
29
/// and the SBI implementation is still working to get the hart in the platform specific SUSPENDED state.
30
30
SuspendPending = 5 ,
31
- /// An interrupt or platform specific hardware event has caused the hart to resume normal execution from
31
+ /// An interrupt or platform specific hardware event has caused the hart to resume normal execution from
32
32
/// the SUSPENDED state and the SBI implementation is still working to get the hart in the STARTED state.
33
33
ResumePending = 6 ,
34
34
}
@@ -91,7 +91,9 @@ impl QemuHsm {
91
91
// this function is called.
92
92
pub ( crate ) fn record_current_stop_finished ( & self ) {
93
93
let hart_id = riscv:: register:: mhartid:: read ( ) ;
94
- self . state . lock ( ) . entry ( hart_id)
94
+ self . state
95
+ . lock ( )
96
+ . entry ( hart_id)
95
97
. insert ( AtomicU8 :: new ( HsmState :: Stopped as u8 ) ) ;
96
98
}
97
99
// Record that current hart id is marked as `Started` state.
@@ -100,7 +102,9 @@ impl QemuHsm {
100
102
// and should jump to target address right away.
101
103
pub ( crate ) fn record_current_start_finished ( & self ) {
102
104
let hart_id = riscv:: register:: mhartid:: read ( ) ;
103
- self . state . lock ( ) . entry ( hart_id)
105
+ self . state
106
+ . lock ( )
107
+ . entry ( hart_id)
104
108
. insert ( AtomicU8 :: new ( HsmState :: Started as u8 ) ) ;
105
109
}
106
110
}
@@ -113,11 +117,12 @@ impl rustsbi::Hsm for QemuHsm {
113
117
// previous privileged mode should be user or supervisor; start from machine mode is not supported
114
118
let mpp = mstatus:: read ( ) . mpp ( ) ;
115
119
if mpp != MPP :: Supervisor && mpp != MPP :: User {
116
- return SbiRet :: invalid_param ( )
117
- }
120
+ return SbiRet :: invalid_param ( ) ;
121
+ }
118
122
// try to modify state to start hart
119
123
let mut state_lock = self . state . lock ( ) ;
120
- let current_state = state_lock. entry ( hart_id)
124
+ let current_state = state_lock
125
+ . entry ( hart_id)
121
126
. or_insert ( AtomicU8 :: new ( HsmState :: Stopped as u8 ) )
122
127
. compare_exchange (
123
128
HsmState :: Stopped as u8 ,
@@ -133,15 +138,17 @@ impl rustsbi::Hsm for QemuHsm {
133
138
}
134
139
// - otherwise return invalid parameter, this may be caused for hart is already transitioning from started state
135
140
if current_state != Ok ( HsmState :: Stopped as u8 ) {
136
- return SbiRet :: invalid_param ( )
141
+ return SbiRet :: invalid_param ( ) ;
137
142
}
138
143
// todo: check start address
139
144
/* SBI_ERR_INVALID_ADDRESS: start_addr is not valid possibly due to following reasons:
140
145
* It is not a valid physical address.
141
146
* The address is prohibited by PMP to run in supervisor mode. */
142
147
// fill in the parameter
143
148
let mut config_lock = self . last_command . lock ( ) ;
144
- config_lock. entry ( hart_id) . insert ( HsmCommand :: Start ( start_addr, opaque) ) ;
149
+ config_lock
150
+ . entry ( hart_id)
151
+ . insert ( HsmCommand :: Start ( start_addr, opaque) ) ;
145
152
drop ( config_lock) ;
146
153
drop ( state_lock) ;
147
154
// now, start the target hart
@@ -154,14 +161,15 @@ impl rustsbi::Hsm for QemuHsm {
154
161
fn hart_stop ( & self , hart_id : usize ) -> SbiRet {
155
162
// try to set current target hart state to stop pending
156
163
let mut state_lock = self . state . lock ( ) ;
157
- let current_state = state_lock. entry ( hart_id)
164
+ let current_state = state_lock
165
+ . entry ( hart_id)
158
166
. or_insert ( AtomicU8 :: new ( HsmState :: Stopped as u8 ) )
159
167
. compare_exchange (
160
168
HsmState :: Started as u8 ,
161
169
HsmState :: StopPending as u8 ,
162
170
Ordering :: AcqRel ,
163
171
Ordering :: Acquire ,
164
- ) ;
172
+ ) ;
165
173
// check current hart state
166
174
if current_state. is_err ( ) {
167
175
return SbiRet :: failed ( ) // illegal state
@@ -170,7 +178,7 @@ impl rustsbi::Hsm for QemuHsm {
170
178
let mut config_lock = self . last_command . lock ( ) ;
171
179
config_lock. entry ( hart_id) . insert ( HsmCommand :: Stop ) ;
172
180
drop ( config_lock) ;
173
- drop ( state_lock) ;
181
+ drop ( state_lock) ;
174
182
// stop the target hart
175
183
let clint = crate :: clint:: Clint :: new ( 0x2000000 as * mut u8 ) ;
176
184
clint. send_soft ( hart_id) ;
@@ -189,8 +197,8 @@ impl rustsbi::Hsm for QemuHsm {
189
197
// Otherwise, the current hart discards current supervisor context, and returns to another
190
198
// `resume_addr` with parameter `opaque`.
191
199
fn hart_suspend ( & self , suspend_type : u32 , resume_addr : usize , opaque : usize ) -> SbiRet {
192
- match suspend_type {
193
- // Resuming from a retentive suspend state is straight forward and the supervisor-mode software
200
+ match suspend_type {
201
+ // Resuming from a retentive suspend state is straight forward and the supervisor-mode software
194
202
// will see SBI suspend call return without any failures.
195
203
SUSPEND_RETENTIVE => {
196
204
// try to set current target hart state to stop pending
@@ -216,10 +224,10 @@ impl rustsbi::Hsm for QemuHsm {
216
224
state_lock. entry ( hart_id) . insert ( AtomicU8 :: new ( HsmState :: Started as u8 ) ) ;
217
225
drop ( state_lock) ;
218
226
SbiRet :: ok ( 0 )
219
- } ,
220
- // Resuming from a non-retentive suspend state is relatively more involved and requires software
221
- // to restore various hart registers and CSRs for all privilege modes.
222
- // Upon resuming from non-retentive suspend state, the hart will jump to supervisor-mode at address
227
+ }
228
+ // Resuming from a non-retentive suspend state is relatively more involved and requires software
229
+ // to restore various hart registers and CSRs for all privilege modes.
230
+ // Upon resuming from non-retentive suspend state, the hart will jump to supervisor-mode at address
223
231
// specified by `resume_addr` with specific registers values described in the table below:
224
232
//
225
233
// | Register Name | Register Value
@@ -299,10 +307,10 @@ pub fn suspend_current_hart(hsm: &QemuHsm) {
299
307
300
308
// Pause current hart, wake through inter-processor interrupt
301
309
pub fn pause ( ) {
302
- use riscv:: asm:: wfi;
303
- use riscv:: register:: { mie, mip, mhartid} ;
304
310
use crate :: clint:: Clint ;
305
- unsafe {
311
+ use riscv:: asm:: wfi;
312
+ use riscv:: register:: { mhartid, mie, mip} ;
313
+ unsafe {
306
314
let hartid = mhartid:: read ( ) ;
307
315
let clint = Clint :: new ( 0x2000000 as * mut u8 ) ;
308
316
clint. clear_soft ( hartid) ; // Clear IPI
@@ -319,5 +327,5 @@ pub fn pause() {
319
327
mie:: clear_msoft ( ) ; // Stop listening for software interrupts
320
328
}
321
329
clint. clear_soft ( hartid) ; // Clear IPI
322
- }
323
- }
330
+ }
331
+ }
0 commit comments