hv:fix rtvm hang with maxcpus=0/1 in bootargs

RTVM (with lapic PT) boots hang when maxcpus is
 assigned a value less than the CPU number configured
 in hypervisor.

 In this case, vlapic_state(per VM) is left in TRANSITION
 state after BSP boot, which blocks interupts to be injected
 to this UOS.

Tracked-On: #4803
Signed-off-by: Yonghua Huang <yonghua.huang@intel.com>
Reviewed-by: Li, Fei <fei1.li@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Yonghua Huang 2020-05-11 15:16:30 +08:00 committed by wenlingz
parent 4d3221a7f3
commit 3391bffb27
4 changed files with 43 additions and 17 deletions

View File

@ -513,7 +513,7 @@ int32_t create_vcpu(uint16_t pcpu_id, struct acrn_vm *vm, struct acrn_vcpu **rtn
/* Populate the return handle */ /* Populate the return handle */
*rtn_vcpu_handle = vcpu; *rtn_vcpu_handle = vcpu;
vcpu->state = VCPU_INIT; vcpu_set_state(vcpu, VCPU_INIT);
init_xsave(vcpu); init_xsave(vcpu);
vcpu_reset_internal(vcpu, POWER_ON_RESET); vcpu_reset_internal(vcpu, POWER_ON_RESET);
@ -670,7 +670,7 @@ void offline_vcpu(struct acrn_vcpu *vcpu)
/* This operation must be atomic to avoid contention with posted interrupt handler */ /* This operation must be atomic to avoid contention with posted interrupt handler */
per_cpu(vcpu_array, pcpuid_from_vcpu(vcpu))[vcpu->vm->vm_id] = NULL; per_cpu(vcpu_array, pcpuid_from_vcpu(vcpu))[vcpu->vm->vm_id] = NULL;
vcpu->state = VCPU_OFFLINE; vcpu_set_state(vcpu, VCPU_OFFLINE);
} }
void kick_vcpu(const struct acrn_vcpu *vcpu) void kick_vcpu(const struct acrn_vcpu *vcpu)
@ -716,7 +716,7 @@ void reset_vcpu(struct acrn_vcpu *vcpu, enum reset_mode mode)
pr_dbg("vcpu%hu reset", vcpu->vcpu_id); pr_dbg("vcpu%hu reset", vcpu->vcpu_id);
vcpu_reset_internal(vcpu, mode); vcpu_reset_internal(vcpu, mode);
vcpu->state = VCPU_INIT; vcpu_set_state(vcpu, VCPU_INIT);
} }
void pause_vcpu(struct acrn_vcpu *vcpu, enum vcpu_state new_state) void pause_vcpu(struct acrn_vcpu *vcpu, enum vcpu_state new_state)
@ -727,7 +727,7 @@ void pause_vcpu(struct acrn_vcpu *vcpu, enum vcpu_state new_state)
if (((vcpu->state == VCPU_RUNNING) || (vcpu->state == VCPU_INIT)) && (new_state == VCPU_ZOMBIE)) { if (((vcpu->state == VCPU_RUNNING) || (vcpu->state == VCPU_INIT)) && (new_state == VCPU_ZOMBIE)) {
vcpu->prev_state = vcpu->state; vcpu->prev_state = vcpu->state;
vcpu->state = new_state; vcpu_set_state(vcpu, new_state);
if (vcpu->prev_state == VCPU_RUNNING) { if (vcpu->prev_state == VCPU_RUNNING) {
sleep_thread(&vcpu->thread_obj); sleep_thread(&vcpu->thread_obj);
@ -747,7 +747,7 @@ int32_t resume_vcpu(struct acrn_vcpu *vcpu)
pr_dbg("vcpu%hu resumed", vcpu->vcpu_id); pr_dbg("vcpu%hu resumed", vcpu->vcpu_id);
if (vcpu->state == VCPU_PAUSED) { if (vcpu->state == VCPU_PAUSED) {
vcpu->state = vcpu->prev_state; vcpu_set_state(vcpu, vcpu->prev_state);
if (vcpu->state == VCPU_RUNNING) { if (vcpu->state == VCPU_RUNNING) {
wake_thread(&vcpu->thread_obj); wake_thread(&vcpu->thread_obj);
} }
@ -818,7 +818,7 @@ void launch_vcpu(struct acrn_vcpu *vcpu)
uint16_t pcpu_id = pcpuid_from_vcpu(vcpu); uint16_t pcpu_id = pcpuid_from_vcpu(vcpu);
pr_dbg("vcpu%hu scheduled on pcpu%hu", vcpu->vcpu_id, pcpu_id); pr_dbg("vcpu%hu scheduled on pcpu%hu", vcpu->vcpu_id, pcpu_id);
vcpu->state = VCPU_RUNNING; vcpu_set_state(vcpu, VCPU_RUNNING);
wake_thread(&vcpu->thread_obj); wake_thread(&vcpu->thread_obj);
} }
@ -922,3 +922,17 @@ void vcpu_handle_pi_notification(uint32_t vcpu_index)
} }
} }
} }
/*
* @brief Update the state of vCPU and state of vlapic
*
* The vlapic state of VM shall be updated for some vCPU
* state update cases, such as from VCPU_INIT to VCPU_RUNNING.
* @pre (vcpu != NULL)
*/
void vcpu_set_state(struct acrn_vcpu *vcpu, enum vcpu_state new_state)
{
vcpu->state = new_state;
update_vm_vlapic_state(vcpu->vm);
}

