2018-02-14 06:09:43 +00:00
|
|
|
// Copyright 2018 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.
|
|
|
|
|
2018-12-22 00:01:56 +00:00
|
|
|
pub mod fdt;
|
|
|
|
|
|
|
|
extern crate byteorder;
|
2018-10-03 17:22:32 +00:00
|
|
|
extern crate devices;
|
2018-07-24 00:58:09 +00:00
|
|
|
extern crate io_jail;
|
2018-02-14 06:09:43 +00:00
|
|
|
extern crate kernel_cmdline;
|
|
|
|
extern crate kvm;
|
|
|
|
extern crate libc;
|
2018-10-03 17:22:32 +00:00
|
|
|
extern crate resources;
|
2018-12-04 07:37:46 +00:00
|
|
|
extern crate sync;
|
2018-10-03 17:22:32 +00:00
|
|
|
extern crate sys_util;
|
2018-02-14 06:09:43 +00:00
|
|
|
|
2019-01-24 03:04:43 +00:00
|
|
|
use std::collections::BTreeMap;
|
2018-07-24 00:58:09 +00:00
|
|
|
use std::fmt;
|
2018-02-14 06:09:43 +00:00
|
|
|
use std::fs::File;
|
2018-12-12 23:20:30 +00:00
|
|
|
use std::io::{Read, Seek, SeekFrom};
|
2018-10-15 21:32:30 +00:00
|
|
|
use std::os::unix::io::AsRawFd;
|
2018-02-14 06:09:43 +00:00
|
|
|
use std::result;
|
2018-12-04 07:37:46 +00:00
|
|
|
use std::sync::Arc;
|
2018-02-14 06:09:43 +00:00
|
|
|
|
2018-07-24 00:58:09 +00:00
|
|
|
use devices::virtio::VirtioDevice;
|
2018-10-03 17:22:32 +00:00
|
|
|
use devices::{
|
2018-10-18 23:45:13 +00:00
|
|
|
Bus, BusDevice, BusError, PciDevice, PciDeviceError, PciInterruptPin, PciRoot, ProxyDevice,
|
|
|
|
Serial,
|
2018-10-03 17:22:32 +00:00
|
|
|
};
|
2018-07-24 00:58:09 +00:00
|
|
|
use io_jail::Minijail;
|
2018-10-15 21:32:30 +00:00
|
|
|
use kvm::{IoeventAddress, Kvm, Vcpu, Vm};
|
2018-05-18 01:47:11 +00:00
|
|
|
use resources::SystemAllocator;
|
2018-12-04 07:37:46 +00:00
|
|
|
use sync::Mutex;
|
2018-12-12 23:20:30 +00:00
|
|
|
use sys_util::{syslog, EventFd, GuestAddress, GuestMemory, GuestMemoryError};
|
2018-02-14 06:09:43 +00:00
|
|
|
|
|
|
|
pub type Result<T> = result::Result<T, Box<std::error::Error>>;
|
|
|
|
|
2018-07-24 00:58:09 +00:00
|
|
|
/// Holds the pieces needed to build a VM. Passed to `build_vm` in the `LinuxArch` trait below to
|
|
|
|
/// create a `RunnableLinuxVm`.
|
|
|
|
pub struct VmComponents {
|
|
|
|
pub memory_mb: u64,
|
|
|
|
pub vcpu_count: u32,
|
|
|
|
pub kernel_image: File,
|
2018-12-22 00:01:56 +00:00
|
|
|
pub android_fstab: Option<File>,
|
2018-12-12 00:29:26 +00:00
|
|
|
pub initrd_image: Option<File>,
|
2018-07-24 00:58:09 +00:00
|
|
|
pub extra_kernel_params: Vec<String>,
|
|
|
|
pub wayland_dmabuf: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Holds the elements needed to run a Linux VM. Created by `build_vm`.
|
|
|
|
pub struct RunnableLinuxVm {
|
|
|
|
pub vm: Vm,
|
|
|
|
pub kvm: Kvm,
|
|
|
|
pub resources: SystemAllocator,
|
|
|
|
pub stdio_serial: Arc<Mutex<Serial>>,
|
|
|
|
pub exit_evt: EventFd,
|
|
|
|
pub vcpus: Vec<Vcpu>,
|
|
|
|
pub irq_chip: Option<File>,
|
|
|
|
pub io_bus: Bus,
|
|
|
|
pub mmio_bus: Bus,
|
2019-01-24 03:04:43 +00:00
|
|
|
pub pid_debug_label_map: BTreeMap<u32, String>,
|
2018-07-24 00:58:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// The device and optional jail.
|
|
|
|
pub struct VirtioDeviceStub {
|
|
|
|
pub dev: Box<VirtioDevice>,
|
|
|
|
pub jail: Option<Minijail>,
|
|
|
|
}
|
|
|
|
|
2018-02-14 06:09:43 +00:00
|
|
|
/// Trait which is implemented for each Linux Architecture in order to
|
|
|
|
/// set up the memory, cpus, and system devices and to boot the kernel.
|
|
|
|
pub trait LinuxArch {
|
2018-07-24 00:58:09 +00:00
|
|
|
/// Takes `VmComponents` and generates a `RunnableLinuxVm`.
|
2018-02-14 06:09:43 +00:00
|
|
|
///
|
|
|
|
/// # Arguments
|
|
|
|
///
|
2018-07-24 00:58:09 +00:00
|
|
|
/// * `components` - Parts to use to build the VM.
|
2019-01-30 05:21:48 +00:00
|
|
|
/// * `split_irqchip` - whether to use a split IRQ chip (i.e. userspace PIT/PIC/IOAPIC)
|
2018-07-24 00:58:09 +00:00
|
|
|
/// * `virtio_devs` - Function to generate a list of virtio devices.
|
2019-01-30 05:21:48 +00:00
|
|
|
fn build_vm<F>(
|
|
|
|
components: VmComponents,
|
|
|
|
split_irqchip: bool,
|
|
|
|
virtio_devs: F,
|
|
|
|
) -> Result<RunnableLinuxVm>
|
2018-10-03 17:22:32 +00:00
|
|
|
where
|
2018-12-12 22:33:42 +00:00
|
|
|
F: FnOnce(
|
|
|
|
&GuestMemory,
|
|
|
|
&EventFd,
|
|
|
|
) -> Result<Vec<(Box<PciDevice + 'static>, Option<Minijail>)>>;
|
2018-07-24 00:58:09 +00:00
|
|
|
}
|
2018-02-14 06:09:43 +00:00
|
|
|
|
2018-07-24 00:58:09 +00:00
|
|
|
/// Errors for device manager.
|
|
|
|
#[derive(Debug)]
|
2018-07-09 22:39:34 +00:00
|
|
|
pub enum DeviceRegistrationError {
|
|
|
|
/// Could not allocate IO space for the device.
|
|
|
|
AllocateIoAddrs(PciDeviceError),
|
|
|
|
/// Could not allocate an IRQ number.
|
|
|
|
AllocateIrq,
|
2018-07-24 00:58:09 +00:00
|
|
|
/// Could not create the mmio device to wrap a VirtioDevice.
|
|
|
|
CreateMmioDevice(sys_util::Error),
|
2018-07-09 22:39:34 +00:00
|
|
|
/// Could not create an event fd.
|
|
|
|
EventFdCreate(sys_util::Error),
|
|
|
|
/// Could not add a device to the mmio bus.
|
|
|
|
MmioInsert(BusError),
|
2018-07-24 00:58:09 +00:00
|
|
|
/// Failed to register ioevent with VM.
|
|
|
|
RegisterIoevent(sys_util::Error),
|
|
|
|
/// Failed to register irq eventfd with VM.
|
|
|
|
RegisterIrqfd(sys_util::Error),
|
|
|
|
/// Failed to initialize proxy device for jailed device.
|
|
|
|
ProxyDeviceCreation(devices::ProxyError),
|
|
|
|
/// Appending to kernel command line failed.
|
|
|
|
Cmdline(kernel_cmdline::Error),
|
|
|
|
/// No more IRQs are available.
|
|
|
|
IrqsExhausted,
|
|
|
|
/// No more MMIO space available.
|
|
|
|
AddrsExhausted,
|
|
|
|
}
|
2018-02-14 06:09:43 +00:00
|
|
|
|
2018-07-09 22:39:34 +00:00
|
|
|
impl fmt::Display for DeviceRegistrationError {
|
2018-07-24 00:58:09 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match self {
|
lint: Resolve the easier clippy lints
Hopefully the changes are self-explanatory and uncontroversial. This
eliminates much of the noise from `cargo clippy` and, for my purposes,
gives me a reasonable way to use it as a tool when writing and reviewing
code.
Here is the Clippy invocation I was using:
cargo +nightly clippy -- -W clippy::correctness -A renamed_and_removed_lints -Aclippy::{blacklisted_name,borrowed_box,cast_lossless,cast_ptr_alignment,enum_variant_names,identity_op,if_same_then_else,mut_from_ref,needless_pass_by_value,new_without_default,new_without_default_derive,or_fun_call,ptr_arg,should_implement_trait,single_match,too_many_arguments,trivially_copy_pass_by_ref,unreadable_literal,unsafe_vector_initialization,useless_transmute}
TEST=cargo check --features wl-dmabuf,gpu,usb-emulation
TEST=boot linux
Change-Id: I55eb1b4a72beb2f762480e3333a921909314a0a2
Reviewed-on: https://chromium-review.googlesource.com/1356911
Commit-Ready: David Tolnay <dtolnay@chromium.org>
Tested-by: David Tolnay <dtolnay@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2018-12-02 01:49:30 +00:00
|
|
|
DeviceRegistrationError::AllocateIoAddrs(e) => {
|
2018-07-09 22:39:34 +00:00
|
|
|
write!(f, "Allocating IO addresses: {:?}", e)
|
|
|
|
}
|
lint: Resolve the easier clippy lints
Hopefully the changes are self-explanatory and uncontroversial. This
eliminates much of the noise from `cargo clippy` and, for my purposes,
gives me a reasonable way to use it as a tool when writing and reviewing
code.
Here is the Clippy invocation I was using:
cargo +nightly clippy -- -W clippy::correctness -A renamed_and_removed_lints -Aclippy::{blacklisted_name,borrowed_box,cast_lossless,cast_ptr_alignment,enum_variant_names,identity_op,if_same_then_else,mut_from_ref,needless_pass_by_value,new_without_default,new_without_default_derive,or_fun_call,ptr_arg,should_implement_trait,single_match,too_many_arguments,trivially_copy_pass_by_ref,unreadable_literal,unsafe_vector_initialization,useless_transmute}
TEST=cargo check --features wl-dmabuf,gpu,usb-emulation
TEST=boot linux
Change-Id: I55eb1b4a72beb2f762480e3333a921909314a0a2
Reviewed-on: https://chromium-review.googlesource.com/1356911
Commit-Ready: David Tolnay <dtolnay@chromium.org>
Tested-by: David Tolnay <dtolnay@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2018-12-02 01:49:30 +00:00
|
|
|
DeviceRegistrationError::AllocateIrq => write!(f, "Allocating IRQ number"),
|
|
|
|
DeviceRegistrationError::CreateMmioDevice(e) => {
|
2018-07-09 22:39:34 +00:00
|
|
|
write!(f, "failed to create mmio device: {:?}", e)
|
|
|
|
}
|
lint: Resolve the easier clippy lints
Hopefully the changes are self-explanatory and uncontroversial. This
eliminates much of the noise from `cargo clippy` and, for my purposes,
gives me a reasonable way to use it as a tool when writing and reviewing
code.
Here is the Clippy invocation I was using:
cargo +nightly clippy -- -W clippy::correctness -A renamed_and_removed_lints -Aclippy::{blacklisted_name,borrowed_box,cast_lossless,cast_ptr_alignment,enum_variant_names,identity_op,if_same_then_else,mut_from_ref,needless_pass_by_value,new_without_default,new_without_default_derive,or_fun_call,ptr_arg,should_implement_trait,single_match,too_many_arguments,trivially_copy_pass_by_ref,unreadable_literal,unsafe_vector_initialization,useless_transmute}
TEST=cargo check --features wl-dmabuf,gpu,usb-emulation
TEST=boot linux
Change-Id: I55eb1b4a72beb2f762480e3333a921909314a0a2
Reviewed-on: https://chromium-review.googlesource.com/1356911
Commit-Ready: David Tolnay <dtolnay@chromium.org>
Tested-by: David Tolnay <dtolnay@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2018-12-02 01:49:30 +00:00
|
|
|
DeviceRegistrationError::Cmdline(e) => {
|
2018-07-24 00:58:09 +00:00
|
|
|
write!(f, "unable to add device to kernel command line: {}", e)
|
|
|
|
}
|
lint: Resolve the easier clippy lints
Hopefully the changes are self-explanatory and uncontroversial. This
eliminates much of the noise from `cargo clippy` and, for my purposes,
gives me a reasonable way to use it as a tool when writing and reviewing
code.
Here is the Clippy invocation I was using:
cargo +nightly clippy -- -W clippy::correctness -A renamed_and_removed_lints -Aclippy::{blacklisted_name,borrowed_box,cast_lossless,cast_ptr_alignment,enum_variant_names,identity_op,if_same_then_else,mut_from_ref,needless_pass_by_value,new_without_default,new_without_default_derive,or_fun_call,ptr_arg,should_implement_trait,single_match,too_many_arguments,trivially_copy_pass_by_ref,unreadable_literal,unsafe_vector_initialization,useless_transmute}
TEST=cargo check --features wl-dmabuf,gpu,usb-emulation
TEST=boot linux
Change-Id: I55eb1b4a72beb2f762480e3333a921909314a0a2
Reviewed-on: https://chromium-review.googlesource.com/1356911
Commit-Ready: David Tolnay <dtolnay@chromium.org>
Tested-by: David Tolnay <dtolnay@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2018-12-02 01:49:30 +00:00
|
|
|
DeviceRegistrationError::EventFdCreate(e) => {
|
2018-07-09 22:39:34 +00:00
|
|
|
write!(f, "failed to create eventfd: {:?}", e)
|
|
|
|
}
|
lint: Resolve the easier clippy lints
Hopefully the changes are self-explanatory and uncontroversial. This
eliminates much of the noise from `cargo clippy` and, for my purposes,
gives me a reasonable way to use it as a tool when writing and reviewing
code.
Here is the Clippy invocation I was using:
cargo +nightly clippy -- -W clippy::correctness -A renamed_and_removed_lints -Aclippy::{blacklisted_name,borrowed_box,cast_lossless,cast_ptr_alignment,enum_variant_names,identity_op,if_same_then_else,mut_from_ref,needless_pass_by_value,new_without_default,new_without_default_derive,or_fun_call,ptr_arg,should_implement_trait,single_match,too_many_arguments,trivially_copy_pass_by_ref,unreadable_literal,unsafe_vector_initialization,useless_transmute}
TEST=cargo check --features wl-dmabuf,gpu,usb-emulation
TEST=boot linux
Change-Id: I55eb1b4a72beb2f762480e3333a921909314a0a2
Reviewed-on: https://chromium-review.googlesource.com/1356911
Commit-Ready: David Tolnay <dtolnay@chromium.org>
Tested-by: David Tolnay <dtolnay@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2018-12-02 01:49:30 +00:00
|
|
|
DeviceRegistrationError::MmioInsert(e) => {
|
2018-07-09 22:39:34 +00:00
|
|
|
write!(f, "failed to add to mmio bus: {:?}", e)
|
|
|
|
}
|
lint: Resolve the easier clippy lints
Hopefully the changes are self-explanatory and uncontroversial. This
eliminates much of the noise from `cargo clippy` and, for my purposes,
gives me a reasonable way to use it as a tool when writing and reviewing
code.
Here is the Clippy invocation I was using:
cargo +nightly clippy -- -W clippy::correctness -A renamed_and_removed_lints -Aclippy::{blacklisted_name,borrowed_box,cast_lossless,cast_ptr_alignment,enum_variant_names,identity_op,if_same_then_else,mut_from_ref,needless_pass_by_value,new_without_default,new_without_default_derive,or_fun_call,ptr_arg,should_implement_trait,single_match,too_many_arguments,trivially_copy_pass_by_ref,unreadable_literal,unsafe_vector_initialization,useless_transmute}
TEST=cargo check --features wl-dmabuf,gpu,usb-emulation
TEST=boot linux
Change-Id: I55eb1b4a72beb2f762480e3333a921909314a0a2
Reviewed-on: https://chromium-review.googlesource.com/1356911
Commit-Ready: David Tolnay <dtolnay@chromium.org>
Tested-by: David Tolnay <dtolnay@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2018-12-02 01:49:30 +00:00
|
|
|
DeviceRegistrationError::RegisterIoevent(e) => {
|
2018-07-24 00:58:09 +00:00
|
|
|
write!(f, "failed to register ioevent to VM: {:?}", e)
|
|
|
|
}
|
lint: Resolve the easier clippy lints
Hopefully the changes are self-explanatory and uncontroversial. This
eliminates much of the noise from `cargo clippy` and, for my purposes,
gives me a reasonable way to use it as a tool when writing and reviewing
code.
Here is the Clippy invocation I was using:
cargo +nightly clippy -- -W clippy::correctness -A renamed_and_removed_lints -Aclippy::{blacklisted_name,borrowed_box,cast_lossless,cast_ptr_alignment,enum_variant_names,identity_op,if_same_then_else,mut_from_ref,needless_pass_by_value,new_without_default,new_without_default_derive,or_fun_call,ptr_arg,should_implement_trait,single_match,too_many_arguments,trivially_copy_pass_by_ref,unreadable_literal,unsafe_vector_initialization,useless_transmute}
TEST=cargo check --features wl-dmabuf,gpu,usb-emulation
TEST=boot linux
Change-Id: I55eb1b4a72beb2f762480e3333a921909314a0a2
Reviewed-on: https://chromium-review.googlesource.com/1356911
Commit-Ready: David Tolnay <dtolnay@chromium.org>
Tested-by: David Tolnay <dtolnay@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2018-12-02 01:49:30 +00:00
|
|
|
DeviceRegistrationError::RegisterIrqfd(e) => {
|
2018-07-24 00:58:09 +00:00
|
|
|
write!(f, "failed to register irq eventfd to VM: {:?}", e)
|
|
|
|
}
|
lint: Resolve the easier clippy lints
Hopefully the changes are self-explanatory and uncontroversial. This
eliminates much of the noise from `cargo clippy` and, for my purposes,
gives me a reasonable way to use it as a tool when writing and reviewing
code.
Here is the Clippy invocation I was using:
cargo +nightly clippy -- -W clippy::correctness -A renamed_and_removed_lints -Aclippy::{blacklisted_name,borrowed_box,cast_lossless,cast_ptr_alignment,enum_variant_names,identity_op,if_same_then_else,mut_from_ref,needless_pass_by_value,new_without_default,new_without_default_derive,or_fun_call,ptr_arg,should_implement_trait,single_match,too_many_arguments,trivially_copy_pass_by_ref,unreadable_literal,unsafe_vector_initialization,useless_transmute}
TEST=cargo check --features wl-dmabuf,gpu,usb-emulation
TEST=boot linux
Change-Id: I55eb1b4a72beb2f762480e3333a921909314a0a2
Reviewed-on: https://chromium-review.googlesource.com/1356911
Commit-Ready: David Tolnay <dtolnay@chromium.org>
Tested-by: David Tolnay <dtolnay@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2018-12-02 01:49:30 +00:00
|
|
|
DeviceRegistrationError::ProxyDeviceCreation(e) => {
|
2018-07-09 22:39:34 +00:00
|
|
|
write!(f, "failed to create proxy device: {}", e)
|
|
|
|
}
|
lint: Resolve the easier clippy lints
Hopefully the changes are self-explanatory and uncontroversial. This
eliminates much of the noise from `cargo clippy` and, for my purposes,
gives me a reasonable way to use it as a tool when writing and reviewing
code.
Here is the Clippy invocation I was using:
cargo +nightly clippy -- -W clippy::correctness -A renamed_and_removed_lints -Aclippy::{blacklisted_name,borrowed_box,cast_lossless,cast_ptr_alignment,enum_variant_names,identity_op,if_same_then_else,mut_from_ref,needless_pass_by_value,new_without_default,new_without_default_derive,or_fun_call,ptr_arg,should_implement_trait,single_match,too_many_arguments,trivially_copy_pass_by_ref,unreadable_literal,unsafe_vector_initialization,useless_transmute}
TEST=cargo check --features wl-dmabuf,gpu,usb-emulation
TEST=boot linux
Change-Id: I55eb1b4a72beb2f762480e3333a921909314a0a2
Reviewed-on: https://chromium-review.googlesource.com/1356911
Commit-Ready: David Tolnay <dtolnay@chromium.org>
Tested-by: David Tolnay <dtolnay@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2018-12-02 01:49:30 +00:00
|
|
|
DeviceRegistrationError::IrqsExhausted => write!(f, "no more IRQs are available"),
|
|
|
|
DeviceRegistrationError::AddrsExhausted => write!(f, "no more addresses are available"),
|
2018-07-09 22:39:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates a root PCI device for use by this Vm.
|
2018-10-03 17:22:32 +00:00
|
|
|
pub fn generate_pci_root(
|
2018-10-18 23:45:13 +00:00
|
|
|
devices: Vec<(Box<PciDevice + 'static>, Option<Minijail>)>,
|
2018-10-03 17:22:32 +00:00
|
|
|
mmio_bus: &mut Bus,
|
|
|
|
resources: &mut SystemAllocator,
|
|
|
|
vm: &mut Vm,
|
2019-01-24 03:04:43 +00:00
|
|
|
) -> std::result::Result<
|
|
|
|
(PciRoot, Vec<(u32, PciInterruptPin)>, BTreeMap<u32, String>),
|
|
|
|
DeviceRegistrationError,
|
|
|
|
> {
|
2018-07-09 22:39:34 +00:00
|
|
|
let mut root = PciRoot::new();
|
|
|
|
let mut pci_irqs = Vec::new();
|
2019-01-24 03:04:43 +00:00
|
|
|
let mut pid_labels = BTreeMap::new();
|
2018-07-09 22:39:34 +00:00
|
|
|
for (dev_idx, (mut device, jail)) in devices.into_iter().enumerate() {
|
2018-09-20 17:59:06 +00:00
|
|
|
let mut keep_fds = device.keep_fds();
|
2018-07-09 22:39:34 +00:00
|
|
|
syslog::push_fds(&mut keep_fds);
|
|
|
|
|
|
|
|
let irqfd = EventFd::new().map_err(DeviceRegistrationError::EventFdCreate)?;
|
2018-10-25 00:06:07 +00:00
|
|
|
let irq_resample_fd = EventFd::new().map_err(DeviceRegistrationError::EventFdCreate)?;
|
2018-07-09 20:35:40 +00:00
|
|
|
let irq_num = resources
|
|
|
|
.allocate_irq()
|
|
|
|
.ok_or(DeviceRegistrationError::AllocateIrq)? as u32;
|
2018-07-09 22:39:34 +00:00
|
|
|
let pci_irq_pin = match dev_idx % 4 {
|
|
|
|
0 => PciInterruptPin::IntA,
|
|
|
|
1 => PciInterruptPin::IntB,
|
|
|
|
2 => PciInterruptPin::IntC,
|
|
|
|
3 => PciInterruptPin::IntD,
|
|
|
|
_ => panic!(""), // Obviously not possible, but the compiler is not smart enough.
|
|
|
|
};
|
2018-10-25 00:06:07 +00:00
|
|
|
vm.register_irqfd_resample(&irqfd, &irq_resample_fd, irq_num)
|
2018-09-17 21:42:59 +00:00
|
|
|
.map_err(DeviceRegistrationError::RegisterIrqfd)?;
|
|
|
|
keep_fds.push(irqfd.as_raw_fd());
|
2018-10-25 00:06:07 +00:00
|
|
|
keep_fds.push(irq_resample_fd.as_raw_fd());
|
|
|
|
device.assign_irq(irqfd, irq_resample_fd, irq_num, pci_irq_pin);
|
2018-09-17 21:42:59 +00:00
|
|
|
pci_irqs.push((dev_idx as u32, pci_irq_pin));
|
2018-07-09 22:39:34 +00:00
|
|
|
|
|
|
|
let ranges = device
|
|
|
|
.allocate_io_bars(resources)
|
|
|
|
.map_err(DeviceRegistrationError::AllocateIoAddrs)?;
|
2018-10-05 21:51:22 +00:00
|
|
|
for (event, addr, datamatch) in device.ioeventfds() {
|
2018-07-09 20:35:40 +00:00
|
|
|
let io_addr = IoeventAddress::Mmio(addr);
|
2018-10-05 21:51:22 +00:00
|
|
|
vm.register_ioevent(&event, io_addr, datamatch)
|
2018-07-09 20:35:40 +00:00
|
|
|
.map_err(DeviceRegistrationError::RegisterIoevent)?;
|
|
|
|
keep_fds.push(event.as_raw_fd());
|
|
|
|
}
|
2018-10-18 23:45:13 +00:00
|
|
|
let arced_dev: Arc<Mutex<BusDevice>> = if let Some(jail) = jail {
|
|
|
|
let proxy = ProxyDevice::new(device, &jail, keep_fds)
|
|
|
|
.map_err(DeviceRegistrationError::ProxyDeviceCreation)?;
|
2019-01-24 03:04:43 +00:00
|
|
|
pid_labels.insert(proxy.pid() as u32, proxy.debug_label());
|
2018-10-18 23:45:13 +00:00
|
|
|
Arc::new(Mutex::new(proxy))
|
|
|
|
} else {
|
|
|
|
Arc::new(Mutex::new(device))
|
|
|
|
};
|
2018-07-09 22:39:34 +00:00
|
|
|
root.add_device(arced_dev.clone());
|
|
|
|
for range in &ranges {
|
2018-10-03 17:22:32 +00:00
|
|
|
mmio_bus
|
|
|
|
.insert(arced_dev.clone(), range.0, range.1, true)
|
2018-07-09 22:39:34 +00:00
|
|
|
.map_err(DeviceRegistrationError::MmioInsert)?;
|
2018-07-24 00:58:09 +00:00
|
|
|
}
|
|
|
|
}
|
2019-01-24 03:04:43 +00:00
|
|
|
Ok((root, pci_irqs, pid_labels))
|
2018-07-24 00:58:09 +00:00
|
|
|
}
|
2018-12-12 23:20:30 +00:00
|
|
|
|
|
|
|
/// Errors for image loading.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum LoadImageError {
|
|
|
|
Seek(std::io::Error),
|
|
|
|
ImageSizeTooLarge(u64),
|
|
|
|
ReadToMemory(GuestMemoryError),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for LoadImageError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match self {
|
|
|
|
LoadImageError::Seek(e) => write!(f, "Seek failed: {:?}", e),
|
|
|
|
LoadImageError::ImageSizeTooLarge(size) => {
|
|
|
|
write!(f, "Image size too large: {:?}", size)
|
|
|
|
}
|
|
|
|
LoadImageError::ReadToMemory(e) => {
|
|
|
|
write!(f, "Reading image into memory failed: {:?}", e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Load an image from a file into guest memory.
|
|
|
|
///
|
|
|
|
/// # Arguments
|
|
|
|
///
|
|
|
|
/// * `guest_mem` - The memory to be used by the guest.
|
|
|
|
/// * `guest_addr` - The starting address to load the image in the guest memory.
|
|
|
|
/// * `max_size` - The amount of space in bytes available in the guest memory for the image.
|
|
|
|
/// * `image` - The file containing the image to be loaded.
|
|
|
|
///
|
|
|
|
/// The size in bytes of the loaded image is returned.
|
|
|
|
pub fn load_image<F>(
|
|
|
|
guest_mem: &GuestMemory,
|
|
|
|
image: &mut F,
|
|
|
|
guest_addr: GuestAddress,
|
|
|
|
max_size: u64,
|
|
|
|
) -> std::result::Result<usize, LoadImageError>
|
|
|
|
where
|
|
|
|
F: Read + Seek,
|
|
|
|
{
|
|
|
|
let size = image.seek(SeekFrom::End(0)).map_err(LoadImageError::Seek)?;
|
|
|
|
|
|
|
|
if size > usize::max_value() as u64 || size > max_size {
|
|
|
|
return Err(LoadImageError::ImageSizeTooLarge(size));
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is safe due to the bounds check above.
|
|
|
|
let size = size as usize;
|
|
|
|
|
|
|
|
image
|
|
|
|
.seek(SeekFrom::Start(0))
|
|
|
|
.map_err(LoadImageError::Seek)?;
|
|
|
|
|
|
|
|
guest_mem
|
|
|
|
.read_to_memory(guest_addr, image, size)
|
|
|
|
.map_err(LoadImageError::ReadToMemory)?;
|
|
|
|
|
|
|
|
Ok(size)
|
|
|
|
}
|