• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 byteorder::{BigEndian, ByteOrder};
6 use libc::{c_char, c_int, c_void};
7 use std::ffi::{CStr, CString};
8 use std::fmt::{self, Display};
9 use std::io;
10 use std::ptr::null;
11 
12 // This links to libfdt which handles the creation of the binary blob
13 // flattened device tree (fdt) that is passed to the kernel and indicates
14 // the hardware configuration of the machine.
15 #[link(name = "fdt")]
16 extern "C" {
fdt_create(buf: *mut c_void, bufsize: c_int) -> c_int17     fn fdt_create(buf: *mut c_void, bufsize: c_int) -> c_int;
fdt_finish_reservemap(fdt: *mut c_void) -> c_int18     fn fdt_finish_reservemap(fdt: *mut c_void) -> c_int;
fdt_begin_node(fdt: *mut c_void, name: *const c_char) -> c_int19     fn fdt_begin_node(fdt: *mut c_void, name: *const c_char) -> c_int;
fdt_property(fdt: *mut c_void, name: *const c_char, val: *const c_void, len: c_int) -> c_int20     fn fdt_property(fdt: *mut c_void, name: *const c_char, val: *const c_void, len: c_int)
21         -> c_int;
fdt_end_node(fdt: *mut c_void) -> c_int22     fn fdt_end_node(fdt: *mut c_void) -> c_int;
fdt_open_into(fdt: *const c_void, buf: *mut c_void, bufsize: c_int) -> c_int23     fn fdt_open_into(fdt: *const c_void, buf: *mut c_void, bufsize: c_int) -> c_int;
fdt_finish(fdt: *const c_void) -> c_int24     fn fdt_finish(fdt: *const c_void) -> c_int;
fdt_pack(fdt: *mut c_void) -> c_int25     fn fdt_pack(fdt: *mut c_void) -> c_int;
26 }
27 
28 #[derive(Debug)]
29 pub enum Error {
30     FdtCreateError(c_int),
31     FdtFinishReservemapError(c_int),
32     FdtBeginNodeError(c_int),
33     FdtPropertyError(c_int),
34     FdtEndNodeError(c_int),
35     FdtOpenIntoError(c_int),
36     FdtFinishError(c_int),
37     FdtPackError(c_int),
38     FdtGuestMemoryWriteError,
39     FdtFileParseError,
40     FdtIoError(io::Error),
41 }
42 
43 impl Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result44     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45         use self::Error::*;
46 
47         write!(f, "libfdt: ")?;
48 
49         match self {
50             FdtCreateError(ret) => write!(f, "error creating FDT, code={}", ret),
51             FdtFinishReservemapError(ret) => write!(f, "error finishing reserve map, code={}", ret),
52             FdtBeginNodeError(ret) => write!(f, "error beginning FDT node, code={}", ret),
53             FdtPropertyError(ret) => write!(f, "error adding FDT property, code={}", ret),
54             FdtEndNodeError(ret) => write!(f, "error ending FDT node, code={}", ret),
55             FdtOpenIntoError(ret) => write!(f, "error copying FDT to Guest, code={}", ret),
56             FdtFinishError(ret) => write!(f, "error performing FDT finish, code={}", ret),
57             FdtPackError(ret) => write!(f, "error packing FDT, code={}", ret),
58             FdtGuestMemoryWriteError => write!(f, "error writing FDT to guest memory"),
59             FdtFileParseError => write!(f, "parse error reading FDT parameters"),
60             FdtIoError(ret) => write!(f, "I/O error reading FDT parameters code={}", ret),
61         }
62     }
63 }
64 
65 pub type Result<T> = std::result::Result<T, Error>;
66 
67 impl std::error::Error for Error {}
68 
begin_node(fdt: &mut Vec<u8>, name: &str) -> Result<()>69 pub fn begin_node(fdt: &mut Vec<u8>, name: &str) -> Result<()> {
70     let cstr_name = CString::new(name).unwrap();
71 
72     // Safe because we allocated fdt and converted name to a CString
73     let fdt_ret = unsafe { fdt_begin_node(fdt.as_mut_ptr() as *mut c_void, cstr_name.as_ptr()) };
74     if fdt_ret != 0 {
75         return Err(Error::FdtBeginNodeError(fdt_ret));
76     }
77     Ok(())
78 }
79 
end_node(fdt: &mut Vec<u8>) -> Result<()>80 pub fn end_node(fdt: &mut Vec<u8>) -> Result<()> {
81     // Safe because we allocated fdt
82     let fdt_ret = unsafe { fdt_end_node(fdt.as_mut_ptr() as *mut c_void) };
83     if fdt_ret != 0 {
84         return Err(Error::FdtEndNodeError(fdt_ret));
85     }
86     Ok(())
87 }
88 
property(fdt: &mut Vec<u8>, name: &str, val: &[u8]) -> Result<()>89 pub fn property(fdt: &mut Vec<u8>, name: &str, val: &[u8]) -> Result<()> {
90     let cstr_name = CString::new(name).unwrap();
91     let val_ptr = val.as_ptr() as *const c_void;
92 
93     // Safe because we allocated fdt and converted name to a CString
94     let fdt_ret = unsafe {
95         fdt_property(
96             fdt.as_mut_ptr() as *mut c_void,
97             cstr_name.as_ptr(),
98             val_ptr,
99             val.len() as i32,
100         )
101     };
102     if fdt_ret != 0 {
103         return Err(Error::FdtPropertyError(fdt_ret));
104     }
105     Ok(())
106 }
107 
cpu_to_fdt32(input: u32) -> [u8; 4]108 fn cpu_to_fdt32(input: u32) -> [u8; 4] {
109     let mut buf = [0; 4];
110     BigEndian::write_u32(&mut buf, input);
111     buf
112 }
113 
cpu_to_fdt64(input: u64) -> [u8; 8]114 fn cpu_to_fdt64(input: u64) -> [u8; 8] {
115     let mut buf = [0; 8];
116     BigEndian::write_u64(&mut buf, input);
117     buf
118 }
119 
property_u32(fdt: &mut Vec<u8>, name: &str, val: u32) -> Result<()>120 pub fn property_u32(fdt: &mut Vec<u8>, name: &str, val: u32) -> Result<()> {
121     property(fdt, name, &cpu_to_fdt32(val))
122 }
123 
property_u64(fdt: &mut Vec<u8>, name: &str, val: u64) -> Result<()>124 pub fn property_u64(fdt: &mut Vec<u8>, name: &str, val: u64) -> Result<()> {
125     property(fdt, name, &cpu_to_fdt64(val))
126 }
127 
128 // Helper to generate a properly formatted byte vector using 32-bit cells
generate_prop32(cells: &[u32]) -> Vec<u8>129 pub fn generate_prop32(cells: &[u32]) -> Vec<u8> {
130     let mut ret: Vec<u8> = Vec::new();
131     for &e in cells {
132         ret.extend(&cpu_to_fdt32(e));
133     }
134     ret
135 }
136 
137 // Helper to generate a properly formatted byte vector using 64-bit cells
generate_prop64(cells: &[u64]) -> Vec<u8>138 pub fn generate_prop64(cells: &[u64]) -> Vec<u8> {
139     let mut ret: Vec<u8> = Vec::new();
140     for &e in cells {
141         ret.extend(&cpu_to_fdt64(e));
142     }
143     ret
144 }
145 
property_null(fdt: &mut Vec<u8>, name: &str) -> Result<()>146 pub fn property_null(fdt: &mut Vec<u8>, name: &str) -> Result<()> {
147     let cstr_name = CString::new(name).unwrap();
148 
149     // Safe because we allocated fdt, converted name to a CString
150     let fdt_ret = unsafe {
151         fdt_property(
152             fdt.as_mut_ptr() as *mut c_void,
153             cstr_name.as_ptr(),
154             null(),
155             0,
156         )
157     };
158     if fdt_ret != 0 {
159         return Err(Error::FdtPropertyError(fdt_ret));
160     }
161     Ok(())
162 }
163 
property_cstring(fdt: &mut Vec<u8>, name: &str, cstr_value: &CStr) -> Result<()>164 pub fn property_cstring(fdt: &mut Vec<u8>, name: &str, cstr_value: &CStr) -> Result<()> {
165     let value_bytes = cstr_value.to_bytes_with_nul();
166     let cstr_name = CString::new(name).unwrap();
167 
168     // Safe because we allocated fdt, converted name and value to CStrings
169     let fdt_ret = unsafe {
170         fdt_property(
171             fdt.as_mut_ptr() as *mut c_void,
172             cstr_name.as_ptr(),
173             value_bytes.as_ptr() as *mut c_void,
174             value_bytes.len() as i32,
175         )
176     };
177     if fdt_ret != 0 {
178         return Err(Error::FdtPropertyError(fdt_ret));
179     }
180     Ok(())
181 }
182 
property_string(fdt: &mut Vec<u8>, name: &str, value: &str) -> Result<()>183 pub fn property_string(fdt: &mut Vec<u8>, name: &str, value: &str) -> Result<()> {
184     let cstr_value = CString::new(value).unwrap();
185     property_cstring(fdt, name, &cstr_value)
186 }
187 
start_fdt(fdt: &mut Vec<u8>, fdt_max_size: usize) -> Result<()>188 pub fn start_fdt(fdt: &mut Vec<u8>, fdt_max_size: usize) -> Result<()> {
189     // Safe since we allocated this array with fdt_max_size
190     let mut fdt_ret = unsafe { fdt_create(fdt.as_mut_ptr() as *mut c_void, fdt_max_size as c_int) };
191 
192     if fdt_ret != 0 {
193         return Err(Error::FdtCreateError(fdt_ret));
194     }
195     // Safe since we allocated this array
196     fdt_ret = unsafe { fdt_finish_reservemap(fdt.as_mut_ptr() as *mut c_void) };
197     if fdt_ret != 0 {
198         return Err(Error::FdtFinishReservemapError(fdt_ret));
199     }
200     Ok(())
201 }
202 
finish_fdt(fdt: &mut Vec<u8>, fdt_final: &mut Vec<u8>, fdt_max_size: usize) -> Result<()>203 pub fn finish_fdt(fdt: &mut Vec<u8>, fdt_final: &mut Vec<u8>, fdt_max_size: usize) -> Result<()> {
204     // Safe since we allocated fdt_final and previously passed in it's size
205     let mut fdt_ret = unsafe { fdt_finish(fdt.as_mut_ptr() as *mut c_void) };
206     if fdt_ret != 0 {
207         return Err(Error::FdtFinishError(fdt_ret));
208     }
209 
210     // Safe because we allocated both arrays with the correct size
211     fdt_ret = unsafe {
212         fdt_open_into(
213             fdt.as_mut_ptr() as *mut c_void,
214             fdt_final.as_mut_ptr() as *mut c_void,
215             fdt_max_size as i32,
216         )
217     };
218     if fdt_ret != 0 {
219         return Err(Error::FdtOpenIntoError(fdt_ret));
220     }
221 
222     // Safe since we allocated fdt_final
223     fdt_ret = unsafe { fdt_pack(fdt_final.as_mut_ptr() as *mut c_void) };
224     if fdt_ret != 0 {
225         return Err(Error::FdtPackError(fdt_ret));
226     }
227     Ok(())
228 }
229