* [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5
@ 2011-04-04 10:39 Joerg Roedel
2011-04-04 10:39 ` [PATCH 01/15] KVM: x86 emulator: add framework for instruction intercepts Joerg Roedel
` (15 more replies)
0 siblings, 16 replies; 17+ messages in thread
From: Joerg Roedel @ 2011-04-04 10:39 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: kvm
Hi,
here is the next version of this patch-set. The changes to the previous
post are limited to the cosmetic changes mentioned by Avi. The full
function names are used now in the opcode table so that the #defines
could be removed and the link between the opcode and the function for
permission checking is now more clear.
Regards,
Joerg
Diffstat:
arch/x86/include/asm/kvm_emulate.h | 90 ++++++++
arch/x86/include/asm/kvm_host.h | 22 ++
arch/x86/kvm/emulate.c | 411 ++++++++++++++++++++++++++++++------
arch/x86/kvm/svm.c | 264 +++++++++++++++++++-----
arch/x86/kvm/vmx.c | 9 +
arch/x86/kvm/x86.c | 25 +--
6 files changed, 695 insertions(+), 126 deletions(-)
Shortlog:
Avi Kivity (2):
KVM: x86 emulator: add framework for instruction intercepts
KVM: x86 emulator: add SVM intercepts
Joerg Roedel (13):
KVM: x86 emulator: Don't write-back cpu-state on X86EMUL_INTERCEPTED
KVM: x86 emulator: Add check_perm callback
KVM: x86 emulator: Add flag to check for protected mode instructions
KVM: x86: Add x86 callback for intercept check
KVM: SVM: Add intercept check for emulated cr accesses
KVM: SVM: Add intercept check for accessing dr registers
KVM: SVM: Add intercept checks for descriptor table accesses
KVM: SVM: Add intercept checks for SVM instructions
KVM: SVM: Add intercept checks for remaining group7 instructions
KVM: SVM: Add intercept checks for remaining twobyte instructions
KVM: SVM: Add intercept checks for one-byte instructions
KVM: SVM: Add checks for IO instructions
KVM: SVM: Remove nested sel_cr0_write handling code
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 01/15] KVM: x86 emulator: add framework for instruction intercepts
2011-04-04 10:39 [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Joerg Roedel
@ 2011-04-04 10:39 ` Joerg Roedel
2011-04-04 10:39 ` [PATCH 02/15] KVM: x86 emulator: add SVM intercepts Joerg Roedel
` (14 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Joerg Roedel @ 2011-04-04 10:39 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Avi Kivity, Joerg Roedel
From: Avi Kivity <avi@redhat.com>
When running in guest mode, certain instructions can be intercepted by
hardware. This also holds for nested guests running on emulated
virtualization hardware, in particular instructions emulated by kvm
itself.
This patch adds a framework for intercepting instructions. If an
instruction is marked for interception, and if we're running in guest
mode, a callback is called to check whether an intercept is needed or
not. The callback is called at three points in time: immediately after
beginning execution, after checking privilge exceptions, and after
checking memory exception. This suits the different interception points
defined for different instructions and for the various virtualization
instruction sets.
In addition, a new X86EMUL_INTERCEPT is defined, which any callback or
memory access may define, allowing the more complicated intercepts to be
implemented in existing callbacks.
Signed-off-by: Avi Kivity <avi@redhat.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/include/asm/kvm_emulate.h | 20 ++++++++++++++++++++
arch/x86/kvm/emulate.c | 26 ++++++++++++++++++++++++++
arch/x86/kvm/x86.c | 9 +++++++++
3 files changed, 55 insertions(+), 0 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 0f52135..92e251d 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -14,6 +14,8 @@
#include <asm/desc_defs.h>
struct x86_emulate_ctxt;
+enum x86_intercept;
+enum x86_intercept_stage;
struct x86_exception {
u8 vector;
@@ -62,6 +64,7 @@ struct x86_exception {
#define X86EMUL_RETRY_INSTR 3 /* retry the instruction for some reason */
#define X86EMUL_CMPXCHG_FAILED 4 /* cmpxchg did not see expected value */
#define X86EMUL_IO_NEEDED 5 /* IO is needed to complete emulation */
+#define X86EMUL_INTERCEPTED 6 /* Intercepted by nested VMCB/VMCS */
struct x86_emulate_ops {
/*
@@ -158,6 +161,9 @@ struct x86_emulate_ops {
int (*set_dr)(int dr, unsigned long value, struct kvm_vcpu *vcpu);
int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
+ int (*intercept)(struct x86_emulate_ctxt *ctxt,
+ enum x86_intercept intercept,
+ enum x86_intercept_stage stage);
};
/* Type, address-of, and value of an instruction's operand. */
@@ -197,6 +203,7 @@ struct read_cache {
struct decode_cache {
u8 twobyte;
u8 b;
+ u8 intercept;
u8 lock_prefix;
u8 rep_prefix;
u8 op_bytes;
@@ -238,6 +245,7 @@ struct x86_emulate_ctxt {
/* interruptibility state, as a result of execution of STI or MOV SS */
int interruptibility;
+ bool guest_mode; /* guest running a nested guest */
bool perm_ok; /* do not check permissions if true */
bool only_vendor_specific_insn;
@@ -259,6 +267,18 @@ struct x86_emulate_ctxt {
#define X86EMUL_MODE_PROT32 4 /* 32-bit protected mode. */
#define X86EMUL_MODE_PROT64 8 /* 64-bit (long) mode. */
+enum x86_intercept_stage {
+ X86_ICPT_PRE_EXCEPT,
+ X86_ICPT_POST_EXCEPT,
+ X86_ICPT_POST_MEMACCESS,
+};
+
+enum x86_intercept {
+ x86_intercept_none,
+
+ nr_x86_intercepts
+};
+
/* Host execution mode. */
#if defined(CONFIG_X86_32)
#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT32
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 14c5ad5..1c574ae 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -102,6 +102,7 @@
struct opcode {
u32 flags;
+ u8 intercept;
union {
int (*execute)(struct x86_emulate_ctxt *ctxt);
struct opcode *group;
@@ -2326,10 +2327,13 @@ static int em_mov(struct x86_emulate_ctxt *ctxt)
}
#define D(_y) { .flags = (_y) }
+#define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i }
#define N D(0)
#define G(_f, _g) { .flags = ((_f) | Group), .u.group = (_g) }
#define GD(_f, _g) { .flags = ((_f) | Group | GroupDual), .u.gdual = (_g) }
#define I(_f, _e) { .flags = (_f), .u.execute = (_e) }
+#define II(_f, _e, _i) \
+ { .flags = (_f), .u.execute = (_e), .intercept = x86_intercept_##_i }
#define D2bv(_f) D((_f) | ByteOp), D(_f)
#define I2bv(_f, _e) I((_f) | ByteOp, _e), I(_f, _e)
@@ -2745,6 +2749,7 @@ done_prefixes:
}
c->execute = opcode.u.execute;
+ c->intercept = opcode.intercept;
/* Unrecognised? */
if (c->d == 0 || (c->d & Undefined))
@@ -2979,12 +2984,26 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
goto done;
}
+ if (unlikely(ctxt->guest_mode) && c->intercept) {
+ rc = ops->intercept(ctxt, c->intercept,
+ X86_ICPT_PRE_EXCEPT);
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
+ }
+
/* Privileged instruction can be executed only in CPL=0 */
if ((c->d & Priv) && ops->cpl(ctxt->vcpu)) {
rc = emulate_gp(ctxt, 0);
goto done;
}
+ if (unlikely(ctxt->guest_mode) && c->intercept) {
+ rc = ops->intercept(ctxt, c->intercept,
+ X86_ICPT_POST_EXCEPT);
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
+ }
+
if (c->rep_prefix && (c->d & String)) {
/* All REP prefixes have the same first termination condition */
if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0) {
@@ -3023,6 +3042,13 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
special_insn:
+ if (unlikely(ctxt->guest_mode) && c->intercept) {
+ rc = ops->intercept(ctxt, c->intercept,
+ X86_ICPT_POST_MEMACCESS);
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
+ }
+
if (c->execute) {
rc = c->execute(ctxt);
if (rc != X86EMUL_CONTINUE)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index c14c5f0..2b4f5b2 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4242,6 +4242,13 @@ static void emulator_set_segment_selector(u16 sel, int seg,
kvm_set_segment(vcpu, &kvm_seg, seg);
}
+static int emulator_intercept(struct x86_emulate_ctxt *ctxt,
+ enum x86_intercept intercept,
+ enum x86_intercept_stage stage)
+{
+ return X86EMUL_CONTINUE;
+}
+
static struct x86_emulate_ops emulate_ops = {
.read_std = kvm_read_guest_virt_system,
.write_std = kvm_write_guest_virt_system,
@@ -4265,6 +4272,7 @@ static struct x86_emulate_ops emulate_ops = {
.set_dr = emulator_set_dr,
.set_msr = kvm_set_msr,
.get_msr = kvm_get_msr,
+ .intercept = emulator_intercept,
};
static void cache_all_regs(struct kvm_vcpu *vcpu)
@@ -4319,6 +4327,7 @@ static void init_emulate_ctxt(struct kvm_vcpu *vcpu)
? X86EMUL_MODE_VM86 : cs_l
? X86EMUL_MODE_PROT64 : cs_db
? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
+ vcpu->arch.emulate_ctxt.guest_mode = is_guest_mode(vcpu);
memset(c, 0, sizeof(struct decode_cache));
memcpy(c->regs, vcpu->arch.regs, sizeof c->regs);
}
--
1.7.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 02/15] KVM: x86 emulator: add SVM intercepts
2011-04-04 10:39 [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Joerg Roedel
2011-04-04 10:39 ` [PATCH 01/15] KVM: x86 emulator: add framework for instruction intercepts Joerg Roedel
@ 2011-04-04 10:39 ` Joerg Roedel
2011-04-04 10:39 ` [PATCH 03/15] KVM: x86 emulator: Don't write-back cpu-state on X86EMUL_INTERCEPTED Joerg Roedel
` (13 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Joerg Roedel @ 2011-04-04 10:39 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Avi Kivity, Joerg Roedel
From: Avi Kivity <avi@redhat.com>
Add intercept codes for instructions defined by SVM as
interceptable.
Signed-off-by: Avi Kivity <avi@redhat.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/include/asm/kvm_emulate.h | 35 +++++++++++++++++++++++++++++++++++
arch/x86/kvm/emulate.c | 24 +++++++++++++-----------
2 files changed, 48 insertions(+), 11 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 92e251d..436207e 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -275,6 +275,41 @@ enum x86_intercept_stage {
enum x86_intercept {
x86_intercept_none,
+ x86_intercept_lmsw,
+ x86_intercept_smsw,
+ x86_intercept_lidt,
+ x86_intercept_sidt,
+ x86_intercept_lgdt,
+ x86_intercept_sgdt,
+ x86_intercept_lldt,
+ x86_intercept_sldt,
+ x86_intercept_ltr,
+ x86_intercept_str,
+ x86_intercept_rdtsc,
+ x86_intercept_rdpmc,
+ x86_intercept_pushf,
+ x86_intercept_popf,
+ x86_intercept_cpuid,
+ x86_intercept_rsm,
+ x86_intercept_iret,
+ x86_intercept_intn,
+ x86_intercept_invd,
+ x86_intercept_pause,
+ x86_intercept_hlt,
+ x86_intercept_invlpg,
+ x86_intercept_invlpga,
+ x86_intercept_vmrun,
+ x86_intercept_vmload,
+ x86_intercept_vmsave,
+ x86_intercept_vmmcall,
+ x86_intercept_stgi,
+ x86_intercept_clgi,
+ x86_intercept_skinit,
+ x86_intercept_rdtscp,
+ x86_intercept_icebp,
+ x86_intercept_wbinvd,
+ x86_intercept_monitor,
+ x86_intercept_mwait,
nr_x86_intercepts
};
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 1c574ae..cee6fc1 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2371,15 +2371,15 @@ static struct opcode group5[] = {
};
static struct group_dual group7 = { {
- N, N, D(ModRM | SrcMem | Priv), D(ModRM | SrcMem | Priv),
- D(SrcNone | ModRM | DstMem | Mov), N,
- D(SrcMem16 | ModRM | Mov | Priv),
- D(SrcMem | ModRM | ByteOp | Priv | NoAccess),
+ N, N, DI(ModRM | SrcMem | Priv, lgdt), DI(ModRM | SrcMem | Priv, lidt),
+ DI(SrcNone | ModRM | DstMem | Mov, smsw), N,
+ DI(SrcMem16 | ModRM | Mov | Priv, lmsw),
+ DI(SrcMem | ModRM | ByteOp | Priv | NoAccess, invlpg),
}, {
D(SrcNone | ModRM | Priv | VendorSpecific), N,
N, D(SrcNone | ModRM | Priv | VendorSpecific),
- D(SrcNone | ModRM | DstMem | Mov), N,
- D(SrcMem16 | ModRM | Mov | Priv), N,
+ DI(SrcNone | ModRM | DstMem | Mov, smsw), N,
+ DI(SrcMem16 | ModRM | Mov | Priv, lmsw), N,
} };
static struct opcode group8[] = {
@@ -2454,7 +2454,7 @@ static struct opcode opcode_table[256] = {
/* 0x98 - 0x9F */
D(DstAcc | SrcNone), I(ImplicitOps | SrcAcc, em_cwd),
I(SrcImmFAddr | No64, em_call_far), N,
- D(ImplicitOps | Stack), D(ImplicitOps | Stack), N, N,
+ DI(ImplicitOps | Stack, pushf), DI(ImplicitOps | Stack, popf), N, N,
/* 0xA0 - 0xA7 */
I2bv(DstAcc | SrcMem | Mov | MemAbs, em_mov),
I2bv(DstMem | SrcAcc | Mov | MemAbs, em_mov),
@@ -2477,7 +2477,8 @@ static struct opcode opcode_table[256] = {
G(ByteOp, group11), G(0, group11),
/* 0xC8 - 0xCF */
N, N, N, D(ImplicitOps | Stack),
- D(ImplicitOps), D(SrcImmByte), D(ImplicitOps | No64), D(ImplicitOps),
+ D(ImplicitOps), DI(SrcImmByte, intn),
+ D(ImplicitOps | No64), DI(ImplicitOps, iret),
/* 0xD0 - 0xD7 */
D2bv(DstMem | SrcOne | ModRM), D2bv(DstMem | ModRM),
N, N, N, N,
@@ -2492,7 +2493,8 @@ static struct opcode opcode_table[256] = {
D2bv(SrcNone | DstAcc), D2bv(SrcAcc | ImplicitOps),
/* 0xF0 - 0xF7 */
N, N, N, N,
- D(ImplicitOps | Priv), D(ImplicitOps), G(ByteOp, group3), G(0, group3),
+ DI(ImplicitOps | Priv, hlt), D(ImplicitOps),
+ G(ByteOp, group3), G(0, group3),
/* 0xF8 - 0xFF */
D(ImplicitOps), D(ImplicitOps), D(ImplicitOps), D(ImplicitOps),
D(ImplicitOps), D(ImplicitOps), G(0, group4), G(0, group5),
@@ -2502,7 +2504,7 @@ static struct opcode twobyte_table[256] = {
/* 0x00 - 0x0F */
N, GD(0, &group7), N, N,
N, D(ImplicitOps | VendorSpecific), D(ImplicitOps | Priv), N,
- D(ImplicitOps | Priv), D(ImplicitOps | Priv), N, N,
+ DI(ImplicitOps | Priv, invd), DI(ImplicitOps | Priv, wbinvd), N, N,
N, D(ImplicitOps | ModRM), N, N,
/* 0x10 - 0x1F */
N, N, N, N, N, N, N, N, D(ImplicitOps | ModRM), N, N, N, N, N, N, N,
@@ -2512,7 +2514,7 @@ static struct opcode twobyte_table[256] = {
N, N, N, N,
N, N, N, N, N, N, N, N,
/* 0x30 - 0x3F */
- D(ImplicitOps | Priv), I(ImplicitOps, em_rdtsc),
+ D(ImplicitOps | Priv), II(ImplicitOps, em_rdtsc, rdtsc),
D(ImplicitOps | Priv), N,
D(ImplicitOps | VendorSpecific), D(ImplicitOps | Priv | VendorSpecific),
N, N,
--
1.7.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 03/15] KVM: x86 emulator: Don't write-back cpu-state on X86EMUL_INTERCEPTED
2011-04-04 10:39 [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Joerg Roedel
2011-04-04 10:39 ` [PATCH 01/15] KVM: x86 emulator: add framework for instruction intercepts Joerg Roedel
2011-04-04 10:39 ` [PATCH 02/15] KVM: x86 emulator: add SVM intercepts Joerg Roedel
@ 2011-04-04 10:39 ` Joerg Roedel
2011-04-04 10:39 ` [PATCH 04/15] KVM: x86 emulator: Add check_perm callback Joerg Roedel
` (12 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Joerg Roedel @ 2011-04-04 10:39 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Joerg Roedel
This patch prevents the changed CPU state to be written back
when the emulator detected that the instruction was
intercepted by the guest.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/include/asm/kvm_emulate.h | 1 +
arch/x86/kvm/emulate.c | 3 +++
arch/x86/kvm/x86.c | 3 +++
3 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 436207e..366de63 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -325,6 +325,7 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len);
#define EMULATION_FAILED -1
#define EMULATION_OK 0
#define EMULATION_RESTART 1
+#define EMULATION_INTERCEPTED 2
int x86_emulate_insn(struct x86_emulate_ctxt *ctxt);
int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
u16 tss_selector, int reason,
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index cee6fc1..b05e50d 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -3455,6 +3455,9 @@ writeback:
done:
if (rc == X86EMUL_PROPAGATE_FAULT)
ctxt->have_exception = true;
+ if (rc == X86EMUL_INTERCEPTED)
+ return EMULATION_INTERCEPTED;
+
return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK;
twobyte_insn:
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 2b4f5b2..11ecee2 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4459,6 +4459,9 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu,
restart:
r = x86_emulate_insn(&vcpu->arch.emulate_ctxt);
+ if (r == EMULATION_INTERCEPTED)
+ return EMULATE_DONE;
+
if (r == EMULATION_FAILED) {
if (reexecute_instruction(vcpu, cr2))
return EMULATE_DONE;
--
1.7.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 04/15] KVM: x86 emulator: Add check_perm callback
2011-04-04 10:39 [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Joerg Roedel
` (2 preceding siblings ...)
2011-04-04 10:39 ` [PATCH 03/15] KVM: x86 emulator: Don't write-back cpu-state on X86EMUL_INTERCEPTED Joerg Roedel
@ 2011-04-04 10:39 ` Joerg Roedel
2011-04-04 10:39 ` [PATCH 05/15] KVM: x86 emulator: Add flag to check for protected mode instructions Joerg Roedel
` (11 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Joerg Roedel @ 2011-04-04 10:39 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Joerg Roedel
This patch adds a check_perm callback for each opcode into
the instruction emulator. This will be used to do all
necessary permission checks on instructions before checking
whether they are intercepted or not.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/include/asm/kvm_emulate.h | 1 +
arch/x86/kvm/emulate.c | 16 ++++++++++++++++
2 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 366de63..a891051 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -216,6 +216,7 @@ struct decode_cache {
u8 seg_override;
unsigned int d;
int (*execute)(struct x86_emulate_ctxt *ctxt);
+ int (*check_perm)(struct x86_emulate_ctxt *ctxt);
unsigned long regs[NR_VCPU_REGS];
unsigned long eip;
/* modrm */
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index b05e50d..b002845 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -108,6 +108,7 @@ struct opcode {
struct opcode *group;
struct group_dual *gdual;
} u;
+ int (*check_perm)(struct x86_emulate_ctxt *ctxt);
};
struct group_dual {
@@ -2328,14 +2329,21 @@ static int em_mov(struct x86_emulate_ctxt *ctxt)
#define D(_y) { .flags = (_y) }
#define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i }
+#define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \
+ .check_perm = (_p) }
#define N D(0)
#define G(_f, _g) { .flags = ((_f) | Group), .u.group = (_g) }
#define GD(_f, _g) { .flags = ((_f) | Group | GroupDual), .u.gdual = (_g) }
#define I(_f, _e) { .flags = (_f), .u.execute = (_e) }
#define II(_f, _e, _i) \
{ .flags = (_f), .u.execute = (_e), .intercept = x86_intercept_##_i }
+#define IIP(_f, _e, _i, _p) \
+ { .flags = (_f), .u.execute = (_e), .intercept = x86_intercept_##_i, \
+ .check_perm = (_p) }
#define D2bv(_f) D((_f) | ByteOp), D(_f)
+#define D2bvI(_f, _i) DI((_f) | ByteOp, _i), DI((_f), _i)
+#define D2bvIP(_f, _i, _p) DIP((_f) | ByteOp, _i, _p), DIP((_f), _i, _p)
#define I2bv(_f, _e) I((_f) | ByteOp, _e), I(_f, _e)
#define D6ALU(_f) D2bv((_f) | DstMem | SrcReg | ModRM), \
@@ -2751,6 +2759,7 @@ done_prefixes:
}
c->execute = opcode.u.execute;
+ c->check_perm = opcode.check_perm;
c->intercept = opcode.intercept;
/* Unrecognised? */
@@ -2999,6 +3008,13 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
goto done;
}
+ /* Do instruction specific permission checks */
+ if (c->check_perm) {
+ rc = c->check_perm(ctxt);
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
+ }
+
if (unlikely(ctxt->guest_mode) && c->intercept) {
rc = ops->intercept(ctxt, c->intercept,
X86_ICPT_POST_EXCEPT);
--
1.7.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 05/15] KVM: x86 emulator: Add flag to check for protected mode instructions
2011-04-04 10:39 [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Joerg Roedel
` (3 preceding siblings ...)
2011-04-04 10:39 ` [PATCH 04/15] KVM: x86 emulator: Add check_perm callback Joerg Roedel
@ 2011-04-04 10:39 ` Joerg Roedel
2011-04-04 10:39 ` [PATCH 06/15] KVM: x86: Add x86 callback for intercept check Joerg Roedel
` (10 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Joerg Roedel @ 2011-04-04 10:39 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Joerg Roedel
This patch adds a flag for the opcoded to tag instruction
which are only recognized in protected mode. The necessary
check is added too.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/include/asm/kvm_emulate.h | 4 ++++
arch/x86/kvm/emulate.c | 7 +++++++
2 files changed, 11 insertions(+), 0 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index a891051..dfca25b 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -268,6 +268,10 @@ struct x86_emulate_ctxt {
#define X86EMUL_MODE_PROT32 4 /* 32-bit protected mode. */
#define X86EMUL_MODE_PROT64 8 /* 64-bit (long) mode. */
+/* any protected mode */
+#define X86EMUL_MODE_PROT (X86EMUL_MODE_PROT16|X86EMUL_MODE_PROT32| \
+ X86EMUL_MODE_PROT64)
+
enum x86_intercept_stage {
X86_ICPT_PRE_EXCEPT,
X86_ICPT_POST_EXCEPT,
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index b002845..686fa0b 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -76,6 +76,7 @@
#define Group (1<<14) /* Bits 3:5 of modrm byte extend opcode */
#define GroupDual (1<<15) /* Alternate decoding of mod == 3 */
/* Misc flags */
+#define Prot (1<<21) /* instruction generates #UD if not in prot-mode */
#define VendorSpecific (1<<22) /* Vendor specific instruction */
#define NoAccess (1<<23) /* Don't access memory (lea/invlpg/verr etc) */
#define Op3264 (1<<24) /* Operand is 64b in long mode, 32b otherwise */
@@ -3008,6 +3009,12 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
goto done;
}
+ /* Instruction can only be executed in protected mode */
+ if ((c->d & Prot) && !(ctxt->mode & X86EMUL_MODE_PROT)) {
+ rc = emulate_ud(ctxt);
+ goto done;
+ }
+
/* Do instruction specific permission checks */
if (c->check_perm) {
rc = c->check_perm(ctxt);
--
1.7.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 06/15] KVM: x86: Add x86 callback for intercept check
2011-04-04 10:39 [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Joerg Roedel
` (4 preceding siblings ...)
2011-04-04 10:39 ` [PATCH 05/15] KVM: x86 emulator: Add flag to check for protected mode instructions Joerg Roedel
@ 2011-04-04 10:39 ` Joerg Roedel
2011-04-04 10:39 ` [PATCH 07/15] KVM: SVM: Add intercept check for emulated cr accesses Joerg Roedel
` (9 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Joerg Roedel @ 2011-04-04 10:39 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Joerg Roedel
This patch adds a callback into kvm_x86_ops so that svm and
vmx code can do intercept checks on emulated instructions.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/include/asm/kvm_emulate.h | 22 ++++++++++++++++++++--
arch/x86/include/asm/kvm_host.h | 7 +++++++
arch/x86/kvm/emulate.c | 32 ++++++++++++++++++++++++++------
arch/x86/kvm/svm.c | 9 +++++++++
arch/x86/kvm/vmx.c | 9 +++++++++
arch/x86/kvm/x86.c | 6 +++---
6 files changed, 74 insertions(+), 11 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index dfca25b..6ac4f64 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -26,6 +26,24 @@ struct x86_exception {
};
/*
+ * This struct is used to carry enough information from the instruction
+ * decoder to main KVM so that a decision can be made whether the
+ * instruction needs to be intercepted or not.
+ */
+struct x86_instruction_info {
+ u8 intercept; /* which intercept */
+ u8 rep_prefix; /* rep prefix? */
+ u8 modrm_mod; /* mod part of modrm */
+ u8 modrm_reg; /* index of register used */
+ u8 modrm_rm; /* rm part of modrm */
+ u64 src_val; /* value of source operand */
+ u8 src_bytes; /* size of source operand */
+ u8 dst_bytes; /* size of destination operand */
+ u8 ad_bytes; /* size of src/dst address */
+ u64 next_rip; /* rip following the instruction */
+};
+
+/*
* x86_emulate_ops:
*
* These operations represent the instruction emulator's interface to memory.
@@ -161,8 +179,8 @@ struct x86_emulate_ops {
int (*set_dr)(int dr, unsigned long value, struct kvm_vcpu *vcpu);
int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
- int (*intercept)(struct x86_emulate_ctxt *ctxt,
- enum x86_intercept intercept,
+ int (*intercept)(struct kvm_vcpu *vcpu,
+ struct x86_instruction_info *info,
enum x86_intercept_stage stage);
};
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 35f81b1..4ef32ac 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -504,6 +504,8 @@ struct kvm_vcpu_stat {
u32 nmi_injections;
};
+struct x86_instruction_info;
+
struct kvm_x86_ops {
int (*cpu_has_kvm_support)(void); /* __init */
int (*disabled_by_bios)(void); /* __init */
@@ -591,6 +593,11 @@ struct kvm_x86_ops {
void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset);
void (*get_exit_info)(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2);
+
+ int (*check_intercept)(struct kvm_vcpu *vcpu,
+ struct x86_instruction_info *info,
+ enum x86_intercept_stage stage);
+
const struct trace_print_flags *exit_reasons_str;
};
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 686fa0b..b9e6839 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -398,6 +398,26 @@ struct group_dual {
(_eip) += (_size); \
})
+static int emulator_check_intercept(struct x86_emulate_ctxt *ctxt,
+ enum x86_intercept intercept,
+ enum x86_intercept_stage stage)
+{
+ struct x86_instruction_info info = {
+ .intercept = intercept,
+ .rep_prefix = ctxt->decode.rep_prefix,
+ .modrm_mod = ctxt->decode.modrm_mod,
+ .modrm_reg = ctxt->decode.modrm_reg,
+ .modrm_rm = ctxt->decode.modrm_rm,
+ .src_val = ctxt->decode.src.val64,
+ .src_bytes = ctxt->decode.src.bytes,
+ .dst_bytes = ctxt->decode.dst.bytes,
+ .ad_bytes = ctxt->decode.ad_bytes,
+ .next_rip = ctxt->eip,
+ };
+
+ return ctxt->ops->intercept(ctxt->vcpu, &info, stage);
+}
+
static inline unsigned long ad_mask(struct decode_cache *c)
{
return (1UL << (c->ad_bytes << 3)) - 1;
@@ -2997,8 +3017,8 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
}
if (unlikely(ctxt->guest_mode) && c->intercept) {
- rc = ops->intercept(ctxt, c->intercept,
- X86_ICPT_PRE_EXCEPT);
+ rc = emulator_check_intercept(ctxt, c->intercept,
+ X86_ICPT_PRE_EXCEPT);
if (rc != X86EMUL_CONTINUE)
goto done;
}
@@ -3023,8 +3043,8 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
}
if (unlikely(ctxt->guest_mode) && c->intercept) {
- rc = ops->intercept(ctxt, c->intercept,
- X86_ICPT_POST_EXCEPT);
+ rc = emulator_check_intercept(ctxt, c->intercept,
+ X86_ICPT_POST_EXCEPT);
if (rc != X86EMUL_CONTINUE)
goto done;
}
@@ -3068,8 +3088,8 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
special_insn:
if (unlikely(ctxt->guest_mode) && c->intercept) {
- rc = ops->intercept(ctxt, c->intercept,
- X86_ICPT_POST_MEMACCESS);
+ rc = emulator_check_intercept(ctxt, c->intercept,
+ X86_ICPT_POST_MEMACCESS);
if (rc != X86EMUL_CONTINUE)
goto done;
}
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index cb43e98..798ebe6 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -3868,6 +3868,13 @@ static void svm_fpu_deactivate(struct kvm_vcpu *vcpu)
update_cr0_intercept(svm);
}
+static int svm_check_intercept(struct kvm_vcpu *vcpu,
+ struct x86_instruction_info *info,
+ enum x86_intercept_stage stage)
+{
+ return X86EMUL_CONTINUE;
+}
+
static struct kvm_x86_ops svm_x86_ops = {
.cpu_has_kvm_support = has_svm,
.disabled_by_bios = is_disabled,
@@ -3953,6 +3960,8 @@ static struct kvm_x86_ops svm_x86_ops = {
.adjust_tsc_offset = svm_adjust_tsc_offset,
.set_tdp_cr3 = set_tdp_cr3,
+
+ .check_intercept = svm_check_intercept,
};
static int __init svm_init(void)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 2b99ae7..3dfefe3 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -4409,6 +4409,13 @@ static void vmx_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry)
{
}
+static int vmx_check_intercept(struct kvm_vcpu *vcpu,
+ struct x86_instruction_info *info,
+ enum x86_intercept_stage stage)
+{
+ return X86EMUL_CONTINUE;
+}
+
static struct kvm_x86_ops vmx_x86_ops = {
.cpu_has_kvm_support = cpu_has_kvm_support,
.disabled_by_bios = vmx_disabled_by_bios,
@@ -4494,6 +4501,8 @@ static struct kvm_x86_ops vmx_x86_ops = {
.adjust_tsc_offset = vmx_adjust_tsc_offset,
.set_tdp_cr3 = vmx_set_cr3,
+
+ .check_intercept = vmx_check_intercept,
};
static int __init vmx_init(void)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 11ecee2..e07ae21 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4242,11 +4242,11 @@ static void emulator_set_segment_selector(u16 sel, int seg,
kvm_set_segment(vcpu, &kvm_seg, seg);
}
-static int emulator_intercept(struct x86_emulate_ctxt *ctxt,
- enum x86_intercept intercept,
+static int emulator_intercept(struct kvm_vcpu *vcpu,
+ struct x86_instruction_info *info,
enum x86_intercept_stage stage)
{
- return X86EMUL_CONTINUE;
+ return kvm_x86_ops->check_intercept(vcpu, info, stage);
}
static struct x86_emulate_ops emulate_ops = {
--
1.7.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 07/15] KVM: SVM: Add intercept check for emulated cr accesses
2011-04-04 10:39 [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Joerg Roedel
` (5 preceding siblings ...)
2011-04-04 10:39 ` [PATCH 06/15] KVM: x86: Add x86 callback for intercept check Joerg Roedel
@ 2011-04-04 10:39 ` Joerg Roedel
2011-04-04 10:39 ` [PATCH 08/15] KVM: SVM: Add intercept check for accessing dr registers Joerg Roedel
` (8 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Joerg Roedel @ 2011-04-04 10:39 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Joerg Roedel
This patch adds all necessary intercept checks for
instructions that access the crX registers.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/include/asm/kvm_emulate.h | 3 +
arch/x86/include/asm/kvm_host.h | 15 +++++
arch/x86/kvm/emulate.c | 105 ++++++++++++++++++++++++++++++++----
arch/x86/kvm/svm.c | 81 +++++++++++++++++++++++++++-
arch/x86/kvm/x86.c | 13 -----
5 files changed, 192 insertions(+), 25 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 6ac4f64..6922200 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -298,6 +298,9 @@ enum x86_intercept_stage {
enum x86_intercept {
x86_intercept_none,
+ x86_intercept_cr_read,
+ x86_intercept_cr_write,
+ x86_intercept_clts,
x86_intercept_lmsw,
x86_intercept_smsw,
x86_intercept_lidt,
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 4ef32ac..e29f99b 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -34,10 +34,25 @@
#define KVM_PIO_PAGE_OFFSET 1
#define KVM_COALESCED_MMIO_PAGE_OFFSET 2
+#define CR0_RESERVED_BITS \
+ (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \
+ | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \
+ | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG))
+
#define CR3_PAE_RESERVED_BITS ((X86_CR3_PWT | X86_CR3_PCD) - 1)
#define CR3_NONPAE_RESERVED_BITS ((PAGE_SIZE-1) & ~(X86_CR3_PWT | X86_CR3_PCD))
#define CR3_L_MODE_RESERVED_BITS (CR3_NONPAE_RESERVED_BITS | \
0xFFFFFF0000000000ULL)
+#define CR4_RESERVED_BITS \
+ (~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\
+ | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE \
+ | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR \
+ | X86_CR4_OSXSAVE \
+ | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE))
+
+#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
+
+
#define INVALID_PAGE (~(hpa_t)0)
#define VALID_PAGE(x) ((x) != INVALID_PAGE)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index b9e6839..a242e04 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2348,6 +2348,95 @@ static int em_mov(struct x86_emulate_ctxt *ctxt)
return X86EMUL_CONTINUE;
}
+static bool valid_cr(int nr)
+{
+ switch (nr) {
+ case 0:
+ case 2 ... 4:
+ case 8:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int check_cr_read(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ if (!valid_cr(c->modrm_reg))
+ return emulate_ud(ctxt);
+
+ return X86EMUL_CONTINUE;
+}
+
+static int check_cr_write(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ u64 new_val = c->src.val64;
+ int cr = c->modrm_reg;
+
+ static u64 cr_reserved_bits[] = {
+ 0xffffffff00000000ULL,
+ 0, 0, 0, /* CR3 checked later */
+ CR4_RESERVED_BITS,
+ 0, 0, 0,
+ CR8_RESERVED_BITS,
+ };
+
+ if (!valid_cr(cr))
+ return emulate_ud(ctxt);
+
+ if (new_val & cr_reserved_bits[cr])
+ return emulate_gp(ctxt, 0);
+
+ switch (cr) {
+ case 0: {
+ u64 cr4, efer;
+ if (((new_val & X86_CR0_PG) && !(new_val & X86_CR0_PE)) ||
+ ((new_val & X86_CR0_NW) && !(new_val & X86_CR0_CD)))
+ return emulate_gp(ctxt, 0);
+
+ cr4 = ctxt->ops->get_cr(4, ctxt->vcpu);
+ ctxt->ops->get_msr(ctxt->vcpu, MSR_EFER, &efer);
+
+ if ((new_val & X86_CR0_PG) && (efer & EFER_LME) &&
+ !(cr4 & X86_CR4_PAE))
+ return emulate_gp(ctxt, 0);
+
+ break;
+ }
+ case 3: {
+ u64 rsvd = 0;
+
+ if (is_long_mode(ctxt->vcpu))
+ rsvd = CR3_L_MODE_RESERVED_BITS;
+ else if (is_pae(ctxt->vcpu))
+ rsvd = CR3_PAE_RESERVED_BITS;
+ else if (is_paging(ctxt->vcpu))
+ rsvd = CR3_NONPAE_RESERVED_BITS;
+
+ if (new_val & rsvd)
+ return emulate_gp(ctxt, 0);
+
+ break;
+ }
+ case 4: {
+ u64 cr4, efer;
+
+ cr4 = ctxt->ops->get_cr(4, ctxt->vcpu);
+ ctxt->ops->get_msr(ctxt->vcpu, MSR_EFER, &efer);
+
+ if ((efer & EFER_LMA) && !(new_val & X86_CR4_PAE))
+ return emulate_gp(ctxt, 0);
+
+ break;
+ }
+ }
+
+ return X86EMUL_CONTINUE;
+}
+
#define D(_y) { .flags = (_y) }
#define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i }
#define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \
@@ -2532,14 +2621,16 @@ static struct opcode opcode_table[256] = {
static struct opcode twobyte_table[256] = {
/* 0x00 - 0x0F */
N, GD(0, &group7), N, N,
- N, D(ImplicitOps | VendorSpecific), D(ImplicitOps | Priv), N,
+ N, D(ImplicitOps | VendorSpecific), DI(ImplicitOps | Priv, clts), N,
DI(ImplicitOps | Priv, invd), DI(ImplicitOps | Priv, wbinvd), N, N,
N, D(ImplicitOps | ModRM), N, N,
/* 0x10 - 0x1F */
N, N, N, N, N, N, N, N, D(ImplicitOps | ModRM), N, N, N, N, N, N, N,
/* 0x20 - 0x2F */
- D(ModRM | DstMem | Priv | Op3264), D(ModRM | DstMem | Priv | Op3264),
- D(ModRM | SrcMem | Priv | Op3264), D(ModRM | SrcMem | Priv | Op3264),
+ DIP(ModRM | DstMem | Priv | Op3264, cr_read, check_cr_read),
+ D(ModRM | DstMem | Priv | Op3264),
+ DIP(ModRM | SrcMem | Priv | Op3264, cr_write, check_cr_write),
+ D(ModRM | SrcMem | Priv | Op3264),
N, N, N, N,
N, N, N, N, N, N, N, N,
/* 0x30 - 0x3F */
@@ -3589,14 +3680,6 @@ twobyte_insn:
case 0x18: /* Grp16 (prefetch/nop) */
break;
case 0x20: /* mov cr, reg */
- switch (c->modrm_reg) {
- case 1:
- case 5 ... 7:
- case 9 ... 15:
- emulate_ud(ctxt);
- rc = X86EMUL_PROPAGATE_FAULT;
- goto done;
- }
c->dst.val = ops->get_cr(c->modrm_reg, ctxt->vcpu);
break;
case 0x21: /* mov from dr to reg */
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 798ebe6..ff4ed36 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -3868,11 +3868,90 @@ static void svm_fpu_deactivate(struct kvm_vcpu *vcpu)
update_cr0_intercept(svm);
}
+#define POST_EX(exit) { .exit_code = (exit), \
+ .stage = X86_ICPT_POST_EXCEPT, \
+ .valid = true }
+
+static struct __x86_intercept {
+ u32 exit_code;
+ enum x86_intercept_stage stage;
+ bool valid;
+} x86_intercept_map[] = {
+ [x86_intercept_cr_read] = POST_EX(SVM_EXIT_READ_CR0),
+ [x86_intercept_cr_write] = POST_EX(SVM_EXIT_WRITE_CR0),
+ [x86_intercept_clts] = POST_EX(SVM_EXIT_WRITE_CR0),
+ [x86_intercept_lmsw] = POST_EX(SVM_EXIT_WRITE_CR0),
+ [x86_intercept_smsw] = POST_EX(SVM_EXIT_READ_CR0),
+};
+
+#undef POST_EX
+
static int svm_check_intercept(struct kvm_vcpu *vcpu,
struct x86_instruction_info *info,
enum x86_intercept_stage stage)
{
- return X86EMUL_CONTINUE;
+ struct vcpu_svm *svm = to_svm(vcpu);
+ int vmexit, ret = X86EMUL_CONTINUE;
+ struct __x86_intercept icpt_info;
+ struct vmcb *vmcb = svm->vmcb;
+
+ if (info->intercept >= ARRAY_SIZE(x86_intercept_map))
+ goto out;
+
+ icpt_info = x86_intercept_map[info->intercept];
+
+ if (!icpt_info.valid || stage != icpt_info.stage)
+ goto out;
+
+ switch (icpt_info.exit_code) {
+ case SVM_EXIT_READ_CR0:
+ if (info->intercept == x86_intercept_cr_read)
+ icpt_info.exit_code += info->modrm_reg;
+ break;
+ case SVM_EXIT_WRITE_CR0: {
+ unsigned long cr0, val;
+ u64 intercept;
+
+ if (info->intercept == x86_intercept_cr_write)
+ icpt_info.exit_code += info->modrm_reg;
+
+ if (icpt_info.exit_code != SVM_EXIT_WRITE_CR0)
+ break;
+
+ intercept = svm->nested.intercept;
+
+ if (!(intercept & (1ULL << INTERCEPT_SELECTIVE_CR0)))
+ break;
+
+ cr0 = vcpu->arch.cr0 & ~SVM_CR0_SELECTIVE_MASK;
+ val = info->src_val & ~SVM_CR0_SELECTIVE_MASK;
+
+ if (info->intercept == x86_intercept_lmsw) {
+ cr0 &= 0xfUL;
+ val &= 0xfUL;
+ /* lmsw can't clear PE - catch this here */
+ if (cr0 & X86_CR0_PE)
+ val |= X86_CR0_PE;
+ }
+
+ if (cr0 ^ val)
+ icpt_info.exit_code = SVM_EXIT_CR0_SEL_WRITE;
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ vmcb->control.next_rip = info->next_rip;
+ vmcb->control.exit_code = icpt_info.exit_code;
+ vmexit = nested_svm_exit_handled(svm);
+
+ ret = (vmexit == NESTED_EXIT_DONE) ? X86EMUL_INTERCEPTED
+ : X86EMUL_CONTINUE;
+
+out:
+ return ret;
}
static struct kvm_x86_ops svm_x86_ops = {
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e07ae21..9344ea7 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -60,19 +60,6 @@
#include <asm/div64.h>
#define MAX_IO_MSRS 256
-#define CR0_RESERVED_BITS \
- (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \
- | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \
- | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG))
-#define CR4_RESERVED_BITS \
- (~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\
- | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE \
- | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR \
- | X86_CR4_OSXSAVE \
- | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE))
-
-#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
-
#define KVM_MAX_MCE_BANKS 32
#define KVM_MCE_CAP_SUPPORTED (MCG_CTL_P | MCG_SER_P)
--
1.7.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 08/15] KVM: SVM: Add intercept check for accessing dr registers
2011-04-04 10:39 [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Joerg Roedel
` (6 preceding siblings ...)
2011-04-04 10:39 ` [PATCH 07/15] KVM: SVM: Add intercept check for emulated cr accesses Joerg Roedel
@ 2011-04-04 10:39 ` Joerg Roedel
2011-04-04 10:39 ` [PATCH 09/15] KVM: SVM: Add intercept checks for descriptor table accesses Joerg Roedel
` (7 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Joerg Roedel @ 2011-04-04 10:39 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Joerg Roedel
This patch adds the intercept checks for instruction
accessing the debug registers.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/include/asm/kvm_emulate.h | 2 +
arch/x86/kvm/emulate.c | 63 +++++++++++++++++++++++++++--------
arch/x86/kvm/svm.c | 6 +++
3 files changed, 56 insertions(+), 15 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 6922200..9b11edd 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -303,6 +303,8 @@ enum x86_intercept {
x86_intercept_clts,
x86_intercept_lmsw,
x86_intercept_smsw,
+ x86_intercept_dr_read,
+ x86_intercept_dr_write,
x86_intercept_lidt,
x86_intercept_sidt,
x86_intercept_lgdt,
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index a242e04..9edac5b 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -499,6 +499,11 @@ static int emulate_exception(struct x86_emulate_ctxt *ctxt, int vec,
return X86EMUL_PROPAGATE_FAULT;
}
+static int emulate_db(struct x86_emulate_ctxt *ctxt)
+{
+ return emulate_exception(ctxt, DB_VECTOR, 0, false);
+}
+
static int emulate_gp(struct x86_emulate_ctxt *ctxt, int err)
{
return emulate_exception(ctxt, GP_VECTOR, err, true);
@@ -2437,6 +2442,47 @@ static int check_cr_write(struct x86_emulate_ctxt *ctxt)
return X86EMUL_CONTINUE;
}
+static int check_dr7_gd(struct x86_emulate_ctxt *ctxt)
+{
+ unsigned long dr7;
+
+ ctxt->ops->get_dr(7, &dr7, ctxt->vcpu);
+
+ /* Check if DR7.Global_Enable is set */
+ return dr7 & (1 << 13);
+}
+
+static int check_dr_read(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ int dr = c->modrm_reg;
+ u64 cr4;
+
+ if (dr > 7)
+ return emulate_ud(ctxt);
+
+ cr4 = ctxt->ops->get_cr(4, ctxt->vcpu);
+ if ((cr4 & X86_CR4_DE) && (dr == 4 || dr == 5))
+ return emulate_ud(ctxt);
+
+ if (check_dr7_gd(ctxt))
+ return emulate_db(ctxt);
+
+ return X86EMUL_CONTINUE;
+}
+
+static int check_dr_write(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ u64 new_val = c->src.val64;
+ int dr = c->modrm_reg;
+
+ if ((dr == 6 || dr == 7) && (new_val & 0xffffffff00000000ULL))
+ return emulate_gp(ctxt, 0);
+
+ return check_dr_read(ctxt);
+}
+
#define D(_y) { .flags = (_y) }
#define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i }
#define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \
@@ -2628,9 +2674,9 @@ static struct opcode twobyte_table[256] = {
N, N, N, N, N, N, N, N, D(ImplicitOps | ModRM), N, N, N, N, N, N, N,
/* 0x20 - 0x2F */
DIP(ModRM | DstMem | Priv | Op3264, cr_read, check_cr_read),
- D(ModRM | DstMem | Priv | Op3264),
+ DIP(ModRM | DstMem | Priv | Op3264, dr_read, check_dr_read),
DIP(ModRM | SrcMem | Priv | Op3264, cr_write, check_cr_write),
- D(ModRM | SrcMem | Priv | Op3264),
+ DIP(ModRM | SrcMem | Priv | Op3264, dr_write, check_dr_write),
N, N, N, N,
N, N, N, N, N, N, N, N,
/* 0x30 - 0x3F */
@@ -3683,12 +3729,6 @@ twobyte_insn:
c->dst.val = ops->get_cr(c->modrm_reg, ctxt->vcpu);
break;
case 0x21: /* mov from dr to reg */
- if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) &&
- (c->modrm_reg == 4 || c->modrm_reg == 5)) {
- emulate_ud(ctxt);
- rc = X86EMUL_PROPAGATE_FAULT;
- goto done;
- }
ops->get_dr(c->modrm_reg, &c->dst.val, ctxt->vcpu);
break;
case 0x22: /* mov reg, cr */
@@ -3700,13 +3740,6 @@ twobyte_insn:
c->dst.type = OP_NONE;
break;
case 0x23: /* mov from reg to dr */
- if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) &&
- (c->modrm_reg == 4 || c->modrm_reg == 5)) {
- emulate_ud(ctxt);
- rc = X86EMUL_PROPAGATE_FAULT;
- goto done;
- }
-
if (ops->set_dr(c->modrm_reg, c->src.val &
((ctxt->mode == X86EMUL_MODE_PROT64) ?
~0ULL : ~0U), ctxt->vcpu) < 0) {
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index ff4ed36..381b038 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -3882,6 +3882,8 @@ static struct __x86_intercept {
[x86_intercept_clts] = POST_EX(SVM_EXIT_WRITE_CR0),
[x86_intercept_lmsw] = POST_EX(SVM_EXIT_WRITE_CR0),
[x86_intercept_smsw] = POST_EX(SVM_EXIT_READ_CR0),
+ [x86_intercept_dr_read] = POST_EX(SVM_EXIT_READ_DR0),
+ [x86_intercept_dr_write] = POST_EX(SVM_EXIT_WRITE_DR0),
};
#undef POST_EX
@@ -3939,6 +3941,10 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
break;
}
+ case SVM_EXIT_READ_DR0:
+ case SVM_EXIT_WRITE_DR0:
+ icpt_info.exit_code += info->modrm_reg;
+ break;
default:
break;
}
--
1.7.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 09/15] KVM: SVM: Add intercept checks for descriptor table accesses
2011-04-04 10:39 [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Joerg Roedel
` (7 preceding siblings ...)
2011-04-04 10:39 ` [PATCH 08/15] KVM: SVM: Add intercept check for accessing dr registers Joerg Roedel
@ 2011-04-04 10:39 ` Joerg Roedel
2011-04-04 10:39 ` [PATCH 10/15] KVM: SVM: Add intercept checks for SVM instructions Joerg Roedel
` (6 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Joerg Roedel @ 2011-04-04 10:39 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Joerg Roedel
This patch add intercept checks into the KVM instruction
emulator to check for the 8 instructions that access the
descriptor table addresses.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/kvm/emulate.c | 14 ++++++++++++--
arch/x86/kvm/svm.c | 8 ++++++++
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 9edac5b..7091b07 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2534,8 +2534,18 @@ static struct opcode group5[] = {
D(SrcMem | ModRM | Stack), N,
};
+static struct opcode group6[] = {
+ DI(ModRM | Prot, sldt),
+ DI(ModRM | Prot, str),
+ DI(ModRM | Prot | Priv, lldt),
+ DI(ModRM | Prot | Priv, ltr),
+ N, N, N, N,
+};
+
static struct group_dual group7 = { {
- N, N, DI(ModRM | SrcMem | Priv, lgdt), DI(ModRM | SrcMem | Priv, lidt),
+ DI(ModRM | Mov | DstMem | Priv, sgdt),
+ DI(ModRM | Mov | DstMem | Priv, sidt),
+ DI(ModRM | SrcMem | Priv, lgdt), DI(ModRM | SrcMem | Priv, lidt),
DI(SrcNone | ModRM | DstMem | Mov, smsw), N,
DI(SrcMem16 | ModRM | Mov | Priv, lmsw),
DI(SrcMem | ModRM | ByteOp | Priv | NoAccess, invlpg),
@@ -2666,7 +2676,7 @@ static struct opcode opcode_table[256] = {
static struct opcode twobyte_table[256] = {
/* 0x00 - 0x0F */
- N, GD(0, &group7), N, N,
+ G(0, group6), GD(0, &group7), N, N,
N, D(ImplicitOps | VendorSpecific), DI(ImplicitOps | Priv, clts), N,
DI(ImplicitOps | Priv, invd), DI(ImplicitOps | Priv, wbinvd), N, N,
N, D(ImplicitOps | ModRM), N, N,
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 381b038..ce251c9 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -3884,6 +3884,14 @@ static struct __x86_intercept {
[x86_intercept_smsw] = POST_EX(SVM_EXIT_READ_CR0),
[x86_intercept_dr_read] = POST_EX(SVM_EXIT_READ_DR0),
[x86_intercept_dr_write] = POST_EX(SVM_EXIT_WRITE_DR0),
+ [x86_intercept_sldt] = POST_EX(SVM_EXIT_LDTR_READ),
+ [x86_intercept_str] = POST_EX(SVM_EXIT_TR_READ),
+ [x86_intercept_lldt] = POST_EX(SVM_EXIT_LDTR_WRITE),
+ [x86_intercept_ltr] = POST_EX(SVM_EXIT_TR_WRITE),
+ [x86_intercept_sgdt] = POST_EX(SVM_EXIT_GDTR_READ),
+ [x86_intercept_sidt] = POST_EX(SVM_EXIT_IDTR_READ),
+ [x86_intercept_lgdt] = POST_EX(SVM_EXIT_GDTR_WRITE),
+ [x86_intercept_lidt] = POST_EX(SVM_EXIT_IDTR_WRITE),
};
#undef POST_EX
--
1.7.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 10/15] KVM: SVM: Add intercept checks for SVM instructions
2011-04-04 10:39 [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Joerg Roedel
` (8 preceding siblings ...)
2011-04-04 10:39 ` [PATCH 09/15] KVM: SVM: Add intercept checks for descriptor table accesses Joerg Roedel
@ 2011-04-04 10:39 ` Joerg Roedel
2011-04-04 10:39 ` [PATCH 11/15] KVM: SVM: Add intercept checks for remaining group7 instructions Joerg Roedel
` (5 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Joerg Roedel @ 2011-04-04 10:39 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Joerg Roedel
This patch adds the necessary code changes in the
instruction emulator and the extensions to svm.c to
implement intercept checks for the svm instructions.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/kvm/emulate.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
arch/x86/kvm/svm.c | 8 ++++++++
2 files changed, 52 insertions(+), 1 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 7091b07..8826689 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -75,6 +75,8 @@
#define Stack (1<<13) /* Stack instruction (push/pop) */
#define Group (1<<14) /* Bits 3:5 of modrm byte extend opcode */
#define GroupDual (1<<15) /* Alternate decoding of mod == 3 */
+#define RMExt (1<<16) /* Opcode extension in ModRM r/m if mod == 3 */
+
/* Misc flags */
#define Prot (1<<21) /* instruction generates #UD if not in prot-mode */
#define VendorSpecific (1<<22) /* Vendor specific instruction */
@@ -2483,11 +2485,35 @@ static int check_dr_write(struct x86_emulate_ctxt *ctxt)
return check_dr_read(ctxt);
}
+static int check_svme(struct x86_emulate_ctxt *ctxt)
+{
+ u64 efer;
+
+ ctxt->ops->get_msr(ctxt->vcpu, MSR_EFER, &efer);
+
+ if (!(efer & EFER_SVME))
+ return emulate_ud(ctxt);
+
+ return X86EMUL_CONTINUE;
+}
+
+static int check_svme_pa(struct x86_emulate_ctxt *ctxt)
+{
+ u64 rax = kvm_register_read(ctxt->vcpu, VCPU_REGS_RAX);
+
+ /* Valid physical address? */
+ if (rax & 0xffff000000000000)
+ return emulate_gp(ctxt, 0);
+
+ return check_svme(ctxt);
+}
+
#define D(_y) { .flags = (_y) }
#define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i }
#define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \
.check_perm = (_p) }
#define N D(0)
+#define EXT(_f, _e) { .flags = ((_f) | RMExt), .u.group = (_e) }
#define G(_f, _g) { .flags = ((_f) | Group), .u.group = (_g) }
#define GD(_f, _g) { .flags = ((_f) | Group | GroupDual), .u.gdual = (_g) }
#define I(_f, _e) { .flags = (_f), .u.execute = (_e) }
@@ -2506,6 +2532,16 @@ static int check_dr_write(struct x86_emulate_ctxt *ctxt)
D2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock), \
D2bv(((_f) & ~Lock) | DstAcc | SrcImm)
+static struct opcode group7_rm3[] = {
+ DIP(SrcNone | ModRM | Prot | Priv, vmrun, check_svme_pa),
+ DIP(SrcNone | ModRM | Prot , vmmcall, check_svme),
+ DIP(SrcNone | ModRM | Prot | Priv, vmload, check_svme_pa),
+ DIP(SrcNone | ModRM | Prot | Priv, vmsave, check_svme_pa),
+ DIP(SrcNone | ModRM | Prot | Priv, stgi, check_svme),
+ DIP(SrcNone | ModRM | Prot | Priv, clgi, check_svme),
+ DIP(SrcNone | ModRM | Prot | Priv, skinit, check_svme),
+ DIP(SrcNone | ModRM | Prot | Priv, invlpga, check_svme),
+};
static struct opcode group1[] = {
X7(D(Lock)), N
@@ -2551,7 +2587,7 @@ static struct group_dual group7 = { {
DI(SrcMem | ModRM | ByteOp | Priv | NoAccess, invlpg),
}, {
D(SrcNone | ModRM | Priv | VendorSpecific), N,
- N, D(SrcNone | ModRM | Priv | VendorSpecific),
+ N, EXT(0, group7_rm3),
DI(SrcNone | ModRM | DstMem | Mov, smsw), N,
DI(SrcMem16 | ModRM | Mov | Priv, lmsw), N,
} };
@@ -2746,6 +2782,7 @@ static struct opcode twobyte_table[256] = {
#undef G
#undef GD
#undef I
+#undef EXT
#undef D2bv
#undef I2bv
@@ -2923,6 +2960,12 @@ done_prefixes:
opcode = g_mod3[goffset];
else
opcode = g_mod012[goffset];
+
+ if (opcode.flags & RMExt) {
+ goffset = c->modrm & 7;
+ opcode = opcode.u.group[goffset];
+ }
+
c->d |= opcode.flags;
}
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index ce251c9..b98d00b 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -3892,6 +3892,14 @@ static struct __x86_intercept {
[x86_intercept_sidt] = POST_EX(SVM_EXIT_IDTR_READ),
[x86_intercept_lgdt] = POST_EX(SVM_EXIT_GDTR_WRITE),
[x86_intercept_lidt] = POST_EX(SVM_EXIT_IDTR_WRITE),
+ [x86_intercept_vmrun] = POST_EX(SVM_EXIT_VMRUN),
+ [x86_intercept_vmmcall] = POST_EX(SVM_EXIT_VMMCALL),
+ [x86_intercept_vmload] = POST_EX(SVM_EXIT_VMLOAD),
+ [x86_intercept_vmsave] = POST_EX(SVM_EXIT_VMSAVE),
+ [x86_intercept_stgi] = POST_EX(SVM_EXIT_STGI),
+ [x86_intercept_clgi] = POST_EX(SVM_EXIT_CLGI),
+ [x86_intercept_skinit] = POST_EX(SVM_EXIT_SKINIT),
+ [x86_intercept_invlpga] = POST_EX(SVM_EXIT_INVLPGA),
};
#undef POST_EX
--
1.7.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 11/15] KVM: SVM: Add intercept checks for remaining group7 instructions
2011-04-04 10:39 [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Joerg Roedel
` (9 preceding siblings ...)
2011-04-04 10:39 ` [PATCH 10/15] KVM: SVM: Add intercept checks for SVM instructions Joerg Roedel
@ 2011-04-04 10:39 ` Joerg Roedel
2011-04-04 10:39 ` [PATCH 12/15] KVM: SVM: Add intercept checks for remaining twobyte instructions Joerg Roedel
` (4 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Joerg Roedel @ 2011-04-04 10:39 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Joerg Roedel
This patch implements the emulator intercept checks for the
RDTSCP, MONITOR, and MWAIT instructions.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/kvm/emulate.c | 25 +++++++++++++++++++++++--
arch/x86/kvm/svm.c | 7 +++++++
2 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 8826689..8cf7fa3 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2508,6 +2508,16 @@ static int check_svme_pa(struct x86_emulate_ctxt *ctxt)
return check_svme(ctxt);
}
+static int check_rdtsc(struct x86_emulate_ctxt *ctxt)
+{
+ u64 cr4 = ctxt->ops->get_cr(4, ctxt->vcpu);
+
+ if (cr4 & X86_CR4_TSD && ctxt->ops->cpl(ctxt->vcpu))
+ return emulate_ud(ctxt);
+
+ return X86EMUL_CONTINUE;
+}
+
#define D(_y) { .flags = (_y) }
#define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i }
#define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \
@@ -2532,6 +2542,12 @@ static int check_svme_pa(struct x86_emulate_ctxt *ctxt)
D2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock), \
D2bv(((_f) & ~Lock) | DstAcc | SrcImm)
+static struct opcode group7_rm1[] = {
+ DI(SrcNone | ModRM | Priv, monitor),
+ DI(SrcNone | ModRM | Priv, mwait),
+ N, N, N, N, N, N,
+};
+
static struct opcode group7_rm3[] = {
DIP(SrcNone | ModRM | Prot | Priv, vmrun, check_svme_pa),
DIP(SrcNone | ModRM | Prot , vmmcall, check_svme),
@@ -2543,6 +2559,11 @@ static struct opcode group7_rm3[] = {
DIP(SrcNone | ModRM | Prot | Priv, invlpga, check_svme),
};
+static struct opcode group7_rm7[] = {
+ N,
+ DIP(SrcNone | ModRM, rdtscp, check_rdtsc),
+ N, N, N, N, N, N,
+};
static struct opcode group1[] = {
X7(D(Lock)), N
};
@@ -2586,10 +2607,10 @@ static struct group_dual group7 = { {
DI(SrcMem16 | ModRM | Mov | Priv, lmsw),
DI(SrcMem | ModRM | ByteOp | Priv | NoAccess, invlpg),
}, {
- D(SrcNone | ModRM | Priv | VendorSpecific), N,
+ D(SrcNone | ModRM | Priv | VendorSpecific), EXT(0, group7_rm1),
N, EXT(0, group7_rm3),
DI(SrcNone | ModRM | DstMem | Mov, smsw), N,
- DI(SrcMem16 | ModRM | Mov | Priv, lmsw), N,
+ DI(SrcMem16 | ModRM | Mov | Priv, lmsw), EXT(0, group7_rm7),
} };
static struct opcode group8[] = {
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index b98d00b..1eb5504 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -3871,6 +3871,9 @@ static void svm_fpu_deactivate(struct kvm_vcpu *vcpu)
#define POST_EX(exit) { .exit_code = (exit), \
.stage = X86_ICPT_POST_EXCEPT, \
.valid = true }
+#define POST_MEM(exit) { .exit_code = (exit), \
+ .stage = X86_ICPT_POST_MEMACCESS, \
+ .valid = true }
static struct __x86_intercept {
u32 exit_code;
@@ -3900,9 +3903,13 @@ static struct __x86_intercept {
[x86_intercept_clgi] = POST_EX(SVM_EXIT_CLGI),
[x86_intercept_skinit] = POST_EX(SVM_EXIT_SKINIT),
[x86_intercept_invlpga] = POST_EX(SVM_EXIT_INVLPGA),
+ [x86_intercept_rdtscp] = POST_EX(SVM_EXIT_RDTSCP),
+ [x86_intercept_monitor] = POST_MEM(SVM_EXIT_MONITOR),
+ [x86_intercept_mwait] = POST_EX(SVM_EXIT_MWAIT),
};
#undef POST_EX
+#undef POST_MEM
static int svm_check_intercept(struct kvm_vcpu *vcpu,
struct x86_instruction_info *info,
--
1.7.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 12/15] KVM: SVM: Add intercept checks for remaining twobyte instructions
2011-04-04 10:39 [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Joerg Roedel
` (10 preceding siblings ...)
2011-04-04 10:39 ` [PATCH 11/15] KVM: SVM: Add intercept checks for remaining group7 instructions Joerg Roedel
@ 2011-04-04 10:39 ` Joerg Roedel
2011-04-04 10:39 ` [PATCH 13/15] KVM: SVM: Add intercept checks for one-byte instructions Joerg Roedel
` (3 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Joerg Roedel @ 2011-04-04 10:39 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Joerg Roedel
This patch adds intercepts checks for the remaining twobyte
instructions to the KVM instruction emulator.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/include/asm/kvm_emulate.h | 2 ++
arch/x86/kvm/emulate.c | 25 ++++++++++++++++++-------
arch/x86/kvm/svm.c | 19 +++++++++++++++++++
3 files changed, 39 insertions(+), 7 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 9b11edd..a9669d7 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -338,6 +338,8 @@ enum x86_intercept {
x86_intercept_wbinvd,
x86_intercept_monitor,
x86_intercept_mwait,
+ x86_intercept_rdmsr,
+ x86_intercept_wrmsr,
nr_x86_intercepts
};
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 8cf7fa3..bc49b2b 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2336,12 +2336,9 @@ static int em_cwd(struct x86_emulate_ctxt *ctxt)
static int em_rdtsc(struct x86_emulate_ctxt *ctxt)
{
- unsigned cpl = ctxt->ops->cpl(ctxt->vcpu);
struct decode_cache *c = &ctxt->decode;
u64 tsc = 0;
- if (cpl > 0 && (ctxt->ops->get_cr(4, ctxt->vcpu) & X86_CR4_TSD))
- return emulate_gp(ctxt, 0);
ctxt->ops->get_msr(ctxt->vcpu, MSR_IA32_TSC, &tsc);
c->regs[VCPU_REGS_RAX] = (u32)tsc;
c->regs[VCPU_REGS_RDX] = tsc >> 32;
@@ -2518,6 +2515,18 @@ static int check_rdtsc(struct x86_emulate_ctxt *ctxt)
return X86EMUL_CONTINUE;
}
+static int check_rdpmc(struct x86_emulate_ctxt *ctxt)
+{
+ u64 cr4 = ctxt->ops->get_cr(4, ctxt->vcpu);
+ u64 rcx = kvm_register_read(ctxt->vcpu, VCPU_REGS_RCX);
+
+ if ((!(cr4 & X86_CR4_PCE) && ctxt->ops->cpl(ctxt->vcpu)) ||
+ (rcx > 3))
+ return emulate_gp(ctxt, 0);
+
+ return X86EMUL_CONTINUE;
+}
+
#define D(_y) { .flags = (_y) }
#define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i }
#define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \
@@ -2747,8 +2756,10 @@ static struct opcode twobyte_table[256] = {
N, N, N, N,
N, N, N, N, N, N, N, N,
/* 0x30 - 0x3F */
- D(ImplicitOps | Priv), II(ImplicitOps, em_rdtsc, rdtsc),
- D(ImplicitOps | Priv), N,
+ DI(ImplicitOps | Priv, wrmsr),
+ IIP(ImplicitOps, em_rdtsc, rdtsc, check_rdtsc),
+ DI(ImplicitOps | Priv, rdmsr),
+ DIP(ImplicitOps | Priv, rdpmc, check_rdpmc),
D(ImplicitOps | VendorSpecific), D(ImplicitOps | Priv | VendorSpecific),
N, N,
N, N, N, N, N, N, N, N,
@@ -2766,12 +2777,12 @@ static struct opcode twobyte_table[256] = {
X16(D(ByteOp | DstMem | SrcNone | ModRM| Mov)),
/* 0xA0 - 0xA7 */
D(ImplicitOps | Stack), D(ImplicitOps | Stack),
- N, D(DstMem | SrcReg | ModRM | BitOp),
+ DI(ImplicitOps, cpuid), D(DstMem | SrcReg | ModRM | BitOp),
D(DstMem | SrcReg | Src2ImmByte | ModRM),
D(DstMem | SrcReg | Src2CL | ModRM), N, N,
/* 0xA8 - 0xAF */
D(ImplicitOps | Stack), D(ImplicitOps | Stack),
- N, D(DstMem | SrcReg | ModRM | BitOp | Lock),
+ DI(ImplicitOps, rsm), D(DstMem | SrcReg | ModRM | BitOp | Lock),
D(DstMem | SrcReg | Src2ImmByte | ModRM),
D(DstMem | SrcReg | Src2CL | ModRM),
D(ModRM), I(DstReg | SrcMem | ModRM, em_imul),
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 1eb5504..9036289 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -3868,6 +3868,9 @@ static void svm_fpu_deactivate(struct kvm_vcpu *vcpu)
update_cr0_intercept(svm);
}
+#define PRE_EX(exit) { .exit_code = (exit), \
+ .stage = X86_ICPT_PRE_EXCEPT, \
+ .valid = true }
#define POST_EX(exit) { .exit_code = (exit), \
.stage = X86_ICPT_POST_EXCEPT, \
.valid = true }
@@ -3906,8 +3909,18 @@ static struct __x86_intercept {
[x86_intercept_rdtscp] = POST_EX(SVM_EXIT_RDTSCP),
[x86_intercept_monitor] = POST_MEM(SVM_EXIT_MONITOR),
[x86_intercept_mwait] = POST_EX(SVM_EXIT_MWAIT),
+ [x86_intercept_invlpg] = POST_EX(SVM_EXIT_INVLPG),
+ [x86_intercept_invd] = POST_EX(SVM_EXIT_INVD),
+ [x86_intercept_wbinvd] = POST_EX(SVM_EXIT_WBINVD),
+ [x86_intercept_wrmsr] = POST_EX(SVM_EXIT_MSR),
+ [x86_intercept_rdtsc] = POST_EX(SVM_EXIT_RDTSC),
+ [x86_intercept_rdmsr] = POST_EX(SVM_EXIT_MSR),
+ [x86_intercept_rdpmc] = POST_EX(SVM_EXIT_RDPMC),
+ [x86_intercept_cpuid] = PRE_EX(SVM_EXIT_CPUID),
+ [x86_intercept_rsm] = PRE_EX(SVM_EXIT_RSM),
};
+#undef PRE_EX
#undef POST_EX
#undef POST_MEM
@@ -3968,6 +3981,12 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
case SVM_EXIT_WRITE_DR0:
icpt_info.exit_code += info->modrm_reg;
break;
+ case SVM_EXIT_MSR:
+ if (info->intercept == x86_intercept_wrmsr)
+ vmcb->control.exit_info_1 = 1;
+ else
+ vmcb->control.exit_info_1 = 0;
+ break;
default:
break;
}
--
1.7.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 13/15] KVM: SVM: Add intercept checks for one-byte instructions
2011-04-04 10:39 [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Joerg Roedel
` (11 preceding siblings ...)
2011-04-04 10:39 ` [PATCH 12/15] KVM: SVM: Add intercept checks for remaining twobyte instructions Joerg Roedel
@ 2011-04-04 10:39 ` Joerg Roedel
2011-04-04 10:39 ` [PATCH 14/15] KVM: SVM: Add checks for IO instructions Joerg Roedel
` (2 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Joerg Roedel @ 2011-04-04 10:39 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Joerg Roedel
This patch add intercept checks for emulated one-byte
instructions to the KVM instruction emulation path.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/kvm/emulate.c | 4 ++--
arch/x86/kvm/svm.c | 14 ++++++++++++++
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index bc49b2b..3fff70f 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2690,7 +2690,7 @@ static struct opcode opcode_table[256] = {
D(DstMem | SrcNone | ModRM | Mov), D(ModRM | SrcMem | NoAccess | DstReg),
D(ImplicitOps | SrcMem16 | ModRM), G(0, group1A),
/* 0x90 - 0x97 */
- X8(D(SrcAcc | DstReg)),
+ DI(SrcAcc | DstReg, pause), X7(D(SrcAcc | DstReg)),
/* 0x98 - 0x9F */
D(DstAcc | SrcNone), I(ImplicitOps | SrcAcc, em_cwd),
I(SrcImmFAddr | No64, em_call_far), N,
@@ -2732,7 +2732,7 @@ static struct opcode opcode_table[256] = {
D(SrcImmFAddr | No64), D(SrcImmByte | ImplicitOps),
D2bv(SrcNone | DstAcc), D2bv(SrcAcc | ImplicitOps),
/* 0xF0 - 0xF7 */
- N, N, N, N,
+ N, DI(ImplicitOps, icebp), N, N,
DI(ImplicitOps | Priv, hlt), D(ImplicitOps),
G(ByteOp, group3), G(0, group3),
/* 0xF8 - 0xFF */
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 9036289..9eb2710 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -3918,6 +3918,13 @@ static struct __x86_intercept {
[x86_intercept_rdpmc] = POST_EX(SVM_EXIT_RDPMC),
[x86_intercept_cpuid] = PRE_EX(SVM_EXIT_CPUID),
[x86_intercept_rsm] = PRE_EX(SVM_EXIT_RSM),
+ [x86_intercept_pause] = PRE_EX(SVM_EXIT_PAUSE),
+ [x86_intercept_pushf] = PRE_EX(SVM_EXIT_PUSHF),
+ [x86_intercept_popf] = PRE_EX(SVM_EXIT_POPF),
+ [x86_intercept_intn] = PRE_EX(SVM_EXIT_SWINT),
+ [x86_intercept_iret] = PRE_EX(SVM_EXIT_IRET),
+ [x86_intercept_icebp] = PRE_EX(SVM_EXIT_ICEBP),
+ [x86_intercept_hlt] = POST_EX(SVM_EXIT_HLT),
};
#undef PRE_EX
@@ -3987,6 +3994,13 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
else
vmcb->control.exit_info_1 = 0;
break;
+ case SVM_EXIT_PAUSE:
+ /*
+ * We get this for NOP only, but pause
+ * is rep not, check this here
+ */
+ if (info->rep_prefix != REPE_PREFIX)
+ goto out;
default:
break;
}
--
1.7.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 14/15] KVM: SVM: Add checks for IO instructions
2011-04-04 10:39 [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Joerg Roedel
` (12 preceding siblings ...)
2011-04-04 10:39 ` [PATCH 13/15] KVM: SVM: Add intercept checks for one-byte instructions Joerg Roedel
@ 2011-04-04 10:39 ` Joerg Roedel
2011-04-04 10:39 ` [PATCH 15/15] KVM: SVM: Remove nested sel_cr0_write handling code Joerg Roedel
2011-04-04 12:05 ` [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Avi Kivity
15 siblings, 0 replies; 17+ messages in thread
From: Joerg Roedel @ 2011-04-04 10:39 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Joerg Roedel
This patch adds code to check for IOIO intercepts on
instructions decoded by the KVM instruction emulator.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/include/asm/kvm_emulate.h | 4 +++
arch/x86/kvm/emulate.c | 44 +++++++++++++++++++++++------------
arch/x86/kvm/svm.c | 36 +++++++++++++++++++++++++++++
3 files changed, 69 insertions(+), 15 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index a9669d7..c72e9ba 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -340,6 +340,10 @@ enum x86_intercept {
x86_intercept_mwait,
x86_intercept_rdmsr,
x86_intercept_wrmsr,
+ x86_intercept_in,
+ x86_intercept_ins,
+ x86_intercept_out,
+ x86_intercept_outs,
nr_x86_intercepts
};
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 3fff70f..3805d55 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2527,6 +2527,28 @@ static int check_rdpmc(struct x86_emulate_ctxt *ctxt)
return X86EMUL_CONTINUE;
}
+static int check_perm_in(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ c->dst.bytes = min(c->dst.bytes, 4u);
+ if (!emulator_io_permited(ctxt, ctxt->ops, c->src.val, c->dst.bytes))
+ return emulate_gp(ctxt, 0);
+
+ return X86EMUL_CONTINUE;
+}
+
+static int check_perm_out(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ c->src.bytes = min(c->src.bytes, 4u);
+ if (!emulator_io_permited(ctxt, ctxt->ops, c->dst.val, c->src.bytes))
+ return emulate_gp(ctxt, 0);
+
+ return X86EMUL_CONTINUE;
+}
+
#define D(_y) { .flags = (_y) }
#define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i }
#define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \
@@ -2674,8 +2696,8 @@ static struct opcode opcode_table[256] = {
I(DstReg | SrcMem | ModRM | Src2Imm, em_imul_3op),
I(SrcImmByte | Mov | Stack, em_push),
I(DstReg | SrcMem | ModRM | Src2ImmByte, em_imul_3op),
- D2bv(DstDI | Mov | String), /* insb, insw/insd */
- D2bv(SrcSI | ImplicitOps | String), /* outsb, outsw/outsd */
+ D2bvIP(DstDI | Mov | String, ins, check_perm_in), /* insb, insw/insd */
+ D2bvIP(SrcSI | ImplicitOps | String, outs, check_perm_out), /* outsb, outsw/outsd */
/* 0x70 - 0x7F */
X16(D(SrcImmByte)),
/* 0x80 - 0x87 */
@@ -2726,11 +2748,13 @@ static struct opcode opcode_table[256] = {
N, N, N, N, N, N, N, N,
/* 0xE0 - 0xE7 */
X4(D(SrcImmByte)),
- D2bv(SrcImmUByte | DstAcc), D2bv(SrcAcc | DstImmUByte),
+ D2bvIP(SrcImmUByte | DstAcc, in, check_perm_in),
+ D2bvIP(SrcAcc | DstImmUByte, out, check_perm_out),
/* 0xE8 - 0xEF */
D(SrcImm | Stack), D(SrcImm | ImplicitOps),
D(SrcImmFAddr | No64), D(SrcImmByte | ImplicitOps),
- D2bv(SrcNone | DstAcc), D2bv(SrcAcc | ImplicitOps),
+ D2bvIP(SrcNone | DstAcc, in, check_perm_in),
+ D2bvIP(SrcAcc | ImplicitOps, out, check_perm_out),
/* 0xF0 - 0xF7 */
N, DI(ImplicitOps, icebp), N, N,
DI(ImplicitOps | Priv, hlt), D(ImplicitOps),
@@ -2817,6 +2841,7 @@ static struct opcode twobyte_table[256] = {
#undef EXT
#undef D2bv
+#undef D2bvI
#undef I2bv
#undef D6ALU
@@ -3597,11 +3622,6 @@ special_insn:
case 0xed: /* in (e/r)ax,dx */
c->src.val = c->regs[VCPU_REGS_RDX];
do_io_in:
- c->dst.bytes = min(c->dst.bytes, 4u);
- if (!emulator_io_permited(ctxt, ops, c->src.val, c->dst.bytes)) {
- rc = emulate_gp(ctxt, 0);
- goto done;
- }
if (!pio_in_emulated(ctxt, ops, c->dst.bytes, c->src.val,
&c->dst.val))
goto done; /* IO is needed */
@@ -3610,12 +3630,6 @@ special_insn:
case 0xef: /* out dx,(e/r)ax */
c->dst.val = c->regs[VCPU_REGS_RDX];
do_io_out:
- c->src.bytes = min(c->src.bytes, 4u);
- if (!emulator_io_permited(ctxt, ops, c->dst.val,
- c->src.bytes)) {
- rc = emulate_gp(ctxt, 0);
- goto done;
- }
ops->pio_out_emulated(c->src.bytes, c->dst.val,
&c->src.val, 1, ctxt->vcpu);
c->dst.type = OP_NONE; /* Disable writeback. */
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 9eb2710..5c6512d 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -3925,6 +3925,10 @@ static struct __x86_intercept {
[x86_intercept_iret] = PRE_EX(SVM_EXIT_IRET),
[x86_intercept_icebp] = PRE_EX(SVM_EXIT_ICEBP),
[x86_intercept_hlt] = POST_EX(SVM_EXIT_HLT),
+ [x86_intercept_in] = POST_EX(SVM_EXIT_IOIO),
+ [x86_intercept_ins] = POST_EX(SVM_EXIT_IOIO),
+ [x86_intercept_out] = POST_EX(SVM_EXIT_IOIO),
+ [x86_intercept_outs] = POST_EX(SVM_EXIT_IOIO),
};
#undef PRE_EX
@@ -4001,6 +4005,38 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
*/
if (info->rep_prefix != REPE_PREFIX)
goto out;
+ case SVM_EXIT_IOIO: {
+ u64 exit_info;
+ u32 bytes;
+
+ exit_info = (vcpu->arch.regs[VCPU_REGS_RDX] & 0xffff) << 16;
+
+ if (info->intercept == x86_intercept_in ||
+ info->intercept == x86_intercept_ins) {
+ exit_info |= SVM_IOIO_TYPE_MASK;
+ bytes = info->src_bytes;
+ } else {
+ bytes = info->dst_bytes;
+ }
+
+ if (info->intercept == x86_intercept_outs ||
+ info->intercept == x86_intercept_ins)
+ exit_info |= SVM_IOIO_STR_MASK;
+
+ if (info->rep_prefix)
+ exit_info |= SVM_IOIO_REP_MASK;
+
+ bytes = min(bytes, 4u);
+
+ exit_info |= bytes << SVM_IOIO_SIZE_SHIFT;
+
+ exit_info |= (u32)info->ad_bytes << (SVM_IOIO_ASIZE_SHIFT - 1);
+
+ vmcb->control.exit_info_1 = exit_info;
+ vmcb->control.exit_info_2 = info->next_rip;
+
+ break;
+ }
default:
break;
}
--
1.7.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 15/15] KVM: SVM: Remove nested sel_cr0_write handling code
2011-04-04 10:39 [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Joerg Roedel
` (13 preceding siblings ...)
2011-04-04 10:39 ` [PATCH 14/15] KVM: SVM: Add checks for IO instructions Joerg Roedel
@ 2011-04-04 10:39 ` Joerg Roedel
2011-04-04 12:05 ` [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Avi Kivity
15 siblings, 0 replies; 17+ messages in thread
From: Joerg Roedel @ 2011-04-04 10:39 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Joerg Roedel
This patch removes all the old code which handled the nested
selective cr0 write intercepts. This code was only in place
as a work-around until the instruction emulator is capable
of doing the same. This is the case with this patch-set and
so the code can be removed.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/kvm/svm.c | 78 +++++++++++++++++----------------------------------
1 files changed, 26 insertions(+), 52 deletions(-)
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 5c6512d..779b091 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -93,14 +93,6 @@ struct nested_state {
/* A VMEXIT is required but not yet emulated */
bool exit_required;
- /*
- * If we vmexit during an instruction emulation we need this to restore
- * the l1 guest rip after the emulation
- */
- unsigned long vmexit_rip;
- unsigned long vmexit_rsp;
- unsigned long vmexit_rax;
-
/* cache for intercepts of the guest */
u32 intercept_cr;
u32 intercept_dr;
@@ -1362,31 +1354,6 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
{
struct vcpu_svm *svm = to_svm(vcpu);
- if (is_guest_mode(vcpu)) {
- /*
- * We are here because we run in nested mode, the host kvm
- * intercepts cr0 writes but the l1 hypervisor does not.
- * But the L1 hypervisor may intercept selective cr0 writes.
- * This needs to be checked here.
- */
- unsigned long old, new;
-
- /* Remove bits that would trigger a real cr0 write intercept */
- old = vcpu->arch.cr0 & SVM_CR0_SELECTIVE_MASK;
- new = cr0 & SVM_CR0_SELECTIVE_MASK;
-
- if (old == new) {
- /* cr0 write with ts and mp unchanged */
- svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE;
- if (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE) {
- svm->nested.vmexit_rip = kvm_rip_read(vcpu);
- svm->nested.vmexit_rsp = kvm_register_read(vcpu, VCPU_REGS_RSP);
- svm->nested.vmexit_rax = kvm_register_read(vcpu, VCPU_REGS_RAX);
- return;
- }
- }
- }
-
#ifdef CONFIG_X86_64
if (vcpu->arch.efer & EFER_LME) {
if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) {
@@ -2673,6 +2640,29 @@ static int emulate_on_interception(struct vcpu_svm *svm)
return emulate_instruction(&svm->vcpu, 0) == EMULATE_DONE;
}
+bool check_selective_cr0_intercepted(struct vcpu_svm *svm, unsigned long val)
+{
+ unsigned long cr0 = svm->vcpu.arch.cr0;
+ bool ret = false;
+ u64 intercept;
+
+ intercept = svm->nested.intercept;
+
+ if (!is_guest_mode(&svm->vcpu) ||
+ (!(intercept & (1ULL << INTERCEPT_SELECTIVE_CR0))))
+ return false;
+
+ cr0 &= ~SVM_CR0_SELECTIVE_MASK;
+ val &= ~SVM_CR0_SELECTIVE_MASK;
+
+ if (cr0 ^ val) {
+ svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE;
+ ret = (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE);
+ }
+
+ return ret;
+}
+
#define CR_VALID (1ULL << 63)
static int cr_interception(struct vcpu_svm *svm)
@@ -2696,7 +2686,8 @@ static int cr_interception(struct vcpu_svm *svm)
val = kvm_register_read(&svm->vcpu, reg);
switch (cr) {
case 0:
- err = kvm_set_cr0(&svm->vcpu, val);
+ if (!check_selective_cr0_intercepted(svm, val))
+ err = kvm_set_cr0(&svm->vcpu, val);
break;
case 3:
err = kvm_set_cr3(&svm->vcpu, val);
@@ -2741,23 +2732,6 @@ static int cr_interception(struct vcpu_svm *svm)
return 1;
}
-static int cr0_write_interception(struct vcpu_svm *svm)
-{
- struct kvm_vcpu *vcpu = &svm->vcpu;
- int r;
-
- r = cr_interception(svm);
-
- if (svm->nested.vmexit_rip) {
- kvm_register_write(vcpu, VCPU_REGS_RIP, svm->nested.vmexit_rip);
- kvm_register_write(vcpu, VCPU_REGS_RSP, svm->nested.vmexit_rsp);
- kvm_register_write(vcpu, VCPU_REGS_RAX, svm->nested.vmexit_rax);
- svm->nested.vmexit_rip = 0;
- }
-
- return r;
-}
-
static int dr_interception(struct vcpu_svm *svm)
{
int reg, dr;
@@ -3045,7 +3019,7 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm) = {
[SVM_EXIT_READ_CR4] = cr_interception,
[SVM_EXIT_READ_CR8] = cr_interception,
[SVM_EXIT_CR0_SEL_WRITE] = emulate_on_interception,
- [SVM_EXIT_WRITE_CR0] = cr0_write_interception,
+ [SVM_EXIT_WRITE_CR0] = cr_interception,
[SVM_EXIT_WRITE_CR3] = cr_interception,
[SVM_EXIT_WRITE_CR4] = cr_interception,
[SVM_EXIT_WRITE_CR8] = cr8_write_interception,
--
1.7.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5
2011-04-04 10:39 [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Joerg Roedel
` (14 preceding siblings ...)
2011-04-04 10:39 ` [PATCH 15/15] KVM: SVM: Remove nested sel_cr0_write handling code Joerg Roedel
@ 2011-04-04 12:05 ` Avi Kivity
15 siblings, 0 replies; 17+ messages in thread
From: Avi Kivity @ 2011-04-04 12:05 UTC (permalink / raw)
To: Joerg Roedel; +Cc: Marcelo Tosatti, kvm
On 04/04/2011 01:39 PM, Joerg Roedel wrote:
> Hi,
>
> here is the next version of this patch-set. The changes to the previous
> post are limited to the cosmetic changes mentioned by Avi. The full
> function names are used now in the opcode table so that the #defines
> could be removed and the link between the opcode and the function for
> permission checking is now more clear.
Applied, thanks.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2011-04-04 12:11 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-04-04 10:39 [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Joerg Roedel
2011-04-04 10:39 ` [PATCH 01/15] KVM: x86 emulator: add framework for instruction intercepts Joerg Roedel
2011-04-04 10:39 ` [PATCH 02/15] KVM: x86 emulator: add SVM intercepts Joerg Roedel
2011-04-04 10:39 ` [PATCH 03/15] KVM: x86 emulator: Don't write-back cpu-state on X86EMUL_INTERCEPTED Joerg Roedel
2011-04-04 10:39 ` [PATCH 04/15] KVM: x86 emulator: Add check_perm callback Joerg Roedel
2011-04-04 10:39 ` [PATCH 05/15] KVM: x86 emulator: Add flag to check for protected mode instructions Joerg Roedel
2011-04-04 10:39 ` [PATCH 06/15] KVM: x86: Add x86 callback for intercept check Joerg Roedel
2011-04-04 10:39 ` [PATCH 07/15] KVM: SVM: Add intercept check for emulated cr accesses Joerg Roedel
2011-04-04 10:39 ` [PATCH 08/15] KVM: SVM: Add intercept check for accessing dr registers Joerg Roedel
2011-04-04 10:39 ` [PATCH 09/15] KVM: SVM: Add intercept checks for descriptor table accesses Joerg Roedel
2011-04-04 10:39 ` [PATCH 10/15] KVM: SVM: Add intercept checks for SVM instructions Joerg Roedel
2011-04-04 10:39 ` [PATCH 11/15] KVM: SVM: Add intercept checks for remaining group7 instructions Joerg Roedel
2011-04-04 10:39 ` [PATCH 12/15] KVM: SVM: Add intercept checks for remaining twobyte instructions Joerg Roedel
2011-04-04 10:39 ` [PATCH 13/15] KVM: SVM: Add intercept checks for one-byte instructions Joerg Roedel
2011-04-04 10:39 ` [PATCH 14/15] KVM: SVM: Add checks for IO instructions Joerg Roedel
2011-04-04 10:39 ` [PATCH 15/15] KVM: SVM: Remove nested sel_cr0_write handling code Joerg Roedel
2011-04-04 12:05 ` [PATCH 0/15] KVM: Make the instruction emulator aware of Nested Virtualization v5 Avi Kivity
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox