Skip to content

Commit

Permalink
Merge #144
Browse files Browse the repository at this point in the history
144: Factor out VirtualCPU::r#continue r=jounathaen a=mkroening

Depends on #143.

Co-authored-by: Martin Kröning <mkroening@posteo.net>
  • Loading branch information
bors[bot] and mkroening committed Aug 21, 2021
2 parents e264777 + 150a4ea commit b955154
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 37 deletions.
62 changes: 37 additions & 25 deletions src/linux/vcpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::linux::virtio::*;
use crate::linux::KVM;
use crate::paging::*;
use crate::vm::HypervisorResult;
use crate::vm::VcpuStopReason;
use crate::vm::VirtualCPU;
use kvm_bindings::*;
use kvm_ioctls::{VcpuExit, VcpuFd};
Expand All @@ -26,6 +27,7 @@ pub struct UhyveCPU {
kernel_path: PathBuf,
tx: Option<std::sync::mpsc::SyncSender<usize>>,
virtio_device: Arc<Mutex<VirtioNetPciDevice>>,
pci_addr: Option<u32>,
pub dbg: Option<Arc<Mutex<DebugManager>>>,
}

Expand All @@ -46,6 +48,7 @@ impl UhyveCPU {
kernel_path,
tx,
virtio_device,
pci_addr: None,
dbg,
}
}
Expand Down Expand Up @@ -273,16 +276,7 @@ impl VirtualCPU for UhyveCPU {
(entry & ((!0usize) << PAGE_BITS)) | (addr & !((!0usize) << PAGE_BITS))
}

