xref: /openbmc/linux/kernel/entry/kvm.c (revision fbb6b31a)
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 | _TIF_NOTIFY_SIGNAL)) {
12 			clear_notify_signal();
13 			if (task_work_pending(current))
14 				task_work_run();
15 		}
16 
17 		if (ti_work & _TIF_SIGPENDING) {
18 			kvm_handle_signal_exit(vcpu);
19 			return -EINTR;
20 		}
21 
22 		if (ti_work & _TIF_NEED_RESCHED)
23 			schedule();
24 
25 		if (ti_work & _TIF_NOTIFY_RESUME)
26 			resume_user_mode_work(NULL);
27 
28 		ret = arch_xfer_to_guest_mode_handle_work(vcpu, ti_work);
29 		if (ret)
30 			return ret;
31 
32 		ti_work = read_thread_flags();
33 	} while (ti_work & XFER_TO_GUEST_MODE_WORK || need_resched());
34 	return 0;
35 }
36 
37 int xfer_to_guest_mode_handle_work(struct kvm_vcpu *vcpu)
38 {
39 	unsigned long ti_work;
40 
41 	/*
42 	 * This is invoked from the outer guest loop with interrupts and
43 	 * preemption enabled.
44 	 *
45 	 * KVM invokes xfer_to_guest_mode_work_pending() with interrupts
46 	 * disabled in the inner loop before going into guest mode. No need
47 	 * to disable interrupts here.
48 	 */
49 	ti_work = read_thread_flags();
50 	if (!(ti_work & XFER_TO_GUEST_MODE_WORK))
51 		return 0;
52 
53 	return xfer_to_guest_mode_work(vcpu, ti_work);
54 }
55 EXPORT_SYMBOL_GPL(xfer_to_guest_mode_handle_work);
56