1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use arch::android::create_android_fdt;
6 use arch::fdt::{Error, FdtWriter};
7 use data_model::DataInit;
8 use std::fs::File;
9 use std::mem;
10 use vm_memory::{GuestAddress, GuestMemory};
11
12 use crate::bootparam::setup_data;
13 use crate::{SETUP_DTB, X86_64_FDT_MAX_SIZE};
14
15 // Like `setup_data` without the incomplete array field at the end, which allows us to safely
16 // implement Copy, Clone, and DataInit.
17 #[repr(C)]
18 #[derive(Copy, Clone, Default)]
19 struct setup_data_hdr {
20 pub next: u64,
21 pub type_: u32,
22 pub len: u32,
23 }
24
25 unsafe impl DataInit for setup_data_hdr {}
26
27 /// Creates a flattened device tree containing all of the parameters for the
28 /// kernel and loads it into the guest memory at the specified offset.
29 ///
30 /// # Arguments
31 ///
32 /// * `fdt_max_size` - The amount of space reserved for the device tree
33 /// * `guest_mem` - The guest memory object
34 /// * `fdt_load_offset` - The offset into physical memory for the device tree
35 /// * `android_fstab` - the File object for the android fstab
create_fdt( fdt_max_size: usize, guest_mem: &GuestMemory, fdt_load_offset: u64, android_fstab: File, ) -> Result<usize, Error>36 pub fn create_fdt(
37 fdt_max_size: usize,
38 guest_mem: &GuestMemory,
39 fdt_load_offset: u64,
40 android_fstab: File,
41 ) -> Result<usize, Error> {
42 // Reserve space for the setup_data
43 let fdt_data_size = fdt_max_size - mem::size_of::<setup_data>();
44
45 let mut fdt = FdtWriter::new(&[]);
46
47 // The whole thing is put into one giant node with some top level properties
48 let root_node = fdt.begin_node("")?;
49 create_android_fdt(&mut fdt, android_fstab)?;
50 fdt.end_node(root_node)?;
51
52 let fdt_final = fdt.finish(fdt_data_size)?;
53
54 assert_eq!(
55 mem::size_of::<setup_data>(),
56 mem::size_of::<setup_data_hdr>()
57 );
58 let hdr = setup_data_hdr {
59 next: 0,
60 type_: SETUP_DTB,
61 len: fdt_data_size as u32,
62 };
63
64 assert!(fdt_data_size as u64 <= X86_64_FDT_MAX_SIZE);
65
66 let fdt_address = GuestAddress(fdt_load_offset);
67 guest_mem
68 .checked_offset(fdt_address, fdt_data_size as u64)
69 .ok_or(Error::FdtGuestMemoryWriteError)?;
70 guest_mem
71 .write_obj_at_addr(hdr, fdt_address)
72 .map_err(|_| Error::FdtGuestMemoryWriteError)?;
73
74 let fdt_data_address = GuestAddress(fdt_load_offset + mem::size_of::<setup_data>() as u64);
75 let written = guest_mem
76 .write_at_addr(fdt_final.as_slice(), fdt_data_address)
77 .map_err(|_| Error::FdtGuestMemoryWriteError)?;
78 if written < fdt_data_size {
79 return Err(Error::FdtGuestMemoryWriteError);
80 }
81 Ok(fdt_data_size)
82 }
83