xref: /cloud-hypervisor/devices/src/legacy/debug_port.rs (revision 5e52729453cb62edbe4fb3a4aa24f8cca31e667e)
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