1 // Copyright © 2022 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 6 use std::fmt; 7 use std::time::Instant; 8 9 use vm_device::BusDevice; 10 11 /// Debug I/O port, see: 12 /// https://www.intel.com/content/www/us/en/support/articles/000005500/boards-and-kits.html 13 /// 14 /// Since we're not a physical platform, we can freely assign code ranges for 15 /// debugging specific parts of our virtual platform. 16 pub enum DebugIoPortRange { 17 Firmware, 18 Bootloader, 19 Kernel, 20 Userspace, 21 Custom, 22 } 23 24 #[cfg(target_arch = "x86_64")] 25 const DEBUG_IOPORT_PREFIX: &str = "Debug I/O port"; 26 27 #[cfg(target_arch = "x86_64")] 28 impl DebugIoPortRange { from_u8(value: u8) -> DebugIoPortRange29 fn from_u8(value: u8) -> DebugIoPortRange { 30 match value { 31 0x00..=0x1f => DebugIoPortRange::Firmware, 32 0x20..=0x3f => DebugIoPortRange::Bootloader, 33 0x40..=0x5f => DebugIoPortRange::Kernel, 34 0x60..=0x7f => DebugIoPortRange::Userspace, 35 _ => DebugIoPortRange::Custom, 36 } 37 } 38 } 39 40 #[cfg(target_arch = "x86_64")] 41 impl fmt::Display for DebugIoPortRange { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result42 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 43 match self { 44 DebugIoPortRange::Firmware => write!(f, "{DEBUG_IOPORT_PREFIX}: Firmware"), 45 DebugIoPortRange::Bootloader => write!(f, "{DEBUG_IOPORT_PREFIX}: Bootloader"), 46 DebugIoPortRange::Kernel => write!(f, "{DEBUG_IOPORT_PREFIX}: Kernel"), 47 DebugIoPortRange::Userspace => write!(f, "{DEBUG_IOPORT_PREFIX}: Userspace"), 48 DebugIoPortRange::Custom => write!(f, "{DEBUG_IOPORT_PREFIX}: Custom"), 49 } 50 } 51 } 52 53 pub struct DebugPort { 54 timestamp: Instant, 55 } 56 57 impl DebugPort { new(timestamp: Instant) -> Self58 pub fn new(timestamp: Instant) -> Self { 59 Self { timestamp } 60 } 61 } 62 63 impl BusDevice for DebugPort { read(&mut self, _base: u64, _offset: u64, _data: &mut [u8])64 fn read(&mut self, _base: u64, _offset: u64, _data: &mut [u8]) { 65 error!("Invalid read to debug port") 66 } 67 write( &mut self, _base: u64, _offset: u64, data: &[u8], ) -> Option<std::sync::Arc<std::sync::Barrier>>68 fn write( 69 &mut self, 70 _base: u64, 71 _offset: u64, 72 data: &[u8], 73 ) -> Option<std::sync::Arc<std::sync::Barrier>> { 74 let elapsed = self.timestamp.elapsed(); 75 76 let code = data[0]; 77 warn!( 78 "[{} code 0x{:x}] {}.{:>06} seconds", 79 DebugIoPortRange::from_u8(code), 80 code, 81 elapsed.as_secs(), 82 elapsed.as_micros() 83 ); 84 85 None 86 } 87 } 88