blob: 78bb618894d58b8f91eeaad6731a40cd9164f520 [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 Kim17ba7a32023-10-19 13:25:15 +090019use libfdt::{Fdt, FdtError, Phandle};
Jaewan Kim5ab13582023-10-20 20:56:27 +090020use std::ffi::{CStr, CString};
Alice Wang9d4df702023-05-25 14:14:12 +000021use std::fs;
22use std::ops::Range;
23
Jaewan Kim5b057772023-10-19 01:02:17 +090024macro_rules! cstr {
25 ($str:literal) => {{
26 CStr::from_bytes_with_nul(concat!($str, "\0").as_bytes()).unwrap()
27 }};
28}
29
Alice Wang2422bdc2023-06-12 08:37:55 +000030const TEST_TREE_WITH_ONE_MEMORY_RANGE_PATH: &str = "data/test_tree_one_memory_range.dtb";
31const TEST_TREE_WITH_MULTIPLE_MEMORY_RANGES_PATH: &str =
32 "data/test_tree_multiple_memory_ranges.dtb";
33const TEST_TREE_WITH_EMPTY_MEMORY_RANGE_PATH: &str = "data/test_tree_empty_memory_range.dtb";
34const TEST_TREE_WITH_NO_MEMORY_NODE_PATH: &str = "data/test_tree_no_memory_node.dtb";
Jaewan Kim17ba7a32023-10-19 13:25:15 +090035const TEST_TREE_PHANDLE_PATH: &str = "data/test_tree_phandle.dtb";
Alice Wang9d4df702023-05-25 14:14:12 +000036
37#[test]
Alice Wang2422bdc2023-06-12 08:37:55 +000038fn retrieving_memory_from_fdt_with_one_memory_range_succeeds() {
39 let data = fs::read(TEST_TREE_WITH_ONE_MEMORY_RANGE_PATH).unwrap();
Alice Wang9d4df702023-05-25 14:14:12 +000040 let fdt = Fdt::from_slice(&data).unwrap();
41
42 const EXPECTED_FIRST_MEMORY_RANGE: Range<usize> = 0..256;
Alice Wang2422bdc2023-06-12 08:37:55 +000043 let mut memory = fdt.memory().unwrap();
Alice Wang9d4df702023-05-25 14:14:12 +000044 assert_eq!(memory.next(), Some(EXPECTED_FIRST_MEMORY_RANGE));
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +000045 assert_eq!(memory.next(), None);
Alice Wang2422bdc2023-06-12 08:37:55 +000046 assert_eq!(fdt.first_memory_range(), Ok(EXPECTED_FIRST_MEMORY_RANGE));
47}
48
49#[test]
50fn retrieving_memory_from_fdt_with_multiple_memory_ranges_succeeds() {
51 let data = fs::read(TEST_TREE_WITH_MULTIPLE_MEMORY_RANGES_PATH).unwrap();
52 let fdt = Fdt::from_slice(&data).unwrap();
53
54 const EXPECTED_FIRST_MEMORY_RANGE: Range<usize> = 0..256;
55 const EXPECTED_SECOND_MEMORY_RANGE: Range<usize> = 512..1024;
56 let mut memory = fdt.memory().unwrap();
57 assert_eq!(memory.next(), Some(EXPECTED_FIRST_MEMORY_RANGE));
58 assert_eq!(memory.next(), Some(EXPECTED_SECOND_MEMORY_RANGE));
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +000059 assert_eq!(memory.next(), None);
Alice Wang2422bdc2023-06-12 08:37:55 +000060 assert_eq!(fdt.first_memory_range(), Ok(EXPECTED_FIRST_MEMORY_RANGE));
61}
62
63#[test]
64fn retrieving_first_memory_from_fdt_with_empty_memory_range_fails() {
65 let data = fs::read(TEST_TREE_WITH_EMPTY_MEMORY_RANGE_PATH).unwrap();
66 let fdt = Fdt::from_slice(&data).unwrap();
67
68 let mut memory = fdt.memory().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +000069 assert_eq!(memory.next(), None);
Alice Wang2422bdc2023-06-12 08:37:55 +000070 assert_eq!(fdt.first_memory_range(), Err(FdtError::NotFound));
71}
72
73#[test]
74fn retrieving_memory_from_fdt_with_no_memory_node_fails() {
75 let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
76 let fdt = Fdt::from_slice(&data).unwrap();
77
78 assert_eq!(fdt.memory().unwrap_err(), FdtError::NotFound);
79 assert_eq!(fdt.first_memory_range(), Err(FdtError::NotFound));
Alice Wang9d4df702023-05-25 14:14:12 +000080}
Jaewan Kimaa638702023-09-19 13:34:01 +090081
82#[test]
83fn node_name() {
84 let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
85 let fdt = Fdt::from_slice(&data).unwrap();
86
87 let root = fdt.root().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +000088 assert_eq!(root.name(), Ok(cstr!("")));
Jaewan Kimaa638702023-09-19 13:34:01 +090089
90 let chosen = fdt.chosen().unwrap().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +000091 assert_eq!(chosen.name(), Ok(cstr!("chosen")));
Jaewan Kimaa638702023-09-19 13:34:01 +090092
Jaewan Kim5b057772023-10-19 01:02:17 +090093 let nested_node_path = cstr!("/cpus/PowerPC,970@0");
Jaewan Kimaa638702023-09-19 13:34:01 +090094 let nested_node = fdt.node(nested_node_path).unwrap().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +000095 assert_eq!(nested_node.name(), Ok(cstr!("PowerPC,970@0")));
Jaewan Kimaa638702023-09-19 13:34:01 +090096}
Jaewan Kimbc828d72023-09-19 15:52:08 +090097
98#[test]
99fn node_subnodes() {
100 let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
101 let fdt = Fdt::from_slice(&data).unwrap();
102 let root = fdt.root().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000103 let expected = [cstr!("cpus"), cstr!("randomnode"), cstr!("chosen")];
Jaewan Kimbc828d72023-09-19 15:52:08 +0900104
105 for (node, name) in root.subnodes().unwrap().zip(expected) {
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000106 assert_eq!(node.name(), Ok(name));
Jaewan Kimbc828d72023-09-19 15:52:08 +0900107 }
108}
Jaewan Kim72d10902023-10-12 21:59:26 +0900109
110#[test]
111fn node_properties() {
112 let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
113 let fdt = Fdt::from_slice(&data).unwrap();
114 let root = fdt.root().unwrap();
115 let one_be = 0x1_u32.to_be_bytes();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000116 let expected = [
117 (cstr!("model"), b"MyBoardName\0".as_ref()),
118 (cstr!("compatible"), b"MyBoardName\0MyBoardFamilyName\0".as_ref()),
119 (cstr!("#address-cells"), &one_be),
120 (cstr!("#size-cells"), &one_be),
121 (cstr!("empty_prop"), &[]),
Jaewan Kim72d10902023-10-12 21:59:26 +0900122 ];
123
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000124 let properties = root.properties().unwrap();
125 for (prop, (name, value)) in properties.zip(expected.into_iter()) {
126 assert_eq!((prop.name(), prop.value()), (Ok(name), Ok(value)));
Jaewan Kim72d10902023-10-12 21:59:26 +0900127 }
128}
Jaewan Kim5b057772023-10-19 01:02:17 +0900129
130#[test]
131fn node_supernode_at_depth() {
132 let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
133 let fdt = Fdt::from_slice(&data).unwrap();
134 let node = fdt.node(cstr!("/cpus/PowerPC,970@1")).unwrap().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000135 let expected = [cstr!(""), cstr!("cpus"), cstr!("PowerPC,970@1")];
Jaewan Kim5b057772023-10-19 01:02:17 +0900136
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000137 for (depth, name) in expected.into_iter().enumerate() {
Jaewan Kim5b057772023-10-19 01:02:17 +0900138 let supernode = node.supernode_at_depth(depth).unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000139 assert_eq!(supernode.name(), Ok(name));
Jaewan Kim5b057772023-10-19 01:02:17 +0900140 }
141}
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900142
143#[test]
144fn phandle_new() {
Pierre-Clément Tosieba27792023-10-30 12:04:12 +0000145 let valid_phandles = [
146 u32::from(Phandle::MIN),
147 u32::from(Phandle::MIN).checked_add(1).unwrap(),
148 0x55,
149 u32::from(Phandle::MAX).checked_sub(1).unwrap(),
150 u32::from(Phandle::MAX),
151 ];
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900152
Pierre-Clément Tosieba27792023-10-30 12:04:12 +0000153 for value in valid_phandles {
154 let phandle = Phandle::new(value).unwrap();
155
156 assert_eq!(value.try_into(), Ok(phandle));
157 assert_eq!(u32::from(phandle), value);
158 }
159
160 let bad_phandles = [
161 u32::from(Phandle::MIN).checked_sub(1).unwrap(),
162 u32::from(Phandle::MAX).checked_add(1).unwrap(),
163 ];
164
165 for value in bad_phandles {
166 assert_eq!(Phandle::new(value), None);
167 assert_eq!(Phandle::try_from(value), Err(FdtError::BadPhandle));
168 }
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900169}
170
171#[test]
172fn max_phandle() {
173 let data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
174 let fdt = Fdt::from_slice(&data).unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000175 let phandle = Phandle::new(0xFF).unwrap();
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900176
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000177 assert_eq!(fdt.max_phandle(), Ok(phandle));
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900178}
179
180#[test]
181fn node_with_phandle() {
182 let data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
183 let fdt = Fdt::from_slice(&data).unwrap();
184
185 // Test linux,phandle
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000186 let phandle = Phandle::new(0xFF).unwrap();
187 let node = fdt.node_with_phandle(phandle).unwrap().unwrap();
188 assert_eq!(node.name(), Ok(cstr!("node_zz")));
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900189
190 // Test phandle
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000191 let phandle = Phandle::new(0x22).unwrap();
192 let node = fdt.node_with_phandle(phandle).unwrap().unwrap();
193 assert_eq!(node.name(), Ok(cstr!("node_abc")));
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900194}
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900195
196#[test]
197fn node_nop() {
198 let mut data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
199 let fdt = Fdt::from_mut_slice(&mut data).unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000200 let phandle = Phandle::new(0xFF).unwrap();
201 let path = cstr!("/node_z/node_zz");
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900202
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000203 fdt.node_with_phandle(phandle).unwrap().unwrap();
204 let node = fdt.node_mut(path).unwrap().unwrap();
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900205
206 node.nop().unwrap();
207
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000208 assert_eq!(fdt.node_with_phandle(phandle), Ok(None));
209 assert_eq!(fdt.node(path), Ok(None));
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900210
211 fdt.unpack().unwrap();
212 fdt.pack().unwrap();
213
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000214 assert_eq!(fdt.node_with_phandle(phandle), Ok(None));
215 assert_eq!(fdt.node(path), Ok(None));
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900216}
Jaewan Kim5ab13582023-10-20 20:56:27 +0900217
218#[test]
219fn node_add_subnode_with_namelen() {
220 let mut data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
221 data.resize(data.len() * 2, 0_u8);
222
223 let fdt = Fdt::from_mut_slice(&mut data).unwrap();
224 fdt.unpack().unwrap();
225
226 let node_path = cstr!("/node_z/node_zz");
227 let subnode_name = cstr!("123456789");
228
229 for len in 0..subnode_name.to_bytes().len() {
230 let mut node = fdt.node_mut(node_path).unwrap().unwrap();
231 assert!(node.subnode_with_namelen(subnode_name, len).unwrap().is_none());
232
233 let mut node = fdt.node_mut(node_path).unwrap().unwrap();
234 node.add_subnode_with_namelen(subnode_name, len).unwrap();
235
236 let mut node = fdt.node_mut(node_path).unwrap().unwrap();
237 assert!(node.subnode_with_namelen(subnode_name, len).unwrap().is_some());
238 }
239
240 let node_path = node_path.to_str().unwrap();
241 for len in 1..subnode_name.to_bytes().len() {
242 let name = String::from_utf8(subnode_name.to_bytes()[..len].to_vec()).unwrap();
243 let path = CString::new(format!("{node_path}/{name}")).unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000244 let name = CString::new(name).unwrap();
Jaewan Kim5ab13582023-10-20 20:56:27 +0900245 let subnode = fdt.node(&path).unwrap().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000246 assert_eq!(subnode.name(), Ok(name.as_c_str()));
Jaewan Kim5ab13582023-10-20 20:56:27 +0900247 }
248}