vmbase: Initialize logger before calling main()
By setting up the console (MMIO_GUARD_MAP-ing it if necessary) and
initializing the logger before entering main, we can centralize the
early error handling instead of expecting clients to deal with it,
provide a standard interface for configuring the log level (relying on
the log crate) which can't fail, and simplify client code.
This will enable vmbase itself to log errors in future changes.
Test: atest DebugPolicyHostTests#testNoAdbInDebugPolicy_withDebugLevelNone_boots
Test: atest rialto_test vmbase_example.integration_test
Change-Id: Id8c7256555d7940174c9f9375435d71851302020
diff --git a/pvmfw/src/entry.rs b/pvmfw/src/entry.rs
index 7727970..c81b57c 100644
--- a/pvmfw/src/entry.rs
+++ b/pvmfw/src/entry.rs
@@ -33,7 +33,7 @@
use vmbase::{
configure_heap, console,
layout::{self, crosvm},
- logger, main,
+ main,
memory::{min_dcache_line_size, MemoryTracker, MEMORY, SIZE_128KB, SIZE_4KB},
power::reboot,
rand,
@@ -192,23 +192,7 @@
// - only perform logging once the logger has been initialized
// - only access non-pvmfw memory once (and while) it has been mapped
- logger::init(LevelFilter::Info).map_err(|_| RebootReason::InternalError)?;
-
- // Use debug!() to avoid printing to the UART if we failed to configure it as only local
- // builds that have tweaked the logger::init() call will actually attempt to log the message.
-
- if let Some(mmio_guard) = get_mmio_guard() {
- mmio_guard.init().map_err(|e| {
- debug!("{e}");
- RebootReason::InternalError
- })?;
-
- mmio_guard.map(console::BASE_ADDRESS).map_err(|e| {
- debug!("Failed to configure the UART: {e}");
- RebootReason::InternalError
- })?;
- }
-
+ log::set_max_level(LevelFilter::Info);
crypto::init();
let page_table = memory::init_page_table().map_err(|e| {
diff --git a/rialto/src/error.rs b/rialto/src/error.rs
index 84228c4..c326566 100644
--- a/rialto/src/error.rs
+++ b/rialto/src/error.rs
@@ -29,8 +29,6 @@
Hypervisor(HypervisorError),
/// Failed when attempting to map some range in the page table.
PageTableMapping(MapError),
- /// Failed to initialize the logger.
- LoggerInit,
/// Invalid FDT.
InvalidFdt(FdtError),
/// Invalid PCI.
@@ -48,7 +46,6 @@
Self::PageTableMapping(e) => {
write!(f, "Failed when attempting to map some range in the page table: {e}.")
}
- Self::LoggerInit => write!(f, "Failed to initialize the logger."),
Self::InvalidFdt(e) => write!(f, "Invalid FDT: {e}"),
Self::InvalidPci(e) => write!(f, "Invalid PCI: {e}"),
Self::MemoryOperationFailed(e) => write!(f, "Failed memory operation: {e}"),
diff --git a/rialto/src/main.rs b/rialto/src/main.rs
index f61c415..3e0485d 100644
--- a/rialto/src/main.rs
+++ b/rialto/src/main.rs
@@ -51,16 +51,6 @@
Ok(page_table)
}
-fn try_init_logger() -> Result<()> {
- if let Some(mmio_guard) = get_mmio_guard() {
- mmio_guard.init()?;
- // pKVM blocks MMIO by default, we need to enable MMIO guard to support logging.
- mmio_guard.map(vmbase::console::BASE_ADDRESS)?;
- }
- vmbase::logger::init(log::LevelFilter::Debug).map_err(|_| Error::LoggerInit)?;
- Ok(())
-}
-
/// # Safety
///
/// Behavior is undefined if any of the following conditions are violated:
@@ -143,10 +133,7 @@
/// Entry point for Rialto.
pub fn main(fdt_addr: u64, _a1: u64, _a2: u64, _a3: u64) {
- if try_init_logger().is_err() {
- // Don't log anything if the logger initialization fails.
- reboot();
- };
+ log::set_max_level(log::LevelFilter::Debug);
// SAFETY: `fdt_addr` is supposed to be a valid pointer and points to
// a valid `Fdt`.
match unsafe { try_main(fdt_addr as usize) } {
diff --git a/vmbase/example/src/main.rs b/vmbase/example/src/main.rs
index 4176626..849302d 100644
--- a/vmbase/example/src/main.rs
+++ b/vmbase/example/src/main.rs
@@ -69,7 +69,7 @@
/// Entry point for VM bootloader.
pub fn main(arg0: u64, arg1: u64, arg2: u64, arg3: u64) {
- logger::init(LevelFilter::Debug).unwrap();
+ log::set_max_level(LevelFilter::Debug);
info!("Hello world");
info!("x0={:#018x}, x1={:#018x}, x2={:#018x}, x3={:#018x}", arg0, arg1, arg2, arg3);
diff --git a/vmbase/src/entry.rs b/vmbase/src/entry.rs
index 0a96d86..3e826a2 100644
--- a/vmbase/src/entry.rs
+++ b/vmbase/src/entry.rs
@@ -14,14 +14,37 @@
//! Rust entry point.
-use crate::{console, heap, power::shutdown};
+use crate::{
+ console, heap, logger,
+ power::{reboot, shutdown},
+};
+use hyp::{self, get_mmio_guard};
+
+fn try_console_init() -> Result<(), hyp::Error> {
+ console::init();
+
+ if let Some(mmio_guard) = get_mmio_guard() {
+ mmio_guard.init()?;
+ mmio_guard.map(console::BASE_ADDRESS)?;
+ }
+
+ Ok(())
+}
/// This is the entry point to the Rust code, called from the binary entry point in `entry.S`.
#[no_mangle]
extern "C" fn rust_entry(x0: u64, x1: u64, x2: u64, x3: u64) -> ! {
// SAFETY: Only called once, from here, and inaccessible to client code.
unsafe { heap::init() };
- console::init();
+
+ if try_console_init().is_err() {
+ // Don't panic (or log) here to avoid accessing the console.
+ reboot()
+ }
+
+ logger::init().expect("Failed to initialize the logger");
+ // We initialize the logger to Off (like the log crate) and clients should log::set_max_level.
+
// SAFETY: `main` is provided by the application using the `main!` macro, and we make sure it
// has the right type.
unsafe {
@@ -37,16 +60,21 @@
/// Marks the main function of the binary.
///
+/// Once main is entered, it can assume that:
+/// - The panic_handler has been configured and panic!() and friends are available;
+/// - The global_allocator has been configured and heap memory is available;
+/// - The logger has been configured and the log::{info, warn, error, ...} macros are available.
+///
/// Example:
///
/// ```rust
-/// use vmbase::{logger, main};
+/// use vmbase::main;
/// use log::{info, LevelFilter};
///
/// main!(my_main);
///
/// fn my_main() {
-/// logger::init(LevelFilter::Info).unwrap();
+/// log::set_max_level(LevelFilter::Info);
/// info!("Hello world");
/// }
/// ```
diff --git a/vmbase/src/logger.rs b/vmbase/src/logger.rs
index 226d905..9130918 100644
--- a/vmbase/src/logger.rs
+++ b/vmbase/src/logger.rs
@@ -20,7 +20,7 @@
use crate::console::println;
use core::sync::atomic::{AtomicBool, Ordering};
-use log::{LevelFilter, Log, Metadata, Record, SetLoggerError};
+use log::{Log, Metadata, Record, SetLoggerError};
struct Logger {
is_enabled: AtomicBool,
@@ -70,9 +70,8 @@
}
/// Initialize vmbase logger with a given max logging level.
-pub fn init(max_level: LevelFilter) -> Result<(), SetLoggerError> {
+pub(crate) fn init() -> Result<(), SetLoggerError> {
log::set_logger(&LOGGER)?;
- log::set_max_level(max_level);
Ok(())
}