Skip to content

Commit 0571c6e

Browse files
committed
vmm: move logic for creating vcpus
On aarch64 KVM_CREATE_VCPU needs to be called before setting up the IRQCHIP, while on x86 it needs to be called after setting up the IRQCHIP. Consequently the configuration of the vcpus was moved to a different function. Also, architecture specific labeling was added. Signed-off-by: Diana Popa <[email protected]>
1 parent 08576d1 commit 0571c6e

File tree

3 files changed

+74
-8
lines changed

3 files changed

+74
-8
lines changed

api_server/src/request/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,14 @@ mod tests {
320320
let vmm_resp =
321321
VmmActionError::StartMicrovm(ErrorKind::Internal, StartMicrovmError::RegisterEvent);
322322
check_error_response(vmm_resp, StatusCode::InternalServerError);
323+
let vmm_resp = VmmActionError::StartMicrovm(
324+
ErrorKind::Internal,
325+
StartMicrovmError::VcpusNotConfigured,
326+
);
327+
check_error_response(vmm_resp, StatusCode::InternalServerError);
328+
let vmm_resp =
329+
VmmActionError::StartMicrovm(ErrorKind::Internal, StartMicrovmError::VcpusNotCreated);
330+
check_error_response(vmm_resp, StatusCode::InternalServerError);
323331
let vmm_resp = VmmActionError::StartMicrovm(
324332
ErrorKind::Internal,
325333
StartMicrovmError::VcpuSpawn(std::io::Error::from_raw_os_error(11)),

vmm/src/lib.rs

+63-8
Original file line numberDiff line numberDiff line change
@@ -980,15 +980,41 @@ impl Vmm {
980980
Ok(())
981981
}
982982

983-
fn start_vcpus(
983+
// On aarch64, the vCPUs need to be created (i.e call KVM_CREATE_VCPU)_and configured before
984+
// setting up the IRQ chip because the `KVM_CREATE_VCPU` ioctl will return error if the IRQCHIP
985+
// was already initialized.
986+
// Search for `kvm_arch_vcpu_create` in arch/arm/kvm/arm.c.
987+
fn create_vcpus(
984988
&mut self,
985989
entry_addr: GuestAddress,
986-
) -> std::result::Result<(), StartMicrovmError> {
990+
) -> std::result::Result<Vec<Vcpu>, StartMicrovmError> {
991+
let vcpu_count = self
992+
.vm_config
993+
.vcpu_count
994+
.ok_or(StartMicrovmError::VcpusNotConfigured)?;
995+
let mut vcpus = Vec::with_capacity(vcpu_count as usize);
996+
for cpu_id in 0..vcpu_count {
997+
let mut vcpu = Vcpu::new(cpu_id, &self.vm).map_err(StartMicrovmError::Vcpu)?;
998+
#[cfg(target_arch = "x86_64")]
999+
vcpu.configure(&self.vm_config, entry_addr, &self.vm)
1000+
.map_err(StartMicrovmError::VcpuConfigure)?;
1001+
vcpus.push(vcpu);
1002+
}
1003+
Ok(vcpus)
1004+
}
1005+
1006+
fn start_vcpus(&mut self, mut vcpus: Vec<Vcpu>) -> std::result::Result<(), StartMicrovmError> {
9871007
// vm_config has a default value for vcpu_count.
9881008
let vcpu_count = self
9891009
.vm_config
9901010
.vcpu_count
9911011
.ok_or(StartMicrovmError::VcpusNotConfigured)?;
1012+
assert_eq!(
1013+
vcpus.len(),
1014+
vcpu_count as usize,
1015+
"The number of vCPU fds is corrupted!"
1016+
);
1017+
9921018
self.vcpu_handles = Some(Vec::with_capacity(vcpu_count as usize));
9931019
// It is safe to unwrap since it's set just above.
9941020
let vcpu_handles = self.vcpu_handles.as_mut().unwrap();
@@ -1014,15 +1040,14 @@ impl Vmm {
10141040
.get_reset_evt_clone()
10151041
.map_err(|_| StartMicrovmError::EventFd)?;
10161042

1017-
let mut vcpu = Vcpu::new(cpu_id, &self.vm).map_err(StartMicrovmError::Vcpu)?;
1043+
// `unwrap` is safe since we are asserting that the `vcpu_count` is equal to the number
1044+
// of items of `vcpus` vector.
1045+
let vcpu = vcpus.pop().unwrap();
1046+
10181047
let seccomp_level = self.seccomp_level;
10191048
// It is safe to unwrap the ht_enabled flag because the machine configure
10201049
// has default values for all fields.
10211050

1022-
#[cfg(target_arch = "x86_64")]
1023-
vcpu.configure(&self.vm_config, entry_addr, &self.vm)
1024-
.map_err(StartMicrovmError::VcpuConfigure)?;
1025-
10261051
vcpu_handles.push(
10271052
thread::Builder::new()
10281053
.name(format!("fc_vcpu{}", cpu_id))
@@ -1256,9 +1281,13 @@ impl Vmm {
12561281

12571282
self.register_events()
12581283
.map_err(|e| VmmActionError::StartMicrovm(ErrorKind::Internal, e))?;
1259-
self.start_vcpus(entry_addr)
1284+
1285+
let vcpus = self
1286+
.create_vcpus(entry_addr)
12601287
.map_err(|e| VmmActionError::StartMicrovm(ErrorKind::Internal, e))?;
12611288

1289+
self.start_vcpus(vcpus)
1290+
.map_err(|e| VmmActionError::StartMicrovm(ErrorKind::Internal, e))?;
12621291
// Use expect() to crash if the other thread poisoned this lock.
12631292
self.shared_info
12641293
.write()
@@ -2988,4 +3017,30 @@ mod tests {
29883017
assert_eq!(vmm.get_dirty_page_count(), 0);
29893018
// Booting an actual guest and getting real data is covered by `kvm::tests::run_code_test`.
29903019
}
3020+
3021+
#[cfg(target_arch = "x86_64")]
3022+
#[test]
3023+
fn test_create_vcpus() {
3024+
let mut vmm = create_vmm_object(InstanceState::Uninitialized);
3025+
vmm.default_kernel_config();
3026+
3027+
assert!(vmm.init_guest_memory().is_ok());
3028+
assert!(vmm.guest_memory.is_some());
3029+
let kvm = KvmContext::new().unwrap();
3030+
let guest_mem = vmm.guest_memory.clone().unwrap();
3031+
3032+
vmm.vm
3033+
.memory_init(guest_mem.clone(), &kvm)
3034+
.expect("Cannot initialize memory for test vm");
3035+
assert!(vmm.vm.get_memory().is_some());
3036+
// `KVM_CREATE_VCPU` fails if the irqchip is not created beforehand. This is x86_64 speciifc.
3037+
vmm.vm
3038+
.setup_irqchip(
3039+
&vmm.legacy_device_manager.com_evt_1_3,
3040+
&vmm.legacy_device_manager.com_evt_2_4,
3041+
&vmm.legacy_device_manager.kbd_evt,
3042+
)
3043+
.expect("Cannot create IRQCHIP");
3044+
assert!(vmm.create_vcpus(GuestAddress(0x0)).is_ok());
3045+
}
29913046
}

vmm/src/vmm_config/instance_info.rs

+3
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ pub enum StartMicrovmError {
101101
VcpuConfigure(vstate::Error),
102102
/// vCPUs were not configured.
103103
VcpusNotConfigured,
104+
/// vCPUs were not created prior to starting them.
105+
VcpusNotCreated,
104106
/// Cannot spawn a new vCPU thread.
105107
VcpuSpawn(std::io::Error),
106108
}
@@ -234,6 +236,7 @@ impl Display for StartMicrovmError {
234236
write!(f, "vCPU configuration failed. {}", err_msg)
235237
}
236238
VcpusNotConfigured => write!(f, "vCPUs were not configured."),
239+
VcpusNotCreated => write!(f, "vCPUs were not created yet."),
237240
VcpuSpawn(ref err) => {
238241
let mut err_msg = format!("{:?}", err);
239242
err_msg = err_msg.replace("\"", "");

0 commit comments

Comments
 (0)