View File

@ -1135,6 +1135,7 @@ vlapic_process_init_sipi(struct acrn_vcpu* target_vcpu, uint32_t mode, uint32_t
pr_err("Start Secondary VCPU%hu for VM[%d]...", pr_err("Start Secondary VCPU%hu for VM[%d]...",
target_vcpu->vcpu_id, target_vcpu->vcpu_id,
target_vcpu->vm->vm_id); target_vcpu->vm->vm_id);
set_vcpu_startup_entry(target_vcpu, (icr_low & APIC_VECTOR_MASK) << 12U); set_vcpu_startup_entry(target_vcpu, (icr_low & APIC_VECTOR_MASK) << 12U);
vcpu_make_request(target_vcpu, ACRN_REQUEST_INIT_VMCS); vcpu_make_request(target_vcpu, ACRN_REQUEST_INIT_VMCS);
launch_vcpu(target_vcpu); launch_vcpu(target_vcpu);

View File

@ -801,9 +801,6 @@ void launch_vms(uint16_t pcpu_id)
* VM_VLAPIC_DISABLED - All the online vCPUs/vLAPICs of this VM are in Disabled mode * VM_VLAPIC_DISABLED - All the online vCPUs/vLAPICs of this VM are in Disabled mode
* VM_VLAPIC_TRANSITION - Online vCPUs/vLAPICs of this VM are in between transistion * VM_VLAPIC_TRANSITION - Online vCPUs/vLAPICs of this VM are in between transistion
* *
* TODO: offline_vcpu need to call this API to reflect the status of rest of the
* vLAPICs that are online.
*
* @pre vm != NULL * @pre vm != NULL
*/ */
void update_vm_vlapic_state(struct acrn_vm *vm) void update_vm_vlapic_state(struct acrn_vm *vm)
@ -817,14 +814,17 @@ void update_vm_vlapic_state(struct acrn_vm *vm)
vcpus_in_xapic = 0U; vcpus_in_xapic = 0U;
spinlock_obtain(&vm->vm_lock); spinlock_obtain(&vm->vm_lock);
foreach_vcpu(i, vm, vcpu) { foreach_vcpu(i, vm, vcpu) {
if (is_x2apic_enabled(vcpu_vlapic(vcpu))) { /* Skip vCPU in state outside of VCPU_RUNNING as it may be offline. */
vcpus_in_x2apic++; if (vcpu->state == VCPU_RUNNING) {
} else if (is_xapic_enabled(vcpu_vlapic(vcpu))) { if (is_x2apic_enabled(vcpu_vlapic(vcpu))) {
vcpus_in_xapic++; vcpus_in_x2apic++;
} else { } else if (is_xapic_enabled(vcpu_vlapic(vcpu))) {
/* vcpus_in_xapic++;
* vCPU is using vLAPIC in Disabled mode } else {
*/ /*
* vCPU is using vLAPIC in Disabled mode
*/
}
} }
} }

View File

@ -715,6 +715,17 @@ bool is_lapic_pt_enabled(struct acrn_vcpu *vcpu);
* @return None * @return None
*/ */
void vcpu_handle_pi_notification(uint32_t vcpu_index); void vcpu_handle_pi_notification(uint32_t vcpu_index);
/*
* @brief Update the state of vCPU and state of vlapic
*
* The vlapic state of VM shall be updated for some vCPU
* state update cases, such as from VCPU_INIT to VCPU_RUNNING.
* @pre (vcpu != NULL)
*/
void vcpu_set_state(struct acrn_vcpu *vcpu, enum vcpu_state new_state);
/** /**
* @} * @}
*/ */