mirror of
https://github.com/obhq/obliteration.git
synced 2024-11-23 03:09:52 +00:00
Initializes CPU interruption from debugger (#1035)
This commit is contained in:
parent
e101b8b7eb
commit
fa844896cd
@ -1,19 +1,57 @@
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::{Arc, Condvar, Mutex};
|
||||
use std::thread::JoinHandle;
|
||||
|
||||
/// Contains objects to control a CPU from outside.
|
||||
pub struct CpuController {
|
||||
thread: ManuallyDrop<JoinHandle<()>>,
|
||||
state: Arc<Mutex<CpuState>>,
|
||||
debug: Arc<(Mutex<DebugStates>, Condvar)>,
|
||||
wakeup: bool,
|
||||
}
|
||||
|
||||
impl CpuController {
|
||||
pub fn new(thread: JoinHandle<()>, state: Arc<Mutex<CpuState>>) -> Self {
|
||||
pub fn new(thread: JoinHandle<()>, debug: Arc<(Mutex<DebugStates>, Condvar)>) -> Self {
|
||||
Self {
|
||||
thread: ManuallyDrop::new(thread),
|
||||
state,
|
||||
debug,
|
||||
wakeup: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn debug_states<R>(&mut self, f: impl FnOnce(&GdbRegs) -> R) -> R {
|
||||
// Request from the CPU if not available.
|
||||
let mut s = self.debug.0.lock().unwrap();
|
||||
|
||||
loop {
|
||||
s = match s.deref() {
|
||||
DebugStates::None => {
|
||||
*s = DebugStates::Request;
|
||||
|
||||
self.wakeup = true;
|
||||
self.debug.1.wait(s).unwrap()
|
||||
}
|
||||
DebugStates::Request => self.debug.1.wait(s).unwrap(),
|
||||
DebugStates::DebuggerOwned(v) => break f(v),
|
||||
DebugStates::CpuOwned(_) => {
|
||||
// The CPU is not pickup the previous value yet.
|
||||
self.debug.1.wait(s).unwrap()
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn release(&mut self) {
|
||||
let mut s = self.debug.0.lock().unwrap();
|
||||
|
||||
match std::mem::take(s.deref_mut()) {
|
||||
DebugStates::DebuggerOwned(v) => *s = DebugStates::CpuOwned(v),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
if std::mem::take(&mut self.wakeup) {
|
||||
self.debug.1.notify_one();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -24,7 +62,18 @@ impl Drop for CpuController {
|
||||
}
|
||||
}
|
||||
|
||||
/// State of a CPU.
|
||||
pub enum CpuState {
|
||||
Running,
|
||||
/// Debugging states of a CPU.
|
||||
#[derive(Default)]
|
||||
pub enum DebugStates {
|
||||
#[default]
|
||||
None,
|
||||
Request,
|
||||
DebuggerOwned(GdbRegs),
|
||||
CpuOwned(GdbRegs),
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
type GdbRegs = gdbstub_arch::aarch64::reg::AArch64CoreRegs;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
type GdbRegs = gdbstub_arch::x86::reg::X86_64CoreRegs;
|
||||
|
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
pub use self::controller::CpuState;
|
||||
pub use self::controller::DebugStates;
|
||||
|
||||
use self::controller::CpuController;
|
||||
use super::hv::{Cpu, CpuExit, CpuIo, Hypervisor};
|
||||
use super::hv::{Cpu, CpuExit, CpuIo, CpuRun, Hypervisor};
|
||||
use super::hw::{DeviceContext, DeviceTree};
|
||||
use super::ram::RamMap;
|
||||
use super::screen::Screen;
|
||||
@ -13,7 +13,7 @@ use std::error::Error;
|
||||
use std::num::NonZero;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::{Arc, Condvar, Mutex};
|
||||
|
||||
#[cfg_attr(target_arch = "aarch64", path = "aarch64.rs")]
|
||||
#[cfg_attr(target_arch = "x86_64", path = "x86_64.rs")]
|
||||
@ -59,24 +59,29 @@ impl<H: Hypervisor, S: Screen> CpuManager<H, S> {
|
||||
};
|
||||
|
||||
// Spawn thread to drive vCPU.
|
||||
let state = Arc::new(Mutex::new(CpuState::Running));
|
||||
let debug = Arc::new((Mutex::default(), Condvar::new()));
|
||||
let t = match map {
|
||||
Some(map) => std::thread::spawn({
|
||||
let state = state.clone();
|
||||
let debug = debug.clone();
|
||||
|
||||
move || Self::main_cpu(args, state, start, map)
|
||||
move || Self::main_cpu(args, debug, start, map)
|
||||
}),
|
||||
None => todo!(),
|
||||
};
|
||||
|
||||
self.cpus.push(CpuController::new(t, state));
|
||||
self.cpus.push(CpuController::new(t, debug));
|
||||
}
|
||||
|
||||
pub fn debug_lock(&mut self) -> DebugLock<H, S> {
|
||||
DebugLock(self)
|
||||
}
|
||||
|
||||
fn main_cpu(args: Args<H, S>, state: Arc<Mutex<CpuState>>, entry: usize, map: RamMap) {
|
||||
fn main_cpu(
|
||||
args: Args<H, S>,
|
||||
debug: Arc<(Mutex<DebugStates>, Condvar)>,
|
||||
entry: usize,
|
||||
map: RamMap,
|
||||
) {
|
||||
let mut cpu = match args.hv.create_cpu(0) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
@ -92,10 +97,14 @@ impl<H: Hypervisor, S: Screen> CpuManager<H, S> {
|
||||
return;
|
||||
}
|
||||
|
||||
Self::run_cpu(&args, &state, cpu);
|
||||
Self::run_cpu(&args, &debug, cpu);
|
||||
}
|
||||
|
||||
fn run_cpu<'a>(args: &'a Args<H, S>, state: &'a Mutex<CpuState>, mut cpu: H::Cpu<'a>) {
|
||||
fn run_cpu<'a>(
|
||||
args: &'a Args<H, S>,
|
||||
debug: &'a (Mutex<DebugStates>, Condvar),
|
||||
mut cpu: H::Cpu<'a>,
|
||||
) {
|
||||
// Build device contexts for this CPU.
|
||||
let mut devices = args
|
||||
.devices
|
||||
@ -103,7 +112,7 @@ impl<H: Hypervisor, S: Screen> CpuManager<H, S> {
|
||||
.map(|(addr, dev)| {
|
||||
let end = dev.len().checked_add(addr).unwrap();
|
||||
|
||||
(addr, (dev.create_context(&args.hv, state), end))
|
||||
(addr, (dev.create_context(&args.hv, debug), end))
|
||||
})
|
||||
.collect::<BTreeMap<usize, (Box<dyn DeviceContext<H::Cpu<'a>>>, NonZero<usize>)>>();
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
use super::arch::{KvmStates, StatesError};
|
||||
use super::ffi::kvm_run;
|
||||
use super::run::KvmRun;
|
||||
use crate::vmm::hv::{Cpu, CpuExit, CpuIo, IoBuf};
|
||||
use crate::vmm::hv::{Cpu, CpuExit, CpuIo, CpuRun, IoBuf};
|
||||
use libc::munmap;
|
||||
use std::os::fd::{AsRawFd, OwnedFd};
|
||||
use std::sync::MutexGuard;
|
||||
@ -38,11 +38,14 @@ impl<'a> Cpu for KvmCpu<'a> {
|
||||
type States<'b> = KvmStates<'b> where Self: 'b;
|
||||
type GetStatesErr = StatesError;
|
||||
type Exit<'b> = KvmExit<'b, 'a> where Self: 'b;
|
||||
type RunErr = std::io::Error;
|
||||
|
||||
fn states(&mut self) -> Result<Self::States<'_>, Self::GetStatesErr> {
|
||||
KvmStates::from_cpu(&mut self.fd)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> CpuRun for KvmCpu<'a> {
|
||||
type RunErr = std::io::Error;
|
||||
|
||||
fn run(&mut self) -> Result<Self::Exit<'_>, Self::RunErr> {
|
||||
match unsafe { kvm_run(self.fd.as_raw_fd()) } {
|
||||
@ -56,6 +59,7 @@ impl<'a> Cpu for KvmCpu<'a> {
|
||||
pub struct KvmExit<'a, 'b>(&'a mut KvmCpu<'b>);
|
||||
|
||||
impl<'a, 'b> CpuExit for KvmExit<'a, 'b> {
|
||||
type Cpu = KvmCpu<'b>;
|
||||
type Io = KvmIo<'a, 'b>;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
@ -80,6 +84,7 @@ impl<'a, 'b> CpuExit for KvmExit<'a, 'b> {
|
||||
pub struct KvmIo<'a, 'b>(&'a mut KvmCpu<'b>);
|
||||
|
||||
impl<'a, 'b> CpuIo for KvmIo<'a, 'b> {
|
||||
type Cpu = KvmCpu<'b>;
|
||||
type TranslateErr = std::io::Error;
|
||||
|
||||
fn addr(&self) -> usize {
|
||||
@ -118,6 +123,10 @@ impl<'a, 'b> CpuIo for KvmIo<'a, 'b> {
|
||||
_ => return Err(std::io::Error::last_os_error()),
|
||||
}
|
||||
}
|
||||
|
||||
fn cpu(&mut self) -> &mut Self::Cpu {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
|
@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
use crate::vmm::hv::{Cpu, CpuExit, CpuIo, CpuStates, IoBuf};
|
||||
use crate::vmm::hv::{Cpu, CpuExit, CpuIo, CpuRun, CpuStates, IoBuf};
|
||||
use applevisor_sys::hv_reg_t::{HV_REG_CPSR, HV_REG_PC, HV_REG_X0, HV_REG_X1};
|
||||
use applevisor_sys::hv_sys_reg_t::{
|
||||
HV_SYS_REG_MAIR_EL1, HV_SYS_REG_SCTLR_EL1, HV_SYS_REG_SP_EL1, HV_SYS_REG_TCR_EL1,
|
||||
@ -30,11 +30,20 @@ impl<'a> HvfCpu<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for HvfCpu<'a> {
|
||||
fn drop(&mut self) {
|
||||
let ret = unsafe { hv_vcpu_destroy(self.instance) };
|
||||
|
||||
if ret != 0 {
|
||||
panic!("hv_vcpu_destroy() fails with {ret:#x}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Cpu for HvfCpu<'a> {
|
||||
type States<'b> = HvfStates<'b, 'a> where Self: 'b;
|
||||
type GetStatesErr = StatesError;
|
||||
type Exit<'b> = HvfExit<'b, 'a> where Self: 'b;
|
||||
type RunErr = RunError;
|
||||
|
||||
fn states(&mut self) -> Result<Self::States<'_>, Self::GetStatesErr> {
|
||||
Ok(HvfStates {
|
||||
@ -51,6 +60,10 @@ impl<'a> Cpu for HvfCpu<'a> {
|
||||
x1: State::None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> CpuRun for HvfCpu<'a> {
|
||||
type RunErr = RunError;
|
||||
|
||||
fn run(&mut self) -> Result<Self::Exit<'_>, Self::RunErr> {
|
||||
match NonZero::new(unsafe { hv_vcpu_run(self.instance) }) {
|
||||
@ -60,16 +73,6 @@ impl<'a> Cpu for HvfCpu<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for HvfCpu<'a> {
|
||||
fn drop(&mut self) {
|
||||
let ret = unsafe { hv_vcpu_destroy(self.instance) };
|
||||
|
||||
if ret != 0 {
|
||||
panic!("hv_vcpu_destroy() fails with {ret:#x}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of [`Cpu::States`] for Hypervisor Framework.
|
||||
pub struct HvfStates<'a, 'b> {
|
||||
cpu: &'a mut HvfCpu<'b>,
|
||||
@ -207,7 +210,8 @@ impl<'a, 'b> HvfExit<'a, 'b> {
|
||||
}
|
||||
|
||||
impl<'a, 'b> CpuExit for HvfExit<'a, 'b> {
|
||||
type Io = HvfIo;
|
||||
type Cpu = HvfCpu<'b>;
|
||||
type Io = HvfIo<'a, 'b>;
|
||||
|
||||
fn into_io(self) -> Result<Self::Io, Self> {
|
||||
todo!();
|
||||
@ -215,9 +219,10 @@ impl<'a, 'b> CpuExit for HvfExit<'a, 'b> {
|
||||
}
|
||||
|
||||
/// Implementation of [`CpuIo`] for Hypervisor Framework.
|
||||
pub struct HvfIo {}
|
||||
pub struct HvfIo<'a, 'b>(&'a mut HvfCpu<'b>);
|
||||
|
||||
impl CpuIo for HvfIo {
|
||||
impl<'a, 'b> CpuIo for HvfIo<'a, 'b> {
|
||||
type Cpu = HvfCpu<'b>;
|
||||
type TranslateErr = std::io::Error;
|
||||
|
||||
fn addr(&self) -> usize {
|
||||
@ -231,6 +236,10 @@ impl CpuIo for HvfIo {
|
||||
fn translate(&self, vaddr: usize) -> Result<usize, std::io::Error> {
|
||||
todo!();
|
||||
}
|
||||
|
||||
fn cpu(&mut self) -> &mut Self::Cpu {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of [`Cpu::RunErr`].
|
||||
|
@ -24,7 +24,7 @@ pub type Default = self::os::Whp;
|
||||
|
||||
/// Underlying hypervisor (e.g. KVM on Linux).
|
||||
pub trait Hypervisor: Send + Sync + 'static {
|
||||
type Cpu<'a>: Cpu
|
||||
type Cpu<'a>: CpuRun
|
||||
where
|
||||
Self: 'a;
|
||||
type CpuErr: Error + Send + 'static;
|
||||
@ -45,12 +45,17 @@ pub trait Cpu {
|
||||
where
|
||||
Self: 'a;
|
||||
type GetStatesErr: Error + Send + 'static;
|
||||
type Exit<'a>: CpuExit
|
||||
type Exit<'a>: CpuExit<Cpu = Self>
|
||||
where
|
||||
Self: 'a;
|
||||
type RunErr: Error + Send + 'static;
|
||||
|
||||
fn states(&mut self) -> Result<Self::States<'_>, Self::GetStatesErr>;
|
||||
}
|
||||
|
||||
/// Provides a method to run the CPU.
|
||||
pub trait CpuRun: Cpu {
|
||||
type RunErr: Error + Send + 'static;
|
||||
|
||||
fn run(&mut self) -> Result<Self::Exit<'_>, Self::RunErr>;
|
||||
}
|
||||
|
||||
@ -139,7 +144,8 @@ pub trait CpuStates {
|
||||
|
||||
/// Contains information when VM exited.
|
||||
pub trait CpuExit: Sized {
|
||||
type Io: CpuIo;
|
||||
type Cpu: Cpu;
|
||||
type Io: CpuIo<Cpu = Self::Cpu>;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn into_hlt(self) -> Result<(), Self>;
|
||||
@ -149,12 +155,14 @@ pub trait CpuExit: Sized {
|
||||
|
||||
/// Contains information when a VM exited because of memory-mapped I/O.
|
||||
pub trait CpuIo {
|
||||
type Cpu: Cpu;
|
||||
type TranslateErr: Error + Send + 'static;
|
||||
|
||||
/// Returns physical address where the VM try to access.
|
||||
fn addr(&self) -> usize;
|
||||
fn buffer(&mut self) -> IoBuf;
|
||||
fn translate(&self, vaddr: usize) -> Result<usize, Self::TranslateErr>;
|
||||
fn cpu(&mut self) -> &mut Self::Cpu;
|
||||
}
|
||||
|
||||
/// Encapsulates a buffer for memory-mapped I/O.
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::vmm::hv::{Cpu, CpuExit, CpuIo, CpuStates, IoBuf};
|
||||
use crate::vmm::hv::{Cpu, CpuExit, CpuIo, CpuRun, CpuStates, IoBuf};
|
||||
use std::error::Error;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::{size_of, zeroed, MaybeUninit};
|
||||
@ -46,7 +46,6 @@ impl<'a> Cpu for WhpCpu<'a> {
|
||||
type States<'b> = WhpStates<'b, 'a> where Self: 'b;
|
||||
type GetStatesErr = StatesError;
|
||||
type Exit<'b> = WhpExit<'b, 'a> where Self: 'b;
|
||||
type RunErr = RunError;
|
||||
|
||||
fn states(&mut self) -> Result<Self::States<'_>, Self::GetStatesErr> {
|
||||
let mut values: [WHV_REGISTER_VALUE; REGISTERS] = unsafe { zeroed() };
|
||||
@ -70,6 +69,10 @@ impl<'a> Cpu for WhpCpu<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> CpuRun for WhpCpu<'a> {
|
||||
type RunErr = RunError;
|
||||
|
||||
fn run(&mut self) -> Result<Self::Exit<'_>, Self::RunErr> {
|
||||
let mut cx = MaybeUninit::<WHV_RUN_VP_EXIT_CONTEXT>::uninit();
|
||||
@ -279,6 +282,7 @@ pub struct WhpExit<'a, 'b> {
|
||||
}
|
||||
|
||||
impl<'a, 'b> CpuExit for WhpExit<'a, 'b> {
|
||||
type Cpu = WhpCpu<'b>;
|
||||
type Io = WhpIo<'a, 'b>;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
@ -301,6 +305,7 @@ pub struct WhpIo<'a, 'b> {
|
||||
}
|
||||
|
||||
impl<'a, 'b> CpuIo for WhpIo<'a, 'b> {
|
||||
type Cpu = WhpCpu<'b>;
|
||||
type TranslateErr = std::io::Error;
|
||||
|
||||
fn addr(&self) -> usize {
|
||||
@ -314,6 +319,10 @@ impl<'a, 'b> CpuIo for WhpIo<'a, 'b> {
|
||||
fn translate(&self, vaddr: usize) -> Result<usize, std::io::Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn cpu(&mut self) -> &mut Self::Cpu {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of [`Cpu::GetStatesErr`] and [`CpuStates::Err`].
|
||||
|
@ -1,12 +1,12 @@
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
use self::context::Context;
|
||||
use super::{Device, DeviceContext};
|
||||
use crate::vmm::cpu::CpuState;
|
||||
use crate::vmm::cpu::DebugStates;
|
||||
use crate::vmm::hv::Hypervisor;
|
||||
use crate::vmm::VmmEventHandler;
|
||||
use obconf::ConsoleMemory;
|
||||
use std::num::NonZero;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::{Condvar, Mutex};
|
||||
|
||||
mod context;
|
||||
|
||||
@ -40,7 +40,7 @@ impl<H: Hypervisor> Device<H> for Console {
|
||||
fn create_context<'a>(
|
||||
&'a self,
|
||||
hv: &'a H,
|
||||
_: &'a Mutex<CpuState>,
|
||||
_: &'a (Mutex<DebugStates>, Condvar),
|
||||
) -> Box<dyn DeviceContext<H::Cpu<'a>> + 'a> {
|
||||
Box::new(Context::new(self, hv))
|
||||
}
|
||||
|
@ -1,25 +1,105 @@
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
use super::Debugger;
|
||||
use crate::vmm::cpu::CpuState;
|
||||
use crate::vmm::cpu::DebugStates;
|
||||
use crate::vmm::hv::{Cpu, CpuExit, CpuIo};
|
||||
use crate::vmm::hw::{read_u8, DeviceContext, MmioError};
|
||||
use crate::vmm::VmmEvent;
|
||||
use obconf::{DebuggerMemory, StopReason};
|
||||
use std::error::Error;
|
||||
use std::mem::offset_of;
|
||||
use std::ops::Deref;
|
||||
use std::ptr::null_mut;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::{Condvar, Mutex};
|
||||
use thiserror::Error;
|
||||
|
||||
/// Implementation of [`DeviceContext`].
|
||||
pub struct Context<'a> {
|
||||
dev: &'a Debugger,
|
||||
state: &'a Mutex<CpuState>,
|
||||
debug: &'a (Mutex<DebugStates>, Condvar),
|
||||
}
|
||||
|
||||
impl<'a> Context<'a> {
|
||||
pub fn new(dev: &'a Debugger, state: &'a Mutex<CpuState>) -> Self {
|
||||
Self { dev, state }
|
||||
pub fn new(dev: &'a Debugger, debug: &'a (Mutex<DebugStates>, Condvar)) -> Self {
|
||||
Self { dev, debug }
|
||||
}
|
||||
|
||||
fn exec_stop<C: Cpu>(
|
||||
&mut self,
|
||||
exit: &mut <C::Exit<'_> as CpuExit>::Io,
|
||||
off: usize,
|
||||
) -> Result<(), ExecError> {
|
||||
// Read stop reason.
|
||||
let stop = read_u8(exit).map_err(|e| ExecError::ReadFailed(off, e))?;
|
||||
let stop: StopReason = stop.try_into().map_err(|_| ExecError::InvalidStop(stop))?;
|
||||
|
||||
self.set_states::<C>(exit, stop)?;
|
||||
|
||||
// Notify GUI. This will block until the debugger works are completed.
|
||||
let stop = match stop {
|
||||
StopReason::WaitForDebugger => null_mut(),
|
||||
};
|
||||
|
||||
unsafe { self.dev.event.invoke(VmmEvent::Breakpoint { stop }) };
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_states<C: Cpu>(
|
||||
&mut self,
|
||||
exit: &mut <C::Exit<'_> as CpuExit>::Io,
|
||||
r: StopReason,
|
||||
) -> Result<(), ExecError> {
|
||||
// Get states.
|
||||
let next = match r {
|
||||
StopReason::WaitForDebugger => Self::get_states(exit.cpu())?,
|
||||
};
|
||||
|
||||
// Set states.
|
||||
let mut s = self.debug.0.lock().unwrap();
|
||||
|
||||
if matches!(s.deref(), DebugStates::None) {
|
||||
*s = DebugStates::DebuggerOwned(next);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Wait until the debugger release us.
|
||||
assert!(matches!(s.deref(), DebugStates::Request));
|
||||
|
||||
*s = DebugStates::DebuggerOwned(next);
|
||||
|
||||
self.debug.1.notify_one();
|
||||
|
||||
loop {
|
||||
s = match s.deref() {
|
||||
DebugStates::DebuggerOwned(_) => self.debug.1.wait(s).unwrap(),
|
||||
DebugStates::CpuOwned(v) => {
|
||||
// Two possible cases here:
|
||||
//
|
||||
// 1. CpuController::debug_states waiting for us to unlock.
|
||||
// 2. CpuController::debug_states waiting for us to notify.
|
||||
//
|
||||
// Condvar::notify_one only wakeup the thread that already waiting.
|
||||
*s = DebugStates::DebuggerOwned(v.clone());
|
||||
self.debug.1.notify_one();
|
||||
break;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn get_states(
|
||||
_: &mut impl Cpu,
|
||||
) -> Result<gdbstub_arch::aarch64::reg::AArch64CoreRegs, ExecError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn get_states(_: &mut impl Cpu) -> Result<gdbstub_arch::x86::reg::X86_64CoreRegs, ExecError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,18 +109,7 @@ impl<'a, C: Cpu> DeviceContext<C> for Context<'a> {
|
||||
let off = exit.addr() - self.dev.addr;
|
||||
|
||||
if off == offset_of!(DebuggerMemory, stop) {
|
||||
// Read stop reason.
|
||||
let stop = read_u8(exit).map_err(|e| ExecError::ReadFailed(off, e))?;
|
||||
let stop: StopReason = stop
|
||||
.try_into()
|
||||
.map_err(|_| Box::new(ExecError::InvalidStop(stop)))?;
|
||||
|
||||
// Notify GUI.
|
||||
let stop = match stop {
|
||||
StopReason::WaitForDebugger => null_mut(),
|
||||
};
|
||||
|
||||
unsafe { self.dev.event.invoke(VmmEvent::Breakpoint { stop }) };
|
||||
self.exec_stop::<C>(exit, off)?;
|
||||
} else {
|
||||
return Err(Box::new(ExecError::UnknownField(off)));
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
use self::context::Context;
|
||||
use super::{Device, DeviceContext};
|
||||
use crate::vmm::cpu::CpuState;
|
||||
use crate::vmm::cpu::DebugStates;
|
||||
use crate::vmm::hv::Hypervisor;
|
||||
use crate::vmm::VmmEventHandler;
|
||||
use obconf::DebuggerMemory;
|
||||
use std::num::NonZero;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::{Condvar, Mutex};
|
||||
|
||||
mod context;
|
||||
|
||||
@ -40,8 +40,8 @@ impl<H: Hypervisor> Device<H> for Debugger {
|
||||
fn create_context<'a>(
|
||||
&'a self,
|
||||
_: &'a H,
|
||||
state: &'a Mutex<CpuState>,
|
||||
debug: &'a (Mutex<DebugStates>, Condvar),
|
||||
) -> Box<dyn DeviceContext<H::Cpu<'a>> + 'a> {
|
||||
Box::new(Context::new(self, state))
|
||||
Box::new(Context::new(self, debug))
|
||||
}
|
||||
}
|
||||
|
@ -3,13 +3,13 @@ pub use self::console::*;
|
||||
pub use self::debugger::*;
|
||||
pub use self::vmm::*;
|
||||
|
||||
use super::cpu::CpuState;
|
||||
use super::cpu::DebugStates;
|
||||
use super::hv::{Cpu, CpuExit, CpuIo, Hypervisor, IoBuf};
|
||||
use super::VmmEventHandler;
|
||||
use std::collections::BTreeMap;
|
||||
use std::error::Error;
|
||||
use std::num::NonZero;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::{Arc, Condvar, Mutex};
|
||||
use thiserror::Error;
|
||||
|
||||
mod console;
|
||||
@ -130,7 +130,7 @@ pub trait Device<H: Hypervisor>: Send + Sync {
|
||||
fn create_context<'a>(
|
||||
&'a self,
|
||||
hv: &'a H,
|
||||
state: &'a Mutex<CpuState>,
|
||||
debug: &'a (Mutex<DebugStates>, Condvar),
|
||||
) -> Box<dyn DeviceContext<H::Cpu<'a>> + 'a>;
|
||||
}
|
||||
|
||||
@ -139,7 +139,7 @@ pub trait DeviceContext<C: Cpu> {
|
||||
fn exec(&mut self, exit: &mut <C::Exit<'_> as CpuExit>::Io) -> Result<bool, Box<dyn Error>>;
|
||||
}
|
||||
|
||||
/// Struct to build virtual device map.
|
||||
/// Struct to build a map of virtual device.
|
||||
struct MapBuilder<H: Hypervisor> {
|
||||
map: BTreeMap<usize, Arc<dyn Device<H>>>,
|
||||
next: usize,
|
||||
|
@ -1,12 +1,12 @@
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
use self::context::Context;
|
||||
use super::{Device, DeviceContext};
|
||||
use crate::vmm::cpu::CpuState;
|
||||
use crate::vmm::cpu::DebugStates;
|
||||
use crate::vmm::hv::Hypervisor;
|
||||
use crate::vmm::VmmEventHandler;
|
||||
use obconf::VmmMemory;
|
||||
use std::num::NonZero;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::{Condvar, Mutex};
|
||||
|
||||
mod context;
|
||||
|
||||
@ -40,7 +40,7 @@ impl<H: Hypervisor> Device<H> for Vmm {
|
||||
fn create_context<'a>(
|
||||
&'a self,
|
||||
_: &'a H,
|
||||
_: &'a Mutex<CpuState>,
|
||||
_: &'a (Mutex<DebugStates>, Condvar),
|
||||
) -> Box<dyn DeviceContext<H::Cpu<'a>> + 'a> {
|
||||
Box::new(Context::new(self))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user