• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use byteorder::{ByteOrder, LittleEndian};
6 
7 use std;
8 use std::fmt::{self, Display};
9 use std::os::unix::io::RawFd;
10 
11 use kvm::Datamatch;
12 use resources::{Error as SystemAllocatorFaliure, SystemAllocator};
13 use sys_util::EventFd;
14 
15 use crate::pci::pci_configuration::{self, PciConfiguration};
16 use crate::pci::PciInterruptPin;
17 use crate::BusDevice;
18 
19 #[derive(Debug)]
20 pub enum Error {
21     /// Setup of the device capabilities failed.
22     CapabilitiesSetup(pci_configuration::Error),
23     /// Allocating space for an IO BAR failed.
24     IoAllocationFailed(u64, SystemAllocatorFaliure),
25     /// Registering an IO BAR failed.
26     IoRegistrationFailed(u64, pci_configuration::Error),
27 }
28 pub type Result<T> = std::result::Result<T, Error>;
29 
30 impl Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result31     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32         use self::Error::*;
33 
34         match self {
35             CapabilitiesSetup(e) => write!(f, "failed to add capability {}", e),
36             IoAllocationFailed(size, e) => write!(
37                 f,
38                 "failed to allocate space for an IO BAR, size={}: {}",
39                 size, e
40             ),
41             IoRegistrationFailed(addr, e) => {
42                 write!(f, "failed to register an IO BAR, addr={} err={}", addr, e)
43             }
44         }
45     }
46 }
47 
48 pub trait PciDevice: Send {
49     /// Returns a label suitable for debug output.
debug_label(&self) -> String50     fn debug_label(&self) -> String;
51     /// Assign a unique bus and device number to this device.
assign_bus_dev(&mut self, _bus: u8, _device: u8 )52     fn assign_bus_dev(&mut self, _bus: u8, _device: u8 /*u5*/) {}
53     /// A vector of device-specific file descriptors that must be kept open
54     /// after jailing. Must be called before the process is jailed.
keep_fds(&self) -> Vec<RawFd>55     fn keep_fds(&self) -> Vec<RawFd>;
56     /// Assign a legacy PCI IRQ to this device.
57     /// The device may write to `irq_evt` to trigger an interrupt.
58     /// When `irq_resample_evt` is signaled, the device should re-assert `irq_evt` if necessary.
assign_irq( &mut self, _irq_evt: EventFd, _irq_resample_evt: EventFd, _irq_num: u32, _irq_pin: PciInterruptPin, )59     fn assign_irq(
60         &mut self,
61         _irq_evt: EventFd,
62         _irq_resample_evt: EventFd,
63         _irq_num: u32,
64         _irq_pin: PciInterruptPin,
65     ) {
66     }
67     /// Allocates the needed IO BAR space using the `allocate` function which takes a size and
68     /// returns an address. Returns a Vec of (address, length) tuples.
allocate_io_bars(&mut self, _resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>>69     fn allocate_io_bars(&mut self, _resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> {
70         Ok(Vec::new())
71     }
72 
73     /// Allocates the needed device BAR space. Returns a Vec of (address, length) tuples.
74     /// Unlike MMIO BARs (see allocate_io_bars), device BARs are not expected to incur VM exits
75     /// - these BARs represent normal memory.
allocate_device_bars( &mut self, _resources: &mut SystemAllocator, ) -> Result<Vec<(u64, u64)>>76     fn allocate_device_bars(
77         &mut self,
78         _resources: &mut SystemAllocator,
79     ) -> Result<Vec<(u64, u64)>> {
80         Ok(Vec::new())
81     }
82 
83     /// Register any capabilties specified by the device.
register_device_capabilities(&mut self) -> Result<()>84     fn register_device_capabilities(&mut self) -> Result<()> {
85         Ok(())
86     }
87 
88     /// Gets a list of ioeventfds that should be registered with the running VM. The list is
89     /// returned as a Vec of (eventfd, addr, datamatch) tuples.
ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)>90     fn ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)> {
91         Vec::new()
92     }
93     /// Gets the configuration registers of the Pci Device.
config_registers(&self) -> &PciConfiguration94     fn config_registers(&self) -> &PciConfiguration; // TODO - remove these
95     /// Gets the configuration registers of the Pci Device for modification.
config_registers_mut(&mut self) -> &mut PciConfiguration96     fn config_registers_mut(&mut self) -> &mut PciConfiguration;
97     /// Reads from a BAR region mapped in to the device.
98     /// * `addr` - The guest address inside the BAR.
99     /// * `data` - Filled with the data from `addr`.
read_bar(&mut self, addr: u64, data: &mut [u8])100     fn read_bar(&mut self, addr: u64, data: &mut [u8]);
101     /// Writes to a BAR region mapped in to the device.
102     /// * `addr` - The guest address inside the BAR.
103     /// * `data` - The data to write.
write_bar(&mut self, addr: u64, data: &[u8])104     fn write_bar(&mut self, addr: u64, data: &[u8]);
105     /// Invoked when the device is sandboxed.
on_device_sandboxed(&mut self)106     fn on_device_sandboxed(&mut self) {}
107 }
108 
109 impl<T: PciDevice> BusDevice for T {
debug_label(&self) -> String110     fn debug_label(&self) -> String {
111         PciDevice::debug_label(self)
112     }
113 
read(&mut self, offset: u64, data: &mut [u8])114     fn read(&mut self, offset: u64, data: &mut [u8]) {
115         self.read_bar(offset, data)
116     }
117 
write(&mut self, offset: u64, data: &[u8])118     fn write(&mut self, offset: u64, data: &[u8]) {
119         self.write_bar(offset, data)
120     }
121 
config_register_write(&mut self, reg_idx: usize, offset: u64, data: &[u8])122     fn config_register_write(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
123         if offset as usize + data.len() > 4 {
124             return;
125         }
126 
127         let regs = self.config_registers_mut();
128 
129         match data.len() {
130             1 => regs.write_byte(reg_idx * 4 + offset as usize, data[0]),
131             2 => regs.write_word(
132                 reg_idx * 4 + offset as usize,
133                 (data[0] as u16) | (data[1] as u16) << 8,
134             ),
135             4 => regs.write_reg(reg_idx, LittleEndian::read_u32(data)),
136             _ => (),
137         }
138     }
139 
config_register_read(&self, reg_idx: usize) -> u32140     fn config_register_read(&self, reg_idx: usize) -> u32 {
141         self.config_registers().read_reg(reg_idx)
142     }
143 
on_sandboxed(&mut self)144     fn on_sandboxed(&mut self) {
145         self.on_device_sandboxed();
146     }
147 }
148 
149 impl<T: PciDevice + ?Sized> PciDevice for Box<T> {
150     /// Returns a label suitable for debug output.
debug_label(&self) -> String151     fn debug_label(&self) -> String {
152         (**self).debug_label()
153     }
assign_bus_dev(&mut self, bus: u8, device: u8 )154     fn assign_bus_dev(&mut self, bus: u8, device: u8 /*u5*/) {
155         (**self).assign_bus_dev(bus, device)
156     }
keep_fds(&self) -> Vec<RawFd>157     fn keep_fds(&self) -> Vec<RawFd> {
158         (**self).keep_fds()
159     }
assign_irq( &mut self, irq_evt: EventFd, irq_resample_evt: EventFd, irq_num: u32, irq_pin: PciInterruptPin, )160     fn assign_irq(
161         &mut self,
162         irq_evt: EventFd,
163         irq_resample_evt: EventFd,
164         irq_num: u32,
165         irq_pin: PciInterruptPin,
166     ) {
167         (**self).assign_irq(irq_evt, irq_resample_evt, irq_num, irq_pin)
168     }
allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>>169     fn allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> {
170         (**self).allocate_io_bars(resources)
171     }
allocate_device_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>>172     fn allocate_device_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> {
173         (**self).allocate_device_bars(resources)
174     }
register_device_capabilities(&mut self) -> Result<()>175     fn register_device_capabilities(&mut self) -> Result<()> {
176         (**self).register_device_capabilities()
177     }
ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)>178     fn ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)> {
179         (**self).ioeventfds()
180     }
config_registers(&self) -> &PciConfiguration181     fn config_registers(&self) -> &PciConfiguration {
182         (**self).config_registers()
183     }
config_registers_mut(&mut self) -> &mut PciConfiguration184     fn config_registers_mut(&mut self) -> &mut PciConfiguration {
185         (**self).config_registers_mut()
186     }
read_bar(&mut self, addr: u64, data: &mut [u8])187     fn read_bar(&mut self, addr: u64, data: &mut [u8]) {
188         (**self).read_bar(addr, data)
189     }
write_bar(&mut self, addr: u64, data: &[u8])190     fn write_bar(&mut self, addr: u64, data: &[u8]) {
191         (**self).write_bar(addr, data)
192     }
193     /// Invoked when the device is sandboxed.
on_device_sandboxed(&mut self)194     fn on_device_sandboxed(&mut self) {
195         (**self).on_device_sandboxed()
196     }
197 }
198