xref: /openbmc/linux/kernel/entry/kvm.c (revision 3a83e4e6)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <linux/entry-kvm.h>
4 #include <linux/kvm_host.h>
5 
6 static int xfer_to_guest_mode_work(struct kvm_vcpu *vcpu, unsigned long ti_work)
7 {
8 	do {
9 		int ret;
10 
11 		if (ti_work & _TIF_SIGPENDING) {
12 			kvm_handle_signal_exit(vcpu);
13 			return -EINTR;
14 		}
15 
16 		if (ti_work & _TIF_NEED_RESCHED)
17 			schedule();
18 
19 		if (ti_work & _TIF_NOTIFY_RESUME) {
20 			clear_thread_flag(TIF_NOTIFY_RESUME);
21 			tracehook_notify_resume(NULL);
22 		}
23 
24 		ret = arch_xfer_to_guest_mode_handle_work(vcpu, ti_work);
25 		if (ret)
26 			return ret;
27 
28 		ti_work = READ_ONCE(current_thread_info()->flags);
29 	} while (ti_work & XFER_TO_GUEST_MODE_WORK || need_resched());
30 	return 0;
31 }
32 
33 int xfer_to_guest_mode_handle_work(struct kvm_vcpu *vcpu)
34 {
35 	unsigned long ti_work;
36 
37 	/*
38 	 * This is invoked from the outer guest loop with interrupts and
39 	 * preemption enabled.
40 	 *
41 	 * KVM invokes xfer_to_guest_mode_work_pending() with interrupts
42 	 * disabled in the inner loop before going into guest mode. No need
43 	 * to disable interrupts here.
44 	 */
45 	ti_work = READ_ONCE(current_thread_info()->flags);
46 	if (!(ti_work & XFER_TO_GUEST_MODE_WORK))
47 		return 0;
48 
49 	return xfer_to_guest_mode_work(vcpu, ti_work);
50 }
51 EXPORT_SYMBOL_GPL(xfer_to_guest_mode_handle_work);
52