|
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | + |
| 3 | +#include <linux/entry-common.h> |
| 4 | +#include <linux/kvm_types.h> |
| 5 | +#include <linux/hrtimer_rearm.h> |
| 6 | +#include <asm/fred.h> |
| 7 | +#include <asm/desc.h> |
| 8 | + |
| 9 | +#if IS_ENABLED(CONFIG_KVM_INTEL) |
| 10 | +/* |
| 11 | + * On VMX, NMIs and IRQs (as configured by KVM) are acknowledged by hardware as |
| 12 | + * part of the VM-Exit, i.e. the event itself is consumed as part the VM-Exit. |
| 13 | + * x86_entry_from_kvm() is invoked by KVM to effectively forward NMIs and IRQs |
| 14 | + * to the kernel for servicing. On SVM, a.k.a. AMD, the NMI/IRQ VM-Exit is |
| 15 | + * purely a signal that an NMI/IRQ is pending, i.e. the event that triggered |
| 16 | + * the VM-Exit is held pending until it's unblocked in the host. |
| 17 | + */ |
| 18 | +noinstr void x86_entry_from_kvm(unsigned int event_type, unsigned int vector) |
| 19 | +{ |
| 20 | + if (event_type == EVENT_TYPE_EXTINT) { |
| 21 | +#ifdef CONFIG_X86_64 |
| 22 | + /* |
| 23 | + * Use FRED dispatch, even when running IDT. The dispatch |
| 24 | + * tables are kept in sync between FRED and IDT, and the FRED |
| 25 | + * dispatch works well with CFI. |
| 26 | + */ |
| 27 | + fred_entry_from_kvm(event_type, vector); |
| 28 | +#else |
| 29 | + idt_entry_from_kvm(vector); |
| 30 | +#endif |
| 31 | + /* |
| 32 | + * Strictly speaking, only the NMI path requires noinstr. |
| 33 | + */ |
| 34 | + instrumentation_begin(); |
| 35 | + /* |
| 36 | + * KVM/VMX will dispatch from IRQ-disabled but for a context |
| 37 | + * that will have IRQs-enabled. This confuses the entry code |
| 38 | + * and it will not have reprogrammed the timer. Do so now. |
| 39 | + */ |
| 40 | + hrtimer_rearm_deferred(); |
| 41 | + instrumentation_end(); |
| 42 | + |
| 43 | + return; |
| 44 | + } |
| 45 | + |
| 46 | + WARN_ON_ONCE(event_type != EVENT_TYPE_NMI); |
| 47 | + |
| 48 | +#ifdef CONFIG_X86_64 |
| 49 | + if (cpu_feature_enabled(X86_FEATURE_FRED)) |
| 50 | + return fred_entry_from_kvm(event_type, vector); |
| 51 | +#endif |
| 52 | + |
| 53 | + /* |
| 54 | + * Notably, we must use IDT dispatch for NMI when running in IDT mode. |
| 55 | + * The FRED NMI context is significantly different and will not work |
| 56 | + * right (specifically FRED fixed the NMI recursion issue). |
| 57 | + */ |
| 58 | + idt_entry_from_kvm(vector); |
| 59 | +} |
| 60 | +EXPORT_SYMBOL_FOR_KVM(x86_entry_from_kvm); |
| 61 | +#endif |
0 commit comments