blob: fe2a4199b37ebcb051356eae647d1f773482b876 [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};
Shikha Panwar55e10ec2024-02-13 12:53:49 +000018use fsfdt::FsFdt;
Pechetty Sravani (xWF)faabfbd2024-09-24 15:27:48 +000019use libfdt::Fdt;
Shikha Panwar55e10ec2024-02-13 12:53:49 +000020use std::ffi::CStr;
21use std::path::Path;
22
Alan Stokesf46a17c2025-01-05 15:50:18 +000023pub(crate) const AVF_NODE_NAME: &CStr = c"avf";
24pub(crate) const UNTRUSTED_NODE_NAME: &CStr = c"untrusted";
Shikha Panwar55e10ec2024-02-13 12:53:49 +000025pub(crate) const VM_DT_OVERLAY_PATH: &str = "vm_dt_overlay.dtbo";
26pub(crate) const VM_DT_OVERLAY_MAX_SIZE: usize = 2000;
27
28/// Create a Device tree overlay containing the provided proc style device tree & properties!
29/// # Arguments
30/// * `dt_path` - (Optional) Path to (proc style) device tree to be included in the overlay.
31/// * `untrusted_props` - Include a property in /avf/untrusted node. This node is used to specify
32/// host provided properties such as `instance-id`.
Seungjae Yoo14e60182024-02-21 13:28:31 +090033/// * `trusted_props` - Include a property in /avf node. This overwrites nodes included with
34/// `dt_path`. In pVM, pvmfw will reject if it doesn't match the value in pvmfw config.
Shikha Panwar55e10ec2024-02-13 12:53:49 +000035///
Seungjae Yoo14e60182024-02-21 13:28:31 +090036/// Example: with `create_device_tree_overlay(_, _, [("instance-id", _),], [("digest", _),])`
Shikha Panwar55e10ec2024-02-13 12:53:49 +000037/// ```
38/// {
39/// fragment@0 {
40/// target-path = "/";
41/// __overlay__ {
42/// avf {
Seungjae Yoo14e60182024-02-21 13:28:31 +090043/// digest = [ 0xaa 0xbb .. ]
44/// untrusted { instance-id = [ 0x01 0x23 .. ] }
Shikha Panwar55e10ec2024-02-13 12:53:49 +000045/// }
46/// };
47/// };
48/// };
49/// };
50/// ```
51pub(crate) fn create_device_tree_overlay<'a>(
52 buffer: &'a mut [u8],
53 dt_path: Option<&'a Path>,
54 untrusted_props: &[(&'a CStr, &'a [u8])],
Seungjae Yoo14e60182024-02-21 13:28:31 +090055 trusted_props: &[(&'a CStr, &'a [u8])],
Shikha Panwar55e10ec2024-02-13 12:53:49 +000056) -> Result<&'a mut Fdt> {
Seungjae Yoo14e60182024-02-21 13:28:31 +090057 if dt_path.is_none() && untrusted_props.is_empty() && trusted_props.is_empty() {
Shikha Panwar55e10ec2024-02-13 12:53:49 +000058 return Err(anyhow!("Expected at least one device tree addition"));
59 }
60
61 let fdt =
62 Fdt::create_empty_tree(buffer).map_err(|e| anyhow!("Failed to create empty Fdt: {e:?}"))?;
Pierre-Clément Tosi244efea2024-02-16 14:48:14 +000063 let mut fragment = fdt
64 .root_mut()
Alan Stokesf46a17c2025-01-05 15:50:18 +000065 .add_subnode(c"fragment@0")
Seungjae Yoo14e60182024-02-21 13:28:31 +090066 .map_err(|e| anyhow!("Failed to add fragment node: {e:?}"))?;
67 fragment
Alan Stokesf46a17c2025-01-05 15:50:18 +000068 .setprop(c"target-path", b"/\0")
Seungjae Yoo14e60182024-02-21 13:28:31 +090069 .map_err(|e| anyhow!("Failed to set target-path property: {e:?}"))?;
70 let overlay = fragment
Alan Stokesf46a17c2025-01-05 15:50:18 +000071 .add_subnode(c"__overlay__")
Seungjae Yoo14e60182024-02-21 13:28:31 +090072 .map_err(|e| anyhow!("Failed to add __overlay__ node: {e:?}"))?;
73 let avf =
74 overlay.add_subnode(AVF_NODE_NAME).map_err(|e| anyhow!("Failed to add avf node: {e:?}"))?;
Shikha Panwar55e10ec2024-02-13 12:53:49 +000075
76 if !untrusted_props.is_empty() {
Seungjae Yoo14e60182024-02-21 13:28:31 +090077 let mut untrusted = avf
Shikha Panwar55e10ec2024-02-13 12:53:49 +000078 .add_subnode(UNTRUSTED_NODE_NAME)
Seungjae Yoo14e60182024-02-21 13:28:31 +090079 .map_err(|e| anyhow!("Failed to add untrusted node: {e:?}"))?;
Shikha Panwar55e10ec2024-02-13 12:53:49 +000080 for (name, value) in untrusted_props {
Seungjae Yoo14e60182024-02-21 13:28:31 +090081 untrusted
82 .setprop(name, value)
83 .map_err(|e| anyhow!("Failed to set untrusted property: {e:?}"))?;
Shikha Panwar55e10ec2024-02-13 12:53:49 +000084 }
85 }
86
Seungjae Yoo14e60182024-02-21 13:28:31 +090087 // Read dt_path from host DT and overlay onto fdt.
Shikha Panwar55e10ec2024-02-13 12:53:49 +000088 if let Some(path) = dt_path {
Alan Stokesf46a17c2025-01-05 15:50:18 +000089 fdt.overlay_onto(c"/fragment@0/__overlay__", path)?;
Shikha Panwar55e10ec2024-02-13 12:53:49 +000090 }
Seungjae Yoo14e60182024-02-21 13:28:31 +090091
Pechetty Sravani (xWF)faabfbd2024-09-24 15:27:48 +000092 if !trusted_props.is_empty() {
Seungjae Yoo14e60182024-02-21 13:28:31 +090093 let mut avf = fdt
Alan Stokesf46a17c2025-01-05 15:50:18 +000094 .node_mut(c"/fragment@0/__overlay__/avf")
Seungjae Yoo14e60182024-02-21 13:28:31 +090095 .map_err(|e| anyhow!("Failed to search avf node: {e:?}"))?
96 .ok_or(anyhow!("Failed to get avf node"))?;
97 for (name, value) in trusted_props {
98 avf.setprop(name, value)
99 .map_err(|e| anyhow!("Failed to set trusted property: {e:?}"))?;
100 }
101 }
102
Shikha Panwar55e10ec2024-02-13 12:53:49 +0000103 fdt.pack().map_err(|e| anyhow!("Failed to pack DT overlay, {e:?}"))?;
104
105 Ok(fdt)
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn empty_overlays_not_allowed() {
114 let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
Seungjae Yoo14e60182024-02-21 13:28:31 +0900115 let res = create_device_tree_overlay(&mut buffer, None, &[], &[]);
Shikha Panwar55e10ec2024-02-13 12:53:49 +0000116 assert!(res.is_err());
117 }
118
119 #[test]
120 fn untrusted_prop_test() {
121 let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
Alan Stokesf46a17c2025-01-05 15:50:18 +0000122 let prop_name = c"XOXO";
Shikha Panwar55e10ec2024-02-13 12:53:49 +0000123 let prop_val_input = b"OXOX";
124 let fdt =
Seungjae Yoo14e60182024-02-21 13:28:31 +0900125 create_device_tree_overlay(&mut buffer, None, &[(prop_name, prop_val_input)], &[])
126 .unwrap();
Shikha Panwar55e10ec2024-02-13 12:53:49 +0000127
128 let prop_value_dt = fdt
Alan Stokesf46a17c2025-01-05 15:50:18 +0000129 .node(c"/fragment@0/__overlay__/avf/untrusted")
Shikha Panwar55e10ec2024-02-13 12:53:49 +0000130 .unwrap()
131 .expect("/avf/untrusted node doesn't exist")
132 .getprop(prop_name)
133 .unwrap()
134 .expect("Prop not found!");
135 assert_eq!(prop_value_dt, prop_val_input, "Unexpected property value");
136 }
Seungjae Yoo14e60182024-02-21 13:28:31 +0900137
138 #[test]
139 fn trusted_prop_test() {
140 let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
Alan Stokesf46a17c2025-01-05 15:50:18 +0000141 let prop_name = c"XOXOXO";
Seungjae Yoo14e60182024-02-21 13:28:31 +0900142 let prop_val_input = b"OXOXOX";
143 let fdt =
144 create_device_tree_overlay(&mut buffer, None, &[], &[(prop_name, prop_val_input)])
145 .unwrap();
146
147 let prop_value_dt = fdt
Alan Stokesf46a17c2025-01-05 15:50:18 +0000148 .node(c"/fragment@0/__overlay__/avf")
Seungjae Yoo14e60182024-02-21 13:28:31 +0900149 .unwrap()
150 .expect("/avf node doesn't exist")
151 .getprop(prop_name)
152 .unwrap()
153 .expect("Prop not found!");
154 assert_eq!(prop_value_dt, prop_val_input, "Unexpected property value");
155 }
Shikha Panwar55e10ec2024-02-13 12:53:49 +0000156}