Skip to content

Commit 64d6067

Browse files
committed
KVM: x86: stubs for SMM support
This patch adds the interface between x86.c and the emulator: the SMBASE register, a new emulator flag, the RSM instruction. It also adds a new request bit that will be used by the KVM_SMI ioctl. Reviewed-by: Radim Krčmář <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent f077825 commit 64d6067

File tree

7 files changed

+81
-4
lines changed

7 files changed

+81
-4
lines changed

arch/x86/include/asm/kvm_emulate.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ struct x86_emulate_ops {
193193
int (*cpl)(struct x86_emulate_ctxt *ctxt);
194194
int (*get_dr)(struct x86_emulate_ctxt *ctxt, int dr, ulong *dest);
195195
int (*set_dr)(struct x86_emulate_ctxt *ctxt, int dr, ulong value);
196+
u64 (*get_smbase)(struct x86_emulate_ctxt *ctxt);
197+
void (*set_smbase)(struct x86_emulate_ctxt *ctxt, u64 smbase);
196198
int (*set_msr)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 data);
197199
int (*get_msr)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 *pdata);
198200
int (*check_pmc)(struct x86_emulate_ctxt *ctxt, u32 pmc);
@@ -264,6 +266,8 @@ enum x86emul_mode {
264266

265267
/* These match some of the HF_* flags defined in kvm_host.h */
266268
#define X86EMUL_GUEST_MASK (1 << 5) /* VCPU is in guest-mode */
269+
#define X86EMUL_SMM_MASK (1 << 6)
270+
#define X86EMUL_SMM_INSIDE_NMI_MASK (1 << 7)
267271

268272
struct x86_emulate_ctxt {
269273
const struct x86_emulate_ops *ops;

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ struct kvm_vcpu_arch {
368368
int32_t apic_arb_prio;
369369
int mp_state;
370370
u64 ia32_misc_enable_msr;
371+
u64 smbase;
371372
bool tpr_access_reporting;
372373
u64 ia32_xss;
373374

arch/x86/kvm/emulate.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2259,6 +2259,14 @@ static int em_lseg(struct x86_emulate_ctxt *ctxt)
22592259
return rc;
22602260
}
22612261

2262+
static int em_rsm(struct x86_emulate_ctxt *ctxt)
2263+
{
2264+
if ((ctxt->emul_flags & X86EMUL_SMM_MASK) == 0)
2265+
return emulate_ud(ctxt);
2266+
2267+
return X86EMUL_UNHANDLEABLE;
2268+
}
2269+
22622270
static void
22632271
setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
22642272
struct desc_struct *cs, struct desc_struct *ss)
@@ -4197,7 +4205,7 @@ static const struct opcode twobyte_table[256] = {
41974205
F(DstMem | SrcReg | Src2CL | ModRM, em_shld), N, N,
41984206
/* 0xA8 - 0xAF */
41994207
I(Stack | Src2GS, em_push_sreg), I(Stack | Src2GS, em_pop_sreg),
4200-
DI(ImplicitOps, rsm),
4208+
II(No64 | EmulateOnUD | ImplicitOps, em_rsm, rsm),
42014209
F(DstMem | SrcReg | ModRM | BitOp | Lock | PageTable, em_bts),
42024210
F(DstMem | SrcReg | Src2ImmByte | ModRM, em_shrd),
42034211
F(DstMem | SrcReg | Src2CL | ModRM, em_shrd),

arch/x86/kvm/lapic.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,9 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
808808
break;
809809

810810
case APIC_DM_SMI:
811-
apic_debug("Ignoring guest SMI\n");
811+
result = 1;
812+
kvm_make_request(KVM_REQ_SMI, vcpu);
813+
kvm_vcpu_kick(vcpu);
812814
break;
813815

814816
case APIC_DM_NMI:

arch/x86/kvm/svm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3394,6 +3394,7 @@ static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = {
33943394
[SVM_EXIT_MWAIT] = mwait_interception,
33953395
[SVM_EXIT_XSETBV] = xsetbv_interception,
33963396
[SVM_EXIT_NPF] = pf_interception,
3397+
[SVM_EXIT_RSM] = emulate_on_interception,
33973398
};
33983399

33993400
static void dump_vmcb(struct kvm_vcpu *vcpu)

arch/x86/kvm/x86.c

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,7 @@ static u32 emulated_msrs[] = {
954954
MSR_IA32_MISC_ENABLE,
955955
MSR_IA32_MCG_STATUS,
956956
MSR_IA32_MCG_CTL,
957+
MSR_IA32_SMBASE,
957958
};
958959

959960
static unsigned num_emulated_msrs;
@@ -2282,6 +2283,11 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
22822283
case MSR_IA32_MISC_ENABLE:
22832284
vcpu->arch.ia32_misc_enable_msr = data;
22842285
break;
2286+
case MSR_IA32_SMBASE:
2287+
if (!msr_info->host_initiated)
2288+
return 1;
2289+
vcpu->arch.smbase = data;
2290+
break;
22852291
case MSR_KVM_WALL_CLOCK_NEW:
22862292
case MSR_KVM_WALL_CLOCK:
22872293
vcpu->kvm->arch.wall_clock = data;
@@ -2679,6 +2685,11 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
26792685
case MSR_IA32_MISC_ENABLE:
26802686
msr_info->data = vcpu->arch.ia32_misc_enable_msr;
26812687
break;
2688+
case MSR_IA32_SMBASE:
2689+
if (!msr_info->host_initiated)
2690+
return 1;
2691+
msr_info->data = vcpu->arch.smbase;
2692+
break;
26822693
case MSR_IA32_PERF_STATUS:
26832694
/* TSC increment by tick */
26842695
msr_info->data = 1000ULL;
@@ -3103,6 +3114,8 @@ static int kvm_vcpu_ioctl_nmi(struct kvm_vcpu *vcpu)
31033114

31043115
static int kvm_vcpu_ioctl_smi(struct kvm_vcpu *vcpu)
31053116
{
3117+
kvm_make_request(KVM_REQ_SMI, vcpu);
3118+
31063119
return 0;
31073120
}
31083121

@@ -5129,6 +5142,20 @@ static int emulator_set_msr(struct x86_emulate_ctxt *ctxt,
51295142
return kvm_set_msr(emul_to_vcpu(ctxt), &msr);
51305143
}
51315144

5145+
static u64 emulator_get_smbase(struct x86_emulate_ctxt *ctxt)
5146+
{
5147+
struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
5148+
5149+
return vcpu->arch.smbase;
5150+
}
5151+
5152+
static void emulator_set_smbase(struct x86_emulate_ctxt *ctxt, u64 smbase)
5153+
{
5154+
struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
5155+
5156+
vcpu->arch.smbase = smbase;
5157+
}
5158+
51325159
static int emulator_check_pmc(struct x86_emulate_ctxt *ctxt,
51335160
u32 pmc)
51345161
{
@@ -5214,6 +5241,8 @@ static const struct x86_emulate_ops emulate_ops = {
52145241
.cpl = emulator_get_cpl,
52155242
.get_dr = emulator_get_dr,
52165243
.set_dr = emulator_set_dr,
5244+
.get_smbase = emulator_get_smbase,
5245+
.set_smbase = emulator_set_smbase,
52175246
.set_msr = emulator_set_msr,
52185247
.get_msr = emulator_get_msr,
52195248
.check_pmc = emulator_check_pmc,
@@ -5276,6 +5305,8 @@ static void init_emulate_ctxt(struct kvm_vcpu *vcpu)
52765305
cs_db ? X86EMUL_MODE_PROT32 :
52775306
X86EMUL_MODE_PROT16;
52785307
BUILD_BUG_ON(HF_GUEST_MASK != X86EMUL_GUEST_MASK);
5308+
BUILD_BUG_ON(HF_SMM_MASK != X86EMUL_SMM_MASK);
5309+
BUILD_BUG_ON(HF_SMM_INSIDE_NMI_MASK != X86EMUL_SMM_INSIDE_NMI_MASK);
52795310
ctxt->emul_flags = vcpu->arch.hflags;
52805311

52815312
init_decode_cache(ctxt);
@@ -5445,9 +5476,24 @@ static bool retry_instruction(struct x86_emulate_ctxt *ctxt,
54455476
static int complete_emulated_mmio(struct kvm_vcpu *vcpu);
54465477
static int complete_emulated_pio(struct kvm_vcpu *vcpu);
54475478

5448-
void kvm_set_hflags(struct kvm_vcpu *vcpu, unsigned emul_flags)
5479+
static void kvm_smm_changed(struct kvm_vcpu *vcpu)
54495480
{
5481+
if (!(vcpu->arch.hflags & HF_SMM_MASK)) {
5482+
if (unlikely(vcpu->arch.smi_pending)) {
5483+
kvm_make_request(KVM_REQ_SMI, vcpu);
5484+
vcpu->arch.smi_pending = 0;
5485+
}
5486+
}
5487+
}
5488+
5489+
static void kvm_set_hflags(struct kvm_vcpu *vcpu, unsigned emul_flags)
5490+
{
5491+
unsigned changed = vcpu->arch.hflags ^ emul_flags;
5492+
54505493
vcpu->arch.hflags = emul_flags;
5494+
5495+
if (changed & HF_SMM_MASK)
5496+
kvm_smm_changed(vcpu);
54515497
}
54525498

54535499
static int kvm_vcpu_check_hw_bp(unsigned long addr, u32 type, u32 dr7,
@@ -6341,6 +6387,16 @@ static void process_nmi(struct kvm_vcpu *vcpu)
63416387
kvm_make_request(KVM_REQ_EVENT, vcpu);
63426388
}
63436389

6390+
static void process_smi(struct kvm_vcpu *vcpu)
6391+
{
6392+
if (is_smm(vcpu)) {
6393+
vcpu->arch.smi_pending = true;
6394+
return;
6395+
}
6396+
6397+
printk_once(KERN_DEBUG "Ignoring guest SMI\n");
6398+
}
6399+
63446400
static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
63456401
{
63466402
u64 eoi_exit_bitmap[4];
@@ -6449,6 +6505,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
64496505
}
64506506
if (kvm_check_request(KVM_REQ_STEAL_UPDATE, vcpu))
64516507
record_steal_time(vcpu);
6508+
if (kvm_check_request(KVM_REQ_SMI, vcpu))
6509+
process_smi(vcpu);
64526510
if (kvm_check_request(KVM_REQ_NMI, vcpu))
64536511
process_nmi(vcpu);
64546512
if (kvm_check_request(KVM_REQ_PMU, vcpu))
@@ -7363,8 +7421,10 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
73637421
kvm_async_pf_hash_reset(vcpu);
73647422
vcpu->arch.apf.halted = false;
73657423

7366-
if (!init_event)
7424+
if (!init_event) {
73677425
kvm_pmu_reset(vcpu);
7426+
vcpu->arch.smbase = 0x30000;
7427+
}
73687428

73697429
memset(vcpu->arch.regs, 0, sizeof(vcpu->arch.regs));
73707430
vcpu->arch.regs_avail = ~0;

include/linux/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ static inline bool is_error_page(struct page *page)
134134
#define KVM_REQ_ENABLE_IBS 23
135135
#define KVM_REQ_DISABLE_IBS 24
136136
#define KVM_REQ_APIC_PAGE_RELOAD 25
137+
#define KVM_REQ_SMI 26
137138

138139
#define KVM_USERSPACE_IRQ_SOURCE_ID 0
139140
#define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1

0 commit comments

Comments
 (0)