Skip to content

Commit f077825

Browse files
committed
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ář <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent a584539 commit f077825

File tree

7 files changed

+99
-10
lines changed

7 files changed

+99
-10
lines changed

Documentation/virtual/kvm/api.txt

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -820,11 +820,21 @@ struct kvm_vcpu_events {
820820
} nmi;
821821
__u32 sipi_vector;
822822
__u32 flags;
823+
struct {
824+
__u8 smm;
825+
__u8 pending;
826+
__u8 smm_inside_nmi;
827+
__u8 latched_init;
828+
} smi;
823829
};
824830

825-
KVM_VCPUEVENT_VALID_SHADOW may be set in the flags field to signal that
826-
interrupt.shadow contains a valid state. Otherwise, this field is undefined.
831+
Only two fields are defined in the flags field:
832+
833+
- KVM_VCPUEVENT_VALID_SHADOW may be set in the flags field to signal that
834+
interrupt.shadow contains a valid state.
827835

836+
- KVM_VCPUEVENT_VALID_SMM may be set in the flags field to signal that
837+
smi contains a valid state.
828838

829839
4.32 KVM_SET_VCPU_EVENTS
830840

@@ -841,17 +851,20 @@ vcpu.
841851
See KVM_GET_VCPU_EVENTS for the data structure.
842852

843853
Fields that may be modified asynchronously by running VCPUs can be excluded
844-
from the update. These fields are nmi.pending and sipi_vector. Keep the
845-
corresponding bits in the flags field cleared to suppress overwriting the
846-
current in-kernel state. The bits are:
854+
from the update. These fields are nmi.pending, sipi_vector, smi.smm,
855+
smi.pending. Keep the corresponding bits in the flags field cleared to
856+
suppress overwriting the current in-kernel state. The bits are:
847857

848858
KVM_VCPUEVENT_VALID_NMI_PENDING - transfer nmi.pending to the kernel
849859
KVM_VCPUEVENT_VALID_SIPI_VECTOR - transfer sipi_vector
860+
KVM_VCPUEVENT_VALID_SMM - transfer the smi sub-struct.
850861

851862
If KVM_CAP_INTR_SHADOW is available, KVM_VCPUEVENT_VALID_SHADOW can be set in
852863
the flags field to signal that interrupt.shadow contains a valid state and
853864
shall be written into the VCPU.
854865

866+
KVM_VCPUEVENT_VALID_SMM can only be set if KVM_CAP_X86_SMM is available.
867+
855868

856869
4.33 KVM_GET_DEBUGREGS
857870

@@ -2979,6 +2992,16 @@ len must be a multiple of sizeof(struct kvm_s390_irq). It must be > 0
29792992
and it must not exceed (max_vcpus + 32) * sizeof(struct kvm_s390_irq),
29802993
which is the maximum number of possibly pending cpu-local interrupts.
29812994

2995+
4.90 KVM_SMI
2996+
2997+
Capability: KVM_CAP_X86_SMM
2998+
Architectures: x86
2999+
Type: vcpu ioctl
3000+
Parameters: none
3001+
Returns: 0 on success, -1 on error
3002+
3003+
Queues an SMI on the thread's vcpu.
3004+
29823005
5. The kvm_run structure
29833006
------------------------
29843007

@@ -3014,7 +3037,12 @@ an interrupt can be injected now with KVM_INTERRUPT.
30143037
The value of the current interrupt flag. Only valid if in-kernel
30153038
local APIC is not used.
30163039

3017-
__u8 padding2[2];
3040+
__u16 flags;
3041+
3042+
More architecture-specific flags detailing state of the VCPU that may
3043+
affect the device's behavior. The only currently defined flag is
3044+
KVM_RUN_X86_SMM, which is valid on x86 machines and is set if the
3045+
VCPU is in system management mode.
30183046

30193047
/* in (pre_kvm_run), out (post_kvm_run) */
30203048
__u64 cr8;

