mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-09-21 03:43:03 +00:00
Merge branch 'kvm-updates/3.3' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Fixing a regression with the PMU MSRs when PMU virtualization is disabled, a guest-internal DoS with the SYSCALL instruction, and a dirty memory logging race that may cause live migration to fail. * 'kvm-updates/3.3' of git://git.kernel.org/pub/scm/virt/kvm/kvm: KVM: do not #GP on perf MSR writes when vPMU is disabled KVM: x86: fix missing checks in syscall emulation KVM: x86: extend "struct x86_emulate_ops" with "get_cpuid" KVM: Fix __set_bit() race in mark_page_dirty() during dirty logging
This commit is contained in:
commit
14fdbf7eb4
|
@ -190,6 +190,9 @@ struct x86_emulate_ops {
|
||||||
int (*intercept)(struct x86_emulate_ctxt *ctxt,
|
int (*intercept)(struct x86_emulate_ctxt *ctxt,
|
||||||
struct x86_instruction_info *info,
|
struct x86_instruction_info *info,
|
||||||
enum x86_intercept_stage stage);
|
enum x86_intercept_stage stage);
|
||||||
|
|
||||||
|
bool (*get_cpuid)(struct x86_emulate_ctxt *ctxt,
|
||||||
|
u32 *eax, u32 *ebx, u32 *ecx, u32 *edx);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef u32 __attribute__((vector_size(16))) sse128_t;
|
typedef u32 __attribute__((vector_size(16))) sse128_t;
|
||||||
|
@ -298,6 +301,19 @@ struct x86_emulate_ctxt {
|
||||||
#define X86EMUL_MODE_PROT (X86EMUL_MODE_PROT16|X86EMUL_MODE_PROT32| \
|
#define X86EMUL_MODE_PROT (X86EMUL_MODE_PROT16|X86EMUL_MODE_PROT32| \
|
||||||
X86EMUL_MODE_PROT64)
|
X86EMUL_MODE_PROT64)
|
||||||
|
|
||||||
|
/* CPUID vendors */
|
||||||
|
#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx 0x68747541
|
||||||
|
#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx 0x444d4163
|
||||||
|
#define X86EMUL_CPUID_VENDOR_AuthenticAMD_edx 0x69746e65
|
||||||
|
|
||||||
|
#define X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx 0x69444d41
|
||||||
|
#define X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx 0x21726574
|
||||||
|
#define X86EMUL_CPUID_VENDOR_AMDisbetterI_edx 0x74656273
|
||||||
|
|
||||||
|
#define X86EMUL_CPUID_VENDOR_GenuineIntel_ebx 0x756e6547
|
||||||
|
#define X86EMUL_CPUID_VENDOR_GenuineIntel_ecx 0x6c65746e
|
||||||
|
#define X86EMUL_CPUID_VENDOR_GenuineIntel_edx 0x49656e69
|
||||||
|
|
||||||
enum x86_intercept_stage {
|
enum x86_intercept_stage {
|
||||||
X86_ICTP_NONE = 0, /* Allow zero-init to not match anything */
|
X86_ICTP_NONE = 0, /* Allow zero-init to not match anything */
|
||||||
X86_ICPT_PRE_EXCEPT,
|
X86_ICPT_PRE_EXCEPT,
|
||||||
|
|
|
@ -1891,6 +1891,51 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
|
||||||
ss->p = 1;
|
ss->p = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool em_syscall_is_enabled(struct x86_emulate_ctxt *ctxt)
|
||||||
|
{
|
||||||
|
struct x86_emulate_ops *ops = ctxt->ops;
|
||||||
|
u32 eax, ebx, ecx, edx;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* syscall should always be enabled in longmode - so only become
|
||||||
|
* vendor specific (cpuid) if other modes are active...
|
||||||
|
*/
|
||||||
|
if (ctxt->mode == X86EMUL_MODE_PROT64)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
eax = 0x00000000;
|
||||||
|
ecx = 0x00000000;
|
||||||
|
if (ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx)) {
|
||||||
|
/*
|
||||||
|
* Intel ("GenuineIntel")
|
||||||
|
* remark: Intel CPUs only support "syscall" in 64bit
|
||||||
|
* longmode. Also an 64bit guest with a
|
||||||
|
* 32bit compat-app running will #UD !! While this
|
||||||
|
* behaviour can be fixed (by emulating) into AMD
|
||||||
|
* response - CPUs of AMD can't behave like Intel.
|
||||||
|
*/
|
||||||
|
if (ebx == X86EMUL_CPUID_VENDOR_GenuineIntel_ebx &&
|
||||||
|
ecx == X86EMUL_CPUID_VENDOR_GenuineIntel_ecx &&
|
||||||
|
edx == X86EMUL_CPUID_VENDOR_GenuineIntel_edx)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* AMD ("AuthenticAMD") */
|
||||||
|
if (ebx == X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx &&
|
||||||
|
ecx == X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx &&
|
||||||
|
edx == X86EMUL_CPUID_VENDOR_AuthenticAMD_edx)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* AMD ("AMDisbetter!") */
|
||||||
|
if (ebx == X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx &&
|
||||||
|
ecx == X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx &&
|
||||||
|
edx == X86EMUL_CPUID_VENDOR_AMDisbetterI_edx)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* default: (not Intel, not AMD), apply Intel's stricter rules... */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static int em_syscall(struct x86_emulate_ctxt *ctxt)
|
static int em_syscall(struct x86_emulate_ctxt *ctxt)
|
||||||
{
|
{
|
||||||
struct x86_emulate_ops *ops = ctxt->ops;
|
struct x86_emulate_ops *ops = ctxt->ops;
|
||||||
|
@ -1904,9 +1949,15 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt)
|
||||||
ctxt->mode == X86EMUL_MODE_VM86)
|
ctxt->mode == X86EMUL_MODE_VM86)
|
||||||
return emulate_ud(ctxt);
|
return emulate_ud(ctxt);
|
||||||
|
|
||||||
|
if (!(em_syscall_is_enabled(ctxt)))
|
||||||
|
return emulate_ud(ctxt);
|
||||||
|
|
||||||
ops->get_msr(ctxt, MSR_EFER, &efer);
|
ops->get_msr(ctxt, MSR_EFER, &efer);
|
||||||
setup_syscalls_segments(ctxt, &cs, &ss);
|
setup_syscalls_segments(ctxt, &cs, &ss);
|
||||||
|
|
||||||
|
if (!(efer & EFER_SCE))
|
||||||
|
return emulate_ud(ctxt);
|
||||||
|
|
||||||
ops->get_msr(ctxt, MSR_STAR, &msr_data);
|
ops->get_msr(ctxt, MSR_STAR, &msr_data);
|
||||||
msr_data >>= 32;
|
msr_data >>= 32;
|
||||||
cs_sel = (u16)(msr_data & 0xfffc);
|
cs_sel = (u16)(msr_data & 0xfffc);
|
||||||
|
|
|
@ -1495,6 +1495,8 @@ static void record_steal_time(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
|
int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
|
||||||
{
|
{
|
||||||
|
bool pr = false;
|
||||||
|
|
||||||
switch (msr) {
|
switch (msr) {
|
||||||
case MSR_EFER:
|
case MSR_EFER:
|
||||||
return set_efer(vcpu, data);
|
return set_efer(vcpu, data);
|
||||||
|
@ -1635,6 +1637,18 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
|
||||||
pr_unimpl(vcpu, "unimplemented perfctr wrmsr: "
|
pr_unimpl(vcpu, "unimplemented perfctr wrmsr: "
|
||||||
"0x%x data 0x%llx\n", msr, data);
|
"0x%x data 0x%llx\n", msr, data);
|
||||||
break;
|
break;
|
||||||
|
case MSR_P6_PERFCTR0:
|
||||||
|
case MSR_P6_PERFCTR1:
|
||||||
|
pr = true;
|
||||||
|
case MSR_P6_EVNTSEL0:
|
||||||
|
case MSR_P6_EVNTSEL1:
|
||||||
|
if (kvm_pmu_msr(vcpu, msr))
|
||||||
|
return kvm_pmu_set_msr(vcpu, msr, data);
|
||||||
|
|
||||||
|
if (pr || data != 0)
|
||||||
|
pr_unimpl(vcpu, "disabled perfctr wrmsr: "
|
||||||
|
"0x%x data 0x%llx\n", msr, data);
|
||||||
|
break;
|
||||||
case MSR_K7_CLK_CTL:
|
case MSR_K7_CLK_CTL:
|
||||||
/*
|
/*
|
||||||
* Ignore all writes to this no longer documented MSR.
|
* Ignore all writes to this no longer documented MSR.
|
||||||
|
@ -1835,6 +1849,14 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
|
||||||
case MSR_FAM10H_MMIO_CONF_BASE:
|
case MSR_FAM10H_MMIO_CONF_BASE:
|
||||||
data = 0;
|
data = 0;
|
||||||
break;
|
break;
|
||||||
|
case MSR_P6_PERFCTR0:
|
||||||
|
case MSR_P6_PERFCTR1:
|
||||||
|
case MSR_P6_EVNTSEL0:
|
||||||
|
case MSR_P6_EVNTSEL1:
|
||||||
|
if (kvm_pmu_msr(vcpu, msr))
|
||||||
|
return kvm_pmu_get_msr(vcpu, msr, pdata);
|
||||||
|
data = 0;
|
||||||
|
break;
|
||||||
case MSR_IA32_UCODE_REV:
|
case MSR_IA32_UCODE_REV:
|
||||||
data = 0x100000000ULL;
|
data = 0x100000000ULL;
|
||||||
break;
|
break;
|
||||||
|
@ -4180,6 +4202,28 @@ static int emulator_intercept(struct x86_emulate_ctxt *ctxt,
|
||||||
return kvm_x86_ops->check_intercept(emul_to_vcpu(ctxt), info, stage);
|
return kvm_x86_ops->check_intercept(emul_to_vcpu(ctxt), info, stage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool emulator_get_cpuid(struct x86_emulate_ctxt *ctxt,
|
||||||
|
u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
|
||||||
|
{
|
||||||
|
struct kvm_cpuid_entry2 *cpuid = NULL;
|
||||||
|
|
||||||
|
if (eax && ecx)
|
||||||
|
cpuid = kvm_find_cpuid_entry(emul_to_vcpu(ctxt),
|
||||||
|
*eax, *ecx);
|
||||||
|
|
||||||
|
if (cpuid) {
|
||||||
|
*eax = cpuid->eax;
|
||||||
|
*ecx = cpuid->ecx;
|
||||||
|
if (ebx)
|
||||||
|
*ebx = cpuid->ebx;
|
||||||
|
if (edx)
|
||||||
|
*edx = cpuid->edx;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static struct x86_emulate_ops emulate_ops = {
|
static struct x86_emulate_ops emulate_ops = {
|
||||||
.read_std = kvm_read_guest_virt_system,
|
.read_std = kvm_read_guest_virt_system,
|
||||||
.write_std = kvm_write_guest_virt_system,
|
.write_std = kvm_write_guest_virt_system,
|
||||||
|
@ -4211,6 +4255,7 @@ static struct x86_emulate_ops emulate_ops = {
|
||||||
.get_fpu = emulator_get_fpu,
|
.get_fpu = emulator_get_fpu,
|
||||||
.put_fpu = emulator_put_fpu,
|
.put_fpu = emulator_put_fpu,
|
||||||
.intercept = emulator_intercept,
|
.intercept = emulator_intercept,
|
||||||
|
.get_cpuid = emulator_get_cpuid,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void cache_all_regs(struct kvm_vcpu *vcpu)
|
static void cache_all_regs(struct kvm_vcpu *vcpu)
|
||||||
|
|
|
@ -1543,7 +1543,7 @@ void mark_page_dirty_in_slot(struct kvm *kvm, struct kvm_memory_slot *memslot,
|
||||||
if (memslot && memslot->dirty_bitmap) {
|
if (memslot && memslot->dirty_bitmap) {
|
||||||
unsigned long rel_gfn = gfn - memslot->base_gfn;
|
unsigned long rel_gfn = gfn - memslot->base_gfn;
|
||||||
|
|
||||||
if (!__test_and_set_bit_le(rel_gfn, memslot->dirty_bitmap))
|
if (!test_and_set_bit_le(rel_gfn, memslot->dirty_bitmap))
|
||||||
memslot->nr_dirty_pages++;
|
memslot->nr_dirty_pages++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue