Skip to content

Commit

Permalink
wire up MSR space
Browse files Browse the repository at this point in the history
  • Loading branch information
gjcolombo committed Oct 14, 2024
1 parent 742e526 commit 363c9ec
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 11 deletions.
12 changes: 11 additions & 1 deletion bin/propolis-server/src/lib/vcpu_tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,17 @@ impl VcpuTasks {
Ok(exit) => exit,
};

entry = vcpu.process_vmexit(&exit).unwrap_or_else(|| {
let maybe_entry = match vcpu.process_vmexit(&exit) {
Ok(entry) => entry,
Err(e) => {
panic!(
"unhandled library error processing VM exit \
{exit:?}: {e}"
)
}
};

entry = maybe_entry.unwrap_or_else(|| {
match exit.kind {
VmExitKind::Inout(pio) => {
debug!(&log, "Unhandled pio {:x?}", pio;
Expand Down
2 changes: 1 addition & 1 deletion bin/propolis-standalone/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,7 @@ impl Instance {
Ok(exit) => exit,
};

entry = vcpu.process_vmexit(&exit).unwrap_or_else(|| {
entry = vcpu.process_vmexit(&exit).unwrap().unwrap_or_else(|| {
match exit.kind {
VmExitKind::Inout(pio) => {
slog::error!(
Expand Down
1 change: 1 addition & 0 deletions lib/propolis/src/exits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use bhyve_api::{
};

/// Describes the reason for exiting execution of a vCPU.
#[derive(Debug)]
pub struct VmExit {
/// The instruction pointer of the guest at the time of exit.
pub rip: u64,
Expand Down
89 changes: 82 additions & 7 deletions lib/propolis/src/vcpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ use crate::cpuid;
use crate::exits::*;
use crate::migrate::*;
use crate::mmio::MmioBus;
use crate::msr::Error as MsrError;
use crate::msr::MsrDisposition;
use crate::msr::MsrId;
use crate::msr::MsrSpace;
use crate::pio::PioBus;
use crate::tasks;
use crate::vmm::VmmHdl;
use anyhow::Context;
use cpuid_utils::{CpuidMapConversionError, CpuidSet};
use migrate::VcpuReadWrite;
use thiserror::Error;
Expand Down Expand Up @@ -53,6 +58,7 @@ pub struct Vcpu {
pub id: i32,
pub bus_mmio: Arc<MmioBus>,
pub bus_pio: Arc<PioBus>,
msr: Arc<MsrSpace>,
}

impl Vcpu {
Expand All @@ -62,8 +68,9 @@ impl Vcpu {
id: i32,
bus_mmio: Arc<MmioBus>,
bus_pio: Arc<PioBus>,
msr: Arc<MsrSpace>,
) -> Arc<Self> {
Arc::new(Self { hdl, id, bus_mmio, bus_pio })
Arc::new(Self { hdl, id, bus_mmio, bus_pio, msr })
}

/// ID of the virtual CPU.
Expand Down Expand Up @@ -392,10 +399,33 @@ impl Vcpu {
unsafe { self.hdl.ioctl(bhyve_api::VM_INJECT_NMI, &mut vm_nmi) }
}

/// Send a general protection fault (#GP) to the vcpu.
pub fn inject_gp(&self) -> Result<()> {
let mut vm_excp = bhyve_api::vm_exception {
cpuid: self.cpuid(),
vector: i32::from(bits::IDT_GP),
error_code: 0,
error_code_valid: 0,
restart_instruction: 1,
};
unsafe { self.hdl.ioctl(bhyve_api::VM_INJECT_EXCEPTION, &mut vm_excp) }
}

/// Process [`VmExit`] in the context of this vCPU, emitting a [`VmEntry`]
/// if the parameters of the exit were such that they could be handled.
pub fn process_vmexit(&self, exit: &VmExit) -> Option<VmEntry> {
match exit.kind {
///
/// # Return value
///
/// - `Ok(Some(entry))` if the exit was successfully handled. The payload
/// describes the parameters the caller should pass back to bhyve when
/// re-entering the guest.
/// - `Ok(None)` if the exit was not handled at this layer.
/// - `Err` if an internal error occurred while trying to handle the exit.
pub fn process_vmexit(
&self,
exit: &VmExit,
) -> anyhow::Result<Option<VmEntry>> {
let entry = match exit.kind {
VmExitKind::Bogus => Some(VmEntry::Run),
VmExitKind::Inout(io) => match io {
InoutReq::Out(io, val) => self
Expand Down Expand Up @@ -432,9 +462,50 @@ impl Vcpu {
})
.ok(),
},
VmExitKind::Rdmsr(_) | VmExitKind::Wrmsr(_, _) => {
// Leave it to the caller to emulate MSRs unhandled by the kernel
None
VmExitKind::Rdmsr(msr) => {
let mut out = 0u64;
match self.msr.rdmsr(MsrId(msr), &mut out) {
Ok(MsrDisposition::Handled) => {
self.set_reg(
bhyve_api::vm_reg_name::VM_REG_GUEST_RAX,
u64::from(out as u32),
)
.unwrap();
self.set_reg(
bhyve_api::vm_reg_name::VM_REG_GUEST_RDX,
out >> 32,
)
.unwrap();
Some(VmEntry::Run)
}
Ok(MsrDisposition::GpException) => {
self.inject_gp().unwrap();
Some(VmEntry::Run)
}
Err(MsrError::HandlerNotFound(_)) => None,
Err(e) => {
return Err(e).with_context(|| {
format!("handling RDMSR for MSR {msr:#x}")
})
}
}
}
VmExitKind::Wrmsr(msr, value) => {
match self.msr.wrmsr(MsrId(msr), value) {
Ok(MsrDisposition::Handled) => Some(VmEntry::Run),
Ok(MsrDisposition::GpException) => {
self.inject_gp().unwrap();
Some(VmEntry::Run)
}
Err(MsrError::HandlerNotFound(_)) => None,
Err(e) => {
return Err(e).with_context(|| {
format!(
"handling WRMSR for MSR {msr:#x}, value {value:#x}"
)
})
}
}
}
VmExitKind::Debug => {
// Until there is an interface to delay until a vCPU is no
Expand All @@ -450,7 +521,9 @@ impl Vcpu {
| VmExitKind::VmxError(_)
| VmExitKind::SvmError(_) => None,
_ => None,
}
};

Ok(entry)
}
}

Expand Down Expand Up @@ -1340,4 +1413,6 @@ pub mod migrate {
mod bits {
pub const MSR_DEBUGCTL: u32 = 0x1d9;
pub const MSR_EFER: u32 = 0xc0000080;

pub const IDT_GP: u8 = 0xd;
}
16 changes: 14 additions & 2 deletions lib/propolis/src/vmm/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use std::sync::Arc;

use crate::accessors::*;
use crate::mmio::MmioBus;
use crate::msr::MsrSpace;
use crate::pio::PioBus;
use crate::vcpu::{Vcpu, MAXCPU};
use crate::vmm::{create_vm, CreateOpts, PhysMap, VmmHdl};
Expand All @@ -31,6 +32,7 @@ pub struct Machine {
pub map_physmem: PhysMap,
pub bus_mmio: Arc<MmioBus>,
pub bus_pio: Arc<PioBus>,
pub msr: Arc<MsrSpace>,

pub acc_mem: MemAccessor,
pub acc_msi: MsiAccessor,
Expand Down Expand Up @@ -118,9 +120,15 @@ impl Machine {

let bus_mmio = Arc::new(MmioBus::new(MAX_PHYSMEM));
let bus_pio = Arc::new(PioBus::new());
let msr = Arc::new(MsrSpace::new());

let vcpus =
vec![Vcpu::new(hdl.clone(), 0, bus_mmio.clone(), bus_pio.clone())];
let vcpus = vec![Vcpu::new(
hdl.clone(),
0,
bus_mmio.clone(),
bus_pio.clone(),
msr.clone(),
)];

let acc_mem = MemAccessor::new(map.memctx());
let acc_msi = MsiAccessor::new(hdl.clone());
Expand All @@ -136,6 +144,7 @@ impl Machine {

bus_mmio,
bus_pio,
msr,

destroyed: AtomicBool::new(false),
})
Expand Down Expand Up @@ -238,6 +247,7 @@ impl Builder {

let bus_mmio = Arc::new(MmioBus::new(MAX_PHYSMEM));
let bus_pio = Arc::new(PioBus::new());
let msr = Arc::new(MsrSpace::new());

let acc_mem = MemAccessor::new(map.memctx());
let acc_msi = MsiAccessor::new(hdl.clone());
Expand All @@ -249,6 +259,7 @@ impl Builder {
i32::from(id),
bus_mmio.clone(),
bus_pio.clone(),
msr.clone(),
)
})
.collect();
Expand All @@ -264,6 +275,7 @@ impl Builder {

bus_mmio,
bus_pio,
msr,

destroyed: AtomicBool::new(false),
};
Expand Down

0 comments on commit 363c9ec

Please sign in to comment.