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