1 /*
2 * Copyright (C) 2018-2022 Intel Corporation.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <asm/guest/vm.h>
8 #include <asm/guest/vm_reset.h>
9 #include <asm/guest/vmcs.h>
10 #include <asm/guest/vmexit.h>
11 #include <asm/guest/virq.h>
12 #include <schedule.h>
13 #include <profiling.h>
14 #include <sprintf.h>
15 #include <trace.h>
16 #include <logmsg.h>
17
vcpu_thread(struct thread_object * obj)18 void vcpu_thread(struct thread_object *obj)
19 {
20 struct acrn_vcpu *vcpu = container_of(obj, struct acrn_vcpu, thread_obj);
21 int32_t ret = 0;
22
23 do {
24 if (!is_lapic_pt_enabled(vcpu)) {
25 CPU_IRQ_DISABLE_ON_CONFIG();
26 }
27
28 /* Don't open interrupt window between here and vmentry */
29 if (need_reschedule(pcpuid_from_vcpu(vcpu))) {
30 schedule();
31 }
32
33 /* Check and process pending requests(including interrupt) */
34 ret = acrn_handle_pending_request(vcpu);
35 if (ret < 0) {
36 pr_fatal("vcpu handling pending request fail");
37 get_vm_lock(vcpu->vm);
38 zombie_vcpu(vcpu, VCPU_ZOMBIE);
39 put_vm_lock(vcpu->vm);
40 /* Fatal error happened (triple fault). Stop the vcpu running. */
41 continue;
42 }
43
44 reset_event(&vcpu->events[VCPU_EVENT_VIRTUAL_INTERRUPT]);
45 profiling_vmenter_handler(vcpu);
46
47 TRACE_2L(TRACE_VM_ENTER, 0UL, 0UL);
48 ret = run_vcpu(vcpu);
49 if (ret != 0) {
50 pr_fatal("vcpu resume failed");
51 get_vm_lock(vcpu->vm);
52 zombie_vcpu(vcpu, VCPU_ZOMBIE);
53 put_vm_lock(vcpu->vm);
54 /* Fatal error happened (resume vcpu failed). Stop the vcpu running. */
55 continue;
56 }
57 TRACE_2L(TRACE_VM_EXIT, vcpu->arch.exit_reason, vcpu_get_rip(vcpu));
58
59 profiling_pre_vmexit_handler(vcpu);
60
61 if (!is_lapic_pt_enabled(vcpu)) {
62 CPU_IRQ_ENABLE_ON_CONFIG();
63 }
64 /* Dispatch handler */
65 ret = vmexit_handler(vcpu);
66 if (ret < 0) {
67 pr_fatal("dispatch VM exit handler failed for reason"
68 " %d, ret = %d!", vcpu->arch.exit_reason, ret);
69 vcpu_inject_gp(vcpu, 0U);
70 continue;
71 }
72
73 profiling_post_vmexit_handler(vcpu);
74 } while (1);
75 }
76
default_idle(__unused struct thread_object * obj)77 void default_idle(__unused struct thread_object *obj)
78 {
79 uint16_t pcpu_id = get_pcpu_id();
80
81 while (1) {
82 if (need_reschedule(pcpu_id)) {
83 schedule();
84 } else if (need_offline(pcpu_id)) {
85 cpu_dead();
86 } else if (need_shutdown_vm(pcpu_id)) {
87 shutdown_vm_from_idle(pcpu_id);
88 } else {
89 cpu_do_idle();
90 }
91 }
92 }
93
run_idle_thread(void)94 void run_idle_thread(void)
95 {
96 uint16_t pcpu_id = get_pcpu_id();
97 struct thread_object *idle = &per_cpu(idle, pcpu_id);
98 struct sched_params idle_params = {0};
99 char idle_name[16];
100
101 snprintf(idle_name, 16U, "idle%hu", pcpu_id);
102 (void)strncpy_s(idle->name, 16U, idle_name, 16U);
103 idle->pcpu_id = pcpu_id;
104 idle->thread_entry = default_idle;
105 idle->switch_out = NULL;
106 idle->switch_in = NULL;
107 idle_params.prio = PRIO_IDLE;
108 init_thread_data(idle, &idle_params);
109
110 run_thread(idle);
111
112 /* Control should not come here */
113 cpu_dead();
114 }
115