diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/kvm/kvm.h | 5 | ||||
-rw-r--r-- | drivers/kvm/kvm_main.c | 69 | ||||
-rw-r--r-- | drivers/kvm/svm.c | 4 | ||||
-rw-r--r-- | drivers/kvm/vmx.c | 4 |
4 files changed, 78 insertions, 4 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index 59cbc5b1d905..be3a0e7ecae4 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h | |||
@@ -55,6 +55,7 @@ | |||
55 | #define KVM_NUM_MMU_PAGES 256 | 55 | #define KVM_NUM_MMU_PAGES 256 |
56 | #define KVM_MIN_FREE_MMU_PAGES 5 | 56 | #define KVM_MIN_FREE_MMU_PAGES 5 |
57 | #define KVM_REFILL_PAGES 25 | 57 | #define KVM_REFILL_PAGES 25 |
58 | #define KVM_MAX_CPUID_ENTRIES 40 | ||
58 | 59 | ||
59 | #define FX_IMAGE_SIZE 512 | 60 | #define FX_IMAGE_SIZE 512 |
60 | #define FX_IMAGE_ALIGN 16 | 61 | #define FX_IMAGE_ALIGN 16 |
@@ -286,6 +287,9 @@ struct kvm_vcpu { | |||
286 | u32 ar; | 287 | u32 ar; |
287 | } tr, es, ds, fs, gs; | 288 | } tr, es, ds, fs, gs; |
288 | } rmode; | 289 | } rmode; |
290 | |||
291 | int cpuid_nent; | ||
292 | struct kvm_cpuid_entry cpuid_entries[KVM_MAX_CPUID_ENTRIES]; | ||
289 | }; | 293 | }; |
290 | 294 | ||
291 | struct kvm_memory_slot { | 295 | struct kvm_memory_slot { |
@@ -446,6 +450,7 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value, | |||
446 | 450 | ||
447 | struct x86_emulate_ctxt; | 451 | struct x86_emulate_ctxt; |
448 | 452 | ||
453 | void kvm_emulate_cpuid(struct kvm_vcpu *vcpu); | ||
449 | int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address); | 454 | int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address); |
450 | int emulate_clts(struct kvm_vcpu *vcpu); | 455 | int emulate_clts(struct kvm_vcpu *vcpu); |
451 | int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr, | 456 | int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr, |
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index ff8bcfee76e5..caec54fbf07f 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -1504,6 +1504,43 @@ void save_msrs(struct vmx_msr_entry *e, int n) | |||
1504 | } | 1504 | } |
1505 | EXPORT_SYMBOL_GPL(save_msrs); | 1505 | EXPORT_SYMBOL_GPL(save_msrs); |
1506 | 1506 | ||
1507 | void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) | ||
1508 | { | ||
1509 | int i; | ||
1510 | u32 function; | ||
1511 | struct kvm_cpuid_entry *e, *best; | ||
1512 | |||
1513 | kvm_arch_ops->cache_regs(vcpu); | ||
1514 | function = vcpu->regs[VCPU_REGS_RAX]; | ||
1515 | vcpu->regs[VCPU_REGS_RAX] = 0; | ||
1516 | vcpu->regs[VCPU_REGS_RBX] = 0; | ||
1517 | vcpu->regs[VCPU_REGS_RCX] = 0; | ||
1518 | vcpu->regs[VCPU_REGS_RDX] = 0; | ||
1519 | best = NULL; | ||
1520 | for (i = 0; i < vcpu->cpuid_nent; ++i) { | ||
1521 | e = &vcpu->cpuid_entries[i]; | ||
1522 | if (e->function == function) { | ||
1523 | best = e; | ||
1524 | break; | ||
1525 | } | ||
1526 | /* | ||
1527 | * Both basic or both extended? | ||
1528 | */ | ||
1529 | if (((e->function ^ function) & 0x80000000) == 0) | ||
1530 | if (!best || e->function > best->function) | ||
1531 | best = e; | ||
1532 | } | ||
1533 | if (best) { | ||
1534 | vcpu->regs[VCPU_REGS_RAX] = best->eax; | ||
1535 | vcpu->regs[VCPU_REGS_RBX] = best->ebx; | ||
1536 | vcpu->regs[VCPU_REGS_RCX] = best->ecx; | ||
1537 | vcpu->regs[VCPU_REGS_RDX] = best->edx; | ||
1538 | } | ||
1539 | kvm_arch_ops->decache_regs(vcpu); | ||
1540 | kvm_arch_ops->skip_emulated_instruction(vcpu); | ||
1541 | } | ||
1542 | EXPORT_SYMBOL_GPL(kvm_emulate_cpuid); | ||
1543 | |||
1507 | static void complete_pio(struct kvm_vcpu *vcpu) | 1544 | static void complete_pio(struct kvm_vcpu *vcpu) |
1508 | { | 1545 | { |
1509 | struct kvm_io *io = &vcpu->run->io; | 1546 | struct kvm_io *io = &vcpu->run->io; |
@@ -2075,6 +2112,26 @@ out: | |||
2075 | return r; | 2112 | return r; |
2076 | } | 2113 | } |
2077 | 2114 | ||
2115 | static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu, | ||
2116 | struct kvm_cpuid *cpuid, | ||
2117 | struct kvm_cpuid_entry __user *entries) | ||
2118 | { | ||
2119 | int r; | ||
2120 | |||
2121 | r = -E2BIG; | ||
2122 | if (cpuid->nent > KVM_MAX_CPUID_ENTRIES) | ||
2123 | goto out; | ||
2124 | r = -EFAULT; | ||
2125 | if (copy_from_user(&vcpu->cpuid_entries, entries, | ||
2126 | cpuid->nent * sizeof(struct kvm_cpuid_entry))) | ||
2127 | goto out; | ||
2128 | vcpu->cpuid_nent = cpuid->nent; | ||
2129 | return 0; | ||
2130 | |||
2131 | out: | ||
2132 | return r; | ||
2133 | } | ||
2134 | |||
2078 | static long kvm_vcpu_ioctl(struct file *filp, | 2135 | static long kvm_vcpu_ioctl(struct file *filp, |
2079 | unsigned int ioctl, unsigned long arg) | 2136 | unsigned int ioctl, unsigned long arg) |
2080 | { | 2137 | { |
@@ -2181,6 +2238,18 @@ static long kvm_vcpu_ioctl(struct file *filp, | |||
2181 | case KVM_SET_MSRS: | 2238 | case KVM_SET_MSRS: |
2182 | r = msr_io(vcpu, argp, do_set_msr, 0); | 2239 | r = msr_io(vcpu, argp, do_set_msr, 0); |
2183 | break; | 2240 | break; |
2241 | case KVM_SET_CPUID: { | ||
2242 | struct kvm_cpuid __user *cpuid_arg = argp; | ||
2243 | struct kvm_cpuid cpuid; | ||
2244 | |||
2245 | r = -EFAULT; | ||
2246 | if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid)) | ||
2247 | goto out; | ||
2248 | r = kvm_vcpu_ioctl_set_cpuid(vcpu, &cpuid, cpuid_arg->entries); | ||
2249 | if (r) | ||
2250 | goto out; | ||
2251 | break; | ||
2252 | } | ||
2184 | default: | 2253 | default: |
2185 | ; | 2254 | ; |
2186 | } | 2255 | } |
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index c35b8c83bf3f..d4b2936479d9 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c | |||
@@ -1101,8 +1101,8 @@ static int task_switch_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_r | |||
1101 | static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | 1101 | static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) |
1102 | { | 1102 | { |
1103 | vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2; | 1103 | vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2; |
1104 | kvm_run->exit_reason = KVM_EXIT_CPUID; | 1104 | kvm_emulate_cpuid(vcpu); |
1105 | return 0; | 1105 | return 1; |
1106 | } | 1106 | } |
1107 | 1107 | ||
1108 | static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | 1108 | static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) |
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index 4d5f40fcb651..71410a65bb90 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c | |||
@@ -1585,8 +1585,8 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1585 | 1585 | ||
1586 | static int handle_cpuid(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | 1586 | static int handle_cpuid(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) |
1587 | { | 1587 | { |
1588 | kvm_run->exit_reason = KVM_EXIT_CPUID; | 1588 | kvm_emulate_cpuid(vcpu); |
1589 | return 0; | 1589 | return 1; |
1590 | } | 1590 | } |
1591 | 1591 | ||
1592 | static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | 1592 | static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) |