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
#[ allow( unused) ]
10
10
#[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
11
11
#[ repr( u8 ) ]
12
12
enum HsmState {
13
13
/// The hart is physically powered-up and executing normally.
14
14
Started = 0 ,
15
- /// The hart is not executing in supervisor-mode or any lower privilege mode.
16
- /// It is probably powered-down by the SBI implementation if the underlying platform has a mechanism
15
+ /// The hart is not executing in supervisor-mode or any lower privilege mode.
16
+ /// It is probably powered-down by the SBI implementation if the underlying platform has a mechanism
17
17
/// to physically power-down harts.
18
18
Stopped = 1 ,
19
- /// Some other hart has requested to start (or power-up) the hart from the STOPPED state
19
+ /// Some other hart has requested to start (or power-up) the hart from the STOPPED state
20
20
/// and the SBI implementation is still working to get the hart in the STARTED state.
21
21
StartPending = 2 ,
22
- /// The hart has requested to stop (or power-down) itself from the STARTED state
22
+ /// The hart has requested to stop (or power-down) itself from the STARTED state
23
23
/// and the SBI implementation is still working to get the hart in the STOPPED state.
24
24
StopPending = 3 ,
25
25
/// This hart is in a platform specific suspend (or low power) state.
26
26
Suspended = 4 ,
27
- /// The hart has requested to put itself in a platform specific low power state from the STARTED state
27
+ /// The hart has requested to put itself in a platform specific low power state from the STARTED state
28
28
/// and the SBI implementation is still working to get the hart in the platform specific SUSPENDED state.
29
29
SuspendPending = 5 ,
30
- /// An interrupt or platform specific hardware event has caused the hart to resume normal execution from
30
+ /// An interrupt or platform specific hardware event has caused the hart to resume normal execution from
31
31
/// the SUSPENDED state and the SBI implementation is still working to get the hart in the STARTED state.
32
32
ResumePending = 6 ,
33
33
}
@@ -61,12 +61,16 @@ impl QemuHsm {
61
61
}
62
62
pub ( crate ) fn record_current_stop_finished ( & self ) {
63
63
let hart_id = riscv:: register:: mhartid:: read ( ) ;
64
- self . state . lock ( ) . entry ( hart_id)
64
+ self . state
65
+ . lock ( )
66
+ . entry ( hart_id)
65
67
. insert ( AtomicU8 :: new ( HsmState :: Stopped as u8 ) ) ;
66
68
}
67
69
pub ( crate ) fn record_current_start_finished ( & self ) {
68
70
let hart_id = riscv:: register:: mhartid:: read ( ) ;
69
- self . state . lock ( ) . entry ( hart_id)
71
+ self . state
72
+ . lock ( )
73
+ . entry ( hart_id)
70
74
. insert ( AtomicU8 :: new ( HsmState :: Started as u8 ) ) ;
71
75
}
72
76
}
@@ -76,28 +80,31 @@ impl rustsbi::Hsm for QemuHsm {
76
80
// previous privileged mode should be user or supervisor; start from machine mode is not supported
77
81
let mpp = mstatus:: read ( ) . mpp ( ) ;
78
82
if mpp != MPP :: Supervisor && mpp != MPP :: User {
79
- return SbiRet :: invalid_param ( )
80
- }
83
+ return SbiRet :: invalid_param ( ) ;
84
+ }
81
85
// try to modify state to start hart
82
86
let mut state_lock = self . state . lock ( ) ;
83
- let current_state = state_lock. entry ( hart_id)
87
+ let current_state = state_lock
88
+ . entry ( hart_id)
84
89
. or_insert ( AtomicU8 :: new ( HsmState :: Stopped as u8 ) )
85
90
. compare_exchange (
86
91
HsmState :: Stopped as u8 ,
87
92
HsmState :: StartPending as u8 ,
88
93
Ordering :: AcqRel ,
89
94
Ordering :: Acquire ,
90
- ) ;
95
+ ) ;
91
96
if current_state == Err ( HsmState :: Started as u8 ) {
92
- return SbiRet :: already_available ( )
97
+ return SbiRet :: already_available ( ) ;
93
98
}
94
99
// hart is already transitioning from started state
95
100
if current_state != Ok ( HsmState :: Stopped as u8 ) {
96
- return SbiRet :: invalid_param ( )
101
+ return SbiRet :: invalid_param ( ) ;
97
102
}
98
103
// fill in the parameter
99
104
let mut config_lock = self . last_command . lock ( ) ;
100
- config_lock. entry ( hart_id) . insert ( HsmCommand :: Start ( start_addr, opaque) ) ;
105
+ config_lock
106
+ . entry ( hart_id)
107
+ . insert ( HsmCommand :: Start ( start_addr, opaque) ) ;
101
108
drop ( config_lock) ;
102
109
drop ( state_lock) ;
103
110
// now, start the target hart
@@ -108,23 +115,24 @@ impl rustsbi::Hsm for QemuHsm {
108
115
fn hart_stop ( & self , hart_id : usize ) -> SbiRet {
109
116
// try to set current target hart state to stop pending
110
117
let mut state_lock = self . state . lock ( ) ;
111
- let current_state = state_lock. entry ( hart_id)
118
+ let current_state = state_lock
119
+ . entry ( hart_id)
112
120
. or_insert ( AtomicU8 :: new ( HsmState :: Stopped as u8 ) )
113
121
. compare_exchange (
114
122
HsmState :: Started as u8 ,
115
123
HsmState :: StopPending as u8 ,
116
124
Ordering :: AcqRel ,
117
125
Ordering :: Acquire ,
118
- ) ;
126
+ ) ;
119
127
// check current hart state
120
128
if current_state == Err ( HsmState :: Started as u8 ) {
121
- return SbiRet :: failed ( ) // illegal state
129
+ return SbiRet :: failed ( ) ; // illegal state
122
130
}
123
131
// fill in the parameter
124
132
let mut config_lock = self . last_command . lock ( ) ;
125
133
config_lock. entry ( hart_id) . insert ( HsmCommand :: Stop ) ;
126
134
drop ( config_lock) ;
127
- drop ( state_lock) ;
135
+ drop ( state_lock) ;
128
136
// stop the target hart
129
137
let clint = crate :: clint:: Clint :: new ( 0x2000000 as * mut u8 ) ;
130
138
clint. send_soft ( hart_id) ;
@@ -133,20 +141,20 @@ impl rustsbi::Hsm for QemuHsm {
133
141
fn hart_get_status ( & self , hart_id : usize ) -> SbiRet {
134
142
self . state . lock ( ) . get ( & hart_id) . map_or (
135
143
SbiRet :: invalid_param ( ) , // if given hart is invalid
136
- |a| SbiRet :: ok ( a. load ( Ordering :: Relaxed ) as usize )
144
+ |a| SbiRet :: ok ( a. load ( Ordering :: Relaxed ) as usize ) ,
137
145
)
138
146
}
139
147
fn hart_suspend ( & self , suspend_type : u32 , resume_addr : usize , opaque : usize ) -> SbiRet {
140
- match suspend_type {
141
- // Resuming from a retentive suspend state is straight forward and the supervisor-mode software
148
+ match suspend_type {
149
+ // Resuming from a retentive suspend state is straight forward and the supervisor-mode software
142
150
// will see SBI suspend call return without any failures.
143
151
SUSPEND_RETENTIVE => {
144
152
pause ( ) ; // pause and wait for machine level ipi
145
153
SbiRet :: ok ( 0 )
146
- } ,
147
- // Resuming from a non-retentive suspend state is relatively more involved and requires software
148
- // to restore various hart registers and CSRs for all privilege modes.
149
- // Upon resuming from non-retentive suspend state, the hart will jump to supervisor-mode at address
154
+ }
155
+ // Resuming from a non-retentive suspend state is relatively more involved and requires software
156
+ // to restore various hart registers and CSRs for all privilege modes.
157
+ // Upon resuming from non-retentive suspend state, the hart will jump to supervisor-mode at address
150
158
// specified by `resume_addr` with specific registers values described in the table below:
151
159
//
152
160
// | Register Name | Register Value
@@ -178,8 +186,8 @@ impl rustsbi::Hsm for QemuHsm {
178
186
unimplemented ! ( "not RISC-V instruction set architecture" )
179
187
}
180
188
} ;
181
- } ,
182
- _ => SbiRet :: not_supported ( )
189
+ }
190
+ _ => SbiRet :: not_supported ( ) ,
183
191
}
184
192
}
185
193
}
@@ -189,10 +197,10 @@ const SUSPEND_NON_RETENTIVE: u32 = 0x80000000;
189
197
190
198
// Pause current hart, wake through inter-processor interrupt
191
199
pub fn pause ( ) {
192
- use riscv:: asm:: wfi;
193
- use riscv:: register:: { mie, mip, mhartid} ;
194
200
use crate :: clint:: Clint ;
195
- unsafe {
201
+ use riscv:: asm:: wfi;
202
+ use riscv:: register:: { mhartid, mie, mip} ;
203
+ unsafe {
196
204
let hartid = mhartid:: read ( ) ;
197
205
let clint = Clint :: new ( 0x2000000 as * mut u8 ) ;
198
206
clint. clear_soft ( hartid) ; // Clear IPI
@@ -208,5 +216,5 @@ pub fn pause() {
208
216
mie:: clear_msoft ( ) ; // Stop listening for software interrupts
209
217
}
210
218
clint. clear_soft ( hartid) ; // Clear IPI
211
- }
212
- }
219
+ }
220
+ }
0 commit comments