arch/x86/include/asm/kvm_host.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ struct kvm_vcpu_arch {
471471
atomic_t nmi_queued; /* unprocessed asynchronous NMIs */
472472
unsigned nmi_pending; /* NMI queued after currently running handler */
473473
bool nmi_injected; /* Trying to inject an NMI this entry */
474+
bool smi_pending; /* SMI queued after currently running handler */
474475

475476
struct mtrr_state_type mtrr_state;
476477
u64 pat;
@@ -1115,6 +1116,8 @@ enum {
11151116
#define HF_NMI_MASK (1 << 3)
11161117
#define HF_IRET_MASK (1 << 4)
11171118
#define HF_GUEST_MASK (1 << 5) /* VCPU is in guest-mode */
1119+
#define HF_SMM_MASK (1 << 6)
1120+
#define HF_SMM_INSIDE_NMI_MASK (1 << 7)
11181121

11191122
/*
11201123
* Hardware virtualization extension instructions may fault if a

arch/x86/include/uapi/asm/kvm.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ struct kvm_ioapic_state {
106106
#define KVM_IRQCHIP_IOAPIC 2
107107
#define KVM_NR_IRQCHIPS 3
108108

109+
#define KVM_RUN_X86_SMM (1 << 0)
110+
109111
/* for KVM_GET_REGS and KVM_SET_REGS */
110112
struct kvm_regs {
111113
/* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
@@ -281,6 +283,7 @@ struct kvm_reinject_control {
281283
#define KVM_VCPUEVENT_VALID_NMI_PENDING 0x00000001
282284
#define KVM_VCPUEVENT_VALID_SIPI_VECTOR 0x00000002
283285
#define KVM_VCPUEVENT_VALID_SHADOW 0x00000004
286+
#define KVM_VCPUEVENT_VALID_SMM 0x00000008
284287

285288
/* Interrupt shadow states */
286289
#define KVM_X86_SHADOW_INT_MOV_SS 0x01
@@ -309,7 +312,13 @@ struct kvm_vcpu_events {
309312
} nmi;
310313
__u32 sipi_vector;
311314
__u32 flags;
312-
__u32 reserved[10];
315+
struct {
316+
__u8 smm;
317+
__u8 pending;
318+
__u8 smm_inside_nmi;
319+
__u8 latched_init;
320+
} smi;
321+
__u32 reserved[9];
313322
};
314323

315324
/* for KVM_GET/SET_DEBUGREGS */

arch/x86/kvm/kvm_cache_regs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,9 @@ static inline bool is_guest_mode(struct kvm_vcpu *vcpu)
9999
return vcpu->arch.hflags & HF_GUEST_MASK;
100100
}
101101

102+
static inline bool is_smm(struct kvm_vcpu *vcpu)
103+
{
104+
return vcpu->arch.hflags & HF_SMM_MASK;
105+
}
106+
102107
#endif

arch/x86/kvm/lapic.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ static inline bool kvm_lowest_prio_delivery(struct kvm_lapic_irq *irq)
159159
irq->msi_redir_hint);
160160
}
161161

162+
static inline int kvm_lapic_latched_init(struct kvm_vcpu *vcpu)
163+
{
164+
return kvm_vcpu_has_lapic(vcpu) && test_bit(KVM_APIC_INIT, &vcpu->arch.apic->pending_events);
165+
}
166+
162167
bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector);
163168

164169
void wait_lapic_expire(struct kvm_vcpu *vcpu);

arch/x86/kvm/x86.c

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3101,6 +3101,11 @@ static int kvm_vcpu_ioctl_nmi(struct kvm_vcpu *vcpu)
31013101
return 0;
31023102
}
31033103

3104+
static int kvm_vcpu_ioctl_smi(struct kvm_vcpu *vcpu)
3105+
{
3106+
return 0;
3107+
}
3108+
31043109
static int vcpu_ioctl_tpr_access_reporting(struct kvm_vcpu *vcpu,
31053110
struct kvm_tpr_access_ctl *tac)
31063111
{
@@ -3206,8 +3211,15 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
32063211

32073212
events->sipi_vector = 0; /* never valid when reporting to user space */
32083213

3214+
events->smi.smm = is_smm(vcpu);
3215+
events->smi.pending = vcpu->arch.smi_pending;
3216+
events->smi.smm_inside_nmi =
3217+
!!(vcpu->arch.hflags & HF_SMM_INSIDE_NMI_MASK);
3218+
events->smi.latched_init = kvm_lapic_latched_init(vcpu);
3219+
32093220
events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING
3210-
| KVM_VCPUEVENT_VALID_SHADOW);
3221+
| KVM_VCPUEVENT_VALID_SHADOW
3222+
| KVM_VCPUEVENT_VALID_SMM);
32113223
memset(&events->reserved, 0, sizeof(events->reserved));
32123224
}
32133225

