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