use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Condvar, Mutex};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum VmState {
Running,
PauseRequested,
Paused,
}
#[derive(Clone, Default)]
pub struct CpuSnapshot {
pub gpr: [u64; 32],
pub pc: u64,
pub priv_level: u8,
pub halted: bool,
}
pub struct MonitorState {
inner: Mutex<VmState>,
pause_barrier: Condvar,
resume_cv: Condvar,
quit_requested: AtomicBool,
wfi_waker: Mutex<Option<Arc<crate::wfi::WfiWaker>>>,
snapshot: Mutex<Option<CpuSnapshot>>,
stop_flag: Mutex<
Option<Arc<AtomicBool>>,
>,
}
impl MonitorState {
pub fn new() -> Self {
Self {
inner: Mutex::new(VmState::Running),
pause_barrier: Condvar::new(),
resume_cv: Condvar::new(),
quit_requested: AtomicBool::new(false),
wfi_waker: Mutex::new(None),
snapshot: Mutex::new(None),
stop_flag: Mutex::new(None),
}
}
pub fn set_stop_flag(
&self,
flag: Arc<AtomicBool>,
) {
*self.stop_flag.lock().unwrap() =
Some(Arc::clone(&flag));
if self.is_quit_requested() {
flag.store(false, Ordering::SeqCst);
}
}
pub fn store_snapshot(&self, snap: CpuSnapshot) {
*self.snapshot.lock().unwrap() = Some(snap);
}
pub fn read_snapshot(&self) -> Option<CpuSnapshot> {
self.snapshot.lock().unwrap().clone()
}
pub fn set_wfi_waker(
&self,
wk: Arc<crate::wfi::WfiWaker>,
) {
let needs_wake = self.is_quit_requested()
|| self.is_pause_requested();
*self.wfi_waker.lock().unwrap() =
Some(Arc::clone(&wk));
if needs_wake {
wk.monitor_wake();
}
}
pub fn request_stop(&self) {
let mut state = self.inner.lock().unwrap();
if *state == VmState::Paused {
return;
}
*state = VmState::PauseRequested;
if let Some(ref wk) =
*self.wfi_waker.lock().unwrap()
{
wk.monitor_wake();
}
while *state == VmState::PauseRequested {
state = self
.pause_barrier
.wait(state)
.unwrap();
}
}
pub fn request_cont(&self) {
let mut state = self.inner.lock().unwrap();
if *state == VmState::Running {
return;
}
*state = VmState::Running;
self.resume_cv.notify_all();
self.pause_barrier.notify_all();
if let Some(ref wk) =
*self.wfi_waker.lock().unwrap()
{
wk.clear_monitor_wake();
}
}
pub fn request_quit(&self) {
self.quit_requested.store(true, Ordering::SeqCst);
if let Some(ref flag) =
*self.stop_flag.lock().unwrap()
{
flag.store(false, Ordering::SeqCst);
}
let mut state = self.inner.lock().unwrap();
*state = VmState::Running;
self.resume_cv.notify_all();
self.pause_barrier.notify_all();
if let Some(ref wk) =
*self.wfi_waker.lock().unwrap()
{
wk.stop();
}
}
pub fn is_quit_requested(&self) -> bool {
self.quit_requested.load(Ordering::SeqCst)
}
pub fn check_pause(&self) -> bool {
if self.is_quit_requested() {
return true;
}
let mut state = self.inner.lock().unwrap();
if *state == VmState::PauseRequested {
*state = VmState::Paused;
self.pause_barrier.notify_all();
while *state == VmState::Paused {
state =
self.resume_cv.wait(state).unwrap();
}
}
self.is_quit_requested()
}
pub fn vm_state(&self) -> VmState {
*self.inner.lock().unwrap()
}
pub fn is_pause_requested(&self) -> bool {
let s = self.inner.lock().unwrap();
*s == VmState::PauseRequested
|| *s == VmState::Paused
}
}
impl Default for MonitorState {
fn default() -> Self {
Self::new()
}
}