|
@@ -38,6 +38,7 @@
|
|
#include <linux/intel-iommu.h>
|
|
#include <linux/intel-iommu.h>
|
|
#include <linux/cpufreq.h>
|
|
#include <linux/cpufreq.h>
|
|
#include <linux/user-return-notifier.h>
|
|
#include <linux/user-return-notifier.h>
|
|
|
|
+#include <linux/srcu.h>
|
|
#include <trace/events/kvm.h>
|
|
#include <trace/events/kvm.h>
|
|
#undef TRACE_INCLUDE_FILE
|
|
#undef TRACE_INCLUDE_FILE
|
|
#define CREATE_TRACE_POINTS
|
|
#define CREATE_TRACE_POINTS
|
|
@@ -93,16 +94,16 @@ module_param_named(ignore_msrs, ignore_msrs, bool, S_IRUGO | S_IWUSR);
|
|
|
|
|
|
struct kvm_shared_msrs_global {
|
|
struct kvm_shared_msrs_global {
|
|
int nr;
|
|
int nr;
|
|
- struct kvm_shared_msr {
|
|
|
|
- u32 msr;
|
|
|
|
- u64 value;
|
|
|
|
- } msrs[KVM_NR_SHARED_MSRS];
|
|
|
|
|
|
+ u32 msrs[KVM_NR_SHARED_MSRS];
|
|
};
|
|
};
|
|
|
|
|
|
struct kvm_shared_msrs {
|
|
struct kvm_shared_msrs {
|
|
struct user_return_notifier urn;
|
|
struct user_return_notifier urn;
|
|
bool registered;
|
|
bool registered;
|
|
- u64 current_value[KVM_NR_SHARED_MSRS];
|
|
|
|
|
|
+ struct kvm_shared_msr_values {
|
|
|
|
+ u64 host;
|
|
|
|
+ u64 curr;
|
|
|
|
+ } values[KVM_NR_SHARED_MSRS];
|
|
};
|
|
};
|
|
|
|
|
|
static struct kvm_shared_msrs_global __read_mostly shared_msrs_global;
|
|
static struct kvm_shared_msrs_global __read_mostly shared_msrs_global;
|
|
@@ -147,53 +148,64 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
|
|
static void kvm_on_user_return(struct user_return_notifier *urn)
|
|
static void kvm_on_user_return(struct user_return_notifier *urn)
|
|
{
|
|
{
|
|
unsigned slot;
|
|
unsigned slot;
|
|
- struct kvm_shared_msr *global;
|
|
|
|
struct kvm_shared_msrs *locals
|
|
struct kvm_shared_msrs *locals
|
|
= container_of(urn, struct kvm_shared_msrs, urn);
|
|
= container_of(urn, struct kvm_shared_msrs, urn);
|
|
|
|
+ struct kvm_shared_msr_values *values;
|
|
|
|
|
|
for (slot = 0; slot < shared_msrs_global.nr; ++slot) {
|
|
for (slot = 0; slot < shared_msrs_global.nr; ++slot) {
|
|
- global = &shared_msrs_global.msrs[slot];
|
|
|
|
- if (global->value != locals->current_value[slot]) {
|
|
|
|
- wrmsrl(global->msr, global->value);
|
|
|
|
- locals->current_value[slot] = global->value;
|
|
|
|
|
|
+ values = &locals->values[slot];
|
|
|
|
+ if (values->host != values->curr) {
|
|
|
|
+ wrmsrl(shared_msrs_global.msrs[slot], values->host);
|
|
|
|
+ values->curr = values->host;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
locals->registered = false;
|
|
locals->registered = false;
|
|
user_return_notifier_unregister(urn);
|
|
user_return_notifier_unregister(urn);
|
|
}
|
|
}
|
|
|
|
|
|
-void kvm_define_shared_msr(unsigned slot, u32 msr)
|
|
|
|
|
|
+static void shared_msr_update(unsigned slot, u32 msr)
|
|
{
|
|
{
|
|
- int cpu;
|
|
|
|
|
|
+ struct kvm_shared_msrs *smsr;
|
|
u64 value;
|
|
u64 value;
|
|
|
|
|
|
|
|
+ smsr = &__get_cpu_var(shared_msrs);
|
|
|
|
+ /* only read, and nobody should modify it at this time,
|
|
|
|
+ * so don't need lock */
|
|
|
|
+ if (slot >= shared_msrs_global.nr) {
|
|
|
|
+ printk(KERN_ERR "kvm: invalid MSR slot!");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ rdmsrl_safe(msr, &value);
|
|
|
|
+ smsr->values[slot].host = value;
|
|
|
|
+ smsr->values[slot].curr = value;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void kvm_define_shared_msr(unsigned slot, u32 msr)
|
|
|
|
+{
|
|
if (slot >= shared_msrs_global.nr)
|
|
if (slot >= shared_msrs_global.nr)
|
|
shared_msrs_global.nr = slot + 1;
|
|
shared_msrs_global.nr = slot + 1;
|
|
- shared_msrs_global.msrs[slot].msr = msr;
|
|
|
|
- rdmsrl_safe(msr, &value);
|
|
|
|
- shared_msrs_global.msrs[slot].value = value;
|
|
|
|
- for_each_online_cpu(cpu)
|
|
|
|
- per_cpu(shared_msrs, cpu).current_value[slot] = value;
|
|
|
|
|
|
+ shared_msrs_global.msrs[slot] = msr;
|
|
|
|
+ /* we need ensured the shared_msr_global have been updated */
|
|
|
|
+ smp_wmb();
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(kvm_define_shared_msr);
|
|
EXPORT_SYMBOL_GPL(kvm_define_shared_msr);
|
|
|
|
|
|
static void kvm_shared_msr_cpu_online(void)
|
|
static void kvm_shared_msr_cpu_online(void)
|
|
{
|
|
{
|
|
unsigned i;
|
|
unsigned i;
|
|
- struct kvm_shared_msrs *locals = &__get_cpu_var(shared_msrs);
|
|
|
|
|
|
|
|
for (i = 0; i < shared_msrs_global.nr; ++i)
|
|
for (i = 0; i < shared_msrs_global.nr; ++i)
|
|
- locals->current_value[i] = shared_msrs_global.msrs[i].value;
|
|
|
|
|
|
+ shared_msr_update(i, shared_msrs_global.msrs[i]);
|
|
}
|
|
}
|
|
|
|
|
|
void kvm_set_shared_msr(unsigned slot, u64 value, u64 mask)
|
|
void kvm_set_shared_msr(unsigned slot, u64 value, u64 mask)
|
|
{
|
|
{
|
|
struct kvm_shared_msrs *smsr = &__get_cpu_var(shared_msrs);
|
|
struct kvm_shared_msrs *smsr = &__get_cpu_var(shared_msrs);
|
|
|
|
|
|
- if (((value ^ smsr->current_value[slot]) & mask) == 0)
|
|
|
|
|
|
+ if (((value ^ smsr->values[slot].curr) & mask) == 0)
|
|
return;
|
|
return;
|
|
- smsr->current_value[slot] = value;
|
|
|
|
- wrmsrl(shared_msrs_global.msrs[slot].msr, value);
|
|
|
|
|
|
+ smsr->values[slot].curr = value;
|
|
|
|
+ wrmsrl(shared_msrs_global.msrs[slot], value);
|
|
if (!smsr->registered) {
|
|
if (!smsr->registered) {
|
|
smsr->urn.on_user_return = kvm_on_user_return;
|
|
smsr->urn.on_user_return = kvm_on_user_return;
|
|
user_return_notifier_register(&smsr->urn);
|
|
user_return_notifier_register(&smsr->urn);
|
|
@@ -257,12 +269,68 @@ void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(kvm_set_apic_base);
|
|
EXPORT_SYMBOL_GPL(kvm_set_apic_base);
|
|
|
|
|
|
|
|
+#define EXCPT_BENIGN 0
|
|
|
|
+#define EXCPT_CONTRIBUTORY 1
|
|
|
|
+#define EXCPT_PF 2
|
|
|
|
+
|
|
|
|
+static int exception_class(int vector)
|
|
|
|
+{
|
|
|
|
+ switch (vector) {
|
|
|
|
+ case PF_VECTOR:
|
|
|
|
+ return EXCPT_PF;
|
|
|
|
+ case DE_VECTOR:
|
|
|
|
+ case TS_VECTOR:
|
|
|
|
+ case NP_VECTOR:
|
|
|
|
+ case SS_VECTOR:
|
|
|
|
+ case GP_VECTOR:
|
|
|
|
+ return EXCPT_CONTRIBUTORY;
|
|
|
|
+ default:
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ return EXCPT_BENIGN;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
|
|
|
|
+ unsigned nr, bool has_error, u32 error_code)
|
|
|
|
+{
|
|
|
|
+ u32 prev_nr;
|
|
|
|
+ int class1, class2;
|
|
|
|
+
|
|
|
|
+ if (!vcpu->arch.exception.pending) {
|
|
|
|
+ queue:
|
|
|
|
+ vcpu->arch.exception.pending = true;
|
|
|
|
+ vcpu->arch.exception.has_error_code = has_error;
|
|
|
|
+ vcpu->arch.exception.nr = nr;
|
|
|
|
+ vcpu->arch.exception.error_code = error_code;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* to check exception */
|
|
|
|
+ prev_nr = vcpu->arch.exception.nr;
|
|
|
|
+ if (prev_nr == DF_VECTOR) {
|
|
|
|
+ /* triple fault -> shutdown */
|
|
|
|
+ set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ class1 = exception_class(prev_nr);
|
|
|
|
+ class2 = exception_class(nr);
|
|
|
|
+ if ((class1 == EXCPT_CONTRIBUTORY && class2 == EXCPT_CONTRIBUTORY)
|
|
|
|
+ || (class1 == EXCPT_PF && class2 != EXCPT_BENIGN)) {
|
|
|
|
+ /* generate double fault per SDM Table 5-5 */
|
|
|
|
+ vcpu->arch.exception.pending = true;
|
|
|
|
+ vcpu->arch.exception.has_error_code = true;
|
|
|
|
+ vcpu->arch.exception.nr = DF_VECTOR;
|
|
|
|
+ vcpu->arch.exception.error_code = 0;
|
|
|
|
+ } else
|
|
|
|
+ /* replace previous exception with a new one in a hope
|
|
|
|
+ that instruction re-execution will regenerate lost
|
|
|
|
+ exception */
|
|
|
|
+ goto queue;
|
|
|
|
+}
|
|
|
|
+
|
|
void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr)
|
|
void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr)
|
|
{
|
|
{
|
|
- WARN_ON(vcpu->arch.exception.pending);
|
|
|
|
- vcpu->arch.exception.pending = true;
|
|
|
|
- vcpu->arch.exception.has_error_code = false;
|
|
|
|
- vcpu->arch.exception.nr = nr;
|
|
|
|
|
|
+ kvm_multiple_exception(vcpu, nr, false, 0);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(kvm_queue_exception);
|
|
EXPORT_SYMBOL_GPL(kvm_queue_exception);
|
|
|
|
|
|
@@ -270,25 +338,6 @@ void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long addr,
|
|
u32 error_code)
|
|
u32 error_code)
|
|
{
|
|
{
|
|
++vcpu->stat.pf_guest;
|
|
++vcpu->stat.pf_guest;
|
|
-
|
|
|
|
- if (vcpu->arch.exception.pending) {
|
|
|
|
- switch(vcpu->arch.exception.nr) {
|
|
|
|
- case DF_VECTOR:
|
|
|
|
- /* triple fault -> shutdown */
|
|
|
|
- set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
|
|
|
|
- return;
|
|
|
|
- case PF_VECTOR:
|
|
|
|
- vcpu->arch.exception.nr = DF_VECTOR;
|
|
|
|
- vcpu->arch.exception.error_code = 0;
|
|
|
|
- return;
|
|
|
|
- default:
|
|
|
|
- /* replace previous exception with a new one in a hope
|
|
|
|
- that instruction re-execution will regenerate lost
|
|
|
|
- exception */
|
|
|
|
- vcpu->arch.exception.pending = false;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
vcpu->arch.cr2 = addr;
|
|
vcpu->arch.cr2 = addr;
|
|
kvm_queue_exception_e(vcpu, PF_VECTOR, error_code);
|
|
kvm_queue_exception_e(vcpu, PF_VECTOR, error_code);
|
|
}
|
|
}
|
|
@@ -301,11 +350,7 @@ EXPORT_SYMBOL_GPL(kvm_inject_nmi);
|
|
|
|
|
|
void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code)
|
|
void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code)
|
|
{
|
|
{
|
|
- WARN_ON(vcpu->arch.exception.pending);
|
|
|
|
- vcpu->arch.exception.pending = true;
|
|
|
|
- vcpu->arch.exception.has_error_code = true;
|
|
|
|
- vcpu->arch.exception.nr = nr;
|
|
|
|
- vcpu->arch.exception.error_code = error_code;
|
|
|
|
|
|
+ kvm_multiple_exception(vcpu, nr, true, error_code);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(kvm_queue_exception_e);
|
|
EXPORT_SYMBOL_GPL(kvm_queue_exception_e);
|
|
|
|
|
|
@@ -383,12 +428,18 @@ out:
|
|
|
|
|
|
void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
|
|
void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
|
|
{
|
|
{
|
|
- if (cr0 & CR0_RESERVED_BITS) {
|
|
|
|
|
|
+ cr0 |= X86_CR0_ET;
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_X86_64
|
|
|
|
+ if (cr0 & 0xffffffff00000000UL) {
|
|
printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n",
|
|
printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n",
|
|
- cr0, vcpu->arch.cr0);
|
|
|
|
|
|
+ cr0, kvm_read_cr0(vcpu));
|
|
kvm_inject_gp(vcpu, 0);
|
|
kvm_inject_gp(vcpu, 0);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ cr0 &= ~CR0_RESERVED_BITS;
|
|
|
|
|
|
if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD)) {
|
|
if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD)) {
|
|
printk(KERN_DEBUG "set_cr0: #GP, CD == 0 && NW == 1\n");
|
|
printk(KERN_DEBUG "set_cr0: #GP, CD == 0 && NW == 1\n");
|
|
@@ -405,7 +456,7 @@ void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
|
|
|
|
|
|
if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) {
|
|
if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) {
|
|
#ifdef CONFIG_X86_64
|
|
#ifdef CONFIG_X86_64
|
|
- if ((vcpu->arch.shadow_efer & EFER_LME)) {
|
|
|
|
|
|
+ if ((vcpu->arch.efer & EFER_LME)) {
|
|
int cs_db, cs_l;
|
|
int cs_db, cs_l;
|
|
|
|
|
|
if (!is_pae(vcpu)) {
|
|
if (!is_pae(vcpu)) {
|
|
@@ -443,13 +494,13 @@ EXPORT_SYMBOL_GPL(kvm_set_cr0);
|
|
|
|
|
|
void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
|
|
void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
|
|
{
|
|
{
|
|
- kvm_set_cr0(vcpu, (vcpu->arch.cr0 & ~0x0ful) | (msw & 0x0f));
|
|
|
|
|
|
+ kvm_set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~0x0ful) | (msw & 0x0f));
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(kvm_lmsw);
|
|
EXPORT_SYMBOL_GPL(kvm_lmsw);
|
|
|
|
|
|
void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
|
|
void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
|
|
{
|
|
{
|
|
- unsigned long old_cr4 = vcpu->arch.cr4;
|
|
|
|
|
|
+ unsigned long old_cr4 = kvm_read_cr4(vcpu);
|
|
unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE;
|
|
unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE;
|
|
|
|
|
|
if (cr4 & CR4_RESERVED_BITS) {
|
|
if (cr4 & CR4_RESERVED_BITS) {
|
|
@@ -575,9 +626,11 @@ static inline u32 bit(int bitno)
|
|
* kvm-specific. Those are put in the beginning of the list.
|
|
* kvm-specific. Those are put in the beginning of the list.
|
|
*/
|
|
*/
|
|
|
|
|
|
-#define KVM_SAVE_MSRS_BEGIN 2
|
|
|
|
|
|
+#define KVM_SAVE_MSRS_BEGIN 5
|
|
static u32 msrs_to_save[] = {
|
|
static u32 msrs_to_save[] = {
|
|
MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
|
|
MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
|
|
|
|
+ HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL,
|
|
|
|
+ HV_X64_MSR_APIC_ASSIST_PAGE,
|
|
MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
|
|
MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
|
|
MSR_K6_STAR,
|
|
MSR_K6_STAR,
|
|
#ifdef CONFIG_X86_64
|
|
#ifdef CONFIG_X86_64
|
|
@@ -602,7 +655,7 @@ static void set_efer(struct kvm_vcpu *vcpu, u64 efer)
|
|
}
|
|
}
|
|
|
|
|
|
if (is_paging(vcpu)
|
|
if (is_paging(vcpu)
|
|
- && (vcpu->arch.shadow_efer & EFER_LME) != (efer & EFER_LME)) {
|
|
|
|
|
|
+ && (vcpu->arch.efer & EFER_LME) != (efer & EFER_LME)) {
|
|
printk(KERN_DEBUG "set_efer: #GP, change LME while paging\n");
|
|
printk(KERN_DEBUG "set_efer: #GP, change LME while paging\n");
|
|
kvm_inject_gp(vcpu, 0);
|
|
kvm_inject_gp(vcpu, 0);
|
|
return;
|
|
return;
|
|
@@ -633,9 +686,9 @@ static void set_efer(struct kvm_vcpu *vcpu, u64 efer)
|
|
kvm_x86_ops->set_efer(vcpu, efer);
|
|
kvm_x86_ops->set_efer(vcpu, efer);
|
|
|
|
|
|
efer &= ~EFER_LMA;
|
|
efer &= ~EFER_LMA;
|
|
- efer |= vcpu->arch.shadow_efer & EFER_LMA;
|
|
|
|
|
|
+ efer |= vcpu->arch.efer & EFER_LMA;
|
|
|
|
|
|
- vcpu->arch.shadow_efer = efer;
|
|
|
|
|
|
+ vcpu->arch.efer = efer;
|
|
|
|
|
|
vcpu->arch.mmu.base_role.nxe = (efer & EFER_NX) && !tdp_enabled;
|
|
vcpu->arch.mmu.base_role.nxe = (efer & EFER_NX) && !tdp_enabled;
|
|
kvm_mmu_reset_context(vcpu);
|
|
kvm_mmu_reset_context(vcpu);
|
|
@@ -957,6 +1010,100 @@ out:
|
|
return r;
|
|
return r;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static bool kvm_hv_hypercall_enabled(struct kvm *kvm)
|
|
|
|
+{
|
|
|
|
+ return kvm->arch.hv_hypercall & HV_X64_MSR_HYPERCALL_ENABLE;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static bool kvm_hv_msr_partition_wide(u32 msr)
|
|
|
|
+{
|
|
|
|
+ bool r = false;
|
|
|
|
+ switch (msr) {
|
|
|
|
+ case HV_X64_MSR_GUEST_OS_ID:
|
|
|
|
+ case HV_X64_MSR_HYPERCALL:
|
|
|
|
+ r = true;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return r;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int set_msr_hyperv_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data)
|
|
|
|
+{
|
|
|
|
+ struct kvm *kvm = vcpu->kvm;
|
|
|
|
+
|
|
|
|
+ switch (msr) {
|
|
|
|
+ case HV_X64_MSR_GUEST_OS_ID:
|
|
|
|
+ kvm->arch.hv_guest_os_id = data;
|
|
|
|
+ /* setting guest os id to zero disables hypercall page */
|
|
|
|
+ if (!kvm->arch.hv_guest_os_id)
|
|
|
|
+ kvm->arch.hv_hypercall &= ~HV_X64_MSR_HYPERCALL_ENABLE;
|
|
|
|
+ break;
|
|
|
|
+ case HV_X64_MSR_HYPERCALL: {
|
|
|
|
+ u64 gfn;
|
|
|
|
+ unsigned long addr;
|
|
|
|
+ u8 instructions[4];
|
|
|
|
+
|
|
|
|
+ /* if guest os id is not set hypercall should remain disabled */
|
|
|
|
+ if (!kvm->arch.hv_guest_os_id)
|
|
|
|
+ break;
|
|
|
|
+ if (!(data & HV_X64_MSR_HYPERCALL_ENABLE)) {
|
|
|
|
+ kvm->arch.hv_hypercall = data;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ gfn = data >> HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT;
|
|
|
|
+ addr = gfn_to_hva(kvm, gfn);
|
|
|
|
+ if (kvm_is_error_hva(addr))
|
|
|
|
+ return 1;
|
|
|
|
+ kvm_x86_ops->patch_hypercall(vcpu, instructions);
|
|
|
|
+ ((unsigned char *)instructions)[3] = 0xc3; /* ret */
|
|
|
|
+ if (copy_to_user((void __user *)addr, instructions, 4))
|
|
|
|
+ return 1;
|
|
|
|
+ kvm->arch.hv_hypercall = data;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ default:
|
|
|
|
+ pr_unimpl(vcpu, "HYPER-V unimplemented wrmsr: 0x%x "
|
|
|
|
+ "data 0x%llx\n", msr, data);
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int set_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 data)
|
|
|
|
+{
|
|
|
|
+ switch (msr) {
|
|
|
|
+ case HV_X64_MSR_APIC_ASSIST_PAGE: {
|
|
|
|
+ unsigned long addr;
|
|
|
|
+
|
|
|
|
+ if (!(data & HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE)) {
|
|
|
|
+ vcpu->arch.hv_vapic = data;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ addr = gfn_to_hva(vcpu->kvm, data >>
|
|
|
|
+ HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT);
|
|
|
|
+ if (kvm_is_error_hva(addr))
|
|
|
|
+ return 1;
|
|
|
|
+ if (clear_user((void __user *)addr, PAGE_SIZE))
|
|
|
|
+ return 1;
|
|
|
|
+ vcpu->arch.hv_vapic = data;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ case HV_X64_MSR_EOI:
|
|
|
|
+ return kvm_hv_vapic_msr_write(vcpu, APIC_EOI, data);
|
|
|
|
+ case HV_X64_MSR_ICR:
|
|
|
|
+ return kvm_hv_vapic_msr_write(vcpu, APIC_ICR, data);
|
|
|
|
+ case HV_X64_MSR_TPR:
|
|
|
|
+ return kvm_hv_vapic_msr_write(vcpu, APIC_TASKPRI, data);
|
|
|
|
+ default:
|
|
|
|
+ pr_unimpl(vcpu, "HYPER-V unimplemented wrmsr: 0x%x "
|
|
|
|
+ "data 0x%llx\n", msr, data);
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
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)
|
|
{
|
|
{
|
|
switch (msr) {
|
|
switch (msr) {
|
|
@@ -1071,6 +1218,16 @@ 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 HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
|
|
|
|
+ if (kvm_hv_msr_partition_wide(msr)) {
|
|
|
|
+ int r;
|
|
|
|
+ mutex_lock(&vcpu->kvm->lock);
|
|
|
|
+ r = set_msr_hyperv_pw(vcpu, msr, data);
|
|
|
|
+ mutex_unlock(&vcpu->kvm->lock);
|
|
|
|
+ return r;
|
|
|
|
+ } else
|
|
|
|
+ return set_msr_hyperv(vcpu, msr, data);
|
|
|
|
+ break;
|
|
default:
|
|
default:
|
|
if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr))
|
|
if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr))
|
|
return xen_hvm_config(vcpu, data);
|
|
return xen_hvm_config(vcpu, data);
|
|
@@ -1170,6 +1327,54 @@ static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int get_msr_hyperv_pw(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
|
|
|
|
+{
|
|
|
|
+ u64 data = 0;
|
|
|
|
+ struct kvm *kvm = vcpu->kvm;
|
|
|
|
+
|
|
|
|
+ switch (msr) {
|
|
|
|
+ case HV_X64_MSR_GUEST_OS_ID:
|
|
|
|
+ data = kvm->arch.hv_guest_os_id;
|
|
|
|
+ break;
|
|
|
|
+ case HV_X64_MSR_HYPERCALL:
|
|
|
|
+ data = kvm->arch.hv_hypercall;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ pr_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ *pdata = data;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int get_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
|
|
|
|
+{
|
|
|
|
+ u64 data = 0;
|
|
|
|
+
|
|
|
|
+ switch (msr) {
|
|
|
|
+ case HV_X64_MSR_VP_INDEX: {
|
|
|
|
+ int r;
|
|
|
|
+ struct kvm_vcpu *v;
|
|
|
|
+ kvm_for_each_vcpu(r, v, vcpu->kvm)
|
|
|
|
+ if (v == vcpu)
|
|
|
|
+ data = r;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ case HV_X64_MSR_EOI:
|
|
|
|
+ return kvm_hv_vapic_msr_read(vcpu, APIC_EOI, pdata);
|
|
|
|
+ case HV_X64_MSR_ICR:
|
|
|
|
+ return kvm_hv_vapic_msr_read(vcpu, APIC_ICR, pdata);
|
|
|
|
+ case HV_X64_MSR_TPR:
|
|
|
|
+ return kvm_hv_vapic_msr_read(vcpu, APIC_TASKPRI, pdata);
|
|
|
|
+ default:
|
|
|
|
+ pr_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+ *pdata = data;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
|
|
int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
|
|
{
|
|
{
|
|
u64 data;
|
|
u64 data;
|
|
@@ -1221,7 +1426,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
|
|
data |= (((uint64_t)4ULL) << 40);
|
|
data |= (((uint64_t)4ULL) << 40);
|
|
break;
|
|
break;
|
|
case MSR_EFER:
|
|
case MSR_EFER:
|
|
- data = vcpu->arch.shadow_efer;
|
|
|
|
|
|
+ data = vcpu->arch.efer;
|
|
break;
|
|
break;
|
|
case MSR_KVM_WALL_CLOCK:
|
|
case MSR_KVM_WALL_CLOCK:
|
|
data = vcpu->kvm->arch.wall_clock;
|
|
data = vcpu->kvm->arch.wall_clock;
|
|
@@ -1236,6 +1441,16 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
|
|
case MSR_IA32_MCG_STATUS:
|
|
case MSR_IA32_MCG_STATUS:
|
|
case MSR_IA32_MC0_CTL ... MSR_IA32_MC0_CTL + 4 * KVM_MAX_MCE_BANKS - 1:
|
|
case MSR_IA32_MC0_CTL ... MSR_IA32_MC0_CTL + 4 * KVM_MAX_MCE_BANKS - 1:
|
|
return get_msr_mce(vcpu, msr, pdata);
|
|
return get_msr_mce(vcpu, msr, pdata);
|
|
|
|
+ case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
|
|
|
|
+ if (kvm_hv_msr_partition_wide(msr)) {
|
|
|
|
+ int r;
|
|
|
|
+ mutex_lock(&vcpu->kvm->lock);
|
|
|
|
+ r = get_msr_hyperv_pw(vcpu, msr, pdata);
|
|
|
|
+ mutex_unlock(&vcpu->kvm->lock);
|
|
|
|
+ return r;
|
|
|
|
+ } else
|
|
|
|
+ return get_msr_hyperv(vcpu, msr, pdata);
|
|
|
|
+ break;
|
|
default:
|
|
default:
|
|
if (!ignore_msrs) {
|
|
if (!ignore_msrs) {
|
|
pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr);
|
|
pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr);
|
|
@@ -1261,15 +1476,15 @@ static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs,
|
|
int (*do_msr)(struct kvm_vcpu *vcpu,
|
|
int (*do_msr)(struct kvm_vcpu *vcpu,
|
|
unsigned index, u64 *data))
|
|
unsigned index, u64 *data))
|
|
{
|
|
{
|
|
- int i;
|
|
|
|
|
|
+ int i, idx;
|
|
|
|
|
|
vcpu_load(vcpu);
|
|
vcpu_load(vcpu);
|
|
|
|
|
|
- down_read(&vcpu->kvm->slots_lock);
|
|
|
|
|
|
+ idx = srcu_read_lock(&vcpu->kvm->srcu);
|
|
for (i = 0; i < msrs->nmsrs; ++i)
|
|
for (i = 0; i < msrs->nmsrs; ++i)
|
|
if (do_msr(vcpu, entries[i].index, &entries[i].data))
|
|
if (do_msr(vcpu, entries[i].index, &entries[i].data))
|
|
break;
|
|
break;
|
|
- up_read(&vcpu->kvm->slots_lock);
|
|
|
|
|
|
+ srcu_read_unlock(&vcpu->kvm->srcu, idx);
|
|
|
|
|
|
vcpu_put(vcpu);
|
|
vcpu_put(vcpu);
|
|
|
|
|
|
@@ -1351,6 +1566,11 @@ int kvm_dev_ioctl_check_extension(long ext)
|
|
case KVM_CAP_XEN_HVM:
|
|
case KVM_CAP_XEN_HVM:
|
|
case KVM_CAP_ADJUST_CLOCK:
|
|
case KVM_CAP_ADJUST_CLOCK:
|
|
case KVM_CAP_VCPU_EVENTS:
|
|
case KVM_CAP_VCPU_EVENTS:
|
|
|
|
+ case KVM_CAP_HYPERV:
|
|
|
|
+ case KVM_CAP_HYPERV_VAPIC:
|
|
|
|
+ case KVM_CAP_HYPERV_SPIN:
|
|
|
|
+ case KVM_CAP_PCI_SEGMENT:
|
|
|
|
+ case KVM_CAP_X86_ROBUST_SINGLESTEP:
|
|
r = 1;
|
|
r = 1;
|
|
break;
|
|
break;
|
|
case KVM_CAP_COALESCED_MMIO:
|
|
case KVM_CAP_COALESCED_MMIO:
|
|
@@ -1464,8 +1684,8 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
|
|
|
|
|
|
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
|
|
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
- kvm_x86_ops->vcpu_put(vcpu);
|
|
|
|
kvm_put_guest_fpu(vcpu);
|
|
kvm_put_guest_fpu(vcpu);
|
|
|
|
+ kvm_x86_ops->vcpu_put(vcpu);
|
|
}
|
|
}
|
|
|
|
|
|
static int is_efer_nx(void)
|
|
static int is_efer_nx(void)
|
|
@@ -1530,6 +1750,7 @@ static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
|
|
cpuid_fix_nx_cap(vcpu);
|
|
cpuid_fix_nx_cap(vcpu);
|
|
r = 0;
|
|
r = 0;
|
|
kvm_apic_set_version(vcpu);
|
|
kvm_apic_set_version(vcpu);
|
|
|
|
+ kvm_x86_ops->cpuid_update(vcpu);
|
|
|
|
|
|
out_free:
|
|
out_free:
|
|
vfree(cpuid_entries);
|
|
vfree(cpuid_entries);
|
|
@@ -1552,6 +1773,7 @@ static int kvm_vcpu_ioctl_set_cpuid2(struct kvm_vcpu *vcpu,
|
|
goto out;
|
|
goto out;
|
|
vcpu->arch.cpuid_nent = cpuid->nent;
|
|
vcpu->arch.cpuid_nent = cpuid->nent;
|
|
kvm_apic_set_version(vcpu);
|
|
kvm_apic_set_version(vcpu);
|
|
|
|
+ kvm_x86_ops->cpuid_update(vcpu);
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
out:
|
|
out:
|
|
@@ -1594,12 +1816,15 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
|
|
u32 index, int *nent, int maxnent)
|
|
u32 index, int *nent, int maxnent)
|
|
{
|
|
{
|
|
unsigned f_nx = is_efer_nx() ? F(NX) : 0;
|
|
unsigned f_nx = is_efer_nx() ? F(NX) : 0;
|
|
- unsigned f_gbpages = kvm_x86_ops->gb_page_enable() ? F(GBPAGES) : 0;
|
|
|
|
#ifdef CONFIG_X86_64
|
|
#ifdef CONFIG_X86_64
|
|
|
|
+ unsigned f_gbpages = (kvm_x86_ops->get_lpage_level() == PT_PDPE_LEVEL)
|
|
|
|
+ ? F(GBPAGES) : 0;
|
|
unsigned f_lm = F(LM);
|
|
unsigned f_lm = F(LM);
|
|
#else
|
|
#else
|
|
|
|
+ unsigned f_gbpages = 0;
|
|
unsigned f_lm = 0;
|
|
unsigned f_lm = 0;
|
|
#endif
|
|
#endif
|
|
|
|
+ unsigned f_rdtscp = kvm_x86_ops->rdtscp_supported() ? F(RDTSCP) : 0;
|
|
|
|
|
|
/* cpuid 1.edx */
|
|
/* cpuid 1.edx */
|
|
const u32 kvm_supported_word0_x86_features =
|
|
const u32 kvm_supported_word0_x86_features =
|
|
@@ -1619,7 +1844,7 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
|
|
F(MTRR) | F(PGE) | F(MCA) | F(CMOV) |
|
|
F(MTRR) | F(PGE) | F(MCA) | F(CMOV) |
|
|
F(PAT) | F(PSE36) | 0 /* Reserved */ |
|
|
F(PAT) | F(PSE36) | 0 /* Reserved */ |
|
|
f_nx | 0 /* Reserved */ | F(MMXEXT) | F(MMX) |
|
|
f_nx | 0 /* Reserved */ | F(MMXEXT) | F(MMX) |
|
|
- F(FXSR) | F(FXSR_OPT) | f_gbpages | 0 /* RDTSCP */ |
|
|
|
|
|
|
+ F(FXSR) | F(FXSR_OPT) | f_gbpages | f_rdtscp |
|
|
0 /* Reserved */ | f_lm | F(3DNOWEXT) | F(3DNOW);
|
|
0 /* Reserved */ | f_lm | F(3DNOWEXT) | F(3DNOW);
|
|
/* cpuid 1.ecx */
|
|
/* cpuid 1.ecx */
|
|
const u32 kvm_supported_word4_x86_features =
|
|
const u32 kvm_supported_word4_x86_features =
|
|
@@ -1866,7 +2091,7 @@ static int kvm_vcpu_ioctl_x86_set_mce(struct kvm_vcpu *vcpu,
|
|
return 0;
|
|
return 0;
|
|
if (mce->status & MCI_STATUS_UC) {
|
|
if (mce->status & MCI_STATUS_UC) {
|
|
if ((vcpu->arch.mcg_status & MCG_STATUS_MCIP) ||
|
|
if ((vcpu->arch.mcg_status & MCG_STATUS_MCIP) ||
|
|
- !(vcpu->arch.cr4 & X86_CR4_MCE)) {
|
|
|
|
|
|
+ !kvm_read_cr4_bits(vcpu, X86_CR4_MCE)) {
|
|
printk(KERN_DEBUG "kvm: set_mce: "
|
|
printk(KERN_DEBUG "kvm: set_mce: "
|
|
"injects mce exception while "
|
|
"injects mce exception while "
|
|
"previous one is in progress!\n");
|
|
"previous one is in progress!\n");
|
|
@@ -2160,14 +2385,14 @@ static int kvm_vm_ioctl_set_nr_mmu_pages(struct kvm *kvm,
|
|
if (kvm_nr_mmu_pages < KVM_MIN_ALLOC_MMU_PAGES)
|
|
if (kvm_nr_mmu_pages < KVM_MIN_ALLOC_MMU_PAGES)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
- down_write(&kvm->slots_lock);
|
|
|
|
|
|
+ mutex_lock(&kvm->slots_lock);
|
|
spin_lock(&kvm->mmu_lock);
|
|
spin_lock(&kvm->mmu_lock);
|
|
|
|
|
|
kvm_mmu_change_mmu_pages(kvm, kvm_nr_mmu_pages);
|
|
kvm_mmu_change_mmu_pages(kvm, kvm_nr_mmu_pages);
|
|
kvm->arch.n_requested_mmu_pages = kvm_nr_mmu_pages;
|
|
kvm->arch.n_requested_mmu_pages = kvm_nr_mmu_pages;
|
|
|
|
|
|
spin_unlock(&kvm->mmu_lock);
|
|
spin_unlock(&kvm->mmu_lock);
|
|
- up_write(&kvm->slots_lock);
|
|
|
|
|
|
+ mutex_unlock(&kvm->slots_lock);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2176,13 +2401,35 @@ static int kvm_vm_ioctl_get_nr_mmu_pages(struct kvm *kvm)
|
|
return kvm->arch.n_alloc_mmu_pages;
|
|
return kvm->arch.n_alloc_mmu_pages;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+gfn_t unalias_gfn_instantiation(struct kvm *kvm, gfn_t gfn)
|
|
|
|
+{
|
|
|
|
+ int i;
|
|
|
|
+ struct kvm_mem_alias *alias;
|
|
|
|
+ struct kvm_mem_aliases *aliases;
|
|
|
|
+
|
|
|
|
+ aliases = rcu_dereference(kvm->arch.aliases);
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < aliases->naliases; ++i) {
|
|
|
|
+ alias = &aliases->aliases[i];
|
|
|
|
+ if (alias->flags & KVM_ALIAS_INVALID)
|
|
|
|
+ continue;
|
|
|
|
+ if (gfn >= alias->base_gfn
|
|
|
|
+ && gfn < alias->base_gfn + alias->npages)
|
|
|
|
+ return alias->target_gfn + gfn - alias->base_gfn;
|
|
|
|
+ }
|
|
|
|
+ return gfn;
|
|
|
|
+}
|
|
|
|
+
|
|
gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
|
|
gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
|
|
{
|
|
{
|
|
int i;
|
|
int i;
|
|
struct kvm_mem_alias *alias;
|
|
struct kvm_mem_alias *alias;
|
|
|
|
+ struct kvm_mem_aliases *aliases;
|
|
|
|
|
|
- for (i = 0; i < kvm->arch.naliases; ++i) {
|
|
|
|
- alias = &kvm->arch.aliases[i];
|
|
|
|
|
|
+ aliases = rcu_dereference(kvm->arch.aliases);
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < aliases->naliases; ++i) {
|
|
|
|
+ alias = &aliases->aliases[i];
|
|
if (gfn >= alias->base_gfn
|
|
if (gfn >= alias->base_gfn
|
|
&& gfn < alias->base_gfn + alias->npages)
|
|
&& gfn < alias->base_gfn + alias->npages)
|
|
return alias->target_gfn + gfn - alias->base_gfn;
|
|
return alias->target_gfn + gfn - alias->base_gfn;
|
|
@@ -2200,6 +2447,7 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
|
|
{
|
|
{
|
|
int r, n;
|
|
int r, n;
|
|
struct kvm_mem_alias *p;
|
|
struct kvm_mem_alias *p;
|
|
|
|
+ struct kvm_mem_aliases *aliases, *old_aliases;
|
|
|
|
|
|
r = -EINVAL;
|
|
r = -EINVAL;
|
|
/* General sanity checks */
|
|
/* General sanity checks */
|
|
@@ -2216,26 +2464,48 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
|
|
< alias->target_phys_addr)
|
|
< alias->target_phys_addr)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
- down_write(&kvm->slots_lock);
|
|
|
|
- spin_lock(&kvm->mmu_lock);
|
|
|
|
|
|
+ r = -ENOMEM;
|
|
|
|
+ aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL);
|
|
|
|
+ if (!aliases)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ mutex_lock(&kvm->slots_lock);
|
|
|
|
|
|
- p = &kvm->arch.aliases[alias->slot];
|
|
|
|
|
|
+ /* invalidate any gfn reference in case of deletion/shrinking */
|
|
|
|
+ memcpy(aliases, kvm->arch.aliases, sizeof(struct kvm_mem_aliases));
|
|
|
|
+ aliases->aliases[alias->slot].flags |= KVM_ALIAS_INVALID;
|
|
|
|
+ old_aliases = kvm->arch.aliases;
|
|
|
|
+ rcu_assign_pointer(kvm->arch.aliases, aliases);
|
|
|
|
+ synchronize_srcu_expedited(&kvm->srcu);
|
|
|
|
+ kvm_mmu_zap_all(kvm);
|
|
|
|
+ kfree(old_aliases);
|
|
|
|
+
|
|
|
|
+ r = -ENOMEM;
|
|
|
|
+ aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL);
|
|
|
|
+ if (!aliases)
|
|
|
|
+ goto out_unlock;
|
|
|
|
+
|
|
|
|
+ memcpy(aliases, kvm->arch.aliases, sizeof(struct kvm_mem_aliases));
|
|
|
|
+
|
|
|
|
+ p = &aliases->aliases[alias->slot];
|
|
p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT;
|
|
p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT;
|
|
p->npages = alias->memory_size >> PAGE_SHIFT;
|
|
p->npages = alias->memory_size >> PAGE_SHIFT;
|
|
p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT;
|
|
p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT;
|
|
|
|
+ p->flags &= ~(KVM_ALIAS_INVALID);
|
|
|
|
|
|
for (n = KVM_ALIAS_SLOTS; n > 0; --n)
|
|
for (n = KVM_ALIAS_SLOTS; n > 0; --n)
|
|
- if (kvm->arch.aliases[n - 1].npages)
|
|
|
|
|
|
+ if (aliases->aliases[n - 1].npages)
|
|
break;
|
|
break;
|
|
- kvm->arch.naliases = n;
|
|
|
|
|
|
+ aliases->naliases = n;
|
|
|
|
|
|
- spin_unlock(&kvm->mmu_lock);
|
|
|
|
- kvm_mmu_zap_all(kvm);
|
|
|
|
-
|
|
|
|
- up_write(&kvm->slots_lock);
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
|
|
+ old_aliases = kvm->arch.aliases;
|
|
|
|
+ rcu_assign_pointer(kvm->arch.aliases, aliases);
|
|
|
|
+ synchronize_srcu_expedited(&kvm->srcu);
|
|
|
|
+ kfree(old_aliases);
|
|
|
|
+ r = 0;
|
|
|
|
|
|
|
|
+out_unlock:
|
|
|
|
+ mutex_unlock(&kvm->slots_lock);
|
|
out:
|
|
out:
|
|
return r;
|
|
return r;
|
|
}
|
|
}
|
|
@@ -2273,18 +2543,18 @@ static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
|
|
r = 0;
|
|
r = 0;
|
|
switch (chip->chip_id) {
|
|
switch (chip->chip_id) {
|
|
case KVM_IRQCHIP_PIC_MASTER:
|
|
case KVM_IRQCHIP_PIC_MASTER:
|
|
- spin_lock(&pic_irqchip(kvm)->lock);
|
|
|
|
|
|
+ raw_spin_lock(&pic_irqchip(kvm)->lock);
|
|
memcpy(&pic_irqchip(kvm)->pics[0],
|
|
memcpy(&pic_irqchip(kvm)->pics[0],
|
|
&chip->chip.pic,
|
|
&chip->chip.pic,
|
|
sizeof(struct kvm_pic_state));
|
|
sizeof(struct kvm_pic_state));
|
|
- spin_unlock(&pic_irqchip(kvm)->lock);
|
|
|
|
|
|
+ raw_spin_unlock(&pic_irqchip(kvm)->lock);
|
|
break;
|
|
break;
|
|
case KVM_IRQCHIP_PIC_SLAVE:
|
|
case KVM_IRQCHIP_PIC_SLAVE:
|
|
- spin_lock(&pic_irqchip(kvm)->lock);
|
|
|
|
|
|
+ raw_spin_lock(&pic_irqchip(kvm)->lock);
|
|
memcpy(&pic_irqchip(kvm)->pics[1],
|
|
memcpy(&pic_irqchip(kvm)->pics[1],
|
|
&chip->chip.pic,
|
|
&chip->chip.pic,
|
|
sizeof(struct kvm_pic_state));
|
|
sizeof(struct kvm_pic_state));
|
|
- spin_unlock(&pic_irqchip(kvm)->lock);
|
|
|
|
|
|
+ raw_spin_unlock(&pic_irqchip(kvm)->lock);
|
|
break;
|
|
break;
|
|
case KVM_IRQCHIP_IOAPIC:
|
|
case KVM_IRQCHIP_IOAPIC:
|
|
r = kvm_set_ioapic(kvm, &chip->chip.ioapic);
|
|
r = kvm_set_ioapic(kvm, &chip->chip.ioapic);
|
|
@@ -2364,29 +2634,62 @@ static int kvm_vm_ioctl_reinject(struct kvm *kvm,
|
|
int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
|
|
int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
|
|
struct kvm_dirty_log *log)
|
|
struct kvm_dirty_log *log)
|
|
{
|
|
{
|
|
- int r;
|
|
|
|
- int n;
|
|
|
|
|
|
+ int r, n, i;
|
|
struct kvm_memory_slot *memslot;
|
|
struct kvm_memory_slot *memslot;
|
|
- int is_dirty = 0;
|
|
|
|
|
|
+ unsigned long is_dirty = 0;
|
|
|
|
+ unsigned long *dirty_bitmap = NULL;
|
|
|
|
|
|
- down_write(&kvm->slots_lock);
|
|
|
|
|
|
+ mutex_lock(&kvm->slots_lock);
|
|
|
|
|
|
- r = kvm_get_dirty_log(kvm, log, &is_dirty);
|
|
|
|
- if (r)
|
|
|
|
|
|
+ r = -EINVAL;
|
|
|
|
+ if (log->slot >= KVM_MEMORY_SLOTS)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ memslot = &kvm->memslots->memslots[log->slot];
|
|
|
|
+ r = -ENOENT;
|
|
|
|
+ if (!memslot->dirty_bitmap)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
|
|
|
|
+
|
|
|
|
+ r = -ENOMEM;
|
|
|
|
+ dirty_bitmap = vmalloc(n);
|
|
|
|
+ if (!dirty_bitmap)
|
|
goto out;
|
|
goto out;
|
|
|
|
+ memset(dirty_bitmap, 0, n);
|
|
|
|
+
|
|
|
|
+ for (i = 0; !is_dirty && i < n/sizeof(long); i++)
|
|
|
|
+ is_dirty = memslot->dirty_bitmap[i];
|
|
|
|
|
|
/* If nothing is dirty, don't bother messing with page tables. */
|
|
/* If nothing is dirty, don't bother messing with page tables. */
|
|
if (is_dirty) {
|
|
if (is_dirty) {
|
|
|
|
+ struct kvm_memslots *slots, *old_slots;
|
|
|
|
+
|
|
spin_lock(&kvm->mmu_lock);
|
|
spin_lock(&kvm->mmu_lock);
|
|
kvm_mmu_slot_remove_write_access(kvm, log->slot);
|
|
kvm_mmu_slot_remove_write_access(kvm, log->slot);
|
|
spin_unlock(&kvm->mmu_lock);
|
|
spin_unlock(&kvm->mmu_lock);
|
|
- memslot = &kvm->memslots[log->slot];
|
|
|
|
- n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
|
|
|
|
- memset(memslot->dirty_bitmap, 0, n);
|
|
|
|
|
|
+
|
|
|
|
+ slots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
|
|
|
|
+ if (!slots)
|
|
|
|
+ goto out_free;
|
|
|
|
+
|
|
|
|
+ memcpy(slots, kvm->memslots, sizeof(struct kvm_memslots));
|
|
|
|
+ slots->memslots[log->slot].dirty_bitmap = dirty_bitmap;
|
|
|
|
+
|
|
|
|
+ old_slots = kvm->memslots;
|
|
|
|
+ rcu_assign_pointer(kvm->memslots, slots);
|
|
|
|
+ synchronize_srcu_expedited(&kvm->srcu);
|
|
|
|
+ dirty_bitmap = old_slots->memslots[log->slot].dirty_bitmap;
|
|
|
|
+ kfree(old_slots);
|
|
}
|
|
}
|
|
|
|
+
|
|
r = 0;
|
|
r = 0;
|
|
|
|
+ if (copy_to_user(log->dirty_bitmap, dirty_bitmap, n))
|
|
|
|
+ r = -EFAULT;
|
|
|
|
+out_free:
|
|
|
|
+ vfree(dirty_bitmap);
|
|
out:
|
|
out:
|
|
- up_write(&kvm->slots_lock);
|
|
|
|
|
|
+ mutex_unlock(&kvm->slots_lock);
|
|
return r;
|
|
return r;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2469,6 +2772,8 @@ long kvm_arch_vm_ioctl(struct file *filp,
|
|
if (vpic) {
|
|
if (vpic) {
|
|
r = kvm_ioapic_init(kvm);
|
|
r = kvm_ioapic_init(kvm);
|
|
if (r) {
|
|
if (r) {
|
|
|
|
+ kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS,
|
|
|
|
+ &vpic->dev);
|
|
kfree(vpic);
|
|
kfree(vpic);
|
|
goto create_irqchip_unlock;
|
|
goto create_irqchip_unlock;
|
|
}
|
|
}
|
|
@@ -2480,10 +2785,8 @@ long kvm_arch_vm_ioctl(struct file *filp,
|
|
r = kvm_setup_default_irq_routing(kvm);
|
|
r = kvm_setup_default_irq_routing(kvm);
|
|
if (r) {
|
|
if (r) {
|
|
mutex_lock(&kvm->irq_lock);
|
|
mutex_lock(&kvm->irq_lock);
|
|
- kfree(kvm->arch.vpic);
|
|
|
|
- kfree(kvm->arch.vioapic);
|
|
|
|
- kvm->arch.vpic = NULL;
|
|
|
|
- kvm->arch.vioapic = NULL;
|
|
|
|
|
|
+ kvm_ioapic_destroy(kvm);
|
|
|
|
+ kvm_destroy_pic(kvm);
|
|
mutex_unlock(&kvm->irq_lock);
|
|
mutex_unlock(&kvm->irq_lock);
|
|
}
|
|
}
|
|
create_irqchip_unlock:
|
|
create_irqchip_unlock:
|
|
@@ -2499,7 +2802,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
|
|
sizeof(struct kvm_pit_config)))
|
|
sizeof(struct kvm_pit_config)))
|
|
goto out;
|
|
goto out;
|
|
create_pit:
|
|
create_pit:
|
|
- down_write(&kvm->slots_lock);
|
|
|
|
|
|
+ mutex_lock(&kvm->slots_lock);
|
|
r = -EEXIST;
|
|
r = -EEXIST;
|
|
if (kvm->arch.vpit)
|
|
if (kvm->arch.vpit)
|
|
goto create_pit_unlock;
|
|
goto create_pit_unlock;
|
|
@@ -2508,7 +2811,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
|
|
if (kvm->arch.vpit)
|
|
if (kvm->arch.vpit)
|
|
r = 0;
|
|
r = 0;
|
|
create_pit_unlock:
|
|
create_pit_unlock:
|
|
- up_write(&kvm->slots_lock);
|
|
|
|
|
|
+ mutex_unlock(&kvm->slots_lock);
|
|
break;
|
|
break;
|
|
case KVM_IRQ_LINE_STATUS:
|
|
case KVM_IRQ_LINE_STATUS:
|
|
case KVM_IRQ_LINE: {
|
|
case KVM_IRQ_LINE: {
|
|
@@ -2725,7 +3028,7 @@ static int vcpu_mmio_write(struct kvm_vcpu *vcpu, gpa_t addr, int len,
|
|
!kvm_iodevice_write(&vcpu->arch.apic->dev, addr, len, v))
|
|
!kvm_iodevice_write(&vcpu->arch.apic->dev, addr, len, v))
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
- return kvm_io_bus_write(&vcpu->kvm->mmio_bus, addr, len, v);
|
|
|
|
|
|
+ return kvm_io_bus_write(vcpu->kvm, KVM_MMIO_BUS, addr, len, v);
|
|
}
|
|
}
|
|
|
|
|
|
static int vcpu_mmio_read(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *v)
|
|
static int vcpu_mmio_read(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *v)
|
|
@@ -2734,17 +3037,44 @@ static int vcpu_mmio_read(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *v)
|
|
!kvm_iodevice_read(&vcpu->arch.apic->dev, addr, len, v))
|
|
!kvm_iodevice_read(&vcpu->arch.apic->dev, addr, len, v))
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
- return kvm_io_bus_read(&vcpu->kvm->mmio_bus, addr, len, v);
|
|
|
|
|
|
+ return kvm_io_bus_read(vcpu->kvm, KVM_MMIO_BUS, addr, len, v);
|
|
}
|
|
}
|
|
|
|
|
|
-static int kvm_read_guest_virt(gva_t addr, void *val, unsigned int bytes,
|
|
|
|
- struct kvm_vcpu *vcpu)
|
|
|
|
|
|
+gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva, u32 *error)
|
|
|
|
+{
|
|
|
|
+ u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
|
|
|
|
+ return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, access, error);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+ gpa_t kvm_mmu_gva_to_gpa_fetch(struct kvm_vcpu *vcpu, gva_t gva, u32 *error)
|
|
|
|
+{
|
|
|
|
+ u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
|
|
|
|
+ access |= PFERR_FETCH_MASK;
|
|
|
|
+ return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, access, error);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva, u32 *error)
|
|
|
|
+{
|
|
|
|
+ u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
|
|
|
|
+ access |= PFERR_WRITE_MASK;
|
|
|
|
+ return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, access, error);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* uses this to access any guest's mapped memory without checking CPL */
|
|
|
|
+gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva, u32 *error)
|
|
|
|
+{
|
|
|
|
+ return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, 0, error);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes,
|
|
|
|
+ struct kvm_vcpu *vcpu, u32 access,
|
|
|
|
+ u32 *error)
|
|
{
|
|
{
|
|
void *data = val;
|
|
void *data = val;
|
|
int r = X86EMUL_CONTINUE;
|
|
int r = X86EMUL_CONTINUE;
|
|
|
|
|
|
while (bytes) {
|
|
while (bytes) {
|
|
- gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
|
|
|
|
|
|
+ gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr, access, error);
|
|
unsigned offset = addr & (PAGE_SIZE-1);
|
|
unsigned offset = addr & (PAGE_SIZE-1);
|
|
unsigned toread = min(bytes, (unsigned)PAGE_SIZE - offset);
|
|
unsigned toread = min(bytes, (unsigned)PAGE_SIZE - offset);
|
|
int ret;
|
|
int ret;
|
|
@@ -2767,14 +3097,37 @@ out:
|
|
return r;
|
|
return r;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* used for instruction fetching */
|
|
|
|
+static int kvm_fetch_guest_virt(gva_t addr, void *val, unsigned int bytes,
|
|
|
|
+ struct kvm_vcpu *vcpu, u32 *error)
|
|
|
|
+{
|
|
|
|
+ u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
|
|
|
|
+ return kvm_read_guest_virt_helper(addr, val, bytes, vcpu,
|
|
|
|
+ access | PFERR_FETCH_MASK, error);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int kvm_read_guest_virt(gva_t addr, void *val, unsigned int bytes,
|
|
|
|
+ struct kvm_vcpu *vcpu, u32 *error)
|
|
|
|
+{
|
|
|
|
+ u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
|
|
|
|
+ return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access,
|
|
|
|
+ error);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int kvm_read_guest_virt_system(gva_t addr, void *val, unsigned int bytes,
|
|
|
|
+ struct kvm_vcpu *vcpu, u32 *error)
|
|
|
|
+{
|
|
|
|
+ return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, error);
|
|
|
|
+}
|
|
|
|
+
|
|
static int kvm_write_guest_virt(gva_t addr, void *val, unsigned int bytes,
|
|
static int kvm_write_guest_virt(gva_t addr, void *val, unsigned int bytes,
|
|
- struct kvm_vcpu *vcpu)
|
|
|
|
|
|
+ struct kvm_vcpu *vcpu, u32 *error)
|
|
{
|
|
{
|
|
void *data = val;
|
|
void *data = val;
|
|
int r = X86EMUL_CONTINUE;
|
|
int r = X86EMUL_CONTINUE;
|
|
|
|
|
|
while (bytes) {
|
|
while (bytes) {
|
|
- gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
|
|
|
|
|
|
+ gpa_t gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, error);
|
|
unsigned offset = addr & (PAGE_SIZE-1);
|
|
unsigned offset = addr & (PAGE_SIZE-1);
|
|
unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset);
|
|
unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset);
|
|
int ret;
|
|
int ret;
|
|
@@ -2804,6 +3157,7 @@ static int emulator_read_emulated(unsigned long addr,
|
|
struct kvm_vcpu *vcpu)
|
|
struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
gpa_t gpa;
|
|
gpa_t gpa;
|
|
|
|
+ u32 error_code;
|
|
|
|
|
|
if (vcpu->mmio_read_completed) {
|
|
if (vcpu->mmio_read_completed) {
|
|
memcpy(val, vcpu->mmio_data, bytes);
|
|
memcpy(val, vcpu->mmio_data, bytes);
|
|
@@ -2813,17 +3167,20 @@ static int emulator_read_emulated(unsigned long addr,
|
|
return X86EMUL_CONTINUE;
|
|
return X86EMUL_CONTINUE;
|
|
}
|
|
}
|
|
|
|
|
|
- gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
|
|
|
|
|
|
+ gpa = kvm_mmu_gva_to_gpa_read(vcpu, addr, &error_code);
|
|
|
|
+
|
|
|
|
+ if (gpa == UNMAPPED_GVA) {
|
|
|
|
+ kvm_inject_page_fault(vcpu, addr, error_code);
|
|
|
|
+ return X86EMUL_PROPAGATE_FAULT;
|
|
|
|
+ }
|
|
|
|
|
|
/* For APIC access vmexit */
|
|
/* For APIC access vmexit */
|
|
if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
|
|
if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
|
|
goto mmio;
|
|
goto mmio;
|
|
|
|
|
|
- if (kvm_read_guest_virt(addr, val, bytes, vcpu)
|
|
|
|
|
|
+ if (kvm_read_guest_virt(addr, val, bytes, vcpu, NULL)
|
|
== X86EMUL_CONTINUE)
|
|
== X86EMUL_CONTINUE)
|
|
return X86EMUL_CONTINUE;
|
|
return X86EMUL_CONTINUE;
|
|
- if (gpa == UNMAPPED_GVA)
|
|
|
|
- return X86EMUL_PROPAGATE_FAULT;
|
|
|
|
|
|
|
|
mmio:
|
|
mmio:
|
|
/*
|
|
/*
|
|
@@ -2862,11 +3219,12 @@ static int emulator_write_emulated_onepage(unsigned long addr,
|
|
struct kvm_vcpu *vcpu)
|
|
struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
gpa_t gpa;
|
|
gpa_t gpa;
|
|
|
|
+ u32 error_code;
|
|
|
|
|
|
- gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
|
|
|
|
|
|
+ gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, &error_code);
|
|
|
|
|
|
if (gpa == UNMAPPED_GVA) {
|
|
if (gpa == UNMAPPED_GVA) {
|
|
- kvm_inject_page_fault(vcpu, addr, 2);
|
|
|
|
|
|
+ kvm_inject_page_fault(vcpu, addr, error_code);
|
|
return X86EMUL_PROPAGATE_FAULT;
|
|
return X86EMUL_PROPAGATE_FAULT;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2930,7 +3288,7 @@ static int emulator_cmpxchg_emulated(unsigned long addr,
|
|
char *kaddr;
|
|
char *kaddr;
|
|
u64 val;
|
|
u64 val;
|
|
|
|
|
|
- gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
|
|
|
|
|
|
+ gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, NULL);
|
|
|
|
|
|
if (gpa == UNMAPPED_GVA ||
|
|
if (gpa == UNMAPPED_GVA ||
|
|
(gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
|
|
(gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
|
|
@@ -2967,35 +3325,21 @@ int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address)
|
|
|
|
|
|
int emulate_clts(struct kvm_vcpu *vcpu)
|
|
int emulate_clts(struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
- kvm_x86_ops->set_cr0(vcpu, vcpu->arch.cr0 & ~X86_CR0_TS);
|
|
|
|
|
|
+ kvm_x86_ops->set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~X86_CR0_TS));
|
|
|
|
+ kvm_x86_ops->fpu_activate(vcpu);
|
|
return X86EMUL_CONTINUE;
|
|
return X86EMUL_CONTINUE;
|
|
}
|
|
}
|
|
|
|
|
|
int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long *dest)
|
|
int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long *dest)
|
|
{
|
|
{
|
|
- struct kvm_vcpu *vcpu = ctxt->vcpu;
|
|
|
|
-
|
|
|
|
- switch (dr) {
|
|
|
|
- case 0 ... 3:
|
|
|
|
- *dest = kvm_x86_ops->get_dr(vcpu, dr);
|
|
|
|
- return X86EMUL_CONTINUE;
|
|
|
|
- default:
|
|
|
|
- pr_unimpl(vcpu, "%s: unexpected dr %u\n", __func__, dr);
|
|
|
|
- return X86EMUL_UNHANDLEABLE;
|
|
|
|
- }
|
|
|
|
|
|
+ return kvm_x86_ops->get_dr(ctxt->vcpu, dr, dest);
|
|
}
|
|
}
|
|
|
|
|
|
int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value)
|
|
int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value)
|
|
{
|
|
{
|
|
unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U;
|
|
unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U;
|
|
- int exception;
|
|
|
|
|
|
|
|
- kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception);
|
|
|
|
- if (exception) {
|
|
|
|
- /* FIXME: better handling */
|
|
|
|
- return X86EMUL_UNHANDLEABLE;
|
|
|
|
- }
|
|
|
|
- return X86EMUL_CONTINUE;
|
|
|
|
|
|
+ return kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask);
|
|
}
|
|
}
|
|
|
|
|
|
void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
|
|
void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
|
|
@@ -3009,7 +3353,7 @@ void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
|
|
|
|
|
|
rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS);
|
|
rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS);
|
|
|
|
|
|
- kvm_read_guest_virt(rip_linear, (void *)opcodes, 4, vcpu);
|
|
|
|
|
|
+ kvm_read_guest_virt(rip_linear, (void *)opcodes, 4, vcpu, NULL);
|
|
|
|
|
|
printk(KERN_ERR "emulation failed (%s) rip %lx %02x %02x %02x %02x\n",
|
|
printk(KERN_ERR "emulation failed (%s) rip %lx %02x %02x %02x %02x\n",
|
|
context, rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]);
|
|
context, rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]);
|
|
@@ -3017,7 +3361,8 @@ void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
|
|
EXPORT_SYMBOL_GPL(kvm_report_emulation_failure);
|
|
EXPORT_SYMBOL_GPL(kvm_report_emulation_failure);
|
|
|
|
|
|
static struct x86_emulate_ops emulate_ops = {
|
|
static struct x86_emulate_ops emulate_ops = {
|
|
- .read_std = kvm_read_guest_virt,
|
|
|
|
|
|
+ .read_std = kvm_read_guest_virt_system,
|
|
|
|
+ .fetch = kvm_fetch_guest_virt,
|
|
.read_emulated = emulator_read_emulated,
|
|
.read_emulated = emulator_read_emulated,
|
|
.write_emulated = emulator_write_emulated,
|
|
.write_emulated = emulator_write_emulated,
|
|
.cmpxchg_emulated = emulator_cmpxchg_emulated,
|
|
.cmpxchg_emulated = emulator_cmpxchg_emulated,
|
|
@@ -3060,8 +3405,9 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
|
|
vcpu->arch.emulate_ctxt.vcpu = vcpu;
|
|
vcpu->arch.emulate_ctxt.vcpu = vcpu;
|
|
vcpu->arch.emulate_ctxt.eflags = kvm_get_rflags(vcpu);
|
|
vcpu->arch.emulate_ctxt.eflags = kvm_get_rflags(vcpu);
|
|
vcpu->arch.emulate_ctxt.mode =
|
|
vcpu->arch.emulate_ctxt.mode =
|
|
|
|
+ (!is_protmode(vcpu)) ? X86EMUL_MODE_REAL :
|
|
(vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM)
|
|
(vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM)
|
|
- ? X86EMUL_MODE_REAL : cs_l
|
|
|
|
|
|
+ ? X86EMUL_MODE_VM86 : cs_l
|
|
? X86EMUL_MODE_PROT64 : cs_db
|
|
? X86EMUL_MODE_PROT64 : cs_db
|
|
? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
|
|
? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
|
|
|
|
|
|
@@ -3153,12 +3499,17 @@ static int pio_copy_data(struct kvm_vcpu *vcpu)
|
|
gva_t q = vcpu->arch.pio.guest_gva;
|
|
gva_t q = vcpu->arch.pio.guest_gva;
|
|
unsigned bytes;
|
|
unsigned bytes;
|
|
int ret;
|
|
int ret;
|
|
|
|
+ u32 error_code;
|
|
|
|
|
|
bytes = vcpu->arch.pio.size * vcpu->arch.pio.cur_count;
|
|
bytes = vcpu->arch.pio.size * vcpu->arch.pio.cur_count;
|
|
if (vcpu->arch.pio.in)
|
|
if (vcpu->arch.pio.in)
|
|
- ret = kvm_write_guest_virt(q, p, bytes, vcpu);
|
|
|
|
|
|
+ ret = kvm_write_guest_virt(q, p, bytes, vcpu, &error_code);
|
|
else
|
|
else
|
|
- ret = kvm_read_guest_virt(q, p, bytes, vcpu);
|
|
|
|
|
|
+ ret = kvm_read_guest_virt(q, p, bytes, vcpu, &error_code);
|
|
|
|
+
|
|
|
|
+ if (ret == X86EMUL_PROPAGATE_FAULT)
|
|
|
|
+ kvm_inject_page_fault(vcpu, q, error_code);
|
|
|
|
+
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -3179,7 +3530,7 @@ int complete_pio(struct kvm_vcpu *vcpu)
|
|
if (io->in) {
|
|
if (io->in) {
|
|
r = pio_copy_data(vcpu);
|
|
r = pio_copy_data(vcpu);
|
|
if (r)
|
|
if (r)
|
|
- return r;
|
|
|
|
|
|
+ goto out;
|
|
}
|
|
}
|
|
|
|
|
|
delta = 1;
|
|
delta = 1;
|
|
@@ -3206,7 +3557,7 @@ int complete_pio(struct kvm_vcpu *vcpu)
|
|
kvm_register_write(vcpu, VCPU_REGS_RSI, val);
|
|
kvm_register_write(vcpu, VCPU_REGS_RSI, val);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+out:
|
|
io->count -= io->cur_count;
|
|
io->count -= io->cur_count;
|
|
io->cur_count = 0;
|
|
io->cur_count = 0;
|
|
|
|
|
|
@@ -3219,11 +3570,12 @@ static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
|
|
int r;
|
|
int r;
|
|
|
|
|
|
if (vcpu->arch.pio.in)
|
|
if (vcpu->arch.pio.in)
|
|
- r = kvm_io_bus_read(&vcpu->kvm->pio_bus, vcpu->arch.pio.port,
|
|
|
|
|
|
+ r = kvm_io_bus_read(vcpu->kvm, KVM_PIO_BUS, vcpu->arch.pio.port,
|
|
vcpu->arch.pio.size, pd);
|
|
vcpu->arch.pio.size, pd);
|
|
else
|
|
else
|
|
- r = kvm_io_bus_write(&vcpu->kvm->pio_bus, vcpu->arch.pio.port,
|
|
|
|
- vcpu->arch.pio.size, pd);
|
|
|
|
|
|
+ r = kvm_io_bus_write(vcpu->kvm, KVM_PIO_BUS,
|
|
|
|
+ vcpu->arch.pio.port, vcpu->arch.pio.size,
|
|
|
|
+ pd);
|
|
return r;
|
|
return r;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -3234,7 +3586,7 @@ static int pio_string_write(struct kvm_vcpu *vcpu)
|
|
int i, r = 0;
|
|
int i, r = 0;
|
|
|
|
|
|
for (i = 0; i < io->cur_count; i++) {
|
|
for (i = 0; i < io->cur_count; i++) {
|
|
- if (kvm_io_bus_write(&vcpu->kvm->pio_bus,
|
|
|
|
|
|
+ if (kvm_io_bus_write(vcpu->kvm, KVM_PIO_BUS,
|
|
io->port, io->size, pd)) {
|
|
io->port, io->size, pd)) {
|
|
r = -EOPNOTSUPP;
|
|
r = -EOPNOTSUPP;
|
|
break;
|
|
break;
|
|
@@ -3248,6 +3600,8 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, int in, int size, unsigned port)
|
|
{
|
|
{
|
|
unsigned long val;
|
|
unsigned long val;
|
|
|
|
|
|
|
|
+ trace_kvm_pio(!in, port, size, 1);
|
|
|
|
+
|
|
vcpu->run->exit_reason = KVM_EXIT_IO;
|
|
vcpu->run->exit_reason = KVM_EXIT_IO;
|
|
vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
|
|
vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
|
|
vcpu->run->io.size = vcpu->arch.pio.size = size;
|
|
vcpu->run->io.size = vcpu->arch.pio.size = size;
|
|
@@ -3259,11 +3613,10 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, int in, int size, unsigned port)
|
|
vcpu->arch.pio.down = 0;
|
|
vcpu->arch.pio.down = 0;
|
|
vcpu->arch.pio.rep = 0;
|
|
vcpu->arch.pio.rep = 0;
|
|
|
|
|
|
- trace_kvm_pio(vcpu->run->io.direction == KVM_EXIT_IO_OUT, port,
|
|
|
|
- size, 1);
|
|
|
|
-
|
|
|
|
- val = kvm_register_read(vcpu, VCPU_REGS_RAX);
|
|
|
|
- memcpy(vcpu->arch.pio_data, &val, 4);
|
|
|
|
|
|
+ if (!vcpu->arch.pio.in) {
|
|
|
|
+ val = kvm_register_read(vcpu, VCPU_REGS_RAX);
|
|
|
|
+ memcpy(vcpu->arch.pio_data, &val, 4);
|
|
|
|
+ }
|
|
|
|
|
|
if (!kernel_pio(vcpu, vcpu->arch.pio_data)) {
|
|
if (!kernel_pio(vcpu, vcpu->arch.pio_data)) {
|
|
complete_pio(vcpu);
|
|
complete_pio(vcpu);
|
|
@@ -3280,6 +3633,8 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in,
|
|
unsigned now, in_page;
|
|
unsigned now, in_page;
|
|
int ret = 0;
|
|
int ret = 0;
|
|
|
|
|
|
|
|
+ trace_kvm_pio(!in, port, size, count);
|
|
|
|
+
|
|
vcpu->run->exit_reason = KVM_EXIT_IO;
|
|
vcpu->run->exit_reason = KVM_EXIT_IO;
|
|
vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
|
|
vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
|
|
vcpu->run->io.size = vcpu->arch.pio.size = size;
|
|
vcpu->run->io.size = vcpu->arch.pio.size = size;
|
|
@@ -3291,9 +3646,6 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in,
|
|
vcpu->arch.pio.down = down;
|
|
vcpu->arch.pio.down = down;
|
|
vcpu->arch.pio.rep = rep;
|
|
vcpu->arch.pio.rep = rep;
|
|
|
|
|
|
- trace_kvm_pio(vcpu->run->io.direction == KVM_EXIT_IO_OUT, port,
|
|
|
|
- size, count);
|
|
|
|
-
|
|
|
|
if (!count) {
|
|
if (!count) {
|
|
kvm_x86_ops->skip_emulated_instruction(vcpu);
|
|
kvm_x86_ops->skip_emulated_instruction(vcpu);
|
|
return 1;
|
|
return 1;
|
|
@@ -3325,10 +3677,8 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in,
|
|
if (!vcpu->arch.pio.in) {
|
|
if (!vcpu->arch.pio.in) {
|
|
/* string PIO write */
|
|
/* string PIO write */
|
|
ret = pio_copy_data(vcpu);
|
|
ret = pio_copy_data(vcpu);
|
|
- if (ret == X86EMUL_PROPAGATE_FAULT) {
|
|
|
|
- kvm_inject_gp(vcpu, 0);
|
|
|
|
|
|
+ if (ret == X86EMUL_PROPAGATE_FAULT)
|
|
return 1;
|
|
return 1;
|
|
- }
|
|
|
|
if (ret == 0 && !pio_string_write(vcpu)) {
|
|
if (ret == 0 && !pio_string_write(vcpu)) {
|
|
complete_pio(vcpu);
|
|
complete_pio(vcpu);
|
|
if (vcpu->arch.pio.count == 0)
|
|
if (vcpu->arch.pio.count == 0)
|
|
@@ -3487,11 +3837,76 @@ static inline gpa_t hc_gpa(struct kvm_vcpu *vcpu, unsigned long a0,
|
|
return a0 | ((gpa_t)a1 << 32);
|
|
return a0 | ((gpa_t)a1 << 32);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
|
|
|
|
+{
|
|
|
|
+ u64 param, ingpa, outgpa, ret;
|
|
|
|
+ uint16_t code, rep_idx, rep_cnt, res = HV_STATUS_SUCCESS, rep_done = 0;
|
|
|
|
+ bool fast, longmode;
|
|
|
|
+ int cs_db, cs_l;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * hypercall generates UD from non zero cpl and real mode
|
|
|
|
+ * per HYPER-V spec
|
|
|
|
+ */
|
|
|
|
+ if (kvm_x86_ops->get_cpl(vcpu) != 0 || !is_protmode(vcpu)) {
|
|
|
|
+ kvm_queue_exception(vcpu, UD_VECTOR);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
|
|
|
|
+ longmode = is_long_mode(vcpu) && cs_l == 1;
|
|
|
|
+
|
|
|
|
+ if (!longmode) {
|
|
|
|
+ param = ((u64)kvm_register_read(vcpu, VCPU_REGS_RDX) << 32) |
|
|
|
|
+ (kvm_register_read(vcpu, VCPU_REGS_RAX) & 0xffffffff);
|
|
|
|
+ ingpa = ((u64)kvm_register_read(vcpu, VCPU_REGS_RBX) << 32) |
|
|
|
|
+ (kvm_register_read(vcpu, VCPU_REGS_RCX) & 0xffffffff);
|
|
|
|
+ outgpa = ((u64)kvm_register_read(vcpu, VCPU_REGS_RDI) << 32) |
|
|
|
|
+ (kvm_register_read(vcpu, VCPU_REGS_RSI) & 0xffffffff);
|
|
|
|
+ }
|
|
|
|
+#ifdef CONFIG_X86_64
|
|
|
|
+ else {
|
|
|
|
+ param = kvm_register_read(vcpu, VCPU_REGS_RCX);
|
|
|
|
+ ingpa = kvm_register_read(vcpu, VCPU_REGS_RDX);
|
|
|
|
+ outgpa = kvm_register_read(vcpu, VCPU_REGS_R8);
|
|
|
|
+ }
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ code = param & 0xffff;
|
|
|
|
+ fast = (param >> 16) & 0x1;
|
|
|
|
+ rep_cnt = (param >> 32) & 0xfff;
|
|
|
|
+ rep_idx = (param >> 48) & 0xfff;
|
|
|
|
+
|
|
|
|
+ trace_kvm_hv_hypercall(code, fast, rep_cnt, rep_idx, ingpa, outgpa);
|
|
|
|
+
|
|
|
|
+ switch (code) {
|
|
|
|
+ case HV_X64_HV_NOTIFY_LONG_SPIN_WAIT:
|
|
|
|
+ kvm_vcpu_on_spin(vcpu);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ res = HV_STATUS_INVALID_HYPERCALL_CODE;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = res | (((u64)rep_done & 0xfff) << 32);
|
|
|
|
+ if (longmode) {
|
|
|
|
+ kvm_register_write(vcpu, VCPU_REGS_RAX, ret);
|
|
|
|
+ } else {
|
|
|
|
+ kvm_register_write(vcpu, VCPU_REGS_RDX, ret >> 32);
|
|
|
|
+ kvm_register_write(vcpu, VCPU_REGS_RAX, ret & 0xffffffff);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
|
|
int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
unsigned long nr, a0, a1, a2, a3, ret;
|
|
unsigned long nr, a0, a1, a2, a3, ret;
|
|
int r = 1;
|
|
int r = 1;
|
|
|
|
|
|
|
|
+ if (kvm_hv_hypercall_enabled(vcpu->kvm))
|
|
|
|
+ return kvm_hv_hypercall(vcpu);
|
|
|
|
+
|
|
nr = kvm_register_read(vcpu, VCPU_REGS_RAX);
|
|
nr = kvm_register_read(vcpu, VCPU_REGS_RAX);
|
|
a0 = kvm_register_read(vcpu, VCPU_REGS_RBX);
|
|
a0 = kvm_register_read(vcpu, VCPU_REGS_RBX);
|
|
a1 = kvm_register_read(vcpu, VCPU_REGS_RCX);
|
|
a1 = kvm_register_read(vcpu, VCPU_REGS_RCX);
|
|
@@ -3534,10 +3949,8 @@ EXPORT_SYMBOL_GPL(kvm_emulate_hypercall);
|
|
int kvm_fix_hypercall(struct kvm_vcpu *vcpu)
|
|
int kvm_fix_hypercall(struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
char instruction[3];
|
|
char instruction[3];
|
|
- int ret = 0;
|
|
|
|
unsigned long rip = kvm_rip_read(vcpu);
|
|
unsigned long rip = kvm_rip_read(vcpu);
|
|
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* Blow out the MMU to ensure that no other VCPU has an active mapping
|
|
* Blow out the MMU to ensure that no other VCPU has an active mapping
|
|
* to ensure that the updated hypercall appears atomically across all
|
|
* to ensure that the updated hypercall appears atomically across all
|
|
@@ -3546,11 +3959,8 @@ int kvm_fix_hypercall(struct kvm_vcpu *vcpu)
|
|
kvm_mmu_zap_all(vcpu->kvm);
|
|
kvm_mmu_zap_all(vcpu->kvm);
|
|
|
|
|
|
kvm_x86_ops->patch_hypercall(vcpu, instruction);
|
|
kvm_x86_ops->patch_hypercall(vcpu, instruction);
|
|
- if (emulator_write_emulated(rip, instruction, 3, vcpu)
|
|
|
|
- != X86EMUL_CONTINUE)
|
|
|
|
- ret = -EFAULT;
|
|
|
|
|
|
|
|
- return ret;
|
|
|
|
|
|
+ return emulator_write_emulated(rip, instruction, 3, vcpu);
|
|
}
|
|
}
|
|
|
|
|
|
static u64 mk_cr_64(u64 curr_cr, u32 new_val)
|
|
static u64 mk_cr_64(u64 curr_cr, u32 new_val)
|
|
@@ -3583,10 +3993,9 @@ unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
|
|
{
|
|
{
|
|
unsigned long value;
|
|
unsigned long value;
|
|
|
|
|
|
- kvm_x86_ops->decache_cr4_guest_bits(vcpu);
|
|
|
|
switch (cr) {
|
|
switch (cr) {
|
|
case 0:
|
|
case 0:
|
|
- value = vcpu->arch.cr0;
|
|
|
|
|
|
+ value = kvm_read_cr0(vcpu);
|
|
break;
|
|
break;
|
|
case 2:
|
|
case 2:
|
|
value = vcpu->arch.cr2;
|
|
value = vcpu->arch.cr2;
|
|
@@ -3595,7 +4004,7 @@ unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
|
|
value = vcpu->arch.cr3;
|
|
value = vcpu->arch.cr3;
|
|
break;
|
|
break;
|
|
case 4:
|
|
case 4:
|
|
- value = vcpu->arch.cr4;
|
|
|
|
|
|
+ value = kvm_read_cr4(vcpu);
|
|
break;
|
|
break;
|
|
case 8:
|
|
case 8:
|
|
value = kvm_get_cr8(vcpu);
|
|
value = kvm_get_cr8(vcpu);
|
|
@@ -3613,7 +4022,7 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val,
|
|
{
|
|
{
|
|
switch (cr) {
|
|
switch (cr) {
|
|
case 0:
|
|
case 0:
|
|
- kvm_set_cr0(vcpu, mk_cr_64(vcpu->arch.cr0, val));
|
|
|
|
|
|
+ kvm_set_cr0(vcpu, mk_cr_64(kvm_read_cr0(vcpu), val));
|
|
*rflags = kvm_get_rflags(vcpu);
|
|
*rflags = kvm_get_rflags(vcpu);
|
|
break;
|
|
break;
|
|
case 2:
|
|
case 2:
|
|
@@ -3623,7 +4032,7 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val,
|
|
kvm_set_cr3(vcpu, val);
|
|
kvm_set_cr3(vcpu, val);
|
|
break;
|
|
break;
|
|
case 4:
|
|
case 4:
|
|
- kvm_set_cr4(vcpu, mk_cr_64(vcpu->arch.cr4, val));
|
|
|
|
|
|
+ kvm_set_cr4(vcpu, mk_cr_64(kvm_read_cr4(vcpu), val));
|
|
break;
|
|
break;
|
|
case 8:
|
|
case 8:
|
|
kvm_set_cr8(vcpu, val & 0xfUL);
|
|
kvm_set_cr8(vcpu, val & 0xfUL);
|
|
@@ -3690,6 +4099,7 @@ struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu,
|
|
}
|
|
}
|
|
return best;
|
|
return best;
|
|
}
|
|
}
|
|
|
|
+EXPORT_SYMBOL_GPL(kvm_find_cpuid_entry);
|
|
|
|
|
|
int cpuid_maxphyaddr(struct kvm_vcpu *vcpu)
|
|
int cpuid_maxphyaddr(struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
@@ -3773,14 +4183,15 @@ static void vapic_enter(struct kvm_vcpu *vcpu)
|
|
static void vapic_exit(struct kvm_vcpu *vcpu)
|
|
static void vapic_exit(struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
struct kvm_lapic *apic = vcpu->arch.apic;
|
|
struct kvm_lapic *apic = vcpu->arch.apic;
|
|
|
|
+ int idx;
|
|
|
|
|
|
if (!apic || !apic->vapic_addr)
|
|
if (!apic || !apic->vapic_addr)
|
|
return;
|
|
return;
|
|
|
|
|
|
- down_read(&vcpu->kvm->slots_lock);
|
|
|
|
|
|
+ idx = srcu_read_lock(&vcpu->kvm->srcu);
|
|
kvm_release_page_dirty(apic->vapic_page);
|
|
kvm_release_page_dirty(apic->vapic_page);
|
|
mark_page_dirty(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT);
|
|
mark_page_dirty(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT);
|
|
- up_read(&vcpu->kvm->slots_lock);
|
|
|
|
|
|
+ srcu_read_unlock(&vcpu->kvm->srcu, idx);
|
|
}
|
|
}
|
|
|
|
|
|
static void update_cr8_intercept(struct kvm_vcpu *vcpu)
|
|
static void update_cr8_intercept(struct kvm_vcpu *vcpu)
|
|
@@ -3876,12 +4287,17 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
|
|
r = 0;
|
|
r = 0;
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
+ if (test_and_clear_bit(KVM_REQ_DEACTIVATE_FPU, &vcpu->requests)) {
|
|
|
|
+ vcpu->fpu_active = 0;
|
|
|
|
+ kvm_x86_ops->fpu_deactivate(vcpu);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
preempt_disable();
|
|
preempt_disable();
|
|
|
|
|
|
kvm_x86_ops->prepare_guest_switch(vcpu);
|
|
kvm_x86_ops->prepare_guest_switch(vcpu);
|
|
- kvm_load_guest_fpu(vcpu);
|
|
|
|
|
|
+ if (vcpu->fpu_active)
|
|
|
|
+ kvm_load_guest_fpu(vcpu);
|
|
|
|
|
|
local_irq_disable();
|
|
local_irq_disable();
|
|
|
|
|
|
@@ -3909,7 +4325,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
|
|
kvm_lapic_sync_to_vapic(vcpu);
|
|
kvm_lapic_sync_to_vapic(vcpu);
|
|
}
|
|
}
|
|
|
|
|
|
- up_read(&vcpu->kvm->slots_lock);
|
|
|
|
|
|
+ srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
|
|
|
|
|
|
kvm_guest_enter();
|
|
kvm_guest_enter();
|
|
|
|
|
|
@@ -3951,7 +4367,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
|
|
|
|
|
|
preempt_enable();
|
|
preempt_enable();
|
|
|
|
|
|
- down_read(&vcpu->kvm->slots_lock);
|
|
|
|
|
|
+ vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
|
|
|
|
|
|
/*
|
|
/*
|
|
* Profile KVM exit RIPs:
|
|
* Profile KVM exit RIPs:
|
|
@@ -3973,6 +4389,7 @@ out:
|
|
static int __vcpu_run(struct kvm_vcpu *vcpu)
|
|
static int __vcpu_run(struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
int r;
|
|
int r;
|
|
|
|
+ struct kvm *kvm = vcpu->kvm;
|
|
|
|
|
|
if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_SIPI_RECEIVED)) {
|
|
if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_SIPI_RECEIVED)) {
|
|
pr_debug("vcpu %d received sipi with vector # %x\n",
|
|
pr_debug("vcpu %d received sipi with vector # %x\n",
|
|
@@ -3984,7 +4401,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
|
|
vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
|
|
vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
|
|
}
|
|
}
|
|
|
|
|
|
- down_read(&vcpu->kvm->slots_lock);
|
|
|
|
|
|
+ vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
|
|
vapic_enter(vcpu);
|
|
vapic_enter(vcpu);
|
|
|
|
|
|
r = 1;
|
|
r = 1;
|
|
@@ -3992,9 +4409,9 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
|
|
if (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE)
|
|
if (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE)
|
|
r = vcpu_enter_guest(vcpu);
|
|
r = vcpu_enter_guest(vcpu);
|
|
else {
|
|
else {
|
|
- up_read(&vcpu->kvm->slots_lock);
|
|
|
|
|
|
+ srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
|
|
kvm_vcpu_block(vcpu);
|
|
kvm_vcpu_block(vcpu);
|
|
- down_read(&vcpu->kvm->slots_lock);
|
|
|
|
|
|
+ vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
|
|
if (test_and_clear_bit(KVM_REQ_UNHALT, &vcpu->requests))
|
|
if (test_and_clear_bit(KVM_REQ_UNHALT, &vcpu->requests))
|
|
{
|
|
{
|
|
switch(vcpu->arch.mp_state) {
|
|
switch(vcpu->arch.mp_state) {
|
|
@@ -4029,13 +4446,13 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
|
|
++vcpu->stat.signal_exits;
|
|
++vcpu->stat.signal_exits;
|
|
}
|
|
}
|
|
if (need_resched()) {
|
|
if (need_resched()) {
|
|
- up_read(&vcpu->kvm->slots_lock);
|
|
|
|
|
|
+ srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
|
|
kvm_resched(vcpu);
|
|
kvm_resched(vcpu);
|
|
- down_read(&vcpu->kvm->slots_lock);
|
|
|
|
|
|
+ vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- up_read(&vcpu->kvm->slots_lock);
|
|
|
|
|
|
+ srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
|
|
post_kvm_run_save(vcpu);
|
|
post_kvm_run_save(vcpu);
|
|
|
|
|
|
vapic_exit(vcpu);
|
|
vapic_exit(vcpu);
|
|
@@ -4074,10 +4491,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
|
vcpu->mmio_read_completed = 1;
|
|
vcpu->mmio_read_completed = 1;
|
|
vcpu->mmio_needed = 0;
|
|
vcpu->mmio_needed = 0;
|
|
|
|
|
|
- down_read(&vcpu->kvm->slots_lock);
|
|
|
|
|
|
+ vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
|
|
r = emulate_instruction(vcpu, vcpu->arch.mmio_fault_cr2, 0,
|
|
r = emulate_instruction(vcpu, vcpu->arch.mmio_fault_cr2, 0,
|
|
EMULTYPE_NO_DECODE);
|
|
EMULTYPE_NO_DECODE);
|
|
- up_read(&vcpu->kvm->slots_lock);
|
|
|
|
|
|
+ srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
|
|
if (r == EMULATE_DO_MMIO) {
|
|
if (r == EMULATE_DO_MMIO) {
|
|
/*
|
|
/*
|
|
* Read-modify-write. Back to userspace.
|
|
* Read-modify-write. Back to userspace.
|
|
@@ -4204,13 +4621,12 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
|
|
sregs->gdt.limit = dt.limit;
|
|
sregs->gdt.limit = dt.limit;
|
|
sregs->gdt.base = dt.base;
|
|
sregs->gdt.base = dt.base;
|
|
|
|
|
|
- kvm_x86_ops->decache_cr4_guest_bits(vcpu);
|
|
|
|
- sregs->cr0 = vcpu->arch.cr0;
|
|
|
|
|
|
+ sregs->cr0 = kvm_read_cr0(vcpu);
|
|
sregs->cr2 = vcpu->arch.cr2;
|
|
sregs->cr2 = vcpu->arch.cr2;
|
|
sregs->cr3 = vcpu->arch.cr3;
|
|
sregs->cr3 = vcpu->arch.cr3;
|
|
- sregs->cr4 = vcpu->arch.cr4;
|
|
|
|
|
|
+ sregs->cr4 = kvm_read_cr4(vcpu);
|
|
sregs->cr8 = kvm_get_cr8(vcpu);
|
|
sregs->cr8 = kvm_get_cr8(vcpu);
|
|
- sregs->efer = vcpu->arch.shadow_efer;
|
|
|
|
|
|
+ sregs->efer = vcpu->arch.efer;
|
|
sregs->apic_base = kvm_get_apic_base(vcpu);
|
|
sregs->apic_base = kvm_get_apic_base(vcpu);
|
|
|
|
|
|
memset(sregs->interrupt_bitmap, 0, sizeof sregs->interrupt_bitmap);
|
|
memset(sregs->interrupt_bitmap, 0, sizeof sregs->interrupt_bitmap);
|
|
@@ -4298,14 +4714,23 @@ static int load_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
|
|
{
|
|
{
|
|
struct descriptor_table dtable;
|
|
struct descriptor_table dtable;
|
|
u16 index = selector >> 3;
|
|
u16 index = selector >> 3;
|
|
|
|
+ int ret;
|
|
|
|
+ u32 err;
|
|
|
|
+ gva_t addr;
|
|
|
|
|
|
get_segment_descriptor_dtable(vcpu, selector, &dtable);
|
|
get_segment_descriptor_dtable(vcpu, selector, &dtable);
|
|
|
|
|
|
if (dtable.limit < index * 8 + 7) {
|
|
if (dtable.limit < index * 8 + 7) {
|
|
kvm_queue_exception_e(vcpu, GP_VECTOR, selector & 0xfffc);
|
|
kvm_queue_exception_e(vcpu, GP_VECTOR, selector & 0xfffc);
|
|
- return 1;
|
|
|
|
|
|
+ return X86EMUL_PROPAGATE_FAULT;
|
|
}
|
|
}
|
|
- return kvm_read_guest_virt(dtable.base + index*8, seg_desc, sizeof(*seg_desc), vcpu);
|
|
|
|
|
|
+ addr = dtable.base + index * 8;
|
|
|
|
+ ret = kvm_read_guest_virt_system(addr, seg_desc, sizeof(*seg_desc),
|
|
|
|
+ vcpu, &err);
|
|
|
|
+ if (ret == X86EMUL_PROPAGATE_FAULT)
|
|
|
|
+ kvm_inject_page_fault(vcpu, addr, err);
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
/* allowed just for 8 bytes segments */
|
|
/* allowed just for 8 bytes segments */
|
|
@@ -4319,15 +4744,23 @@ static int save_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
|
|
|
|
|
|
if (dtable.limit < index * 8 + 7)
|
|
if (dtable.limit < index * 8 + 7)
|
|
return 1;
|
|
return 1;
|
|
- return kvm_write_guest_virt(dtable.base + index*8, seg_desc, sizeof(*seg_desc), vcpu);
|
|
|
|
|
|
+ return kvm_write_guest_virt(dtable.base + index*8, seg_desc, sizeof(*seg_desc), vcpu, NULL);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static gpa_t get_tss_base_addr_write(struct kvm_vcpu *vcpu,
|
|
|
|
+ struct desc_struct *seg_desc)
|
|
|
|
+{
|
|
|
|
+ u32 base_addr = get_desc_base(seg_desc);
|
|
|
|
+
|
|
|
|
+ return kvm_mmu_gva_to_gpa_write(vcpu, base_addr, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
-static gpa_t get_tss_base_addr(struct kvm_vcpu *vcpu,
|
|
|
|
|
|
+static gpa_t get_tss_base_addr_read(struct kvm_vcpu *vcpu,
|
|
struct desc_struct *seg_desc)
|
|
struct desc_struct *seg_desc)
|
|
{
|
|
{
|
|
u32 base_addr = get_desc_base(seg_desc);
|
|
u32 base_addr = get_desc_base(seg_desc);
|
|
|
|
|
|
- return vcpu->arch.mmu.gva_to_gpa(vcpu, base_addr);
|
|
|
|
|
|
+ return kvm_mmu_gva_to_gpa_read(vcpu, base_addr, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
static u16 get_segment_selector(struct kvm_vcpu *vcpu, int seg)
|
|
static u16 get_segment_selector(struct kvm_vcpu *vcpu, int seg)
|
|
@@ -4338,18 +4771,6 @@ static u16 get_segment_selector(struct kvm_vcpu *vcpu, int seg)
|
|
return kvm_seg.selector;
|
|
return kvm_seg.selector;
|
|
}
|
|
}
|
|
|
|
|
|
-static int load_segment_descriptor_to_kvm_desct(struct kvm_vcpu *vcpu,
|
|
|
|
- u16 selector,
|
|
|
|
- struct kvm_segment *kvm_seg)
|
|
|
|
-{
|
|
|
|
- struct desc_struct seg_desc;
|
|
|
|
-
|
|
|
|
- if (load_guest_segment_descriptor(vcpu, selector, &seg_desc))
|
|
|
|
- return 1;
|
|
|
|
- seg_desct_to_kvm_desct(&seg_desc, selector, kvm_seg);
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static int kvm_load_realmode_segment(struct kvm_vcpu *vcpu, u16 selector, int seg)
|
|
static int kvm_load_realmode_segment(struct kvm_vcpu *vcpu, u16 selector, int seg)
|
|
{
|
|
{
|
|
struct kvm_segment segvar = {
|
|
struct kvm_segment segvar = {
|
|
@@ -4367,7 +4788,7 @@ static int kvm_load_realmode_segment(struct kvm_vcpu *vcpu, u16 selector, int se
|
|
.unusable = 0,
|
|
.unusable = 0,
|
|
};
|
|
};
|
|
kvm_x86_ops->set_segment(vcpu, &segvar, seg);
|
|
kvm_x86_ops->set_segment(vcpu, &segvar, seg);
|
|
- return 0;
|
|
|
|
|
|
+ return X86EMUL_CONTINUE;
|
|
}
|
|
}
|
|
|
|
|
|
static int is_vm86_segment(struct kvm_vcpu *vcpu, int seg)
|
|
static int is_vm86_segment(struct kvm_vcpu *vcpu, int seg)
|
|
@@ -4377,24 +4798,112 @@ static int is_vm86_segment(struct kvm_vcpu *vcpu, int seg)
|
|
(kvm_get_rflags(vcpu) & X86_EFLAGS_VM);
|
|
(kvm_get_rflags(vcpu) & X86_EFLAGS_VM);
|
|
}
|
|
}
|
|
|
|
|
|
-int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
|
|
|
|
- int type_bits, int seg)
|
|
|
|
|
|
+int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg)
|
|
{
|
|
{
|
|
struct kvm_segment kvm_seg;
|
|
struct kvm_segment kvm_seg;
|
|
|
|
+ struct desc_struct seg_desc;
|
|
|
|
+ u8 dpl, rpl, cpl;
|
|
|
|
+ unsigned err_vec = GP_VECTOR;
|
|
|
|
+ u32 err_code = 0;
|
|
|
|
+ bool null_selector = !(selector & ~0x3); /* 0000-0003 are null */
|
|
|
|
+ int ret;
|
|
|
|
|
|
- if (is_vm86_segment(vcpu, seg) || !(vcpu->arch.cr0 & X86_CR0_PE))
|
|
|
|
|
|
+ if (is_vm86_segment(vcpu, seg) || !is_protmode(vcpu))
|
|
return kvm_load_realmode_segment(vcpu, selector, seg);
|
|
return kvm_load_realmode_segment(vcpu, selector, seg);
|
|
- if (load_segment_descriptor_to_kvm_desct(vcpu, selector, &kvm_seg))
|
|
|
|
- return 1;
|
|
|
|
- kvm_seg.type |= type_bits;
|
|
|
|
|
|
|
|
- if (seg != VCPU_SREG_SS && seg != VCPU_SREG_CS &&
|
|
|
|
- seg != VCPU_SREG_LDTR)
|
|
|
|
- if (!kvm_seg.s)
|
|
|
|
- kvm_seg.unusable = 1;
|
|
|
|
|
|
+ /* NULL selector is not valid for TR, CS and SS */
|
|
|
|
+ if ((seg == VCPU_SREG_CS || seg == VCPU_SREG_SS || seg == VCPU_SREG_TR)
|
|
|
|
+ && null_selector)
|
|
|
|
+ goto exception;
|
|
|
|
+
|
|
|
|
+ /* TR should be in GDT only */
|
|
|
|
+ if (seg == VCPU_SREG_TR && (selector & (1 << 2)))
|
|
|
|
+ goto exception;
|
|
|
|
+
|
|
|
|
+ ret = load_guest_segment_descriptor(vcpu, selector, &seg_desc);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ seg_desct_to_kvm_desct(&seg_desc, selector, &kvm_seg);
|
|
|
|
+
|
|
|
|
+ if (null_selector) { /* for NULL selector skip all following checks */
|
|
|
|
+ kvm_seg.unusable = 1;
|
|
|
|
+ goto load;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ err_code = selector & 0xfffc;
|
|
|
|
+ err_vec = GP_VECTOR;
|
|
|
|
|
|
|
|
+ /* can't load system descriptor into segment selecor */
|
|
|
|
+ if (seg <= VCPU_SREG_GS && !kvm_seg.s)
|
|
|
|
+ goto exception;
|
|
|
|
+
|
|
|
|
+ if (!kvm_seg.present) {
|
|
|
|
+ err_vec = (seg == VCPU_SREG_SS) ? SS_VECTOR : NP_VECTOR;
|
|
|
|
+ goto exception;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rpl = selector & 3;
|
|
|
|
+ dpl = kvm_seg.dpl;
|
|
|
|
+ cpl = kvm_x86_ops->get_cpl(vcpu);
|
|
|
|
+
|
|
|
|
+ switch (seg) {
|
|
|
|
+ case VCPU_SREG_SS:
|
|
|
|
+ /*
|
|
|
|
+ * segment is not a writable data segment or segment
|
|
|
|
+ * selector's RPL != CPL or segment selector's RPL != CPL
|
|
|
|
+ */
|
|
|
|
+ if (rpl != cpl || (kvm_seg.type & 0xa) != 0x2 || dpl != cpl)
|
|
|
|
+ goto exception;
|
|
|
|
+ break;
|
|
|
|
+ case VCPU_SREG_CS:
|
|
|
|
+ if (!(kvm_seg.type & 8))
|
|
|
|
+ goto exception;
|
|
|
|
+
|
|
|
|
+ if (kvm_seg.type & 4) {
|
|
|
|
+ /* conforming */
|
|
|
|
+ if (dpl > cpl)
|
|
|
|
+ goto exception;
|
|
|
|
+ } else {
|
|
|
|
+ /* nonconforming */
|
|
|
|
+ if (rpl > cpl || dpl != cpl)
|
|
|
|
+ goto exception;
|
|
|
|
+ }
|
|
|
|
+ /* CS(RPL) <- CPL */
|
|
|
|
+ selector = (selector & 0xfffc) | cpl;
|
|
|
|
+ break;
|
|
|
|
+ case VCPU_SREG_TR:
|
|
|
|
+ if (kvm_seg.s || (kvm_seg.type != 1 && kvm_seg.type != 9))
|
|
|
|
+ goto exception;
|
|
|
|
+ break;
|
|
|
|
+ case VCPU_SREG_LDTR:
|
|
|
|
+ if (kvm_seg.s || kvm_seg.type != 2)
|
|
|
|
+ goto exception;
|
|
|
|
+ break;
|
|
|
|
+ default: /* DS, ES, FS, or GS */
|
|
|
|
+ /*
|
|
|
|
+ * segment is not a data or readable code segment or
|
|
|
|
+ * ((segment is a data or nonconforming code segment)
|
|
|
|
+ * and (both RPL and CPL > DPL))
|
|
|
|
+ */
|
|
|
|
+ if ((kvm_seg.type & 0xa) == 0x8 ||
|
|
|
|
+ (((kvm_seg.type & 0xc) != 0xc) && (rpl > dpl && cpl > dpl)))
|
|
|
|
+ goto exception;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!kvm_seg.unusable && kvm_seg.s) {
|
|
|
|
+ /* mark segment as accessed */
|
|
|
|
+ kvm_seg.type |= 1;
|
|
|
|
+ seg_desc.type |= 1;
|
|
|
|
+ save_guest_segment_descriptor(vcpu, selector, &seg_desc);
|
|
|
|
+ }
|
|
|
|
+load:
|
|
kvm_set_segment(vcpu, &kvm_seg, seg);
|
|
kvm_set_segment(vcpu, &kvm_seg, seg);
|
|
- return 0;
|
|
|
|
|
|
+ return X86EMUL_CONTINUE;
|
|
|
|
+exception:
|
|
|
|
+ kvm_queue_exception_e(vcpu, err_vec, err_code);
|
|
|
|
+ return X86EMUL_PROPAGATE_FAULT;
|
|
}
|
|
}
|
|
|
|
|
|
static void save_state_to_tss32(struct kvm_vcpu *vcpu,
|
|
static void save_state_to_tss32(struct kvm_vcpu *vcpu,
|
|
@@ -4420,6 +4929,14 @@ static void save_state_to_tss32(struct kvm_vcpu *vcpu,
|
|
tss->ldt_selector = get_segment_selector(vcpu, VCPU_SREG_LDTR);
|
|
tss->ldt_selector = get_segment_selector(vcpu, VCPU_SREG_LDTR);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void kvm_load_segment_selector(struct kvm_vcpu *vcpu, u16 sel, int seg)
|
|
|
|
+{
|
|
|
|
+ struct kvm_segment kvm_seg;
|
|
|
|
+ kvm_get_segment(vcpu, &kvm_seg, seg);
|
|
|
|
+ kvm_seg.selector = sel;
|
|
|
|
+ kvm_set_segment(vcpu, &kvm_seg, seg);
|
|
|
|
+}
|
|
|
|
+
|
|
static int load_state_from_tss32(struct kvm_vcpu *vcpu,
|
|
static int load_state_from_tss32(struct kvm_vcpu *vcpu,
|
|
struct tss_segment_32 *tss)
|
|
struct tss_segment_32 *tss)
|
|
{
|
|
{
|
|
@@ -4437,25 +4954,41 @@ static int load_state_from_tss32(struct kvm_vcpu *vcpu,
|
|
kvm_register_write(vcpu, VCPU_REGS_RSI, tss->esi);
|
|
kvm_register_write(vcpu, VCPU_REGS_RSI, tss->esi);
|
|
kvm_register_write(vcpu, VCPU_REGS_RDI, tss->edi);
|
|
kvm_register_write(vcpu, VCPU_REGS_RDI, tss->edi);
|
|
|
|
|
|
- if (kvm_load_segment_descriptor(vcpu, tss->ldt_selector, 0, VCPU_SREG_LDTR))
|
|
|
|
|
|
+ /*
|
|
|
|
+ * SDM says that segment selectors are loaded before segment
|
|
|
|
+ * descriptors
|
|
|
|
+ */
|
|
|
|
+ kvm_load_segment_selector(vcpu, tss->ldt_selector, VCPU_SREG_LDTR);
|
|
|
|
+ kvm_load_segment_selector(vcpu, tss->es, VCPU_SREG_ES);
|
|
|
|
+ kvm_load_segment_selector(vcpu, tss->cs, VCPU_SREG_CS);
|
|
|
|
+ kvm_load_segment_selector(vcpu, tss->ss, VCPU_SREG_SS);
|
|
|
|
+ kvm_load_segment_selector(vcpu, tss->ds, VCPU_SREG_DS);
|
|
|
|
+ kvm_load_segment_selector(vcpu, tss->fs, VCPU_SREG_FS);
|
|
|
|
+ kvm_load_segment_selector(vcpu, tss->gs, VCPU_SREG_GS);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Now load segment descriptors. If fault happenes at this stage
|
|
|
|
+ * it is handled in a context of new task
|
|
|
|
+ */
|
|
|
|
+ if (kvm_load_segment_descriptor(vcpu, tss->ldt_selector, VCPU_SREG_LDTR))
|
|
return 1;
|
|
return 1;
|
|
|
|
|
|
- if (kvm_load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES))
|
|
|
|
|
|
+ if (kvm_load_segment_descriptor(vcpu, tss->es, VCPU_SREG_ES))
|
|
return 1;
|
|
return 1;
|
|
|
|
|
|
- if (kvm_load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS))
|
|
|
|
|
|
+ if (kvm_load_segment_descriptor(vcpu, tss->cs, VCPU_SREG_CS))
|
|
return 1;
|
|
return 1;
|
|
|
|
|
|
- if (kvm_load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS))
|
|
|
|
|
|
+ if (kvm_load_segment_descriptor(vcpu, tss->ss, VCPU_SREG_SS))
|
|
return 1;
|
|
return 1;
|
|
|
|
|
|
- if (kvm_load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS))
|
|
|
|
|
|
+ if (kvm_load_segment_descriptor(vcpu, tss->ds, VCPU_SREG_DS))
|
|
return 1;
|
|
return 1;
|
|
|
|
|
|
- if (kvm_load_segment_descriptor(vcpu, tss->fs, 1, VCPU_SREG_FS))
|
|
|
|
|
|
+ if (kvm_load_segment_descriptor(vcpu, tss->fs, VCPU_SREG_FS))
|
|
return 1;
|
|
return 1;
|
|
|
|
|
|
- if (kvm_load_segment_descriptor(vcpu, tss->gs, 1, VCPU_SREG_GS))
|
|
|
|
|
|
+ if (kvm_load_segment_descriptor(vcpu, tss->gs, VCPU_SREG_GS))
|
|
return 1;
|
|
return 1;
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -4495,19 +5028,33 @@ static int load_state_from_tss16(struct kvm_vcpu *vcpu,
|
|
kvm_register_write(vcpu, VCPU_REGS_RSI, tss->si);
|
|
kvm_register_write(vcpu, VCPU_REGS_RSI, tss->si);
|
|
kvm_register_write(vcpu, VCPU_REGS_RDI, tss->di);
|
|
kvm_register_write(vcpu, VCPU_REGS_RDI, tss->di);
|
|
|
|
|
|
- if (kvm_load_segment_descriptor(vcpu, tss->ldt, 0, VCPU_SREG_LDTR))
|
|
|
|
|
|
+ /*
|
|
|
|
+ * SDM says that segment selectors are loaded before segment
|
|
|
|
+ * descriptors
|
|
|
|
+ */
|
|
|
|
+ kvm_load_segment_selector(vcpu, tss->ldt, VCPU_SREG_LDTR);
|
|
|
|
+ kvm_load_segment_selector(vcpu, tss->es, VCPU_SREG_ES);
|
|
|
|
+ kvm_load_segment_selector(vcpu, tss->cs, VCPU_SREG_CS);
|
|
|
|
+ kvm_load_segment_selector(vcpu, tss->ss, VCPU_SREG_SS);
|
|
|
|
+ kvm_load_segment_selector(vcpu, tss->ds, VCPU_SREG_DS);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Now load segment descriptors. If fault happenes at this stage
|
|
|
|
+ * it is handled in a context of new task
|
|
|
|
+ */
|
|
|
|
+ if (kvm_load_segment_descriptor(vcpu, tss->ldt, VCPU_SREG_LDTR))
|
|
return 1;
|
|
return 1;
|
|
|
|
|
|
- if (kvm_load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES))
|
|
|
|
|
|
+ if (kvm_load_segment_descriptor(vcpu, tss->es, VCPU_SREG_ES))
|
|
return 1;
|
|
return 1;
|
|
|
|
|
|
- if (kvm_load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS))
|
|
|
|
|
|
+ if (kvm_load_segment_descriptor(vcpu, tss->cs, VCPU_SREG_CS))
|
|
return 1;
|
|
return 1;
|
|
|
|
|
|
- if (kvm_load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS))
|
|
|
|
|
|
+ if (kvm_load_segment_descriptor(vcpu, tss->ss, VCPU_SREG_SS))
|
|
return 1;
|
|
return 1;
|
|
|
|
|
|
- if (kvm_load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS))
|
|
|
|
|
|
+ if (kvm_load_segment_descriptor(vcpu, tss->ds, VCPU_SREG_DS))
|
|
return 1;
|
|
return 1;
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -4529,7 +5076,7 @@ static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
|
|
sizeof tss_segment_16))
|
|
sizeof tss_segment_16))
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
- if (kvm_read_guest(vcpu->kvm, get_tss_base_addr(vcpu, nseg_desc),
|
|
|
|
|
|
+ if (kvm_read_guest(vcpu->kvm, get_tss_base_addr_read(vcpu, nseg_desc),
|
|
&tss_segment_16, sizeof tss_segment_16))
|
|
&tss_segment_16, sizeof tss_segment_16))
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
@@ -4537,7 +5084,7 @@ static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
|
|
tss_segment_16.prev_task_link = old_tss_sel;
|
|
tss_segment_16.prev_task_link = old_tss_sel;
|
|
|
|
|
|
if (kvm_write_guest(vcpu->kvm,
|
|
if (kvm_write_guest(vcpu->kvm,
|
|
- get_tss_base_addr(vcpu, nseg_desc),
|
|
|
|
|
|
+ get_tss_base_addr_write(vcpu, nseg_desc),
|
|
&tss_segment_16.prev_task_link,
|
|
&tss_segment_16.prev_task_link,
|
|
sizeof tss_segment_16.prev_task_link))
|
|
sizeof tss_segment_16.prev_task_link))
|
|
goto out;
|
|
goto out;
|
|
@@ -4568,7 +5115,7 @@ static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
|
|
sizeof tss_segment_32))
|
|
sizeof tss_segment_32))
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
- if (kvm_read_guest(vcpu->kvm, get_tss_base_addr(vcpu, nseg_desc),
|
|
|
|
|
|
+ if (kvm_read_guest(vcpu->kvm, get_tss_base_addr_read(vcpu, nseg_desc),
|
|
&tss_segment_32, sizeof tss_segment_32))
|
|
&tss_segment_32, sizeof tss_segment_32))
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
@@ -4576,7 +5123,7 @@ static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
|
|
tss_segment_32.prev_task_link = old_tss_sel;
|
|
tss_segment_32.prev_task_link = old_tss_sel;
|
|
|
|
|
|
if (kvm_write_guest(vcpu->kvm,
|
|
if (kvm_write_guest(vcpu->kvm,
|
|
- get_tss_base_addr(vcpu, nseg_desc),
|
|
|
|
|
|
+ get_tss_base_addr_write(vcpu, nseg_desc),
|
|
&tss_segment_32.prev_task_link,
|
|
&tss_segment_32.prev_task_link,
|
|
sizeof tss_segment_32.prev_task_link))
|
|
sizeof tss_segment_32.prev_task_link))
|
|
goto out;
|
|
goto out;
|
|
@@ -4599,7 +5146,7 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
|
|
u32 old_tss_base = get_segment_base(vcpu, VCPU_SREG_TR);
|
|
u32 old_tss_base = get_segment_base(vcpu, VCPU_SREG_TR);
|
|
u16 old_tss_sel = get_segment_selector(vcpu, VCPU_SREG_TR);
|
|
u16 old_tss_sel = get_segment_selector(vcpu, VCPU_SREG_TR);
|
|
|
|
|
|
- old_tss_base = vcpu->arch.mmu.gva_to_gpa(vcpu, old_tss_base);
|
|
|
|
|
|
+ old_tss_base = kvm_mmu_gva_to_gpa_write(vcpu, old_tss_base, NULL);
|
|
|
|
|
|
/* FIXME: Handle errors. Failure to read either TSS or their
|
|
/* FIXME: Handle errors. Failure to read either TSS or their
|
|
* descriptors should generate a pagefault.
|
|
* descriptors should generate a pagefault.
|
|
@@ -4658,7 +5205,7 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
|
|
&nseg_desc);
|
|
&nseg_desc);
|
|
}
|
|
}
|
|
|
|
|
|
- kvm_x86_ops->set_cr0(vcpu, vcpu->arch.cr0 | X86_CR0_TS);
|
|
|
|
|
|
+ kvm_x86_ops->set_cr0(vcpu, kvm_read_cr0(vcpu) | X86_CR0_TS);
|
|
seg_desct_to_kvm_desct(&nseg_desc, tss_selector, &tr_seg);
|
|
seg_desct_to_kvm_desct(&nseg_desc, tss_selector, &tr_seg);
|
|
tr_seg.type = 11;
|
|
tr_seg.type = 11;
|
|
kvm_set_segment(vcpu, &tr_seg, VCPU_SREG_TR);
|
|
kvm_set_segment(vcpu, &tr_seg, VCPU_SREG_TR);
|
|
@@ -4689,17 +5236,15 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
|
|
|
|
|
|
kvm_set_cr8(vcpu, sregs->cr8);
|
|
kvm_set_cr8(vcpu, sregs->cr8);
|
|
|
|
|
|
- mmu_reset_needed |= vcpu->arch.shadow_efer != sregs->efer;
|
|
|
|
|
|
+ mmu_reset_needed |= vcpu->arch.efer != sregs->efer;
|
|
kvm_x86_ops->set_efer(vcpu, sregs->efer);
|
|
kvm_x86_ops->set_efer(vcpu, sregs->efer);
|
|
kvm_set_apic_base(vcpu, sregs->apic_base);
|
|
kvm_set_apic_base(vcpu, sregs->apic_base);
|
|
|
|
|
|
- kvm_x86_ops->decache_cr4_guest_bits(vcpu);
|
|
|
|
-
|
|
|
|
- mmu_reset_needed |= vcpu->arch.cr0 != sregs->cr0;
|
|
|
|
|
|
+ mmu_reset_needed |= kvm_read_cr0(vcpu) != sregs->cr0;
|
|
kvm_x86_ops->set_cr0(vcpu, sregs->cr0);
|
|
kvm_x86_ops->set_cr0(vcpu, sregs->cr0);
|
|
vcpu->arch.cr0 = sregs->cr0;
|
|
vcpu->arch.cr0 = sregs->cr0;
|
|
|
|
|
|
- mmu_reset_needed |= vcpu->arch.cr4 != sregs->cr4;
|
|
|
|
|
|
+ mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4;
|
|
kvm_x86_ops->set_cr4(vcpu, sregs->cr4);
|
|
kvm_x86_ops->set_cr4(vcpu, sregs->cr4);
|
|
if (!is_long_mode(vcpu) && is_pae(vcpu)) {
|
|
if (!is_long_mode(vcpu) && is_pae(vcpu)) {
|
|
load_pdptrs(vcpu, vcpu->arch.cr3);
|
|
load_pdptrs(vcpu, vcpu->arch.cr3);
|
|
@@ -4734,7 +5279,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
|
|
/* Older userspace won't unhalt the vcpu on reset. */
|
|
/* Older userspace won't unhalt the vcpu on reset. */
|
|
if (kvm_vcpu_is_bsp(vcpu) && kvm_rip_read(vcpu) == 0xfff0 &&
|
|
if (kvm_vcpu_is_bsp(vcpu) && kvm_rip_read(vcpu) == 0xfff0 &&
|
|
sregs->cs.selector == 0xf000 && sregs->cs.base == 0xffff0000 &&
|
|
sregs->cs.selector == 0xf000 && sregs->cs.base == 0xffff0000 &&
|
|
- !(vcpu->arch.cr0 & X86_CR0_PE))
|
|
|
|
|
|
+ !is_protmode(vcpu))
|
|
vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
|
|
vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
|
|
|
|
|
|
vcpu_put(vcpu);
|
|
vcpu_put(vcpu);
|
|
@@ -4832,11 +5377,12 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
|
|
{
|
|
{
|
|
unsigned long vaddr = tr->linear_address;
|
|
unsigned long vaddr = tr->linear_address;
|
|
gpa_t gpa;
|
|
gpa_t gpa;
|
|
|
|
+ int idx;
|
|
|
|
|
|
vcpu_load(vcpu);
|
|
vcpu_load(vcpu);
|
|
- down_read(&vcpu->kvm->slots_lock);
|
|
|
|
- gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, vaddr);
|
|
|
|
- up_read(&vcpu->kvm->slots_lock);
|
|
|
|
|
|
+ idx = srcu_read_lock(&vcpu->kvm->srcu);
|
|
|
|
+ gpa = kvm_mmu_gva_to_gpa_system(vcpu, vaddr, NULL);
|
|
|
|
+ srcu_read_unlock(&vcpu->kvm->srcu, idx);
|
|
tr->physical_address = gpa;
|
|
tr->physical_address = gpa;
|
|
tr->valid = gpa != UNMAPPED_GVA;
|
|
tr->valid = gpa != UNMAPPED_GVA;
|
|
tr->writeable = 1;
|
|
tr->writeable = 1;
|
|
@@ -4917,14 +5463,14 @@ EXPORT_SYMBOL_GPL(fx_init);
|
|
|
|
|
|
void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
|
|
void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
- if (!vcpu->fpu_active || vcpu->guest_fpu_loaded)
|
|
|
|
|
|
+ if (vcpu->guest_fpu_loaded)
|
|
return;
|
|
return;
|
|
|
|
|
|
vcpu->guest_fpu_loaded = 1;
|
|
vcpu->guest_fpu_loaded = 1;
|
|
kvm_fx_save(&vcpu->arch.host_fx_image);
|
|
kvm_fx_save(&vcpu->arch.host_fx_image);
|
|
kvm_fx_restore(&vcpu->arch.guest_fx_image);
|
|
kvm_fx_restore(&vcpu->arch.guest_fx_image);
|
|
|
|
+ trace_kvm_fpu(1);
|
|
}
|
|
}
|
|
-EXPORT_SYMBOL_GPL(kvm_load_guest_fpu);
|
|
|
|
|
|
|
|
void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
|
|
void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
@@ -4935,8 +5481,9 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
|
|
kvm_fx_save(&vcpu->arch.guest_fx_image);
|
|
kvm_fx_save(&vcpu->arch.guest_fx_image);
|
|
kvm_fx_restore(&vcpu->arch.host_fx_image);
|
|
kvm_fx_restore(&vcpu->arch.host_fx_image);
|
|
++vcpu->stat.fpu_reload;
|
|
++vcpu->stat.fpu_reload;
|
|
|
|
+ set_bit(KVM_REQ_DEACTIVATE_FPU, &vcpu->requests);
|
|
|
|
+ trace_kvm_fpu(0);
|
|
}
|
|
}
|
|
-EXPORT_SYMBOL_GPL(kvm_put_guest_fpu);
|
|
|
|
|
|
|
|
void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
|
|
void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
@@ -5088,11 +5635,13 @@ fail:
|
|
|
|
|
|
void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
|
|
void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
|
|
+ int idx;
|
|
|
|
+
|
|
kfree(vcpu->arch.mce_banks);
|
|
kfree(vcpu->arch.mce_banks);
|
|
kvm_free_lapic(vcpu);
|
|
kvm_free_lapic(vcpu);
|
|
- down_read(&vcpu->kvm->slots_lock);
|
|
|
|
|
|
+ idx = srcu_read_lock(&vcpu->kvm->srcu);
|
|
kvm_mmu_destroy(vcpu);
|
|
kvm_mmu_destroy(vcpu);
|
|
- up_read(&vcpu->kvm->slots_lock);
|
|
|
|
|
|
+ srcu_read_unlock(&vcpu->kvm->srcu, idx);
|
|
free_page((unsigned long)vcpu->arch.pio_data);
|
|
free_page((unsigned long)vcpu->arch.pio_data);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -5103,6 +5652,12 @@ struct kvm *kvm_arch_create_vm(void)
|
|
if (!kvm)
|
|
if (!kvm)
|
|
return ERR_PTR(-ENOMEM);
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
|
|
+ kvm->arch.aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL);
|
|
|
|
+ if (!kvm->arch.aliases) {
|
|
|
|
+ kfree(kvm);
|
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
|
+ }
|
|
|
|
+
|
|
INIT_LIST_HEAD(&kvm->arch.active_mmu_pages);
|
|
INIT_LIST_HEAD(&kvm->arch.active_mmu_pages);
|
|
INIT_LIST_HEAD(&kvm->arch.assigned_dev_head);
|
|
INIT_LIST_HEAD(&kvm->arch.assigned_dev_head);
|
|
|
|
|
|
@@ -5159,16 +5714,18 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
|
|
put_page(kvm->arch.apic_access_page);
|
|
put_page(kvm->arch.apic_access_page);
|
|
if (kvm->arch.ept_identity_pagetable)
|
|
if (kvm->arch.ept_identity_pagetable)
|
|
put_page(kvm->arch.ept_identity_pagetable);
|
|
put_page(kvm->arch.ept_identity_pagetable);
|
|
|
|
+ cleanup_srcu_struct(&kvm->srcu);
|
|
|
|
+ kfree(kvm->arch.aliases);
|
|
kfree(kvm);
|
|
kfree(kvm);
|
|
}
|
|
}
|
|
|
|
|
|
-int kvm_arch_set_memory_region(struct kvm *kvm,
|
|
|
|
- struct kvm_userspace_memory_region *mem,
|
|
|
|
|
|
+int kvm_arch_prepare_memory_region(struct kvm *kvm,
|
|
|
|
+ struct kvm_memory_slot *memslot,
|
|
struct kvm_memory_slot old,
|
|
struct kvm_memory_slot old,
|
|
|
|
+ struct kvm_userspace_memory_region *mem,
|
|
int user_alloc)
|
|
int user_alloc)
|
|
{
|
|
{
|
|
- int npages = mem->memory_size >> PAGE_SHIFT;
|
|
|
|
- struct kvm_memory_slot *memslot = &kvm->memslots[mem->slot];
|
|
|
|
|
|
+ int npages = memslot->npages;
|
|
|
|
|
|
/*To keep backward compatibility with older userspace,
|
|
/*To keep backward compatibility with older userspace,
|
|
*x86 needs to hanlde !user_alloc case.
|
|
*x86 needs to hanlde !user_alloc case.
|
|
@@ -5188,26 +5745,35 @@ int kvm_arch_set_memory_region(struct kvm *kvm,
|
|
if (IS_ERR((void *)userspace_addr))
|
|
if (IS_ERR((void *)userspace_addr))
|
|
return PTR_ERR((void *)userspace_addr);
|
|
return PTR_ERR((void *)userspace_addr);
|
|
|
|
|
|
- /* set userspace_addr atomically for kvm_hva_to_rmapp */
|
|
|
|
- spin_lock(&kvm->mmu_lock);
|
|
|
|
memslot->userspace_addr = userspace_addr;
|
|
memslot->userspace_addr = userspace_addr;
|
|
- spin_unlock(&kvm->mmu_lock);
|
|
|
|
- } else {
|
|
|
|
- if (!old.user_alloc && old.rmap) {
|
|
|
|
- int ret;
|
|
|
|
-
|
|
|
|
- down_write(¤t->mm->mmap_sem);
|
|
|
|
- ret = do_munmap(current->mm, old.userspace_addr,
|
|
|
|
- old.npages * PAGE_SIZE);
|
|
|
|
- up_write(¤t->mm->mmap_sem);
|
|
|
|
- if (ret < 0)
|
|
|
|
- printk(KERN_WARNING
|
|
|
|
- "kvm_vm_ioctl_set_memory_region: "
|
|
|
|
- "failed to munmap memory\n");
|
|
|
|
- }
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void kvm_arch_commit_memory_region(struct kvm *kvm,
|
|
|
|
+ struct kvm_userspace_memory_region *mem,
|
|
|
|
+ struct kvm_memory_slot old,
|
|
|
|
+ int user_alloc)
|
|
|
|
+{
|
|
|
|
+
|
|
|
|
+ int npages = mem->memory_size >> PAGE_SHIFT;
|
|
|
|
+
|
|
|
|
+ if (!user_alloc && !old.user_alloc && old.rmap && !npages) {
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ down_write(¤t->mm->mmap_sem);
|
|
|
|
+ ret = do_munmap(current->mm, old.userspace_addr,
|
|
|
|
+ old.npages * PAGE_SIZE);
|
|
|
|
+ up_write(¤t->mm->mmap_sem);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ printk(KERN_WARNING
|
|
|
|
+ "kvm_vm_ioctl_set_memory_region: "
|
|
|
|
+ "failed to munmap memory\n");
|
|
|
|
+ }
|
|
|
|
+
|
|
spin_lock(&kvm->mmu_lock);
|
|
spin_lock(&kvm->mmu_lock);
|
|
if (!kvm->arch.n_requested_mmu_pages) {
|
|
if (!kvm->arch.n_requested_mmu_pages) {
|
|
unsigned int nr_mmu_pages = kvm_mmu_calculate_mmu_pages(kvm);
|
|
unsigned int nr_mmu_pages = kvm_mmu_calculate_mmu_pages(kvm);
|
|
@@ -5216,8 +5782,6 @@ int kvm_arch_set_memory_region(struct kvm *kvm,
|
|
|
|
|
|
kvm_mmu_slot_remove_write_access(kvm, mem->slot);
|
|
kvm_mmu_slot_remove_write_access(kvm, mem->slot);
|
|
spin_unlock(&kvm->mmu_lock);
|
|
spin_unlock(&kvm->mmu_lock);
|
|
-
|
|
|
|
- return 0;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void kvm_arch_flush_shadow(struct kvm *kvm)
|
|
void kvm_arch_flush_shadow(struct kvm *kvm)
|