1#![cfg(target_arch = "x86_64")]
8
9use std::fmt::Debug;
10use std::sync::{Arc, Mutex};
11
12use acpi_tables::aml::AmlError;
13use acpi_tables::{Aml, aml};
14use libc::EFD_NONBLOCK;
15use vm_superio::Serial;
16use vmm_sys_util::eventfd::EventFd;
17
18use crate::Vm;
19use crate::devices::legacy::serial::SerialOut;
20use crate::devices::legacy::{EventFdTrigger, I8042Device, SerialDevice, SerialEventsWrapper};
21use crate::vstate::bus::BusError;
22
23#[derive(Debug, derive_more::From, thiserror::Error, displaydoc::Display)]
25pub enum LegacyDeviceError {
26 BusError(BusError),
28 EventFd(std::io::Error),
30}
31
32#[derive(Debug)]
36pub struct PortIODeviceManager {
37 pub stdio_serial: Arc<Mutex<SerialDevice>>,
39 pub i8042: Arc<Mutex<I8042Device>>,
41
42 pub com_evt_1_3: EventFdTrigger,
44 pub com_evt_2_4: EventFdTrigger,
46 pub kbd_evt: EventFd,
48}
49
50impl PortIODeviceManager {
51 const COM_EVT_1_3_GSI: u32 = 4;
55 const COM_EVT_2_4_GSI: u32 = 3;
59 const KBD_EVT_GSI: u32 = 1;
62 const SERIAL_PORT_ADDRESSES: [u64; 4] = [0x3f8, 0x2f8, 0x3e8, 0x2e8];
65 const SERIAL_PORT_SIZE: u64 = 0x8;
67 const I8042_KDB_DATA_REGISTER_ADDRESS: u64 = 0x060;
70 const I8042_KDB_DATA_REGISTER_SIZE: u64 = 0x5;
72
73 pub fn new(
75 stdio_serial: Arc<Mutex<SerialDevice>>,
76 i8042: Arc<Mutex<I8042Device>>,
77 ) -> Result<Self, LegacyDeviceError> {
78 let com_evt_1_3 = stdio_serial
79 .lock()
80 .expect("Poisoned lock")
81 .serial
82 .interrupt_evt()
83 .try_clone()?;
84 let com_evt_2_4 = EventFdTrigger::new(EventFd::new(EFD_NONBLOCK)?);
85 let kbd_evt = i8042
86 .lock()
87 .expect("Poisoned lock")
88 .kbd_interrupt_evt
89 .try_clone()?;
90
91 Ok(PortIODeviceManager {
92 stdio_serial,
93 i8042,
94 com_evt_1_3,
95 com_evt_2_4,
96 kbd_evt,
97 })
98 }
99
100 pub fn register_devices(&mut self, vm: &Vm) -> Result<(), LegacyDeviceError> {
102 let serial_2_4 = Arc::new(Mutex::new(SerialDevice {
103 serial: Serial::with_events(
104 self.com_evt_2_4.try_clone()?.try_clone()?,
105 SerialEventsWrapper {
106 buffer_ready_event_fd: None,
107 },
108 SerialOut::Sink,
109 ),
110 input: None,
111 }));
112 let serial_1_3 = Arc::new(Mutex::new(SerialDevice {
113 serial: Serial::with_events(
114 self.com_evt_1_3.try_clone()?.try_clone()?,
115 SerialEventsWrapper {
116 buffer_ready_event_fd: None,
117 },
118 SerialOut::Sink,
119 ),
120 input: None,
121 }));
122
123 let io_bus = &vm.pio_bus;
124 io_bus.insert(
125 self.stdio_serial.clone(),
126 Self::SERIAL_PORT_ADDRESSES[0],
127 Self::SERIAL_PORT_SIZE,
128 )?;
129 io_bus.insert(
130 serial_2_4.clone(),
131 Self::SERIAL_PORT_ADDRESSES[1],
132 Self::SERIAL_PORT_SIZE,
133 )?;
134 io_bus.insert(
135 serial_1_3,
136 Self::SERIAL_PORT_ADDRESSES[2],
137 Self::SERIAL_PORT_SIZE,
138 )?;
139 io_bus.insert(
140 serial_2_4,
141 Self::SERIAL_PORT_ADDRESSES[3],
142 Self::SERIAL_PORT_SIZE,
143 )?;
144 io_bus.insert(
145 self.i8042.clone(),
146 Self::I8042_KDB_DATA_REGISTER_ADDRESS,
147 Self::I8042_KDB_DATA_REGISTER_SIZE,
148 )?;
149
150 vm.register_irq(&self.com_evt_1_3, Self::COM_EVT_1_3_GSI)
151 .map_err(|e| {
152 LegacyDeviceError::EventFd(std::io::Error::from_raw_os_error(e.errno()))
153 })?;
154 vm.register_irq(&self.com_evt_2_4, Self::COM_EVT_2_4_GSI)
155 .map_err(|e| {
156 LegacyDeviceError::EventFd(std::io::Error::from_raw_os_error(e.errno()))
157 })?;
158 vm.register_irq(&self.kbd_evt, Self::KBD_EVT_GSI)
159 .map_err(|e| {
160 LegacyDeviceError::EventFd(std::io::Error::from_raw_os_error(e.errno()))
161 })?;
162
163 Ok(())
164 }
165
166 pub(crate) fn append_aml_bytes(bytes: &mut Vec<u8>) -> Result<(), AmlError> {
167 let gsi = [
169 Self::COM_EVT_1_3_GSI,
170 Self::COM_EVT_2_4_GSI,
171 Self::COM_EVT_1_3_GSI,
172 Self::COM_EVT_2_4_GSI,
173 ];
174 for com in 0u8..4 {
175 aml::Device::new(
177 format!("_SB_.COM{}", com + 1).as_str().try_into()?,
178 vec![
179 &aml::Name::new("_HID".try_into()?, &aml::EisaName::new("PNP0501")?)?,
180 &aml::Name::new("_UID".try_into()?, &com)?,
181 &aml::Name::new("_DDN".try_into()?, &format!("COM{}", com + 1))?,
182 &aml::Name::new(
183 "_CRS".try_into().unwrap(),
184 &aml::ResourceTemplate::new(vec![
185 &aml::Interrupt::new(true, true, false, false, gsi[com as usize]),
186 &aml::Io::new(
187 PortIODeviceManager::SERIAL_PORT_ADDRESSES[com as usize]
188 .try_into()
189 .unwrap(),
190 PortIODeviceManager::SERIAL_PORT_ADDRESSES[com as usize]
191 .try_into()
192 .unwrap(),
193 1,
194 PortIODeviceManager::SERIAL_PORT_SIZE.try_into().unwrap(),
195 ),
196 ]),
197 )?,
198 ],
199 )
200 .append_aml_bytes(bytes)?;
201 }
202 aml::Device::new(
204 "_SB_.PS2_".try_into()?,
205 vec![
206 &aml::Name::new("_HID".try_into()?, &aml::EisaName::new("PNP0303")?)?,
207 &aml::Method::new(
208 "_STA".try_into()?,
209 0,
210 false,
211 vec![&aml::Return::new(&0x0fu8)],
212 ),
213 &aml::Name::new(
214 "_CRS".try_into()?,
215 &aml::ResourceTemplate::new(vec![
216 &aml::Io::new(
217 PortIODeviceManager::I8042_KDB_DATA_REGISTER_ADDRESS
218 .try_into()
219 .unwrap(),
220 PortIODeviceManager::I8042_KDB_DATA_REGISTER_ADDRESS
221 .try_into()
222 .unwrap(),
223 1u8,
224 1u8,
225 ),
226 &aml::Io::new(0x0064, 0x0064, 1u8, 1u8),
228 &aml::Interrupt::new(true, true, false, false, Self::KBD_EVT_GSI),
229 ]),
230 )?,
231 ],
232 )
233 .append_aml_bytes(bytes)
234 }
235}
236
237#[cfg(test)]
238mod tests {
239 use super::*;
240 use crate::vstate::vm::tests::setup_vm_with_memory;
241
242 #[test]
243 fn test_register_legacy_devices() {
244 let (_, vm) = setup_vm_with_memory(0x1000);
245 vm.setup_irqchip().unwrap();
246 let mut ldm = PortIODeviceManager::new(
247 Arc::new(Mutex::new(SerialDevice {
248 serial: Serial::with_events(
249 EventFdTrigger::new(EventFd::new(EFD_NONBLOCK).unwrap()),
250 SerialEventsWrapper {
251 buffer_ready_event_fd: None,
252 },
253 SerialOut::Sink,
254 ),
255 input: None,
256 })),
257 Arc::new(Mutex::new(
258 I8042Device::new(EventFd::new(libc::EFD_NONBLOCK).unwrap()).unwrap(),
259 )),
260 )
261 .unwrap();
262 ldm.register_devices(&vm).unwrap();
263 }
264}