blob: 83f7734e00ebc64b2310b6b3b998fb7f83a4c2c4 [file] [log] [blame]
Shikha Panwar55e10ec2024-02-13 12:53:49 +00001// Copyright 2024, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! This module support creating AFV related overlays, that can then be appended to DT by VM.
16
17use anyhow::{anyhow, Result};
18use cstr::cstr;
19use fsfdt::FsFdt;
20use libfdt::Fdt;
21use std::ffi::CStr;
22use std::path::Path;
23
24pub(crate) const AVF_NODE_NAME: &CStr = cstr!("avf");
25pub(crate) const UNTRUSTED_NODE_NAME: &CStr = cstr!("untrusted");
26pub(crate) const VM_DT_OVERLAY_PATH: &str = "vm_dt_overlay.dtbo";
27pub(crate) const VM_DT_OVERLAY_MAX_SIZE: usize = 2000;
28
29/// Create a Device tree overlay containing the provided proc style device tree & properties!
30/// # Arguments
31/// * `dt_path` - (Optional) Path to (proc style) device tree to be included in the overlay.
32/// * `untrusted_props` - Include a property in /avf/untrusted node. This node is used to specify
33/// host provided properties such as `instance-id`.
34///
35/// Example: with `create_device_tree_overlay(_, _, [("instance-id", _),])`
36/// ```
37/// {
38/// fragment@0 {
39/// target-path = "/";
40/// __overlay__ {
41/// avf {
42/// untrusted { instance-id = [0x01 0x23 .. ] }
43/// }
44/// };
45/// };
46/// };
47/// };
48/// ```
49pub(crate) fn create_device_tree_overlay<'a>(
50 buffer: &'a mut [u8],
51 dt_path: Option<&'a Path>,
52 untrusted_props: &[(&'a CStr, &'a [u8])],
53) -> Result<&'a mut Fdt> {
54 if dt_path.is_none() && untrusted_props.is_empty() {
55 return Err(anyhow!("Expected at least one device tree addition"));
56 }
57
58 let fdt =
59 Fdt::create_empty_tree(buffer).map_err(|e| anyhow!("Failed to create empty Fdt: {e:?}"))?;
60 let mut root = fdt.root_mut().map_err(|e| anyhow!("Failed to get root: {e:?}"))?;
61 let mut node =
62 root.add_subnode(cstr!("fragment@0")).map_err(|e| anyhow!("Failed to fragment: {e:?}"))?;
63 node.setprop(cstr!("target-path"), b"/\0")
64 .map_err(|e| anyhow!("Failed to set target-path: {e:?}"))?;
65 let mut node = node
66 .add_subnode(cstr!("__overlay__"))
67 .map_err(|e| anyhow!("Failed to __overlay__ node: {e:?}"))?;
68
69 if !untrusted_props.is_empty() {
70 let mut node = node
71 .add_subnode(AVF_NODE_NAME)
72 .map_err(|e| anyhow!("Failed to add avf node: {e:?}"))?;
73 let mut node = node
74 .add_subnode(UNTRUSTED_NODE_NAME)
75 .map_err(|e| anyhow!("Failed to add /avf/untrusted node: {e:?}"))?;
76 for (name, value) in untrusted_props {
77 node.setprop(name, value).map_err(|e| anyhow!("Failed to set property: {e:?}"))?;
78 }
79 }
80
81 if let Some(path) = dt_path {
82 fdt.overlay_onto(cstr!("/fragment@0/__overlay__"), path)?;
83 }
84 fdt.pack().map_err(|e| anyhow!("Failed to pack DT overlay, {e:?}"))?;
85
86 Ok(fdt)
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn empty_overlays_not_allowed() {
95 let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
96 let res = create_device_tree_overlay(&mut buffer, None, &[]);
97 assert!(res.is_err());
98 }
99
100 #[test]
101 fn untrusted_prop_test() {
102 let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
103 let prop_name = cstr!("XOXO");
104 let prop_val_input = b"OXOX";
105 let fdt =
106 create_device_tree_overlay(&mut buffer, None, &[(prop_name, prop_val_input)]).unwrap();
107
108 let prop_value_dt = fdt
109 .node(cstr!("/fragment@0/__overlay__/avf/untrusted"))
110 .unwrap()
111 .expect("/avf/untrusted node doesn't exist")
112 .getprop(prop_name)
113 .unwrap()
114 .expect("Prop not found!");
115 assert_eq!(prop_value_dt, prop_val_input, "Unexpected property value");
116 }
117}