History

entry: Provide infrastructure for work before transitioning to guest mode

Entering a guest is similar to exiting to user space. Pending work like handling signals, rescheduling, task work etc. needs to be handled before that. Provide generic infrastructure to avoid duplication of the same handling code all over the place. The transfer to guest mode handling is different from the exit to usermode handling, e.g. vs. rseq and live patching, so a separate function is used. The initial list of work items handled is: TIF_SIGPENDING, TIF_NEED_RESCHED, TIF_NOTIFY_RESUME Architecture specific TIF flags can be added via defines in the architecture specific include files. The calling convention is also different from the syscall/interrupt entry functions as KVM invokes this from the outer vcpu_run() loop with interrupts and preemption enabled. To prevent missing a pending work item it invokes a check for pending TIF work from interrupt disabled code right before transitioning to guest mode. The lockdep, RCU and tracing state handling is also done directly around the switch to and from guest mode.

Thomas Gleixner committed 6 years ago

Commit 935ace21 parent a5497ba5 files · +144 −1Browse files

Unified · Split

5 files
  1. include/linux/entry-kvm.h +80 −0
  2. include/linux/kvm_host.h +8 −0
  3. kernel/entry/Makefile +2 −1
  4. kernel/entry/kvm.c +51 −0
  5. virt/kvm/Kconfig +3 −0
include/linux/entry-kvm.h+80−0
@@ -0,0 +1,80 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef __LINUX_ENTRYKVM_H
3#define __LINUX_ENTRYKVM_H
4
5#include <linux/entry-common.h>
6
7/* Transfer to guest mode work */
8#ifdef CONFIG_KVM_XFER_TO_GUEST_WORK
9
10#ifndef ARCH_XFER_TO_GUEST_MODE_WORK
11# define ARCH_XFER_TO_GUEST_MODE_WORK (0)
12#endif
13
14#define XFER_TO_GUEST_MODE_WORK \
15 (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
16 _TIF_NOTIFY_RESUME | ARCH_XFER_TO_GUEST_MODE_WORK)
17
18struct kvm_vcpu;
19
20/**
21 * arch_xfer_to_guest_mode_handle_work - Architecture specific xfer to guest
22 * mode work handling function.
23 * @vcpu: Pointer to current's VCPU data
24 * @ti_work: Cached TIF flags gathered in xfer_to_guest_mode_handle_work()
25 *
26 * Invoked from xfer_to_guest_mode_handle_work(). Defaults to NOOP. Can be
27 * replaced by architecture specific code.
28 */
29static inline int arch_xfer_to_guest_mode_handle_work(struct kvm_vcpu *vcpu,
30 unsigned long ti_work);
31
32#ifndef arch_xfer_to_guest_mode_work
33static inline int arch_xfer_to_guest_mode_handle_work(struct kvm_vcpu *vcpu,
34 unsigned long ti_work)
35{
36 return 0;
37}
38#endif
39
40/**
41 * xfer_to_guest_mode_handle_work - Check and handle pending work which needs
42 * to be handled before going to guest mode
43 * @vcpu: Pointer to current's VCPU data
44 *
45 * Returns: 0 or an error code
46 */
47int xfer_to_guest_mode_handle_work(struct kvm_vcpu *vcpu);
48
49/**
50 * __xfer_to_guest_mode_work_pending - Check if work is pending
51 *
52 * Returns: True if work pending, False otherwise.
53 *
54 * Bare variant of xfer_to_guest_mode_work_pending(). Can be called from
55 * interrupt enabled code for racy quick checks with care.
56 */
57static inline bool __xfer_to_guest_mode_work_pending(void)
58{
59 unsigned long ti_work = READ_ONCE(current_thread_info()->flags);
60
61 return !!(ti_work & XFER_TO_GUEST_MODE_WORK);
62}
63
64/**
65 * xfer_to_guest_mode_work_pending - Check if work is pending which needs to be
66 * handled before returning to guest mode
67 *
68 * Returns: True if work pending, False otherwise.
69 *
70 * Has to be invoked with interrupts disabled before the transition to
71 * guest mode.
72 */
73static inline bool xfer_to_guest_mode_work_pending(void)
74{
75 lockdep_assert_irqs_disabled();
76 return __xfer_to_guest_mode_work_pending();
77}
78#endif /* CONFIG_KVM_XFER_TO_GUEST_WORK */
79
80#endif
include/linux/kvm_host.h+8−0
@@ -1439,4 +1439,12 @@ int kvm_vm_create_worker_thread(struct kvm *kvm, kvm_vm_thread_fn_t thread_fn, · 1438 unmodified lines
1439 uintptr_t data, const char *name,1439 uintptr_t data, const char *name,
1440 struct task_struct **thread_ptr);1440 struct task_struct **thread_ptr);
1441 1441
1442#ifdef CONFIG_KVM_XFER_TO_GUEST_WORK
1443static inline void kvm_handle_signal_exit(struct kvm_vcpu *vcpu)
1444{
1445 vcpu->run->exit_reason = KVM_EXIT_INTR;
1446 vcpu->stat.signal_exits++;
1447}
1448#endif /* CONFIG_KVM_XFER_TO_GUEST_WORK */
1449
1442#endif1450#endif
kernel/entry/Makefile+2−1
@@ -9,4 +9,5 @@ KCOV_INSTRUMENT := n · 8 unmodified lines
9CFLAGS_REMOVE_common.o = -fstack-protector -fstack-protector-strong9CFLAGS_REMOVE_common.o = -fstack-protector -fstack-protector-strong
10CFLAGS_common.o += -fno-stack-protector10CFLAGS_common.o += -fno-stack-protector
11 11
12obj-$(CONFIG_GENERIC_ENTRY) += common.o12obj-$(CONFIG_GENERIC_ENTRY) += common.o
13obj-$(CONFIG_KVM_XFER_TO_GUEST_WORK) += kvm.o
kernel/entry/kvm.c+51−0
@@ -0,0 +1,51 @@
1// SPDX-License-Identifier: GPL-2.0
2
3#include <linux/entry-kvm.h>
4#include <linux/kvm_host.h>
5
6static 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
33int 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}
51EXPORT_SYMBOL_GPL(xfer_to_guest_mode_handle_work);
virt/kvm/Kconfig+3−0
@@ -60,3 +60,6 @@ config HAVE_KVM_VCPU_RUN_PID_CHANGE · 59 unmodified lines
60 60
61config HAVE_KVM_NO_POLL61config HAVE_KVM_NO_POLL
62 bool62 bool
63
64config KVM_XFER_TO_GUEST_WORK
65 bool