blob: 71d3a2693d3e9be204485927eeb83717e43bc927 [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:?}"))?;
Pierre-Clément Tosia3c4ec32024-02-15 20:05:15 +000060 let root = fdt.root_mut().map_err(|e| anyhow!("Failed to get root: {e:?}"))?;
Shikha Panwar55e10ec2024-02-13 12:53:49 +000061 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:?}"))?;
Pierre-Clément Tosia3c4ec32024-02-15 20:05:15 +000065 let node = node
Shikha Panwar55e10ec2024-02-13 12:53:49 +000066 .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)
Pierre-Clément Tosia3c4ec32024-02-15 20:05:15 +000072 .map_err(|e| anyhow!("Failed to add avf node: {e:?}"))?
Shikha Panwar55e10ec2024-02-13 12:53:49 +000073 .add_subnode(UNTRUSTED_NODE_NAME)
74 .map_err(|e| anyhow!("Failed to add /avf/untrusted node: {e:?}"))?;
75 for (name, value) in untrusted_props {
76 node.setprop(name, value).map_err(|e| anyhow!("Failed to set property: {e:?}"))?;
77 }
78 }
79
80 if let Some(path) = dt_path {
81 fdt.overlay_onto(cstr!("/fragment@0/__overlay__"), path)?;
82 }
83 fdt.pack().map_err(|e| anyhow!("Failed to pack DT overlay, {e:?}"))?;
84
85 Ok(fdt)
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn empty_overlays_not_allowed() {
94 let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
95 let res = create_device_tree_overlay(&mut buffer, None, &[]);
96 assert!(res.is_err());
97 }
98
99 #[test]
100 fn untrusted_prop_test() {
101 let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
102 let prop_name = cstr!("XOXO");
103 let prop_val_input = b"OXOX";
104 let fdt =
105 create_device_tree_overlay(&mut buffer, None, &[(prop_name, prop_val_input)]).unwrap();
106
107 let prop_value_dt = fdt
108 .node(cstr!("/fragment@0/__overlay__/avf/untrusted"))
109 .unwrap()
110 .expect("/avf/untrusted node doesn't exist")
111 .getprop(prop_name)
112 .unwrap()
113 .expect("Prop not found!");
114 assert_eq!(prop_value_dt, prop_val_input, "Unexpected property value");
115 }
116}