blob: 78c640ef9f04a967c331a204771334a82bb5a1b5 [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 Kimb635bb02023-11-01 13:00:34 +090024// TODO(b/308694211): Use cstr!() from vmbase
Jaewan Kim5b057772023-10-19 01:02:17 +090025macro_rules! cstr {
26 ($str:literal) => {{
27 CStr::from_bytes_with_nul(concat!($str, "\0").as_bytes()).unwrap()
28 }};
29}
30
Alice Wang2422bdc2023-06-12 08:37:55 +000031const TEST_TREE_WITH_ONE_MEMORY_RANGE_PATH: &str = "data/test_tree_one_memory_range.dtb";
32const TEST_TREE_WITH_MULTIPLE_MEMORY_RANGES_PATH: &str =
33 "data/test_tree_multiple_memory_ranges.dtb";
34const TEST_TREE_WITH_EMPTY_MEMORY_RANGE_PATH: &str = "data/test_tree_empty_memory_range.dtb";
35const TEST_TREE_WITH_NO_MEMORY_NODE_PATH: &str = "data/test_tree_no_memory_node.dtb";
Jaewan Kim17ba7a32023-10-19 13:25:15 +090036const TEST_TREE_PHANDLE_PATH: &str = "data/test_tree_phandle.dtb";
Alice Wang9d4df702023-05-25 14:14:12 +000037
38#[test]
Alice Wang2422bdc2023-06-12 08:37:55 +000039fn retrieving_memory_from_fdt_with_one_memory_range_succeeds() {
40 let data = fs::read(TEST_TREE_WITH_ONE_MEMORY_RANGE_PATH).unwrap();
Alice Wang9d4df702023-05-25 14:14:12 +000041 let fdt = Fdt::from_slice(&data).unwrap();
42
43 const EXPECTED_FIRST_MEMORY_RANGE: Range<usize> = 0..256;
Alice Wang2422bdc2023-06-12 08:37:55 +000044 let mut memory = fdt.memory().unwrap();
Alice Wang9d4df702023-05-25 14:14:12 +000045 assert_eq!(memory.next(), Some(EXPECTED_FIRST_MEMORY_RANGE));
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +000046 assert_eq!(memory.next(), None);
Alice Wang2422bdc2023-06-12 08:37:55 +000047 assert_eq!(fdt.first_memory_range(), Ok(EXPECTED_FIRST_MEMORY_RANGE));
48}
49
50#[test]
51fn retrieving_memory_from_fdt_with_multiple_memory_ranges_succeeds() {
52 let data = fs::read(TEST_TREE_WITH_MULTIPLE_MEMORY_RANGES_PATH).unwrap();
53 let fdt = Fdt::from_slice(&data).unwrap();
54
55 const EXPECTED_FIRST_MEMORY_RANGE: Range<usize> = 0..256;
56 const EXPECTED_SECOND_MEMORY_RANGE: Range<usize> = 512..1024;
57 let mut memory = fdt.memory().unwrap();
58 assert_eq!(memory.next(), Some(EXPECTED_FIRST_MEMORY_RANGE));
59 assert_eq!(memory.next(), Some(EXPECTED_SECOND_MEMORY_RANGE));
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +000060 assert_eq!(memory.next(), None);
Alice Wang2422bdc2023-06-12 08:37:55 +000061 assert_eq!(fdt.first_memory_range(), Ok(EXPECTED_FIRST_MEMORY_RANGE));
62}
63
64#[test]
65fn retrieving_first_memory_from_fdt_with_empty_memory_range_fails() {
66 let data = fs::read(TEST_TREE_WITH_EMPTY_MEMORY_RANGE_PATH).unwrap();
67 let fdt = Fdt::from_slice(&data).unwrap();
68
69 let mut memory = fdt.memory().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +000070 assert_eq!(memory.next(), None);
Alice Wang2422bdc2023-06-12 08:37:55 +000071 assert_eq!(fdt.first_memory_range(), Err(FdtError::NotFound));
72}
73
74#[test]
75fn retrieving_memory_from_fdt_with_no_memory_node_fails() {
76 let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
77 let fdt = Fdt::from_slice(&data).unwrap();
78
79 assert_eq!(fdt.memory().unwrap_err(), FdtError::NotFound);
80 assert_eq!(fdt.first_memory_range(), Err(FdtError::NotFound));
Alice Wang9d4df702023-05-25 14:14:12 +000081}
Jaewan Kimaa638702023-09-19 13:34:01 +090082
83#[test]
84fn node_name() {
85 let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
86 let fdt = Fdt::from_slice(&data).unwrap();
87
88 let root = fdt.root().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +000089 assert_eq!(root.name(), Ok(cstr!("")));
Jaewan Kimaa638702023-09-19 13:34:01 +090090
91 let chosen = fdt.chosen().unwrap().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +000092 assert_eq!(chosen.name(), Ok(cstr!("chosen")));
Jaewan Kimaa638702023-09-19 13:34:01 +090093
Jaewan Kim5b057772023-10-19 01:02:17 +090094 let nested_node_path = cstr!("/cpus/PowerPC,970@0");
Jaewan Kimaa638702023-09-19 13:34:01 +090095 let nested_node = fdt.node(nested_node_path).unwrap().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +000096 assert_eq!(nested_node.name(), Ok(cstr!("PowerPC,970@0")));
Jaewan Kimaa638702023-09-19 13:34:01 +090097}
Jaewan Kimbc828d72023-09-19 15:52:08 +090098
99#[test]
100fn node_subnodes() {
101 let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
102 let fdt = Fdt::from_slice(&data).unwrap();
103 let root = fdt.root().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000104 let expected = [cstr!("cpus"), cstr!("randomnode"), cstr!("chosen")];
Jaewan Kimbc828d72023-09-19 15:52:08 +0900105
106 for (node, name) in root.subnodes().unwrap().zip(expected) {
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000107 assert_eq!(node.name(), Ok(name));
Jaewan Kimbc828d72023-09-19 15:52:08 +0900108 }
109}
Jaewan Kim72d10902023-10-12 21:59:26 +0900110
111#[test]
112fn node_properties() {
113 let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
114 let fdt = Fdt::from_slice(&data).unwrap();
115 let root = fdt.root().unwrap();
116 let one_be = 0x1_u32.to_be_bytes();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000117 let expected = [
118 (cstr!("model"), b"MyBoardName\0".as_ref()),
119 (cstr!("compatible"), b"MyBoardName\0MyBoardFamilyName\0".as_ref()),
120 (cstr!("#address-cells"), &one_be),
121 (cstr!("#size-cells"), &one_be),
122 (cstr!("empty_prop"), &[]),
Jaewan Kim72d10902023-10-12 21:59:26 +0900123 ];
124
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000125 let properties = root.properties().unwrap();
126 for (prop, (name, value)) in properties.zip(expected.into_iter()) {
127 assert_eq!((prop.name(), prop.value()), (Ok(name), Ok(value)));
Jaewan Kim72d10902023-10-12 21:59:26 +0900128 }
129}
Jaewan Kim5b057772023-10-19 01:02:17 +0900130
131#[test]
132fn node_supernode_at_depth() {
133 let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
134 let fdt = Fdt::from_slice(&data).unwrap();
135 let node = fdt.node(cstr!("/cpus/PowerPC,970@1")).unwrap().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000136 let expected = [cstr!(""), cstr!("cpus"), cstr!("PowerPC,970@1")];
Jaewan Kim5b057772023-10-19 01:02:17 +0900137
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000138 for (depth, name) in expected.into_iter().enumerate() {
Jaewan Kim5b057772023-10-19 01:02:17 +0900139 let supernode = node.supernode_at_depth(depth).unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000140 assert_eq!(supernode.name(), Ok(name));
Jaewan Kim5b057772023-10-19 01:02:17 +0900141 }
142}
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900143
144#[test]
145fn phandle_new() {
Pierre-Clément Tosieba27792023-10-30 12:04:12 +0000146 let valid_phandles = [
147 u32::from(Phandle::MIN),
148 u32::from(Phandle::MIN).checked_add(1).unwrap(),
149 0x55,
150 u32::from(Phandle::MAX).checked_sub(1).unwrap(),
151 u32::from(Phandle::MAX),
152 ];
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900153
Pierre-Clément Tosieba27792023-10-30 12:04:12 +0000154 for value in valid_phandles {
155 let phandle = Phandle::new(value).unwrap();
156
157 assert_eq!(value.try_into(), Ok(phandle));
158 assert_eq!(u32::from(phandle), value);
159 }
160
161 let bad_phandles = [
162 u32::from(Phandle::MIN).checked_sub(1).unwrap(),
163 u32::from(Phandle::MAX).checked_add(1).unwrap(),
164 ];
165
166 for value in bad_phandles {
167 assert_eq!(Phandle::new(value), None);
168 assert_eq!(Phandle::try_from(value), Err(FdtError::BadPhandle));
169 }
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900170}
171
172#[test]
173fn max_phandle() {
174 let data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
175 let fdt = Fdt::from_slice(&data).unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000176 let phandle = Phandle::new(0xFF).unwrap();
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900177
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000178 assert_eq!(fdt.max_phandle(), Ok(phandle));
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900179}
180
181#[test]
182fn node_with_phandle() {
183 let data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
184 let fdt = Fdt::from_slice(&data).unwrap();
185
186 // Test linux,phandle
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000187 let phandle = Phandle::new(0xFF).unwrap();
188 let node = fdt.node_with_phandle(phandle).unwrap().unwrap();
189 assert_eq!(node.name(), Ok(cstr!("node_zz")));
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900190
191 // Test phandle
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000192 let phandle = Phandle::new(0x22).unwrap();
193 let node = fdt.node_with_phandle(phandle).unwrap().unwrap();
194 assert_eq!(node.name(), Ok(cstr!("node_abc")));
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900195}
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900196
197#[test]
198fn node_nop() {
199 let mut data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
200 let fdt = Fdt::from_mut_slice(&mut data).unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000201 let phandle = Phandle::new(0xFF).unwrap();
202 let path = cstr!("/node_z/node_zz");
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900203
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000204 fdt.node_with_phandle(phandle).unwrap().unwrap();
205 let node = fdt.node_mut(path).unwrap().unwrap();
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900206
207 node.nop().unwrap();
208
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000209 assert_eq!(fdt.node_with_phandle(phandle), Ok(None));
210 assert_eq!(fdt.node(path), Ok(None));
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900211
212 fdt.unpack().unwrap();
213 fdt.pack().unwrap();
214
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000215 assert_eq!(fdt.node_with_phandle(phandle), Ok(None));
216 assert_eq!(fdt.node(path), Ok(None));
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900217}
Jaewan Kim5ab13582023-10-20 20:56:27 +0900218
219#[test]
220fn node_add_subnode_with_namelen() {
221 let mut data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
222 data.resize(data.len() * 2, 0_u8);
223
224 let fdt = Fdt::from_mut_slice(&mut data).unwrap();
225 fdt.unpack().unwrap();
226
227 let node_path = cstr!("/node_z/node_zz");
228 let subnode_name = cstr!("123456789");
229
230 for len in 0..subnode_name.to_bytes().len() {
231 let mut node = fdt.node_mut(node_path).unwrap().unwrap();
232 assert!(node.subnode_with_namelen(subnode_name, len).unwrap().is_none());
233
234 let mut node = fdt.node_mut(node_path).unwrap().unwrap();
235 node.add_subnode_with_namelen(subnode_name, len).unwrap();
236
237 let mut node = fdt.node_mut(node_path).unwrap().unwrap();
238 assert!(node.subnode_with_namelen(subnode_name, len).unwrap().is_some());
239 }
240
241 let node_path = node_path.to_str().unwrap();
242 for len in 1..subnode_name.to_bytes().len() {
243 let name = String::from_utf8(subnode_name.to_bytes()[..len].to_vec()).unwrap();
244 let path = CString::new(format!("{node_path}/{name}")).unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000245 let name = CString::new(name).unwrap();
Jaewan Kim5ab13582023-10-20 20:56:27 +0900246 let subnode = fdt.node(&path).unwrap().unwrap();
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000247 assert_eq!(subnode.name(), Ok(name.as_c_str()));
Jaewan Kim5ab13582023-10-20 20:56:27 +0900248 }
249}