diff options
author | Tristan Muntsinger <muntsinger@google.com> | 2018-12-21 16:01:56 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2019-01-28 14:17:10 -0800 |
commit | 4133b0120d1e16cafbb373b2ae17a214b594038b (patch) | |
tree | 177506988846e4b86e639cdb963bbaba0c4e6ca9 /x86_64 | |
parent | f052cfefc8d6d27fa068c34190615db1819b8fef (diff) | |
download | crosvm-4133b0120d1e16cafbb373b2ae17a214b594038b.tar crosvm-4133b0120d1e16cafbb373b2ae17a214b594038b.tar.gz crosvm-4133b0120d1e16cafbb373b2ae17a214b594038b.tar.bz2 crosvm-4133b0120d1e16cafbb373b2ae17a214b594038b.tar.lz crosvm-4133b0120d1e16cafbb373b2ae17a214b594038b.tar.xz crosvm-4133b0120d1e16cafbb373b2ae17a214b594038b.tar.zst crosvm-4133b0120d1e16cafbb373b2ae17a214b594038b.zip |
crosvm: x86_64 guest support for android device-tree
This device tree is derived from the Android fstab file which is provided via command line flag. BUG=chromium:922737 TEST=None CQ-DEPEND=CL:1415390 CQ-DEPEND=CL:1415270 Change-Id: Idd007c844f84cab3ff37be16a718f14e5f630312 Reviewed-on: https://chromium-review.googlesource.com/1370058 Commit-Ready: Daniel Verkamp <dverkamp@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'x86_64')
-rw-r--r-- | x86_64/src/fdt.rs | 91 | ||||
-rw-r--r-- | x86_64/src/lib.rs | 43 |
2 files changed, 129 insertions, 5 deletions
diff --git a/x86_64/src/fdt.rs b/x86_64/src/fdt.rs new file mode 100644 index 0000000..afbb602 --- /dev/null +++ b/x86_64/src/fdt.rs @@ -0,0 +1,91 @@ +// 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. + +extern crate arch; + +use arch::fdt::{begin_node, end_node, finish_fdt, property_string, start_fdt, Error}; +use bootparam::setup_data; +use bootparam::SETUP_DTB; +use std::fs::File; +use std::io::BufRead; +use std::io::BufReader; +use std::mem; +use sys_util::{GuestAddress, GuestMemory}; + +use X86_64_FDT_MAX_SIZE; + +/// Creates a flattened device tree containing all of the parameters for the +/// kernel and loads it into the guest memory at the specified offset. +/// +/// # Arguments +/// +/// * `fdt_max_size` - The amount of space reserved for the device tree +/// * `guest_mem` - The guest memory object +/// * `fdt_load_offset` - The offset into physical memory for the device tree +/// * `android_fstab` - the File object for the android fstab +pub fn create_fdt( + fdt_max_size: usize, + guest_mem: &GuestMemory, + fdt_load_offset: u64, + android_fstab: &mut File, +) -> Result<(), Box<Error>> { + // Reserve space for the setup_data + let fdt_data_size = fdt_max_size - mem::size_of::<setup_data>(); + + let mut fdt = vec![0; fdt_data_size]; + start_fdt(&mut fdt, fdt_data_size)?; + + // The whole thing is put into one giant node with some top level properties + begin_node(&mut fdt, "")?; + begin_node(&mut fdt, "firmware")?; + begin_node(&mut fdt, "android")?; + property_string(&mut fdt, "compatible", "android,firmware")?; + begin_node(&mut fdt, "fstab")?; + property_string(&mut fdt, "compatible", "android,fstab")?; + let file = BufReader::new(android_fstab); + for line in file.lines().filter_map(|l| l.ok()) { + let vec = line.split(" ").collect::<Vec<&str>>(); + assert_eq!(vec.len(), 5); + let partition = &vec[1][1..]; + begin_node(&mut fdt, partition)?; + property_string(&mut fdt, "compatible", &("android,".to_owned() + partition))?; + property_string(&mut fdt, "dev", vec[0])?; + property_string(&mut fdt, "type", vec[2])?; + property_string(&mut fdt, "mnt_flags", vec[3])?; + property_string(&mut fdt, "fsmgr_flags", vec[4])?; + end_node(&mut fdt)?; + } + end_node(&mut fdt)?; + end_node(&mut fdt)?; + end_node(&mut fdt)?; + end_node(&mut fdt)?; + + // Allocate another buffer so we can format and then write fdt to guest + let mut fdt_final = vec![0; fdt_data_size]; + finish_fdt(&mut fdt, &mut fdt_final, fdt_data_size)?; + + let mut hdr: setup_data = Default::default(); + hdr.next = 0; + hdr.type_ = SETUP_DTB; + hdr.len = fdt_data_size as u32; + + assert!(fdt_data_size as u64 <= X86_64_FDT_MAX_SIZE); + + let fdt_address = GuestAddress(fdt_load_offset); + guest_mem + .checked_offset(fdt_address, fdt_data_size as u64) + .ok_or(Error::FdtGuestMemoryWriteError)?; + guest_mem + .write_obj_at_addr(hdr, fdt_address) + .map_err(|_| Error::FdtGuestMemoryWriteError)?; + + let fdt_data_address = GuestAddress(fdt_load_offset + mem::size_of::<setup_data>() as u64); + let written = guest_mem + .write_at_addr(fdt_final.as_slice(), fdt_data_address) + .map_err(|_| Error::FdtGuestMemoryWriteError)?; + if written < fdt_data_size { + return Err(Box::new(Error::FdtGuestMemoryWriteError)); + } + Ok(()) +} diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs index 2857bb7..ed5637d 100644 --- a/x86_64/src/lib.rs +++ b/x86_64/src/lib.rs @@ -16,6 +16,10 @@ extern crate resources; extern crate sync; extern crate sys_util; +mod fdt; + +const X86_64_FDT_MAX_SIZE: u64 = 0x200000; + #[allow(dead_code)] #[allow(non_upper_case_globals)] #[allow(non_camel_case_types)] @@ -36,6 +40,7 @@ impl Clone for bootparam::boot_params { } // boot_params is just a series of ints, it is safe to initialize it. unsafe impl data_model::DataInit for bootparam::boot_params {} +unsafe impl data_model::DataInit for bootparam::setup_data {} #[allow(dead_code)] #[allow(non_upper_case_globals)] @@ -159,11 +164,14 @@ const X86_64_IRQ_BASE: u32 = 5; fn configure_system( guest_mem: &GuestMemory, + _mem_size: u64, kernel_addr: GuestAddress, cmdline_addr: GuestAddress, cmdline_size: usize, num_cpus: u8, pci_irqs: Vec<(u32, PciInterruptPin)>, + android_fstab: &mut Option<File>, + kernel_end: u64, ) -> Result<()> { const EBDA_START: u64 = 0x0009fc00; const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55; @@ -178,12 +186,18 @@ fn configure_system( let mut params: boot_params = Default::default(); + let kernel_end_aligned = (((kernel_end + 64 - 1) / 64) * 64) + 64; + let dtb_start = GuestAddress(kernel_end_aligned); + params.hdr.type_of_loader = KERNEL_LOADER_OTHER; params.hdr.boot_flag = KERNEL_BOOT_FLAG_MAGIC; params.hdr.header = KERNEL_HDR_MAGIC; params.hdr.cmd_line_ptr = cmdline_addr.offset() as u32; params.hdr.cmdline_size = cmdline_size as u32; params.hdr.kernel_alignment = KERNEL_MIN_ALIGNMENT_BYTES; + if android_fstab.is_some() { + params.hdr.setup_data = dtb_start.offset(); + } add_e820_entry(&mut params, 0, EBDA_START, E820_RAM)?; @@ -220,6 +234,14 @@ fn configure_system( .write_obj_at_addr(params, zero_page_addr) .map_err(|_| Error::ZeroPageSetup)?; + if let Some(fstab) = android_fstab { + fdt::create_fdt( + X86_64_FDT_MAX_SIZE as usize, + guest_mem, + dtb_start.offset(), + fstab, + )?; + } Ok(()) } @@ -317,13 +339,16 @@ impl arch::LinuxArch for X8664arch { // separate out load_kernel from other setup to get a specific error for // kernel loading - Self::load_kernel(&mem, &mut components.kernel_image)?; + let kernel_end = Self::load_kernel(&mem, &mut components.kernel_image)?; + Self::setup_system_memory( &mem, components.memory_mb, vcpu_count, &CString::new(cmdline).unwrap(), pci_irqs, + components.android_fstab, + kernel_end, )?; Ok(RunnableLinuxVm { @@ -348,9 +373,12 @@ impl X8664arch { /// /// * `mem` - The memory to be used by the guest. /// * `kernel_image` - the File object for the specified kernel. - fn load_kernel(mem: &GuestMemory, mut kernel_image: &mut File) -> Result<()> { - kernel_loader::load_kernel(mem, GuestAddress(KERNEL_START_OFFSET), &mut kernel_image)?; - Ok(()) + fn load_kernel(mem: &GuestMemory, mut kernel_image: &mut File) -> Result<u64> { + Ok(kernel_loader::load_kernel( + mem, + GuestAddress(KERNEL_START_OFFSET), + &mut kernel_image, + )?) } /// Configures the system memory space should be called once per vm before @@ -363,19 +391,24 @@ impl X8664arch { /// * `cmdline` - the kernel commandline fn setup_system_memory( mem: &GuestMemory, - _mem_size: u64, + mem_size: u64, vcpu_count: u32, cmdline: &CStr, pci_irqs: Vec<(u32, PciInterruptPin)>, + mut android_fstab: Option<File>, + kernel_end: u64, ) -> Result<()> { kernel_loader::load_cmdline(mem, GuestAddress(CMDLINE_OFFSET), cmdline)?; configure_system( mem, + mem_size, GuestAddress(KERNEL_START_OFFSET), GuestAddress(CMDLINE_OFFSET), cmdline.to_bytes().len() + 1, vcpu_count as u8, pci_irqs, + &mut android_fstab, + kernel_end, )?; Ok(()) } |