blob: 108ed61bb8bf4750b001ce6764ff39ac76565adb [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`.
Seungjae Yoo14e60182024-02-21 13:28:31 +090034/// * `trusted_props` - Include a property in /avf node. This overwrites nodes included with
35/// `dt_path`. In pVM, pvmfw will reject if it doesn't match the value in pvmfw config.
Shikha Panwar55e10ec2024-02-13 12:53:49 +000036///
Seungjae Yoo14e60182024-02-21 13:28:31 +090037/// Example: with `create_device_tree_overlay(_, _, [("instance-id", _),], [("digest", _),])`
Shikha Panwar55e10ec2024-02-13 12:53:49 +000038/// ```
39/// {
40/// fragment@0 {
41/// target-path = "/";
42/// __overlay__ {
43/// avf {
Seungjae Yoo14e60182024-02-21 13:28:31 +090044/// digest = [ 0xaa 0xbb .. ]
45/// untrusted { instance-id = [ 0x01 0x23 .. ] }
Shikha Panwar55e10ec2024-02-13 12:53:49 +000046/// }
47/// };
48/// };
49/// };
50/// };
51/// ```
52pub(crate) fn create_device_tree_overlay<'a>(
53 buffer: &'a mut [u8],
54 dt_path: Option<&'a Path>,
55 untrusted_props: &[(&'a CStr, &'a [u8])],
Seungjae Yoo14e60182024-02-21 13:28:31 +090056 trusted_props: &[(&'a CStr, &'a [u8])],
Shikha Panwar55e10ec2024-02-13 12:53:49 +000057) -> Result<&'a mut Fdt> {
Seungjae Yoo14e60182024-02-21 13:28:31 +090058 if dt_path.is_none() && untrusted_props.is_empty() && trusted_props.is_empty() {
Shikha Panwar55e10ec2024-02-13 12:53:49 +000059 return Err(anyhow!("Expected at least one device tree addition"));
60 }
61
62 let fdt =
63 Fdt::create_empty_tree(buffer).map_err(|e| anyhow!("Failed to create empty Fdt: {e:?}"))?;
Pierre-Clément Tosi244efea2024-02-16 14:48:14 +000064 let mut fragment = fdt
65 .root_mut()
Seungjae Yoo14e60182024-02-21 13:28:31 +090066 .add_subnode(cstr!("fragment@0"))
67 .map_err(|e| anyhow!("Failed to add fragment node: {e:?}"))?;
68 fragment
69 .setprop(cstr!("target-path"), b"/\0")
70 .map_err(|e| anyhow!("Failed to set target-path property: {e:?}"))?;
71 let overlay = fragment
Shikha Panwar55e10ec2024-02-13 12:53:49 +000072 .add_subnode(cstr!("__overlay__"))
Seungjae Yoo14e60182024-02-21 13:28:31 +090073 .map_err(|e| anyhow!("Failed to add __overlay__ node: {e:?}"))?;
74 let avf =
75 overlay.add_subnode(AVF_NODE_NAME).map_err(|e| anyhow!("Failed to add avf node: {e:?}"))?;
Shikha Panwar55e10ec2024-02-13 12:53:49 +000076
77 if !untrusted_props.is_empty() {
Seungjae Yoo14e60182024-02-21 13:28:31 +090078 let mut untrusted = avf
Shikha Panwar55e10ec2024-02-13 12:53:49 +000079 .add_subnode(UNTRUSTED_NODE_NAME)
Seungjae Yoo14e60182024-02-21 13:28:31 +090080 .map_err(|e| anyhow!("Failed to add untrusted node: {e:?}"))?;
Shikha Panwar55e10ec2024-02-13 12:53:49 +000081 for (name, value) in untrusted_props {
Seungjae Yoo14e60182024-02-21 13:28:31 +090082 untrusted
83 .setprop(name, value)
84 .map_err(|e| anyhow!("Failed to set untrusted property: {e:?}"))?;
Shikha Panwar55e10ec2024-02-13 12:53:49 +000085 }
86 }
87
Seungjae Yoo14e60182024-02-21 13:28:31 +090088 // Read dt_path from host DT and overlay onto fdt.
Shikha Panwar55e10ec2024-02-13 12:53:49 +000089 if let Some(path) = dt_path {
90 fdt.overlay_onto(cstr!("/fragment@0/__overlay__"), path)?;
91 }
Seungjae Yoo14e60182024-02-21 13:28:31 +090092
93 if !trusted_props.is_empty() {
94 let mut avf = fdt
95 .node_mut(cstr!("/fragment@0/__overlay__/avf"))
96 .map_err(|e| anyhow!("Failed to search avf node: {e:?}"))?
97 .ok_or(anyhow!("Failed to get avf node"))?;
98 for (name, value) in trusted_props {
99 avf.setprop(name, value)
100 .map_err(|e| anyhow!("Failed to set trusted property: {e:?}"))?;
101 }
102 }
103
Shikha Panwar55e10ec2024-02-13 12:53:49 +0000104 fdt.pack().map_err(|e| anyhow!("Failed to pack DT overlay, {e:?}"))?;
105
106 Ok(fdt)
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn empty_overlays_not_allowed() {
115 let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
Seungjae Yoo14e60182024-02-21 13:28:31 +0900116 let res = create_device_tree_overlay(&mut buffer, None, &[], &[]);
Shikha Panwar55e10ec2024-02-13 12:53:49 +0000117 assert!(res.is_err());
118 }
119
120 #[test]
121 fn untrusted_prop_test() {
122 let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
123 let prop_name = cstr!("XOXO");
124 let prop_val_input = b"OXOX";
125 let fdt =
Seungjae Yoo14e60182024-02-21 13:28:31 +0900126 create_device_tree_overlay(&mut buffer, None, &[(prop_name, prop_val_input)], &[])
127 .unwrap();
Shikha Panwar55e10ec2024-02-13 12:53:49 +0000128
129 let prop_value_dt = fdt
130 .node(cstr!("/fragment@0/__overlay__/avf/untrusted"))
131 .unwrap()
132 .expect("/avf/untrusted node doesn't exist")
133 .getprop(prop_name)
134 .unwrap()
135 .expect("Prop not found!");
136 assert_eq!(prop_value_dt, prop_val_input, "Unexpected property value");
137 }
Seungjae Yoo14e60182024-02-21 13:28:31 +0900138
139 #[test]
140 fn trusted_prop_test() {
141 let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
142 let prop_name = cstr!("XOXOXO");
143 let prop_val_input = b"OXOXOX";
144 let fdt =
145 create_device_tree_overlay(&mut buffer, None, &[], &[(prop_name, prop_val_input)])
146 .unwrap();
147
148 let prop_value_dt = fdt
149 .node(cstr!("/fragment@0/__overlay__/avf"))
150 .unwrap()
151 .expect("/avf node doesn't exist")
152 .getprop(prop_name)
153 .unwrap()
154 .expect("Prop not found!");
155 assert_eq!(prop_value_dt, prop_val_input, "Unexpected property value");
156 }
Shikha Panwar55e10ec2024-02-13 12:53:49 +0000157}