1use std::io;
9use std::num::Wrapping;
10use std::sync::{Arc, Barrier};
11
12use log::warn;
13use serde::Serialize;
14use vmm_sys_util::eventfd::EventFd;
15
16use crate::logger::{IncMetric, SharedIncMetric, error};
17use crate::vstate::bus::BusDevice;
18
19#[derive(Debug, thiserror::Error, displaydoc::Display)]
21pub enum I8042Error {
22 InternalBufferFull,
24 KbdInterruptDisabled,
26 KbdInterruptFailure(io::Error),
28}
29
30#[derive(Debug, Serialize)]
32pub(super) struct I8042DeviceMetrics {
33 error_count: SharedIncMetric,
35 missed_read_count: SharedIncMetric,
37 missed_write_count: SharedIncMetric,
39 read_count: SharedIncMetric,
41 reset_count: SharedIncMetric,
43 write_count: SharedIncMetric,
45}
46impl I8042DeviceMetrics {
47 const fn new() -> Self {
49 Self {
50 error_count: SharedIncMetric::new(),
51 missed_read_count: SharedIncMetric::new(),
52 missed_write_count: SharedIncMetric::new(),
53 read_count: SharedIncMetric::new(),
54 reset_count: SharedIncMetric::new(),
55 write_count: SharedIncMetric::new(),
56 }
57 }
58}
59
60pub(super) static METRICS: I8042DeviceMetrics = I8042DeviceMetrics::new();
62
63const OFS_STATUS: u64 = 4;
65
66const OFS_DATA: u64 = 0;
68
69const CMD_READ_CTR: u8 = 0x20; const CMD_WRITE_CTR: u8 = 0x60; const CMD_READ_OUTP: u8 = 0xD0; const CMD_WRITE_OUTP: u8 = 0xD1; const CMD_RESET_CPU: u8 = 0xFE; const SB_OUT_DATA_AVAIL: u8 = 0x0001; const SB_I8042_CMD_DATA: u8 = 0x0008; const SB_KBD_ENABLED: u8 = 0x0010; const CB_KBD_INT: u8 = 0x0001; const CB_POST_OK: u8 = 0x0004; const KEY_CTRL: u16 = 0x0014;
88const KEY_ALT: u16 = 0x0011;
89const KEY_DEL: u16 = 0xE071;
90
91const BUF_SIZE: usize = 16;
93
94#[derive(Debug)]
96pub struct I8042Device {
97 reset_evt: EventFd,
99
100 pub kbd_interrupt_evt: EventFd,
102
103 status: u8,
105
106 control: u8,
108
109 outp: u8,
111
112 cmd: u8,
114
115 buf: [u8; BUF_SIZE],
117 bhead: Wrapping<usize>,
118 btail: Wrapping<usize>,
119}
120
121impl I8042Device {
122 pub fn new(reset_evt: EventFd) -> Result<I8042Device, std::io::Error> {
124 Ok(I8042Device {
125 reset_evt,
126 kbd_interrupt_evt: EventFd::new(libc::EFD_NONBLOCK)?,
127 control: CB_POST_OK | CB_KBD_INT,
128 cmd: 0,
129 outp: 0,
130 status: SB_KBD_ENABLED,
131 buf: [0; BUF_SIZE],
132 bhead: Wrapping(0),
133 btail: Wrapping(0),
134 })
135 }
136
137 #[inline]
139 pub fn trigger_ctrl_alt_del(&mut self) -> Result<(), I8042Error> {
140 if BUF_SIZE - self.buf_len() < 4 {
143 return Err(I8042Error::InternalBufferFull);
144 }
145 self.trigger_key(KEY_CTRL)?;
146 self.trigger_key(KEY_ALT)?;
147 self.trigger_key(KEY_DEL)?;
148 Ok(())
149 }
150
151 fn trigger_kbd_interrupt(&self) -> Result<(), I8042Error> {
152 if (self.control & CB_KBD_INT) == 0 {
153 warn!("Failed to trigger i8042 kbd interrupt (disabled by guest OS)");
154 return Err(I8042Error::KbdInterruptDisabled);
155 }
156 self.kbd_interrupt_evt
157 .write(1)
158 .map_err(I8042Error::KbdInterruptFailure)
159 }
160
161 fn trigger_key(&mut self, key: u16) -> Result<(), I8042Error> {
162 if key & 0xff00 != 0 {
163 if BUF_SIZE - self.buf_len() < 2 {
165 return Err(I8042Error::InternalBufferFull);
166 }
167 self.push_byte((key >> 8) as u8)?;
168 }
169 self.push_byte((key & 0xff) as u8)?;
170
171 match self.trigger_kbd_interrupt() {
172 Ok(_) | Err(I8042Error::KbdInterruptDisabled) => Ok(()),
173 Err(err) => Err(err),
174 }
175 }
176
177 #[inline]
178 fn push_byte(&mut self, byte: u8) -> Result<(), I8042Error> {
179 self.status |= SB_OUT_DATA_AVAIL;
180 if self.buf_len() == BUF_SIZE {
181 return Err(I8042Error::InternalBufferFull);
182 }
183 self.buf[self.btail.0 % BUF_SIZE] = byte;
184 self.btail += Wrapping(1usize);
185 Ok(())
186 }
187
188 #[inline]
189 fn pop_byte(&mut self) -> Option<u8> {
190 if self.buf_len() == 0 {
191 return None;
192 }
193 let res = self.buf[self.bhead.0 % BUF_SIZE];
194 self.bhead += Wrapping(1usize);
195 if self.buf_len() == 0 {
196 self.status &= !SB_OUT_DATA_AVAIL;
197 }
198 Some(res)
199 }
200
201 #[inline]
202 fn flush_buf(&mut self) {
203 self.bhead = Wrapping(0usize);
204 self.btail = Wrapping(0usize);
205 self.status &= !SB_OUT_DATA_AVAIL;
206 }
207
208 #[inline]
209 fn buf_len(&self) -> usize {
210 (self.btail - self.bhead).0
211 }
212}
213
214impl BusDevice for I8042Device {
215 fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
216 if data.len() != 1 {
218 METRICS.missed_read_count.inc();
219 return;
220 }
221
222 let mut read_ok = true;
223
224 match offset {
225 OFS_STATUS => data[0] = self.status,
226 OFS_DATA => {
227 data[0] = self.pop_byte().unwrap_or(0);
230
231 if (self.status & SB_OUT_DATA_AVAIL) != 0
235 && let Err(I8042Error::KbdInterruptFailure(err)) = self.trigger_kbd_interrupt()
236 {
237 warn!("Failed to trigger i8042 kbd interrupt {:?}", err);
238 }
239 }
240 _ => read_ok = false,
241 }
242 if read_ok {
243 METRICS.read_count.add(data.len() as u64);
244 } else {
245 METRICS.missed_read_count.inc();
246 }
247 }
248
249 fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
250 if data.len() != 1 {
252 METRICS.missed_write_count.inc();
253 return None;
254 }
255
256 let mut write_ok = true;
257
258 match offset {
259 OFS_STATUS if data[0] == CMD_RESET_CPU => {
260 if let Err(err) = self.reset_evt.write(1) {
264 error!("Failed to trigger i8042 reset event: {:?}", err);
265 METRICS.error_count.inc();
266 }
267 METRICS.reset_count.inc();
268 }
269 OFS_STATUS if data[0] == CMD_READ_CTR => {
270 self.flush_buf();
274 let control = self.control;
275 self.push_byte(control).unwrap();
277 }
278 OFS_STATUS if data[0] == CMD_WRITE_CTR => {
279 self.flush_buf();
285 self.status |= SB_I8042_CMD_DATA;
286 self.cmd = data[0];
287 }
288 OFS_STATUS if data[0] == CMD_READ_OUTP => {
289 self.flush_buf();
293 let outp = self.outp;
294 self.push_byte(outp).unwrap();
296 }
297 OFS_STATUS if data[0] == CMD_WRITE_OUTP => {
298 self.status |= SB_I8042_CMD_DATA;
302 self.cmd = data[0];
303 }
304 OFS_DATA if (self.status & SB_I8042_CMD_DATA) != 0 => {
305 match self.cmd {
311 CMD_WRITE_CTR => self.control = data[0],
312 CMD_WRITE_OUTP => self.outp = data[0],
313 _ => (),
314 }
315 self.status &= !SB_I8042_CMD_DATA;
316 }
317 OFS_DATA => {
318 self.flush_buf();
323 self.push_byte(0xFA).unwrap();
325 if let Err(I8042Error::KbdInterruptFailure(err)) = self.trigger_kbd_interrupt() {
326 warn!("Failed to trigger i8042 kbd interrupt {:?}", err);
327 }
328 }
329 _ => {
330 write_ok = false;
331 }
332 }
333
334 if write_ok {
335 METRICS.write_count.inc();
336 } else {
337 METRICS.missed_write_count.inc();
338 }
339
340 None
341 }
342}
343
344#[cfg(test)]
345mod tests {
346
347 use super::*;
348
349 impl PartialEq for I8042Error {
350 fn eq(&self, other: &I8042Error) -> bool {
351 self.to_string() == other.to_string()
352 }
353 }
354
355 #[test]
356 fn test_i8042_read_write_and_event() {
357 let mut i8042 = I8042Device::new(EventFd::new(libc::EFD_NONBLOCK).unwrap()).unwrap();
358 let reset_evt = i8042.reset_evt.try_clone().unwrap();
359
360 let mut data = [1, 2];
362 i8042.read(0x0, 0, &mut data);
363 assert_eq!(data, [1, 2]);
364 i8042.read(0x0, 1, &mut data);
365 assert_eq!(data, [1, 2]);
366
367 reset_evt.write(1).unwrap();
371 let mut data = [CMD_RESET_CPU];
372 i8042.write(0x0, OFS_STATUS, &data);
373 assert_eq!(reset_evt.read().unwrap(), 2);
374
375 i8042.read(0x0, 1, &mut data);
377 assert_eq!(data[0], CMD_RESET_CPU);
378
379 let before = METRICS.missed_write_count.count();
381 i8042.write(0x0, 1, &data);
383 data[0] = CMD_RESET_CPU + 1;
385 i8042.write(0x0, 1, &data);
386 let data = [CMD_RESET_CPU; 2];
388 i8042.write(0x0, 1, &data);
389 assert_eq!(METRICS.missed_write_count.count(), before + 3);
390 }
391
392 #[test]
393 fn test_i8042_commands() {
394 let mut i8042 = I8042Device::new(EventFd::new(libc::EFD_NONBLOCK).unwrap()).unwrap();
395 let mut data = [1];
396
397 data[0] = CMD_WRITE_CTR;
399 i8042.write(0x0, OFS_STATUS, &data);
400 assert_ne!(i8042.status & SB_I8042_CMD_DATA, 0);
401 data[0] = 0x52;
402 i8042.write(0x0, OFS_DATA, &data);
403 data[0] = CMD_READ_CTR;
404 i8042.write(0x0, OFS_STATUS, &data);
405 assert_ne!(i8042.status & SB_OUT_DATA_AVAIL, 0);
406 i8042.read(0x0, OFS_DATA, &mut data);
407 assert_eq!(data[0], 0x52);
408
409 data[0] = CMD_WRITE_OUTP;
411 i8042.write(0x0, OFS_STATUS, &data);
412 assert_ne!(i8042.status & SB_I8042_CMD_DATA, 0);
413 data[0] = 0x52;
414 i8042.write(0x0, OFS_DATA, &data);
415 data[0] = CMD_READ_OUTP;
416 i8042.write(0x0, OFS_STATUS, &data);
417 assert_ne!(i8042.status & SB_OUT_DATA_AVAIL, 0);
418 i8042.read(0x0, OFS_DATA, &mut data);
419 assert_eq!(data[0], 0x52);
420
421 data[0] = 0x52;
423 i8042.write(0x0, OFS_DATA, &data);
424 assert_ne!(i8042.status & SB_OUT_DATA_AVAIL, 0);
425 i8042.read(0x0, OFS_DATA, &mut data);
426 assert_eq!(data[0], 0xFA);
427 }
428
429 #[test]
430 fn test_i8042_buffer() {
431 let mut i8042 = I8042Device::new(EventFd::new(libc::EFD_NONBLOCK).unwrap()).unwrap();
432
433 i8042.push_byte(52).unwrap();
435 assert_ne!(i8042.status & SB_OUT_DATA_AVAIL, 0);
436 assert_eq!(i8042.pop_byte().unwrap(), 52);
437 assert_eq!(i8042.status & SB_OUT_DATA_AVAIL, 0);
438
439 assert!(i8042.pop_byte().is_none());
441
442 for i in 0..BUF_SIZE {
444 i8042.push_byte(i.try_into().unwrap()).unwrap();
445 assert_eq!(i8042.buf_len(), i + 1);
446 }
447 assert_eq!(
448 i8042.push_byte(0).unwrap_err(),
449 I8042Error::InternalBufferFull
450 );
451 }
452
453 #[test]
454 fn test_i8042_kbd() {
455 let mut i8042 = I8042Device::new(EventFd::new(libc::EFD_NONBLOCK).unwrap()).unwrap();
456
457 fn expect_key(i8042: &mut I8042Device, key: u16) {
458 let mut data = [1];
459
460 i8042.trigger_kbd_interrupt().unwrap();
462 assert!(i8042.kbd_interrupt_evt.read().unwrap() > 1);
463
464 i8042.read(0x0, OFS_STATUS, &mut data);
466
467 let mut key_byte: u8;
468 if key & 0xFF00 != 0 {
469 key_byte = ((key & 0xFF00) >> 8) as u8;
471 i8042.read(0x0, OFS_DATA, &mut data);
472 assert_eq!(data[0], key_byte);
473
474 i8042.trigger_kbd_interrupt().unwrap();
478 assert!(i8042.kbd_interrupt_evt.read().unwrap() > 1);
479 i8042.read(0x0, OFS_STATUS, &mut data);
481 }
482 key_byte = (key & 0xFF) as u8;
483 i8042.read(0x0, OFS_DATA, &mut data);
484 assert_eq!(data[0], key_byte);
485 }
486
487 i8042.trigger_key(KEY_CTRL).unwrap();
489 expect_key(&mut i8042, KEY_CTRL);
490
491 i8042.trigger_key(KEY_DEL).unwrap();
493 expect_key(&mut i8042, KEY_DEL);
494
495 i8042.trigger_ctrl_alt_del().unwrap();
497 expect_key(&mut i8042, KEY_CTRL);
498 expect_key(&mut i8042, KEY_ALT);
499 expect_key(&mut i8042, KEY_DEL);
500
501 for _i in 0..BUF_SIZE - 1 {
503 i8042.push_byte(1).unwrap();
504 }
505
506 assert_eq!(i8042.buf_len(), BUF_SIZE - 1);
508 assert_eq!(
509 i8042.trigger_key(KEY_DEL).unwrap_err(),
510 I8042Error::InternalBufferFull
511 );
512
513 i8042.pop_byte().unwrap();
515 i8042.pop_byte().unwrap();
516 assert_eq!(i8042.buf_len(), BUF_SIZE - 3);
517 assert_eq!(
518 i8042.trigger_ctrl_alt_del().unwrap_err(),
519 I8042Error::InternalBufferFull
520 );
521
522 let mut data = [1];
524 data[0] = CMD_WRITE_CTR;
525 i8042.write(0x0, OFS_STATUS, &data);
526 data[0] = i8042.control & !CB_KBD_INT;
527 i8042.write(0x0, OFS_DATA, &data);
528 i8042.trigger_key(KEY_CTRL).unwrap();
529 assert_eq!(
530 i8042.trigger_kbd_interrupt().unwrap_err(),
531 I8042Error::KbdInterruptDisabled
532 )
533 }
534}