mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-04-30 20:54:26 +00:00
dragonball: add legacy devices manager
The legacy devices manager is used for managing legacy devices. Fixes: #4257 Signed-off-by: Liu Jiang <gerry@linux.alibaba.com> Signed-off-by: wllenyj <wllenyj@linux.alibaba.com> Signed-off-by: Chao Wu <chaowu@linux.alibaba.com>
This commit is contained in:
parent
3c45c0715f
commit
0bcb422fcb
155
src/dragonball/src/device_manager/legacy.rs
Normal file
155
src/dragonball/src/device_manager/legacy.rs
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
// Copyright (C) 2022 Alibaba Cloud. All rights reserved.
|
||||||
|
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// Portions 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 THIRD-PARTY file.
|
||||||
|
|
||||||
|
//! Device Manager for Legacy Devices.
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use dbs_device::device_manager::Error as IoManagerError;
|
||||||
|
use dbs_legacy_devices::SerialDevice;
|
||||||
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
|
// The I8042 Data Port (IO Port 0x60) is used for reading data that was received from a I8042 device or from the I8042 controller itself and writing data to a I8042 device or to the I8042 controller itself.
|
||||||
|
const I8042_DATA_PORT: u16 = 0x60;
|
||||||
|
|
||||||
|
/// Errors generated by legacy device manager.
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Cannot add legacy device to Bus.
|
||||||
|
#[error("bus failure while managing legacy device")]
|
||||||
|
BusError(#[source] IoManagerError),
|
||||||
|
|
||||||
|
/// Cannot create EventFd.
|
||||||
|
#[error("failure while reading EventFd file descriptor")]
|
||||||
|
EventFd(#[source] io::Error),
|
||||||
|
|
||||||
|
/// Failed to register/deregister interrupt.
|
||||||
|
#[error("failure while managing interrupt for legacy device")]
|
||||||
|
IrqManager(#[source] vmm_sys_util::errno::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The `LegacyDeviceManager` is a wrapper that is used for registering legacy devices
|
||||||
|
/// on an I/O Bus.
|
||||||
|
///
|
||||||
|
/// It currently manages the uart and i8042 devices. The `LegacyDeviceManger` should be initialized
|
||||||
|
/// only by using the constructor.
|
||||||
|
pub struct LegacyDeviceManager {
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
i8042_reset_eventfd: EventFd,
|
||||||
|
pub(crate) com1_device: Arc<Mutex<SerialDevice>>,
|
||||||
|
_com1_eventfd: EventFd,
|
||||||
|
pub(crate) com2_device: Arc<Mutex<SerialDevice>>,
|
||||||
|
_com2_eventfd: EventFd,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LegacyDeviceManager {
|
||||||
|
/// Get the serial device for com1.
|
||||||
|
pub fn get_com1_serial(&self) -> Arc<Mutex<SerialDevice>> {
|
||||||
|
self.com1_device.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the serial device for com2
|
||||||
|
pub fn get_com2_serial(&self) -> Arc<Mutex<SerialDevice>> {
|
||||||
|
self.com2_device.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub(crate) mod x86_64 {
|
||||||
|
use super::*;
|
||||||
|
use dbs_device::device_manager::IoManager;
|
||||||
|
use dbs_device::resources::Resource;
|
||||||
|
use dbs_legacy_devices::{EventFdTrigger, I8042Device, I8042DeviceMetrics};
|
||||||
|
use kvm_ioctls::VmFd;
|
||||||
|
|
||||||
|
pub(crate) const COM1_IRQ: u32 = 4;
|
||||||
|
pub(crate) const COM1_PORT1: u16 = 0x3f8;
|
||||||
|
pub(crate) const COM2_IRQ: u32 = 3;
|
||||||
|
pub(crate) const COM2_PORT1: u16 = 0x2f8;
|
||||||
|
|
||||||
|
type Result<T> = ::std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
impl LegacyDeviceManager {
|
||||||
|
/// Create a LegacyDeviceManager instance handling legacy devices (uart, i8042).
|
||||||
|
pub fn create_manager(bus: &mut IoManager, vm_fd: Option<Arc<VmFd>>) -> Result<Self> {
|
||||||
|
let (com1_device, com1_eventfd) =
|
||||||
|
Self::create_com_device(bus, vm_fd.as_ref(), COM1_IRQ, COM1_PORT1)?;
|
||||||
|
let (com2_device, com2_eventfd) =
|
||||||
|
Self::create_com_device(bus, vm_fd.as_ref(), COM2_IRQ, COM2_PORT1)?;
|
||||||
|
|
||||||
|
let exit_evt = EventFd::new(libc::EFD_NONBLOCK).map_err(Error::EventFd)?;
|
||||||
|
let i8042_device = Arc::new(Mutex::new(I8042Device::new(
|
||||||
|
EventFdTrigger::new(exit_evt.try_clone().map_err(Error::EventFd)?),
|
||||||
|
Arc::new(I8042DeviceMetrics::default()),
|
||||||
|
)));
|
||||||
|
let resources = [Resource::PioAddressRange {
|
||||||
|
// 0x60 and 0x64 are the io ports that i8042 devices used.
|
||||||
|
// We register pio address range from 0x60 - 0x64 with base I8042_DATA_PORT for i8042 to use.
|
||||||
|
base: I8042_DATA_PORT,
|
||||||
|
size: 0x5,
|
||||||
|
}];
|
||||||
|
bus.register_device_io(i8042_device, &resources)
|
||||||
|
.map_err(Error::BusError)?;
|
||||||
|
|
||||||
|
Ok(LegacyDeviceManager {
|
||||||
|
i8042_reset_eventfd: exit_evt,
|
||||||
|
com1_device,
|
||||||
|
_com1_eventfd: com1_eventfd,
|
||||||
|
com2_device,
|
||||||
|
_com2_eventfd: com2_eventfd,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the eventfd for exit notification.
|
||||||
|
pub fn get_reset_eventfd(&self) -> Result<EventFd> {
|
||||||
|
self.i8042_reset_eventfd.try_clone().map_err(Error::EventFd)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_com_device(
|
||||||
|
bus: &mut IoManager,
|
||||||
|
vm_fd: Option<&Arc<VmFd>>,
|
||||||
|
irq: u32,
|
||||||
|
port_base: u16,
|
||||||
|
) -> Result<(Arc<Mutex<SerialDevice>>, EventFd)> {
|
||||||
|
let eventfd = EventFd::new(libc::EFD_NONBLOCK).map_err(Error::EventFd)?;
|
||||||
|
let device = Arc::new(Mutex::new(SerialDevice::new(
|
||||||
|
eventfd.try_clone().map_err(Error::EventFd)?,
|
||||||
|
)));
|
||||||
|
// port_base defines the base port address for the COM devices.
|
||||||
|
// Since every COM device has 8 data registers so we register the pio address range as size 0x8.
|
||||||
|
let resources = [Resource::PioAddressRange {
|
||||||
|
base: port_base,
|
||||||
|
size: 0x8,
|
||||||
|
}];
|
||||||
|
bus.register_device_io(device.clone(), &resources)
|
||||||
|
.map_err(Error::BusError)?;
|
||||||
|
|
||||||
|
if let Some(fd) = vm_fd {
|
||||||
|
fd.register_irqfd(&eventfd, irq)
|
||||||
|
.map_err(Error::IrqManager)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((device, eventfd))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
fn test_create_legacy_device_manager() {
|
||||||
|
let mut bus = dbs_device::device_manager::IoManager::new();
|
||||||
|
let mgr = LegacyDeviceManager::create_manager(&mut bus, None).unwrap();
|
||||||
|
let _exit_fd = mgr.get_reset_eventfd().unwrap();
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,9 @@ pub mod console_manager;
|
|||||||
/// Console Manager for virtual machines console device.
|
/// Console Manager for virtual machines console device.
|
||||||
pub use self::console_manager::ConsoleManager;
|
pub use self::console_manager::ConsoleManager;
|
||||||
|
|
||||||
|
mod legacy;
|
||||||
|
pub use self::legacy::{Error as LegacyDeviceError, LegacyDeviceManager};
|
||||||
|
|
||||||
/// Errors related to device manager operations.
|
/// Errors related to device manager operations.
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum DeviceMgrError {
|
pub enum DeviceMgrError {
|
||||||
|
Loading…
Reference in New Issue
Block a user