crosvm/devices/src/i8042.rs
Colin Downs-Razouk 62e2e2e8de devices: add un-mutex-ed BusDevice in Bus
Allow devices to be added to a Bus without a mutex. If a device
implements BusDeviceSync and is inserted into the Bus via the new
insert_sync function, the Bus will not lock the device before write and
read operations. This feature will allow IrqChip implementations to use
the mmio bus for APIC mmio, and allow each vcpu to write to their
respective APICs simultaneously.

This also changes the BusDevice trait so read and write functions take a
new BusAccessInfo struct. The BusAccessInfo conveys the full address of
the read/write operation, the offset of the address relative to the
device start address, and an id that in practice will hold the vcpu id
for the vcpu thread perforing the read/write.

As a result, inserts into the Bus are no longer distinguished between
full_addr and non full_addr inserts. Instead, each device's BusDevice
implementation must decide whether they use the absolute read/write
address or the relative read/write offset.

BUG=chromium:1077058
TEST=ran build_test
TEST=ran simple debian image

Change-Id: I9125aaa69869c1004b6c6a099b50f5c58038d4ab
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2514662
Reviewed-by: Zach Reizner <zachr@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Colin Downs-Razouk <colindr@google.com>
2020-11-23 22:47:29 +00:00

45 lines
1.5 KiB
Rust

// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use base::{error, Event};
use crate::{BusAccessInfo, BusDevice};
/// A i8042 PS/2 controller that emulates just enough to shutdown the machine.
pub struct I8042Device {
reset_evt: Event,
}
impl I8042Device {
/// Constructs a i8042 device that will signal the given event when the guest requests it.
pub fn new(reset_evt: Event) -> I8042Device {
I8042Device { reset_evt }
}
}
// i8042 device is mapped I/O address 0x61. We partially implement two 8-bit
// registers: port 0x61 (I8042_PORT_B_REG), and port 0x64 (I8042_COMMAND_REG).
impl BusDevice for I8042Device {
fn debug_label(&self) -> String {
"i8042".to_owned()
}
fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
if data.len() == 1 && info.offset == 0x64 {
data[0] = 0x0;
} else if data.len() == 1 && info.offset == 0x61 {
// Like kvmtool, we return bit 5 set in I8042_PORT_B_REG to
// avoid hang in pit_calibrate_tsc() in Linux kernel.
data[0] = 0x20;
}
}
fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
if data.len() == 1 && data[0] == 0xfe && info.offset == 0x64 {
if let Err(e) = self.reset_evt.write(1) {
error!("failed to trigger i8042 reset event: {}", e);
}
}
}
}