summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryan Cantrill <bryan@joyent.com>2011-10-13 04:37:22 +0000
committerBryan Cantrill <bryan@joyent.com>2011-10-13 04:37:22 +0000
commitbea064793c86b83c043bd862f28768f1bb1d3803 (patch)
tree71325957ece02d951191fb2ceff532e8143b07d6
parent70d98895e10fb59a8589d9d9fa64721cab5059ae (diff)
downloadillumos-kvm-bea064793c86b83c043bd862f28768f1bb1d3803.tar.gz
HVM-666 VMs will panic/hang with more than 64GB
HVM-675 conflicting definitions of kvm_read_guest_virt_helper() HVM-676 emulation failure should always result in a verbose kernel message
-rw-r--r--kvm_emulate.c2
-rw-r--r--kvm_host.h2
-rw-r--r--kvm_x86.c90
3 files changed, 46 insertions, 48 deletions
diff --git a/kvm_emulate.c b/kvm_emulate.c
index fb2c768..80b9345 100644
--- a/kvm_emulate.c
+++ b/kvm_emulate.c
@@ -1992,7 +1992,7 @@ realmode_set_cr(struct kvm_vcpu *vcpu,
}
}
-static int
+int
kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes,
struct kvm_vcpu *vcpu, uint32_t access, uint32_t *error)
{
diff --git a/kvm_host.h b/kvm_host.h
index 13b6a39..81ea4e0 100644
--- a/kvm_host.h
+++ b/kvm_host.h
@@ -287,6 +287,8 @@ extern void kvm_get_pfn(struct kvm_vcpu *, pfn_t);
extern int kvm_read_guest_page(struct kvm *, gfn_t, void *, int, int);
extern int kvm_read_guest_atomic(struct kvm *, gpa_t, void *, unsigned long);
extern int kvm_read_guest(struct kvm *, gpa_t, void *, unsigned long);
+extern int kvm_read_guest_virt_helper(gva_t, void *, unsigned int,
+ struct kvm_vcpu *, uint32_t, uint32_t *);
extern int kvm_write_guest_page(struct kvm *, gfn_t, const void *, int, int);
extern int kvm_write_guest(struct kvm *, gpa_t, const void *, unsigned long);
extern int kvm_clear_guest_page(struct kvm *, gfn_t, int, int);
diff --git a/kvm_x86.c b/kvm_x86.c
index 329cea7..97f3b7d 100644
--- a/kvm_x86.c
+++ b/kvm_x86.c
@@ -2371,38 +2371,6 @@ kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva, uint32_t *error)
return (vcpu->arch.mmu.gva_to_gpa(vcpu, gva, access, error));
}
-static int
-kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes,
- struct kvm_vcpu *vcpu, uint32_t access, uint32_t *error)
-{
- uintptr_t data = (uintptr_t)val;
- int r = 0; /* X86EMUL_CONTINUE */
-
- while (bytes) {
- gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr,
- access, error);
- unsigned offset = addr & (PAGESIZE-1);
- unsigned toread = min(bytes, (unsigned)PAGESIZE - offset);
- int ret;
-
- if (gpa == UNMAPPED_GVA) {
- r = 1; /* X86EMUL_PROPAGATE_FAULT */
- goto out;
- }
- ret = kvm_read_guest(vcpu->kvm, gpa, (void *)data, toread);
- if (ret < 0) {
- r = 1; /* X86EMUL_UNHANDLEABLE */
- goto out;
- }
-
- bytes -= toread;
- data += toread;
- addr += toread;
- }
-out:
- return (r);
-}
-
/* used for instruction fetching */
static int
kvm_fetch_guest_virt(gva_t addr, void *val, unsigned int bytes,
@@ -2645,6 +2613,7 @@ emulate_instruction(struct kvm_vcpu *vcpu, unsigned long cr2,
int r, shadow_mask;
struct decode_cache *c;
struct kvm_run *run = vcpu->run;
+ char *ctx = NULL;
kvm_clear_exception_queue(vcpu);
vcpu->arch.mmio_fault_cr2 = cr2;
@@ -2680,28 +2649,43 @@ emulate_instruction(struct kvm_vcpu *vcpu, unsigned long cr2,
*/
c = &vcpu->arch.emulate_ctxt.decode;
if (emulation_type & EMULTYPE_TRAP_UD) {
- if (!c->twobyte)
- return (EMULATE_FAIL);
+ if (!c->twobyte) {
+ ctx = "non-twobyte";
+ goto fail;
+ }
+
switch (c->b) {
case 0x01: /* VMMCALL */
- if (c->modrm_mod != 3 || c->modrm_rm != 1)
- return (EMULATE_FAIL);
+ if (c->modrm_mod != 3 || c->modrm_rm != 1) {
+ ctx = "vmmcall";
+ goto fail;
+ }
+
break;
case 0x34: /* sysenter */
case 0x35: /* sysexit */
- if (c->modrm_mod != 0 || c->modrm_rm != 0)
- return (EMULATE_FAIL);
+ if (c->modrm_mod != 0 || c->modrm_rm != 0) {
+ ctx = "sysenter/sysexit";
+ goto fail;
+ }
+
break;
case 0x05: /* syscall */
- if (c->modrm_mod != 0 || c->modrm_rm != 0)
- return (EMULATE_FAIL);
+ if (c->modrm_mod != 0 || c->modrm_rm != 0) {
+ ctx = "syscall";
+ goto fail;
+ }
+
break;
default:
- return (EMULATE_FAIL);
+ ctx = "unknown";
+ goto fail;
}
- if (!(c->modrm_reg == 0 || c->modrm_reg == 3))
- return (EMULATE_FAIL);
+ if (!(c->modrm_reg == 0 || c->modrm_reg == 3)) {
+ ctx = "modcrm";
+ goto fail;
+ }
}
KVM_VCPU_KSTAT_INC(vcpu, kvmvs_insn_emulation);
@@ -2711,7 +2695,9 @@ emulate_instruction(struct kvm_vcpu *vcpu, unsigned long cr2,
if (kvm_mmu_unprotect_page_virt(vcpu, cr2))
return (EMULATE_DONE);
- return (EMULATE_FAIL);
+
+ ctx = "decode";
+ goto fail;
}
}
@@ -2740,9 +2726,10 @@ emulate_instruction(struct kvm_vcpu *vcpu, unsigned long cr2,
if (r) {
if (kvm_mmu_unprotect_page_virt(vcpu, cr2))
return (EMULATE_DONE);
+
if (!vcpu->mmio_needed) {
- kvm_report_emulation_failure(vcpu, "mmio");
- return (EMULATE_FAIL);
+ ctx = "mmio";
+ goto fail;
}
return (EMULATE_DO_MMIO);
@@ -2756,6 +2743,10 @@ emulate_instruction(struct kvm_vcpu *vcpu, unsigned long cr2,
}
return (EMULATE_DONE);
+
+fail:
+ kvm_report_emulation_failure(vcpu, ctx != NULL ? ctx : "????");
+ return (EMULATE_FAIL);
}
static int
@@ -3160,7 +3151,12 @@ kvm_find_cpuid_entry(struct kvm_vcpu *vcpu, uint32_t function, uint32_t index)
int
cpuid_maxphyaddr(struct kvm_vcpu *vcpu)
{
- return (36); /* from linux. number of bits, perhaps? */
+ struct kvm_cpuid_entry2 *best;
+
+ if ((best = kvm_find_cpuid_entry(vcpu, 0x80000008, 0)) != NULL)
+ return (best->eax & 0xff);
+
+ return (36);
}
void