On 27/05/2015 19:05, Paolo Bonzini wrote: > This patch includes changes to the external API for SMM support. > All the changes are predicated by the availability of a new > capability, KVM_CAP_X86_SMM, which is added at the end of the > patch series. > > Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> Radim, I forgot to change flags to u8 in this patch. However, I am thinking that it's just as good to leave it as u16. The reason is that the other two fields in this 32-bit word were just 1-bit flags that were expanded to 8 bits for no particular reasons. If we make it now u8 flags; u8 padding2; chances are that in due time it will become simply u8 flags; u8 flags2; and then it's nicer to just have an u16. On the other hand, your argument that KVM_RUN has very little free space is also a good one. What do you think? I have already done the change in my local repo, but I can change it back too. Paolo > --- > RFC->v1: add smi.pending and smi.rsm_unmasks_nmi fields, reduce padding > in struct kvm_vcpu_events; remove memset of events struct, > instead zero smi.pad. KVM_CAP_X86_SMM frozen at 117. > --- > Documentation/virtual/kvm/api.txt | 40 +++++++++++++++++++++++++++++++++------ > arch/x86/include/asm/kvm_host.h | 3 +++ > arch/x86/include/uapi/asm/kvm.h | 11 ++++++++++- > arch/x86/kvm/kvm_cache_regs.h | 5 +++++ > arch/x86/kvm/x86.c | 34 +++++++++++++++++++++++++++++++-- > include/uapi/linux/kvm.h | 5 ++++- > 6 files changed, 88 insertions(+), 10 deletions(-) > > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt > index 695544420ff2..51523b70b6b2 100644 > --- a/Documentation/virtual/kvm/api.txt > +++ b/Documentation/virtual/kvm/api.txt > @@ -820,11 +820,21 @@ struct kvm_vcpu_events { > } nmi; > __u32 sipi_vector; > __u32 flags; > + struct { > + __u8 smm; > + __u8 pending; > + __u8 smm_inside_nmi; > + __u8 pad; > + } 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; > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h > index 4e299fcd0eb6..d52d7aea375f 100644 > --- a/arch/x86/include/asm/kvm_host.h > +++ b/arch/x86/include/asm/kvm_host.h > @@ -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 > diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h > index 2fec75e4b1e1..30100a3c1bed 100644 > --- a/arch/x86/include/uapi/asm/kvm.h > +++ b/arch/x86/include/uapi/asm/kvm.h > @@ -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 pad; > + } smi; > + __u32 reserved[9]; > }; > > /* for KVM_GET/SET_DEBUGREGS */ > diff --git a/arch/x86/kvm/kvm_cache_regs.h b/arch/x86/kvm/kvm_cache_regs.h > index 544076c4f44b..e1e89ee4af75 100644 > --- a/arch/x86/kvm/kvm_cache_regs.h > +++ b/arch/x86/kvm/kvm_cache_regs.h > @@ -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 > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c > index 70072f94318e..0deb83f526c0 100644 > --- a/arch/x86/kvm/x86.c > +++ b/arch/x86/kvm/x86.c > @@ -3097,6 +3097,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) > { > @@ -3202,8 +3207,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.pad = 0; > + > 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)); > } > > @@ -3212,7 +3224,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); > @@ -3237,6 +3250,18 @@ 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; > + } > + > kvm_make_request(KVM_REQ_EVENT, vcpu); > > return 0; > @@ -3496,6 +3521,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; > @@ -6178,6 +6207,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)) > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h > index 75bd9f7fd846..eace8babd227 100644 > --- a/include/uapi/linux/kvm.h > +++ b/include/uapi/linux/kvm.h > @@ -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) > -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html