mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-04-30 04:33:58 +00:00
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>
114 lines
2.6 KiB
C
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();
|
|
}
|