diff --git a/aarch64/src/fdt.rs b/aarch64/src/fdt.rs index 97f3c61726..01ac887259 100644 --- a/aarch64/src/fdt.rs +++ b/aarch64/src/fdt.rs @@ -36,7 +36,6 @@ use AARCH64_SERIAL_SPEED; // These are related to guest virtio devices. use AARCH64_IRQ_BASE; use AARCH64_MMIO_BASE; -use AARCH64_MMIO_LEN; use AARCH64_MMIO_SIZE; use AARCH64_PCI_CFG_BASE; use AARCH64_PCI_CFG_SIZE; @@ -368,30 +367,6 @@ fn create_chosen_node(fdt: &mut Vec, cmdline: &CStr) -> Result<(), Box) -> Result<(), Box> { - // TODO(sonnyrao) Pass in bus to get number of devices - // HACK -- this is creating a static number of device nodes - // the unused nodes just throw a warning when the guest boots - for i in 0..8 { - let addr = AARCH64_MMIO_BASE + i * AARCH64_MMIO_LEN; - let node = format!("virtio@{:x}", addr); - let reg = generate_prop64(&[addr, AARCH64_MMIO_LEN]); - let irq = generate_prop32(&[ - GIC_FDT_IRQ_TYPE_SPI, - AARCH64_IRQ_BASE + i as u32, - IRQ_TYPE_EDGE_RISING, - ]); - - begin_node(fdt, &node)?; - property_string(fdt, "compatible", "virtio,mmio")?; - property(fdt, "reg", ®)?; - property_null(fdt, "dma-coherent")?; - property(fdt, "interrupts", &irq)?; - end_node(fdt)?; - } - Ok(()) -} - fn create_pci_nodes( fdt: &mut Vec, pci_irqs: Vec<(u32, PciInterruptPin)>, @@ -539,12 +514,7 @@ pub fn create_fdt( create_timer_node(&mut fdt, num_cpus)?; create_serial_node(&mut fdt)?; create_psci_node(&mut fdt)?; - // TODO(dverkamp): remove create_io_nodes() once the PCI conversion is complete - if !pci_irqs.is_empty() { - create_pci_nodes(&mut fdt, pci_irqs)?; - } else { - create_io_nodes(&mut fdt)?; - } + create_pci_nodes(&mut fdt, pci_irqs)?; create_rtc_node(&mut fdt)?; // End giant node end_node(&mut fdt)?; diff --git a/aarch64/src/lib.rs b/aarch64/src/lib.rs index 064bbbf761..fe8053475b 100644 --- a/aarch64/src/lib.rs +++ b/aarch64/src/lib.rs @@ -111,8 +111,6 @@ const AARCH64_PCI_CFG_SIZE: u64 = 0x1000000; const AARCH64_MMIO_BASE: u64 = 0x1010000; // Size of the whole MMIO region. const AARCH64_MMIO_SIZE: u64 = 0x100000; -// Each MMIO device gets a 4k page. -const AARCH64_MMIO_LEN: u64 = 0x1000; // Virtio devices start at SPI interrupt number 2 const AARCH64_IRQ_BASE: u32 = 2; diff --git a/arch/src/lib.rs b/arch/src/lib.rs index 455bd0ea40..bd061fdcc1 100644 --- a/arch/src/lib.rs +++ b/arch/src/lib.rs @@ -12,7 +12,7 @@ extern crate sys_util; use std::fmt; use std::fs::File; -use std::os::unix::io::{AsRawFd, RawFd}; +use std::os::unix::io::AsRawFd; use std::result; use std::sync::{Arc, Mutex}; @@ -22,7 +22,7 @@ use devices::{ Serial, }; use io_jail::Minijail; -use kvm::{Datamatch, IoeventAddress, Kvm, Vcpu, Vm}; +use kvm::{IoeventAddress, Kvm, Vcpu, Vm}; use resources::SystemAllocator; use sys_util::{syslog, EventFd, GuestMemory}; @@ -192,64 +192,3 @@ pub fn generate_pci_root( } Ok((root, pci_irqs)) } - -/// Register a device to be used via MMIO transport. -pub fn register_mmio( - bus: &mut devices::Bus, - vm: &mut Vm, - device: Box, - jail: Option, - resources: &mut SystemAllocator, - cmdline: &mut kernel_cmdline::Cmdline, -) -> std::result::Result<(), DeviceRegistrationError> { - let irq = match resources.allocate_irq() { - None => return Err(DeviceRegistrationError::IrqsExhausted), - Some(i) => i, - }; - - // List of FDs to keep open in the child after it forks. - let mut keep_fds: Vec = device.keep_fds(); - syslog::push_fds(&mut keep_fds); - - let mmio_device = devices::virtio::MmioDevice::new((*vm.get_memory()).clone(), device) - .map_err(DeviceRegistrationError::CreateMmioDevice)?; - let mmio_len = 0x1000; // TODO(dgreid) - configurable per arch? - let mmio_base = resources - .allocate_mmio_addresses(mmio_len) - .ok_or(DeviceRegistrationError::AddrsExhausted)?; - for (i, queue_evt) in mmio_device.queue_evts().iter().enumerate() { - let io_addr = IoeventAddress::Mmio(mmio_base + devices::virtio::NOTIFY_REG_OFFSET as u64); - vm.register_ioevent(&queue_evt, io_addr, Datamatch::U32(Some(i as u32))) - .map_err(DeviceRegistrationError::RegisterIoevent)?; - keep_fds.push(queue_evt.as_raw_fd()); - } - - if let Some(interrupt_evt) = mmio_device.interrupt_evt() { - vm.register_irqfd(&interrupt_evt, irq) - .map_err(DeviceRegistrationError::RegisterIrqfd)?; - keep_fds.push(interrupt_evt.as_raw_fd()); - } - - if let Some(jail) = jail { - let proxy_dev = devices::ProxyDevice::new(mmio_device, &jail, keep_fds) - .map_err(DeviceRegistrationError::ProxyDeviceCreation)?; - - bus.insert(Arc::new(Mutex::new(proxy_dev)), mmio_base, mmio_len, false) - .unwrap(); - } else { - bus.insert( - Arc::new(Mutex::new(mmio_device)), - mmio_base, - mmio_len, - false, - ).unwrap(); - } - - cmdline - .insert( - "virtio_mmio.device", - &format!("4K@0x{:08x}:{}", mmio_base, irq), - ).map_err(DeviceRegistrationError::Cmdline)?; - - Ok(()) -} diff --git a/devices/src/virtio/mmio.rs b/devices/src/virtio/mmio.rs deleted file mode 100644 index bca6de0712..0000000000 --- a/devices/src/virtio/mmio.rs +++ /dev/null @@ -1,230 +0,0 @@ -// 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 std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Arc; - -use byteorder::{ByteOrder, LittleEndian}; - -use super::*; -use sys_util::{EventFd, GuestAddress, GuestMemory, Result}; -use BusDevice; - -const VENDOR_ID: u32 = 0; - -const MMIO_MAGIC_VALUE: u32 = 0x74726976; -const MMIO_VERSION: u32 = 2; - -/// Implements the -/// [MMIO](http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html#x1-1090002) -/// transport for virtio devices. -/// -/// This requires 3 points of installation to work with a VM: -/// -/// 1. Mmio reads and writes must be sent to this device at what is referred to here as MMIO base. -/// 1. `Mmio::queue_evts` must be installed at `virtio::NOTIFY_REG_OFFSET` offset from the MMIO -/// base. Each event in the array must be signaled if the index is written at that offset. -/// 1. `Mmio::interrupt_evt` must signal an interrupt that the guest driver is listening to when it -/// is written to. -/// -/// Typically one page (4096 bytes) of MMIO address space is sufficient to handle this transport -/// and inner virtio device. -pub struct MmioDevice { - device: Box, - device_activated: bool, - - features_select: u32, - acked_features_select: u32, - queue_select: u32, - interrupt_status: Arc, - interrupt_evt: Option, - interrupt_resample_evt: Option, - driver_status: u32, - config_generation: u32, - queues: Vec, - queue_evts: Vec, - mem: Option, -} - -impl MmioDevice { - /// Constructs a new MMIO transport for the given virtio device. - pub fn new(mem: GuestMemory, device: Box) -> Result { - let mut queue_evts = Vec::new(); - for _ in device.queue_max_sizes().iter() { - queue_evts.push(EventFd::new()?) - } - let queues = device - .queue_max_sizes() - .iter() - .map(|&s| Queue::new(s)) - .collect(); - Ok(MmioDevice { - device, - device_activated: false, - features_select: 0, - acked_features_select: 0, - queue_select: 0, - interrupt_status: Arc::new(AtomicUsize::new(0)), - interrupt_evt: Some(EventFd::new()?), - interrupt_resample_evt: Some(EventFd::new()?), - driver_status: 0, - config_generation: 0, - queues, - queue_evts, - mem: Some(mem), - }) - } - - /// Gets the list of queue events that must be triggered whenever the VM writes to - /// `virtio::NOTIFY_REG_OFFSET` past the MMIO base. Each event must be triggered when the - /// value being written equals the index of the event in this list. - pub fn queue_evts(&self) -> &[EventFd] { - self.queue_evts.as_slice() - } - - /// Gets the event this device uses to interrupt the VM when the used queue is changed. - pub fn interrupt_evt(&self) -> Option<&EventFd> { - self.interrupt_evt.as_ref() - } - - fn is_driver_ready(&self) -> bool { - let ready_bits = DEVICE_ACKNOWLEDGE | DEVICE_DRIVER | DEVICE_DRIVER_OK | DEVICE_FEATURES_OK; - self.driver_status == ready_bits && self.driver_status & DEVICE_FAILED == 0 - } - - fn are_queues_valid(&self) -> bool { - if let Some(mem) = self.mem.as_ref() { - self.queues.iter().all(|q| q.is_valid(mem)) - } else { - false - } - } - - fn with_queue(&self, d: U, f: F) -> U - where - F: FnOnce(&Queue) -> U, - { - match self.queues.get(self.queue_select as usize) { - Some(queue) => f(queue), - None => d, - } - } - - fn with_queue_mut(&mut self, f: F) -> bool { - if let Some(queue) = self.queues.get_mut(self.queue_select as usize) { - f(queue); - true - } else { - false - } - } -} - -impl BusDevice for MmioDevice { - fn read(&mut self, offset: u64, data: &mut [u8]) { - match offset { - 0x00...0xff if data.len() == 4 => { - let v = match offset { - 0x0 => MMIO_MAGIC_VALUE, - 0x04 => MMIO_VERSION, - 0x08 => self.device.device_type(), - 0x0c => VENDOR_ID, // vendor id - 0x10 => { - self.device.features(self.features_select) - | if self.features_select == 1 { 0x1 } else { 0x0 } - } - 0x34 => self.with_queue(0, |q| q.max_size as u32), - 0x44 => self.with_queue(0, |q| q.ready as u32), - 0x60 => self.interrupt_status.load(Ordering::SeqCst) as u32, - 0x70 => self.driver_status, - 0xfc => self.config_generation, - _ => { - warn!("unknown virtio mmio register read: 0x{:x}", offset); - return; - } - }; - LittleEndian::write_u32(data, v); - } - 0x100...0xfff => self.device.read_config(offset - 0x100, data), - _ => { - warn!( - "invalid virtio mmio read: 0x{:x}:0x{:x}", - offset, - data.len() - ); - } - }; - } - - fn write(&mut self, offset: u64, data: &[u8]) { - fn hi(v: &mut GuestAddress, x: u32) { - *v = (*v & 0xffffffff) | ((x as u64) << 32) - } - - fn lo(v: &mut GuestAddress, x: u32) { - *v = (*v & !0xffffffff) | (x as u64) - } - - let mut mut_q = false; - match offset { - 0x00...0xff if data.len() == 4 => { - let v = LittleEndian::read_u32(data); - match offset { - 0x14 => self.features_select = v, - 0x20 => self.device.ack_features(self.acked_features_select, v), - 0x24 => self.acked_features_select = v, - 0x30 => self.queue_select = v, - 0x38 => mut_q = self.with_queue_mut(|q| q.size = v as u16), - 0x44 => mut_q = self.with_queue_mut(|q| q.ready = v == 1), - 0x64 => { - self.interrupt_status - .fetch_and(!(v as usize), Ordering::SeqCst); - } - 0x70 => self.driver_status = v, - 0x80 => mut_q = self.with_queue_mut(|q| lo(&mut q.desc_table, v)), - 0x84 => mut_q = self.with_queue_mut(|q| hi(&mut q.desc_table, v)), - 0x90 => mut_q = self.with_queue_mut(|q| lo(&mut q.avail_ring, v)), - 0x94 => mut_q = self.with_queue_mut(|q| hi(&mut q.avail_ring, v)), - 0xa0 => mut_q = self.with_queue_mut(|q| lo(&mut q.used_ring, v)), - 0xa4 => mut_q = self.with_queue_mut(|q| hi(&mut q.used_ring, v)), - _ => { - warn!("unknown virtio mmio register write: 0x{:x}", offset); - return; - } - } - } - 0x100...0xfff => return self.device.write_config(offset - 0x100, data), - _ => { - warn!( - "invalid virtio mmio write: 0x{:x}:0x{:x}", - offset, - data.len() - ); - return; - } - } - - if self.device_activated && mut_q { - warn!("virtio queue was changed after device was activated"); - } - - if !self.device_activated && self.is_driver_ready() && self.are_queues_valid() { - if let Some(interrupt_evt) = self.interrupt_evt.take() { - if let Some(interrupt_resample_evt) = self.interrupt_resample_evt.take() { - if let Some(mem) = self.mem.take() { - self.device.activate( - mem, - interrupt_evt, - interrupt_resample_evt, - self.interrupt_status.clone(), - self.queues.clone(), - self.queue_evts.split_off(0), - ); - self.device_activated = true; - } - } - } - } - } -} diff --git a/devices/src/virtio/mod.rs b/devices/src/virtio/mod.rs index c23c56d128..12b74ec014 100644 --- a/devices/src/virtio/mod.rs +++ b/devices/src/virtio/mod.rs @@ -8,7 +8,6 @@ mod balloon; mod block; #[cfg(feature = "gpu")] mod gpu; -mod mmio; mod net; mod p9; mod queue; @@ -24,7 +23,6 @@ pub use self::balloon::*; pub use self::block::*; #[cfg(feature = "gpu")] pub use self::gpu::*; -pub use self::mmio::*; pub use self::net::*; pub use self::p9::*; pub use self::queue::*;