blob: d76b1a406ed878660dcf412be445f62e24a8be57 [file] [log] [blame]
Alice Wang9d4df702023-05-25 14:14:12 +00001/*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//! Integration tests of the library libfdt.
18
Jaewan Kima041d4b2023-11-10 13:38:11 +090019use core::ffi::CStr;
Jaewan Kimf163d762023-11-01 13:12:50 +090020use libfdt::{Fdt, FdtError, FdtNodeMut, Phandle};
Pierre-Clément Tosi180a7c22023-11-07 09:54:39 +000021use std::ffi::CString;
Alice Wang9d4df702023-05-25 14:14:12 +000022use std::fs;
23use std::ops::Range;
24
Jaewan Kimb635bb02023-11-01 13:00:34 +090025// TODO(b/308694211): Use cstr!() from vmbase
Jaewan Kim5b057772023-10-19 01:02:17 +090026macro_rules! cstr {
27 ($str:literal) => {{
Pierre-Clément Tosi180a7c22023-11-07 09:54:39 +000028 const S: &str = concat!($str, "\0");
29 const C: &::core::ffi::CStr = match ::core::ffi::CStr::from_bytes_with_nul(S.as_bytes()) {
30 Ok(v) => v,
31 Err(_) => panic!("string contains interior NUL"),
32 };
33 C
Jaewan Kim5b057772023-10-19 01:02:17 +090034 }};
35}
36
Alice Wang2422bdc2023-06-12 08:37:55 +000037const TEST_TREE_WITH_ONE_MEMORY_RANGE_PATH: &str = "data/test_tree_one_memory_range.dtb";
38const TEST_TREE_WITH_MULTIPLE_MEMORY_RANGES_PATH: &str =
39 "data/test_tree_multiple_memory_ranges.dtb";
40const TEST_TREE_WITH_EMPTY_MEMORY_RANGE_PATH: &str = "data/test_tree_empty_memory_range.dtb";
41const TEST_TREE_WITH_NO_MEMORY_NODE_PATH: &str = "data/test_tree_no_memory_node.dtb";
Jaewan Kim17ba7a32023-10-19 13:25:15 +090042const TEST_TREE_PHANDLE_PATH: &str = "data/test_tree_phandle.dtb";
Alice Wang9d4df702023-05-25 14:14:12 +000043
44#[test]
Alice Wang2422bdc2023-06-12 08:37:55 +000045fn retrieving_memory_from_fdt_with_one_memory_range_succeeds() {
46 let data = fs::read(TEST_TREE_WITH_ONE_MEMORY_RANGE_PATH).unwrap();
Alice Wang9d4df702023-05-25 14:14:12 +000047 let fdt = Fdt::from_slice(&data).unwrap();
48
49 const EXPECTED_FIRST_MEMORY_RANGE: Range<usize> = 0..256;
Alice Wang2422bdc2023-06-12 08:37:55 +000050 let mut memory = fdt.memory().unwrap();
Alice Wang9d4df702023-05-25 14:14:12 +000051 assert_eq!(memory.next(), Some(EXPECTED_FIRST_MEMORY_RANGE));
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +000052 assert_eq!(memory.next(), None);
Alice Wang2422bdc2023-06-12 08:37:55 +000053 assert_eq!(fdt.first_memory_range(), Ok(EXPECTED_FIRST_MEMORY_RANGE));
54}
55
56#[test]
57fn retrieving_memory_from_fdt_with_multiple_memory_ranges_succeeds() {
58 let data = fs::read(TEST_TREE_WITH_MULTIPLE_MEMORY_RANGES_PATH).unwrap();
59 let fdt = Fdt::from_slice(&data).unwrap();
60
61 const EXPECTED_FIRST_MEMORY_RANGE: Range<usize> = 0..256;
62 const EXPECTED_SECOND_MEMORY_RANGE: Range<usize> = 512..1024;
63 let mut memory = fdt.memory().unwrap();
64 assert_eq!(memory.next(), Some(EXPECTED_FIRST_MEMORY_RANGE));
65 assert_eq!(memory.next(), Some(EXPECTED_SECOND_MEMORY_RANGE));
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +000066 assert_eq!(memory.next(), None);
Alice Wang2422bdc2023-06-12 08:37:55 +000067 assert_eq!(fdt.first_memory_range(), Ok(EXPECTED_FIRST_MEMORY_RANGE));
68}
69
70#[test]
71fn retrieving_first_memory_from_fdt_with_empty_memory_range_fails() {
72 let data = fs::read(TEST_TREE_WITH_EMPTY_MEMORY_RANGE_PATH).unwrap();
73 let fdt = Fdt::from_slice(&data).unwrap();
74
75 let mut memory = fdt.memory().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +000076 assert_eq!(memory.next(), None);
Alice Wang2422bdc2023-06-12 08:37:55 +000077 assert_eq!(fdt.first_memory_range(), Err(FdtError::NotFound));
78}
79
80#[test]
81fn retrieving_memory_from_fdt_with_no_memory_node_fails() {
82 let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
83 let fdt = Fdt::from_slice(&data).unwrap();
84
85 assert_eq!(fdt.memory().unwrap_err(), FdtError::NotFound);
86 assert_eq!(fdt.first_memory_range(), Err(FdtError::NotFound));
Alice Wang9d4df702023-05-25 14:14:12 +000087}
Jaewan Kimaa638702023-09-19 13:34:01 +090088
89#[test]
90fn node_name() {
91 let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
92 let fdt = Fdt::from_slice(&data).unwrap();
93
94 let root = fdt.root().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +000095 assert_eq!(root.name(), Ok(cstr!("")));
Jaewan Kimaa638702023-09-19 13:34:01 +090096
97 let chosen = fdt.chosen().unwrap().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +000098 assert_eq!(chosen.name(), Ok(cstr!("chosen")));
Jaewan Kimaa638702023-09-19 13:34:01 +090099
Jaewan Kim5b057772023-10-19 01:02:17 +0900100 let nested_node_path = cstr!("/cpus/PowerPC,970@0");
Jaewan Kimaa638702023-09-19 13:34:01 +0900101 let nested_node = fdt.node(nested_node_path).unwrap().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000102 assert_eq!(nested_node.name(), Ok(cstr!("PowerPC,970@0")));
Jaewan Kimaa638702023-09-19 13:34:01 +0900103}
Jaewan Kimbc828d72023-09-19 15:52:08 +0900104
105#[test]
106fn node_subnodes() {
107 let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
108 let fdt = Fdt::from_slice(&data).unwrap();
109 let root = fdt.root().unwrap();
Jaewan Kima041d4b2023-11-10 13:38:11 +0900110 let expected = [Ok(cstr!("cpus")), Ok(cstr!("randomnode")), Ok(cstr!("chosen"))];
Jaewan Kimbc828d72023-09-19 15:52:08 +0900111
Jaewan Kima041d4b2023-11-10 13:38:11 +0900112 let root_subnodes = root.subnodes().unwrap();
113 let subnode_names: Vec<_> = root_subnodes.map(|node| node.name()).collect();
114 assert_eq!(subnode_names, expected);
Jaewan Kimbc828d72023-09-19 15:52:08 +0900115}
Jaewan Kim72d10902023-10-12 21:59:26 +0900116
117#[test]
118fn node_properties() {
119 let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
120 let fdt = Fdt::from_slice(&data).unwrap();
121 let root = fdt.root().unwrap();
122 let one_be = 0x1_u32.to_be_bytes();
Jaewan Kima041d4b2023-11-10 13:38:11 +0900123 type Result<T> = core::result::Result<T, FdtError>;
124 let expected: Vec<(Result<&CStr>, Result<&[u8]>)> = vec![
125 (Ok(cstr!("model")), Ok(b"MyBoardName\0".as_ref())),
126 (Ok(cstr!("compatible")), Ok(b"MyBoardName\0MyBoardFamilyName\0".as_ref())),
127 (Ok(cstr!("#address-cells")), Ok(&one_be)),
128 (Ok(cstr!("#size-cells")), Ok(&one_be)),
129 (Ok(cstr!("empty_prop")), Ok(&[])),
Jaewan Kim72d10902023-10-12 21:59:26 +0900130 ];
131
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000132 let properties = root.properties().unwrap();
Jaewan Kima041d4b2023-11-10 13:38:11 +0900133 let subnode_properties: Vec<_> = properties.map(|prop| (prop.name(), prop.value())).collect();
134
135 assert_eq!(subnode_properties, expected);
Jaewan Kim72d10902023-10-12 21:59:26 +0900136}
Jaewan Kim5b057772023-10-19 01:02:17 +0900137
138#[test]
139fn node_supernode_at_depth() {
140 let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
141 let fdt = Fdt::from_slice(&data).unwrap();
142 let node = fdt.node(cstr!("/cpus/PowerPC,970@1")).unwrap().unwrap();
Jaewan Kima041d4b2023-11-10 13:38:11 +0900143 let expected = vec![Ok(cstr!("")), Ok(cstr!("cpus")), Ok(cstr!("PowerPC,970@1"))];
Jaewan Kim5b057772023-10-19 01:02:17 +0900144
Jaewan Kima041d4b2023-11-10 13:38:11 +0900145 let mut supernode_names = vec![];
146 let mut depth = 0;
147 while let Ok(supernode) = node.supernode_at_depth(depth) {
148 supernode_names.push(supernode.name());
149 depth += 1;
Jaewan Kim5b057772023-10-19 01:02:17 +0900150 }
Jaewan Kima041d4b2023-11-10 13:38:11 +0900151
152 assert_eq!(supernode_names, expected);
Jaewan Kim5b057772023-10-19 01:02:17 +0900153}
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900154
155#[test]
156fn phandle_new() {
Pierre-Clément Tosieba27792023-10-30 12:04:12 +0000157 let valid_phandles = [
158 u32::from(Phandle::MIN),
159 u32::from(Phandle::MIN).checked_add(1).unwrap(),
160 0x55,
161 u32::from(Phandle::MAX).checked_sub(1).unwrap(),
162 u32::from(Phandle::MAX),
163 ];
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900164
Pierre-Clément Tosieba27792023-10-30 12:04:12 +0000165 for value in valid_phandles {
166 let phandle = Phandle::new(value).unwrap();
167
168 assert_eq!(value.try_into(), Ok(phandle));
169 assert_eq!(u32::from(phandle), value);
170 }
171
172 let bad_phandles = [
173 u32::from(Phandle::MIN).checked_sub(1).unwrap(),
174 u32::from(Phandle::MAX).checked_add(1).unwrap(),
175 ];
176
177 for value in bad_phandles {
178 assert_eq!(Phandle::new(value), None);
179 assert_eq!(Phandle::try_from(value), Err(FdtError::BadPhandle));
180 }
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900181}
182
183#[test]
184fn max_phandle() {
185 let data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
186 let fdt = Fdt::from_slice(&data).unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000187 let phandle = Phandle::new(0xFF).unwrap();
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900188
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000189 assert_eq!(fdt.max_phandle(), Ok(phandle));
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900190}
191
192#[test]
193fn node_with_phandle() {
194 let data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
195 let fdt = Fdt::from_slice(&data).unwrap();
196
197 // Test linux,phandle
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000198 let phandle = Phandle::new(0xFF).unwrap();
199 let node = fdt.node_with_phandle(phandle).unwrap().unwrap();
200 assert_eq!(node.name(), Ok(cstr!("node_zz")));
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900201
202 // Test phandle
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000203 let phandle = Phandle::new(0x22).unwrap();
204 let node = fdt.node_with_phandle(phandle).unwrap().unwrap();
205 assert_eq!(node.name(), Ok(cstr!("node_abc")));
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900206}
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900207
208#[test]
Jaewan Kimc63246d2023-11-09 15:41:01 +0900209fn node_mut_with_phandle() {
210 let mut data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
211 let fdt = Fdt::from_mut_slice(&mut data).unwrap();
212
213 // Test linux,phandle
214 let phandle = Phandle::new(0xFF).unwrap();
215 let node: FdtNodeMut = fdt.node_mut_with_phandle(phandle).unwrap().unwrap();
216 assert_eq!(node.as_node().name(), Ok(cstr!("node_zz")));
217
218 // Test phandle
219 let phandle = Phandle::new(0x22).unwrap();
220 let node: FdtNodeMut = fdt.node_mut_with_phandle(phandle).unwrap().unwrap();
221 assert_eq!(node.as_node().name(), Ok(cstr!("node_abc")));
222}
223
224#[test]
Jaewan Kimf34f4b82023-11-03 19:38:38 +0900225fn node_get_phandle() {
226 let data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
227 let fdt = Fdt::from_slice(&data).unwrap();
228
229 // Test linux,phandle
230 let node = fdt.node(cstr!("/node_z/node_zz")).unwrap().unwrap();
231 assert_eq!(node.get_phandle(), Ok(Phandle::new(0xFF)));
232
233 // Test phandle
234 let node = fdt.node(cstr!("/node_a/node_ab/node_abc")).unwrap().unwrap();
235 assert_eq!(node.get_phandle(), Ok(Phandle::new(0x22)));
236
237 // Test no phandle
238 let node = fdt.node(cstr!("/node_b")).unwrap().unwrap();
239 assert_eq!(node.get_phandle(), Ok(None));
240}
241
242#[test]
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900243fn node_nop() {
244 let mut data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
245 let fdt = Fdt::from_mut_slice(&mut data).unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000246 let phandle = Phandle::new(0xFF).unwrap();
247 let path = cstr!("/node_z/node_zz");
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900248
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000249 fdt.node_with_phandle(phandle).unwrap().unwrap();
250 let node = fdt.node_mut(path).unwrap().unwrap();
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900251
252 node.nop().unwrap();
253
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000254 assert_eq!(fdt.node_with_phandle(phandle), Ok(None));
255 assert_eq!(fdt.node(path), Ok(None));
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900256
257 fdt.unpack().unwrap();
258 fdt.pack().unwrap();
259
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000260 assert_eq!(fdt.node_with_phandle(phandle), Ok(None));
261 assert_eq!(fdt.node(path), Ok(None));
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900262}
Jaewan Kim5ab13582023-10-20 20:56:27 +0900263
264#[test]
265fn node_add_subnode_with_namelen() {
266 let mut data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
267 data.resize(data.len() * 2, 0_u8);
268
269 let fdt = Fdt::from_mut_slice(&mut data).unwrap();
270 fdt.unpack().unwrap();
271
272 let node_path = cstr!("/node_z/node_zz");
273 let subnode_name = cstr!("123456789");
274
275 for len in 0..subnode_name.to_bytes().len() {
276 let mut node = fdt.node_mut(node_path).unwrap().unwrap();
277 assert!(node.subnode_with_namelen(subnode_name, len).unwrap().is_none());
278
279 let mut node = fdt.node_mut(node_path).unwrap().unwrap();
280 node.add_subnode_with_namelen(subnode_name, len).unwrap();
281
282 let mut node = fdt.node_mut(node_path).unwrap().unwrap();
283 assert!(node.subnode_with_namelen(subnode_name, len).unwrap().is_some());
284 }
285
286 let node_path = node_path.to_str().unwrap();
287 for len in 1..subnode_name.to_bytes().len() {
288 let name = String::from_utf8(subnode_name.to_bytes()[..len].to_vec()).unwrap();
289 let path = CString::new(format!("{node_path}/{name}")).unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000290 let name = CString::new(name).unwrap();
Jaewan Kim5ab13582023-10-20 20:56:27 +0900291 let subnode = fdt.node(&path).unwrap().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000292 assert_eq!(subnode.name(), Ok(name.as_c_str()));
Jaewan Kim5ab13582023-10-20 20:56:27 +0900293 }
294}
Jaewan Kimf163d762023-11-01 13:12:50 +0900295
296#[test]
297fn fdt_symbols() {
298 let mut data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
299 let fdt = Fdt::from_mut_slice(&mut data).unwrap();
300
301 let symbols = fdt.symbols().unwrap().unwrap();
302 assert_eq!(symbols.name(), Ok(cstr!("__symbols__")));
303
304 // Validates type.
305 let _symbols: FdtNodeMut = fdt.symbols_mut().unwrap().unwrap();
306}
Jaewan Kimf72f4f22023-11-03 19:21:34 +0900307
308#[test]
309fn node_mut_as_node() {
310 let mut data = fs::read(TEST_TREE_WITH_ONE_MEMORY_RANGE_PATH).unwrap();
311 let fdt = Fdt::from_mut_slice(&mut data).unwrap();
312
313 let mut memory = fdt.node_mut(cstr!("/memory")).unwrap().unwrap();
314 {
315 let memory = memory.as_node();
316 assert_eq!(memory.name(), Ok(cstr!("memory")));
317 }
318
319 // Just check whether borrow checker doesn't complain this.
320 memory.setprop_inplace(cstr!("device_type"), b"MEMORY\0").unwrap();
321}