blob: f4b99a6fb8d42ade5c85d5fc013e74f8ce69d9f1 [file] [log] [blame]
Jaewan Kimba8929b2023-01-13 11:13:29 +09001// Copyright 2023, 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//! Support for the debug policy overlay in pvmfw
16
Jiyong Parkb87f3302023-03-21 10:03:11 +090017use crate::cstr;
Jaewan Kim3124ef02023-03-23 19:25:20 +090018use alloc::vec::Vec;
Jaewan Kimba8929b2023-01-13 11:13:29 +090019use core::ffi::CStr;
20use core::fmt;
21use libfdt::FdtError;
22use log::info;
23
24#[derive(Debug, Clone)]
25pub enum DebugPolicyError {
26 /// The provided baseline FDT was invalid or malformed, so cannot access certain node/prop
27 Fdt(&'static str, FdtError),
28 /// The provided debug policy FDT was invalid or malformed.
29 DebugPolicyFdt(&'static str, FdtError),
30 /// The overlaid result FDT is invalid or malformed, and may be corrupted.
31 OverlaidFdt(&'static str, FdtError),
32}
33
34impl fmt::Display for DebugPolicyError {
35 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36 match self {
37 Self::Fdt(s, e) => write!(f, "Invalid baseline FDT. {s}: {e}"),
38 Self::DebugPolicyFdt(s, e) => write!(f, "Invalid overlay FDT. {s}: {e}"),
39 Self::OverlaidFdt(s, e) => write!(f, "Invalid overlaid FDT. {s}: {e}"),
40 }
41 }
42}
43
44/// Applies the debug policy device tree overlay to the pVM DT.
45///
46/// # Safety
47///
48/// When an error is returned by this function, the input `Fdt` should be
49/// discarded as it may have have been partially corrupted during the overlay
50/// application process.
51unsafe fn apply_debug_policy(
52 fdt: &mut libfdt::Fdt,
53 debug_policy: &mut [u8],
54) -> Result<(), DebugPolicyError> {
55 let overlay = libfdt::Fdt::from_mut_slice(debug_policy)
56 .map_err(|e| DebugPolicyError::DebugPolicyFdt("Failed to load debug policy overlay", e))?;
57
58 fdt.unpack().map_err(|e| DebugPolicyError::Fdt("Failed to unpack", e))?;
59
60 let fdt = fdt
61 .apply_overlay(overlay)
62 .map_err(|e| DebugPolicyError::DebugPolicyFdt("Failed to apply overlay", e))?;
63
64 fdt.pack().map_err(|e| DebugPolicyError::OverlaidFdt("Failed to re-pack", e))
65}
66
Jaewan Kimc03f6612023-02-20 00:06:26 +090067/// Enables console output by adding kernel.printk.devkmsg and kernel.console to bootargs.
68/// This uses hardcoded console name 'hvc0' and it should be match with microdroid's bootconfig.debuggable.
69fn enable_console_output(fdt: &mut libfdt::Fdt) -> Result<(), DebugPolicyError> {
Jaewan Kimc03f6612023-02-20 00:06:26 +090070 let chosen = match fdt
Jiyong Parkb87f3302023-03-21 10:03:11 +090071 .node(cstr!("/chosen"))
Jaewan Kimc03f6612023-02-20 00:06:26 +090072 .map_err(|e| DebugPolicyError::Fdt("Failed to find /chosen", e))?
73 {
74 Some(node) => node,
75 None => return Ok(()),
76 };
77
78 let bootargs = match chosen
Jiyong Parkb87f3302023-03-21 10:03:11 +090079 .getprop_str(cstr!("bootargs"))
Jaewan Kimc03f6612023-02-20 00:06:26 +090080 .map_err(|e| DebugPolicyError::Fdt("Failed to find bootargs prop", e))?
81 {
82 Some(value) if !value.to_bytes().is_empty() => value,
83 _ => return Ok(()),
84 };
85
86 let mut new_bootargs = Vec::from(bootargs.to_bytes());
87 new_bootargs.extend_from_slice(b" printk.devkmsg=on console=hvc0\0");
88
89 // We'll set larger prop, and need to prepare some room first.
90 fdt.unpack().map_err(|e| DebugPolicyError::OverlaidFdt("Failed to unpack", e))?;
91
92 // We've checked existence of /chosen node at the beginning.
Jiyong Parkb87f3302023-03-21 10:03:11 +090093 let mut chosen_mut = fdt.node_mut(cstr!("/chosen")).unwrap().unwrap();
94 chosen_mut.setprop(cstr!("bootargs"), new_bootargs.as_slice()).map_err(|e| {
Jaewan Kimc03f6612023-02-20 00:06:26 +090095 DebugPolicyError::OverlaidFdt("Failed to enabled console output. FDT might be corrupted", e)
96 })?;
97
98 fdt.pack().map_err(|e| DebugPolicyError::OverlaidFdt("Failed to pack", e))?;
99 Ok(())
100}
101
102/// Returns true only if fdt has log prop in the /avf/guest/common node with value <1>
103fn is_console_output_enabled(fdt: &libfdt::Fdt) -> Result<bool, DebugPolicyError> {
104 let common = match fdt
Jiyong Parkb87f3302023-03-21 10:03:11 +0900105 .node(cstr!("/avf/guest/common"))
Jaewan Kimc03f6612023-02-20 00:06:26 +0900106 .map_err(|e| DebugPolicyError::DebugPolicyFdt("Failed to find /avf/guest/common node", e))?
107 {
108 Some(node) => node,
109 None => return Ok(false),
110 };
111
112 match common
Jiyong Parkb87f3302023-03-21 10:03:11 +0900113 .getprop_u32(cstr!("log"))
Jaewan Kimc03f6612023-02-20 00:06:26 +0900114 .map_err(|e| DebugPolicyError::DebugPolicyFdt("Failed to find log prop", e))?
115 {
116 Some(1) => Ok(true),
117 _ => Ok(false),
118 }
119}
120
Jaewan Kimba8929b2023-01-13 11:13:29 +0900121/// Handles debug policies.
122///
123/// # Safety
124///
125/// This may corrupt the input `Fdt` when overlaying debug policy or applying
126/// ramdump configuration.
127pub unsafe fn handle_debug_policy(
128 fdt: &mut libfdt::Fdt,
129 debug_policy: Option<&mut [u8]>,
130) -> Result<(), DebugPolicyError> {
131 if let Some(dp) = debug_policy {
132 apply_debug_policy(fdt, dp)?;
133 }
134
Jaewan Kim66f062e2023-02-25 01:07:43 +0900135 // Handles console output in the debug policy
Jaewan Kimc03f6612023-02-20 00:06:26 +0900136 if is_console_output_enabled(fdt)? {
137 enable_console_output(fdt)?;
138 info!("console output is enabled by debug policy");
139 }
140 Ok(())
Jaewan Kimba8929b2023-01-13 11:13:29 +0900141}