mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-07-21 02:41:32 +00:00
HV: refine reset_vcpu api
The patch abstract a vcpu_reset_internal() api for internal usage, the function would not touch any vcpu state transition and just do vcpu reset processing. It will be called by create_vcpu() and reset_vcpu(). The reset_vcpu() will act as a public api and should be called only when vcpu receive INIT or vm reset/resume from S3. It should not be called when do shutdown_vm() or hcall_sos_offline_cpu(), so the patch remove reset_vcpu() in shutdown_vm() and hcall_sos_offline_cpu(). The patch also introduced reset_mode enum so that vcpu and vlapic could do different context operation according to different reset mode; Tracked-On: #4267 Signed-off-by: Victor Sun <victor.sun@intel.com> Reviewed-by: Jason Chen CJ <jason.cj.chen@intel.com> Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
parent
d1a46b8289
commit
a5158e2c16
@ -193,6 +193,35 @@ void vcpu_reset_eoi_exit_bitmaps(struct acrn_vcpu *vcpu)
|
|||||||
vcpu_make_request(vcpu, ACRN_REQUEST_EOI_EXIT_BITMAP_UPDATE);
|
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 acrn_vcpu *get_running_vcpu(uint16_t pcpu_id)
|
||||||
{
|
{
|
||||||
struct thread_object *curr = sched_get_current(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;
|
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 */
|
/* Create per vcpu vlapic */
|
||||||
vlapic_create(vcpu);
|
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 */
|
/* Populate the return handle */
|
||||||
*rtn_vcpu_handle = vcpu;
|
*rtn_vcpu_handle = vcpu;
|
||||||
|
|
||||||
vcpu->launched = false;
|
|
||||||
vcpu->running = false;
|
|
||||||
vcpu->arch.nr_sipi = 0U;
|
|
||||||
vcpu->state = VCPU_INIT;
|
vcpu->state = VCPU_INIT;
|
||||||
|
|
||||||
init_xsave(vcpu);
|
init_xsave(vcpu);
|
||||||
reset_vcpu_regs(vcpu);
|
vcpu_reset_internal(vcpu, POWER_ON_RESET);
|
||||||
(void)memset((void *)&vcpu->req, 0U, sizeof(struct io_request));
|
(void)memset((void *)&vcpu->req, 0U, sizeof(struct io_request));
|
||||||
vm->hw.created_vcpus++;
|
vm->hw.created_vcpus++;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@ -655,40 +674,15 @@ static uint64_t build_stack_frame(struct acrn_vcpu *vcpu)
|
|||||||
/* NOTE:
|
/* NOTE:
|
||||||
* vcpu should be paused before call this function.
|
* 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);
|
pr_dbg("vcpu%hu reset", vcpu->vcpu_id);
|
||||||
ASSERT(vcpu->state != VCPU_RUNNING,
|
ASSERT(vcpu->state != VCPU_RUNNING,
|
||||||
"reset vcpu when it's running");
|
"reset vcpu when it's running");
|
||||||
|
|
||||||
if (vcpu->state != VCPU_INIT) {
|
if (vcpu->state != VCPU_INIT) {
|
||||||
|
vcpu_reset_internal(vcpu, mode);
|
||||||
vcpu->state = VCPU_INIT;
|
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.sched_ctl = &per_cpu(sched_ctl, pcpu_id);
|
||||||
vcpu->thread_obj.thread_entry = vcpu_thread;
|
vcpu->thread_obj.thread_entry = vcpu_thread;
|
||||||
vcpu->thread_obj.pcpu_id = pcpu_id;
|
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.host_sp = build_stack_frame(vcpu);
|
||||||
vcpu->thread_obj.switch_out = context_switch_out;
|
vcpu->thread_obj.switch_out = context_switch_out;
|
||||||
vcpu->thread_obj.switch_in = context_switch_in;
|
vcpu->thread_obj.switch_in = context_switch_in;
|
||||||
|
@ -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 */
|
/* put target vcpu to INIT state and wait for SIPI */
|
||||||
pause_vcpu(target_vcpu, VCPU_PAUSED);
|
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,
|
/* new cpu model only need one SIPI to kick AP run,
|
||||||
* the second SIPI will be ignored as it move out of
|
* the second SIPI will be ignored as it move out of
|
||||||
* wait-for-SIPI state.
|
* wait-for-SIPI state.
|
||||||
@ -1686,8 +1686,6 @@ void
|
|||||||
vlapic_init(struct acrn_vlapic *vlapic)
|
vlapic_init(struct acrn_vlapic *vlapic)
|
||||||
{
|
{
|
||||||
vlapic_init_timer(vlapic);
|
vlapic_init_timer(vlapic);
|
||||||
|
|
||||||
vlapic_reset(vlapic, apicv_ops);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vlapic_restore(struct acrn_vlapic *vlapic, const struct lapic_regs *regs)
|
void vlapic_restore(struct acrn_vlapic *vlapic, const struct lapic_regs *regs)
|
||||||
|
@ -650,7 +650,6 @@ int32_t shutdown_vm(struct acrn_vm *vm)
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach_vcpu(i, vm, vcpu) {
|
foreach_vcpu(i, vm, vcpu) {
|
||||||
reset_vcpu(vcpu);
|
|
||||||
offline_vcpu(vcpu);
|
offline_vcpu(vcpu);
|
||||||
|
|
||||||
if (bitmap_test(pcpuid_from_vcpu(vcpu), &mask)) {
|
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) {
|
foreach_vcpu(i, vm, vcpu) {
|
||||||
reset_vcpu(vcpu);
|
reset_vcpu(vcpu, COLD_RESET);
|
||||||
|
|
||||||
if (bitmap_test(pcpuid_from_vcpu(vcpu), &mask)) {
|
if (bitmap_test(pcpuid_from_vcpu(vcpu), &mask)) {
|
||||||
make_pcpu_offline(pcpuid_from_vcpu(vcpu));
|
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;
|
vm->state = VM_STARTED;
|
||||||
|
|
||||||
reset_vcpu(bsp);
|
reset_vcpu(bsp, POWER_ON_RESET);
|
||||||
|
|
||||||
/* When SOS resume from S3, it will return to real mode
|
/* When SOS resume from S3, it will return to real mode
|
||||||
* with entry set to wakeup_vec.
|
* with entry set to wakeup_vec.
|
||||||
|
@ -64,7 +64,6 @@ int32_t hcall_sos_offline_cpu(struct acrn_vm *vm, uint64_t lapicid)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pause_vcpu(vcpu, VCPU_ZOMBIE);
|
pause_vcpu(vcpu, VCPU_ZOMBIE);
|
||||||
reset_vcpu(vcpu);
|
|
||||||
offline_vcpu(vcpu);
|
offline_vcpu(vcpu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,6 +146,7 @@ enum vm_cpu_mode {
|
|||||||
CPU_MODE_64BIT, /* IA-32E mode (CS.L = 1) */
|
CPU_MODE_64BIT, /* IA-32E mode (CS.L = 1) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum reset_mode;
|
||||||
|
|
||||||
/* 2 worlds: 0 for Normal World, 1 for Secure World */
|
/* 2 worlds: 0 for Normal World, 1 for Secure World */
|
||||||
#define NR_WORLD 2
|
#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.
|
* Reset all fields in a vCPU instance, the vCPU state is reset to VCPU_INIT.
|
||||||
*
|
*
|
||||||
* @param[inout] vcpu pointer to vcpu data structure
|
* @param[inout] vcpu pointer to vcpu data structure
|
||||||
|
* @param[in] mode the reset mode
|
||||||
*
|
*
|
||||||
* @return None
|
* @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
|
* @brief pause the vcpu and set new state
|
||||||
|
@ -30,6 +30,14 @@
|
|||||||
#include <hyperv.h>
|
#include <hyperv.h>
|
||||||
#endif
|
#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 {
|
struct vm_hw_info {
|
||||||
/* vcpu array of this VM */
|
/* vcpu array of this VM */
|
||||||
struct acrn_vcpu vcpu_array[MAX_VCPUS_PER_VM];
|
struct acrn_vcpu vcpu_array[MAX_VCPUS_PER_VM];
|
||||||
|
Loading…
Reference in New Issue
Block a user