xref: /openbmc/linux/kernel/entry/kvm.c (revision 03248add)
1935ace2fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0
2935ace2fSThomas Gleixner 
3935ace2fSThomas Gleixner #include <linux/entry-kvm.h>
4935ace2fSThomas Gleixner #include <linux/kvm_host.h>
5935ace2fSThomas Gleixner 
6935ace2fSThomas Gleixner static int xfer_to_guest_mode_work(struct kvm_vcpu *vcpu, unsigned long ti_work)
7935ace2fSThomas Gleixner {
8935ace2fSThomas Gleixner 	do {
9935ace2fSThomas Gleixner 		int ret;
10935ace2fSThomas Gleixner 
117c5d8fa6SEric W. Biederman 		if (ti_work & (_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL)) {
127c5d8fa6SEric W. Biederman 			clear_notify_signal();
137c5d8fa6SEric W. Biederman 			if (task_work_pending(current))
147c5d8fa6SEric W. Biederman 				task_work_run();
157c5d8fa6SEric W. Biederman 		}
1612db8b69SJens Axboe 
17935ace2fSThomas Gleixner 		if (ti_work & _TIF_SIGPENDING) {
18935ace2fSThomas Gleixner 			kvm_handle_signal_exit(vcpu);
19935ace2fSThomas Gleixner 			return -EINTR;
20935ace2fSThomas Gleixner 		}
21935ace2fSThomas Gleixner 
22935ace2fSThomas Gleixner 		if (ti_work & _TIF_NEED_RESCHED)
23935ace2fSThomas Gleixner 			schedule();
24935ace2fSThomas Gleixner 
253c532798SJens Axboe 		if (ti_work & _TIF_NOTIFY_RESUME)
26*03248addSEric W. Biederman 			resume_user_mode_work(NULL);
27935ace2fSThomas Gleixner 
28935ace2fSThomas Gleixner 		ret = arch_xfer_to_guest_mode_handle_work(vcpu, ti_work);
29935ace2fSThomas Gleixner 		if (ret)
30935ace2fSThomas Gleixner 			return ret;
31935ace2fSThomas Gleixner 
326ce89512SMark Rutland 		ti_work = read_thread_flags();
33935ace2fSThomas Gleixner 	} while (ti_work & XFER_TO_GUEST_MODE_WORK || need_resched());
34935ace2fSThomas Gleixner 	return 0;
35935ace2fSThomas Gleixner }
36935ace2fSThomas Gleixner 
37935ace2fSThomas Gleixner int xfer_to_guest_mode_handle_work(struct kvm_vcpu *vcpu)
38935ace2fSThomas Gleixner {
39935ace2fSThomas Gleixner 	unsigned long ti_work;
40935ace2fSThomas Gleixner 
41935ace2fSThomas Gleixner 	/*
42935ace2fSThomas Gleixner 	 * This is invoked from the outer guest loop with interrupts and
43935ace2fSThomas Gleixner 	 * preemption enabled.
44935ace2fSThomas Gleixner 	 *
45935ace2fSThomas Gleixner 	 * KVM invokes xfer_to_guest_mode_work_pending() with interrupts
46935ace2fSThomas Gleixner 	 * disabled in the inner loop before going into guest mode. No need
47935ace2fSThomas Gleixner 	 * to disable interrupts here.
48935ace2fSThomas Gleixner 	 */
496ce89512SMark Rutland 	ti_work = read_thread_flags();
50935ace2fSThomas Gleixner 	if (!(ti_work & XFER_TO_GUEST_MODE_WORK))
51935ace2fSThomas Gleixner 		return 0;
52935ace2fSThomas Gleixner 
53935ace2fSThomas Gleixner 	return xfer_to_guest_mode_work(vcpu, ti_work);
54935ace2fSThomas Gleixner }
55935ace2fSThomas Gleixner EXPORT_SYMBOL_GPL(xfer_to_guest_mode_handle_work);
56