diff --git a/hypervisor/arch/x86/guest/vcpu.c b/hypervisor/arch/x86/guest/vcpu.c index ea6d0f49a..071e201d1 100644 --- a/hypervisor/arch/x86/guest/vcpu.c +++ b/hypervisor/arch/x86/guest/vcpu.c @@ -193,6 +193,35 @@ void vcpu_reset_eoi_exit_bitmaps(struct acrn_vcpu *vcpu) vcpu_make_request(vcpu, ACRN_REQUEST_EOI_EXIT_BITMAP_UPDATE); } +/* As a vcpu reset internal API, DO NOT touch any vcpu state transition in this function. */ +static void vcpu_reset_internal(struct acrn_vcpu *vcpu, __unused enum reset_mode mode) +{ + int32_t i; + struct acrn_vlapic *vlapic; + + vcpu->launched = false; + vcpu->running = false; + vcpu->arch.nr_sipi = 0U; + + vcpu->arch.exception_info.exception = VECTOR_INVALID; + vcpu->arch.cur_context = NORMAL_WORLD; + vcpu->arch.irq_window_enabled = false; + (void)memset((void *)vcpu->arch.vmcs, 0U, PAGE_SIZE); + + for (i = 0; i < NR_WORLD; i++) { + (void)memset((void *)(&vcpu->arch.contexts[i]), 0U, + sizeof(struct run_context)); + } + + /* TODO: we may need to add one scheduler->reset_data to reset the thread_obj */ + vcpu->thread_obj.notify_mode = SCHED_NOTIFY_IPI; + + vlapic = vcpu_vlapic(vcpu); + vlapic_reset(vlapic, apicv_ops); + + reset_vcpu_regs(vcpu); +} + struct acrn_vcpu *get_running_vcpu(uint16_t pcpu_id) { struct thread_object *curr = sched_get_current(pcpu_id); @@ -445,12 +474,6 @@ int32_t create_vcpu(uint16_t pcpu_id, struct acrn_vm *vm, struct acrn_vcpu **rtn */ vcpu->arch.vpid = 1U + (vm->vm_id * MAX_VCPUS_PER_VM) + vcpu->vcpu_id; - /* Initialize exception field in VCPU context */ - vcpu->arch.exception_info.exception = VECTOR_INVALID; - - /* Initialize cur context */ - vcpu->arch.cur_context = NORMAL_WORLD; - /* Create per vcpu vlapic */ vlapic_create(vcpu); @@ -460,14 +483,10 @@ int32_t create_vcpu(uint16_t pcpu_id, struct acrn_vm *vm, struct acrn_vcpu **rtn /* Populate the return handle */ *rtn_vcpu_handle = vcpu; - - vcpu->launched = false; - vcpu->running = false; - vcpu->arch.nr_sipi = 0U; vcpu->state = VCPU_INIT; init_xsave(vcpu); - reset_vcpu_regs(vcpu); + vcpu_reset_internal(vcpu, POWER_ON_RESET); (void)memset((void *)&vcpu->req, 0U, sizeof(struct io_request)); vm->hw.created_vcpus++; ret = 0; @@ -655,40 +674,15 @@ static uint64_t build_stack_frame(struct acrn_vcpu *vcpu) /* NOTE: * vcpu should be paused before call this function. */ -void reset_vcpu(struct acrn_vcpu *vcpu) +void reset_vcpu(struct acrn_vcpu *vcpu, enum reset_mode mode) { - int32_t i; - struct acrn_vlapic *vlapic; - pr_dbg("vcpu%hu reset", vcpu->vcpu_id); ASSERT(vcpu->state != VCPU_RUNNING, "reset vcpu when it's running"); if (vcpu->state != VCPU_INIT) { + vcpu_reset_internal(vcpu, mode); vcpu->state = VCPU_INIT; - - vcpu->launched = false; - vcpu->running = false; - vcpu->arch.nr_sipi = 0U; - - vcpu->arch.exception_info.exception = VECTOR_INVALID; - vcpu->arch.cur_context = NORMAL_WORLD; - vcpu->arch.irq_window_enabled = false; - (void)memset((void *)vcpu->arch.vmcs, 0U, PAGE_SIZE); - - for (i = 0; i < NR_WORLD; i++) { - (void)memset((void *)(&vcpu->arch.contexts[i]), 0U, - sizeof(struct run_context)); - } - vcpu->arch.cur_context = NORMAL_WORLD; - - /* TODO: we may need to add one scheduler->reset_data to reset the thread_obj */ - vcpu->thread_obj.notify_mode = SCHED_NOTIFY_IPI; - - vlapic = vcpu_vlapic(vcpu); - vlapic_reset(vlapic, apicv_ops); - - reset_vcpu_regs(vcpu); } } @@ -806,7 +800,7 @@ int32_t prepare_vcpu(struct acrn_vm *vm, uint16_t pcpu_id) vcpu->thread_obj.sched_ctl = &per_cpu(sched_ctl, pcpu_id); vcpu->thread_obj.thread_entry = vcpu_thread; vcpu->thread_obj.pcpu_id = pcpu_id; - vcpu->thread_obj.notify_mode = SCHED_NOTIFY_IPI; + /* vcpu->thread_obj.notify_mode is initialized in vcpu_reset_internal() when create vcpu */ vcpu->thread_obj.host_sp = build_stack_frame(vcpu); vcpu->thread_obj.switch_out = context_switch_out; vcpu->thread_obj.switch_in = context_switch_in; diff --git a/hypervisor/arch/x86/guest/vlapic.c b/hypervisor/arch/x86/guest/vlapic.c index 36885efd2..f487a74ff 100644 --- a/hypervisor/arch/x86/guest/vlapic.c +++ b/hypervisor/arch/x86/guest/vlapic.c @@ -1163,7 +1163,7 @@ vlapic_process_init_sipi(struct acrn_vcpu* target_vcpu, uint32_t mode, uint32_t /* put target vcpu to INIT state and wait for SIPI */ pause_vcpu(target_vcpu, VCPU_PAUSED); - reset_vcpu(target_vcpu); + reset_vcpu(target_vcpu, INIT_RESET); /* new cpu model only need one SIPI to kick AP run, * the second SIPI will be ignored as it move out of * wait-for-SIPI state. @@ -1686,8 +1686,6 @@ void vlapic_init(struct acrn_vlapic *vlapic) { vlapic_init_timer(vlapic); - - vlapic_reset(vlapic, apicv_ops); } void vlapic_restore(struct acrn_vlapic *vlapic, const struct lapic_regs *regs) diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c index 37dc29550..cb2cf5cac 100644 --- a/hypervisor/arch/x86/guest/vm.c +++ b/hypervisor/arch/x86/guest/vm.c @@ -650,7 +650,6 @@ int32_t shutdown_vm(struct acrn_vm *vm) } foreach_vcpu(i, vm, vcpu) { - reset_vcpu(vcpu); offline_vcpu(vcpu); if (bitmap_test(pcpuid_from_vcpu(vcpu), &mask)) { @@ -737,7 +736,7 @@ int32_t reset_vm(struct acrn_vm *vm) } foreach_vcpu(i, vm, vcpu) { - reset_vcpu(vcpu); + reset_vcpu(vcpu, COLD_RESET); if (bitmap_test(pcpuid_from_vcpu(vcpu), &mask)) { make_pcpu_offline(pcpuid_from_vcpu(vcpu)); @@ -824,7 +823,7 @@ void resume_vm_from_s3(struct acrn_vm *vm, uint32_t wakeup_vec) vm->state = VM_STARTED; - reset_vcpu(bsp); + reset_vcpu(bsp, POWER_ON_RESET); /* When SOS resume from S3, it will return to real mode * with entry set to wakeup_vec. diff --git a/hypervisor/common/hypercall.c b/hypervisor/common/hypercall.c index c11404080..94ec0da4c 100644 --- a/hypervisor/common/hypercall.c +++ b/hypervisor/common/hypercall.c @@ -64,7 +64,6 @@ int32_t hcall_sos_offline_cpu(struct acrn_vm *vm, uint64_t lapicid) break; } pause_vcpu(vcpu, VCPU_ZOMBIE); - reset_vcpu(vcpu); offline_vcpu(vcpu); } } diff --git a/hypervisor/include/arch/x86/guest/vcpu.h b/hypervisor/include/arch/x86/guest/vcpu.h index bfee6e4b6..dc2cb99a0 100644 --- a/hypervisor/include/arch/x86/guest/vcpu.h +++ b/hypervisor/include/arch/x86/guest/vcpu.h @@ -146,6 +146,7 @@ enum vm_cpu_mode { CPU_MODE_64BIT, /* IA-32E mode (CS.L = 1) */ }; +enum reset_mode; /* 2 worlds: 0 for Normal World, 1 for Secure World */ #define NR_WORLD 2 @@ -600,10 +601,11 @@ void offline_vcpu(struct acrn_vcpu *vcpu); * Reset all fields in a vCPU instance, the vCPU state is reset to VCPU_INIT. * * @param[inout] vcpu pointer to vcpu data structure + * @param[in] mode the reset mode * * @return None */ -void reset_vcpu(struct acrn_vcpu *vcpu); +void reset_vcpu(struct acrn_vcpu *vcpu, enum reset_mode mode); /** * @brief pause the vcpu and set new state diff --git a/hypervisor/include/arch/x86/guest/vm.h b/hypervisor/include/arch/x86/guest/vm.h index 6c4a22b37..7d1a33f97 100644 --- a/hypervisor/include/arch/x86/guest/vm.h +++ b/hypervisor/include/arch/x86/guest/vm.h @@ -30,6 +30,14 @@ #include #endif +enum reset_mode { + POWER_ON_RESET, /* reset by hardware Power-on */ + COLD_RESET, /* hardware cold reset */ + WARM_RESET, /* behavior slightly differ from cold reset, that some MSRs might be retained. */ + INIT_RESET, /* reset by INIT */ + SOFTWARE_RESET, /* reset by software disable<->enable */ +}; + struct vm_hw_info { /* vcpu array of this VM */ struct acrn_vcpu vcpu_array[MAX_VCPUS_PER_VM];