fn run(&mut self) -> HypervisorResult<i32> {
//self.print_registers();

// Pause first CPU before first execution, so we have time to attach debugger
if self.id == 0 {
self.gdb_handle_exception(None);
}

let mut pci_addr: u32 = 0;
let mut pci_addr_set: bool = false;
fn r#continue(&mut self) -> HypervisorResult<VcpuStopReason> {
loop {
let exitreason = self.vcpu.run()?;
match exitreason {
Expand All @@ -291,18 +285,19 @@ impl VirtualCPU for UhyveCPU {
debug!("{:?}", VcpuExit::Hlt);
}
VcpuExit::Shutdown => {
return Ok(0);
return Ok(VcpuStopReason::Exit(0));
}
VcpuExit::IoIn(port, addr) => match port {
PCI_CONFIG_DATA_PORT => {
if pci_addr & 0x1ff800 == 0 && pci_addr_set {
let virtio_device = self.virtio_device.lock().unwrap();
virtio_device.handle_read(pci_addr & 0x3ff, addr);
if let Some(pci_addr) = self.pci_addr {
if pci_addr & 0x1ff800 == 0 {
let virtio_device = self.virtio_device.lock().unwrap();
virtio_device.handle_read(pci_addr & 0x3ff, addr);
} else {
unsafe { *(addr.as_ptr() as *mut u32) = 0xffffffff };
}
} else {
#[allow(clippy::cast_ptr_alignment)]
unsafe {
*(addr.as_ptr() as *mut u32) = 0xffffffff
};
unsafe { *(addr.as_ptr() as *mut u32) = 0xffffffff };
}
}
PCI_CONFIG_ADDRESS_PORT => {}
Expand Down Expand Up @@ -359,7 +354,9 @@ impl VirtualCPU for UhyveCPU {
UHYVE_PORT_EXIT => {
let data_addr: usize =
unsafe { (*(addr.as_ptr() as *const u32)) as usize };
return Ok(self.exit(self.host_address(data_addr)));
return Ok(VcpuStopReason::Exit(
self.exit(self.host_address(data_addr)),
));
}
UHYVE_PORT_OPEN => {
let data_addr: usize =
Expand Down Expand Up @@ -393,14 +390,15 @@ impl VirtualCPU for UhyveCPU {
}
//TODO:
PCI_CONFIG_DATA_PORT => {
if pci_addr & 0x1ff800 == 0 && pci_addr_set {
let mut virtio_device = self.virtio_device.lock().unwrap();
virtio_device.handle_write(pci_addr & 0x3ff, addr);
if let Some(pci_addr) = self.pci_addr {
if pci_addr & 0x1ff800 == 0 {
let mut virtio_device = self.virtio_device.lock().unwrap();
virtio_device.handle_write(pci_addr & 0x3ff, addr);
}
}
}
PCI_CONFIG_ADDRESS_PORT => {
pci_addr = unsafe { *(addr.as_ptr() as *const u32) };
pci_addr_set = true;
self.pci_addr = Some(unsafe { *(addr.as_ptr() as *const u32) });
}
VIRTIO_PCI_STATUS => {
let mut virtio_device = self.virtio_device.lock().unwrap();
Expand Down Expand Up @@ -429,7 +427,7 @@ impl VirtualCPU for UhyveCPU {
}
VcpuExit::Debug => {
info!("Caught Debug Interrupt! {:?}", exitreason);
self.gdb_handle_exception(Some(VcpuExit::Debug));
return Ok(VcpuStopReason::Debug);
}
VcpuExit::InternalError => {
panic!("{:?}", VcpuExit::InternalError)
Expand All @@ -441,6 +439,20 @@ impl VirtualCPU for UhyveCPU {
}
}

fn run(&mut self) -> HypervisorResult<i32> {
// Pause first CPU before first execution, so we have time to attach debugger
if self.id == 0 {
self.gdb_handle_exception(None);
}

loop {
match self.r#continue()? {
VcpuStopReason::Debug => self.gdb_handle_exception(Some(VcpuExit::Debug)),
VcpuStopReason::Exit(code) => break Ok(code),
}
}
}

fn print_registers(&self) {
let regs = self.vcpu.get_regs().unwrap();
let sregs = self.vcpu.get_sregs().unwrap();
Expand Down
33 changes: 21 additions & 12 deletions src/macos/vcpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::debug_manager::DebugManager;
use crate::macos::ioapic::IoApic;
use crate::paging::*;
use crate::vm::HypervisorResult;
use crate::vm::VcpuStopReason;
use crate::vm::VirtualCPU;
use burst::x86::{disassemble_64, InstructionOperation, OperandType};
use lazy_static::lazy_static;
Expand Down Expand Up @@ -577,15 +578,7 @@ impl VirtualCPU for UhyveCPU {
(entry & ((!0usize) << PAGE_BITS)) | (addr & !((!0usize) << PAGE_BITS))
}

fn run(&mut self) -> HypervisorResult<i32> {
//self.print_registers();

// Pause first CPU before first execution, so we have time to attach debugger
if self.id == 0 {
self.gdb_handle_exception(false);
}

debug!("Run vCPU {}", self.id);
fn r#continue(&mut self) -> HypervisorResult<VcpuStopReason> {
loop {
/*if self.extint_pending == true {
let irq_info = self.vcpu.read_vmcs(VMCS_CTRL_VMENTRY_IRQ_INFO)?;
Expand Down Expand Up @@ -623,7 +616,7 @@ impl VirtualCPU for UhyveCPU {
irq_vec
);
debug!("Handle breakpoint exception");
self.gdb_handle_exception(true);
return Ok(VcpuStopReason::Debug);
}
vmx_exit::VMX_REASON_CPUID => {
self.emulate_cpuid(rip)?;
Expand Down Expand Up @@ -661,7 +654,7 @@ impl VirtualCPU for UhyveCPU {

match port {
SHUTDOWN_PORT => {
return Ok(0);
return Ok(VcpuStopReason::Exit(0));
}
UHYVE_UART_PORT => {
let al = (self.vcpu.read_register(&x86Reg::RAX)? & 0xFF) as u8;
Expand All @@ -684,7 +677,9 @@ impl VirtualCPU for UhyveCPU {
UHYVE_PORT_EXIT => {
let data_addr: u64 =
self.vcpu.read_register(&x86Reg::RAX)? & 0xFFFFFFFF;
return Ok(self.exit(self.host_address(data_addr as usize)));
return Ok(VcpuStopReason::Exit(
self.exit(self.host_address(data_addr as usize)),
));
}
UHYVE_PORT_OPEN => {
let data_addr: u64 =
Expand Down Expand Up @@ -735,6 +730,20 @@ impl VirtualCPU for UhyveCPU {
}
}

fn run(&mut self) -> HypervisorResult<i32> {
// Pause first CPU before first execution, so we have time to attach debugger
if self.id == 0 {
self.gdb_handle_exception(false);
}

loop {
match self.r#continue()? {
VcpuStopReason::Debug => self.gdb_handle_exception(true),
VcpuStopReason::Exit(code) => break Ok(code),
}
}
}

fn print_registers(&self) {
println!("\nDump state of CPU {}", self.id);
println!("VMCS:");
Expand Down
16 changes: 16 additions & 0 deletions src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,17 +226,33 @@ pub enum LoadKernelError {

pub type LoadKernelResult<T> = Result<T, LoadKernelError>;

/// Reasons for vCPU exits.
pub enum VcpuStopReason {
/// The vCPU stopped for debugging.
Debug,
/// The vCPU exited with the specified exit code.
Exit(i32),
}

pub trait VirtualCPU {
/// Initialize the cpu to start running the code ad entry_point.
fn init(&mut self, entry_point: u64) -> HypervisorResult<()>;

/// Continues execution.
fn r#continue(&mut self) -> HypervisorResult<VcpuStopReason>;

/// Start the execution of the CPU. The function will run until it crashes (`Err`) or terminate with an exit code (`Ok`).
fn run(&mut self) -> HypervisorResult<i32>;

/// Prints the VCPU's registers to stdout.
fn print_registers(&self);

/// Translates an address from the VM's physical space into the hosts virtual space.
fn host_address(&self, addr: usize) -> usize;

/// Looks up the guests pagetable and translates a guest's virtual address to a guest's physical address.
fn virt_to_phys(&self, addr: usize) -> usize;

/// Returns the (host) path of the kernel binary.
fn kernel_path(&self) -> PathBuf;

Expand Down

0 comments on commit b955154

Please sign in to comment.