diff options
-rw-r--r-- | arch/src/lib.rs | 9 | ||||
-rw-r--r-- | arch/src/pstore.rs | 74 | ||||
-rw-r--r-- | resources/src/lib.rs | 2 | ||||
-rw-r--r-- | src/crosvm.rs | 3 | ||||
-rw-r--r-- | src/linux.rs | 1 | ||||
-rw-r--r-- | src/main.rs | 43 | ||||
-rw-r--r-- | x86_64/src/lib.rs | 29 |
7 files changed, 161 insertions, 0 deletions
diff --git a/arch/src/lib.rs b/arch/src/lib.rs index ca9cd66..16cd6fa 100644 --- a/arch/src/lib.rs +++ b/arch/src/lib.rs @@ -4,6 +4,7 @@ pub mod android; pub mod fdt; +pub mod pstore; use std::collections::BTreeMap; use std::error::Error as StdError; @@ -11,6 +12,7 @@ use std::fmt::{self, Display}; use std::fs::File; use std::io::{self, Read, Seek, SeekFrom}; use std::os::unix::io::AsRawFd; +use std::path::PathBuf; use std::sync::Arc; use devices::virtio::VirtioDevice; @@ -29,6 +31,12 @@ pub enum VmImage { Bios(File), } +#[derive(Clone)] +pub struct Pstore { + pub path: PathBuf, + pub size: u32, +} + /// Holds the pieces needed to build a VM. Passed to `build_vm` in the `LinuxArch` trait below to /// create a `RunnableLinuxVm`. pub struct VmComponents { @@ -37,6 +45,7 @@ pub struct VmComponents { pub vcpu_affinity: Vec<usize>, pub vm_image: VmImage, pub android_fstab: Option<File>, + pub pstore: Option<Pstore>, pub initrd_image: Option<File>, pub extra_kernel_params: Vec<String>, pub wayland_dmabuf: bool, diff --git a/arch/src/pstore.rs b/arch/src/pstore.rs new file mode 100644 index 0000000..a06ea1b --- /dev/null +++ b/arch/src/pstore.rs @@ -0,0 +1,74 @@ +// Copyright 2020 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::fmt::{self, Display}; +use std::fs::OpenOptions; +use std::io; + +use crate::Pstore; +use kvm::Vm; +use resources::SystemAllocator; +use resources::{Alloc, MmioType}; +use sys_util::{GuestAddress, MemoryMapping}; + +/// Error for pstore. +#[derive(Debug)] +pub enum Error { + IoError(io::Error), + MmapError(sys_util::MmapError), + ResourcesError(resources::Error), + SysUtilError(sys_util::Error), +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::Error::*; + + match self { + IoError(e) => write!(f, "failed to create pstore backend file: {}", e), + MmapError(e) => write!(f, "failed to get file mapped address: {}", e), + ResourcesError(e) => write!(f, "failed to allocate pstore region: {}", e), + SysUtilError(e) => write!(f, "file to add pstore region to mmio: {}", e), + } + } +} + +impl std::error::Error for Error {} +type Result<T> = std::result::Result<T, Error>; + +pub struct RamoopsRegion { + pub address: u64, + pub size: u32, +} + +/// Creates a mmio memory region for pstore. +pub fn create_memory_region( + vm: &mut Vm, + resources: &mut SystemAllocator, + pstore: &Pstore, +) -> Result<RamoopsRegion> { + let file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(&pstore.path) + .map_err(Error::IoError)?; + file.set_len(pstore.size as u64).map_err(Error::IoError)?; + + let address = resources + .mmio_allocator(MmioType::High) + .allocate(pstore.size as u64, Alloc::Pstore, "pstore".to_owned()) + .map_err(Error::ResourcesError)?; + + let memory_mapping = + MemoryMapping::from_fd(&file, pstore.size as usize).map_err(Error::MmapError)?; + + vm.add_mmio_memory(GuestAddress(address), memory_mapping, false, false) + .map_err(Error::SysUtilError)?; + + Ok(RamoopsRegion { + address, + size: pstore.size, + }) +} diff --git a/resources/src/lib.rs b/resources/src/lib.rs index 0e16786..a0c6c98 100644 --- a/resources/src/lib.rs +++ b/resources/src/lib.rs @@ -36,6 +36,8 @@ pub enum Alloc { GpuRenderNode, /// Pmem device region with associated device index. PmemDevice(usize), + /// pstore region. + Pstore, } #[derive(Debug, Eq, PartialEq)] diff --git a/src/crosvm.rs b/src/crosvm.rs index ad3d4d1..082e43c 100644 --- a/src/crosvm.rs +++ b/src/crosvm.rs @@ -16,6 +16,7 @@ use std::os::unix::io::RawFd; use std::path::PathBuf; use std::str::FromStr; +use arch::Pstore; use devices::virtio::fs::passthrough; #[cfg(feature = "gpu")] use devices::virtio::gpu::GpuParameters; @@ -136,6 +137,7 @@ pub struct Config { pub plugin_gid_maps: Vec<GidMap>, pub disks: Vec<DiskOption>, pub pmem_devices: Vec<DiskOption>, + pub pstore: Option<Pstore>, pub host_ip: Option<net::Ipv4Addr>, pub netmask: Option<net::Ipv4Addr>, pub mac_address: Option<net_util::MacAddress>, @@ -184,6 +186,7 @@ impl Default for Config { plugin_gid_maps: Vec::new(), disks: Vec::new(), pmem_devices: Vec::new(), + pstore: None, host_ip: None, netmask: None, mac_address: None, diff --git a/src/linux.rs b/src/linux.rs index 144345e..a26e7bb 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -1513,6 +1513,7 @@ pub fn run_config(cfg: Config) -> Result<()> { .as_ref() .map(|x| File::open(x).map_err(|e| Error::OpenAndroidFstab(x.to_path_buf(), e))) .map_or(Ok(None), |v| v.map(Some))?, + pstore: cfg.pstore.clone(), initrd_image, extra_kernel_params: cfg.params.clone(), wayland_dmabuf: cfg.wayland_dmabuf, diff --git a/src/main.rs b/src/main.rs index 45efc0f..e053082 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,7 @@ use std::string::String; use std::thread::sleep; use std::time::Duration; +use arch::Pstore; use crosvm::{ argument::{self, print_help, set_arguments, Argument}, linux, BindMount, Config, DiskOption, Executable, GidMap, SharedDir, TouchDeviceOption, @@ -577,6 +578,47 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: block_size: sys_util::pagesize() as u32, }); } + "pstore" => { + if cfg.pstore.is_some() { + return Err(argument::Error::TooManyArguments( + "`pstore` already given".to_owned(), + )); + } + + let value = value.unwrap(); + let components: Vec<&str> = value.split(',').collect(); + if components.len() != 2 { + return Err(argument::Error::InvalidValue { + value: value.to_owned(), + expected: "pstore must have exactly 2 components: path=<path>,size=<size>", + }); + } + cfg.pstore = Some(Pstore { + path: { + if components[0].len() <= 5 || !components[0].starts_with("path=") { + return Err(argument::Error::InvalidValue { + value: components[0].to_owned(), + expected: "pstore path must follow with `path=`", + }); + }; + PathBuf::from(&components[0][5..]) + }, + size: { + if components[1].len() <= 5 || !components[1].starts_with("size=") { + return Err(argument::Error::InvalidValue { + value: components[1].to_owned(), + expected: "pstore size must follow with `size=`", + }); + }; + components[1][5..] + .parse() + .map_err(|_| argument::Error::InvalidValue { + value: value.to_owned(), + expected: "pstore size must be an integer", + })? + }, + }); + } "host_ip" => { if cfg.host_ip.is_some() { return Err(argument::Error::TooManyArguments( @@ -1059,6 +1101,7 @@ fn run_vm(args: std::env::Args) -> std::result::Result<(), ()> { Argument::value("rwqcow", "PATH", "Path to a writable qcow2 disk image. (Deprecated; use --rwdisk instead.)"), Argument::value("rw-pmem-device", "PATH", "Path to a writable disk image."), Argument::value("pmem-device", "PATH", "Path to a disk image."), + Argument::value("pstore", "path=PATH,size=SIZE", "Path to pstore buffer backend file follewed by size."), Argument::value("host_ip", "IP", "IP address to assign to host tap interface."), diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs index fa5bc85..84f7dfd 100644 --- a/x86_64/src/lib.rs +++ b/x86_64/src/lib.rs @@ -87,6 +87,7 @@ pub enum Error { LoadCmdline(kernel_loader::Error), LoadInitrd(arch::LoadImageError), LoadKernel(kernel_loader::Error), + Pstore(arch::pstore::Error), RegisterIrqfd(sys_util::Error), RegisterVsock(arch::DeviceRegistrationError), SetLint(interrupts::Error), @@ -132,6 +133,7 @@ impl Display for Error { LoadCmdline(e) => write!(f, "error loading command line: {}", e), LoadInitrd(e) => write!(f, "error loading initrd: {}", e), LoadKernel(e) => write!(f, "error loading Kernel: {}", e), + Pstore(e) => write!(f, "failed to allocate pstore region: {}", e), RegisterIrqfd(e) => write!(f, "error registering an IrqFd: {}", e), RegisterVsock(e) => write!(f, "error registering virtual socket device: {}", e), SetLint(e) => write!(f, "failed to set interrupts: {}", e), @@ -369,6 +371,14 @@ impl arch::LinuxArch for X8664arch { let stdio_serial_num = Self::setup_serial_devices(&mut vm, &mut io_bus, serial_parameters, serial_jail)?; + let ramoops_region = match components.pstore { + Some(pstore) => Some( + arch::pstore::create_memory_region(&mut vm, &mut resources, &pstore) + .map_err(Error::Pstore)?, + ), + None => None, + }; + match components.vm_image { VmImage::Bios(ref mut bios) => Self::load_bios(&mem, bios)?, VmImage::Kernel(ref mut kernel_image) => { @@ -377,6 +387,25 @@ impl arch::LinuxArch for X8664arch { cmdline.insert_str(¶m).map_err(Error::Cmdline)?; } + // It seems that default record_size is only 4096 byte even if crosvm allocates + // more memory. It means that one crash can only 4096 byte. + // Set record_size and console_size to 1/4 of allocated memory size. + // This configulation is same as the host. + if let Some(ramoops_region) = ramoops_region { + let ramoops_opts = [ + ("mem_address", ramoops_region.address), + ("mem_size", ramoops_region.size as u64), + ("console_size", (ramoops_region.size / 4) as u64), + ("record_size", (ramoops_region.size / 4) as u64), + ("dump_oops", 1_u64), + ]; + for (name, val) in &ramoops_opts { + cmdline + .insert_str(format!("ramoops.{}={:#x}", name, val)) + .map_err(Error::Cmdline)?; + } + } + // separate out load_kernel from other setup to get a specific error for // kernel loading let (params, kernel_end) = Self::load_kernel(&mem, kernel_image)?; |