From 1b7d5b8fba5b3607e4d6e88b6f91eef83f77d609 Mon Sep 17 00:00:00 2001 From: Daniel Verkamp Date: Thu, 23 Jun 2022 17:50:13 -0700 Subject: [PATCH] arch: provide one vcpu_init per vcpu Rather than having a single vcpu_init instance that is used for all VCPUs, make vcpu_init into a Vec so it can store different initial state for each VCPU. This allows us to set up e.g. bootstrap processor state differently than other processors, and it also means that the VcpuInit struct doesn't need to be Copy. BUG=b:237095693 TEST=Boot Linux with >1 CPU Change-Id: I0ebfdc2dbd84d0817e3f75c2c852e4320b9e77c5 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3723798 Reviewed-by: Alexandre Courbot Commit-Queue: Daniel Verkamp Tested-by: kokoro --- aarch64/src/lib.rs | 6 ++++-- arch/src/lib.rs | 5 +++-- hypervisor/src/aarch64.rs | 2 +- hypervisor/src/x86_64.rs | 2 +- src/crosvm/linux/mod.rs | 8 ++++++-- src/crosvm/linux/vcpu.rs | 4 ++-- x86_64/src/lib.rs | 12 ++++++------ 7 files changed, 23 insertions(+), 16 deletions(-) diff --git a/aarch64/src/lib.rs b/aarch64/src/lib.rs index 9a3f075f39..ba0d8ff575 100644 --- a/aarch64/src/lib.rs +++ b/aarch64/src/lib.rs @@ -525,11 +525,13 @@ impl arch::LinuxArch for AArch64 { ) .map_err(Error::CreateFdt)?; + let vcpu_init = vec![VcpuInitAArch64::default(); vcpu_count]; + Ok(RunnableLinuxVm { vm, vcpu_count, vcpus: Some(vcpus), - vcpu_init: VcpuInitAArch64 {}, + vcpu_init, vcpu_affinity: components.vcpu_affinity, no_smt: components.no_smt, irq_chip: irq_chip.try_box_clone().map_err(Error::CloneIrqChip)?, @@ -553,7 +555,7 @@ impl arch::LinuxArch for AArch64 { _hypervisor: &dyn Hypervisor, _irq_chip: &mut dyn IrqChipAArch64, _vcpu: &mut dyn VcpuAArch64, - _vcpu_init: &VcpuInitAArch64, + _vcpu_init: VcpuInitAArch64, _vcpu_id: usize, _num_cpus: usize, _has_bios: bool, diff --git a/arch/src/lib.rs b/arch/src/lib.rs index 0c985e367e..75a0e27a46 100644 --- a/arch/src/lib.rs +++ b/arch/src/lib.rs @@ -148,7 +148,8 @@ pub struct RunnableLinuxVm { pub suspend_evt: Event, pub vcpu_affinity: Option, pub vcpu_count: usize, - pub vcpu_init: VcpuInitArch, + /// Per-VCPU initialization data, indexed by vcpu_id. + pub vcpu_init: Vec, /// If vcpus is None, then it's the responsibility of the vcpu thread to create vcpus. /// If it's Some, then `build_vm` already created the vcpus. pub vcpus: Option>, @@ -244,7 +245,7 @@ pub trait LinuxArch { hypervisor: &dyn HypervisorArch, irq_chip: &mut dyn IrqChipArch, vcpu: &mut dyn VcpuArch, - vcpu_init: &VcpuInitArch, + vcpu_init: VcpuInitArch, vcpu_id: usize, num_cpus: usize, has_bios: bool, diff --git a/hypervisor/src/aarch64.rs b/hypervisor/src/aarch64.rs index 95ae7ec9ce..edbcfdb68f 100644 --- a/hypervisor/src/aarch64.rs +++ b/hypervisor/src/aarch64.rs @@ -122,7 +122,7 @@ pub trait VcpuAArch64: Vcpu { impl_downcast!(VcpuAArch64); /// Initial state for AArch64 VCPUs. -#[derive(Copy, Clone)] +#[derive(Clone, Default)] pub struct VcpuInitAArch64 {} // Convenience constructors for IrqRoutes diff --git a/hypervisor/src/x86_64.rs b/hypervisor/src/x86_64.rs index c8b4c15669..7e42536a90 100644 --- a/hypervisor/src/x86_64.rs +++ b/hypervisor/src/x86_64.rs @@ -172,7 +172,7 @@ pub(crate) fn host_phys_addr_bits() -> u8 { } /// Initial state for x86_64 VCPUs. -#[derive(Copy, Clone, Default)] +#[derive(Clone, Default)] pub struct VcpuInitX86_64 { /// General-purpose registers. pub regs: Regs, diff --git a/src/crosvm/linux/mod.rs b/src/crosvm/linux/mod.rs index 5e31ca82cc..ec396bc0f7 100644 --- a/src/crosvm/linux/mod.rs +++ b/src/crosvm/linux/mod.rs @@ -1952,7 +1952,11 @@ fn run_control( let guest_suspended_cvar = Arc::new((Mutex::new(false), Condvar::new())); - for (cpu_id, vcpu) in vcpus.into_iter().enumerate() { + // Architecture-specific code must supply a vcpu_init element for each VCPU. + assert_eq!(vcpus.len(), linux.vcpu_init.len()); + + for ((cpu_id, vcpu), vcpu_init) in vcpus.into_iter().enumerate().zip(linux.vcpu_init.drain(..)) + { let (to_vcpu_channel, from_main_channel) = mpsc::channel(); let vcpu_affinity = match linux.vcpu_affinity.clone() { Some(VcpuAffinity::Global(v)) => v, @@ -1963,7 +1967,7 @@ fn run_control( cpu_id, vcpu_ids[cpu_id], vcpu, - linux.vcpu_init, + vcpu_init, linux.vm.try_clone().context("failed to clone vm")?, linux .irq_chip diff --git a/src/crosvm/linux/vcpu.rs b/src/crosvm/linux/vcpu.rs index 08a8115e3b..cd74d04ff2 100644 --- a/src/crosvm/linux/vcpu.rs +++ b/src/crosvm/linux/vcpu.rs @@ -133,7 +133,7 @@ pub fn runnable_vcpu( cpu_id: usize, vcpu_id: usize, vcpu: Option, - vcpu_init: &VcpuInitArch, + vcpu_init: VcpuInitArch, vm: impl VmArch, irq_chip: &mut dyn IrqChipArch, vcpu_count: usize, @@ -609,7 +609,7 @@ where cpu_id, vcpu_id, vcpu, - &vcpu_init, + vcpu_init, vm, irq_chip.as_mut(), vcpu_count, diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs index 73370847ad..e462185813 100644 --- a/x86_64/src/lib.rs +++ b/x86_64/src/lib.rs @@ -698,7 +698,7 @@ impl arch::LinuxArch for X8664arch { .map_err(Error::Cmdline)?; } - let mut vcpu_init = VcpuInitX86_64::default(); + let mut vcpu_init = vec![VcpuInitX86_64::default(); vcpu_count]; match components.vm_image { VmImage::Bios(ref mut bios) => { @@ -724,11 +724,11 @@ impl arch::LinuxArch for X8664arch { params, )?; - // Configure the VCPU for the Linux/x86 64-bit boot protocol. + // Configure the bootstrap VCPU for the Linux/x86 64-bit boot protocol. // - vcpu_init.regs.rip = kernel_entry.offset(); - vcpu_init.regs.rsp = BOOT_STACK_POINTER; - vcpu_init.regs.rsi = ZERO_PAGE_OFFSET; + vcpu_init[0].regs.rip = kernel_entry.offset(); + vcpu_init[0].regs.rsp = BOOT_STACK_POINTER; + vcpu_init[0].regs.rsi = ZERO_PAGE_OFFSET; } } @@ -762,7 +762,7 @@ impl arch::LinuxArch for X8664arch { hypervisor: &dyn HypervisorX86_64, irq_chip: &mut dyn IrqChipX86_64, vcpu: &mut dyn VcpuX86_64, - vcpu_init: &VcpuInitX86_64, + vcpu_init: VcpuInitX86_64, vcpu_id: usize, num_cpus: usize, has_bios: bool,