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 /arch/src/fdt.rs | |
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 'arch/src/fdt.rs')
-rw-r--r-- | arch/src/fdt.rs | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/arch/src/fdt.rs b/arch/src/fdt.rs new file mode 100644 index 0000000..20a017b --- /dev/null +++ b/arch/src/fdt.rs @@ -0,0 +1,249 @@ +// 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. + +use byteorder::{BigEndian, ByteOrder}; +use libc::{c_char, c_int, c_void}; +use std::error::{self, Error as FdtError}; +use std::ffi::{CStr, CString}; +use std::fmt; +use std::ptr::null; + +// This links to libfdt which handles the creation of the binary blob +// flattened device tree (fdt) that is passed to the kernel and indicates +// the hardware configuration of the machine. +#[link(name = "fdt")] +extern "C" { + fn fdt_create(buf: *mut c_void, bufsize: c_int) -> c_int; + fn fdt_finish_reservemap(fdt: *mut c_void) -> c_int; + fn fdt_begin_node(fdt: *mut c_void, name: *const c_char) -> c_int; + fn fdt_property(fdt: *mut c_void, name: *const c_char, val: *const c_void, len: c_int) + -> c_int; + fn fdt_end_node(fdt: *mut c_void) -> c_int; + fn fdt_open_into(fdt: *const c_void, buf: *mut c_void, bufsize: c_int) -> c_int; + fn fdt_finish(fdt: *const c_void) -> c_int; + fn fdt_pack(fdt: *mut c_void) -> c_int; +} + +#[derive(Debug)] +pub enum Error { + FdtCreateError(c_int), + FdtFinishReservemapError(c_int), + FdtBeginNodeError(c_int), + FdtPropertyError(c_int), + FdtEndNodeError(c_int), + FdtOpenIntoError(c_int), + FdtFinishError(c_int), + FdtPackError(c_int), + FdtGuestMemoryWriteError, +} + +impl error::Error for Error { + fn description(&self) -> &str { + match self { + &Error::FdtCreateError(_) => "Error creating FDT", + &Error::FdtFinishReservemapError(_) => "Error finishing reserve map", + &Error::FdtBeginNodeError(_) => "Error beginning FDT node", + &Error::FdtPropertyError(_) => "Error adding FDT property", + &Error::FdtEndNodeError(_) => "Error ending FDT node", + &Error::FdtOpenIntoError(_) => "Error copying FDT to Guest", + &Error::FdtFinishError(_) => "Error performing FDT finish", + &Error::FdtPackError(_) => "Error packing FDT", + &Error::FdtGuestMemoryWriteError => "Error writing FDT to Guest Memory", + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let prefix = "Libfdt Error: "; + match self { + &Error::FdtCreateError(fdt_ret) + | &Error::FdtFinishReservemapError(fdt_ret) + | &Error::FdtBeginNodeError(fdt_ret) + | &Error::FdtPropertyError(fdt_ret) + | &Error::FdtEndNodeError(fdt_ret) + | &Error::FdtOpenIntoError(fdt_ret) + | &Error::FdtFinishError(fdt_ret) + | &Error::FdtPackError(fdt_ret) => write!( + f, + "{} {} code: {}", + prefix, + Error::description(self), + fdt_ret + ), + &Error::FdtGuestMemoryWriteError => { + write!(f, "{} {}", prefix, Error::description(self)) + } + } + } +} + +pub fn begin_node(fdt: &mut Vec<u8>, name: &str) -> Result<(), Box<Error>> { + let cstr_name = CString::new(name).unwrap(); + + // Safe because we allocated fdt and converted name to a CString + let fdt_ret = unsafe { fdt_begin_node(fdt.as_mut_ptr() as *mut c_void, cstr_name.as_ptr()) }; + if fdt_ret != 0 { + return Err(Box::new(Error::FdtBeginNodeError(fdt_ret))); + } + Ok(()) +} + +pub fn end_node(fdt: &mut Vec<u8>) -> Result<(), Box<Error>> { + // Safe because we allocated fdt + let fdt_ret = unsafe { fdt_end_node(fdt.as_mut_ptr() as *mut c_void) }; + if fdt_ret != 0 { + return Err(Box::new(Error::FdtEndNodeError(fdt_ret))); + } + Ok(()) +} + +pub fn property(fdt: &mut Vec<u8>, name: &str, val: &[u8]) -> Result<(), Box<Error>> { + let cstr_name = CString::new(name).unwrap(); + let val_ptr = val.as_ptr() as *const c_void; + + // Safe because we allocated fdt and converted name to a CString + let fdt_ret = unsafe { + fdt_property( + fdt.as_mut_ptr() as *mut c_void, + cstr_name.as_ptr(), + val_ptr, + val.len() as i32, + ) + }; + if fdt_ret != 0 { + return Err(Box::new(Error::FdtPropertyError(fdt_ret))); + } + Ok(()) +} + +fn cpu_to_fdt32(input: u32) -> [u8; 4] { + let mut buf = [0; 4]; + BigEndian::write_u32(&mut buf, input); + buf +} + +fn cpu_to_fdt64(input: u64) -> [u8; 8] { + let mut buf = [0; 8]; + BigEndian::write_u64(&mut buf, input); + buf +} + +pub fn property_u32(fdt: &mut Vec<u8>, name: &str, val: u32) -> Result<(), Box<Error>> { + property(fdt, name, &cpu_to_fdt32(val)) +} + +pub fn property_u64(fdt: &mut Vec<u8>, name: &str, val: u64) -> Result<(), Box<Error>> { + property(fdt, name, &cpu_to_fdt64(val)) +} + +// Helper to generate a properly formatted byte vector using 32-bit cells +pub fn generate_prop32(cells: &[u32]) -> Vec<u8> { + let mut ret: Vec<u8> = Vec::new(); + for &e in cells { + ret.extend(cpu_to_fdt32(e).into_iter()); + } + ret +} + +// Helper to generate a properly formatted byte vector using 64-bit cells +pub fn generate_prop64(cells: &[u64]) -> Vec<u8> { + let mut ret: Vec<u8> = Vec::new(); + for &e in cells { + ret.extend(cpu_to_fdt64(e).into_iter()); + } + ret +} + +pub fn property_null(fdt: &mut Vec<u8>, name: &str) -> Result<(), Box<Error>> { + let cstr_name = CString::new(name).unwrap(); + + // Safe because we allocated fdt, converted name to a CString + let fdt_ret = unsafe { + fdt_property( + fdt.as_mut_ptr() as *mut c_void, + cstr_name.as_ptr(), + null(), + 0, + ) + }; + if fdt_ret != 0 { + return Err(Box::new(Error::FdtPropertyError(fdt_ret))); + } + Ok(()) +} + +pub fn property_cstring( + fdt: &mut Vec<u8>, + name: &str, + cstr_value: &CStr, +) -> Result<(), Box<Error>> { + let value_bytes = cstr_value.to_bytes_with_nul(); + let cstr_name = CString::new(name).unwrap(); + + // Safe because we allocated fdt, converted name and value to CStrings + let fdt_ret = unsafe { + fdt_property( + fdt.as_mut_ptr() as *mut c_void, + cstr_name.as_ptr(), + value_bytes.as_ptr() as *mut c_void, + value_bytes.len() as i32, + ) + }; + if fdt_ret != 0 { + return Err(Box::new(Error::FdtPropertyError(fdt_ret))); + } + Ok(()) +} + +pub fn property_string(fdt: &mut Vec<u8>, name: &str, value: &str) -> Result<(), Box<Error>> { + let cstr_value = CString::new(value).unwrap(); + property_cstring(fdt, name, &cstr_value) +} + +pub fn start_fdt(fdt: &mut Vec<u8>, fdt_max_size: usize) -> Result<(), Box<Error>> { + // Safe since we allocated this array with fdt_max_size + let mut fdt_ret = unsafe { fdt_create(fdt.as_mut_ptr() as *mut c_void, fdt_max_size as c_int) }; + + if fdt_ret != 0 { + return Err(Box::new(Error::FdtCreateError(fdt_ret))); + } + // Safe since we allocated this array + fdt_ret = unsafe { fdt_finish_reservemap(fdt.as_mut_ptr() as *mut c_void) }; + if fdt_ret != 0 { + return Err(Box::new(Error::FdtFinishReservemapError(fdt_ret))); + } + Ok(()) +} + +pub fn finish_fdt( + fdt: &mut Vec<u8>, + fdt_final: &mut Vec<u8>, + fdt_max_size: usize, +) -> Result<(), Box<Error>> { + // Safe since we allocated fdt_final and previously passed in it's size + let mut fdt_ret = unsafe { fdt_finish(fdt.as_mut_ptr() as *mut c_void) }; + if fdt_ret != 0 { + return Err(Box::new(Error::FdtFinishError(fdt_ret))); + } + + // Safe because we allocated both arrays with the correct size + fdt_ret = unsafe { + fdt_open_into( + fdt.as_mut_ptr() as *mut c_void, + fdt_final.as_mut_ptr() as *mut c_void, + fdt_max_size as i32, + ) + }; + if fdt_ret != 0 { + return Err(Box::new(Error::FdtOpenIntoError(fdt_ret))); + } + + // Safe since we allocated fdt_final + fdt_ret = unsafe { fdt_pack(fdt_final.as_mut_ptr() as *mut c_void) }; + if fdt_ret != 0 { + return Err(Box::new(Error::FdtPackError(fdt_ret))); + } + Ok(()) +} |