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