From 48a9300667395453137b07e63e2dbcacd6a5464a Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 14 Aug 2019 14:10:29 +0200 Subject: [PATCH] vmm: Log 0x80 IO port writes The 0x80 IO port is typically used for BIOS debugging and testing on bare metal x86 platforms. We use that port and its dedicated 16 debug codes to time and track the guest boot process. Fixes #63 Signed-off-by: Samuel Ortiz --- vmm/src/vm.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index bfd255151..32ed4a0a2 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -47,7 +47,7 @@ use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::{AsRawFd, RawFd}; use std::ptr::null_mut; use std::sync::{Arc, Barrier, Mutex}; -use std::{result, str, thread}; +use std::{fmt, result, str, thread}; use vfio::{VfioDevice, VfioPciDevice, VfioPciError}; use vm_allocator::{GsiApic, SystemAllocator}; use vm_memory::guest_memory::FileOffset; @@ -76,6 +76,48 @@ const KERNEL_64BIT_ENTRY_OFFSET: u64 = 0x200; const IOAPIC_RANGE_ADDR: u64 = 0xfec0_0000; const IOAPIC_RANGE_SIZE: u64 = 0x20; +// Debug I/O port +#[cfg(target_arch = "x86_64")] +const DEBUG_IOPORT: u16 = 0x80; +const DEBUG_IOPORT_PREFIX: &str = "Debug I/O port"; + +/// Debug I/O port, see: +/// https://www.intel.com/content/www/us/en/support/articles/000005500/boards-and-kits.html +/// +/// Since we're not a physical platform, we can freely assign code ranges for +/// debugging specific parts of our virtual platform. +pub enum DebugIoPortRange { + Firmware, + Bootloader, + Kernel, + Userspace, + Custom, +} + +impl DebugIoPortRange { + fn from_u8(value: u8) -> DebugIoPortRange { + match value { + 0x00...0x1f => DebugIoPortRange::Firmware, + 0x20...0x3f => DebugIoPortRange::Bootloader, + 0x40...0x5f => DebugIoPortRange::Kernel, + 0x60...0x7f => DebugIoPortRange::Userspace, + _ => DebugIoPortRange::Custom, + } + } +} + +impl fmt::Display for DebugIoPortRange { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + DebugIoPortRange::Firmware => write!(f, "{}: Firmware", DEBUG_IOPORT_PREFIX), + DebugIoPortRange::Bootloader => write!(f, "{}: Bootloader", DEBUG_IOPORT_PREFIX), + DebugIoPortRange::Kernel => write!(f, "{}: Kernel", DEBUG_IOPORT_PREFIX), + DebugIoPortRange::Userspace => write!(f, "{}: Userspace", DEBUG_IOPORT_PREFIX), + DebugIoPortRange::Custom => write!(f, "{}: Custom", DEBUG_IOPORT_PREFIX), + } + } +} + /// Errors associated with VM management #[derive(Debug)] pub enum Error { @@ -423,6 +465,9 @@ impl Vcpu { Ok(()) } VcpuExit::IoOut(addr, data) => { + if addr == DEBUG_IOPORT && data.len() == 1 { + self.log_debug_ioport(data[0]); + } self.io_bus.write(u64::from(addr), data); Ok(()) } @@ -455,6 +500,11 @@ impl Vcpu { }, } } + + // Log debug io port codes. + fn log_debug_ioport(&self, code: u8) { + debug!("{} (code 0x{:x})", DebugIoPortRange::from_u8(code), code); + } } struct VmInfo<'a> {