Add --enable-earlycon option to vm tool
This should make it easier to debug issues that occur before
virtio_console is available.
The code is guarded by the new RELEASE_AVF_IMPROVE_DEBUGGABLE_VMS
trunk-stable flag. This patch also guards the corresponding change in
pvmfw with the same flag just for the sake of consistency.
This is effectively a relanding of
ec68eaf6e8ba07cf400cdc33501cdd1a85dfe665 with a minor fix to avoid build
breakage.
Test: vm run-microdroid --protected --enable-earlycon --debug full
Test: vm run-microdroid --protected --enable-earlycon --debug none
Test: atest MicrodroidTests
Change-Id: Ic01b35a633456d2fc202374c10da1e22a83ee23d
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index 7a357f3..5355c19 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -989,6 +989,10 @@
vm_config.devices.clone_from(&custom_config.devices);
vm_config.networkSupported = custom_config.networkSupported;
+
+ for param in custom_config.extraKernelCmdlineParams.iter() {
+ append_kernel_param(param, &mut vm_config);
+ }
}
if config.memoryMib > 0 {
@@ -1541,6 +1545,17 @@
Ok(())
}
+fn check_no_extra_kernel_cmdline_params(config: &VirtualMachineConfig) -> binder::Result<()> {
+ let VirtualMachineConfig::AppConfig(config) = config else { return Ok(()) };
+ if let Some(custom_config) = &config.customConfig {
+ if !custom_config.extraKernelCmdlineParams.is_empty() {
+ return Err(anyhow!("debuggable_vms_improvements feature is disabled"))
+ .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION);
+ }
+ }
+ Ok(())
+}
+
fn check_protected_vm_is_supported() -> binder::Result<()> {
let is_pvm_supported =
hypervisor_props::is_protected_vm_supported().or_service_specific_exception(-1)?;
@@ -1562,6 +1577,9 @@
if !cfg!(multi_tenant) {
check_no_extra_apks(config)?;
}
+ if !cfg!(debuggable_vms_improvements) {
+ check_no_extra_kernel_cmdline_params(config)?;
+ }
Ok(())
}
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
index ee39d75..9123742 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
@@ -127,6 +127,9 @@
/** Whether the VM should have network feature. */
boolean networkSupported;
+
+ /** Additional parameters to pass to the VM's kernel cmdline. */
+ String[] extraKernelCmdlineParams;
}
/** Configuration parameters guarded by android.permission.USE_CUSTOM_VIRTUAL_MACHINE */
diff --git a/android/vm/src/main.rs b/android/vm/src/main.rs
index 3c0887c..6eee201 100644
--- a/android/vm/src/main.rs
+++ b/android/vm/src/main.rs
@@ -109,6 +109,23 @@
/// Note: this is only supported on Android kernels android14-5.15 and higher.
#[arg(long)]
gdb: Option<NonZeroU16>,
+
+ /// Whether to enable earlycon. Only supported for debuggable Linux-based VMs.
+ #[cfg(debuggable_vms_improvements)]
+ #[arg(long)]
+ enable_earlycon: bool,
+}
+
+impl DebugConfig {
+ #[cfg(debuggable_vms_improvements)]
+ fn enable_earlycon(&self) -> bool {
+ self.enable_earlycon
+ }
+
+ #[cfg(not(debuggable_vms_improvements))]
+ fn enable_earlycon(&self) -> bool {
+ false
+ }
}
#[derive(Args, Default)]
diff --git a/android/vm/src/run.rs b/android/vm/src/run.rs
index b3743ae..823546f 100644
--- a/android/vm/src/run.rs
+++ b/android/vm/src/run.rs
@@ -148,7 +148,7 @@
let payload_config_str = format!("{:?}!{:?}", config.apk, payload);
- let custom_config = CustomConfig {
+ let mut custom_config = CustomConfig {
gdbPort: config.debug.gdb.map(u16::from).unwrap_or(0) as i32, // 0 means no gdb
vendorImage: vendor,
devices: config
@@ -163,6 +163,21 @@
..Default::default()
};
+ if config.debug.enable_earlycon() {
+ if config.debug.debug != DebugLevel::FULL {
+ bail!("earlycon is only supported for debuggable VMs")
+ }
+ if cfg!(target_arch = "aarch64") {
+ custom_config
+ .extraKernelCmdlineParams
+ .push(String::from("earlycon=uart8250,mmio,0x3f8"));
+ } else if cfg!(target_arch = "x86_64") {
+ custom_config.extraKernelCmdlineParams.push(String::from("earlycon=uart8250,io,0x3f8"));
+ } else {
+ bail!("unexpected architecture!");
+ }
+ }
+
let vm_config = VirtualMachineConfig::AppConfig(VirtualMachineAppConfig {
name: config.common.name.unwrap_or_else(|| String::from("VmRunApp")),
apk: apk_fd.into(),
diff --git a/build/Android.bp b/build/Android.bp
index 66cc626..6ab1d89 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -44,6 +44,9 @@
}) + select(release_flag("RELEASE_AVF_ENABLE_VIRT_CPUFREQ"), {
true: ["virt_cpufreq"],
default: [],
+ }) + select(release_flag("RELEASE_AVF_IMPROVE_DEBUGGABLE_VMS"), {
+ true: ["debuggable_vms_improvements"],
+ default: [],
}) + select(release_flag("RELEASE_AVF_SUPPORT_CUSTOM_VM_WITH_PARAVIRTUALIZED_DEVICES"), {
true: ["paravirtualized_devices"],
default: [],
diff --git a/guest/pvmfw/src/entry.rs b/guest/pvmfw/src/entry.rs
index ce04317..8f9340b 100644
--- a/guest/pvmfw/src/entry.rs
+++ b/guest/pvmfw/src/entry.rs
@@ -276,8 +276,9 @@
MEMORY.lock().as_mut().unwrap().unshare_all_memory();
if let Some(mmio_guard) = get_mmio_guard() {
- // Keep UART MMIO_GUARD-ed for debuggable payloads, to enable earlycon.
- if !debuggable_payload {
+ if cfg!(debuggable_vms_improvements) && debuggable_payload {
+ // Keep UART MMIO_GUARD-ed for debuggable payloads, to enable earlycon.
+ } else {
mmio_guard.unmap(UART_PAGE_ADDR).map_err(|e| {
error!("Failed to unshare the UART: {e}");
RebootReason::InternalError
diff --git a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
index 7ae4a55..a1230df 100644
--- a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -777,6 +777,7 @@
VirtualMachineAppConfig.CustomConfig customConfig =
new VirtualMachineAppConfig.CustomConfig();
customConfig.devices = EMPTY_STRING_ARRAY;
+ customConfig.extraKernelCmdlineParams = EMPTY_STRING_ARRAY;
try {
customConfig.vendorImage =
ParcelFileDescriptor.open(mVendorDiskImage, MODE_READ_ONLY);