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