aarch64: fdt: Fix format of properties containing multiple values

When a FDT's property contains multiple values, the property must be a byte
array which uses the null character ('\0') as the delimiter, but we didn't
so.
This CL fixes the format so the guest kernel can parse PSCI versions
properly.

BUG=b:174224484
TEST=arc.Reboot.vm on kukui-arc-r

Change-Id: I61a983251cdbe8c021f5999cbf5efd026bbc0c27
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2567837
Tested-by: Keiichi Watanabe <keiichiw@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Marc Zyngier <mzyngier@google.com>
Reviewed-by: Lepton Wu <lepton@chromium.org>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Commit-Queue: Keiichi Watanabe <keiichiw@chromium.org>
This commit is contained in:
Keiichi Watanabe 2020-12-02 00:12:44 +09:00 committed by Commit Bot
parent 80f76b9558
commit 22f808ff13
2 changed files with 30 additions and 14 deletions

View file

@ -8,7 +8,8 @@ use std::io::Read;
use arch::fdt::{
begin_node, end_node, finish_fdt, generate_prop32, generate_prop64, property, property_cstring,
property_null, property_string, property_u32, property_u64, start_fdt, Error, Result,
property_null, property_string, property_string_list, property_u32, property_u64, start_fdt,
Error, Result,
};
use arch::SERIAL_ADDR;
use devices::{PciAddress, PciInterruptPin};
@ -184,17 +185,14 @@ fn create_serial_nodes(fdt: &mut Vec<u8>) -> Result<()> {
}
fn create_psci_node(fdt: &mut Vec<u8>, version: &PsciVersion) -> Result<()> {
let compatible = if version.major == 1 {
let mut compatible = vec![format!("arm,psci-{}.{}", version.major, version.minor)];
if version.major == 1 {
// Put `psci-0.2` as well because PSCI 1.0 is compatible with PSCI 0.2.
format!(
"\"arm,psci-{}.{}\", \"arm,psci-0.2\"",
version.major, version.minor
)
} else {
format!("arm,psci-{}.{}", version.major, version.minor)
compatible.push(format!("arm,psci-0.2"))
};
begin_node(fdt, "psci")?;
property_string(fdt, "compatible", &compatible)?;
property_string_list(fdt, "compatible", compatible)?;
// Only support aarch64 guest
property_string(fdt, "method", "hvc")?;
end_node(fdt)?;

View file

@ -156,17 +156,16 @@ pub fn property_null(fdt: &mut Vec<u8>, name: &str) -> Result<()> {
Ok(())
}
pub fn property_cstring(fdt: &mut Vec<u8>, name: &str, cstr_value: &CStr) -> Result<()> {
let value_bytes = cstr_value.to_bytes_with_nul();
pub fn property_bytes(fdt: &mut Vec<u8>, name: &str, bytes: &[u8]) -> Result<()> {
let cstr_name = CString::new(name).unwrap();
// Safe because we allocated fdt, converted name and value to CStrings
// Safe because we allocated fdt, converted name to CStrings
let fdt_ret = unsafe {
fdt_property(
fdt.as_mut_ptr() as *mut c_void,
cstr_name.as_ptr(),
value_bytes.as_ptr() as *mut c_void,
value_bytes.len() as i32,
bytes.as_ptr() as *mut c_void,
bytes.len() as i32,
)
};
if fdt_ret != 0 {
@ -175,11 +174,30 @@ pub fn property_cstring(fdt: &mut Vec<u8>, name: &str, cstr_value: &CStr) -> Res
Ok(())
}
pub fn property_cstring(fdt: &mut Vec<u8>, name: &str, cstr_value: &CStr) -> Result<()> {
let value_bytes = cstr_value.to_bytes_with_nul();
property_bytes(fdt, name, value_bytes)
}
pub fn property_string(fdt: &mut Vec<u8>, name: &str, value: &str) -> Result<()> {
let cstr_value = CString::new(value).unwrap();
property_cstring(fdt, name, &cstr_value)
}
pub fn property_string_list(fdt: &mut Vec<u8>, name: &str, values: Vec<String>) -> Result<()> {
let bytes = values
.into_iter()
.map(|s| {
let mut bytes = s.into_bytes();
// Each value must be null-terminated.
bytes.push(0);
bytes
})
.flatten()
.collect::<Vec<u8>>();
property_bytes(fdt, name, &bytes)
}
pub fn start_fdt(fdt: &mut Vec<u8>, fdt_max_size: usize) -> Result<()> {
// Safe since we allocated this array with fdt_max_size
let mut fdt_ret = unsafe { fdt_create(fdt.as_mut_ptr() as *mut c_void, fdt_max_size as c_int) };