pvmfw: Expect an appended BCC

In Android T, the BCC was passed by the platform to pvmfw by appending
it to its binary at load time. Expect this behavior and make use of the
BCC in main() by logging the slice, for now.

Add the 'legacy' feature to control support for legacy interfaces; it is
intended to be disabled in the future.

Bug: 256827715
Test: atest MicrodroidTestApp
Change-Id: I4d0cfb028e42f2f7f5d343a941124f64d4d93f9a
This commit is contained in:
Pierre-Clément Tosi 2022-10-17 13:35:27 +01:00
parent 619f9585cf
commit e8726e47df
4 changed files with 57 additions and 8 deletions

View File

@ -8,6 +8,9 @@ rust_ffi_static {
defaults: ["vmbase_ffi_defaults"],
srcs: ["src/main.rs"],
edition: "2021",
features: [
"legacy",
],
rustlibs: [
"libbuddy_system_allocator",
"liblog_rust_nostd",

View File

@ -19,11 +19,15 @@ use crate::helpers;
use crate::mmio_guard;
use core::arch::asm;
use core::slice;
use log::{debug, error, LevelFilter};
use vmbase::{console, logger, main, power::reboot};
use log::debug;
use log::error;
use log::LevelFilter;
use vmbase::{console, layout, logger, main, power::reboot};
#[derive(Debug, Clone)]
enum RebootReason {
/// A malformed BCC was received.
InvalidBcc,
/// An unexpected internal error happened.
InternalError,
}
@ -80,8 +84,17 @@ fn main_wrapper(fdt: usize, payload: usize, payload_size: usize) -> Result<(), R
RebootReason::InternalError
})?;
// SAFETY - We only get the appended payload from here, once. It is mapped and the linker
// script prevents it from overlapping with other objects.
let bcc = as_bcc(unsafe { get_appended_data_slice() }).ok_or_else(|| {
error!("Invalid BCC");
RebootReason::InvalidBcc
})?;
// This wrapper allows main() to be blissfully ignorant of platform details.
crate::main(fdt, payload);
crate::main(fdt, payload, bcc);
// TODO: Overwrite BCC before jumping to payload to avoid leaking our sealing key.
mmio_guard::unmap(console::BASE_ADDRESS).map_err(|e| {
error!("Failed to unshare the UART: {e}");
@ -147,3 +160,22 @@ fn jump_to_payload(fdt_address: u64, payload_start: u64) -> ! {
);
};
}
unsafe fn get_appended_data_slice() -> &'static mut [u8] {
let base = helpers::align_up(layout::binary_end(), helpers::SIZE_4KB).unwrap();
// pvmfw is contained in a 2MiB region so the payload can't be larger than the 2MiB alignment.
let size = helpers::align_up(base, helpers::SIZE_2MB).unwrap() - base;
slice::from_raw_parts_mut(base as *mut u8, size)
}
fn as_bcc(data: &mut [u8]) -> Option<&mut [u8]> {
const BCC_SIZE: usize = helpers::SIZE_4KB;
if cfg!(feature = "legacy") {
// TODO(b/256148034): return None if BccHandoverParse(bcc) != kDiceResultOk.
Some(&mut data[..BCC_SIZE])
} else {
None
}
}

View File

@ -17,12 +17,25 @@
pub const SIZE_4KB: usize = 4 << 10;
pub const SIZE_2MB: usize = 2 << 20;
/// Computes the address of the page containing a given address.
pub const fn page_of(addr: usize, page_size: usize) -> usize {
addr & !(page_size - 1)
/// Computes the largest multiple of the provided alignment smaller or equal to the address.
///
/// Note: the result is undefined if alignment isn't a power of two.
pub const fn unchecked_align_down(addr: usize, alignment: usize) -> usize {
addr & !(alignment - 1)
}
/// Safe wrapper around unchecked_align_up() that validates its assumptions and doesn't wrap.
pub const fn align_up(addr: usize, alignment: usize) -> Option<usize> {
if !alignment.is_power_of_two() {
None
} else if let Some(s) = addr.checked_add(alignment - 1) {
Some(unchecked_align_down(s, alignment))
} else {
None
}
}
/// Computes the address of the 4KiB page containing a given address.
pub const fn page_4kb_of(addr: usize) -> usize {
page_of(addr, SIZE_4KB)
unchecked_align_down(addr, SIZE_4KB)
}

View File

@ -29,7 +29,7 @@ mod smccc;
use avb::PUBLIC_KEY;
use log::{debug, info};
fn main(fdt: &mut [u8], payload: &[u8]) {
fn main(fdt: &mut [u8], payload: &[u8], bcc: &[u8]) {
info!("pVM firmware");
debug!(
"fdt_address={:#018x}, payload_start={:#018x}, payload_size={:#018x}",
@ -37,6 +37,7 @@ fn main(fdt: &mut [u8], payload: &[u8]) {
payload.as_ptr() as usize,
payload.len(),
);
debug!("BCC: {:?} ({:#x} bytes)", bcc.as_ptr(), bcc.len());
debug!("AVB public key: addr={:?}, size={:#x} ({1})", PUBLIC_KEY.as_ptr(), PUBLIC_KEY.len());
info!("Starting payload...");
}