xref: /aosp_15_r20/external/crosvm/cros_fdt/src/overlay.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2023 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker //! This module applies binary flattened device tree overlays.
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeMap;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::HashSet;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::VecDeque;
10*bb4ee6a4SAndroid Build Coastguard Worker 
11*bb4ee6a4SAndroid Build Coastguard Worker use crate::fdt::Error;
12*bb4ee6a4SAndroid Build Coastguard Worker use crate::fdt::Fdt;
13*bb4ee6a4SAndroid Build Coastguard Worker use crate::fdt::FdtNode;
14*bb4ee6a4SAndroid Build Coastguard Worker use crate::fdt::FdtReserveEntry;
15*bb4ee6a4SAndroid Build Coastguard Worker use crate::fdt::Result;
16*bb4ee6a4SAndroid Build Coastguard Worker use crate::path::parse_path_with_prop;
17*bb4ee6a4SAndroid Build Coastguard Worker use crate::path::Path;
18*bb4ee6a4SAndroid Build Coastguard Worker use crate::path::PhandlePin;
19*bb4ee6a4SAndroid Build Coastguard Worker use crate::path::PATH_SEP;
20*bb4ee6a4SAndroid Build Coastguard Worker 
21*bb4ee6a4SAndroid Build Coastguard Worker const PHANDLE_PROP: &str = "phandle";
22*bb4ee6a4SAndroid Build Coastguard Worker const LINUX_PHANDLE_PROP: &str = "linux,phandle";
23*bb4ee6a4SAndroid Build Coastguard Worker const TARGET_PATH_PROP: &str = "target-path";
24*bb4ee6a4SAndroid Build Coastguard Worker const TARGET_PROP: &str = "target";
25*bb4ee6a4SAndroid Build Coastguard Worker const LOCAL_FIXUPS_NODE: &str = "__local_fixups__";
26*bb4ee6a4SAndroid Build Coastguard Worker const OVERLAY_NODE: &str = "__overlay__";
27*bb4ee6a4SAndroid Build Coastguard Worker const SYMBOLS_NODE: &str = "__symbols__";
28*bb4ee6a4SAndroid Build Coastguard Worker const FIXUPS_NODE: &str = "__fixups__";
29*bb4ee6a4SAndroid Build Coastguard Worker const ROOT_NODE: &str = "/";
30*bb4ee6a4SAndroid Build Coastguard Worker 
31*bb4ee6a4SAndroid Build Coastguard Worker // Ensure filtered symbols exist and contain a valid path. They will be the starting points
32*bb4ee6a4SAndroid Build Coastguard Worker // for the filtering algorithm.
prepare_filtered_symbols<T: AsRef<str>>( start_symbols: impl std::iter::IntoIterator<Item = T>, fdt: &Fdt, ) -> Result<(HashSet<String>, Vec<Path>)>33*bb4ee6a4SAndroid Build Coastguard Worker fn prepare_filtered_symbols<T: AsRef<str>>(
34*bb4ee6a4SAndroid Build Coastguard Worker     start_symbols: impl std::iter::IntoIterator<Item = T>,
35*bb4ee6a4SAndroid Build Coastguard Worker     fdt: &Fdt,
36*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<(HashSet<String>, Vec<Path>)> {
37*bb4ee6a4SAndroid Build Coastguard Worker     let symbols = HashSet::from_iter(start_symbols.into_iter().map(|s| s.as_ref().to_owned()));
38*bb4ee6a4SAndroid Build Coastguard Worker     let mut paths = vec![];
39*bb4ee6a4SAndroid Build Coastguard Worker     for symbol in &symbols {
40*bb4ee6a4SAndroid Build Coastguard Worker         paths.push(
41*bb4ee6a4SAndroid Build Coastguard Worker             fdt.symbol_to_path(symbol)
42*bb4ee6a4SAndroid Build Coastguard Worker                 .map_err(|e| Error::FilterError(format!("{e}")))?,
43*bb4ee6a4SAndroid Build Coastguard Worker         );
44*bb4ee6a4SAndroid Build Coastguard Worker     }
45*bb4ee6a4SAndroid Build Coastguard Worker     Ok((symbols, paths))
46*bb4ee6a4SAndroid Build Coastguard Worker }
47*bb4ee6a4SAndroid Build Coastguard Worker 
48*bb4ee6a4SAndroid Build Coastguard Worker // Look for references (phandle values) defined by `fixup_node` in properties of `tree_node`.
collect_phandle_refs_from_props(fixup_node: &FdtNode, tree_node: &FdtNode) -> Result<Vec<u32>>49*bb4ee6a4SAndroid Build Coastguard Worker fn collect_phandle_refs_from_props(fixup_node: &FdtNode, tree_node: &FdtNode) -> Result<Vec<u32>> {
50*bb4ee6a4SAndroid Build Coastguard Worker     let mut phandles = vec![];
51*bb4ee6a4SAndroid Build Coastguard Worker     for propname in fixup_node.prop_names() {
52*bb4ee6a4SAndroid Build Coastguard Worker         for phandle_offset in fixup_node.get_prop::<Vec<u32>>(propname).unwrap() {
53*bb4ee6a4SAndroid Build Coastguard Worker             phandles.push(
54*bb4ee6a4SAndroid Build Coastguard Worker                 tree_node
55*bb4ee6a4SAndroid Build Coastguard Worker                     .phandle_at_offset(propname, phandle_offset as usize)
56*bb4ee6a4SAndroid Build Coastguard Worker                     .ok_or(Error::PropertyValueInvalid)?,
57*bb4ee6a4SAndroid Build Coastguard Worker             );
58*bb4ee6a4SAndroid Build Coastguard Worker         }
59*bb4ee6a4SAndroid Build Coastguard Worker     }
60*bb4ee6a4SAndroid Build Coastguard Worker     Ok(phandles)
61*bb4ee6a4SAndroid Build Coastguard Worker }
62*bb4ee6a4SAndroid Build Coastguard Worker 
63*bb4ee6a4SAndroid Build Coastguard Worker // Traverse all nodes along given node path, and collect phandle reference values from properties.
collect_all_references_by_path( path: &Path, root: &FdtNode, local_fixups_node: &FdtNode, ) -> Result<HashSet<u32>>64*bb4ee6a4SAndroid Build Coastguard Worker fn collect_all_references_by_path(
65*bb4ee6a4SAndroid Build Coastguard Worker     path: &Path,
66*bb4ee6a4SAndroid Build Coastguard Worker     root: &FdtNode,
67*bb4ee6a4SAndroid Build Coastguard Worker     local_fixups_node: &FdtNode,
68*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<HashSet<u32>> {
69*bb4ee6a4SAndroid Build Coastguard Worker     // Follow node names inside the local fixups node and in the tree root.
70*bb4ee6a4SAndroid Build Coastguard Worker     let mut tree_node = root;
71*bb4ee6a4SAndroid Build Coastguard Worker     let mut fixup_node = local_fixups_node;
72*bb4ee6a4SAndroid Build Coastguard Worker     let mut phandle_refs = HashSet::<u32>::new();
73*bb4ee6a4SAndroid Build Coastguard Worker 
74*bb4ee6a4SAndroid Build Coastguard Worker     // Follow node names along path
75*bb4ee6a4SAndroid Build Coastguard Worker     for node_name in path.iter() {
76*bb4ee6a4SAndroid Build Coastguard Worker         tree_node = tree_node
77*bb4ee6a4SAndroid Build Coastguard Worker             .subnode(node_name)
78*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or_else(|| Error::InvalidPath(format!("cannot find subnode {}", node_name)))?;
79*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(n) = fixup_node.subnode(node_name) {
80*bb4ee6a4SAndroid Build Coastguard Worker             fixup_node = n
81*bb4ee6a4SAndroid Build Coastguard Worker         } else {
82*bb4ee6a4SAndroid Build Coastguard Worker             return Ok(phandle_refs); // No references left to collect in this subtree.
83*bb4ee6a4SAndroid Build Coastguard Worker         }
84*bb4ee6a4SAndroid Build Coastguard Worker 
85*bb4ee6a4SAndroid Build Coastguard Worker         // Look for references (phandle values) in properties along path; add them to set.
86*bb4ee6a4SAndroid Build Coastguard Worker         phandle_refs.extend(collect_phandle_refs_from_props(fixup_node, tree_node)?);
87*bb4ee6a4SAndroid Build Coastguard Worker     }
88*bb4ee6a4SAndroid Build Coastguard Worker     Ok(phandle_refs)
89*bb4ee6a4SAndroid Build Coastguard Worker }
90*bb4ee6a4SAndroid Build Coastguard Worker 
91*bb4ee6a4SAndroid Build Coastguard Worker // Collect locations of all phandles in the FDT.
get_all_phandles(fdt: &Fdt) -> BTreeMap<u32, Path>92*bb4ee6a4SAndroid Build Coastguard Worker fn get_all_phandles(fdt: &Fdt) -> BTreeMap<u32, Path> {
93*bb4ee6a4SAndroid Build Coastguard Worker     let mut phandles = BTreeMap::new();
94*bb4ee6a4SAndroid Build Coastguard Worker     let mut nodes = VecDeque::<(&FdtNode, Path)>::new();
95*bb4ee6a4SAndroid Build Coastguard Worker     nodes.push_back((&fdt.root, ROOT_NODE.parse().unwrap()));
96*bb4ee6a4SAndroid Build Coastguard Worker     while let Some((node, path)) = nodes.pop_front() {
97*bb4ee6a4SAndroid Build Coastguard Worker         for subnode in node.iter_subnodes() {
98*bb4ee6a4SAndroid Build Coastguard Worker             nodes.push_back((subnode, path.push(&subnode.name).unwrap()));
99*bb4ee6a4SAndroid Build Coastguard Worker         }
100*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(phandle) = get_node_phandle(node) {
101*bb4ee6a4SAndroid Build Coastguard Worker             phandles.insert(phandle, path);
102*bb4ee6a4SAndroid Build Coastguard Worker         }
103*bb4ee6a4SAndroid Build Coastguard Worker     }
104*bb4ee6a4SAndroid Build Coastguard Worker     phandles
105*bb4ee6a4SAndroid Build Coastguard Worker }
106*bb4ee6a4SAndroid Build Coastguard Worker 
107*bb4ee6a4SAndroid Build Coastguard Worker // Minimize paths - if the vector contains two paths where one is the
108*bb4ee6a4SAndroid Build Coastguard Worker // parent of the other, only include the parent path, and drop the child path.
minimize_paths(paths: &mut Vec<Path>)109*bb4ee6a4SAndroid Build Coastguard Worker fn minimize_paths(paths: &mut Vec<Path>) {
110*bb4ee6a4SAndroid Build Coastguard Worker     paths.sort();
111*bb4ee6a4SAndroid Build Coastguard Worker     paths.dedup_by(|a, b| a.is_child_of(b));
112*bb4ee6a4SAndroid Build Coastguard Worker }
113*bb4ee6a4SAndroid Build Coastguard Worker 
114*bb4ee6a4SAndroid Build Coastguard Worker // Collect paths of all nodes that nodes in `start_paths` depend on. Path A depends on
115*bb4ee6a4SAndroid Build Coastguard Worker // path B if any node along the path A references the node path B points to.
collect_all_filtered_paths(mut start_paths: Vec<Path>, fdt: &Fdt) -> Result<Vec<Path>>116*bb4ee6a4SAndroid Build Coastguard Worker fn collect_all_filtered_paths(mut start_paths: Vec<Path>, fdt: &Fdt) -> Result<Vec<Path>> {
117*bb4ee6a4SAndroid Build Coastguard Worker     if start_paths.is_empty() {
118*bb4ee6a4SAndroid Build Coastguard Worker         return Ok(vec![]);
119*bb4ee6a4SAndroid Build Coastguard Worker     }
120*bb4ee6a4SAndroid Build Coastguard Worker     minimize_paths(&mut start_paths);
121*bb4ee6a4SAndroid Build Coastguard Worker     let Some(local_fixups_node) = fdt.root.subnode(LOCAL_FIXUPS_NODE) else {
122*bb4ee6a4SAndroid Build Coastguard Worker         return Ok(start_paths); // No fixups node -> no other references
123*bb4ee6a4SAndroid Build Coastguard Worker     };
124*bb4ee6a4SAndroid Build Coastguard Worker 
125*bb4ee6a4SAndroid Build Coastguard Worker     let all_phandles = get_all_phandles(fdt); // All FDT phandles, mapped to their paths
126*bb4ee6a4SAndroid Build Coastguard Worker     let mut result_paths = HashSet::<Path>::with_capacity(start_paths.len());
127*bb4ee6a4SAndroid Build Coastguard Worker     let mut pending_paths: VecDeque<_> = start_paths.iter().collect(); // Paths to visit
128*bb4ee6a4SAndroid Build Coastguard Worker 
129*bb4ee6a4SAndroid Build Coastguard Worker     while let Some(path) = pending_paths.pop_front() {
130*bb4ee6a4SAndroid Build Coastguard Worker         if result_paths.contains(path) {
131*bb4ee6a4SAndroid Build Coastguard Worker             continue; // Already seen this path
132*bb4ee6a4SAndroid Build Coastguard Worker         }
133*bb4ee6a4SAndroid Build Coastguard Worker         // Collect all phandles that this path references
134*bb4ee6a4SAndroid Build Coastguard Worker         let phandles = collect_all_references_by_path(path, &fdt.root, local_fixups_node)?;
135*bb4ee6a4SAndroid Build Coastguard Worker         // Map the phandles to other locations
136*bb4ee6a4SAndroid Build Coastguard Worker         for ph in phandles {
137*bb4ee6a4SAndroid Build Coastguard Worker             pending_paths.push_back(all_phandles.get(&ph).ok_or(Error::PropertyValueInvalid)?);
138*bb4ee6a4SAndroid Build Coastguard Worker         }
139*bb4ee6a4SAndroid Build Coastguard Worker         // This path should remain in the final overlay.
140*bb4ee6a4SAndroid Build Coastguard Worker         result_paths.insert(path.to_owned());
141*bb4ee6a4SAndroid Build Coastguard Worker     }
142*bb4ee6a4SAndroid Build Coastguard Worker 
143*bb4ee6a4SAndroid Build Coastguard Worker     let mut result_paths = result_paths.into_iter().collect();
144*bb4ee6a4SAndroid Build Coastguard Worker     minimize_paths(&mut result_paths);
145*bb4ee6a4SAndroid Build Coastguard Worker     Ok(result_paths)
146*bb4ee6a4SAndroid Build Coastguard Worker }
147*bb4ee6a4SAndroid Build Coastguard Worker 
148*bb4ee6a4SAndroid Build Coastguard Worker // Drop nodes which are not covered by the filtered paths.
do_overlay_filter(filtered_paths: Vec<Path>, overlay: &mut Fdt)149*bb4ee6a4SAndroid Build Coastguard Worker fn do_overlay_filter(filtered_paths: Vec<Path>, overlay: &mut Fdt) {
150*bb4ee6a4SAndroid Build Coastguard Worker     if filtered_paths.is_empty() {
151*bb4ee6a4SAndroid Build Coastguard Worker         return;
152*bb4ee6a4SAndroid Build Coastguard Worker     }
153*bb4ee6a4SAndroid Build Coastguard Worker     let mut new_root = FdtNode::empty("").unwrap();
154*bb4ee6a4SAndroid Build Coastguard Worker     for path in filtered_paths {
155*bb4ee6a4SAndroid Build Coastguard Worker         let mut src_node = &overlay.root;
156*bb4ee6a4SAndroid Build Coastguard Worker         let mut tgt_node = &mut new_root;
157*bb4ee6a4SAndroid Build Coastguard Worker         for node_name in path.iter() {
158*bb4ee6a4SAndroid Build Coastguard Worker             src_node = src_node
159*bb4ee6a4SAndroid Build Coastguard Worker                 .subnode(node_name)
160*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("filtered paths reference valid nodes");
161*bb4ee6a4SAndroid Build Coastguard Worker             tgt_node = tgt_node
162*bb4ee6a4SAndroid Build Coastguard Worker                 .subnode_mut(node_name)
163*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("filtered paths reference valid nodes");
164*bb4ee6a4SAndroid Build Coastguard Worker             tgt_node.props.clone_from(&src_node.props);
165*bb4ee6a4SAndroid Build Coastguard Worker         }
166*bb4ee6a4SAndroid Build Coastguard Worker     }
167*bb4ee6a4SAndroid Build Coastguard Worker     overlay.root = new_root;
168*bb4ee6a4SAndroid Build Coastguard Worker }
169*bb4ee6a4SAndroid Build Coastguard Worker 
170*bb4ee6a4SAndroid Build Coastguard Worker // Read 'phandle' or 'linux,phandle' property of a node.
get_node_phandle(node: &FdtNode) -> Option<u32>171*bb4ee6a4SAndroid Build Coastguard Worker fn get_node_phandle(node: &FdtNode) -> Option<u32> {
172*bb4ee6a4SAndroid Build Coastguard Worker     node.get_prop(PHANDLE_PROP)
173*bb4ee6a4SAndroid Build Coastguard Worker         .or_else(|| node.get_prop(LINUX_PHANDLE_PROP))
174*bb4ee6a4SAndroid Build Coastguard Worker }
175*bb4ee6a4SAndroid Build Coastguard Worker 
176*bb4ee6a4SAndroid Build Coastguard Worker // Return the largest phandle value in a node tree.
get_max_phandle(root_node: &FdtNode) -> u32177*bb4ee6a4SAndroid Build Coastguard Worker fn get_max_phandle(root_node: &FdtNode) -> u32 {
178*bb4ee6a4SAndroid Build Coastguard Worker     let mut max_phandle = 0u32;
179*bb4ee6a4SAndroid Build Coastguard Worker     let mut nodes_to_visit = VecDeque::new();
180*bb4ee6a4SAndroid Build Coastguard Worker     nodes_to_visit.push_back(root_node);
181*bb4ee6a4SAndroid Build Coastguard Worker     while let Some(node) = nodes_to_visit.pop_front() {
182*bb4ee6a4SAndroid Build Coastguard Worker         max_phandle = max_phandle.max(get_node_phandle(node).unwrap_or(0u32));
183*bb4ee6a4SAndroid Build Coastguard Worker         nodes_to_visit.extend(node.iter_subnodes());
184*bb4ee6a4SAndroid Build Coastguard Worker     }
185*bb4ee6a4SAndroid Build Coastguard Worker     max_phandle
186*bb4ee6a4SAndroid Build Coastguard Worker }
187*bb4ee6a4SAndroid Build Coastguard Worker 
188*bb4ee6a4SAndroid Build Coastguard Worker // Add the given delta to the phandle property of the node.
offset_phandle_prop(node: &mut FdtNode, propname: &str, delta: u32) -> Result<()>189*bb4ee6a4SAndroid Build Coastguard Worker fn offset_phandle_prop(node: &mut FdtNode, propname: &str, delta: u32) -> Result<()> {
190*bb4ee6a4SAndroid Build Coastguard Worker     let mut val: u32 = node.get_prop(propname).ok_or_else(|| {
191*bb4ee6a4SAndroid Build Coastguard Worker         Error::ApplyOverlayError(format!(
192*bb4ee6a4SAndroid Build Coastguard Worker             "cannot offset {}:{} - invalid value",
193*bb4ee6a4SAndroid Build Coastguard Worker             node.name, propname
194*bb4ee6a4SAndroid Build Coastguard Worker         ))
195*bb4ee6a4SAndroid Build Coastguard Worker     })?;
196*bb4ee6a4SAndroid Build Coastguard Worker     val = val
197*bb4ee6a4SAndroid Build Coastguard Worker         .checked_add(delta)
198*bb4ee6a4SAndroid Build Coastguard Worker         .ok_or_else(|| Error::ApplyOverlayError("cannot offset phandle - value overflow".into()))?;
199*bb4ee6a4SAndroid Build Coastguard Worker     node.set_prop(propname, val)
200*bb4ee6a4SAndroid Build Coastguard Worker         .expect("phandle property name is valid");
201*bb4ee6a4SAndroid Build Coastguard Worker     Ok(())
202*bb4ee6a4SAndroid Build Coastguard Worker }
203*bb4ee6a4SAndroid Build Coastguard Worker 
204*bb4ee6a4SAndroid Build Coastguard Worker // Add the given delta to phandle properties of all nodes in the FDT.
offset_phandle_values(fdt: &mut Fdt, delta: u32) -> Result<()>205*bb4ee6a4SAndroid Build Coastguard Worker fn offset_phandle_values(fdt: &mut Fdt, delta: u32) -> Result<()> {
206*bb4ee6a4SAndroid Build Coastguard Worker     let mut stack = VecDeque::new();
207*bb4ee6a4SAndroid Build Coastguard Worker     stack.push_back(&mut fdt.root);
208*bb4ee6a4SAndroid Build Coastguard Worker     while let Some(node) = stack.pop_front() {
209*bb4ee6a4SAndroid Build Coastguard Worker         if node.has_prop(PHANDLE_PROP) {
210*bb4ee6a4SAndroid Build Coastguard Worker             offset_phandle_prop(node, PHANDLE_PROP, delta)?;
211*bb4ee6a4SAndroid Build Coastguard Worker         }
212*bb4ee6a4SAndroid Build Coastguard Worker         if node.has_prop(LINUX_PHANDLE_PROP) {
213*bb4ee6a4SAndroid Build Coastguard Worker             offset_phandle_prop(node, LINUX_PHANDLE_PROP, delta)?;
214*bb4ee6a4SAndroid Build Coastguard Worker         }
215*bb4ee6a4SAndroid Build Coastguard Worker         stack.extend(node.iter_subnodes_mut());
216*bb4ee6a4SAndroid Build Coastguard Worker     }
217*bb4ee6a4SAndroid Build Coastguard Worker     Ok(())
218*bb4ee6a4SAndroid Build Coastguard Worker }
219*bb4ee6a4SAndroid Build Coastguard Worker 
220*bb4ee6a4SAndroid Build Coastguard Worker // Returns a vector of paths which contain a local phandle value (reference)
collect_local_fixup_paths(fdt: &Fdt) -> Result<BTreeMap<Path, Vec<PhandlePin>>>221*bb4ee6a4SAndroid Build Coastguard Worker fn collect_local_fixup_paths(fdt: &Fdt) -> Result<BTreeMap<Path, Vec<PhandlePin>>> {
222*bb4ee6a4SAndroid Build Coastguard Worker     let mut local_phandles = BTreeMap::<Path, Vec<PhandlePin>>::new();
223*bb4ee6a4SAndroid Build Coastguard Worker     let Some(local_fixups_node) = fdt.root.subnode(LOCAL_FIXUPS_NODE) else {
224*bb4ee6a4SAndroid Build Coastguard Worker         return Ok(local_phandles);
225*bb4ee6a4SAndroid Build Coastguard Worker     };
226*bb4ee6a4SAndroid Build Coastguard Worker     let mut stack = VecDeque::<(Path, &FdtNode)>::new();
227*bb4ee6a4SAndroid Build Coastguard Worker     stack.push_back((ROOT_NODE.parse().unwrap(), local_fixups_node));
228*bb4ee6a4SAndroid Build Coastguard Worker 
229*bb4ee6a4SAndroid Build Coastguard Worker     // Collect local phandle properties to fixup from __local_fixups__
230*bb4ee6a4SAndroid Build Coastguard Worker     while let Some((path, node)) = stack.pop_front() {
231*bb4ee6a4SAndroid Build Coastguard Worker         // Every property in __local_fixups__ contains a vector of offsets (u32)
232*bb4ee6a4SAndroid Build Coastguard Worker         // where the phandles are located
233*bb4ee6a4SAndroid Build Coastguard Worker         for propname in node.prop_names() {
234*bb4ee6a4SAndroid Build Coastguard Worker             let offsets = node.get_prop::<Vec<u32>>(propname).ok_or_else(|| {
235*bb4ee6a4SAndroid Build Coastguard Worker                 Error::ApplyOverlayError(format!(
236*bb4ee6a4SAndroid Build Coastguard Worker                     "fixup node {} contains invalid offset array",
237*bb4ee6a4SAndroid Build Coastguard Worker                     node.name
238*bb4ee6a4SAndroid Build Coastguard Worker                 ))
239*bb4ee6a4SAndroid Build Coastguard Worker             })?;
240*bb4ee6a4SAndroid Build Coastguard Worker             // Add phandle pins
241*bb4ee6a4SAndroid Build Coastguard Worker             if !local_phandles.contains_key(&path) {
242*bb4ee6a4SAndroid Build Coastguard Worker                 local_phandles.insert(path.clone(), vec![]);
243*bb4ee6a4SAndroid Build Coastguard Worker             }
244*bb4ee6a4SAndroid Build Coastguard Worker             let pins = local_phandles.get_mut(&path).unwrap();
245*bb4ee6a4SAndroid Build Coastguard Worker             pins.extend(offsets.into_iter().map(|o| PhandlePin(propname.into(), o)));
246*bb4ee6a4SAndroid Build Coastguard Worker         }
247*bb4ee6a4SAndroid Build Coastguard Worker         // Traverse into this node's children
248*bb4ee6a4SAndroid Build Coastguard Worker         for child in node.iter_subnodes() {
249*bb4ee6a4SAndroid Build Coastguard Worker             stack.push_back((path.push(&child.name)?, child));
250*bb4ee6a4SAndroid Build Coastguard Worker         }
251*bb4ee6a4SAndroid Build Coastguard Worker     }
252*bb4ee6a4SAndroid Build Coastguard Worker     Ok(local_phandles)
253*bb4ee6a4SAndroid Build Coastguard Worker }
254*bb4ee6a4SAndroid Build Coastguard Worker 
update_local_phandle_propvals( fdt: &mut Fdt, paths: BTreeMap<Path, Vec<PhandlePin>>, delta: u32, ) -> Result<()>255*bb4ee6a4SAndroid Build Coastguard Worker fn update_local_phandle_propvals(
256*bb4ee6a4SAndroid Build Coastguard Worker     fdt: &mut Fdt,
257*bb4ee6a4SAndroid Build Coastguard Worker     paths: BTreeMap<Path, Vec<PhandlePin>>,
258*bb4ee6a4SAndroid Build Coastguard Worker     delta: u32,
259*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> {
260*bb4ee6a4SAndroid Build Coastguard Worker     // Update phandles in collected locations
261*bb4ee6a4SAndroid Build Coastguard Worker     for (path, pins) in paths {
262*bb4ee6a4SAndroid Build Coastguard Worker         let node = fdt
263*bb4ee6a4SAndroid Build Coastguard Worker             .get_node_mut(path)
264*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or_else(|| Error::ApplyOverlayError("cannot find node for fixup".into()))?;
265*bb4ee6a4SAndroid Build Coastguard Worker         for pin in pins {
266*bb4ee6a4SAndroid Build Coastguard Worker             let phandle_val = node
267*bb4ee6a4SAndroid Build Coastguard Worker                 .phandle_at_offset(&pin.0, pin.1 as usize)
268*bb4ee6a4SAndroid Build Coastguard Worker                 .ok_or_else(|| Error::ApplyOverlayError(format!("missing property {}", &pin.0)))?;
269*bb4ee6a4SAndroid Build Coastguard Worker             node.update_phandle_at_offset(&pin.0, pin.1 as usize, phandle_val + delta)?;
270*bb4ee6a4SAndroid Build Coastguard Worker         }
271*bb4ee6a4SAndroid Build Coastguard Worker     }
272*bb4ee6a4SAndroid Build Coastguard Worker     Ok(())
273*bb4ee6a4SAndroid Build Coastguard Worker }
274*bb4ee6a4SAndroid Build Coastguard Worker 
update_local_refs(fdt: &mut Fdt, delta: u32) -> Result<()>275*bb4ee6a4SAndroid Build Coastguard Worker fn update_local_refs(fdt: &mut Fdt, delta: u32) -> Result<()> {
276*bb4ee6a4SAndroid Build Coastguard Worker     let phandle_locations = collect_local_fixup_paths(fdt)?;
277*bb4ee6a4SAndroid Build Coastguard Worker     update_local_phandle_propvals(fdt, phandle_locations, delta)
278*bb4ee6a4SAndroid Build Coastguard Worker }
279*bb4ee6a4SAndroid Build Coastguard Worker 
280*bb4ee6a4SAndroid Build Coastguard Worker // Given a DT symbol (label), find the path and phandle value of the node the symbol refers to.
get_symbol_path_and_phandle(symbol: &str, fdt: &Fdt) -> Option<(String, u32)>281*bb4ee6a4SAndroid Build Coastguard Worker fn get_symbol_path_and_phandle(symbol: &str, fdt: &Fdt) -> Option<(String, u32)> {
282*bb4ee6a4SAndroid Build Coastguard Worker     let symbols_node = fdt.root.subnode(SYMBOLS_NODE)?;
283*bb4ee6a4SAndroid Build Coastguard Worker     let symbol = symbols_node.get_prop::<String>(symbol)?;
284*bb4ee6a4SAndroid Build Coastguard Worker     let target_node = fdt.get_node(symbol.as_str())?;
285*bb4ee6a4SAndroid Build Coastguard Worker     Some((symbol, get_node_phandle(target_node)?))
286*bb4ee6a4SAndroid Build Coastguard Worker }
287*bb4ee6a4SAndroid Build Coastguard Worker 
288*bb4ee6a4SAndroid Build Coastguard Worker // For each symbol defined in base and referenced in overlay, set its references in overlay to
289*bb4ee6a4SAndroid Build Coastguard Worker // correct phandle values.
apply_external_fixups(base: &Fdt, overlay: &mut Fdt) -> Result<()>290*bb4ee6a4SAndroid Build Coastguard Worker fn apply_external_fixups(base: &Fdt, overlay: &mut Fdt) -> Result<()> {
291*bb4ee6a4SAndroid Build Coastguard Worker     let Some(fixups_node) = overlay.root.subnode(FIXUPS_NODE) else {
292*bb4ee6a4SAndroid Build Coastguard Worker         return Ok(()); // No references to base nodes
293*bb4ee6a4SAndroid Build Coastguard Worker     };
294*bb4ee6a4SAndroid Build Coastguard Worker 
295*bb4ee6a4SAndroid Build Coastguard Worker     // Collect locations in overlay where external nodes are referenced
296*bb4ee6a4SAndroid Build Coastguard Worker     let mut paths_to_update = BTreeMap::<(String, u32), Vec<String>>::new();
297*bb4ee6a4SAndroid Build Coastguard Worker     for fixup_symbol in fixups_node.prop_names() {
298*bb4ee6a4SAndroid Build Coastguard Worker         // Find phandle value and path of a labeled node in base DT
299*bb4ee6a4SAndroid Build Coastguard Worker         let path_and_phandle =
300*bb4ee6a4SAndroid Build Coastguard Worker             get_symbol_path_and_phandle(fixup_symbol, base).ok_or_else(|| {
301*bb4ee6a4SAndroid Build Coastguard Worker                 Error::ApplyOverlayError(format!("cannot find symbol {fixup_symbol} in base fdt"))
302*bb4ee6a4SAndroid Build Coastguard Worker             })?;
303*bb4ee6a4SAndroid Build Coastguard Worker         // Get target paths of this symbol in overlay
304*bb4ee6a4SAndroid Build Coastguard Worker         let target_paths: Vec<String> = fixups_node.get_prop(fixup_symbol).ok_or_else(|| {
305*bb4ee6a4SAndroid Build Coastguard Worker             Error::ApplyOverlayError(format!(
306*bb4ee6a4SAndroid Build Coastguard Worker                 "cannot parse target paths for fixup {fixup_symbol}"
307*bb4ee6a4SAndroid Build Coastguard Worker             ))
308*bb4ee6a4SAndroid Build Coastguard Worker         })?;
309*bb4ee6a4SAndroid Build Coastguard Worker         paths_to_update.insert(path_and_phandle, target_paths);
310*bb4ee6a4SAndroid Build Coastguard Worker     }
311*bb4ee6a4SAndroid Build Coastguard Worker 
312*bb4ee6a4SAndroid Build Coastguard Worker     // Update locations in overlay where external nodes are referenced
313*bb4ee6a4SAndroid Build Coastguard Worker     for ((base_path, phandle), paths) in paths_to_update {
314*bb4ee6a4SAndroid Build Coastguard Worker         for path in paths {
315*bb4ee6a4SAndroid Build Coastguard Worker             let (path, pin) = parse_path_with_prop(&path)?;
316*bb4ee6a4SAndroid Build Coastguard Worker             // Update phandle reference in target to new value
317*bb4ee6a4SAndroid Build Coastguard Worker             let target_node = overlay
318*bb4ee6a4SAndroid Build Coastguard Worker                 .get_node_mut(path)
319*bb4ee6a4SAndroid Build Coastguard Worker                 .ok_or_else(|| Error::ApplyOverlayError("invalid fixup target path".into()))?;
320*bb4ee6a4SAndroid Build Coastguard Worker             target_node.update_phandle_at_offset(&pin.0, pin.1 as usize, phandle)?;
321*bb4ee6a4SAndroid Build Coastguard Worker 
322*bb4ee6a4SAndroid Build Coastguard Worker             // If the property that is being updated here is actually a `target` property of
323*bb4ee6a4SAndroid Build Coastguard Worker             // an overlay fragment, also add the `target-path` property to the fragment, containing
324*bb4ee6a4SAndroid Build Coastguard Worker             // the full path to the target node in base FDT.
325*bb4ee6a4SAndroid Build Coastguard Worker             // This covers the case where the target of an overlay fragment is a phandle reference
326*bb4ee6a4SAndroid Build Coastguard Worker             // (of a node in base overlay), instead of absolute path in base.
327*bb4ee6a4SAndroid Build Coastguard Worker             if pin.0 == TARGET_PROP && target_node.iter_subnodes().any(|n| n.name == OVERLAY_NODE) {
328*bb4ee6a4SAndroid Build Coastguard Worker                 target_node.set_prop(TARGET_PATH_PROP, base_path.as_str())?;
329*bb4ee6a4SAndroid Build Coastguard Worker             }
330*bb4ee6a4SAndroid Build Coastguard Worker         }
331*bb4ee6a4SAndroid Build Coastguard Worker     }
332*bb4ee6a4SAndroid Build Coastguard Worker     Ok(())
333*bb4ee6a4SAndroid Build Coastguard Worker }
334*bb4ee6a4SAndroid Build Coastguard Worker 
335*bb4ee6a4SAndroid Build Coastguard Worker // Copy properties from overlay node to base node, then add subnodes and overlay them as well.
overlay_node_pair(base_node: &mut FdtNode, overlay_node: &FdtNode) -> Result<()>336*bb4ee6a4SAndroid Build Coastguard Worker fn overlay_node_pair(base_node: &mut FdtNode, overlay_node: &FdtNode) -> Result<()> {
337*bb4ee6a4SAndroid Build Coastguard Worker     base_node.props.extend(overlay_node.props.clone());
338*bb4ee6a4SAndroid Build Coastguard Worker     for overlay_subnode in overlay_node.iter_subnodes() {
339*bb4ee6a4SAndroid Build Coastguard Worker         overlay_node_pair(
340*bb4ee6a4SAndroid Build Coastguard Worker             base_node.subnode_mut(&overlay_subnode.name)?,
341*bb4ee6a4SAndroid Build Coastguard Worker             overlay_subnode,
342*bb4ee6a4SAndroid Build Coastguard Worker         )?;
343*bb4ee6a4SAndroid Build Coastguard Worker     }
344*bb4ee6a4SAndroid Build Coastguard Worker     Ok(())
345*bb4ee6a4SAndroid Build Coastguard Worker }
346*bb4ee6a4SAndroid Build Coastguard Worker 
347*bb4ee6a4SAndroid Build Coastguard Worker // Verify and apply an overlay fragment node to the base FDT.
overlay_fragment(fragment_node: &FdtNode, base: &mut Fdt) -> Result<()>348*bb4ee6a4SAndroid Build Coastguard Worker fn overlay_fragment(fragment_node: &FdtNode, base: &mut Fdt) -> Result<()> {
349*bb4ee6a4SAndroid Build Coastguard Worker     // Fragment must have an '__overlay__' subnode and `target-path` property.
350*bb4ee6a4SAndroid Build Coastguard Worker     let Some(overlay_node) = fragment_node.subnode(OVERLAY_NODE) else {
351*bb4ee6a4SAndroid Build Coastguard Worker         return Ok(()); // Skip invalid fragments.
352*bb4ee6a4SAndroid Build Coastguard Worker     };
353*bb4ee6a4SAndroid Build Coastguard Worker     let Some(target_path) = fragment_node.get_prop::<String>(TARGET_PATH_PROP) else {
354*bb4ee6a4SAndroid Build Coastguard Worker         return Ok(()); // Skip invalid fragments.
355*bb4ee6a4SAndroid Build Coastguard Worker     };
356*bb4ee6a4SAndroid Build Coastguard Worker     // Apply overlay fragment to target node in base FDT.
357*bb4ee6a4SAndroid Build Coastguard Worker     let target_node = base.get_node_mut(target_path.as_str()).ok_or_else(|| {
358*bb4ee6a4SAndroid Build Coastguard Worker         Error::ApplyOverlayError(format!(
359*bb4ee6a4SAndroid Build Coastguard Worker             "cannot find node in base FDT for target-path {target_path}",
360*bb4ee6a4SAndroid Build Coastguard Worker         ))
361*bb4ee6a4SAndroid Build Coastguard Worker     })?;
362*bb4ee6a4SAndroid Build Coastguard Worker     overlay_node_pair(target_node, overlay_node)
363*bb4ee6a4SAndroid Build Coastguard Worker }
364*bb4ee6a4SAndroid Build Coastguard Worker 
365*bb4ee6a4SAndroid Build Coastguard Worker // Parse the location of the symbol (property value), extract fragment name and the
366*bb4ee6a4SAndroid Build Coastguard Worker // rest of the path after `__overlay__`, (expected structure:
367*bb4ee6a4SAndroid Build Coastguard Worker // "/fragment@X/__overlay__/path/to/subnode").
extract_fragment_and_subpath(path: &Path) -> Result<(&str, String)>368*bb4ee6a4SAndroid Build Coastguard Worker fn extract_fragment_and_subpath(path: &Path) -> Result<(&str, String)> {
369*bb4ee6a4SAndroid Build Coastguard Worker     let mut path_iter = path.iter();
370*bb4ee6a4SAndroid Build Coastguard Worker     let fragment_name = path_iter
371*bb4ee6a4SAndroid Build Coastguard Worker         .next()
372*bb4ee6a4SAndroid Build Coastguard Worker         .ok_or_else(|| Error::ApplyOverlayError(format!("symbol path {path} too short")))?;
373*bb4ee6a4SAndroid Build Coastguard Worker     path_iter.next(); // Skip "__overlay__" node
374*bb4ee6a4SAndroid Build Coastguard Worker     let rest = path_iter.collect::<Vec<_>>();
375*bb4ee6a4SAndroid Build Coastguard Worker     if rest.is_empty() {
376*bb4ee6a4SAndroid Build Coastguard Worker         Err(Error::ApplyOverlayError(format!(
377*bb4ee6a4SAndroid Build Coastguard Worker             "symbol path {path} too short"
378*bb4ee6a4SAndroid Build Coastguard Worker         )))
379*bb4ee6a4SAndroid Build Coastguard Worker     } else {
380*bb4ee6a4SAndroid Build Coastguard Worker         Ok((fragment_name, rest.join(PATH_SEP)))
381*bb4ee6a4SAndroid Build Coastguard Worker     }
382*bb4ee6a4SAndroid Build Coastguard Worker }
383*bb4ee6a4SAndroid Build Coastguard Worker 
update_base_symbols( base: &mut Fdt, overlay: &Fdt, filtered_symbols: HashSet<String>, ) -> Result<()>384*bb4ee6a4SAndroid Build Coastguard Worker fn update_base_symbols(
385*bb4ee6a4SAndroid Build Coastguard Worker     base: &mut Fdt,
386*bb4ee6a4SAndroid Build Coastguard Worker     overlay: &Fdt,
387*bb4ee6a4SAndroid Build Coastguard Worker     filtered_symbols: HashSet<String>,
388*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> {
389*bb4ee6a4SAndroid Build Coastguard Worker     let Some(overlay_symbols_node) = overlay.root.subnode(SYMBOLS_NODE) else {
390*bb4ee6a4SAndroid Build Coastguard Worker         return Ok(()); // If there are no symbols in the overlay, just skip it.
391*bb4ee6a4SAndroid Build Coastguard Worker     };
392*bb4ee6a4SAndroid Build Coastguard Worker     let base_symbols_node = base.root.subnode_mut(SYMBOLS_NODE).unwrap();
393*bb4ee6a4SAndroid Build Coastguard Worker     for symbol in overlay_symbols_node.prop_names() {
394*bb4ee6a4SAndroid Build Coastguard Worker         if !filtered_symbols.is_empty() && !filtered_symbols.contains(symbol) {
395*bb4ee6a4SAndroid Build Coastguard Worker             continue; // Skip this symbol, it is not in the set of symbols we want.
396*bb4ee6a4SAndroid Build Coastguard Worker         }
397*bb4ee6a4SAndroid Build Coastguard Worker 
398*bb4ee6a4SAndroid Build Coastguard Worker         let symbol_target: Path = overlay_symbols_node
399*bb4ee6a4SAndroid Build Coastguard Worker             .get_prop::<String>(symbol)
400*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap()
401*bb4ee6a4SAndroid Build Coastguard Worker             .parse()?;
402*bb4ee6a4SAndroid Build Coastguard Worker 
403*bb4ee6a4SAndroid Build Coastguard Worker         // Parse location
404*bb4ee6a4SAndroid Build Coastguard Worker         let (fragment_name, rest) = extract_fragment_and_subpath(&symbol_target)?;
405*bb4ee6a4SAndroid Build Coastguard Worker 
406*bb4ee6a4SAndroid Build Coastguard Worker         // Find the overlay fragment
407*bb4ee6a4SAndroid Build Coastguard Worker         let fragment_node = overlay.root.subnode(fragment_name).ok_or_else(|| {
408*bb4ee6a4SAndroid Build Coastguard Worker             Error::ApplyOverlayError(format!("invalid symbol path {symbol_target}"))
409*bb4ee6a4SAndroid Build Coastguard Worker         })?;
410*bb4ee6a4SAndroid Build Coastguard Worker 
411*bb4ee6a4SAndroid Build Coastguard Worker         // Construct the new symbol path from `target-path` property value and the remainder of
412*bb4ee6a4SAndroid Build Coastguard Worker         // the symbol location. Eg, for target-path = "/node", and overlay symbol path
413*bb4ee6a4SAndroid Build Coastguard Worker         // "/fragment@X/__overlay__/path/to/subnode", the result is "/node/path/to/subnode".
414*bb4ee6a4SAndroid Build Coastguard Worker         let new_path: String = fragment_node
415*bb4ee6a4SAndroid Build Coastguard Worker             .get_prop::<String>(TARGET_PATH_PROP)
416*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap_or_default()
417*bb4ee6a4SAndroid Build Coastguard Worker             .parse::<Path>()?
418*bb4ee6a4SAndroid Build Coastguard Worker             .push(&rest)?
419*bb4ee6a4SAndroid Build Coastguard Worker             .into();
420*bb4ee6a4SAndroid Build Coastguard Worker         // Update base with new symbol path. `symbol` is a valid property name.
421*bb4ee6a4SAndroid Build Coastguard Worker         base_symbols_node.set_prop(symbol, new_path).unwrap();
422*bb4ee6a4SAndroid Build Coastguard Worker     }
423*bb4ee6a4SAndroid Build Coastguard Worker     Ok(())
424*bb4ee6a4SAndroid Build Coastguard Worker }
425*bb4ee6a4SAndroid Build Coastguard Worker 
426*bb4ee6a4SAndroid Build Coastguard Worker // Merge new reserved memory entries from overlay into base.
merge_resvmem(base: &mut Vec<FdtReserveEntry>, new_entries: Vec<FdtReserveEntry>)427*bb4ee6a4SAndroid Build Coastguard Worker fn merge_resvmem(base: &mut Vec<FdtReserveEntry>, new_entries: Vec<FdtReserveEntry>) {
428*bb4ee6a4SAndroid Build Coastguard Worker     base.extend(new_entries);
429*bb4ee6a4SAndroid Build Coastguard Worker     base.sort_by_key(|a| std::cmp::Reverse(a.address));
430*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(mut entry) = base.pop() {
431*bb4ee6a4SAndroid Build Coastguard Worker         let mut result = Vec::new();
432*bb4ee6a4SAndroid Build Coastguard Worker         while let Some(next_entry) = base.pop() {
433*bb4ee6a4SAndroid Build Coastguard Worker             if next_entry.address <= entry.address + entry.size {
434*bb4ee6a4SAndroid Build Coastguard Worker                 entry.size = (entry.address + entry.size).max(next_entry.address + next_entry.size)
435*bb4ee6a4SAndroid Build Coastguard Worker                     - entry.address;
436*bb4ee6a4SAndroid Build Coastguard Worker             } else {
437*bb4ee6a4SAndroid Build Coastguard Worker                 result.push(entry);
438*bb4ee6a4SAndroid Build Coastguard Worker                 entry = next_entry;
439*bb4ee6a4SAndroid Build Coastguard Worker             }
440*bb4ee6a4SAndroid Build Coastguard Worker         }
441*bb4ee6a4SAndroid Build Coastguard Worker         result.push(entry);
442*bb4ee6a4SAndroid Build Coastguard Worker         base.extend(result);
443*bb4ee6a4SAndroid Build Coastguard Worker     }
444*bb4ee6a4SAndroid Build Coastguard Worker }
445*bb4ee6a4SAndroid Build Coastguard Worker 
446*bb4ee6a4SAndroid Build Coastguard Worker /// Apply an overlay to the base FDT.
447*bb4ee6a4SAndroid Build Coastguard Worker ///
448*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
449*bb4ee6a4SAndroid Build Coastguard Worker ///
450*bb4ee6a4SAndroid Build Coastguard Worker /// `base` - base FDT that will be updated with new nodes and properties.
451*bb4ee6a4SAndroid Build Coastguard Worker /// `overlay` - overlay FDT that will be applied to the base. Must contain symbols and fixups nodes.
452*bb4ee6a4SAndroid Build Coastguard Worker /// `filtered_symbols` - A slice of node labels (symbols) listing nodes which will be applied to the
453*bb4ee6a4SAndroid Build Coastguard Worker ///     base. Values must correspond to the properties of overlay `__symbols__` node. If empty, the
454*bb4ee6a4SAndroid Build Coastguard Worker ///     entire overlay is applied to base.
apply_overlay<T: AsRef<str>>( base: &mut Fdt, mut overlay: Fdt, filter_symbols: impl std::iter::IntoIterator<Item = T>, ) -> Result<()>455*bb4ee6a4SAndroid Build Coastguard Worker pub fn apply_overlay<T: AsRef<str>>(
456*bb4ee6a4SAndroid Build Coastguard Worker     base: &mut Fdt,
457*bb4ee6a4SAndroid Build Coastguard Worker     mut overlay: Fdt,
458*bb4ee6a4SAndroid Build Coastguard Worker     filter_symbols: impl std::iter::IntoIterator<Item = T>,
459*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> {
460*bb4ee6a4SAndroid Build Coastguard Worker     // Analyze filtered symbols and find paths they point to.
461*bb4ee6a4SAndroid Build Coastguard Worker     let (filter_symbols, filter_paths) = prepare_filtered_symbols(filter_symbols, &overlay)?;
462*bb4ee6a4SAndroid Build Coastguard Worker 
463*bb4ee6a4SAndroid Build Coastguard Worker     // Analyze the overlay tree and extract paths that have to be applied to base.
464*bb4ee6a4SAndroid Build Coastguard Worker     let filtered_paths = collect_all_filtered_paths(filter_paths, &overlay)?;
465*bb4ee6a4SAndroid Build Coastguard Worker 
466*bb4ee6a4SAndroid Build Coastguard Worker     // Offset phandle property values in overlay nodes
467*bb4ee6a4SAndroid Build Coastguard Worker     let max_phandle = get_max_phandle(&base.root);
468*bb4ee6a4SAndroid Build Coastguard Worker     offset_phandle_values(&mut overlay, max_phandle)?;
469*bb4ee6a4SAndroid Build Coastguard Worker 
470*bb4ee6a4SAndroid Build Coastguard Worker     // Offset local phandle references in overlay properties
471*bb4ee6a4SAndroid Build Coastguard Worker     update_local_refs(&mut overlay, max_phandle)?;
472*bb4ee6a4SAndroid Build Coastguard Worker 
473*bb4ee6a4SAndroid Build Coastguard Worker     // Apply phandle values for external references
474*bb4ee6a4SAndroid Build Coastguard Worker     apply_external_fixups(base, &mut overlay)?;
475*bb4ee6a4SAndroid Build Coastguard Worker 
476*bb4ee6a4SAndroid Build Coastguard Worker     // Copy filtered overlay __symbols__ to base
477*bb4ee6a4SAndroid Build Coastguard Worker     update_base_symbols(base, &overlay, filter_symbols)?;
478*bb4ee6a4SAndroid Build Coastguard Worker 
479*bb4ee6a4SAndroid Build Coastguard Worker     // Remove unneeded nodes
480*bb4ee6a4SAndroid Build Coastguard Worker     do_overlay_filter(filtered_paths, &mut overlay);
481*bb4ee6a4SAndroid Build Coastguard Worker 
482*bb4ee6a4SAndroid Build Coastguard Worker     // Merge nodes from overlay into base
483*bb4ee6a4SAndroid Build Coastguard Worker     for fragment_node in overlay.root.iter_subnodes() {
484*bb4ee6a4SAndroid Build Coastguard Worker         overlay_fragment(fragment_node, base)?;
485*bb4ee6a4SAndroid Build Coastguard Worker     }
486*bb4ee6a4SAndroid Build Coastguard Worker 
487*bb4ee6a4SAndroid Build Coastguard Worker     // Merge reserved regions
488*bb4ee6a4SAndroid Build Coastguard Worker     merge_resvmem(&mut base.reserved_memory, overlay.reserved_memory);
489*bb4ee6a4SAndroid Build Coastguard Worker     Ok(())
490*bb4ee6a4SAndroid Build Coastguard Worker }
491*bb4ee6a4SAndroid Build Coastguard Worker 
492*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
493*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
494*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
495*bb4ee6a4SAndroid Build Coastguard Worker 
load_fdt(mut reader: impl std::io::Read) -> Result<Fdt>496*bb4ee6a4SAndroid Build Coastguard Worker     fn load_fdt(mut reader: impl std::io::Read) -> Result<Fdt> {
497*bb4ee6a4SAndroid Build Coastguard Worker         let mut buffer = Vec::new();
498*bb4ee6a4SAndroid Build Coastguard Worker         reader.read_to_end(&mut buffer).map_err(Error::FdtIoError)?;
499*bb4ee6a4SAndroid Build Coastguard Worker         Fdt::from_blob(&buffer[..])
500*bb4ee6a4SAndroid Build Coastguard Worker     }
501*bb4ee6a4SAndroid Build Coastguard Worker 
502*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_merge_resvmem()503*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_merge_resvmem() {
504*bb4ee6a4SAndroid Build Coastguard Worker         let mut base = vec![
505*bb4ee6a4SAndroid Build Coastguard Worker             FdtReserveEntry::new(1000, 100),
506*bb4ee6a4SAndroid Build Coastguard Worker             FdtReserveEntry::new(2000, 500),
507*bb4ee6a4SAndroid Build Coastguard Worker             FdtReserveEntry::new(3000, 1000),
508*bb4ee6a4SAndroid Build Coastguard Worker         ];
509*bb4ee6a4SAndroid Build Coastguard Worker         let new_entries = vec![
510*bb4ee6a4SAndroid Build Coastguard Worker             FdtReserveEntry::new(1010, 20),
511*bb4ee6a4SAndroid Build Coastguard Worker             FdtReserveEntry::new(1050, 1000),
512*bb4ee6a4SAndroid Build Coastguard Worker             FdtReserveEntry::new(2700, 500),
513*bb4ee6a4SAndroid Build Coastguard Worker         ];
514*bb4ee6a4SAndroid Build Coastguard Worker         merge_resvmem(&mut base, new_entries);
515*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
516*bb4ee6a4SAndroid Build Coastguard Worker             base,
517*bb4ee6a4SAndroid Build Coastguard Worker             vec![
518*bb4ee6a4SAndroid Build Coastguard Worker                 FdtReserveEntry::new(1000, 1500),
519*bb4ee6a4SAndroid Build Coastguard Worker                 FdtReserveEntry::new(2700, 1300),
520*bb4ee6a4SAndroid Build Coastguard Worker             ]
521*bb4ee6a4SAndroid Build Coastguard Worker         );
522*bb4ee6a4SAndroid Build Coastguard Worker     }
523*bb4ee6a4SAndroid Build Coastguard Worker 
524*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_find_phandle_single()525*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_find_phandle_single() {
526*bb4ee6a4SAndroid Build Coastguard Worker         let mut root = FdtNode::empty("").unwrap();
527*bb4ee6a4SAndroid Build Coastguard Worker         root.set_prop("a", 1u32).unwrap();
528*bb4ee6a4SAndroid Build Coastguard Worker         root.set_prop("b", 2u32).unwrap();
529*bb4ee6a4SAndroid Build Coastguard Worker         root.set_prop("phandle", 3u32).unwrap();
530*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(get_node_phandle(&root), Some(3));
531*bb4ee6a4SAndroid Build Coastguard Worker     }
532*bb4ee6a4SAndroid Build Coastguard Worker 
533*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_find_phandle_none()534*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_find_phandle_none() {
535*bb4ee6a4SAndroid Build Coastguard Worker         let mut root = FdtNode::empty("").unwrap();
536*bb4ee6a4SAndroid Build Coastguard Worker         root.set_prop("a", 1u32).unwrap();
537*bb4ee6a4SAndroid Build Coastguard Worker         root.set_prop("b", 2u32).unwrap();
538*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(get_node_phandle(&root), None);
539*bb4ee6a4SAndroid Build Coastguard Worker     }
540*bb4ee6a4SAndroid Build Coastguard Worker 
541*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_find_phandle_deprecated()542*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_find_phandle_deprecated() {
543*bb4ee6a4SAndroid Build Coastguard Worker         let mut root = FdtNode::empty("").unwrap();
544*bb4ee6a4SAndroid Build Coastguard Worker         root.set_prop("a", 1u32).unwrap();
545*bb4ee6a4SAndroid Build Coastguard Worker         root.set_prop("linux,phandle", 2u32).unwrap();
546*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(get_node_phandle(&root), Some(2));
547*bb4ee6a4SAndroid Build Coastguard Worker     }
548*bb4ee6a4SAndroid Build Coastguard Worker 
549*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_find_max_phandle()550*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_find_max_phandle() {
551*bb4ee6a4SAndroid Build Coastguard Worker         let mut root = FdtNode::empty("").unwrap();
552*bb4ee6a4SAndroid Build Coastguard Worker         root.set_prop("phandle", 2u32).unwrap();
553*bb4ee6a4SAndroid Build Coastguard Worker         let node_a = root.subnode_mut("a").unwrap();
554*bb4ee6a4SAndroid Build Coastguard Worker         node_a.set_prop("linux,phandle", 4u32).unwrap();
555*bb4ee6a4SAndroid Build Coastguard Worker         let node_b = root.subnode_mut("b").unwrap();
556*bb4ee6a4SAndroid Build Coastguard Worker         node_b.set_prop("phandle", 0xAu32).unwrap();
557*bb4ee6a4SAndroid Build Coastguard Worker         node_b.set_prop("linux,phandle", 0xAAu32).unwrap();
558*bb4ee6a4SAndroid Build Coastguard Worker 
559*bb4ee6a4SAndroid Build Coastguard Worker         let node_c = node_b.subnode_mut("c").unwrap();
560*bb4ee6a4SAndroid Build Coastguard Worker         node_c.set_prop("linux,phandle", 0x10u32).unwrap();
561*bb4ee6a4SAndroid Build Coastguard Worker         node_c.set_prop("not-phandle", 0x11u32).unwrap();
562*bb4ee6a4SAndroid Build Coastguard Worker         let node_d = node_b.subnode_mut("d").unwrap();
563*bb4ee6a4SAndroid Build Coastguard Worker         node_d.set_prop("not-phandle", 0x20u32).unwrap();
564*bb4ee6a4SAndroid Build Coastguard Worker         node_b.subnode_mut("").unwrap();
565*bb4ee6a4SAndroid Build Coastguard Worker 
566*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(get_max_phandle(&root), 0x10);
567*bb4ee6a4SAndroid Build Coastguard Worker     }
568*bb4ee6a4SAndroid Build Coastguard Worker 
569*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_offset_phandles()570*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_offset_phandles() {
571*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = Fdt::new(&[]);
572*bb4ee6a4SAndroid Build Coastguard Worker         fdt.root.set_prop("a", 1u32).unwrap();
573*bb4ee6a4SAndroid Build Coastguard Worker         fdt.root.set_prop("b", 2u32).unwrap();
574*bb4ee6a4SAndroid Build Coastguard Worker         fdt.root.set_prop("phandle", 3u32).unwrap();
575*bb4ee6a4SAndroid Build Coastguard Worker         let node_a = fdt.root.subnode_mut("a").unwrap();
576*bb4ee6a4SAndroid Build Coastguard Worker         node_a.set_prop("linux,phandle", 0x10u32).unwrap();
577*bb4ee6a4SAndroid Build Coastguard Worker         fdt.root.subnode_mut("b").unwrap();
578*bb4ee6a4SAndroid Build Coastguard Worker 
579*bb4ee6a4SAndroid Build Coastguard Worker         offset_phandle_values(&mut fdt, 100).unwrap();
580*bb4ee6a4SAndroid Build Coastguard Worker         for (prop, exp_val) in fdt.root.prop_names().zip([1u32, 2, 103].into_iter()) {
581*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(fdt.root.get_prop::<u32>(prop).unwrap(), exp_val);
582*bb4ee6a4SAndroid Build Coastguard Worker         }
583*bb4ee6a4SAndroid Build Coastguard Worker         let node = fdt.get_node("/a").unwrap();
584*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(node.get_prop::<u32>(LINUX_PHANDLE_PROP).unwrap(), 116);
585*bb4ee6a4SAndroid Build Coastguard Worker         let node = fdt.get_node("/b").unwrap();
586*bb4ee6a4SAndroid Build Coastguard Worker         assert!(node.prop_names().next().is_none());
587*bb4ee6a4SAndroid Build Coastguard Worker     }
588*bb4ee6a4SAndroid Build Coastguard Worker 
589*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_collect_local_references()590*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_collect_local_references() {
591*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = Fdt::new(&[]);
592*bb4ee6a4SAndroid Build Coastguard Worker         let fixups_node = fdt.root.subnode_mut(LOCAL_FIXUPS_NODE).unwrap();
593*bb4ee6a4SAndroid Build Coastguard Worker         fixups_node.set_prop("p1", vec![0u32, 4u32]).unwrap();
594*bb4ee6a4SAndroid Build Coastguard Worker         let fixups_subnode = fixups_node.subnode_mut("subnode1").unwrap();
595*bb4ee6a4SAndroid Build Coastguard Worker         fixups_subnode.set_prop("p2", vec![8u32]).unwrap();
596*bb4ee6a4SAndroid Build Coastguard Worker         let fixups_subnode = fixups_node.subnode_mut("subnode2").unwrap();
597*bb4ee6a4SAndroid Build Coastguard Worker         fixups_subnode.set_prop("p1", vec![16u32, 24u32]).unwrap();
598*bb4ee6a4SAndroid Build Coastguard Worker 
599*bb4ee6a4SAndroid Build Coastguard Worker         let paths = collect_local_fixup_paths(&fdt).unwrap();
600*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(paths.len(), 3);
601*bb4ee6a4SAndroid Build Coastguard Worker 
602*bb4ee6a4SAndroid Build Coastguard Worker         let expected_paths: BTreeMap<Path, Vec<PhandlePin>> = BTreeMap::from([
603*bb4ee6a4SAndroid Build Coastguard Worker             (
604*bb4ee6a4SAndroid Build Coastguard Worker                 ROOT_NODE.parse().unwrap(),
605*bb4ee6a4SAndroid Build Coastguard Worker                 vec![PhandlePin("p1".into(), 0), PhandlePin("p1".into(), 4)],
606*bb4ee6a4SAndroid Build Coastguard Worker             ),
607*bb4ee6a4SAndroid Build Coastguard Worker             (
608*bb4ee6a4SAndroid Build Coastguard Worker                 "/subnode1".parse().unwrap(),
609*bb4ee6a4SAndroid Build Coastguard Worker                 vec![PhandlePin("p2".into(), 8)],
610*bb4ee6a4SAndroid Build Coastguard Worker             ),
611*bb4ee6a4SAndroid Build Coastguard Worker             (
612*bb4ee6a4SAndroid Build Coastguard Worker                 "/subnode2".parse().unwrap(),
613*bb4ee6a4SAndroid Build Coastguard Worker                 vec![PhandlePin("p1".into(), 16), PhandlePin("p1".into(), 24)],
614*bb4ee6a4SAndroid Build Coastguard Worker             ),
615*bb4ee6a4SAndroid Build Coastguard Worker         ]);
616*bb4ee6a4SAndroid Build Coastguard Worker 
617*bb4ee6a4SAndroid Build Coastguard Worker         for (key, value) in expected_paths {
618*bb4ee6a4SAndroid Build Coastguard Worker             assert!(value.eq(paths.get(&key).unwrap()));
619*bb4ee6a4SAndroid Build Coastguard Worker         }
620*bb4ee6a4SAndroid Build Coastguard Worker     }
621*bb4ee6a4SAndroid Build Coastguard Worker 
make_fragment0() -> FdtNode622*bb4ee6a4SAndroid Build Coastguard Worker     fn make_fragment0() -> FdtNode {
623*bb4ee6a4SAndroid Build Coastguard Worker         let mut fragment_node = FdtNode::empty("fragment@0").unwrap();
624*bb4ee6a4SAndroid Build Coastguard Worker         fragment_node.set_prop("target-path", ROOT_NODE).unwrap();
625*bb4ee6a4SAndroid Build Coastguard Worker 
626*bb4ee6a4SAndroid Build Coastguard Worker         let overlay_node = fragment_node.subnode_mut(OVERLAY_NODE).unwrap();
627*bb4ee6a4SAndroid Build Coastguard Worker         overlay_node.set_prop("root-prop1", 1u32).unwrap();
628*bb4ee6a4SAndroid Build Coastguard Worker         overlay_node
629*bb4ee6a4SAndroid Build Coastguard Worker             .set_prop("root-prop2", vec![1u32, 2u32, 3u32])
630*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
631*bb4ee6a4SAndroid Build Coastguard Worker         let overlay_child_node = overlay_node.subnode_mut("child1").unwrap();
632*bb4ee6a4SAndroid Build Coastguard Worker         overlay_child_node.set_prop("prop1", 10u32).unwrap();
633*bb4ee6a4SAndroid Build Coastguard Worker         overlay_child_node
634*bb4ee6a4SAndroid Build Coastguard Worker             .set_prop("prop2", vec![10u32, 20u32, 30u32])
635*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
636*bb4ee6a4SAndroid Build Coastguard Worker         fragment_node
637*bb4ee6a4SAndroid Build Coastguard Worker     }
638*bb4ee6a4SAndroid Build Coastguard Worker 
make_fragment1() -> FdtNode639*bb4ee6a4SAndroid Build Coastguard Worker     fn make_fragment1() -> FdtNode {
640*bb4ee6a4SAndroid Build Coastguard Worker         let mut fragment_node = FdtNode::empty("fragment@1").unwrap();
641*bb4ee6a4SAndroid Build Coastguard Worker         fragment_node.set_prop("target-path", ROOT_NODE).unwrap();
642*bb4ee6a4SAndroid Build Coastguard Worker 
643*bb4ee6a4SAndroid Build Coastguard Worker         let overlay_node = fragment_node.subnode_mut(OVERLAY_NODE).unwrap();
644*bb4ee6a4SAndroid Build Coastguard Worker         overlay_node.set_prop("root-prop1", "abc").unwrap();
645*bb4ee6a4SAndroid Build Coastguard Worker         overlay_node.set_prop("root-prop3", 100u64).unwrap();
646*bb4ee6a4SAndroid Build Coastguard Worker         let overlay_child_node = overlay_node.subnode_mut("child1").unwrap();
647*bb4ee6a4SAndroid Build Coastguard Worker         overlay_child_node.set_prop("prop1", 0u32).unwrap();
648*bb4ee6a4SAndroid Build Coastguard Worker         let _ = overlay_node.subnode_mut("child2").unwrap();
649*bb4ee6a4SAndroid Build Coastguard Worker         fragment_node
650*bb4ee6a4SAndroid Build Coastguard Worker     }
651*bb4ee6a4SAndroid Build Coastguard Worker 
652*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_test_overlay_nodes()653*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_test_overlay_nodes() {
654*bb4ee6a4SAndroid Build Coastguard Worker         let mut base = Fdt::new(&[]);
655*bb4ee6a4SAndroid Build Coastguard Worker 
656*bb4ee6a4SAndroid Build Coastguard Worker         let fragment_node = make_fragment0();
657*bb4ee6a4SAndroid Build Coastguard Worker         overlay_fragment(&fragment_node, &mut base).unwrap();
658*bb4ee6a4SAndroid Build Coastguard Worker 
659*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(base.root.get_prop::<u32>("root-prop1").unwrap(), 1u32);
660*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
661*bb4ee6a4SAndroid Build Coastguard Worker             base.root.get_prop::<Vec<u32>>("root-prop2").unwrap(),
662*bb4ee6a4SAndroid Build Coastguard Worker             vec![1u32, 2u32, 3u32]
663*bb4ee6a4SAndroid Build Coastguard Worker         );
664*bb4ee6a4SAndroid Build Coastguard Worker         let child_node = base.get_node("/child1").unwrap();
665*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(child_node.get_prop::<u32>("prop1").unwrap(), 10u32);
666*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
667*bb4ee6a4SAndroid Build Coastguard Worker             child_node.get_prop::<Vec<u32>>("prop2").unwrap(),
668*bb4ee6a4SAndroid Build Coastguard Worker             vec![10u32, 20u32, 30u32]
669*bb4ee6a4SAndroid Build Coastguard Worker         );
670*bb4ee6a4SAndroid Build Coastguard Worker 
671*bb4ee6a4SAndroid Build Coastguard Worker         let fragment_node = make_fragment1();
672*bb4ee6a4SAndroid Build Coastguard Worker         overlay_fragment(&fragment_node, &mut base).unwrap();
673*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
674*bb4ee6a4SAndroid Build Coastguard Worker             base.root.get_prop::<Vec<u8>>("root-prop1").unwrap(),
675*bb4ee6a4SAndroid Build Coastguard Worker             vec![b'a', b'b', b'c', 0u8]
676*bb4ee6a4SAndroid Build Coastguard Worker         );
677*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(base.root.get_prop::<u64>("root-prop3").unwrap(), 100u64);
678*bb4ee6a4SAndroid Build Coastguard Worker 
679*bb4ee6a4SAndroid Build Coastguard Worker         let child_node = base.get_node("/child1").unwrap();
680*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(child_node.get_prop::<u32>("prop1").unwrap(), 0u32);
681*bb4ee6a4SAndroid Build Coastguard Worker 
682*bb4ee6a4SAndroid Build Coastguard Worker         let child_node = base.get_node("/child2").unwrap();
683*bb4ee6a4SAndroid Build Coastguard Worker         assert!(child_node.prop_names().next().is_none());
684*bb4ee6a4SAndroid Build Coastguard Worker     }
685*bb4ee6a4SAndroid Build Coastguard Worker 
686*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_overlay_symbols()687*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_overlay_symbols() {
688*bb4ee6a4SAndroid Build Coastguard Worker         let mut base = Fdt::new(&[]);
689*bb4ee6a4SAndroid Build Coastguard Worker         let symbols = base.root.subnode_mut(SYMBOLS_NODE).unwrap();
690*bb4ee6a4SAndroid Build Coastguard Worker 
691*bb4ee6a4SAndroid Build Coastguard Worker         symbols.set_prop("n1", "/path/to/node1").unwrap();
692*bb4ee6a4SAndroid Build Coastguard Worker         symbols.set_prop("n2", "/path/to/node2").unwrap();
693*bb4ee6a4SAndroid Build Coastguard Worker 
694*bb4ee6a4SAndroid Build Coastguard Worker         let mut overlay = Fdt::new(&[]);
695*bb4ee6a4SAndroid Build Coastguard Worker         let symbols = overlay.root.subnode_mut(SYMBOLS_NODE).unwrap();
696*bb4ee6a4SAndroid Build Coastguard Worker         symbols
697*bb4ee6a4SAndroid Build Coastguard Worker             .set_prop("n1", "/fragment@0/__overlay__/node1")
698*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
699*bb4ee6a4SAndroid Build Coastguard Worker         symbols
700*bb4ee6a4SAndroid Build Coastguard Worker             .set_prop("n3", "/fragment@0/__overlay__/path/to/node3")
701*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
702*bb4ee6a4SAndroid Build Coastguard Worker         let fragment = overlay.root.subnode_mut("fragment@0").unwrap();
703*bb4ee6a4SAndroid Build Coastguard Worker         fragment.set_prop("target-path", ROOT_NODE).unwrap();
704*bb4ee6a4SAndroid Build Coastguard Worker 
705*bb4ee6a4SAndroid Build Coastguard Worker         update_base_symbols(&mut base, &overlay, [].into()).unwrap();
706*bb4ee6a4SAndroid Build Coastguard Worker 
707*bb4ee6a4SAndroid Build Coastguard Worker         let symbols = base.root.subnode_mut(SYMBOLS_NODE).unwrap();
708*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(symbols.get_prop::<String>("n1").unwrap(), "/node1");
709*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(symbols.get_prop::<String>("n2").unwrap(), "/path/to/node2");
710*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(symbols.get_prop::<String>("n3").unwrap(), "/path/to/node3");
711*bb4ee6a4SAndroid Build Coastguard Worker     }
712*bb4ee6a4SAndroid Build Coastguard Worker 
713*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_overlay_filtered_symbols()714*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_overlay_filtered_symbols() {
715*bb4ee6a4SAndroid Build Coastguard Worker         let mut base = Fdt::new(&[]);
716*bb4ee6a4SAndroid Build Coastguard Worker 
717*bb4ee6a4SAndroid Build Coastguard Worker         let symbols = base.root.subnode_mut(SYMBOLS_NODE).unwrap();
718*bb4ee6a4SAndroid Build Coastguard Worker         symbols.set_prop("n1", "/path/to/node1").unwrap();
719*bb4ee6a4SAndroid Build Coastguard Worker         symbols.set_prop("n2", "/path/to/node2").unwrap();
720*bb4ee6a4SAndroid Build Coastguard Worker 
721*bb4ee6a4SAndroid Build Coastguard Worker         let mut overlay = Fdt::new(&[]);
722*bb4ee6a4SAndroid Build Coastguard Worker         let symbols = overlay.root.subnode_mut(SYMBOLS_NODE).unwrap();
723*bb4ee6a4SAndroid Build Coastguard Worker         symbols
724*bb4ee6a4SAndroid Build Coastguard Worker             .set_prop("n1", "/fragment@0/__overlay__/node1")
725*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
726*bb4ee6a4SAndroid Build Coastguard Worker         symbols
727*bb4ee6a4SAndroid Build Coastguard Worker             .set_prop("n3", "/fragment@0/__overlay__/path/to/node3")
728*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
729*bb4ee6a4SAndroid Build Coastguard Worker         symbols
730*bb4ee6a4SAndroid Build Coastguard Worker             .set_prop("not-this", "/fragment@0/__overlay__/path/to/not-this")
731*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
732*bb4ee6a4SAndroid Build Coastguard Worker         symbols
733*bb4ee6a4SAndroid Build Coastguard Worker             .set_prop(
734*bb4ee6a4SAndroid Build Coastguard Worker                 "not-this-either",
735*bb4ee6a4SAndroid Build Coastguard Worker                 "/fragment@0/__overlay__/path/to/not-this-either",
736*bb4ee6a4SAndroid Build Coastguard Worker             )
737*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
738*bb4ee6a4SAndroid Build Coastguard Worker         let fragment = overlay.root.subnode_mut("fragment@0").unwrap();
739*bb4ee6a4SAndroid Build Coastguard Worker         fragment.set_prop("target-path", ROOT_NODE).unwrap();
740*bb4ee6a4SAndroid Build Coastguard Worker 
741*bb4ee6a4SAndroid Build Coastguard Worker         update_base_symbols(
742*bb4ee6a4SAndroid Build Coastguard Worker             &mut base,
743*bb4ee6a4SAndroid Build Coastguard Worker             &overlay,
744*bb4ee6a4SAndroid Build Coastguard Worker             ["n1".to_string(), "n3".to_string()].into(),
745*bb4ee6a4SAndroid Build Coastguard Worker         )
746*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
747*bb4ee6a4SAndroid Build Coastguard Worker         let symbols = base.root.subnode(SYMBOLS_NODE).unwrap();
748*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(symbols.get_prop::<String>("n1").unwrap(), "/node1");
749*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(symbols.get_prop::<String>("n2").unwrap(), "/path/to/node2");
750*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(symbols.get_prop::<String>("n3").unwrap(), "/path/to/node3");
751*bb4ee6a4SAndroid Build Coastguard Worker         assert!(symbols.get_prop::<String>("not-this").is_none());
752*bb4ee6a4SAndroid Build Coastguard Worker         assert!(symbols.get_prop::<String>("not-this-either").is_none());
753*bb4ee6a4SAndroid Build Coastguard Worker 
754*bb4ee6a4SAndroid Build Coastguard Worker         update_base_symbols(&mut base, &overlay, [].into()).unwrap();
755*bb4ee6a4SAndroid Build Coastguard Worker         let symbols = base.root.subnode(SYMBOLS_NODE).unwrap();
756*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(symbols.get_prop::<String>("n1").unwrap(), "/node1");
757*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(symbols.get_prop::<String>("n2").unwrap(), "/path/to/node2");
758*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(symbols.get_prop::<String>("n3").unwrap(), "/path/to/node3");
759*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
760*bb4ee6a4SAndroid Build Coastguard Worker             symbols.get_prop::<String>("not-this").unwrap(),
761*bb4ee6a4SAndroid Build Coastguard Worker             "/path/to/not-this"
762*bb4ee6a4SAndroid Build Coastguard Worker         );
763*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
764*bb4ee6a4SAndroid Build Coastguard Worker             symbols.get_prop::<String>("not-this-either").unwrap(),
765*bb4ee6a4SAndroid Build Coastguard Worker             "/path/to/not-this-either"
766*bb4ee6a4SAndroid Build Coastguard Worker         );
767*bb4ee6a4SAndroid Build Coastguard Worker     }
768*bb4ee6a4SAndroid Build Coastguard Worker 
make_fdt_with_local_refs(references: &[(&str, u32)]) -> Result<Fdt>769*bb4ee6a4SAndroid Build Coastguard Worker     fn make_fdt_with_local_refs(references: &[(&str, u32)]) -> Result<Fdt> {
770*bb4ee6a4SAndroid Build Coastguard Worker         /* Returns this structure:
771*bb4ee6a4SAndroid Build Coastguard Worker            /
772*bb4ee6a4SAndroid Build Coastguard Worker                node1 (phandle=1)
773*bb4ee6a4SAndroid Build Coastguard Worker                    node1-1 (phandle=2)
774*bb4ee6a4SAndroid Build Coastguard Worker                        node1-1-1 (phandle=3)
775*bb4ee6a4SAndroid Build Coastguard Worker                        node1-1-2 (phandle=4)
776*bb4ee6a4SAndroid Build Coastguard Worker                    node1-2 (phandle=5)
777*bb4ee6a4SAndroid Build Coastguard Worker                        node1-2-1 (phandle=6)
778*bb4ee6a4SAndroid Build Coastguard Worker                node2 (phandle=7)
779*bb4ee6a4SAndroid Build Coastguard Worker                    node2-1 (phandle=8)
780*bb4ee6a4SAndroid Build Coastguard Worker                    node2-2 (phandle=9)
781*bb4ee6a4SAndroid Build Coastguard Worker                    node2-3 (phandle=10)
782*bb4ee6a4SAndroid Build Coastguard Worker                        node2-3-1 (phandle=11)
783*bb4ee6a4SAndroid Build Coastguard Worker                node3 (phandle=12)
784*bb4ee6a4SAndroid Build Coastguard Worker                    node3-1 (phandle=13)
785*bb4ee6a4SAndroid Build Coastguard Worker                __local_fixups__
786*bb4ee6a4SAndroid Build Coastguard Worker                    <references>
787*bb4ee6a4SAndroid Build Coastguard Worker                __symbols__
788*bb4ee6a4SAndroid Build Coastguard Worker                    <symbols>
789*bb4ee6a4SAndroid Build Coastguard Worker         */
790*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = Fdt::new(&[]);
791*bb4ee6a4SAndroid Build Coastguard Worker         let root = fdt.root_mut();
792*bb4ee6a4SAndroid Build Coastguard Worker 
793*bb4ee6a4SAndroid Build Coastguard Worker         let node1 = root.subnode_mut("node1")?;
794*bb4ee6a4SAndroid Build Coastguard Worker         node1.set_prop(PHANDLE_PROP, 1u32)?;
795*bb4ee6a4SAndroid Build Coastguard Worker         let node11 = node1.subnode_mut("node1-1")?;
796*bb4ee6a4SAndroid Build Coastguard Worker         node11.set_prop(PHANDLE_PROP, 2u32)?;
797*bb4ee6a4SAndroid Build Coastguard Worker         let node111 = node11.subnode_mut("node1-1-1")?;
798*bb4ee6a4SAndroid Build Coastguard Worker         node111.set_prop(PHANDLE_PROP, 3u32)?;
799*bb4ee6a4SAndroid Build Coastguard Worker         let node112 = node11.subnode_mut("node1-1-2")?;
800*bb4ee6a4SAndroid Build Coastguard Worker         node112.set_prop(PHANDLE_PROP, 4u32)?;
801*bb4ee6a4SAndroid Build Coastguard Worker         let node12 = node1.subnode_mut("node1-2")?;
802*bb4ee6a4SAndroid Build Coastguard Worker         node12.set_prop(PHANDLE_PROP, 5u32)?;
803*bb4ee6a4SAndroid Build Coastguard Worker         let node121 = node12.subnode_mut("node1-2-1")?;
804*bb4ee6a4SAndroid Build Coastguard Worker         node121.set_prop(PHANDLE_PROP, 6u32)?;
805*bb4ee6a4SAndroid Build Coastguard Worker         let node2 = root.subnode_mut("node2")?;
806*bb4ee6a4SAndroid Build Coastguard Worker         node2.set_prop(PHANDLE_PROP, 7u32)?;
807*bb4ee6a4SAndroid Build Coastguard Worker         let node21 = node2.subnode_mut("node2-1")?;
808*bb4ee6a4SAndroid Build Coastguard Worker         node21.set_prop(PHANDLE_PROP, 8u32)?;
809*bb4ee6a4SAndroid Build Coastguard Worker         let node22 = node2.subnode_mut("node2-2")?;
810*bb4ee6a4SAndroid Build Coastguard Worker         node22.set_prop(PHANDLE_PROP, 9u32)?;
811*bb4ee6a4SAndroid Build Coastguard Worker         let node23 = node2.subnode_mut("node2-3")?;
812*bb4ee6a4SAndroid Build Coastguard Worker         node23.set_prop(PHANDLE_PROP, 10u32)?;
813*bb4ee6a4SAndroid Build Coastguard Worker         let node231 = node23.subnode_mut("node2-3-1")?;
814*bb4ee6a4SAndroid Build Coastguard Worker         node231.set_prop(PHANDLE_PROP, 11u32)?;
815*bb4ee6a4SAndroid Build Coastguard Worker         let node3 = root.subnode_mut("node3")?;
816*bb4ee6a4SAndroid Build Coastguard Worker         node3.set_prop(PHANDLE_PROP, 12u32)?;
817*bb4ee6a4SAndroid Build Coastguard Worker         let node31 = node3.subnode_mut("node3-1")?;
818*bb4ee6a4SAndroid Build Coastguard Worker         node31.set_prop(PHANDLE_PROP, 13u32)?;
819*bb4ee6a4SAndroid Build Coastguard Worker 
820*bb4ee6a4SAndroid Build Coastguard Worker         let symbols = root.subnode_mut(SYMBOLS_NODE)?;
821*bb4ee6a4SAndroid Build Coastguard Worker         symbols.set_prop("node1", "/node1")?;
822*bb4ee6a4SAndroid Build Coastguard Worker         symbols.set_prop("node1-1", "/node1/node1-1")?;
823*bb4ee6a4SAndroid Build Coastguard Worker         symbols.set_prop("node1-1-2", "/node1/node1-1/node1-1-2")?;
824*bb4ee6a4SAndroid Build Coastguard Worker         symbols.set_prop("node2", "/node2")?;
825*bb4ee6a4SAndroid Build Coastguard Worker         symbols.set_prop("node2-3-1", "/node2/node2-3/node2-3-1")?;
826*bb4ee6a4SAndroid Build Coastguard Worker 
827*bb4ee6a4SAndroid Build Coastguard Worker         for (loc, phandle_val) in references {
828*bb4ee6a4SAndroid Build Coastguard Worker             let (path, pin) = parse_path_with_prop(loc)?;
829*bb4ee6a4SAndroid Build Coastguard Worker             // Write reference value in the tree sutrcture
830*bb4ee6a4SAndroid Build Coastguard Worker             let mut node = fdt
831*bb4ee6a4SAndroid Build Coastguard Worker                 .get_node_mut(path.clone())
832*bb4ee6a4SAndroid Build Coastguard Worker                 .ok_or_else(|| Error::InvalidPath(path.to_string()))?;
833*bb4ee6a4SAndroid Build Coastguard Worker             node.set_prop(&pin.0, *phandle_val)?;
834*bb4ee6a4SAndroid Build Coastguard Worker 
835*bb4ee6a4SAndroid Build Coastguard Worker             // Write reference path to local fixups node
836*bb4ee6a4SAndroid Build Coastguard Worker             node = fdt.root_mut().subnode_mut(LOCAL_FIXUPS_NODE)?;
837*bb4ee6a4SAndroid Build Coastguard Worker             for nname in path.iter() {
838*bb4ee6a4SAndroid Build Coastguard Worker                 node = node.subnode_mut(nname)?;
839*bb4ee6a4SAndroid Build Coastguard Worker             }
840*bb4ee6a4SAndroid Build Coastguard Worker             node.set_prop(&pin.0, 0u32)?;
841*bb4ee6a4SAndroid Build Coastguard Worker         }
842*bb4ee6a4SAndroid Build Coastguard Worker 
843*bb4ee6a4SAndroid Build Coastguard Worker         Ok(fdt)
844*bb4ee6a4SAndroid Build Coastguard Worker     }
845*bb4ee6a4SAndroid Build Coastguard Worker 
846*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_collect_filter_roots()847*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_collect_filter_roots() {
848*bb4ee6a4SAndroid Build Coastguard Worker         let fdt = make_fdt_with_local_refs(&[]).unwrap();
849*bb4ee6a4SAndroid Build Coastguard Worker         let (symbols, paths) = prepare_filtered_symbols::<&str>([], &fdt).unwrap();
850*bb4ee6a4SAndroid Build Coastguard Worker         assert!(symbols.is_empty());
851*bb4ee6a4SAndroid Build Coastguard Worker         assert!(paths.is_empty());
852*bb4ee6a4SAndroid Build Coastguard Worker 
853*bb4ee6a4SAndroid Build Coastguard Worker         let (symbols, paths) = prepare_filtered_symbols(["node1"], &fdt).unwrap();
854*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(symbols.len(), 1);
855*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(paths.len(), 1);
856*bb4ee6a4SAndroid Build Coastguard Worker         assert!(symbols.contains("node1"));
857*bb4ee6a4SAndroid Build Coastguard Worker         assert!(paths.contains(&"/node1".parse().unwrap()));
858*bb4ee6a4SAndroid Build Coastguard Worker 
859*bb4ee6a4SAndroid Build Coastguard Worker         let (symbols, paths) =
860*bb4ee6a4SAndroid Build Coastguard Worker             prepare_filtered_symbols(["node1", "node1-1", "node1"], &fdt).unwrap();
861*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(symbols.len(), 2);
862*bb4ee6a4SAndroid Build Coastguard Worker         assert!(symbols.contains("node1") && symbols.contains("node1-1"));
863*bb4ee6a4SAndroid Build Coastguard Worker         assert!(
864*bb4ee6a4SAndroid Build Coastguard Worker             paths.contains(&"/node1".parse().unwrap())
865*bb4ee6a4SAndroid Build Coastguard Worker                 && paths.contains(&"/node1/node1-1".parse().unwrap())
866*bb4ee6a4SAndroid Build Coastguard Worker         );
867*bb4ee6a4SAndroid Build Coastguard Worker 
868*bb4ee6a4SAndroid Build Coastguard Worker         prepare_filtered_symbols(["node1", "node1-1", "node1", "nosuchnode"], &fdt)
869*bb4ee6a4SAndroid Build Coastguard Worker             .expect_err("no symbol");
870*bb4ee6a4SAndroid Build Coastguard Worker         prepare_filtered_symbols(["node1-1-1"], &fdt).expect_err("no symbol");
871*bb4ee6a4SAndroid Build Coastguard Worker         prepare_filtered_symbols(["node1"], &Fdt::new(&[])).expect_err("no symbols node");
872*bb4ee6a4SAndroid Build Coastguard Worker     }
873*bb4ee6a4SAndroid Build Coastguard Worker 
874*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_collect_filtered_paths()875*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_collect_filtered_paths() {
876*bb4ee6a4SAndroid Build Coastguard Worker         // /node1/node1-2/node1-2-1:prop:0 => /node2/node2-3/node2-3-1 (phandle=11)
877*bb4ee6a4SAndroid Build Coastguard Worker         // /node1:prop:0 => /node3 (phandle=12)
878*bb4ee6a4SAndroid Build Coastguard Worker         let fdt = make_fdt_with_local_refs(&[
879*bb4ee6a4SAndroid Build Coastguard Worker             ("/node1/node1-2/node1-2-1:prop:0", 11),
880*bb4ee6a4SAndroid Build Coastguard Worker             ("/node1:prop:0", 12),
881*bb4ee6a4SAndroid Build Coastguard Worker         ])
882*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
883*bb4ee6a4SAndroid Build Coastguard Worker         let (_, paths) = prepare_filtered_symbols(["node1"], &fdt).unwrap();
884*bb4ee6a4SAndroid Build Coastguard Worker         let filtered = collect_all_filtered_paths(paths, &fdt).unwrap();
885*bb4ee6a4SAndroid Build Coastguard Worker 
886*bb4ee6a4SAndroid Build Coastguard Worker         // This is referenced by the symbol that was given.
887*bb4ee6a4SAndroid Build Coastguard Worker         assert!(filtered.contains(&"/node1".parse().unwrap()));
888*bb4ee6a4SAndroid Build Coastguard Worker         // This is referenced by the phandle value stored in the property.
889*bb4ee6a4SAndroid Build Coastguard Worker         assert!(filtered.contains(&"/node3".parse().unwrap()));
890*bb4ee6a4SAndroid Build Coastguard Worker         // References that appeart in the subtree of the filtered node are not included.
891*bb4ee6a4SAndroid Build Coastguard Worker         assert!(!filtered.contains(&"/node2/node2-3/node2-3-1".parse().unwrap()));
892*bb4ee6a4SAndroid Build Coastguard Worker     }
893*bb4ee6a4SAndroid Build Coastguard Worker 
894*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_collect_filtered_paths_circular()895*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_collect_filtered_paths_circular() {
896*bb4ee6a4SAndroid Build Coastguard Worker         // /node1:prop:0 => /node2/node2-3/node2-3-1 (phandle=11)
897*bb4ee6a4SAndroid Build Coastguard Worker         // /node2/node2-3:prop:0 => /node1/node1-1 (phandle=2)
898*bb4ee6a4SAndroid Build Coastguard Worker         let fdt = make_fdt_with_local_refs(&[("/node1:prop:0", 11), ("/node2/node2-3:prop:0", 2)])
899*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
900*bb4ee6a4SAndroid Build Coastguard Worker         let (_, paths) = prepare_filtered_symbols(["node1-1"], &fdt).unwrap();
901*bb4ee6a4SAndroid Build Coastguard Worker         let filtered = collect_all_filtered_paths(paths, &fdt).unwrap();
902*bb4ee6a4SAndroid Build Coastguard Worker 
903*bb4ee6a4SAndroid Build Coastguard Worker         // This is referenced by the symbol that was given.
904*bb4ee6a4SAndroid Build Coastguard Worker         assert!(filtered.contains(&"/node1/node1-1".parse().unwrap()));
905*bb4ee6a4SAndroid Build Coastguard Worker         // This is referenced by a parent node of the given symbol.
906*bb4ee6a4SAndroid Build Coastguard Worker         assert!(filtered.contains(&"/node2/node2-3/node2-3-1".parse().unwrap()));
907*bb4ee6a4SAndroid Build Coastguard Worker         // Above two paths cover all references
908*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(filtered.len(), 2);
909*bb4ee6a4SAndroid Build Coastguard Worker     }
910*bb4ee6a4SAndroid Build Coastguard Worker 
911*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_collect_filtered_paths_dangling()912*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_collect_filtered_paths_dangling() {
913*bb4ee6a4SAndroid Build Coastguard Worker         // /node1:prop:0 => /node2/node2-3/node2-3-1 (phandle=11)
914*bb4ee6a4SAndroid Build Coastguard Worker         // /node2/node2-3:prop:0 => dangling phandle=200
915*bb4ee6a4SAndroid Build Coastguard Worker         let fdt =
916*bb4ee6a4SAndroid Build Coastguard Worker             make_fdt_with_local_refs(&[("/node1:prop:0", 11), ("/node2/node2-3:prop:0", 200)])
917*bb4ee6a4SAndroid Build Coastguard Worker                 .unwrap();
918*bb4ee6a4SAndroid Build Coastguard Worker         let (_, paths) = prepare_filtered_symbols(["node1"], &fdt).unwrap();
919*bb4ee6a4SAndroid Build Coastguard Worker         collect_all_filtered_paths(paths, &fdt).expect_err("dangling phandle");
920*bb4ee6a4SAndroid Build Coastguard Worker     }
921*bb4ee6a4SAndroid Build Coastguard Worker 
922*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_collect_filtered_paths_minimal()923*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_collect_filtered_paths_minimal() {
924*bb4ee6a4SAndroid Build Coastguard Worker         // /node1:prop:0 => /node3/node3-1 (phandle=13)
925*bb4ee6a4SAndroid Build Coastguard Worker         // /node1/node1-1:prop:0 => /node1/node1-1/node1-1-2 (phandle=4)
926*bb4ee6a4SAndroid Build Coastguard Worker         // /node1/node1-1/node1-1-2:prop:0 => /node1 (phandle=1)
927*bb4ee6a4SAndroid Build Coastguard Worker         // /node3/node3-1:prop:0 => /node3 (phandle=12)
928*bb4ee6a4SAndroid Build Coastguard Worker         let fdt = make_fdt_with_local_refs(&[
929*bb4ee6a4SAndroid Build Coastguard Worker             ("/node1:prop:0", 13),
930*bb4ee6a4SAndroid Build Coastguard Worker             ("/node1/node1-1:prop:0", 4),
931*bb4ee6a4SAndroid Build Coastguard Worker             ("/node1/node1-1/node1-1-2:prop:0", 1),
932*bb4ee6a4SAndroid Build Coastguard Worker             ("/node3/node3-1:prop:0", 12),
933*bb4ee6a4SAndroid Build Coastguard Worker         ])
934*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
935*bb4ee6a4SAndroid Build Coastguard Worker         let (_, paths) = prepare_filtered_symbols(["node1"], &fdt).unwrap();
936*bb4ee6a4SAndroid Build Coastguard Worker         let filtered = collect_all_filtered_paths(paths, &fdt).unwrap();
937*bb4ee6a4SAndroid Build Coastguard Worker 
938*bb4ee6a4SAndroid Build Coastguard Worker         assert!(filtered.contains(&"/node1".parse().unwrap()));
939*bb4ee6a4SAndroid Build Coastguard Worker         assert!(filtered.contains(&"/node3".parse().unwrap()));
940*bb4ee6a4SAndroid Build Coastguard Worker         // Above two paths cover all references
941*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(filtered.len(), 2);
942*bb4ee6a4SAndroid Build Coastguard Worker     }
943*bb4ee6a4SAndroid Build Coastguard Worker 
count_nodes(root: &FdtNode) -> usize944*bb4ee6a4SAndroid Build Coastguard Worker     fn count_nodes(root: &FdtNode) -> usize {
945*bb4ee6a4SAndroid Build Coastguard Worker         let mut count = 1;
946*bb4ee6a4SAndroid Build Coastguard Worker         for s in root.iter_subnodes() {
947*bb4ee6a4SAndroid Build Coastguard Worker             count += count_nodes(s);
948*bb4ee6a4SAndroid Build Coastguard Worker         }
949*bb4ee6a4SAndroid Build Coastguard Worker         count
950*bb4ee6a4SAndroid Build Coastguard Worker     }
951*bb4ee6a4SAndroid Build Coastguard Worker 
952*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_do_filter_simple()953*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_do_filter_simple() {
954*bb4ee6a4SAndroid Build Coastguard Worker         let l1 = "/node1";
955*bb4ee6a4SAndroid Build Coastguard Worker         let l2 = "/node2";
956*bb4ee6a4SAndroid Build Coastguard Worker         let l3 = "/node3";
957*bb4ee6a4SAndroid Build Coastguard Worker         let fdt = &mut make_fdt_with_local_refs(&[]).unwrap();
958*bb4ee6a4SAndroid Build Coastguard Worker 
959*bb4ee6a4SAndroid Build Coastguard Worker         do_overlay_filter([].into(), fdt);
960*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node(l1).is_some());
961*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node(l2).is_some());
962*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node(l3).is_some());
963*bb4ee6a4SAndroid Build Coastguard Worker 
964*bb4ee6a4SAndroid Build Coastguard Worker         do_overlay_filter([l1.try_into().unwrap(), l2.try_into().unwrap()].into(), fdt);
965*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node(l1).is_some());
966*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node(l2).is_some());
967*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node(l3).is_none());
968*bb4ee6a4SAndroid Build Coastguard Worker     }
969*bb4ee6a4SAndroid Build Coastguard Worker 
970*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_do_filter_subnodes()971*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_do_filter_subnodes() {
972*bb4ee6a4SAndroid Build Coastguard Worker         let l1: Path = "/node1/node1-1".parse().unwrap();
973*bb4ee6a4SAndroid Build Coastguard Worker         let fdt = &mut make_fdt_with_local_refs(&[]).unwrap();
974*bb4ee6a4SAndroid Build Coastguard Worker 
975*bb4ee6a4SAndroid Build Coastguard Worker         do_overlay_filter([l1.clone()].into(), fdt);
976*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node(l1).is_some());
977*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(count_nodes(&fdt.root), 3);
978*bb4ee6a4SAndroid Build Coastguard Worker     }
979*bb4ee6a4SAndroid Build Coastguard Worker 
980*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_do_filter_deep()981*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_do_filter_deep() {
982*bb4ee6a4SAndroid Build Coastguard Worker         let l1: Path = "/node1/node1-1/node1-1-1".parse().unwrap();
983*bb4ee6a4SAndroid Build Coastguard Worker         let l2: Path = "/node2/node2-2".parse().unwrap();
984*bb4ee6a4SAndroid Build Coastguard Worker         let l3: Path = "/node2/node2-3/node2-3-1".parse().unwrap();
985*bb4ee6a4SAndroid Build Coastguard Worker         let fdt = &mut make_fdt_with_local_refs(&[]).unwrap();
986*bb4ee6a4SAndroid Build Coastguard Worker 
987*bb4ee6a4SAndroid Build Coastguard Worker         do_overlay_filter([l1.clone(), l2.clone(), l3.clone()].into(), fdt);
988*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node(l1).is_some());
989*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node(l2).is_some());
990*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node(l3).is_some());
991*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(count_nodes(&fdt.root), 8);
992*bb4ee6a4SAndroid Build Coastguard Worker     }
993*bb4ee6a4SAndroid Build Coastguard Worker 
994*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_offset_local_references()995*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_offset_local_references() {
996*bb4ee6a4SAndroid Build Coastguard Worker         let file = include_bytes!("../test-files/local_refs.dtb").as_slice();
997*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = load_fdt(file).unwrap();
998*bb4ee6a4SAndroid Build Coastguard Worker 
999*bb4ee6a4SAndroid Build Coastguard Worker         let node = fdt.get_node("/fragment@0/__overlay__/node1").unwrap();
1000*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(node.get_prop::<u32>("p2").unwrap(), 0x01);
1001*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(node.get_prop::<u32>("p3").unwrap(), 0xaa);
1002*bb4ee6a4SAndroid Build Coastguard Worker         let node = fdt.get_node("/fragment@0/__overlay__/node1/node2").unwrap();
1003*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(node.get_prop::<u32>("p1").unwrap(), 0xaa);
1004*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(node.get_prop::<u32>("p2").unwrap(), 0x02);
1005*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(node.get_prop::<u32>("p3").unwrap(), 0x03);
1006*bb4ee6a4SAndroid Build Coastguard Worker         let node = fdt.get_node("/fragment@0/__overlay__/node1/node3").unwrap();
1007*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(node.get_prop::<u32>("p1").unwrap(), 0x01);
1008*bb4ee6a4SAndroid Build Coastguard Worker 
1009*bb4ee6a4SAndroid Build Coastguard Worker         update_local_refs(&mut fdt, 5).unwrap();
1010*bb4ee6a4SAndroid Build Coastguard Worker         let node = fdt.get_node("/fragment@0/__overlay__/node1").unwrap();
1011*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(node.get_prop::<u32>("p2").unwrap(), 0x06);
1012*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(node.get_prop::<u32>("p3").unwrap(), 0xaa);
1013*bb4ee6a4SAndroid Build Coastguard Worker         let node = fdt.get_node("/fragment@0/__overlay__/node1/node2").unwrap();
1014*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(node.get_prop::<u32>("p1").unwrap(), 0xaa);
1015*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(node.get_prop::<u32>("p2").unwrap(), 0x07);
1016*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(node.get_prop::<u32>("p3").unwrap(), 0x08);
1017*bb4ee6a4SAndroid Build Coastguard Worker         let node = fdt.get_node("/fragment@0/__overlay__/node1/node3").unwrap();
1018*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(node.get_prop::<u32>("p1").unwrap(), 0x06);
1019*bb4ee6a4SAndroid Build Coastguard Worker     }
1020*bb4ee6a4SAndroid Build Coastguard Worker 
1021*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_collect_symbols()1022*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_collect_symbols() {
1023*bb4ee6a4SAndroid Build Coastguard Worker         let base =
1024*bb4ee6a4SAndroid Build Coastguard Worker             load_fdt(include_bytes!("../test-files/external_refs_base.dtb").as_slice()).unwrap();
1025*bb4ee6a4SAndroid Build Coastguard Worker         let mut overlay =
1026*bb4ee6a4SAndroid Build Coastguard Worker             load_fdt(include_bytes!("../test-files/external_refs_overlay.dtb").as_slice()).unwrap();
1027*bb4ee6a4SAndroid Build Coastguard Worker         let paths = [
1028*bb4ee6a4SAndroid Build Coastguard Worker             "/fragment@0/__overlay__/node1:p2:0",
1029*bb4ee6a4SAndroid Build Coastguard Worker             "/fragment@0/__overlay__/node1/node2:p3:4",
1030*bb4ee6a4SAndroid Build Coastguard Worker             "/fragment@0/__overlay__/node1/node3:p1:0",
1031*bb4ee6a4SAndroid Build Coastguard Worker         ];
1032*bb4ee6a4SAndroid Build Coastguard Worker         for p in paths.iter() {
1033*bb4ee6a4SAndroid Build Coastguard Worker             let (path, pin) = parse_path_with_prop(p).unwrap();
1034*bb4ee6a4SAndroid Build Coastguard Worker             let node = overlay.get_node(path).unwrap();
1035*bb4ee6a4SAndroid Build Coastguard Worker             let ref_val = node.phandle_at_offset(&pin.0, pin.1 as usize).unwrap();
1036*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(ref_val, 0xffffffff);
1037*bb4ee6a4SAndroid Build Coastguard Worker         }
1038*bb4ee6a4SAndroid Build Coastguard Worker 
1039*bb4ee6a4SAndroid Build Coastguard Worker         apply_external_fixups(&base, &mut overlay).unwrap();
1040*bb4ee6a4SAndroid Build Coastguard Worker         for (p, exp_val) in paths.iter().zip([1u32, 2u32, 2u32].into_iter()) {
1041*bb4ee6a4SAndroid Build Coastguard Worker             let (path, pin) = parse_path_with_prop(p).unwrap();
1042*bb4ee6a4SAndroid Build Coastguard Worker             let node = overlay.get_node(path).unwrap();
1043*bb4ee6a4SAndroid Build Coastguard Worker             let ref_val = node.phandle_at_offset(&pin.0, pin.1 as usize).unwrap();
1044*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(ref_val, exp_val);
1045*bb4ee6a4SAndroid Build Coastguard Worker         }
1046*bb4ee6a4SAndroid Build Coastguard Worker     }
1047*bb4ee6a4SAndroid Build Coastguard Worker 
1048*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_apply_overlay_complete()1049*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_apply_overlay_complete() {
1050*bb4ee6a4SAndroid Build Coastguard Worker         let mut base = load_fdt(include_bytes!("../test-files/base.dtb").as_slice()).unwrap();
1051*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(count_nodes(&base.root), 7);
1052*bb4ee6a4SAndroid Build Coastguard Worker 
1053*bb4ee6a4SAndroid Build Coastguard Worker         let overlay = load_fdt(include_bytes!("../test-files/overlay.dtb").as_slice()).unwrap();
1054*bb4ee6a4SAndroid Build Coastguard Worker         apply_overlay(&mut base, overlay, ["mydev"]).unwrap();
1055*bb4ee6a4SAndroid Build Coastguard Worker         assert!(base.get_node("/mydev@8000000").is_some());
1056*bb4ee6a4SAndroid Build Coastguard Worker         assert!(base.get_node("/mydev@8000000/devnode1").is_none());
1057*bb4ee6a4SAndroid Build Coastguard Worker         assert!(base.get_node("/mydev@8001000").is_none());
1058*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(count_nodes(&base.root), 8);
1059*bb4ee6a4SAndroid Build Coastguard Worker 
1060*bb4ee6a4SAndroid Build Coastguard Worker         let overlay = load_fdt(include_bytes!("../test-files/overlay.dtb").as_slice()).unwrap();
1061*bb4ee6a4SAndroid Build Coastguard Worker         apply_overlay(&mut base, overlay, ["mydev"]).unwrap();
1062*bb4ee6a4SAndroid Build Coastguard Worker         assert!(base.get_node("/mydev@8000000").is_some());
1063*bb4ee6a4SAndroid Build Coastguard Worker         assert!(base.get_node("/mydev@8001000").is_none());
1064*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(count_nodes(&base.root), 8);
1065*bb4ee6a4SAndroid Build Coastguard Worker 
1066*bb4ee6a4SAndroid Build Coastguard Worker         let overlay = load_fdt(include_bytes!("../test-files/overlay.dtb").as_slice()).unwrap();
1067*bb4ee6a4SAndroid Build Coastguard Worker         apply_overlay(&mut base, overlay, ["mydev2"]).unwrap();
1068*bb4ee6a4SAndroid Build Coastguard Worker         assert!(base.get_node("/mydev@8000000").is_some());
1069*bb4ee6a4SAndroid Build Coastguard Worker         assert!(base.get_node("/mydev@8001000").is_some());
1070*bb4ee6a4SAndroid Build Coastguard Worker         assert!(base.get_node("/mydev@8000000/devnode1").is_none());
1071*bb4ee6a4SAndroid Build Coastguard Worker         assert!(base.get_node("/mydev@8001000/devnode1").is_none());
1072*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(count_nodes(&base.root), 9);
1073*bb4ee6a4SAndroid Build Coastguard Worker     }
1074*bb4ee6a4SAndroid Build Coastguard Worker 
1075*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_overlay_filter_with_dependencies()1076*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_overlay_filter_with_dependencies() {
1077*bb4ee6a4SAndroid Build Coastguard Worker         let mut base = Fdt::new(&[]);
1078*bb4ee6a4SAndroid Build Coastguard Worker         let overlay =
1079*bb4ee6a4SAndroid Build Coastguard Worker             load_fdt(include_bytes!("../test-files/overlay_deps.dtb").as_slice()).unwrap();
1080*bb4ee6a4SAndroid Build Coastguard Worker         apply_overlay(&mut base, overlay, ["dev2"]).unwrap();
1081*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(count_nodes(&base.root), 6);
1082*bb4ee6a4SAndroid Build Coastguard Worker 
1083*bb4ee6a4SAndroid Build Coastguard Worker         let n = base.get_node("/n0-1").unwrap();
1084*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(n.get_prop::<u32>("prop1"), Some(1));
1085*bb4ee6a4SAndroid Build Coastguard Worker 
1086*bb4ee6a4SAndroid Build Coastguard Worker         assert!(base.get_node("/no-1/n2").is_none());
1087*bb4ee6a4SAndroid Build Coastguard Worker         let n = base.get_node("/n0-1/n1").unwrap();
1088*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(n.get_prop::<u32>("prop1"), Some(2));
1089*bb4ee6a4SAndroid Build Coastguard Worker 
1090*bb4ee6a4SAndroid Build Coastguard Worker         let n = base.get_node("/n0-2").unwrap();
1091*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(n.get_prop::<u32>("prop1"), Some(4));
1092*bb4ee6a4SAndroid Build Coastguard Worker 
1093*bb4ee6a4SAndroid Build Coastguard Worker         assert!(base.get_node("/n0-2/n2").is_none());
1094*bb4ee6a4SAndroid Build Coastguard Worker         let n = base.get_node("/n0-2/n1").unwrap();
1095*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(n.get_prop::<u32>("prop1"), Some(5));
1096*bb4ee6a4SAndroid Build Coastguard Worker     }
1097*bb4ee6a4SAndroid Build Coastguard Worker 
1098*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_overlay_skips_children()1099*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_overlay_skips_children() {
1100*bb4ee6a4SAndroid Build Coastguard Worker         let mut base =
1101*bb4ee6a4SAndroid Build Coastguard Worker             load_fdt(include_bytes!("../test-files/external_refs_base.dtb").as_slice()).unwrap();
1102*bb4ee6a4SAndroid Build Coastguard Worker         let overlay =
1103*bb4ee6a4SAndroid Build Coastguard Worker             load_fdt(include_bytes!("../test-files/external_refs_overlay.dtb").as_slice()).unwrap();
1104*bb4ee6a4SAndroid Build Coastguard Worker         apply_overlay(&mut base, overlay, ["n1"]).unwrap();
1105*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(count_nodes(&base.root), 6);
1106*bb4ee6a4SAndroid Build Coastguard Worker         assert!(base.get_node("/node1").is_some());
1107*bb4ee6a4SAndroid Build Coastguard Worker         assert!(base.get_node("/node1/node2").is_none());
1108*bb4ee6a4SAndroid Build Coastguard Worker         assert!(base.get_node("/node1/node3").is_none());
1109*bb4ee6a4SAndroid Build Coastguard Worker     }
1110*bb4ee6a4SAndroid Build Coastguard Worker }
1111