@@ -3216,7 +3228,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
32163228
{
32173229
if (events->flags & ~(KVM_VCPUEVENT_VALID_NMI_PENDING
32183230
| KVM_VCPUEVENT_VALID_SIPI_VECTOR
3219-
| KVM_VCPUEVENT_VALID_SHADOW))
3231+
| KVM_VCPUEVENT_VALID_SHADOW
3232+
| KVM_VCPUEVENT_VALID_SMM))
32203233
return -EINVAL;
32213234

32223235
process_nmi(vcpu);
@@ -3241,6 +3254,24 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
32413254
kvm_vcpu_has_lapic(vcpu))
32423255
vcpu->arch.apic->sipi_vector = events->sipi_vector;
32433256

3257+
if (events->flags & KVM_VCPUEVENT_VALID_SMM) {
3258+
if (events->smi.smm)
3259+
vcpu->arch.hflags |= HF_SMM_MASK;
3260+
else
3261+
vcpu->arch.hflags &= ~HF_SMM_MASK;
3262+
vcpu->arch.smi_pending = events->smi.pending;
3263+
if (events->smi.smm_inside_nmi)
3264+
vcpu->arch.hflags |= HF_SMM_INSIDE_NMI_MASK;
3265+
else
3266+
vcpu->arch.hflags &= ~HF_SMM_INSIDE_NMI_MASK;
3267+
if (kvm_vcpu_has_lapic(vcpu)) {
3268+
if (events->smi.latched_init)
3269+
set_bit(KVM_APIC_INIT, &vcpu->arch.apic->pending_events);
3270+
else
3271+
clear_bit(KVM_APIC_INIT, &vcpu->arch.apic->pending_events);
3272+
}
3273+
}
3274+
32443275
kvm_make_request(KVM_REQ_EVENT, vcpu);
32453276

32463277
return 0;
@@ -3500,6 +3531,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
35003531
r = kvm_vcpu_ioctl_nmi(vcpu);
35013532
break;
35023533
}
3534+
case KVM_SMI: {
3535+
r = kvm_vcpu_ioctl_smi(vcpu);
3536+
break;
3537+
}
35033538
case KVM_SET_CPUID: {
35043539
struct kvm_cpuid __user *cpuid_arg = argp;
35053540
struct kvm_cpuid cpuid;
@@ -6182,6 +6217,7 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
61826217
struct kvm_run *kvm_run = vcpu->run;
61836218

61846219
kvm_run->if_flag = (kvm_get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
6220+
kvm_run->flags = is_smm(vcpu) ? KVM_RUN_X86_SMM : 0;
61856221
kvm_run->cr8 = kvm_get_cr8(vcpu);
61866222
kvm_run->apic_base = kvm_get_apic_base(vcpu);
61876223
if (irqchip_in_kernel(vcpu->kvm))

include/uapi/linux/kvm.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ struct kvm_run {
202202
__u32 exit_reason;
203203
__u8 ready_for_interrupt_injection;
204204
__u8 if_flag;
205-
__u8 padding2[2];
205+
__u16 flags;
206206

207207
/* in (pre_kvm_run), out (post_kvm_run) */
208208
__u64 cr8;
@@ -815,6 +815,7 @@ struct kvm_ppc_smmu_info {
815815
#define KVM_CAP_S390_IRQ_STATE 114
816816
#define KVM_CAP_PPC_HWRNG 115
817817
#define KVM_CAP_DISABLE_QUIRKS 116
818+
#define KVM_CAP_X86_SMM 117
818819

819820
#ifdef KVM_CAP_IRQ_ROUTING
820821

@@ -1200,6 +1201,8 @@ struct kvm_s390_ucas_mapping {
12001201
/* Available with KVM_CAP_S390_IRQ_STATE */
12011202
#define KVM_S390_SET_IRQ_STATE _IOW(KVMIO, 0xb5, struct kvm_s390_irq_state)
12021203
#define KVM_S390_GET_IRQ_STATE _IOW(KVMIO, 0xb6, struct kvm_s390_irq_state)
1204+
/* Available with KVM_CAP_X86_SMM */
1205+
#define KVM_SMI _IO(KVMIO, 0xb7)
12031206

12041207
#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
12051208
#define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1)

0 commit comments

Comments
 (0)