blob: d226635987a6dd0fa0de26e080dd8aa911f1f497 [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;
Matt Gilbrideef4c6ec2024-08-30 16:29:42 +000020use libfdt::{Fdt, FdtError};
Shikha Panwar55e10ec2024-02-13 12:53:49 +000021use 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
Matt Gilbrideef4c6ec2024-08-30 16:29:42 +000093 if cfg!(tpu_assignable_device) {
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 let vendor_digest = cstr!("vendor_hashtree_descriptor_root_digest");
99 // Remove the vendor digest.
100 // In the case it is actually requested, it will be re-added by virtue of being in
101 // `trusted_props`.
102 match avf.delprop(vendor_digest) {
103 Ok(()) | Err(FdtError::NotFound) => {}
104 Err(e) => {
105 return Err(anyhow!("Unexpected error pre-removing {vendor_digest:?}: {e:?}"))
106 }
107 }
108 for (name, value) in trusted_props {
109 avf.setprop(name, value)
110 .map_err(|e| anyhow!("Failed to set trusted property: {e:?}"))?;
111 }
112 } else if !trusted_props.is_empty() {
Seungjae Yoo14e60182024-02-21 13:28:31 +0900113 let mut avf = fdt
114 .node_mut(cstr!("/fragment@0/__overlay__/avf"))
115 .map_err(|e| anyhow!("Failed to search avf node: {e:?}"))?
116 .ok_or(anyhow!("Failed to get avf node"))?;
117 for (name, value) in trusted_props {
118 avf.setprop(name, value)
119 .map_err(|e| anyhow!("Failed to set trusted property: {e:?}"))?;
120 }
121 }
122
Shikha Panwar55e10ec2024-02-13 12:53:49 +0000123 fdt.pack().map_err(|e| anyhow!("Failed to pack DT overlay, {e:?}"))?;
124
125 Ok(fdt)
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131
132 #[test]
133 fn empty_overlays_not_allowed() {
134 let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
Seungjae Yoo14e60182024-02-21 13:28:31 +0900135 let res = create_device_tree_overlay(&mut buffer, None, &[], &[]);
Shikha Panwar55e10ec2024-02-13 12:53:49 +0000136 assert!(res.is_err());
137 }
138
139 #[test]
140 fn untrusted_prop_test() {
141 let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
142 let prop_name = cstr!("XOXO");
143 let prop_val_input = b"OXOX";
144 let fdt =
Seungjae Yoo14e60182024-02-21 13:28:31 +0900145 create_device_tree_overlay(&mut buffer, None, &[(prop_name, prop_val_input)], &[])
146 .unwrap();
Shikha Panwar55e10ec2024-02-13 12:53:49 +0000147
148 let prop_value_dt = fdt
149 .node(cstr!("/fragment@0/__overlay__/avf/untrusted"))
150 .unwrap()
151 .expect("/avf/untrusted 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 }
Seungjae Yoo14e60182024-02-21 13:28:31 +0900157
158 #[test]
159 fn trusted_prop_test() {
160 let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
161 let prop_name = cstr!("XOXOXO");
162 let prop_val_input = b"OXOXOX";
163 let fdt =
164 create_device_tree_overlay(&mut buffer, None, &[], &[(prop_name, prop_val_input)])
165 .unwrap();
166
167 let prop_value_dt = fdt
168 .node(cstr!("/fragment@0/__overlay__/avf"))
169 .unwrap()
170 .expect("/avf node doesn't exist")
171 .getprop(prop_name)
172 .unwrap()
173 .expect("Prop not found!");
174 assert_eq!(prop_value_dt, prop_val_input, "Unexpected property value");
175 }
Shikha Panwar55e10ec2024-02-13 12:53:49 +0000176}