acrn-hypervisor/hypervisor/common/hv_main.c
Shuo A Liu 4303ccb1a0 hv: HLT emulation in hypervisor
HLT emulation is import to CPU resource maximum utilization. vcpu
doing HLT means it is idle and can give up CPU proactively. Thus, we
pause the vcpu thread in HLT emulation and resume it while event happens.

When vcpu enter HLT, its vcpu thread will sleep, but the vcpu state is
still 'Running'.

VM ID    PCPU ID    VCPU ID    VCPU ROLE    VCPU STATE
=====    =======    =======    =========    ==========
  0         0          0       PRIMARY      Running
  0         1          1       SECONDARY    Running

Tracked-On: #4329
Signed-off-by: Shuo A Liu <shuo.a.liu@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
2020-01-07 11:23:32 +08:00

114 lines
2.6 KiB
C

/*
* Copyright (C) 2018 Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <vm.h>
#include <vm_reset.h>
#include <vmcs.h>
#include <vmexit.h>
#include <irq.h>
#include <schedule.h>
#include <profiling.h>
#include <sprintf.h>
#include <trace.h>
#include <logmsg.h>
void vcpu_thread(struct thread_object *obj)
{
struct acrn_vcpu *vcpu = list_entry(obj, struct acrn_vcpu, thread_obj);
uint32_t basic_exit_reason = 0U;
int32_t ret = 0;
do {
if (!is_lapic_pt_enabled(vcpu)) {
CPU_IRQ_DISABLE();
}
/* Don't open interrupt window between here and vmentry */
if (need_reschedule(pcpuid_from_vcpu(vcpu))) {
schedule();
}
/* Check and process pending requests(including interrupt) */
ret = acrn_handle_pending_request(vcpu);
if (ret < 0) {
pr_fatal("vcpu handling pending request fail");
pause_vcpu(vcpu, VCPU_ZOMBIE);
/* Fatal error happened (triple fault). Stop the vcpu running. */
continue;
}
reset_event(&vcpu->events[VCPU_EVENT_VIRTUAL_INTERRUPT]);
profiling_vmenter_handler(vcpu);
TRACE_2L(TRACE_VM_ENTER, 0UL, 0UL);
ret = run_vcpu(vcpu);
if (ret != 0) {
pr_fatal("vcpu resume failed");
pause_vcpu(vcpu, VCPU_ZOMBIE);
/* Fatal error happened (resume vcpu failed). Stop the vcpu running. */
continue;
}
basic_exit_reason = vcpu->arch.exit_reason & 0xFFFFU;
TRACE_2L(TRACE_VM_EXIT, basic_exit_reason, vcpu_get_rip(vcpu));
vcpu->arch.nrexits++;
profiling_pre_vmexit_handler(vcpu);
if (!is_lapic_pt_enabled(vcpu)) {
CPU_IRQ_ENABLE();
}
/* Dispatch handler */
ret = vmexit_handler(vcpu);
if (ret < 0) {
pr_fatal("dispatch VM exit handler failed for reason"
" %d, ret = %d!", basic_exit_reason, ret);
vcpu_inject_gp(vcpu, 0U);
continue;
}
profiling_post_vmexit_handler(vcpu);
} while (1);
}
void default_idle(__unused struct thread_object *obj)
{
uint16_t pcpu_id = get_pcpu_id();
while (1) {
if (need_reschedule(pcpu_id)) {
schedule();
} else if (need_offline(pcpu_id)) {
cpu_dead();
} else if (need_shutdown_vm(pcpu_id)) {
shutdown_vm_from_idle(pcpu_id);
} else {
CPU_IRQ_ENABLE();
cpu_do_idle();
CPU_IRQ_DISABLE();
}
}
}
void run_idle_thread(void)
{
uint16_t pcpu_id = get_pcpu_id();
struct thread_object *idle = &per_cpu(idle, pcpu_id);
char idle_name[16];
snprintf(idle_name, 16U, "idle%hu", pcpu_id);
(void)strncpy_s(idle->name, 16U, idle_name, 16U);
idle->pcpu_id = pcpu_id;
idle->thread_entry = default_idle;
idle->switch_out = NULL;
idle->switch_in = NULL;
run_thread(idle);
/* Control should not come here */
cpu_dead();
}