KVM: x86: API changes for SMM support
This patch includes changes to the external API for SMM support. Userspace can predicate the availability of the new fields and ioctls on a new capability, KVM_CAP_X86_SMM, which is added at the end of the patch series. Reviewed-by: Radim Krčmář <rkrcmar@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
a584539b24
commit
f077825a87
|
@ -820,11 +820,21 @@ struct kvm_vcpu_events {
|
|||
} nmi;
|
||||
__u32 sipi_vector;
|
||||
__u32 flags;
|
||||
struct {
|
||||
__u8 smm;
|
||||
__u8 pending;
|
||||
__u8 smm_inside_nmi;
|
||||
__u8 latched_init;
|
||||
} smi;
|
||||
};
|
||||
|
||||
KVM_VCPUEVENT_VALID_SHADOW may be set in the flags field to signal that
|
||||
interrupt.shadow contains a valid state. Otherwise, this field is undefined.
|
||||
Only two fields are defined in the flags field:
|
||||
|
||||
- KVM_VCPUEVENT_VALID_SHADOW may be set in the flags field to signal that
|
||||
interrupt.shadow contains a valid state.
|
||||
|
||||
- KVM_VCPUEVENT_VALID_SMM may be set in the flags field to signal that
|
||||
smi contains a valid state.
|
||||
|
||||
4.32 KVM_SET_VCPU_EVENTS
|
||||
|
||||
|
@ -841,17 +851,20 @@ vcpu.
|
|||
See KVM_GET_VCPU_EVENTS for the data structure.
|
||||
|
||||
Fields that may be modified asynchronously by running VCPUs can be excluded
|
||||
from the update. These fields are nmi.pending and sipi_vector. Keep the
|
||||
corresponding bits in the flags field cleared to suppress overwriting the
|
||||
current in-kernel state. The bits are:
|
||||
from the update. These fields are nmi.pending, sipi_vector, smi.smm,
|
||||
smi.pending. Keep the corresponding bits in the flags field cleared to
|
||||
suppress overwriting the current in-kernel state. The bits are:
|
||||
|
||||
KVM_VCPUEVENT_VALID_NMI_PENDING - transfer nmi.pending to the kernel
|
||||
KVM_VCPUEVENT_VALID_SIPI_VECTOR - transfer sipi_vector
|
||||
KVM_VCPUEVENT_VALID_SMM - transfer the smi sub-struct.
|
||||
|
||||
If KVM_CAP_INTR_SHADOW is available, KVM_VCPUEVENT_VALID_SHADOW can be set in
|
||||
the flags field to signal that interrupt.shadow contains a valid state and
|
||||
shall be written into the VCPU.
|
||||
|
||||
KVM_VCPUEVENT_VALID_SMM can only be set if KVM_CAP_X86_SMM is available.
|
||||
|
||||
|
||||
4.33 KVM_GET_DEBUGREGS
|
||||
|
||||
|
@ -2979,6 +2992,16 @@ len must be a multiple of sizeof(struct kvm_s390_irq). It must be > 0
|
|||
and it must not exceed (max_vcpus + 32) * sizeof(struct kvm_s390_irq),
|
||||
which is the maximum number of possibly pending cpu-local interrupts.
|
||||
|
||||
4.90 KVM_SMI
|
||||
|
||||
Capability: KVM_CAP_X86_SMM
|
||||
Architectures: x86
|
||||
Type: vcpu ioctl
|
||||
Parameters: none
|
||||
Returns: 0 on success, -1 on error
|
||||
|
||||
Queues an SMI on the thread's vcpu.
|
||||
|
||||
5. The kvm_run structure
|
||||
------------------------
|
||||
|
||||
|
@ -3014,7 +3037,12 @@ an interrupt can be injected now with KVM_INTERRUPT.
|
|||
The value of the current interrupt flag. Only valid if in-kernel
|
||||
local APIC is not used.
|
||||
|
||||
__u8 padding2[2];
|
||||
__u16 flags;
|
||||
|
||||
More architecture-specific flags detailing state of the VCPU that may
|
||||
affect the device's behavior. The only currently defined flag is
|
||||
KVM_RUN_X86_SMM, which is valid on x86 machines and is set if the
|
||||
VCPU is in system management mode.
|
||||
|
||||
/* in (pre_kvm_run), out (post_kvm_run) */
|
||||
__u64 cr8;
|
||||
|
|
|
@ -471,6 +471,7 @@ struct kvm_vcpu_arch {
|
|||
atomic_t nmi_queued; /* unprocessed asynchronous NMIs */
|
||||
unsigned nmi_pending; /* NMI queued after currently running handler */
|
||||
bool nmi_injected; /* Trying to inject an NMI this entry */
|
||||
bool smi_pending; /* SMI queued after currently running handler */
|
||||
|
||||
struct mtrr_state_type mtrr_state;
|
||||
u64 pat;
|
||||
|
@ -1115,6 +1116,8 @@ enum {
|
|||
#define HF_NMI_MASK (1 << 3)
|
||||
#define HF_IRET_MASK (1 << 4)
|
||||
#define HF_GUEST_MASK (1 << 5) /* VCPU is in guest-mode */
|
||||
#define HF_SMM_MASK (1 << 6)
|
||||
#define HF_SMM_INSIDE_NMI_MASK (1 << 7)
|
||||
|
||||
/*
|
||||
* Hardware virtualization extension instructions may fault if a
|
||||
|
|
|
@ -106,6 +106,8 @@ struct kvm_ioapic_state {
|
|||
#define KVM_IRQCHIP_IOAPIC 2
|
||||
#define KVM_NR_IRQCHIPS 3
|
||||
|
||||
#define KVM_RUN_X86_SMM (1 << 0)
|
||||
|
||||
/* for KVM_GET_REGS and KVM_SET_REGS */
|
||||
struct kvm_regs {
|
||||
/* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
|
||||
|
@ -281,6 +283,7 @@ struct kvm_reinject_control {
|
|||
#define KVM_VCPUEVENT_VALID_NMI_PENDING 0x00000001
|
||||
#define KVM_VCPUEVENT_VALID_SIPI_VECTOR 0x00000002
|
||||
#define KVM_VCPUEVENT_VALID_SHADOW 0x00000004
|
||||
#define KVM_VCPUEVENT_VALID_SMM 0x00000008
|
||||
|
||||
/* Interrupt shadow states */
|
||||
#define KVM_X86_SHADOW_INT_MOV_SS 0x01
|
||||
|
@ -309,7 +312,13 @@ struct kvm_vcpu_events {
|
|||
} nmi;
|
||||
__u32 sipi_vector;
|
||||
__u32 flags;
|
||||
__u32 reserved[10];
|
||||
struct {
|
||||
__u8 smm;
|
||||
__u8 pending;
|
||||
__u8 smm_inside_nmi;
|
||||
__u8 latched_init;
|
||||
} smi;
|
||||
__u32 reserved[9];
|
||||
};
|
||||
|
||||
/* for KVM_GET/SET_DEBUGREGS */
|
||||
|
|
|
@ -99,4 +99,9 @@ static inline bool is_guest_mode(struct kvm_vcpu *vcpu)
|
|||
return vcpu->arch.hflags & HF_GUEST_MASK;
|
||||
}
|
||||
|
||||
static inline bool is_smm(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return vcpu->arch.hflags & HF_SMM_MASK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -159,6 +159,11 @@ static inline bool kvm_lowest_prio_delivery(struct kvm_lapic_irq *irq)
|
|||
irq->msi_redir_hint);
|
||||
}
|
||||
|
||||
static inline int kvm_lapic_latched_init(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_vcpu_has_lapic(vcpu) && test_bit(KVM_APIC_INIT, &vcpu->arch.apic->pending_events);
|
||||
}
|
||||
|
||||
bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector);
|
||||
|
||||
void wait_lapic_expire(struct kvm_vcpu *vcpu);
|
||||
|
|
|
@ -3101,6 +3101,11 @@ static int kvm_vcpu_ioctl_nmi(struct kvm_vcpu *vcpu)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_vcpu_ioctl_smi(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vcpu_ioctl_tpr_access_reporting(struct kvm_vcpu *vcpu,
|
||||
struct kvm_tpr_access_ctl *tac)
|
||||
{
|
||||
|
@ -3206,8 +3211,15 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
|
|||
|
||||
events->sipi_vector = 0; /* never valid when reporting to user space */
|
||||
|
||||
events->smi.smm = is_smm(vcpu);
|
||||
events->smi.pending = vcpu->arch.smi_pending;
|
||||
events->smi.smm_inside_nmi =
|
||||
!!(vcpu->arch.hflags & HF_SMM_INSIDE_NMI_MASK);
|
||||
events->smi.latched_init = kvm_lapic_latched_init(vcpu);
|
||||
|
||||
events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING
|
||||
| KVM_VCPUEVENT_VALID_SHADOW);
|
||||
| KVM_VCPUEVENT_VALID_SHADOW
|
||||
| KVM_VCPUEVENT_VALID_SMM);
|
||||
memset(&events->reserved, 0, sizeof(events->reserved));
|
||||
}
|
||||
|
||||
|
@ -3216,7 +3228,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
|
|||
{
|
||||
if (events->flags & ~(KVM_VCPUEVENT_VALID_NMI_PENDING
|
||||
| KVM_VCPUEVENT_VALID_SIPI_VECTOR
|
||||
| KVM_VCPUEVENT_VALID_SHADOW))
|
||||
| KVM_VCPUEVENT_VALID_SHADOW
|
||||
| KVM_VCPUEVENT_VALID_SMM))
|
||||
return -EINVAL;
|
||||
|
||||
process_nmi(vcpu);
|
||||
|
@ -3241,6 +3254,24 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
|
|||
kvm_vcpu_has_lapic(vcpu))
|
||||
vcpu->arch.apic->sipi_vector = events->sipi_vector;
|
||||
|
||||
if (events->flags & KVM_VCPUEVENT_VALID_SMM) {
|
||||
if (events->smi.smm)
|
||||
vcpu->arch.hflags |= HF_SMM_MASK;
|
||||
else
|
||||
vcpu->arch.hflags &= ~HF_SMM_MASK;
|
||||
vcpu->arch.smi_pending = events->smi.pending;
|
||||
if (events->smi.smm_inside_nmi)
|
||||
vcpu->arch.hflags |= HF_SMM_INSIDE_NMI_MASK;
|
||||
else
|
||||
vcpu->arch.hflags &= ~HF_SMM_INSIDE_NMI_MASK;
|
||||
if (kvm_vcpu_has_lapic(vcpu)) {
|
||||
if (events->smi.latched_init)
|
||||
set_bit(KVM_APIC_INIT, &vcpu->arch.apic->pending_events);
|
||||
else
|
||||
clear_bit(KVM_APIC_INIT, &vcpu->arch.apic->pending_events);
|
||||
}
|
||||
}
|
||||
|
||||
kvm_make_request(KVM_REQ_EVENT, vcpu);
|
||||
|
||||
return 0;
|
||||
|
@ -3500,6 +3531,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
|||
r = kvm_vcpu_ioctl_nmi(vcpu);
|
||||
break;
|
||||
}
|
||||
case KVM_SMI: {
|
||||
r = kvm_vcpu_ioctl_smi(vcpu);
|
||||
break;
|
||||
}
|
||||
case KVM_SET_CPUID: {
|
||||
struct kvm_cpuid __user *cpuid_arg = argp;
|
||||
struct kvm_cpuid cpuid;
|
||||
|
@ -6182,6 +6217,7 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
|
|||
struct kvm_run *kvm_run = vcpu->run;
|
||||
|
||||
kvm_run->if_flag = (kvm_get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
|
||||
kvm_run->flags = is_smm(vcpu) ? KVM_RUN_X86_SMM : 0;
|
||||
kvm_run->cr8 = kvm_get_cr8(vcpu);
|
||||
kvm_run->apic_base = kvm_get_apic_base(vcpu);
|
||||
if (irqchip_in_kernel(vcpu->kvm))
|
||||
|
|
|
@ -202,7 +202,7 @@ struct kvm_run {
|
|||
__u32 exit_reason;
|
||||
__u8 ready_for_interrupt_injection;
|
||||
__u8 if_flag;
|
||||
__u8 padding2[2];
|
||||
__u16 flags;
|
||||
|
||||
/* in (pre_kvm_run), out (post_kvm_run) */
|
||||
__u64 cr8;
|
||||
|
@ -815,6 +815,7 @@ struct kvm_ppc_smmu_info {
|
|||
#define KVM_CAP_S390_IRQ_STATE 114
|
||||
#define KVM_CAP_PPC_HWRNG 115
|
||||
#define KVM_CAP_DISABLE_QUIRKS 116
|
||||
#define KVM_CAP_X86_SMM 117
|
||||
|
||||
#ifdef KVM_CAP_IRQ_ROUTING
|
||||
|
||||
|
@ -1200,6 +1201,8 @@ struct kvm_s390_ucas_mapping {
|
|||
/* Available with KVM_CAP_S390_IRQ_STATE */
|
||||
#define KVM_S390_SET_IRQ_STATE _IOW(KVMIO, 0xb5, struct kvm_s390_irq_state)
|
||||
#define KVM_S390_GET_IRQ_STATE _IOW(KVMIO, 0xb6, struct kvm_s390_irq_state)
|
||||
/* Available with KVM_CAP_X86_SMM */
|
||||
#define KVM_SMI _IO(KVMIO, 0xb7)
|
||||
|
||||
#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
|
||||
#define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1)
|
||||
|
|
Loading…
Reference in New Issue