* [PATCH v2 00/30] emulator cleanup
@ 2010-03-14 16:20 Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 01/30] KVM: x86 emulator: Fix DstAcc decoding Gleb Natapov
` (29 more replies)
0 siblings, 30 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:20 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
This is the first series of patches that tries to cleanup emulator code.
This is mix of bug fixes and moving code that does emulation from x86.c
to emulator.c while making it KVM independent. The status of the patches:
works for me. realtime.flat test now also pass where it failed before.
ChangeLog:
v1->v2:
- A couple of new bug fixed
- cpl is now x86_emulator_ops callback
- during string instruction re-enter guest on each page boundary
- retain fast path for pio out (do not go through emulator)
Gleb Natapov (30):
KVM: x86 emulator: Fix DstAcc decoding.
KVM: x86 emulator: fix RCX access during rep emulation
KVM: x86 emulator: check return value against correct define
KVM: Remove pointer to rflags from realmode_set_cr parameters.
KVM: Provide callback to get/set control registers in emulator ops.
KVM: remove realmode_lmsw function.
KVM: Provide x86_emulate_ctxt callback to get current cpl
KVM: Provide current eip as part of emulator context.
KVM: x86 emulator: fix mov r/m, sreg emulation.
KVM: x86 emulator: fix 0f 01 /5 emulation
KVM: x86 emulator: 0f (20|21|22|23) ignore mod bits.
KVM: x86 emulator: inject #UD on access to non-existing CR
KVM: x86 emulator: fix mov dr to inject #UD when needed.
KVM: x86 emulator: fix return values of syscall/sysenter/sysexit
emulations
KVM: x86 emulator: do not call writeback if msr access fails.
KVM: x86 emulator: If LOCK prefix is used dest arg should be memory.
KVM: x86 emulator: cleanup grp3 return value
KVM: x86 emulator: Provide more callbacks for x86 emulator.
KVM: x86 emulator: Emulate task switch in emulator.c
KVM: x86 emulator: Use load_segment_descriptor() instead of
kvm_load_segment_descriptor()
KVM: Use task switch from emulator.c
KVM: x86 emulator: populate OP_MEM operand during decoding.
KVM: x86 emulator: add decoding of X,Y parameters from Intel SDM
KVM: x86 emulator: during rep emulation decrement ECX only if
emulation succeeded
KVM: x86 emulator: fix in/out emulation.
KVM: x86 emulator: Move string pio emulation into emulator.c
KVM: x86 emulator: remove saved_eip
KVM: x86 emulator: restart string instruction without going back to a
guest.
KVM: x86 emulator: introduce pio in string read ahead.
KVM: small kvm_arch_vcpu_ioctl_run() cleanup.
arch/x86/include/asm/kvm_emulate.h | 41 ++-
arch/x86/include/asm/kvm_host.h | 16 +-
arch/x86/kvm/emulate.c | 1044 +++++++++++++++++++++++++--------
arch/x86/kvm/svm.c | 20 +-
arch/x86/kvm/vmx.c | 20 +-
arch/x86/kvm/x86.c | 1121 +++++++++---------------------------
6 files changed, 1133 insertions(+), 1129 deletions(-)
^ permalink raw reply [flat|nested] 53+ messages in thread
* [PATCH v2 01/30] KVM: x86 emulator: Fix DstAcc decoding.
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
@ 2010-03-14 16:20 ` Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 02/30] KVM: x86 emulator: fix RCX access during rep emulation Gleb Natapov
` (28 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:20 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Set correct operation length. Add RAX (64bit) handling.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/emulate.c | 7 +++++--
1 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 2832a8c..0b70a36 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1194,9 +1194,9 @@ done_prefixes:
break;
case DstAcc:
c->dst.type = OP_REG;
- c->dst.bytes = c->op_bytes;
+ c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
c->dst.ptr = &c->regs[VCPU_REGS_RAX];
- switch (c->op_bytes) {
+ switch (c->dst.bytes) {
case 1:
c->dst.val = *(u8 *)c->dst.ptr;
break;
@@ -1206,6 +1206,9 @@ done_prefixes:
case 4:
c->dst.val = *(u32 *)c->dst.ptr;
break;
+ case 8:
+ c->dst.val = *(u64 *)c->dst.ptr;
+ break;
}
c->dst.orig_val = c->dst.val;
break;
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 02/30] KVM: x86 emulator: fix RCX access during rep emulation
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 01/30] KVM: x86 emulator: Fix DstAcc decoding Gleb Natapov
@ 2010-03-14 16:20 ` Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 03/30] KVM: x86 emulator: check return value against correct define Gleb Natapov
` (27 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:20 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
During rep emulation access length to RCX depends on current address
mode.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/emulate.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 0b70a36..4dce805 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1852,7 +1852,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
if (c->rep_prefix && (c->d & String)) {
/* All REP prefixes have the same first termination condition */
- if (c->regs[VCPU_REGS_RCX] == 0) {
+ if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0) {
kvm_rip_write(ctxt->vcpu, c->eip);
goto done;
}
@@ -1876,7 +1876,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
goto done;
}
}
- c->regs[VCPU_REGS_RCX]--;
+ register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1);
c->eip = kvm_rip_read(ctxt->vcpu);
}
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 03/30] KVM: x86 emulator: check return value against correct define
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 01/30] KVM: x86 emulator: Fix DstAcc decoding Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 02/30] KVM: x86 emulator: fix RCX access during rep emulation Gleb Natapov
@ 2010-03-14 16:20 ` Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 04/30] KVM: Remove pointer to rflags from realmode_set_cr parameters Gleb Natapov
` (26 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:20 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Check return value against correct define instead of open code
the value.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/emulate.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 4dce805..670ca8f 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -566,7 +566,7 @@ static u32 group2_table[] = {
#define insn_fetch(_type, _size, _eip) \
({ unsigned long _x; \
rc = do_insn_fetch(ctxt, ops, (_eip), &_x, (_size)); \
- if (rc != 0) \
+ if (rc != X86EMUL_CONTINUE) \
goto done; \
(_eip) += (_size); \
(_type)_x; \
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 04/30] KVM: Remove pointer to rflags from realmode_set_cr parameters.
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (2 preceding siblings ...)
2010-03-14 16:20 ` [PATCH v2 03/30] KVM: x86 emulator: check return value against correct define Gleb Natapov
@ 2010-03-14 16:20 ` Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 05/30] KVM: Provide callback to get/set control registers in emulator ops Gleb Natapov
` (25 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:20 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Mov reg, cr instruction doesn't change flags in any meaningful way, so
no need to update rflags after instruction execution.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/include/asm/kvm_host.h | 3 +--
arch/x86/kvm/emulate.c | 3 +--
arch/x86/kvm/x86.c | 4 +---
3 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index ec891a2..3b178d8 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -586,8 +586,7 @@ void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
unsigned long *rflags);
unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr);
-void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value,
- unsigned long *rflags);
+void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value);
void kvm_enable_efer_bits(u64);
int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 670ca8f..91450b5 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2534,8 +2534,7 @@ twobyte_insn:
case 0x22: /* mov reg, cr */
if (c->modrm_mod != 3)
goto cannot_emulate;
- realmode_set_cr(ctxt->vcpu,
- c->modrm_reg, c->modrm_val, &ctxt->eflags);
+ realmode_set_cr(ctxt->vcpu, c->modrm_reg, c->modrm_val);
c->dst.type = OP_NONE;
break;
case 0x23: /* mov from reg to dr */
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index bcf52d1..a1e671a 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4027,13 +4027,11 @@ unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
return value;
}
-void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val,
- unsigned long *rflags)
+void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val)
{
switch (cr) {
case 0:
kvm_set_cr0(vcpu, mk_cr_64(kvm_read_cr0(vcpu), val));
- *rflags = kvm_get_rflags(vcpu);
break;
case 2:
vcpu->arch.cr2 = val;
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 05/30] KVM: Provide callback to get/set control registers in emulator ops.
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (3 preceding siblings ...)
2010-03-14 16:20 ` [PATCH v2 04/30] KVM: Remove pointer to rflags from realmode_set_cr parameters Gleb Natapov
@ 2010-03-14 16:20 ` Gleb Natapov
2010-03-15 13:06 ` Andre Przywara
2010-03-14 16:20 ` [PATCH v2 06/30] KVM: remove realmode_lmsw function Gleb Natapov
` (24 subsequent siblings)
29 siblings, 1 reply; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:20 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Use this callback instead of directly call kvm function. Also rename
realmode_(set|get)_cr to emulator_(set|get)_cr since function has nothing
to do with real mode.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/include/asm/kvm_emulate.h | 3 +-
arch/x86/include/asm/kvm_host.h | 2 -
arch/x86/kvm/emulate.c | 7 +-
arch/x86/kvm/x86.c | 114 ++++++++++++++++++------------------
4 files changed, 63 insertions(+), 63 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 2666d7a..0c5caa4 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -108,7 +108,8 @@ struct x86_emulate_ops {
const void *new,
unsigned int bytes,
struct kvm_vcpu *vcpu);
-
+ ulong (*get_cr)(int cr, struct kvm_vcpu *vcpu);
+ void (*set_cr)(int cr, ulong val, struct kvm_vcpu *vcpu);
};
/* Type, address-of, and value of an instruction's operand. */
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 3b178d8..e8e108a 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -585,8 +585,6 @@ void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
unsigned long *rflags);
-unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr);
-void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value);
void kvm_enable_efer_bits(u64);
int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 91450b5..5b060e4 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2483,7 +2483,7 @@ twobyte_insn:
break;
case 4: /* smsw */
c->dst.bytes = 2;
- c->dst.val = realmode_get_cr(ctxt->vcpu, 0);
+ c->dst.val = ops->get_cr(0, ctxt->vcpu);
break;
case 6: /* lmsw */
realmode_lmsw(ctxt->vcpu, (u16)c->src.val,
@@ -2519,8 +2519,7 @@ twobyte_insn:
case 0x20: /* mov cr, reg */
if (c->modrm_mod != 3)
goto cannot_emulate;
- c->regs[c->modrm_rm] =
- realmode_get_cr(ctxt->vcpu, c->modrm_reg);
+ c->regs[c->modrm_rm] = ops->get_cr(c->modrm_reg, ctxt->vcpu);
c->dst.type = OP_NONE; /* no writeback */
break;
case 0x21: /* mov from dr to reg */
@@ -2534,7 +2533,7 @@ twobyte_insn:
case 0x22: /* mov reg, cr */
if (c->modrm_mod != 3)
goto cannot_emulate;
- realmode_set_cr(ctxt->vcpu, c->modrm_reg, c->modrm_val);
+ ops->set_cr(c->modrm_reg, c->modrm_val, ctxt->vcpu);
c->dst.type = OP_NONE;
break;
case 0x23: /* mov from reg to dr */
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index a1e671a..bf714df 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3370,12 +3370,70 @@ void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
}
EXPORT_SYMBOL_GPL(kvm_report_emulation_failure);
+static u64 mk_cr_64(u64 curr_cr, u32 new_val)
+{
+ return (curr_cr & ~((1ULL << 32) - 1)) | new_val;
+}
+
+static unsigned long emulator_get_cr(int cr, struct kvm_vcpu *vcpu)
+{
+ unsigned long value;
+
+ switch (cr) {
+ case 0:
+ value = kvm_read_cr0(vcpu);
+ break;
+ case 2:
+ value = vcpu->arch.cr2;
+ break;
+ case 3:
+ value = vcpu->arch.cr3;
+ break;
+ case 4:
+ value = kvm_read_cr4(vcpu);
+ break;
+ case 8:
+ value = kvm_get_cr8(vcpu);
+ break;
+ default:
+ vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
+ return 0;
+ }
+
+ return value;
+}
+
+static void emulator_set_cr(int cr, unsigned long val, struct kvm_vcpu *vcpu)
+{
+ switch (cr) {
+ case 0:
+ kvm_set_cr0(vcpu, mk_cr_64(kvm_read_cr0(vcpu), val));
+ break;
+ case 2:
+ vcpu->arch.cr2 = val;
+ break;
+ case 3:
+ kvm_set_cr3(vcpu, val);
+ break;
+ case 4:
+ kvm_set_cr4(vcpu, mk_cr_64(kvm_read_cr4(vcpu), val));
+ break;
+ case 8:
+ kvm_set_cr8(vcpu, val & 0xfUL);
+ break;
+ default:
+ vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
+ }
+}
+
static struct x86_emulate_ops emulate_ops = {
.read_std = kvm_read_guest_virt_system,
.fetch = kvm_fetch_guest_virt,
.read_emulated = emulator_read_emulated,
.write_emulated = emulator_write_emulated,
.cmpxchg_emulated = emulator_cmpxchg_emulated,
+ .get_cr = emulator_get_cr,
+ .set_cr = emulator_set_cr,
};
static void cache_all_regs(struct kvm_vcpu *vcpu)
@@ -3973,11 +4031,6 @@ int kvm_fix_hypercall(struct kvm_vcpu *vcpu)
return emulator_write_emulated(rip, instruction, 3, vcpu);
}
-static u64 mk_cr_64(u64 curr_cr, u32 new_val)
-{
- return (curr_cr & ~((1ULL << 32) - 1)) | new_val;
-}
-
void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
{
struct desc_ptr dt = { limit, base };
@@ -3999,57 +4052,6 @@ void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
*rflags = kvm_get_rflags(vcpu);
}
-unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
-{
- unsigned long value;
-
- switch (cr) {
- case 0:
- value = kvm_read_cr0(vcpu);
- break;
- case 2:
- value = vcpu->arch.cr2;
- break;
- case 3:
- value = vcpu->arch.cr3;
- break;
- case 4:
- value = kvm_read_cr4(vcpu);
- break;
- case 8:
- value = kvm_get_cr8(vcpu);
- break;
- default:
- vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
- return 0;
- }
-
- return value;
-}
-
-void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val)
-{
- switch (cr) {
- case 0:
- kvm_set_cr0(vcpu, mk_cr_64(kvm_read_cr0(vcpu), val));
- break;
- case 2:
- vcpu->arch.cr2 = val;
- break;
- case 3:
- kvm_set_cr3(vcpu, val);
- break;
- case 4:
- kvm_set_cr4(vcpu, mk_cr_64(kvm_read_cr4(vcpu), val));
- break;
- case 8:
- kvm_set_cr8(vcpu, val & 0xfUL);
- break;
- default:
- vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
- }
-}
-
static int move_to_next_stateful_cpuid_entry(struct kvm_vcpu *vcpu, int i)
{
struct kvm_cpuid_entry2 *e = &vcpu->arch.cpuid_entries[i];
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 06/30] KVM: remove realmode_lmsw function.
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (4 preceding siblings ...)
2010-03-14 16:20 ` [PATCH v2 05/30] KVM: Provide callback to get/set control registers in emulator ops Gleb Natapov
@ 2010-03-14 16:20 ` Gleb Natapov
2010-03-15 11:02 ` Andre Przywara
2010-03-14 16:20 ` [PATCH v2 07/30] KVM: Provide x86_emulate_ctxt callback to get current cpl Gleb Natapov
` (23 subsequent siblings)
29 siblings, 1 reply; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:20 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Use (get|set)_cr callback to emulate lmsw inside emulator.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/include/asm/kvm_host.h | 2 --
arch/x86/kvm/emulate.c | 4 ++--
arch/x86/kvm/x86.c | 7 -------
3 files changed, 2 insertions(+), 11 deletions(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index e8e108a..1e15a0a 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -582,8 +582,6 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context);
void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
-void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
- unsigned long *rflags);
void kvm_enable_efer_bits(u64);
int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 5b060e4..5e2fa61 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2486,8 +2486,8 @@ twobyte_insn:
c->dst.val = ops->get_cr(0, ctxt->vcpu);
break;
case 6: /* lmsw */
- realmode_lmsw(ctxt->vcpu, (u16)c->src.val,
- &ctxt->eflags);
+ ops->set_cr(0, (ops->get_cr(0, ctxt->vcpu) & ~0x0ful) |
+ (c->src.val & 0x0f), ctxt->vcpu);
c->dst.type = OP_NONE;
break;
case 7: /* invlpg*/
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index bf714df..b08f8a1 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4045,13 +4045,6 @@ void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
kvm_x86_ops->set_idt(vcpu, &dt);
}
-void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
- unsigned long *rflags)
-{
- kvm_lmsw(vcpu, msw);
- *rflags = kvm_get_rflags(vcpu);
-}
-
static int move_to_next_stateful_cpuid_entry(struct kvm_vcpu *vcpu, int i)
{
struct kvm_cpuid_entry2 *e = &vcpu->arch.cpuid_entries[i];
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 07/30] KVM: Provide x86_emulate_ctxt callback to get current cpl
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (5 preceding siblings ...)
2010-03-14 16:20 ` [PATCH v2 06/30] KVM: remove realmode_lmsw function Gleb Natapov
@ 2010-03-14 16:20 ` Gleb Natapov
2010-03-15 13:16 ` Andre Przywara
2010-03-14 16:20 ` [PATCH v2 08/30] KVM: Provide current eip as part of emulator context Gleb Natapov
` (22 subsequent siblings)
29 siblings, 1 reply; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:20 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/include/asm/kvm_emulate.h | 1 +
arch/x86/kvm/emulate.c | 15 ++++++++-------
arch/x86/kvm/x86.c | 6 ++++++
3 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 0c5caa4..b048fd2 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -110,6 +110,7 @@ struct x86_emulate_ops {
struct kvm_vcpu *vcpu);
ulong (*get_cr)(int cr, struct kvm_vcpu *vcpu);
void (*set_cr)(int cr, ulong val, struct kvm_vcpu *vcpu);
+ int (*cpl)(struct kvm_vcpu *vcpu);
};
/* Type, address-of, and value of an instruction's operand. */
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 5e2fa61..8bd0557 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1257,7 +1257,7 @@ static int emulate_popf(struct x86_emulate_ctxt *ctxt,
int rc;
unsigned long val, change_mask;
int iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
- int cpl = kvm_x86_ops->get_cpl(ctxt->vcpu);
+ int cpl = ops->cpl(ctxt->vcpu);
rc = emulate_pop(ctxt, ops, &val, len);
if (rc != X86EMUL_CONTINUE)
@@ -1758,7 +1758,8 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
return X86EMUL_CONTINUE;
}
-static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt)
+static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops)
{
int iopl;
if (ctxt->mode == X86EMUL_MODE_REAL)
@@ -1766,7 +1767,7 @@ static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt)
if (ctxt->mode == X86EMUL_MODE_VM86)
return true;
iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
- return kvm_x86_ops->get_cpl(ctxt->vcpu) > iopl;
+ return ops->cpl(ctxt->vcpu) > iopl;
}
static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt,
@@ -1803,7 +1804,7 @@ static bool emulator_io_permited(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops,
u16 port, u16 len)
{
- if (emulator_bad_iopl(ctxt))
+ if (emulator_bad_iopl(ctxt, ops))
if (!emulator_io_port_access_allowed(ctxt, ops, port, len))
return false;
return true;
@@ -1842,7 +1843,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
}
/* Privileged instruction can be executed only in CPL=0 */
- if ((c->d & Priv) && kvm_x86_ops->get_cpl(ctxt->vcpu)) {
+ if ((c->d & Priv) && ops->cpl(ctxt->vcpu)) {
kvm_inject_gp(ctxt->vcpu, 0);
goto done;
}
@@ -2378,7 +2379,7 @@ special_insn:
c->dst.type = OP_NONE; /* Disable writeback. */
break;
case 0xfa: /* cli */
- if (emulator_bad_iopl(ctxt))
+ if (emulator_bad_iopl(ctxt, ops))
kvm_inject_gp(ctxt->vcpu, 0);
else {
ctxt->eflags &= ~X86_EFLAGS_IF;
@@ -2386,7 +2387,7 @@ special_insn:
}
break;
case 0xfb: /* sti */
- if (emulator_bad_iopl(ctxt))
+ if (emulator_bad_iopl(ctxt, ops))
kvm_inject_gp(ctxt->vcpu, 0);
else {
toggle_interruptibility(ctxt, KVM_X86_SHADOW_INT_STI);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index b08f8a1..3f2a8d3 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3426,6 +3426,11 @@ static void emulator_set_cr(int cr, unsigned long val, struct kvm_vcpu *vcpu)
}
}
+static int emulator_get_cpl(struct kvm_vcpu *vcpu)
+{
+ return kvm_x86_ops->get_cpl(vcpu);
+}
+
static struct x86_emulate_ops emulate_ops = {
.read_std = kvm_read_guest_virt_system,
.fetch = kvm_fetch_guest_virt,
@@ -3434,6 +3439,7 @@ static struct x86_emulate_ops emulate_ops = {
.cmpxchg_emulated = emulator_cmpxchg_emulated,
.get_cr = emulator_get_cr,
.set_cr = emulator_set_cr,
+ .cpl = emulator_get_cpl,
};
static void cache_all_regs(struct kvm_vcpu *vcpu)
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 08/30] KVM: Provide current eip as part of emulator context.
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (6 preceding siblings ...)
2010-03-14 16:20 ` [PATCH v2 07/30] KVM: Provide x86_emulate_ctxt callback to get current cpl Gleb Natapov
@ 2010-03-14 16:20 ` Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 09/30] KVM: x86 emulator: fix mov r/m, sreg emulation Gleb Natapov
` (21 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:20 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Eliminate the need to call back into KVM to get it from emulator.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/include/asm/kvm_emulate.h | 3 ++-
arch/x86/kvm/emulate.c | 12 ++++++------
arch/x86/kvm/x86.c | 1 +
3 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index b048fd2..0765725 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -141,7 +141,7 @@ struct decode_cache {
u8 seg_override;
unsigned int d;
unsigned long regs[NR_VCPU_REGS];
- unsigned long eip, eip_orig;
+ unsigned long eip;
/* modrm */
u8 modrm;
u8 modrm_mod;
@@ -160,6 +160,7 @@ struct x86_emulate_ctxt {
struct kvm_vcpu *vcpu;
unsigned long eflags;
+ unsigned long eip; /* eip before instruction emulation */
/* Emulated execution mode, represented by an X86EMUL_MODE value. */
int mode;
u32 cs_base;
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 8bd0557..2c27aa4 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -667,7 +667,7 @@ static int do_insn_fetch(struct x86_emulate_ctxt *ctxt,
int rc;
/* x86 instructions are limited to 15 bytes. */
- if (eip + size - ctxt->decode.eip_orig > 15)
+ if (eip + size - ctxt->eip > 15)
return X86EMUL_UNHANDLEABLE;
eip += ctxt->cs_base;
while (size--) {
@@ -927,7 +927,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
/* Shadow copy of register state. Committed on successful emulation. */
memset(c, 0, sizeof(struct decode_cache));
- c->eip = c->eip_orig = kvm_rip_read(ctxt->vcpu);
+ c->eip = ctxt->eip;
ctxt->cs_base = seg_base(ctxt, VCPU_SREG_CS);
memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
@@ -1878,7 +1878,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
}
}
register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1);
- c->eip = kvm_rip_read(ctxt->vcpu);
+ c->eip = ctxt->eip;
}
if (c->src.type == OP_MEM) {
@@ -2447,7 +2447,7 @@ twobyte_insn:
goto done;
/* Let the processor re-execute the fixed hypercall */
- c->eip = kvm_rip_read(ctxt->vcpu);
+ c->eip = ctxt->eip;
/* Disable writeback. */
c->dst.type = OP_NONE;
break;
@@ -2551,7 +2551,7 @@ twobyte_insn:
| ((u64)c->regs[VCPU_REGS_RDX] << 32);
if (kvm_set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data)) {
kvm_inject_gp(ctxt->vcpu, 0);
- c->eip = kvm_rip_read(ctxt->vcpu);
+ c->eip = ctxt->eip;
}
rc = X86EMUL_CONTINUE;
c->dst.type = OP_NONE;
@@ -2560,7 +2560,7 @@ twobyte_insn:
/* rdmsr */
if (kvm_get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data)) {
kvm_inject_gp(ctxt->vcpu, 0);
- c->eip = kvm_rip_read(ctxt->vcpu);
+ c->eip = ctxt->eip;
} else {
c->regs[VCPU_REGS_RAX] = (u32)msr_data;
c->regs[VCPU_REGS_RDX] = msr_data >> 32;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 3f2a8d3..6cbac79 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3478,6 +3478,7 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
vcpu->arch.emulate_ctxt.vcpu = vcpu;
vcpu->arch.emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu);
+ vcpu->arch.emulate_ctxt.eip = kvm_rip_read(vcpu);
vcpu->arch.emulate_ctxt.mode =
(!is_protmode(vcpu)) ? X86EMUL_MODE_REAL :
(vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM)
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 09/30] KVM: x86 emulator: fix mov r/m, sreg emulation.
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (7 preceding siblings ...)
2010-03-14 16:20 ` [PATCH v2 08/30] KVM: Provide current eip as part of emulator context Gleb Natapov
@ 2010-03-14 16:20 ` Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 10/30] KVM: x86 emulator: fix 0f 01 /5 emulation Gleb Natapov
` (20 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:20 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
mov r/m, sreg generates #UD ins sreg is incorrect.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/emulate.c | 7 +++----
1 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 2c27aa4..c3b9334 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2126,12 +2126,11 @@ special_insn:
case 0x8c: { /* mov r/m, sreg */
struct kvm_segment segreg;
- if (c->modrm_reg <= 5)
+ if (c->modrm_reg <= VCPU_SREG_GS)
kvm_get_segment(ctxt->vcpu, &segreg, c->modrm_reg);
else {
- printk(KERN_INFO "0x8c: Invalid segreg in modrm byte 0x%02x\n",
- c->modrm);
- goto cannot_emulate;
+ kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+ goto done;
}
c->dst.val = segreg.selector;
break;
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 10/30] KVM: x86 emulator: fix 0f 01 /5 emulation
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (8 preceding siblings ...)
2010-03-14 16:20 ` [PATCH v2 09/30] KVM: x86 emulator: fix mov r/m, sreg emulation Gleb Natapov
@ 2010-03-14 16:20 ` Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 11/30] KVM: x86 emulator: 0f (20|21|22|23) ignore mod bits Gleb Natapov
` (19 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:20 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
It is undefined and should generate #UD.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/emulate.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index c3b9334..7c7debb 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2490,6 +2490,9 @@ twobyte_insn:
(c->src.val & 0x0f), ctxt->vcpu);
c->dst.type = OP_NONE;
break;
+ case 5: /* not defined */
+ kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+ goto done;
case 7: /* invlpg*/
emulate_invlpg(ctxt->vcpu, memop);
/* Disable writeback. */
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 11/30] KVM: x86 emulator: 0f (20|21|22|23) ignore mod bits.
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (9 preceding siblings ...)
2010-03-14 16:20 ` [PATCH v2 10/30] KVM: x86 emulator: fix 0f 01 /5 emulation Gleb Natapov
@ 2010-03-14 16:20 ` Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 12/30] KVM: x86 emulator: inject #UD on access to non-existing CR Gleb Natapov
` (18 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:20 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Resent spec says that for 0f (20|21|22|23) the 2 bits in the mod field
are ignored. Interestingly enough older spec says that 11 is only valid
encoding.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/emulate.c | 8 --------
1 files changed, 0 insertions(+), 8 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 7c7debb..fa4604e 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2520,28 +2520,20 @@ twobyte_insn:
c->dst.type = OP_NONE;
break;
case 0x20: /* mov cr, reg */
- if (c->modrm_mod != 3)
- goto cannot_emulate;
c->regs[c->modrm_rm] = ops->get_cr(c->modrm_reg, ctxt->vcpu);
c->dst.type = OP_NONE; /* no writeback */
break;
case 0x21: /* mov from dr to reg */
- if (c->modrm_mod != 3)
- goto cannot_emulate;
if (emulator_get_dr(ctxt, c->modrm_reg, &c->regs[c->modrm_rm]))
goto cannot_emulate;
rc = X86EMUL_CONTINUE;
c->dst.type = OP_NONE; /* no writeback */
break;
case 0x22: /* mov reg, cr */
- if (c->modrm_mod != 3)
- goto cannot_emulate;
ops->set_cr(c->modrm_reg, c->modrm_val, ctxt->vcpu);
c->dst.type = OP_NONE;
break;
case 0x23: /* mov from reg to dr */
- if (c->modrm_mod != 3)
- goto cannot_emulate;
if (emulator_set_dr(ctxt, c->modrm_reg, c->regs[c->modrm_rm]))
goto cannot_emulate;
rc = X86EMUL_CONTINUE;
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 12/30] KVM: x86 emulator: inject #UD on access to non-existing CR
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (10 preceding siblings ...)
2010-03-14 16:20 ` [PATCH v2 11/30] KVM: x86 emulator: 0f (20|21|22|23) ignore mod bits Gleb Natapov
@ 2010-03-14 16:20 ` Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 13/30] KVM: x86 emulator: fix mov dr to inject #UD when needed Gleb Natapov
` (17 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:20 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/emulate.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index fa4604e..836e97b 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2520,6 +2520,13 @@ twobyte_insn:
c->dst.type = OP_NONE;
break;
case 0x20: /* mov cr, reg */
+ switch (c->modrm_reg) {
+ case 1:
+ case 5 ... 7:
+ case 9 ... 15:
+ kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+ goto done;
+ }
c->regs[c->modrm_rm] = ops->get_cr(c->modrm_reg, ctxt->vcpu);
c->dst.type = OP_NONE; /* no writeback */
break;
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 13/30] KVM: x86 emulator: fix mov dr to inject #UD when needed.
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (11 preceding siblings ...)
2010-03-14 16:20 ` [PATCH v2 12/30] KVM: x86 emulator: inject #UD on access to non-existing CR Gleb Natapov
@ 2010-03-14 16:20 ` Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 14/30] KVM: x86 emulator: fix return values of syscall/sysenter/sysexit emulations Gleb Natapov
` (16 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:20 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
If CR4.DE=1 access to registers DR4/DR5 cause #UD.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/emulate.c | 18 ++++++++++++------
1 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 836e97b..5afddcf 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2531,9 +2531,12 @@ twobyte_insn:
c->dst.type = OP_NONE; /* no writeback */
break;
case 0x21: /* mov from dr to reg */
- if (emulator_get_dr(ctxt, c->modrm_reg, &c->regs[c->modrm_rm]))
- goto cannot_emulate;
- rc = X86EMUL_CONTINUE;
+ if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) &&
+ (c->modrm_reg == 4 || c->modrm_reg == 5)) {
+ kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+ goto done;
+ }
+ emulator_get_dr(ctxt, c->modrm_reg, &c->regs[c->modrm_rm]);
c->dst.type = OP_NONE; /* no writeback */
break;
case 0x22: /* mov reg, cr */
@@ -2541,9 +2544,12 @@ twobyte_insn:
c->dst.type = OP_NONE;
break;
case 0x23: /* mov from reg to dr */
- if (emulator_set_dr(ctxt, c->modrm_reg, c->regs[c->modrm_rm]))
- goto cannot_emulate;
- rc = X86EMUL_CONTINUE;
+ if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) &&
+ (c->modrm_reg == 4 || c->modrm_reg == 5)) {
+ kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+ goto done;
+ }
+ emulator_set_dr(ctxt, c->modrm_reg, c->regs[c->modrm_rm]);
c->dst.type = OP_NONE; /* no writeback */
break;
case 0x30:
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 14/30] KVM: x86 emulator: fix return values of syscall/sysenter/sysexit emulations
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (12 preceding siblings ...)
2010-03-14 16:20 ` [PATCH v2 13/30] KVM: x86 emulator: fix mov dr to inject #UD when needed Gleb Natapov
@ 2010-03-14 16:20 ` Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 15/30] KVM: x86 emulator: do not call writeback if msr access fails Gleb Natapov
` (15 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:20 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Return X86EMUL_PROPAGATE_FAULT is fault was injected. Also inject #UD
for those instruction when appropriate.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/emulate.c | 17 +++++++++++------
1 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 5afddcf..1393bf0 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1600,8 +1600,11 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt)
u64 msr_data;
/* syscall is not available in real mode */
- if (ctxt->mode == X86EMUL_MODE_REAL || ctxt->mode == X86EMUL_MODE_VM86)
- return X86EMUL_UNHANDLEABLE;
+ if (ctxt->mode == X86EMUL_MODE_REAL ||
+ ctxt->mode == X86EMUL_MODE_VM86) {
+ kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+ return X86EMUL_PROPAGATE_FAULT;
+ }
setup_syscalls_segments(ctxt, &cs, &ss);
@@ -1651,14 +1654,16 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt)
/* inject #GP if in real mode */
if (ctxt->mode == X86EMUL_MODE_REAL) {
kvm_inject_gp(ctxt->vcpu, 0);
- return X86EMUL_UNHANDLEABLE;
+ return X86EMUL_PROPAGATE_FAULT;
}
/* XXX sysenter/sysexit have not been tested in 64bit mode.
* Therefore, we inject an #UD.
*/
- if (ctxt->mode == X86EMUL_MODE_PROT64)
- return X86EMUL_UNHANDLEABLE;
+ if (ctxt->mode == X86EMUL_MODE_PROT64) {
+ kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+ return X86EMUL_PROPAGATE_FAULT;
+ }
setup_syscalls_segments(ctxt, &cs, &ss);
@@ -1713,7 +1718,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
if (ctxt->mode == X86EMUL_MODE_REAL ||
ctxt->mode == X86EMUL_MODE_VM86) {
kvm_inject_gp(ctxt->vcpu, 0);
- return X86EMUL_UNHANDLEABLE;
+ return X86EMUL_PROPAGATE_FAULT;
}
setup_syscalls_segments(ctxt, &cs, &ss);
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 15/30] KVM: x86 emulator: do not call writeback if msr access fails.
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (13 preceding siblings ...)
2010-03-14 16:20 ` [PATCH v2 14/30] KVM: x86 emulator: fix return values of syscall/sysenter/sysexit emulations Gleb Natapov
@ 2010-03-14 16:21 ` Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 16/30] KVM: x86 emulator: If LOCK prefix is used dest arg should be memory Gleb Natapov
` (14 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:21 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/emulate.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 1393bf0..b89a8f2 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2563,7 +2563,7 @@ twobyte_insn:
| ((u64)c->regs[VCPU_REGS_RDX] << 32);
if (kvm_set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data)) {
kvm_inject_gp(ctxt->vcpu, 0);
- c->eip = ctxt->eip;
+ goto done;
}
rc = X86EMUL_CONTINUE;
c->dst.type = OP_NONE;
@@ -2572,7 +2572,7 @@ twobyte_insn:
/* rdmsr */
if (kvm_get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data)) {
kvm_inject_gp(ctxt->vcpu, 0);
- c->eip = ctxt->eip;
+ goto done;
} else {
c->regs[VCPU_REGS_RAX] = (u32)msr_data;
c->regs[VCPU_REGS_RDX] = msr_data >> 32;
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 16/30] KVM: x86 emulator: If LOCK prefix is used dest arg should be memory.
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (14 preceding siblings ...)
2010-03-14 16:21 ` [PATCH v2 15/30] KVM: x86 emulator: do not call writeback if msr access fails Gleb Natapov
@ 2010-03-14 16:21 ` Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 17/30] KVM: x86 emulator: cleanup grp3 return value Gleb Natapov
` (13 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:21 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
If LOCK prefix is used dest arg should be memory, otherwise instruction
should generate #UD.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/emulate.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index b89a8f2..46a7ee3 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1842,7 +1842,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
}
/* LOCK prefix is allowed only with some instructions */
- if (c->lock_prefix && !(c->d & Lock)) {
+ if (c->lock_prefix && (!(c->d & Lock) || c->dst.type != OP_MEM)) {
kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
goto done;
}
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 17/30] KVM: x86 emulator: cleanup grp3 return value
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (15 preceding siblings ...)
2010-03-14 16:21 ` [PATCH v2 16/30] KVM: x86 emulator: If LOCK prefix is used dest arg should be memory Gleb Natapov
@ 2010-03-14 16:21 ` Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 18/30] KVM: x86 emulator: Provide more callbacks for x86 emulator Gleb Natapov
` (12 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:21 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
When x86_emulate_insn() does not know how to emulate instruction it
exits via cannot_emulate label in all cases except when emulating
grp3. Fix that.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/emulate.c | 12 ++++--------
1 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 46a7ee3..d696cbd 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1397,7 +1397,6 @@ static inline int emulate_grp3(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops)
{
struct decode_cache *c = &ctxt->decode;
- int rc = X86EMUL_CONTINUE;
switch (c->modrm_reg) {
case 0 ... 1: /* test */
@@ -1410,11 +1409,9 @@ static inline int emulate_grp3(struct x86_emulate_ctxt *ctxt,
emulate_1op("neg", c->dst, ctxt->eflags);
break;
default:
- DPRINTF("Cannot emulate %02x\n", c->b);
- rc = X86EMUL_UNHANDLEABLE;
- break;
+ return 0;
}
- return rc;
+ return 1;
}
static inline int emulate_grp45(struct x86_emulate_ctxt *ctxt,
@@ -2374,9 +2371,8 @@ special_insn:
c->dst.type = OP_NONE; /* Disable writeback. */
break;
case 0xf6 ... 0xf7: /* Grp3 */
- rc = emulate_grp3(ctxt, ops);
- if (rc != X86EMUL_CONTINUE)
- goto done;
+ if (!emulate_grp3(ctxt, ops))
+ goto cannot_emulate;
break;
case 0xf8: /* clc */
ctxt->eflags &= ~EFLG_CF;
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 18/30] KVM: x86 emulator: Provide more callbacks for x86 emulator.
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (16 preceding siblings ...)
2010-03-14 16:21 ` [PATCH v2 17/30] KVM: x86 emulator: cleanup grp3 return value Gleb Natapov
@ 2010-03-14 16:21 ` Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 19/30] KVM: x86 emulator: Emulate task switch in emulator.c Gleb Natapov
` (11 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:21 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Provide get_cached_descriptor(), set_cached_descriptor(),
get_segment_selector(), set_segment_selector(), get_gdt(),
write_std() callbacks.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/include/asm/kvm_emulate.h | 16 +++++
arch/x86/kvm/x86.c | 130 +++++++++++++++++++++++++++++++----
2 files changed, 131 insertions(+), 15 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 0765725..f901467 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -63,6 +63,15 @@ struct x86_emulate_ops {
unsigned int bytes, struct kvm_vcpu *vcpu, u32 *error);
/*
+ * write_std: Write bytes of standard (non-emulated/special) memory.
+ * Used for descriptor writing.
+ * @addr: [IN ] Linear address to which to write.
+ * @val: [OUT] Value write to memory, zero-extended to 'u_long'.
+ * @bytes: [IN ] Number of bytes to write to memory.
+ */
+ int (*write_std)(unsigned long addr, void *val,
+ unsigned int bytes, struct kvm_vcpu *vcpu, u32 *error);
+ /*
* fetch: Read bytes of standard (non-emulated/special) memory.
* Used for instruction fetch.
* @addr: [IN ] Linear address from which to read.
@@ -108,6 +117,13 @@ struct x86_emulate_ops {
const void *new,
unsigned int bytes,
struct kvm_vcpu *vcpu);
+ bool (*get_cached_descriptor)(struct desc_struct *desc,
+ int seg, struct kvm_vcpu *vcpu);
+ void (*set_cached_descriptor)(struct desc_struct *desc,
+ int seg, struct kvm_vcpu *vcpu);
+ u16 (*get_segment_selector)(int seg, struct kvm_vcpu *vcpu);
+ void (*set_segment_selector)(u16 sel, int seg, struct kvm_vcpu *vcpu);
+ void (*get_gdt)(struct desc_ptr *dt, struct kvm_vcpu *vcpu);
ulong (*get_cr)(int cr, struct kvm_vcpu *vcpu);
void (*set_cr)(int cr, ulong val, struct kvm_vcpu *vcpu);
int (*cpl)(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 6cbac79..c30e81d 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3050,6 +3050,18 @@ static int vcpu_mmio_read(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *v)
return kvm_io_bus_read(vcpu->kvm, KVM_MMIO_BUS, addr, len, v);
}
+static void kvm_set_segment(struct kvm_vcpu *vcpu,
+ struct kvm_segment *var, int seg)
+{
+ kvm_x86_ops->set_segment(vcpu, var, seg);
+}
+
+void kvm_get_segment(struct kvm_vcpu *vcpu,
+ struct kvm_segment *var, int seg)
+{
+ kvm_x86_ops->get_segment(vcpu, var, seg);
+}
+
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;
@@ -3130,14 +3142,18 @@ static int kvm_read_guest_virt_system(gva_t addr, void *val, unsigned int bytes,
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,
- struct kvm_vcpu *vcpu, u32 *error)
+static int kvm_write_guest_virt_helper(gva_t addr, void *val,
+ unsigned int bytes,
+ struct kvm_vcpu *vcpu, u32 access,
+ u32 *error)
{
void *data = val;
int r = X86EMUL_CONTINUE;
+ access |= PFERR_WRITE_MASK;
+
while (bytes) {
- gpa_t gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, error);
+ gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr, access, error);
unsigned offset = addr & (PAGE_SIZE-1);
unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset);
int ret;
@@ -3160,6 +3176,19 @@ out:
return r;
}
+static int kvm_write_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_write_guest_virt_helper(addr, val, bytes, vcpu, access, error);
+}
+
+static int kvm_write_guest_virt_system(gva_t addr, void *val,
+ unsigned int bytes,
+ struct kvm_vcpu *vcpu, u32 *error)
+{
+ return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, 0, error);
+}
static int emulator_read_emulated(unsigned long addr,
void *val,
@@ -3431,12 +3460,95 @@ static int emulator_get_cpl(struct kvm_vcpu *vcpu)
return kvm_x86_ops->get_cpl(vcpu);
}
+static void emulator_get_gdt(struct desc_ptr *dt, struct kvm_vcpu *vcpu)
+{
+ kvm_x86_ops->get_gdt(vcpu, dt);
+}
+
+static bool emulator_get_cached_descriptor(struct desc_struct *desc, int seg,
+ struct kvm_vcpu *vcpu)
+{
+ struct kvm_segment var;
+
+ kvm_get_segment(vcpu, &var, seg);
+
+ if (var.unusable)
+ return false;
+
+ if (var.g)
+ var.limit >>= 12;
+ set_desc_limit(desc, var.limit);
+ set_desc_base(desc, (unsigned long)var.base);
+ desc->type = var.type;
+ desc->s = var.s;
+ desc->dpl = var.dpl;
+ desc->p = var.present;
+ desc->avl = var.avl;
+ desc->l = var.l;
+ desc->d = var.db;
+ desc->g = var.g;
+
+ return true;
+}
+
+static void emulator_set_cached_descriptor(struct desc_struct *desc, int seg,
+ struct kvm_vcpu *vcpu)
+{
+ struct kvm_segment var;
+
+ /* needed to preserve selector */
+ kvm_get_segment(vcpu, &var, seg);
+
+ var.base = get_desc_base(desc);
+ var.limit = get_desc_limit(desc);
+ if (desc->g)
+ var.limit = (var.limit << 12) | 0xfff;
+ var.type = desc->type;
+ var.present = desc->p;
+ var.dpl = desc->dpl;
+ var.db = desc->d;
+ var.s = desc->s;
+ var.l = desc->l;
+ var.g = desc->g;
+ var.avl = desc->avl;
+ var.present = desc->p;
+ var.unusable = !var.present;
+ var.padding = 0;
+
+ kvm_set_segment(vcpu, &var, seg);
+ return;
+}
+
+static u16 emulator_get_segment_selector(int seg, struct kvm_vcpu *vcpu)
+{
+ struct kvm_segment kvm_seg;
+
+ kvm_get_segment(vcpu, &kvm_seg, seg);
+ return kvm_seg.selector;
+}
+
+static void emulator_set_segment_selector(u16 sel, int seg,
+ struct kvm_vcpu *vcpu)
+{
+ struct kvm_segment kvm_seg;
+
+ kvm_get_segment(vcpu, &kvm_seg, seg);
+ kvm_seg.selector = sel;
+ kvm_set_segment(vcpu, &kvm_seg, seg);
+}
+
static struct x86_emulate_ops emulate_ops = {
.read_std = kvm_read_guest_virt_system,
+ .write_std = kvm_write_guest_virt_system,
.fetch = kvm_fetch_guest_virt,
.read_emulated = emulator_read_emulated,
.write_emulated = emulator_write_emulated,
.cmpxchg_emulated = emulator_cmpxchg_emulated,
+ .get_cached_descriptor = emulator_get_cached_descriptor,
+ .set_cached_descriptor = emulator_set_cached_descriptor,
+ .get_segment_selector = emulator_get_segment_selector,
+ .set_segment_selector = emulator_set_segment_selector,
+ .get_gdt = emulator_get_gdt,
.get_cr = emulator_get_cr,
.set_cr = emulator_set_cr,
.cpl = emulator_get_cpl,
@@ -4596,12 +4708,6 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
return 0;
}
-void kvm_get_segment(struct kvm_vcpu *vcpu,
- struct kvm_segment *var, int seg)
-{
- kvm_x86_ops->get_segment(vcpu, var, seg);
-}
-
void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
{
struct kvm_segment cs;
@@ -4673,12 +4779,6 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
return 0;
}
-static void kvm_set_segment(struct kvm_vcpu *vcpu,
- struct kvm_segment *var, int seg)
-{
- kvm_x86_ops->set_segment(vcpu, var, seg);
-}
-
static void seg_desct_to_kvm_desct(struct desc_struct *seg_desc, u16 selector,
struct kvm_segment *kvm_desct)
{
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 19/30] KVM: x86 emulator: Emulate task switch in emulator.c
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (17 preceding siblings ...)
2010-03-14 16:21 ` [PATCH v2 18/30] KVM: x86 emulator: Provide more callbacks for x86 emulator Gleb Natapov
@ 2010-03-14 16:21 ` Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 20/30] KVM: x86 emulator: Use load_segment_descriptor() instead of kvm_load_segment_descriptor() Gleb Natapov
` (10 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:21 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Implement emulation of 16/32 bit task switch in emulator.c
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/include/asm/kvm_emulate.h | 5 +
arch/x86/kvm/emulate.c | 564 ++++++++++++++++++++++++++++++++++++
2 files changed, 569 insertions(+), 0 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index f901467..bd46929 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -11,6 +11,8 @@
#ifndef _ASM_X86_KVM_X86_EMULATE_H
#define _ASM_X86_KVM_X86_EMULATE_H
+#include <asm/desc_defs.h>
+
struct x86_emulate_ctxt;
/*
@@ -210,5 +212,8 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops);
int x86_emulate_insn(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops);
+int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops,
+ u16 tss_selector, int reason);
#endif /* _ASM_X86_KVM_X86_EMULATE_H */
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index d696cbd..cc1bb20 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -33,6 +33,7 @@
#include <asm/kvm_emulate.h>
#include "x86.h"
+#include "tss.h"
/*
* Opcode effective-address decode tables.
@@ -1221,6 +1222,199 @@ done:
return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
}
+static u32 desc_limit_scaled(struct desc_struct *desc)
+{
+ u32 limit = get_desc_limit(desc);
+
+ return desc->g ? (limit << 12) | 0xfff : limit;
+}
+
+static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops,
+ u16 selector, struct desc_ptr *dt)
+{
+ if (selector & 1 << 2) {
+ struct desc_struct desc;
+ memset (dt, 0, sizeof *dt);
+ if(!ops->get_cached_descriptor(&desc, VCPU_SREG_LDTR, ctxt->vcpu))
+ return;
+
+ dt->size = desc_limit_scaled(&desc); /* what if limit > 65535? */
+ dt->address = get_desc_base(&desc);
+ }
+ else
+ ops->get_gdt(dt, ctxt->vcpu);
+}
+
+/* allowed just for 8 bytes segments */
+static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops,
+ u16 selector, struct desc_struct *desc)
+{
+ struct desc_ptr dt;
+ u16 index = selector >> 3;
+ int ret;
+ u32 err;
+ ulong addr;
+
+ get_descriptor_table_ptr(ctxt, ops, selector, &dt);
+
+ if (dt.size < index * 8 + 7) {
+ kvm_inject_gp(ctxt->vcpu, selector & 0xfffc);
+ return X86EMUL_PROPAGATE_FAULT;
+ }
+ addr = dt.address + index * 8;
+ ret = ops->read_std(addr, desc, sizeof *desc, ctxt->vcpu, &err);
+ if (ret == X86EMUL_PROPAGATE_FAULT)
+ kvm_inject_page_fault(ctxt->vcpu, addr, err);
+
+ return ret;
+}
+
+/* allowed just for 8 bytes segments */
+static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops,
+ u16 selector, struct desc_struct *desc)
+{
+ struct desc_ptr dt;
+ u16 index = selector >> 3;
+ u32 err;
+ ulong addr;
+ int ret;
+
+ get_descriptor_table_ptr(ctxt, ops, selector, &dt);
+
+ if (dt.size < index * 8 + 7) {
+ kvm_inject_gp(ctxt->vcpu, selector & 0xfffc);
+ return X86EMUL_PROPAGATE_FAULT;
+ }
+
+ addr = dt.address + index * 8;
+ ret = ops->write_std(addr, desc, sizeof *desc, ctxt->vcpu, &err);
+ if (ret == X86EMUL_PROPAGATE_FAULT)
+ kvm_inject_page_fault(ctxt->vcpu, addr, err);
+
+ return ret;
+}
+
+static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops,
+ u16 selector, int 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;
+
+ memset(&seg_desc, 0, sizeof seg_desc);
+
+ if ((seg <= VCPU_SREG_GS && ctxt->mode == X86EMUL_MODE_VM86)
+ || ctxt->mode == X86EMUL_MODE_REAL) {
+ /* set real mode segment descriptor */
+ set_desc_base(&seg_desc, selector << 4);
+ set_desc_limit(&seg_desc, 0xffff);
+ seg_desc.type = 3;
+ seg_desc.p = 1;
+ seg_desc.s = 1;
+ goto load;
+ }
+
+ /* 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;
+
+ if (null_selector) /* for NULL selector skip all following checks */
+ goto load;
+
+ ret = read_segment_descriptor(ctxt, ops, selector, &seg_desc);
+ if (ret != X86EMUL_CONTINUE)
+ return ret;
+
+ err_code = selector & 0xfffc;
+ err_vec = GP_VECTOR;
+
+ /* can't load system descriptor into segment selecor */
+ if (seg <= VCPU_SREG_GS && !seg_desc.s)
+ goto exception;
+
+ if (!seg_desc.p) {
+ err_vec = (seg == VCPU_SREG_SS) ? SS_VECTOR : NP_VECTOR;
+ goto exception;
+ }
+
+ rpl = selector & 3;
+ dpl = seg_desc.dpl;
+ cpl = ops->cpl(ctxt->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 || (seg_desc.type & 0xa) != 0x2 || dpl != cpl)
+ goto exception;
+ break;
+ case VCPU_SREG_CS:
+ if (!(seg_desc.type & 8))
+ goto exception;
+
+ if (seg_desc.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 (seg_desc.s || (seg_desc.type != 1 && seg_desc.type != 9))
+ goto exception;
+ break;
+ case VCPU_SREG_LDTR:
+ if (seg_desc.s || seg_desc.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 ((seg_desc.type & 0xa) == 0x8 ||
+ (((seg_desc.type & 0xc) != 0xc) &&
+ (rpl > dpl && cpl > dpl)))
+ goto exception;
+ break;
+ }
+
+ if (seg_desc.s) {
+ /* mark segment as accessed */
+ seg_desc.type |= 1;
+ ret = write_segment_descriptor(ctxt, ops, selector, &seg_desc);
+ if (ret != X86EMUL_CONTINUE)
+ return ret;
+ }
+load:
+ ops->set_segment_selector(selector, seg, ctxt->vcpu);
+ ops->set_cached_descriptor(&seg_desc, seg, ctxt->vcpu);
+ return X86EMUL_CONTINUE;
+exception:
+ kvm_queue_exception_e(ctxt->vcpu, err_vec, err_code);
+ return X86EMUL_PROPAGATE_FAULT;
+}
+
static inline void emulate_push(struct x86_emulate_ctxt *ctxt)
{
struct decode_cache *c = &ctxt->decode;
@@ -1812,6 +2006,376 @@ static bool emulator_io_permited(struct x86_emulate_ctxt *ctxt,
return true;
}
+static u32 get_cached_descriptor_base(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops,
+ int seg)
+{
+ struct desc_struct desc;
+ if (ops->get_cached_descriptor(&desc, seg, ctxt->vcpu))
+ return get_desc_base(&desc);
+ else
+ return ~0;
+}
+
+static void save_state_to_tss16(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops,
+ struct tss_segment_16 *tss)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ tss->ip = c->eip;
+ tss->flag = ctxt->eflags;
+ tss->ax = c->regs[VCPU_REGS_RAX];
+ tss->cx = c->regs[VCPU_REGS_RCX];
+ tss->dx = c->regs[VCPU_REGS_RDX];
+ tss->bx = c->regs[VCPU_REGS_RBX];
+ tss->sp = c->regs[VCPU_REGS_RSP];
+ tss->bp = c->regs[VCPU_REGS_RBP];
+ tss->si = c->regs[VCPU_REGS_RSI];
+ tss->di = c->regs[VCPU_REGS_RDI];
+
+ tss->es = ops->get_segment_selector(VCPU_SREG_ES, ctxt->vcpu);
+ tss->cs = ops->get_segment_selector(VCPU_SREG_CS, ctxt->vcpu);
+ tss->ss = ops->get_segment_selector(VCPU_SREG_SS, ctxt->vcpu);
+ tss->ds = ops->get_segment_selector(VCPU_SREG_DS, ctxt->vcpu);
+ tss->ldt = ops->get_segment_selector(VCPU_SREG_LDTR, ctxt->vcpu);
+}
+
+static int load_state_from_tss16(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops,
+ struct tss_segment_16 *tss)
+{
+ struct decode_cache *c = &ctxt->decode;
+ int ret;
+
+ c->eip = tss->ip;
+ ctxt->eflags = tss->flag | 2;
+ c->regs[VCPU_REGS_RAX] = tss->ax;
+ c->regs[VCPU_REGS_RCX] = tss->cx;
+ c->regs[VCPU_REGS_RDX] = tss->dx;
+ c->regs[VCPU_REGS_RBX] = tss->bx;
+ c->regs[VCPU_REGS_RSP] = tss->sp;
+ c->regs[VCPU_REGS_RBP] = tss->bp;
+ c->regs[VCPU_REGS_RSI] = tss->si;
+ c->regs[VCPU_REGS_RDI] = tss->di;
+
+ /*
+ * SDM says that segment selectors are loaded before segment
+ * descriptors
+ */
+ ops->set_segment_selector(tss->ldt, VCPU_SREG_LDTR, ctxt->vcpu);
+ ops->set_segment_selector(tss->es, VCPU_SREG_ES, ctxt->vcpu);
+ ops->set_segment_selector(tss->cs, VCPU_SREG_CS, ctxt->vcpu);
+ ops->set_segment_selector(tss->ss, VCPU_SREG_SS, ctxt->vcpu);
+ ops->set_segment_selector(tss->ds, VCPU_SREG_DS, ctxt->vcpu);
+
+ /*
+ * Now load segment descriptors. If fault happenes at this stage
+ * it is handled in a context of new task
+ */
+ ret = load_segment_descriptor(ctxt, ops, tss->ldt, VCPU_SREG_LDTR);
+ if (ret != X86EMUL_CONTINUE)
+ return ret;
+ ret = load_segment_descriptor(ctxt, ops, tss->es, VCPU_SREG_ES);
+ if (ret != X86EMUL_CONTINUE)
+ return ret;
+ ret = load_segment_descriptor(ctxt, ops, tss->cs, VCPU_SREG_CS);
+ if (ret != X86EMUL_CONTINUE)
+ return ret;
+ ret = load_segment_descriptor(ctxt, ops, tss->ss, VCPU_SREG_SS);
+ if (ret != X86EMUL_CONTINUE)
+ return ret;
+ ret = load_segment_descriptor(ctxt, ops, tss->ds, VCPU_SREG_DS);
+ if (ret != X86EMUL_CONTINUE)
+ return ret;
+
+ return X86EMUL_CONTINUE;
+}
+
+static int task_switch_16(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops,
+ u16 tss_selector, u16 old_tss_sel,
+ ulong old_tss_base, struct desc_struct *new_desc)
+{
+ struct tss_segment_16 tss_seg;
+ int ret;
+ u32 err, new_tss_base = get_desc_base(new_desc);
+
+ ret = ops->read_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu,
+ &err);
+ if (ret == X86EMUL_PROPAGATE_FAULT) {
+ /* FIXME: need to provide precise fault address */
+ kvm_inject_page_fault(ctxt->vcpu, old_tss_base, err);
+ return ret;
+ }
+
+ save_state_to_tss16(ctxt, ops, &tss_seg);
+
+ ret = ops->write_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu,
+ &err);
+ if (ret == X86EMUL_PROPAGATE_FAULT) {
+ /* FIXME: need to provide precise fault address */
+ kvm_inject_page_fault(ctxt->vcpu, old_tss_base, err);
+ return ret;
+ }
+
+ ret = ops->read_std(new_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu,
+ &err);
+ if (ret == X86EMUL_PROPAGATE_FAULT) {
+ /* FIXME: need to provide precise fault address */
+ kvm_inject_page_fault(ctxt->vcpu, new_tss_base, err);
+ return ret;
+ }
+
+ if (old_tss_sel != 0xffff) {
+ tss_seg.prev_task_link = old_tss_sel;
+
+ ret = ops->write_std(new_tss_base,
+ &tss_seg.prev_task_link,
+ sizeof tss_seg.prev_task_link,
+ ctxt->vcpu, &err);
+ if (ret == X86EMUL_PROPAGATE_FAULT) {
+ /* FIXME: need to provide precise fault address */
+ kvm_inject_page_fault(ctxt->vcpu, new_tss_base, err);
+ return ret;
+ }
+ }
+
+ return load_state_from_tss16(ctxt, ops, &tss_seg);
+}
+
+static void save_state_to_tss32(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops,
+ struct tss_segment_32 *tss)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ tss->cr3 = ops->get_cr(3, ctxt->vcpu);
+ tss->eip = c->eip;
+ tss->eflags = ctxt->eflags;
+ tss->eax = c->regs[VCPU_REGS_RAX];
+ tss->ecx = c->regs[VCPU_REGS_RCX];
+ tss->edx = c->regs[VCPU_REGS_RDX];
+ tss->ebx = c->regs[VCPU_REGS_RBX];
+ tss->esp = c->regs[VCPU_REGS_RSP];
+ tss->ebp = c->regs[VCPU_REGS_RBP];
+ tss->esi = c->regs[VCPU_REGS_RSI];
+ tss->edi = c->regs[VCPU_REGS_RDI];
+
+ tss->es = ops->get_segment_selector(VCPU_SREG_ES, ctxt->vcpu);
+ tss->cs = ops->get_segment_selector(VCPU_SREG_CS, ctxt->vcpu);
+ tss->ss = ops->get_segment_selector(VCPU_SREG_SS, ctxt->vcpu);
+ tss->ds = ops->get_segment_selector(VCPU_SREG_DS, ctxt->vcpu);
+ tss->fs = ops->get_segment_selector(VCPU_SREG_FS, ctxt->vcpu);
+ tss->gs = ops->get_segment_selector(VCPU_SREG_GS, ctxt->vcpu);
+ tss->ldt_selector = ops->get_segment_selector(VCPU_SREG_LDTR, ctxt->vcpu);
+}
+
+static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops,
+ struct tss_segment_32 *tss)
+{
+ struct decode_cache *c = &ctxt->decode;
+ int ret;
+
+ ops->set_cr(3, tss->cr3, ctxt->vcpu);
+ c->eip = tss->eip;
+ ctxt->eflags = tss->eflags | 2;
+ c->regs[VCPU_REGS_RAX] = tss->eax;
+ c->regs[VCPU_REGS_RCX] = tss->ecx;
+ c->regs[VCPU_REGS_RDX] = tss->edx;
+ c->regs[VCPU_REGS_RBX] = tss->ebx;
+ c->regs[VCPU_REGS_RSP] = tss->esp;
+ c->regs[VCPU_REGS_RBP] = tss->ebp;
+ c->regs[VCPU_REGS_RSI] = tss->esi;
+ c->regs[VCPU_REGS_RDI] = tss->edi;
+
+ /*
+ * SDM says that segment selectors are loaded before segment
+ * descriptors
+ */
+ ops->set_segment_selector(tss->ldt_selector, VCPU_SREG_LDTR, ctxt->vcpu);
+ ops->set_segment_selector(tss->es, VCPU_SREG_ES, ctxt->vcpu);
+ ops->set_segment_selector(tss->cs, VCPU_SREG_CS, ctxt->vcpu);
+ ops->set_segment_selector(tss->ss, VCPU_SREG_SS, ctxt->vcpu);
+ ops->set_segment_selector(tss->ds, VCPU_SREG_DS, ctxt->vcpu);
+ ops->set_segment_selector(tss->fs, VCPU_SREG_FS, ctxt->vcpu);
+ ops->set_segment_selector(tss->gs, VCPU_SREG_GS, ctxt->vcpu);
+
+ /*
+ * Now load segment descriptors. If fault happenes at this stage
+ * it is handled in a context of new task
+ */
+ ret = load_segment_descriptor(ctxt, ops, tss->ldt_selector, VCPU_SREG_LDTR);
+ if (ret != X86EMUL_CONTINUE)
+ return ret;
+ ret = load_segment_descriptor(ctxt, ops, tss->es, VCPU_SREG_ES);
+ if (ret != X86EMUL_CONTINUE)
+ return ret;
+ ret = load_segment_descriptor(ctxt, ops, tss->cs, VCPU_SREG_CS);
+ if (ret != X86EMUL_CONTINUE)
+ return ret;
+ ret = load_segment_descriptor(ctxt, ops, tss->ss, VCPU_SREG_SS);
+ if (ret != X86EMUL_CONTINUE)
+ return ret;
+ ret = load_segment_descriptor(ctxt, ops, tss->ds, VCPU_SREG_DS);
+ if (ret != X86EMUL_CONTINUE)
+ return ret;
+ ret = load_segment_descriptor(ctxt, ops, tss->fs, VCPU_SREG_FS);
+ if (ret != X86EMUL_CONTINUE)
+ return ret;
+ ret = load_segment_descriptor(ctxt, ops, tss->gs, VCPU_SREG_GS);
+ if (ret != X86EMUL_CONTINUE)
+ return ret;
+
+ return X86EMUL_CONTINUE;
+}
+
+static int task_switch_32(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops,
+ u16 tss_selector, u16 old_tss_sel,
+ ulong old_tss_base, struct desc_struct *new_desc)
+{
+ struct tss_segment_32 tss_seg;
+ int ret;
+ u32 err, new_tss_base = get_desc_base(new_desc);
+
+ ret = ops->read_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu,
+ &err);
+ if (ret == X86EMUL_PROPAGATE_FAULT) {
+ /* FIXME: need to provide precise fault address */
+ kvm_inject_page_fault(ctxt->vcpu, old_tss_base, err);
+ return ret;
+ }
+
+ save_state_to_tss32(ctxt, ops, &tss_seg);
+
+ ret = ops->write_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu,
+ &err);
+ if (ret == X86EMUL_PROPAGATE_FAULT) {
+ /* FIXME: need to provide precise fault address */
+ kvm_inject_page_fault(ctxt->vcpu, old_tss_base, err);
+ return ret;
+ }
+
+ ret = ops->read_std(new_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu,
+ &err);
+ if (ret == X86EMUL_PROPAGATE_FAULT) {
+ /* FIXME: need to provide precise fault address */
+ kvm_inject_page_fault(ctxt->vcpu, new_tss_base, err);
+ return ret;
+ }
+
+ if (old_tss_sel != 0xffff) {
+ tss_seg.prev_task_link = old_tss_sel;
+
+ ret = ops->write_std(new_tss_base,
+ &tss_seg.prev_task_link,
+ sizeof tss_seg.prev_task_link,
+ ctxt->vcpu, &err);
+ if (ret == X86EMUL_PROPAGATE_FAULT) {
+ /* FIXME: need to provide precise fault address */
+ kvm_inject_page_fault(ctxt->vcpu, new_tss_base, err);
+ return ret;
+ }
+ }
+
+ return load_state_from_tss32(ctxt, ops, &tss_seg);
+}
+
+static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops,
+ u16 tss_selector, int reason)
+{
+ struct desc_struct curr_tss_desc, next_tss_desc;
+ int ret;
+ u16 old_tss_sel = ops->get_segment_selector(VCPU_SREG_TR, ctxt->vcpu);
+ ulong old_tss_base =
+ get_cached_descriptor_base(ctxt, ops, VCPU_SREG_TR);
+
+ /* FIXME: old_tss_base == ~0 ? */
+
+ ret = read_segment_descriptor(ctxt, ops, tss_selector, &next_tss_desc);
+ if (ret != X86EMUL_CONTINUE)
+ return ret;
+ ret = read_segment_descriptor(ctxt, ops, old_tss_sel, &curr_tss_desc);
+ if (ret != X86EMUL_CONTINUE)
+ return ret;
+
+ /* FIXME: check that next_tss_desc is tss */
+
+ if (reason != TASK_SWITCH_IRET) {
+ if ((tss_selector & 3) > next_tss_desc.dpl ||
+ ops->cpl(ctxt->vcpu) > next_tss_desc.dpl) {
+ kvm_inject_gp(ctxt->vcpu, 0);
+ return X86EMUL_PROPAGATE_FAULT;
+ }
+ }
+
+ if (!next_tss_desc.p || desc_limit_scaled(&next_tss_desc) < 0x67) {
+ kvm_queue_exception_e(ctxt->vcpu, TS_VECTOR,
+ tss_selector & 0xfffc);
+ return X86EMUL_PROPAGATE_FAULT;
+ }
+
+ if (reason == TASK_SWITCH_IRET || reason == TASK_SWITCH_JMP) {
+ curr_tss_desc.type &= ~(1 << 1); /* clear busy flag */
+ write_segment_descriptor(ctxt, ops, old_tss_sel,
+ &curr_tss_desc);
+ }
+
+ if (reason == TASK_SWITCH_IRET)
+ ctxt->eflags = ctxt->eflags & ~X86_EFLAGS_NT;
+
+ /* set back link to prev task only if NT bit is set in eflags
+ note that old_tss_sel is not used afetr this point */
+ if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE)
+ old_tss_sel = 0xffff;
+
+ if (next_tss_desc.type & 8)
+ ret = task_switch_32(ctxt, ops, tss_selector, old_tss_sel,
+ old_tss_base, &next_tss_desc);
+ else
+ ret = task_switch_16(ctxt, ops, tss_selector, old_tss_sel,
+ old_tss_base, &next_tss_desc);
+
+ if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE)
+ ctxt->eflags = ctxt->eflags | X86_EFLAGS_NT;
+
+ if (reason != TASK_SWITCH_IRET) {
+ next_tss_desc.type |= (1 << 1); /* set busy flag */
+ write_segment_descriptor(ctxt, ops, tss_selector,
+ &next_tss_desc);
+ }
+
+ ops->set_cr(0, ops->get_cr(0, ctxt->vcpu) | X86_CR0_TS, ctxt->vcpu);
+ ops->set_cached_descriptor(&next_tss_desc, VCPU_SREG_TR, ctxt->vcpu);
+ ops->set_segment_selector(tss_selector, VCPU_SREG_TR, ctxt->vcpu);
+
+ return ret;
+}
+
+int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops,
+ u16 tss_selector, int reason)
+{
+ struct decode_cache *c = &ctxt->decode;
+ int rc;
+
+ memset(c, 0, sizeof(struct decode_cache));
+ c->eip = ctxt->eip;
+ memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
+
+ rc = emulator_do_task_switch(ctxt, ops, tss_selector, reason);
+
+ if (rc == X86EMUL_CONTINUE) {
+ memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs);
+ kvm_rip_write(ctxt->vcpu, c->eip);
+ }
+
+ return rc;
+}
+
int
x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
{
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 20/30] KVM: x86 emulator: Use load_segment_descriptor() instead of kvm_load_segment_descriptor()
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (18 preceding siblings ...)
2010-03-14 16:21 ` [PATCH v2 19/30] KVM: x86 emulator: Emulate task switch in emulator.c Gleb Natapov
@ 2010-03-14 16:21 ` Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 21/30] KVM: Use task switch from emulator.c Gleb Natapov
` (9 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:21 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/emulate.c | 10 +++++-----
1 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index cc1bb20..40370b2 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1509,7 +1509,7 @@ static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt,
if (rc != X86EMUL_CONTINUE)
return rc;
- rc = kvm_load_segment_descriptor(ctxt->vcpu, (u16)selector, seg);
+ rc = load_segment_descriptor(ctxt, ops, (u16)selector, seg);
return rc;
}
@@ -1684,7 +1684,7 @@ static int emulate_ret_far(struct x86_emulate_ctxt *ctxt,
rc = emulate_pop(ctxt, ops, &cs, c->op_bytes);
if (rc != X86EMUL_CONTINUE)
return rc;
- rc = kvm_load_segment_descriptor(ctxt->vcpu, (u16)cs, VCPU_SREG_CS);
+ rc = load_segment_descriptor(ctxt, ops, (u16)cs, VCPU_SREG_CS);
return rc;
}
@@ -2718,7 +2718,7 @@ special_insn:
if (c->modrm_reg == VCPU_SREG_SS)
toggle_interruptibility(ctxt, KVM_X86_SHADOW_INT_MOV_SS);
- rc = kvm_load_segment_descriptor(ctxt->vcpu, sel, c->modrm_reg);
+ rc = load_segment_descriptor(ctxt, ops, sel, c->modrm_reg);
c->dst.type = OP_NONE; /* Disable writeback. */
break;
@@ -2893,8 +2893,8 @@ special_insn:
goto jmp;
case 0xea: /* jmp far */
jump_far:
- if (kvm_load_segment_descriptor(ctxt->vcpu, c->src2.val,
- VCPU_SREG_CS))
+ if (load_segment_descriptor(ctxt, ops, c->src2.val,
+ VCPU_SREG_CS))
goto done;
c->eip = c->src.val;
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 21/30] KVM: Use task switch from emulator.c
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (19 preceding siblings ...)
2010-03-14 16:21 ` [PATCH v2 20/30] KVM: x86 emulator: Use load_segment_descriptor() instead of kvm_load_segment_descriptor() Gleb Natapov
@ 2010-03-14 16:21 ` Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 22/30] KVM: x86 emulator: populate OP_MEM operand during decoding Gleb Natapov
` (8 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:21 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Remove old task switch code from x86.c
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/x86.c | 557 ++--------------------------------------------------
1 files changed, 17 insertions(+), 540 deletions(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index c30e81d..3c5ffa2 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4779,553 +4779,30 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
return 0;
}
-static void seg_desct_to_kvm_desct(struct desc_struct *seg_desc, u16 selector,
- struct kvm_segment *kvm_desct)
-{
- kvm_desct->base = get_desc_base(seg_desc);
- kvm_desct->limit = get_desc_limit(seg_desc);
- if (seg_desc->g) {
- kvm_desct->limit <<= 12;
- kvm_desct->limit |= 0xfff;
- }
- kvm_desct->selector = selector;
- kvm_desct->type = seg_desc->type;
- kvm_desct->present = seg_desc->p;
- kvm_desct->dpl = seg_desc->dpl;
- kvm_desct->db = seg_desc->d;
- kvm_desct->s = seg_desc->s;
- kvm_desct->l = seg_desc->l;
- kvm_desct->g = seg_desc->g;
- kvm_desct->avl = seg_desc->avl;
- if (!selector)
- kvm_desct->unusable = 1;
- else
- kvm_desct->unusable = 0;
- kvm_desct->padding = 0;
-}
-
-static void get_segment_descriptor_dtable(struct kvm_vcpu *vcpu,
- u16 selector,
- struct desc_ptr *dtable)
-{
- if (selector & 1 << 2) {
- struct kvm_segment kvm_seg;
-
- kvm_get_segment(vcpu, &kvm_seg, VCPU_SREG_LDTR);
-
- if (kvm_seg.unusable)
- dtable->size = 0;
- else
- dtable->size = kvm_seg.limit;
- dtable->address = kvm_seg.base;
- }
- else
- kvm_x86_ops->get_gdt(vcpu, dtable);
-}
-
-/* allowed just for 8 bytes segments */
-static int load_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
- struct desc_struct *seg_desc)
-{
- struct desc_ptr dtable;
- u16 index = selector >> 3;
- int ret;
- u32 err;
- gva_t addr;
-
- get_segment_descriptor_dtable(vcpu, selector, &dtable);
-
- if (dtable.size < index * 8 + 7) {
- kvm_queue_exception_e(vcpu, GP_VECTOR, selector & 0xfffc);
- return X86EMUL_PROPAGATE_FAULT;
- }
- addr = dtable.address + 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 */
-static int save_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
- struct desc_struct *seg_desc)
-{
- struct desc_ptr dtable;
- u16 index = selector >> 3;
-
- get_segment_descriptor_dtable(vcpu, selector, &dtable);
-
- if (dtable.size < index * 8 + 7)
- return 1;
- return kvm_write_guest_virt(dtable.address + 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_read(struct kvm_vcpu *vcpu,
- struct desc_struct *seg_desc)
-{
- u32 base_addr = get_desc_base(seg_desc);
-
- return kvm_mmu_gva_to_gpa_read(vcpu, base_addr, NULL);
-}
-
-static u16 get_segment_selector(struct kvm_vcpu *vcpu, int seg)
-{
- struct kvm_segment kvm_seg;
-
- kvm_get_segment(vcpu, &kvm_seg, seg);
- return kvm_seg.selector;
-}
-
-static int kvm_load_realmode_segment(struct kvm_vcpu *vcpu, u16 selector, int seg)
-{
- struct kvm_segment segvar = {
- .base = selector << 4,
- .limit = 0xffff,
- .selector = selector,
- .type = 3,
- .present = 1,
- .dpl = 3,
- .db = 0,
- .s = 1,
- .l = 0,
- .g = 0,
- .avl = 0,
- .unusable = 0,
- };
- kvm_x86_ops->set_segment(vcpu, &segvar, seg);
- return X86EMUL_CONTINUE;
-}
-
-static int is_vm86_segment(struct kvm_vcpu *vcpu, int seg)
-{
- return (seg != VCPU_SREG_LDTR) &&
- (seg != VCPU_SREG_TR) &&
- (kvm_get_rflags(vcpu) & X86_EFLAGS_VM);
-}
-
-int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int 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) || !is_protmode(vcpu))
- return kvm_load_realmode_segment(vcpu, selector, seg);
-
- /* 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);
- 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,
- struct tss_segment_32 *tss)
-{
- tss->cr3 = vcpu->arch.cr3;
- tss->eip = kvm_rip_read(vcpu);
- tss->eflags = kvm_get_rflags(vcpu);
- tss->eax = kvm_register_read(vcpu, VCPU_REGS_RAX);
- tss->ecx = kvm_register_read(vcpu, VCPU_REGS_RCX);
- tss->edx = kvm_register_read(vcpu, VCPU_REGS_RDX);
- tss->ebx = kvm_register_read(vcpu, VCPU_REGS_RBX);
- tss->esp = kvm_register_read(vcpu, VCPU_REGS_RSP);
- tss->ebp = kvm_register_read(vcpu, VCPU_REGS_RBP);
- tss->esi = kvm_register_read(vcpu, VCPU_REGS_RSI);
- tss->edi = kvm_register_read(vcpu, VCPU_REGS_RDI);
- tss->es = get_segment_selector(vcpu, VCPU_SREG_ES);
- tss->cs = get_segment_selector(vcpu, VCPU_SREG_CS);
- tss->ss = get_segment_selector(vcpu, VCPU_SREG_SS);
- tss->ds = get_segment_selector(vcpu, VCPU_SREG_DS);
- tss->fs = get_segment_selector(vcpu, VCPU_SREG_FS);
- tss->gs = get_segment_selector(vcpu, VCPU_SREG_GS);
- 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,
- struct tss_segment_32 *tss)
-{
- kvm_set_cr3(vcpu, tss->cr3);
-
- kvm_rip_write(vcpu, tss->eip);
- kvm_set_rflags(vcpu, tss->eflags | 2);
-
- kvm_register_write(vcpu, VCPU_REGS_RAX, tss->eax);
- kvm_register_write(vcpu, VCPU_REGS_RCX, tss->ecx);
- kvm_register_write(vcpu, VCPU_REGS_RDX, tss->edx);
- kvm_register_write(vcpu, VCPU_REGS_RBX, tss->ebx);
- kvm_register_write(vcpu, VCPU_REGS_RSP, tss->esp);
- kvm_register_write(vcpu, VCPU_REGS_RBP, tss->ebp);
- kvm_register_write(vcpu, VCPU_REGS_RSI, tss->esi);
- kvm_register_write(vcpu, VCPU_REGS_RDI, tss->edi);
-
- /*
- * 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;
-
- if (kvm_load_segment_descriptor(vcpu, tss->es, VCPU_SREG_ES))
- return 1;
-
- if (kvm_load_segment_descriptor(vcpu, tss->cs, VCPU_SREG_CS))
- return 1;
-
- if (kvm_load_segment_descriptor(vcpu, tss->ss, VCPU_SREG_SS))
- return 1;
-
- if (kvm_load_segment_descriptor(vcpu, tss->ds, VCPU_SREG_DS))
- return 1;
-
- if (kvm_load_segment_descriptor(vcpu, tss->fs, VCPU_SREG_FS))
- return 1;
-
- if (kvm_load_segment_descriptor(vcpu, tss->gs, VCPU_SREG_GS))
- return 1;
- return 0;
-}
-
-static void save_state_to_tss16(struct kvm_vcpu *vcpu,
- struct tss_segment_16 *tss)
-{
- tss->ip = kvm_rip_read(vcpu);
- tss->flag = kvm_get_rflags(vcpu);
- tss->ax = kvm_register_read(vcpu, VCPU_REGS_RAX);
- tss->cx = kvm_register_read(vcpu, VCPU_REGS_RCX);
- tss->dx = kvm_register_read(vcpu, VCPU_REGS_RDX);
- tss->bx = kvm_register_read(vcpu, VCPU_REGS_RBX);
- tss->sp = kvm_register_read(vcpu, VCPU_REGS_RSP);
- tss->bp = kvm_register_read(vcpu, VCPU_REGS_RBP);
- tss->si = kvm_register_read(vcpu, VCPU_REGS_RSI);
- tss->di = kvm_register_read(vcpu, VCPU_REGS_RDI);
-
- tss->es = get_segment_selector(vcpu, VCPU_SREG_ES);
- tss->cs = get_segment_selector(vcpu, VCPU_SREG_CS);
- tss->ss = get_segment_selector(vcpu, VCPU_SREG_SS);
- tss->ds = get_segment_selector(vcpu, VCPU_SREG_DS);
- tss->ldt = get_segment_selector(vcpu, VCPU_SREG_LDTR);
-}
-
-static int load_state_from_tss16(struct kvm_vcpu *vcpu,
- struct tss_segment_16 *tss)
-{
- kvm_rip_write(vcpu, tss->ip);
- kvm_set_rflags(vcpu, tss->flag | 2);
- kvm_register_write(vcpu, VCPU_REGS_RAX, tss->ax);
- kvm_register_write(vcpu, VCPU_REGS_RCX, tss->cx);
- kvm_register_write(vcpu, VCPU_REGS_RDX, tss->dx);
- kvm_register_write(vcpu, VCPU_REGS_RBX, tss->bx);
- kvm_register_write(vcpu, VCPU_REGS_RSP, tss->sp);
- kvm_register_write(vcpu, VCPU_REGS_RBP, tss->bp);
- kvm_register_write(vcpu, VCPU_REGS_RSI, tss->si);
- kvm_register_write(vcpu, VCPU_REGS_RDI, tss->di);
-
- /*
- * 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;
-
- if (kvm_load_segment_descriptor(vcpu, tss->es, VCPU_SREG_ES))
- return 1;
-
- if (kvm_load_segment_descriptor(vcpu, tss->cs, VCPU_SREG_CS))
- return 1;
-
- if (kvm_load_segment_descriptor(vcpu, tss->ss, VCPU_SREG_SS))
- return 1;
-
- if (kvm_load_segment_descriptor(vcpu, tss->ds, VCPU_SREG_DS))
- return 1;
- return 0;
-}
-
-static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
- u16 old_tss_sel, u32 old_tss_base,
- struct desc_struct *nseg_desc)
-{
- struct tss_segment_16 tss_segment_16;
- int ret = 0;
-
- if (kvm_read_guest(vcpu->kvm, old_tss_base, &tss_segment_16,
- sizeof tss_segment_16))
- goto out;
-
- save_state_to_tss16(vcpu, &tss_segment_16);
-
- if (kvm_write_guest(vcpu->kvm, old_tss_base, &tss_segment_16,
- sizeof tss_segment_16))
- goto out;
-
- if (kvm_read_guest(vcpu->kvm, get_tss_base_addr_read(vcpu, nseg_desc),
- &tss_segment_16, sizeof tss_segment_16))
- goto out;
-
- if (old_tss_sel != 0xffff) {
- tss_segment_16.prev_task_link = old_tss_sel;
-
- if (kvm_write_guest(vcpu->kvm,
- get_tss_base_addr_write(vcpu, nseg_desc),
- &tss_segment_16.prev_task_link,
- sizeof tss_segment_16.prev_task_link))
- goto out;
- }
-
- if (load_state_from_tss16(vcpu, &tss_segment_16))
- goto out;
-
- ret = 1;
-out:
- return ret;
-}
-
-static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
- u16 old_tss_sel, u32 old_tss_base,
- struct desc_struct *nseg_desc)
-{
- struct tss_segment_32 tss_segment_32;
- int ret = 0;
-
- if (kvm_read_guest(vcpu->kvm, old_tss_base, &tss_segment_32,
- sizeof tss_segment_32))
- goto out;
-
- save_state_to_tss32(vcpu, &tss_segment_32);
-
- if (kvm_write_guest(vcpu->kvm, old_tss_base, &tss_segment_32,
- sizeof tss_segment_32))
- goto out;
-
- if (kvm_read_guest(vcpu->kvm, get_tss_base_addr_read(vcpu, nseg_desc),
- &tss_segment_32, sizeof tss_segment_32))
- goto out;
-
- if (old_tss_sel != 0xffff) {
- tss_segment_32.prev_task_link = old_tss_sel;
-
- if (kvm_write_guest(vcpu->kvm,
- get_tss_base_addr_write(vcpu, nseg_desc),
- &tss_segment_32.prev_task_link,
- sizeof tss_segment_32.prev_task_link))
- goto out;
- }
-
- if (load_state_from_tss32(vcpu, &tss_segment_32))
- goto out;
-
- ret = 1;
-out:
- return ret;
-}
-
int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
{
- struct kvm_segment tr_seg;
- struct desc_struct cseg_desc;
- struct desc_struct nseg_desc;
- int ret = 0;
- u32 old_tss_base = get_segment_base(vcpu, VCPU_SREG_TR);
- u16 old_tss_sel = get_segment_selector(vcpu, VCPU_SREG_TR);
-
- old_tss_base = kvm_mmu_gva_to_gpa_write(vcpu, old_tss_base, NULL);
-
- /* FIXME: Handle errors. Failure to read either TSS or their
- * descriptors should generate a pagefault.
- */
- if (load_guest_segment_descriptor(vcpu, tss_selector, &nseg_desc))
- goto out;
-
- if (load_guest_segment_descriptor(vcpu, old_tss_sel, &cseg_desc))
- goto out;
-
- if (reason != TASK_SWITCH_IRET) {
- int cpl;
-
- cpl = kvm_x86_ops->get_cpl(vcpu);
- if ((tss_selector & 3) > nseg_desc.dpl || cpl > nseg_desc.dpl) {
- kvm_queue_exception_e(vcpu, GP_VECTOR, 0);
- return 1;
- }
- }
-
- if (!nseg_desc.p || get_desc_limit(&nseg_desc) < 0x67) {
- kvm_queue_exception_e(vcpu, TS_VECTOR, tss_selector & 0xfffc);
- return 1;
- }
-
- if (reason == TASK_SWITCH_IRET || reason == TASK_SWITCH_JMP) {
- cseg_desc.type &= ~(1 << 1); //clear the B flag
- save_guest_segment_descriptor(vcpu, old_tss_sel, &cseg_desc);
- }
-
- if (reason == TASK_SWITCH_IRET) {
- u32 eflags = kvm_get_rflags(vcpu);
- kvm_set_rflags(vcpu, eflags & ~X86_EFLAGS_NT);
- }
+ int cs_db, cs_l, ret;
+ cache_all_regs(vcpu);
- /* set back link to prev task only if NT bit is set in eflags
- note that old_tss_sel is not used afetr this point */
- if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE)
- old_tss_sel = 0xffff;
+ kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
- if (nseg_desc.type & 8)
- ret = kvm_task_switch_32(vcpu, tss_selector, old_tss_sel,
- old_tss_base, &nseg_desc);
- else
- ret = kvm_task_switch_16(vcpu, tss_selector, old_tss_sel,
- old_tss_base, &nseg_desc);
+ vcpu->arch.emulate_ctxt.vcpu = vcpu;
+ vcpu->arch.emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu);
+ vcpu->arch.emulate_ctxt.eip = kvm_rip_read(vcpu);
+ vcpu->arch.emulate_ctxt.mode =
+ (!is_protmode(vcpu)) ? X86EMUL_MODE_REAL :
+ (vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM)
+ ? X86EMUL_MODE_VM86 : cs_l
+ ? X86EMUL_MODE_PROT64 : cs_db
+ ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
- if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) {
- u32 eflags = kvm_get_rflags(vcpu);
- kvm_set_rflags(vcpu, eflags | X86_EFLAGS_NT);
- }
+ ret = emulator_task_switch(&vcpu->arch.emulate_ctxt, &emulate_ops,
+ tss_selector, reason);
- if (reason != TASK_SWITCH_IRET) {
- nseg_desc.type |= (1 << 1);
- save_guest_segment_descriptor(vcpu, tss_selector,
- &nseg_desc);
- }
+ if (ret == X86EMUL_CONTINUE)
+ kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
- kvm_x86_ops->set_cr0(vcpu, kvm_read_cr0(vcpu) | X86_CR0_TS);
- seg_desct_to_kvm_desct(&nseg_desc, tss_selector, &tr_seg);
- tr_seg.type = 11;
- kvm_set_segment(vcpu, &tr_seg, VCPU_SREG_TR);
-out:
- return ret;
+ return (ret != X86EMUL_CONTINUE);
}
EXPORT_SYMBOL_GPL(kvm_task_switch);
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 22/30] KVM: x86 emulator: populate OP_MEM operand during decoding.
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (20 preceding siblings ...)
2010-03-14 16:21 ` [PATCH v2 21/30] KVM: Use task switch from emulator.c Gleb Natapov
@ 2010-03-14 16:21 ` Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 23/30] KVM: x86 emulator: add decoding of X,Y parameters from Intel SDM Gleb Natapov
` (7 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:21 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
All struct operand fields are initialized during decoding for all
operand types except OP_MEM, but there is no reason for that. Move
OP_MEM operand initialization into decoding stage for consistency.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/emulate.c | 62 ++++++++++++++++++++++-------------------------
1 files changed, 29 insertions(+), 33 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 40370b2..d283fe8 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1057,6 +1057,10 @@ done_prefixes:
if (c->ad_bytes != 8)
c->modrm_ea = (u32)c->modrm_ea;
+
+ if (c->rip_relative)
+ c->modrm_ea += c->eip;
+
/*
* Decode and fetch the source operand: register, memory
* or immediate.
@@ -1091,6 +1095,8 @@ done_prefixes:
break;
}
c->src.type = OP_MEM;
+ c->src.ptr = (unsigned long *)c->modrm_ea;
+ c->src.val = 0;
break;
case SrcImm:
case SrcImmU:
@@ -1169,8 +1175,10 @@ done_prefixes:
c->src2.val = 1;
break;
case Src2Mem16:
- c->src2.bytes = 2;
c->src2.type = OP_MEM;
+ c->src2.bytes = 2;
+ c->src2.ptr = (unsigned long *)(c->modrm_ea + c->src.bytes);
+ c->src2.val = 0;
break;
}
@@ -1192,6 +1200,15 @@ done_prefixes:
break;
}
c->dst.type = OP_MEM;
+ c->dst.ptr = (unsigned long *)c->modrm_ea;
+ c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+ c->dst.val = 0;
+ if (c->d & BitOp) {
+ unsigned long mask = ~(c->dst.bytes * 8 - 1);
+
+ c->dst.ptr = (void *)c->dst.ptr +
+ (c->src.val & mask) / 8;
+ }
break;
case DstAcc:
c->dst.type = OP_REG;
@@ -1215,9 +1232,6 @@ done_prefixes:
break;
}
- if (c->rip_relative)
- c->modrm_ea += c->eip;
-
done:
return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
}
@@ -1639,14 +1653,13 @@ static inline int emulate_grp45(struct x86_emulate_ctxt *ctxt,
}
static inline int emulate_grp9(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops,
- unsigned long memop)
+ struct x86_emulate_ops *ops)
{
struct decode_cache *c = &ctxt->decode;
u64 old, new;
int rc;
- rc = ops->read_emulated(memop, &old, 8, ctxt->vcpu);
+ rc = ops->read_emulated(c->modrm_ea, &old, 8, ctxt->vcpu);
if (rc != X86EMUL_CONTINUE)
return rc;
@@ -1661,7 +1674,7 @@ static inline int emulate_grp9(struct x86_emulate_ctxt *ctxt,
new = ((u64)c->regs[VCPU_REGS_RCX] << 32) |
(u32) c->regs[VCPU_REGS_RBX];
- rc = ops->cmpxchg_emulated(memop, &old, &new, 8, ctxt->vcpu);
+ rc = ops->cmpxchg_emulated(c->modrm_ea, &old, &new, 8, ctxt->vcpu);
if (rc != X86EMUL_CONTINUE)
return rc;
ctxt->eflags |= EFLG_ZF;
@@ -2448,8 +2461,6 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
}
if (c->src.type == OP_MEM) {
- c->src.ptr = (unsigned long *)memop;
- c->src.val = 0;
rc = ops->read_emulated((unsigned long)c->src.ptr,
&c->src.val,
c->src.bytes,
@@ -2460,8 +2471,6 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
}
if (c->src2.type == OP_MEM) {
- c->src2.ptr = (unsigned long *)(memop + c->src.bytes);
- c->src2.val = 0;
rc = ops->read_emulated((unsigned long)c->src2.ptr,
&c->src2.val,
c->src2.bytes,
@@ -2474,25 +2483,12 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
goto special_insn;
- if (c->dst.type == OP_MEM) {
- c->dst.ptr = (unsigned long *)memop;
- c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
- c->dst.val = 0;
- if (c->d & BitOp) {
- unsigned long mask = ~(c->dst.bytes * 8 - 1);
-
- c->dst.ptr = (void *)c->dst.ptr +
- (c->src.val & mask) / 8;
- }
- if (!(c->d & Mov)) {
- /* optimisation - avoid slow emulated read */
- rc = ops->read_emulated((unsigned long)c->dst.ptr,
- &c->dst.val,
- c->dst.bytes,
- ctxt->vcpu);
- if (rc != X86EMUL_CONTINUE)
- goto done;
- }
+ if ((c->dst.type == OP_MEM) && !(c->d & Mov)) {
+ /* optimisation - avoid slow emulated read if Mov */
+ rc = ops->read_emulated((unsigned long)c->dst.ptr, &c->dst.val,
+ c->dst.bytes, ctxt->vcpu);
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
}
c->dst.orig_val = c->dst.val;
@@ -3059,7 +3055,7 @@ twobyte_insn:
kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
goto done;
case 7: /* invlpg*/
- emulate_invlpg(ctxt->vcpu, memop);
+ emulate_invlpg(ctxt->vcpu, c->modrm_ea);
/* Disable writeback. */
c->dst.type = OP_NONE;
break;
@@ -3260,7 +3256,7 @@ twobyte_insn:
(u64) c->src.val;
break;
case 0xc7: /* Grp9 (cmpxchg8b) */
- rc = emulate_grp9(ctxt, ops, memop);
+ rc = emulate_grp9(ctxt, ops);
if (rc != X86EMUL_CONTINUE)
goto done;
c->dst.type = OP_NONE;
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 23/30] KVM: x86 emulator: add decoding of X,Y parameters from Intel SDM
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (21 preceding siblings ...)
2010-03-14 16:21 ` [PATCH v2 22/30] KVM: x86 emulator: populate OP_MEM operand during decoding Gleb Natapov
@ 2010-03-14 16:21 ` Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 24/30] KVM: x86 emulator: during rep emulation decrement ECX only if emulation succeeded Gleb Natapov
` (6 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:21 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Add decoding of X,Y parameters from Intel SDM which are used by string
instruction to specify source and destination. Use this new decoding
to implement movs, cmps, stos, lods in a generic way.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/emulate.c | 125 +++++++++++++++++-------------------------------
1 files changed, 44 insertions(+), 81 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index d283fe8..12c630c 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -51,6 +51,7 @@
#define DstReg (2<<1) /* Register operand. */
#define DstMem (3<<1) /* Memory operand. */
#define DstAcc (4<<1) /* Destination Accumulator */
+#define DstDI (5<<1) /* Destination is in ES:(E)DI */
#define DstMask (7<<1)
/* Source operand type. */
#define SrcNone (0<<4) /* No source operand. */
@@ -64,6 +65,7 @@
#define SrcOne (7<<4) /* Implied '1' */
#define SrcImmUByte (8<<4) /* 8-bit unsigned immediate operand. */
#define SrcImmU (9<<4) /* Immediate operand, unsigned */
+#define SrcSI (0xa<<4) /* Source is in the DS:RSI */
#define SrcMask (0xf<<4)
/* Generic ModRM decode. */
#define ModRM (1<<8)
@@ -177,12 +179,12 @@ static u32 opcode_table[256] = {
/* 0xA0 - 0xA7 */
ByteOp | DstReg | SrcMem | Mov | MemAbs, DstReg | SrcMem | Mov | MemAbs,
ByteOp | DstMem | SrcReg | Mov | MemAbs, DstMem | SrcReg | Mov | MemAbs,
- ByteOp | ImplicitOps | Mov | String, ImplicitOps | Mov | String,
- ByteOp | ImplicitOps | String, ImplicitOps | String,
+ ByteOp | SrcSI | DstDI | Mov | String, SrcSI | DstDI | Mov | String,
+ ByteOp | SrcSI | DstDI | String, SrcSI | DstDI | String,
/* 0xA8 - 0xAF */
- 0, 0, ByteOp | ImplicitOps | Mov | String, ImplicitOps | Mov | String,
- ByteOp | ImplicitOps | Mov | String, ImplicitOps | Mov | String,
- ByteOp | ImplicitOps | String, ImplicitOps | String,
+ 0, 0, ByteOp | DstDI | Mov | String, DstDI | Mov | String,
+ ByteOp | SrcSI | DstAcc | Mov | String, SrcSI | DstAcc | Mov | String,
+ ByteOp | DstDI | String, DstDI | String,
/* 0xB0 - 0xB7 */
ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov,
ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov,
@@ -1145,6 +1147,14 @@ done_prefixes:
c->src.bytes = 1;
c->src.val = 1;
break;
+ case SrcSI:
+ c->src.type = OP_MEM;
+ c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+ c->src.ptr = (unsigned long *)
+ register_address(c, seg_override_base(ctxt, c),
+ c->regs[VCPU_REGS_RSI]);
+ c->src.val = 0;
+ break;
}
/*
@@ -1230,6 +1240,14 @@ done_prefixes:
}
c->dst.orig_val = c->dst.val;
break;
+ case DstDI:
+ c->dst.type = OP_MEM;
+ c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+ c->dst.ptr = (unsigned long *)
+ register_address(c, es_base(ctxt),
+ c->regs[VCPU_REGS_RDI]);
+ c->dst.val = 0;
+ break;
}
done:
@@ -2755,89 +2773,16 @@ special_insn:
c->dst.val = (unsigned long)c->regs[VCPU_REGS_RAX];
break;
case 0xa4 ... 0xa5: /* movs */
- c->dst.type = OP_MEM;
- c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
- c->dst.ptr = (unsigned long *)register_address(c,
- es_base(ctxt),
- c->regs[VCPU_REGS_RDI]);
- rc = ops->read_emulated(register_address(c,
- seg_override_base(ctxt, c),
- c->regs[VCPU_REGS_RSI]),
- &c->dst.val,
- c->dst.bytes, ctxt->vcpu);
- if (rc != X86EMUL_CONTINUE)
- goto done;
- register_address_increment(c, &c->regs[VCPU_REGS_RSI],
- (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
- : c->dst.bytes);
- register_address_increment(c, &c->regs[VCPU_REGS_RDI],
- (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
- : c->dst.bytes);
- break;
+ goto mov;
case 0xa6 ... 0xa7: /* cmps */
- c->src.type = OP_NONE; /* Disable writeback. */
- c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
- c->src.ptr = (unsigned long *)register_address(c,
- seg_override_base(ctxt, c),
- c->regs[VCPU_REGS_RSI]);
- rc = ops->read_emulated((unsigned long)c->src.ptr,
- &c->src.val,
- c->src.bytes,
- ctxt->vcpu);
- if (rc != X86EMUL_CONTINUE)
- goto done;
-
c->dst.type = OP_NONE; /* Disable writeback. */
- c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
- c->dst.ptr = (unsigned long *)register_address(c,
- es_base(ctxt),
- c->regs[VCPU_REGS_RDI]);
- rc = ops->read_emulated((unsigned long)c->dst.ptr,
- &c->dst.val,
- c->dst.bytes,
- ctxt->vcpu);
- if (rc != X86EMUL_CONTINUE)
- goto done;
-
DPRINTF("cmps: mem1=0x%p mem2=0x%p\n", c->src.ptr, c->dst.ptr);
-
- emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags);
-
- register_address_increment(c, &c->regs[VCPU_REGS_RSI],
- (ctxt->eflags & EFLG_DF) ? -c->src.bytes
- : c->src.bytes);
- register_address_increment(c, &c->regs[VCPU_REGS_RDI],
- (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
- : c->dst.bytes);
-
- break;
+ goto cmp;
case 0xaa ... 0xab: /* stos */
- c->dst.type = OP_MEM;
- c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
- c->dst.ptr = (unsigned long *)register_address(c,
- es_base(ctxt),
- c->regs[VCPU_REGS_RDI]);
c->dst.val = c->regs[VCPU_REGS_RAX];
- register_address_increment(c, &c->regs[VCPU_REGS_RDI],
- (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
- : c->dst.bytes);
break;
case 0xac ... 0xad: /* lods */
- c->dst.type = OP_REG;
- c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
- c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
- rc = ops->read_emulated(register_address(c,
- seg_override_base(ctxt, c),
- c->regs[VCPU_REGS_RSI]),
- &c->dst.val,
- c->dst.bytes,
- ctxt->vcpu);
- if (rc != X86EMUL_CONTINUE)
- goto done;
- register_address_increment(c, &c->regs[VCPU_REGS_RSI],
- (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
- : c->dst.bytes);
- break;
+ goto mov;
case 0xae ... 0xaf: /* scas */
DPRINTF("Urk! I don't handle SCAS.\n");
goto cannot_emulate;
@@ -2980,6 +2925,24 @@ writeback:
if (rc != X86EMUL_CONTINUE)
goto done;
+ if ((c->d & SrcMask) == SrcSI) {
+ register_address_increment(c, &c->regs[VCPU_REGS_RSI],
+ (ctxt->eflags & EFLG_DF) ?
+ -c->src.bytes : c->src.bytes);
+ c->src.ptr = (unsigned long *)
+ register_address(c, seg_override_base(ctxt, c),
+ c->regs[VCPU_REGS_RSI]);
+ }
+
+ if ((c->d & DstMask) == DstDI) {
+ register_address_increment(c, &c->regs[VCPU_REGS_RDI],
+ (ctxt->eflags & EFLG_DF) ?
+ -c->dst.bytes : c->dst.bytes);
+ c->dst.ptr = (unsigned long *)
+ register_address(c, es_base(ctxt),
+ c->regs[VCPU_REGS_RDI]);
+ }
+
/* Commit shadow register state. */
memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs);
kvm_rip_write(ctxt->vcpu, c->eip);
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 24/30] KVM: x86 emulator: during rep emulation decrement ECX only if emulation succeeded
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (22 preceding siblings ...)
2010-03-14 16:21 ` [PATCH v2 23/30] KVM: x86 emulator: add decoding of X,Y parameters from Intel SDM Gleb Natapov
@ 2010-03-14 16:21 ` Gleb Natapov
2010-03-14 16:42 ` Avi Kivity
2010-03-14 16:21 ` [PATCH v2 25/30] KVM: x86 emulator: fix in/out emulation Gleb Natapov
` (5 subsequent siblings)
29 siblings, 1 reply; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:21 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/emulate.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 12c630c..8f5e4c8 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2474,7 +2474,6 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
goto done;
}
}
- register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1);
c->eip = ctxt->eip;
}
@@ -2943,6 +2942,9 @@ writeback:
c->regs[VCPU_REGS_RDI]);
}
+ if (c->rep_prefix)
+ register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1);
+
/* Commit shadow register state. */
memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs);
kvm_rip_write(ctxt->vcpu, c->eip);
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 25/30] KVM: x86 emulator: fix in/out emulation.
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (23 preceding siblings ...)
2010-03-14 16:21 ` [PATCH v2 24/30] KVM: x86 emulator: during rep emulation decrement ECX only if emulation succeeded Gleb Natapov
@ 2010-03-14 16:21 ` Gleb Natapov
2010-03-14 16:54 ` Avi Kivity
2010-03-14 16:21 ` [PATCH v2 26/30] KVM: x86 emulator: Move string pio emulation into emulator.c Gleb Natapov
` (4 subsequent siblings)
29 siblings, 1 reply; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:21 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
in/out emulation is broken now. The breakage is different depending
on where IO device resides. If it is in userspace emulator reports
emulation failure since it incorrectly interprets kvm_emulate_pio()
return value. If IO device is in the kernel emulation of 'in' will do
nothing since kvm_emulate_pio() stores result directly into vcpu
registers, so emulator will overwrite result of emulation during
commit of shadowed register.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/include/asm/kvm_emulate.h | 7 +
arch/x86/include/asm/kvm_host.h | 3 +-
arch/x86/kvm/emulate.c | 47 ++++-----
arch/x86/kvm/svm.c | 20 +--
arch/x86/kvm/vmx.c | 20 ++--
arch/x86/kvm/x86.c | 213 ++++++++++++++++++++++--------------
6 files changed, 176 insertions(+), 134 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index bd46929..679245c 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -119,6 +119,13 @@ struct x86_emulate_ops {
const void *new,
unsigned int bytes,
struct kvm_vcpu *vcpu);
+
+ int (*pio_in_emulated)(int size, unsigned short port, void *val,
+ unsigned int count, struct kvm_vcpu *vcpu);
+
+ int (*pio_out_emulated)(int size, unsigned short port, const void *val,
+ unsigned int count, struct kvm_vcpu *vcpu);
+
bool (*get_cached_descriptor)(struct desc_struct *desc,
int seg, struct kvm_vcpu *vcpu);
void (*set_cached_descriptor)(struct desc_struct *desc,
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 1e15a0a..6f7ad5c 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -589,8 +589,7 @@ int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
struct x86_emulate_ctxt;
-int kvm_emulate_pio(struct kvm_vcpu *vcpu, int in,
- int size, unsigned port);
+int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port);
int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in,
int size, unsigned long count, int down,
gva_t address, int rep, unsigned port);
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 8f5e4c8..344e17b 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -210,13 +210,13 @@ static u32 opcode_table[256] = {
0, 0, 0, 0, 0, 0, 0, 0,
/* 0xE0 - 0xE7 */
0, 0, 0, 0,
- ByteOp | SrcImmUByte, SrcImmUByte,
- ByteOp | SrcImmUByte, SrcImmUByte,
+ ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
+ ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
/* 0xE8 - 0xEF */
SrcImm | Stack, SrcImm | ImplicitOps,
SrcImmU | Src2Imm16 | No64, SrcImmByte | ImplicitOps,
- SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps,
- SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps,
+ SrcNone | ByteOp | DstAcc, SrcNone | DstAcc,
+ SrcNone | ByteOp | DstAcc, SrcNone | DstAcc,
/* 0xF0 - 0xF7 */
0, 0, 0, 0,
ImplicitOps | Priv, ImplicitOps, Group | Group3_Byte, Group | Group3,
@@ -2414,8 +2414,6 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
u64 msr_data;
unsigned long saved_eip = 0;
struct decode_cache *c = &ctxt->decode;
- unsigned int port;
- int io_dir_in;
int rc = X86EMUL_CONTINUE;
ctxt->interruptibility = 0;
@@ -2814,14 +2812,10 @@ special_insn:
break;
case 0xe4: /* inb */
case 0xe5: /* in */
- port = c->src.val;
- io_dir_in = 1;
- goto do_io;
+ goto do_io_in;
case 0xe6: /* outb */
case 0xe7: /* out */
- port = c->src.val;
- io_dir_in = 0;
- goto do_io;
+ goto do_io_out;
case 0xe8: /* call (near) */ {
long int rel = c->src.val;
c->src.val = (unsigned long) c->eip;
@@ -2846,25 +2840,26 @@ special_insn:
break;
case 0xec: /* in al,dx */
case 0xed: /* in (e/r)ax,dx */
- port = c->regs[VCPU_REGS_RDX];
- io_dir_in = 1;
- goto do_io;
+ c->src.val = c->regs[VCPU_REGS_RDX];
+ do_io_in:
+ if (!emulator_io_permited(ctxt, ops, c->src.val, c->dst.bytes)) {
+ kvm_inject_gp(ctxt->vcpu, 0);
+ goto done;
+ }
+ ops->pio_in_emulated(c->dst.bytes, c->src.val, &c->dst.val, 1,
+ ctxt->vcpu);
+ break;
case 0xee: /* out al,dx */
case 0xef: /* out (e/r)ax,dx */
- port = c->regs[VCPU_REGS_RDX];
- io_dir_in = 0;
- do_io:
- if (!emulator_io_permited(ctxt, ops, port,
- (c->d & ByteOp) ? 1 : c->op_bytes)) {
+ c->src.val = c->regs[VCPU_REGS_RDX];
+ do_io_out:
+ if (!emulator_io_permited(ctxt, ops, c->src.val, c->dst.bytes)) {
kvm_inject_gp(ctxt->vcpu, 0);
goto done;
}
- if (kvm_emulate_pio(ctxt->vcpu, io_dir_in,
- (c->d & ByteOp) ? 1 : c->op_bytes,
- port) != 0) {
- c->eip = saved_eip;
- goto cannot_emulate;
- }
+ ops->pio_out_emulated(c->dst.bytes, c->src.val, &c->dst.val, 1,
+ ctxt->vcpu);
+ c->dst.type = OP_NONE; /* Disable writeback. */
break;
case 0xf4: /* hlt */
ctxt->vcpu->arch.halt_request = 1;
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index b646e96..2a49310 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1493,29 +1493,23 @@ static int shutdown_interception(struct vcpu_svm *svm)
static int io_interception(struct vcpu_svm *svm)
{
+ struct kvm_vcpu *vcpu = &svm->vcpu;
u32 io_info = svm->vmcb->control.exit_info_1; /* address size bug? */
int size, in, string;
unsigned port;
++svm->vcpu.stat.io_exits;
-
- svm->next_rip = svm->vmcb->control.exit_info_2;
-
string = (io_info & SVM_IOIO_STR_MASK) != 0;
-
- if (string) {
- if (emulate_instruction(&svm->vcpu,
- 0, 0, 0) == EMULATE_DO_MMIO)
- return 0;
- return 1;
- }
-
in = (io_info & SVM_IOIO_TYPE_MASK) != 0;
+ if (string || in)
+ return !(emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DO_MMIO);
+
port = io_info >> 16;
size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT;
+ svm->next_rip = svm->vmcb->control.exit_info_2;
+ skip_emulated_instruction(&svm->vcpu);
- skip_emulated_instruction(&svm->vcpu);
- return kvm_emulate_pio(&svm->vcpu, in, size, port);
+ return kvm_fast_pio_out(vcpu, size, port);
}
static int nmi_interception(struct vcpu_svm *svm)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 06108f3..1042324 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -2977,23 +2977,21 @@ static int handle_io(struct kvm_vcpu *vcpu)
unsigned long exit_qualification;
int size, in, string;
unsigned port;
-
- ++vcpu->stat.io_exits;
+
exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
string = (exit_qualification & 16) != 0;
+ in = (exit_qualification & 8) != 0;
- if (string) {
- if (emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DO_MMIO)
- return 0;
- return 1;
- }
+ ++vcpu->stat.io_exits;
- size = (exit_qualification & 7) + 1;
- in = (exit_qualification & 8) != 0;
- port = exit_qualification >> 16;
+ if (string || in)
+ return !(emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DO_MMIO);
+ port = exit_qualification >> 16;
+ size = (exit_qualification & 7) + 1;
skip_emulated_instruction(vcpu);
- return kvm_emulate_pio(vcpu, in, size, port);
+
+ return kvm_fast_pio_out(vcpu, size, port);
}
static void
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 3c5ffa2..37c6178 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3351,6 +3351,86 @@ emul_write:
return emulator_write_emulated(addr, new, bytes, vcpu);
}
+static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
+{
+ /* TODO: String I/O for in kernel device */
+ int r;
+
+ if (vcpu->arch.pio.in)
+ r = kvm_io_bus_read(vcpu->kvm, KVM_PIO_BUS, vcpu->arch.pio.port,
+ vcpu->arch.pio.size, pd);
+ else
+ r = kvm_io_bus_write(vcpu->kvm, KVM_PIO_BUS,
+ vcpu->arch.pio.port, vcpu->arch.pio.size,
+ pd);
+ return r;
+}
+
+
+static int emulator_pio_in_emulated(int size, unsigned short port, void *val,
+ unsigned int count, struct kvm_vcpu *vcpu)
+{
+ if (vcpu->arch.pio.cur_count)
+ goto data_avail;
+
+ trace_kvm_pio(1, port, size, 1);
+
+ vcpu->arch.pio.port = port;
+ vcpu->arch.pio.in = 1;
+ vcpu->arch.pio.string = 0;
+ vcpu->arch.pio.down = 0;
+ vcpu->arch.pio.rep = 0;
+ vcpu->arch.pio.count = vcpu->arch.pio.cur_count = count;
+ vcpu->arch.pio.size = size;
+
+ if (!kernel_pio(vcpu, vcpu->arch.pio_data)) {
+ data_avail:
+ memcpy(val, vcpu->arch.pio_data, size * count);
+ vcpu->arch.pio.cur_count = 0;
+ return 1;
+ }
+
+ vcpu->run->exit_reason = KVM_EXIT_IO;
+ vcpu->run->io.direction = KVM_EXIT_IO_IN;
+ vcpu->run->io.size = size;
+ vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
+ vcpu->run->io.count = count;
+ vcpu->run->io.port = port;
+
+ return 0;
+}
+
+static int emulator_pio_out_emulated(int size, unsigned short port,
+ const void *val, unsigned int count,
+ struct kvm_vcpu *vcpu)
+{
+ trace_kvm_pio(0, port, size, 1);
+
+ vcpu->arch.pio.port = port;
+ vcpu->arch.pio.in = 0;
+ vcpu->arch.pio.string = 0;
+ vcpu->arch.pio.down = 0;
+ vcpu->arch.pio.rep = 0;
+ vcpu->arch.pio.count = vcpu->arch.pio.cur_count = count;
+ vcpu->arch.pio.size = size;
+
+ memcpy(vcpu->arch.pio_data, val, size * count);
+
+ if (!kernel_pio(vcpu, vcpu->arch.pio_data)) {
+ vcpu->arch.pio.cur_count = 0;
+ return 1;
+ }
+
+ vcpu->run->exit_reason = KVM_EXIT_IO;
+ vcpu->run->io.direction = KVM_EXIT_IO_OUT;
+ vcpu->run->io.size = size;
+ vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
+ vcpu->run->io.count = count;
+ vcpu->run->io.port = port;
+
+ return 0;
+}
+
static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
{
return kvm_x86_ops->get_segment_base(vcpu, seg);
@@ -3544,6 +3624,8 @@ static struct x86_emulate_ops emulate_ops = {
.read_emulated = emulator_read_emulated,
.write_emulated = emulator_write_emulated,
.cmpxchg_emulated = emulator_cmpxchg_emulated,
+ .pio_in_emulated = emulator_pio_in_emulated,
+ .pio_out_emulated = emulator_pio_out_emulated,
.get_cached_descriptor = emulator_get_cached_descriptor,
.set_cached_descriptor = emulator_set_cached_descriptor,
.get_segment_selector = emulator_get_segment_selector,
@@ -3651,6 +3733,12 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
if (vcpu->arch.pio.string)
return EMULATE_DO_MMIO;
+ if (vcpu->arch.pio.cur_count && !vcpu->arch.pio.string) {
+ if (!vcpu->arch.pio.in)
+ vcpu->arch.pio.cur_count = 0;
+ return EMULATE_DO_MMIO;
+ }
+
if (r || vcpu->mmio_is_write) {
run->exit_reason = KVM_EXIT_MMIO;
run->mmio.phys_addr = vcpu->mmio_phys_addr;
@@ -3707,43 +3795,36 @@ int complete_pio(struct kvm_vcpu *vcpu)
int r;
unsigned long val;
- if (!io->string) {
- if (io->in) {
- val = kvm_register_read(vcpu, VCPU_REGS_RAX);
- memcpy(&val, vcpu->arch.pio_data, io->size);
- kvm_register_write(vcpu, VCPU_REGS_RAX, val);
- }
- } else {
- if (io->in) {
- r = pio_copy_data(vcpu);
- if (r)
- goto out;
- }
+ if (io->in) {
+ r = pio_copy_data(vcpu);
+ if (r)
+ goto out;
+ }
- delta = 1;
- if (io->rep) {
- delta *= io->cur_count;
- /*
- * The size of the register should really depend on
- * current address size.
- */
- val = kvm_register_read(vcpu, VCPU_REGS_RCX);
- val -= delta;
- kvm_register_write(vcpu, VCPU_REGS_RCX, val);
- }
- if (io->down)
- delta = -delta;
- delta *= io->size;
- if (io->in) {
- val = kvm_register_read(vcpu, VCPU_REGS_RDI);
- val += delta;
- kvm_register_write(vcpu, VCPU_REGS_RDI, val);
- } else {
- val = kvm_register_read(vcpu, VCPU_REGS_RSI);
- val += delta;
- kvm_register_write(vcpu, VCPU_REGS_RSI, val);
- }
+ delta = 1;
+ if (io->rep) {
+ delta *= io->cur_count;
+ /*
+ * The size of the register should really depend on
+ * current address size.
+ */
+ val = kvm_register_read(vcpu, VCPU_REGS_RCX);
+ val -= delta;
+ kvm_register_write(vcpu, VCPU_REGS_RCX, val);
+ }
+ if (io->down)
+ delta = -delta;
+ delta *= io->size;
+ if (io->in) {
+ val = kvm_register_read(vcpu, VCPU_REGS_RDI);
+ val += delta;
+ kvm_register_write(vcpu, VCPU_REGS_RDI, val);
+ } else {
+ val = kvm_register_read(vcpu, VCPU_REGS_RSI);
+ val += delta;
+ kvm_register_write(vcpu, VCPU_REGS_RSI, val);
}
+
out:
io->count -= io->cur_count;
io->cur_count = 0;
@@ -3751,21 +3832,6 @@ out:
return 0;
}
-static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
-{
- /* TODO: String I/O for in kernel device */
- int r;
-
- if (vcpu->arch.pio.in)
- r = kvm_io_bus_read(vcpu->kvm, KVM_PIO_BUS, vcpu->arch.pio.port,
- vcpu->arch.pio.size, pd);
- else
- r = kvm_io_bus_write(vcpu->kvm, KVM_PIO_BUS,
- vcpu->arch.pio.port, vcpu->arch.pio.size,
- pd);
- return r;
-}
-
static int pio_string_write(struct kvm_vcpu *vcpu)
{
struct kvm_pio_request *io = &vcpu->arch.pio;
@@ -3783,36 +3849,6 @@ static int pio_string_write(struct kvm_vcpu *vcpu)
return r;
}
-int kvm_emulate_pio(struct kvm_vcpu *vcpu, int in, int size, unsigned port)
-{
- unsigned long val;
-
- trace_kvm_pio(!in, port, size, 1);
-
- vcpu->run->exit_reason = KVM_EXIT_IO;
- 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.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
- vcpu->run->io.count = vcpu->arch.pio.count = vcpu->arch.pio.cur_count = 1;
- vcpu->run->io.port = vcpu->arch.pio.port = port;
- vcpu->arch.pio.in = in;
- vcpu->arch.pio.string = 0;
- vcpu->arch.pio.down = 0;
- vcpu->arch.pio.rep = 0;
-
- 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)) {
- complete_pio(vcpu);
- return 1;
- }
- return 0;
-}
-EXPORT_SYMBOL_GPL(kvm_emulate_pio);
-
int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in,
int size, unsigned long count, int down,
gva_t address, int rep, unsigned port)
@@ -3878,6 +3914,16 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in,
}
EXPORT_SYMBOL_GPL(kvm_emulate_pio_string);
+int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port)
+{
+ unsigned long val = kvm_register_read(vcpu, VCPU_REGS_RAX);
+ int ret = emulator_pio_out_emulated(size, port, &val, 1, vcpu);
+ /* do not return to emulator after return from userspace */
+ vcpu->arch.pio.count = 0;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(kvm_fast_pio_out);
+
static void bounce_off(void *info)
{
/* nothing */
@@ -4608,9 +4654,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
if (vcpu->arch.pio.cur_count) {
vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
- r = complete_pio(vcpu);
+ if (!vcpu->arch.pio.string)
+ r = emulate_instruction(vcpu, 0, 0, EMULTYPE_NO_DECODE);
+ else
+ r = complete_pio(vcpu);
srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
- if (r)
+ if (r == EMULATE_DO_MMIO)
goto out;
}
if (vcpu->mmio_needed) {
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 26/30] KVM: x86 emulator: Move string pio emulation into emulator.c
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (24 preceding siblings ...)
2010-03-14 16:21 ` [PATCH v2 25/30] KVM: x86 emulator: fix in/out emulation Gleb Natapov
@ 2010-03-14 16:21 ` Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 27/30] KVM: x86 emulator: remove saved_eip Gleb Natapov
` (3 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:21 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Currently emulation is done outside of emulator so things like doing
ins/outs to/from mmio are broken it also makes it hard (if not impossible)
to implement single stepping in the future. The implementation in this
patch is not efficient since it exits to userspace for each IO while
previous implementation did 'ins' in batches. Further patch that
implements pio in string read ahead address this problem.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/include/asm/kvm_host.h | 8 --
arch/x86/kvm/emulate.c | 46 +++------
arch/x86/kvm/x86.c | 204 +++------------------------------------
3 files changed, 29 insertions(+), 229 deletions(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 6f7ad5c..00c4892 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -224,14 +224,9 @@ struct kvm_pv_mmu_op_buffer {
struct kvm_pio_request {
unsigned long count;
- int cur_count;
- gva_t guest_gva;
int in;
int port;
int size;
- int string;
- int down;
- int rep;
};
/*
@@ -590,9 +585,6 @@ int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
struct x86_emulate_ctxt;
int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port);
-int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in,
- int size, unsigned long count, int down,
- gva_t address, int rep, unsigned port);
void kvm_emulate_cpuid(struct kvm_vcpu *vcpu);
int kvm_emulate_halt(struct kvm_vcpu *vcpu);
int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address);
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 344e17b..1495441 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -153,8 +153,8 @@ static u32 opcode_table[256] = {
0, 0, 0, 0,
/* 0x68 - 0x6F */
SrcImm | Mov | Stack, 0, SrcImmByte | Mov | Stack, 0,
- SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* insb, insw/insd */
- SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* outsb, outsw/outsd */
+ DstDI | ByteOp | Mov | String, DstDI | Mov | String, /* insb, insw/insd */
+ SrcSI | ByteOp | ImplicitOps | String, SrcSI | ImplicitOps | String, /* outsb, outsw/outsd */
/* 0x70 - 0x77 */
SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
@@ -2607,46 +2607,26 @@ special_insn:
case 0x6c: /* insb */
case 0x6d: /* insw/insd */
if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
- (c->d & ByteOp) ? 1 : c->op_bytes)) {
+ c->dst.bytes)) {
kvm_inject_gp(ctxt->vcpu, 0);
goto done;
}
- if (kvm_emulate_pio_string(ctxt->vcpu,
- 1,
- (c->d & ByteOp) ? 1 : c->op_bytes,
- c->rep_prefix ?
- address_mask(c, c->regs[VCPU_REGS_RCX]) : 1,
- (ctxt->eflags & EFLG_DF),
- register_address(c, es_base(ctxt),
- c->regs[VCPU_REGS_RDI]),
- c->rep_prefix,
- c->regs[VCPU_REGS_RDX]) == 0) {
- c->eip = saved_eip;
- return -1;
- }
- return 0;
+ if (!ops->pio_in_emulated(c->dst.bytes, c->regs[VCPU_REGS_RDX],
+ &c->dst.val, 1, ctxt->vcpu))
+ goto done; /* IO is needed, skip writeback */
+ break;
case 0x6e: /* outsb */
case 0x6f: /* outsw/outsd */
if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
- (c->d & ByteOp) ? 1 : c->op_bytes)) {
+ c->src.bytes)) {
kvm_inject_gp(ctxt->vcpu, 0);
goto done;
}
- if (kvm_emulate_pio_string(ctxt->vcpu,
- 0,
- (c->d & ByteOp) ? 1 : c->op_bytes,
- c->rep_prefix ?
- address_mask(c, c->regs[VCPU_REGS_RCX]) : 1,
- (ctxt->eflags & EFLG_DF),
- register_address(c,
- seg_override_base(ctxt, c),
- c->regs[VCPU_REGS_RSI]),
- c->rep_prefix,
- c->regs[VCPU_REGS_RDX]) == 0) {
- c->eip = saved_eip;
- return -1;
- }
- return 0;
+ ops->pio_out_emulated(c->src.bytes, c->regs[VCPU_REGS_RDX],
+ &c->src.val, 1, ctxt->vcpu);
+
+ c->dst.type = OP_NONE; /* nothing to writeback */
+ break;
case 0x70 ... 0x7f: /* jcc (short) */
if (test_cc(c->b, ctxt->eflags))
jmp_rel(c, c->src.val);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 37c6178..e38ba94 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3142,18 +3142,17 @@ static int kvm_read_guest_virt_system(gva_t addr, void *val, unsigned int bytes,
return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, error);
}
-static int kvm_write_guest_virt_helper(gva_t addr, void *val,
+static int kvm_write_guest_virt_system(gva_t addr, void *val,
unsigned int bytes,
- struct kvm_vcpu *vcpu, u32 access,
+ struct kvm_vcpu *vcpu,
u32 *error)
{
void *data = val;
int r = X86EMUL_CONTINUE;
- access |= PFERR_WRITE_MASK;
-
while (bytes) {
- gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr, access, error);
+ gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr,
+ PFERR_WRITE_MASK, error);
unsigned offset = addr & (PAGE_SIZE-1);
unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset);
int ret;
@@ -3176,20 +3175,6 @@ out:
return r;
}
-static int kvm_write_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_write_guest_virt_helper(addr, val, bytes, vcpu, access, error);
-}
-
-static int kvm_write_guest_virt_system(gva_t addr, void *val,
- unsigned int bytes,
- struct kvm_vcpu *vcpu, u32 *error)
-{
- return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, 0, error);
-}
-
static int emulator_read_emulated(unsigned long addr,
void *val,
unsigned int bytes,
@@ -3370,23 +3355,20 @@ static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
static int emulator_pio_in_emulated(int size, unsigned short port, void *val,
unsigned int count, struct kvm_vcpu *vcpu)
{
- if (vcpu->arch.pio.cur_count)
+ if (vcpu->arch.pio.count)
goto data_avail;
trace_kvm_pio(1, port, size, 1);
vcpu->arch.pio.port = port;
vcpu->arch.pio.in = 1;
- vcpu->arch.pio.string = 0;
- vcpu->arch.pio.down = 0;
- vcpu->arch.pio.rep = 0;
- vcpu->arch.pio.count = vcpu->arch.pio.cur_count = count;
+ vcpu->arch.pio.count = count;
vcpu->arch.pio.size = size;
if (!kernel_pio(vcpu, vcpu->arch.pio_data)) {
data_avail:
memcpy(val, vcpu->arch.pio_data, size * count);
- vcpu->arch.pio.cur_count = 0;
+ vcpu->arch.pio.count = 0;
return 1;
}
@@ -3408,16 +3390,13 @@ static int emulator_pio_out_emulated(int size, unsigned short port,
vcpu->arch.pio.port = port;
vcpu->arch.pio.in = 0;
- vcpu->arch.pio.string = 0;
- vcpu->arch.pio.down = 0;
- vcpu->arch.pio.rep = 0;
- vcpu->arch.pio.count = vcpu->arch.pio.cur_count = count;
+ vcpu->arch.pio.count = count;
vcpu->arch.pio.size = size;
memcpy(vcpu->arch.pio_data, val, size * count);
if (!kernel_pio(vcpu, vcpu->arch.pio_data)) {
- vcpu->arch.pio.cur_count = 0;
+ vcpu->arch.pio.count = 0;
return 1;
}
@@ -3664,7 +3643,6 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
cache_all_regs(vcpu);
vcpu->mmio_is_write = 0;
- vcpu->arch.pio.string = 0;
if (!(emulation_type & EMULTYPE_NO_DECODE)) {
int cs_db, cs_l;
@@ -3730,12 +3708,9 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
if (r == 0)
kvm_x86_ops->set_interrupt_shadow(vcpu, shadow_mask);
- if (vcpu->arch.pio.string)
- return EMULATE_DO_MMIO;
-
- if (vcpu->arch.pio.cur_count && !vcpu->arch.pio.string) {
+ if (vcpu->arch.pio.count) {
if (!vcpu->arch.pio.in)
- vcpu->arch.pio.cur_count = 0;
+ vcpu->arch.pio.count = 0;
return EMULATE_DO_MMIO;
}
@@ -3768,152 +3743,6 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
}
EXPORT_SYMBOL_GPL(emulate_instruction);
-static int pio_copy_data(struct kvm_vcpu *vcpu)
-{
- void *p = vcpu->arch.pio_data;
- gva_t q = vcpu->arch.pio.guest_gva;
- unsigned bytes;
- int ret;
- u32 error_code;
-
- bytes = vcpu->arch.pio.size * vcpu->arch.pio.cur_count;
- if (vcpu->arch.pio.in)
- ret = kvm_write_guest_virt(q, p, bytes, vcpu, &error_code);
- else
- 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;
-}
-
-int complete_pio(struct kvm_vcpu *vcpu)
-{
- struct kvm_pio_request *io = &vcpu->arch.pio;
- long delta;
- int r;
- unsigned long val;
-
- if (io->in) {
- r = pio_copy_data(vcpu);
- if (r)
- goto out;
- }
-
- delta = 1;
- if (io->rep) {
- delta *= io->cur_count;
- /*
- * The size of the register should really depend on
- * current address size.
- */
- val = kvm_register_read(vcpu, VCPU_REGS_RCX);
- val -= delta;
- kvm_register_write(vcpu, VCPU_REGS_RCX, val);
- }
- if (io->down)
- delta = -delta;
- delta *= io->size;
- if (io->in) {
- val = kvm_register_read(vcpu, VCPU_REGS_RDI);
- val += delta;
- kvm_register_write(vcpu, VCPU_REGS_RDI, val);
- } else {
- val = kvm_register_read(vcpu, VCPU_REGS_RSI);
- val += delta;
- kvm_register_write(vcpu, VCPU_REGS_RSI, val);
- }
-
-out:
- io->count -= io->cur_count;
- io->cur_count = 0;
-
- return 0;
-}
-
-static int pio_string_write(struct kvm_vcpu *vcpu)
-{
- struct kvm_pio_request *io = &vcpu->arch.pio;
- void *pd = vcpu->arch.pio_data;
- int i, r = 0;
-
- for (i = 0; i < io->cur_count; i++) {
- if (kvm_io_bus_write(vcpu->kvm, KVM_PIO_BUS,
- io->port, io->size, pd)) {
- r = -EOPNOTSUPP;
- break;
- }
- pd += io->size;
- }
- return r;
-}
-
-int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in,
- int size, unsigned long count, int down,
- gva_t address, int rep, unsigned port)
-{
- unsigned now, in_page;
- int ret = 0;
-
- trace_kvm_pio(!in, port, size, count);
-
- vcpu->run->exit_reason = KVM_EXIT_IO;
- 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.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
- vcpu->run->io.count = vcpu->arch.pio.count = vcpu->arch.pio.cur_count = count;
- vcpu->run->io.port = vcpu->arch.pio.port = port;
- vcpu->arch.pio.in = in;
- vcpu->arch.pio.string = 1;
- vcpu->arch.pio.down = down;
- vcpu->arch.pio.rep = rep;
-
- if (!count) {
- kvm_x86_ops->skip_emulated_instruction(vcpu);
- return 1;
- }
-
- if (!down)
- in_page = PAGE_SIZE - offset_in_page(address);
- else
- in_page = offset_in_page(address) + size;
- now = min(count, (unsigned long)in_page / size);
- if (!now)
- now = 1;
- if (down) {
- /*
- * String I/O in reverse. Yuck. Kill the guest, fix later.
- */
- pr_unimpl(vcpu, "guest string pio down\n");
- kvm_inject_gp(vcpu, 0);
- return 1;
- }
- vcpu->run->io.count = now;
- vcpu->arch.pio.cur_count = now;
-
- if (vcpu->arch.pio.cur_count == vcpu->arch.pio.count)
- kvm_x86_ops->skip_emulated_instruction(vcpu);
-
- vcpu->arch.pio.guest_gva = address;
-
- if (!vcpu->arch.pio.in) {
- /* string PIO write */
- ret = pio_copy_data(vcpu);
- if (ret == X86EMUL_PROPAGATE_FAULT)
- return 1;
- if (ret == 0 && !pio_string_write(vcpu)) {
- complete_pio(vcpu);
- if (vcpu->arch.pio.count == 0)
- ret = 1;
- }
- }
- /* no string PIO read support yet */
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(kvm_emulate_pio_string);
-
int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port)
{
unsigned long val = kvm_register_read(vcpu, VCPU_REGS_RAX);
@@ -4652,15 +4481,14 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
if (!irqchip_in_kernel(vcpu->kvm))
kvm_set_cr8(vcpu, kvm_run->cr8);
- if (vcpu->arch.pio.cur_count) {
+ if (vcpu->arch.pio.count) {
vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
- if (!vcpu->arch.pio.string)
- r = emulate_instruction(vcpu, 0, 0, EMULTYPE_NO_DECODE);
- else
- r = complete_pio(vcpu);
+ r = emulate_instruction(vcpu, 0, 0, EMULTYPE_NO_DECODE);
srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
- if (r == EMULATE_DO_MMIO)
+ if (r == EMULATE_DO_MMIO) {
+ r = 0;
goto out;
+ }
}
if (vcpu->mmio_needed) {
memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 27/30] KVM: x86 emulator: remove saved_eip
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (25 preceding siblings ...)
2010-03-14 16:21 ` [PATCH v2 26/30] KVM: x86 emulator: Move string pio emulation into emulator.c Gleb Natapov
@ 2010-03-14 16:21 ` Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 28/30] KVM: x86 emulator: restart string instruction without going back to a guest Gleb Natapov
` (2 subsequent siblings)
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:21 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
c->eip is never written back in case of emulation failure, so no need to
set it to old value.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/emulate.c | 9 +--------
1 files changed, 1 insertions(+), 8 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 1495441..9d8c7b6 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2412,7 +2412,6 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
{
unsigned long memop = 0;
u64 msr_data;
- unsigned long saved_eip = 0;
struct decode_cache *c = &ctxt->decode;
int rc = X86EMUL_CONTINUE;
@@ -2424,7 +2423,6 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
*/
memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
- saved_eip = c->eip;
if (ctxt->mode == X86EMUL_MODE_PROT64 && (c->d & No64)) {
kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
@@ -2925,11 +2923,7 @@ writeback:
kvm_rip_write(ctxt->vcpu, c->eip);
done:
- if (rc == X86EMUL_UNHANDLEABLE) {
- c->eip = saved_eip;
- return -1;
- }
- return 0;
+ return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
twobyte_insn:
switch (c->b) {
@@ -3206,6 +3200,5 @@ twobyte_insn:
cannot_emulate:
DPRINTF("Cannot emulate %02x\n", c->b);
- c->eip = saved_eip;
return -1;
}
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 28/30] KVM: x86 emulator: restart string instruction without going back to a guest.
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (26 preceding siblings ...)
2010-03-14 16:21 ` [PATCH v2 27/30] KVM: x86 emulator: remove saved_eip Gleb Natapov
@ 2010-03-14 16:21 ` Gleb Natapov
2010-03-14 16:56 ` Avi Kivity
2010-03-14 16:21 ` [PATCH v2 29/30] KVM: x86 emulator: introduce pio in string read ahead Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 30/30] KVM: small kvm_arch_vcpu_ioctl_run() cleanup Gleb Natapov
29 siblings, 1 reply; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:21 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Currently when string instruction is only partially complete we go back
to a guest mode, guest tries to reexecute instruction and exits again
and at this point emulation continues. Avoid all of this by restarting
instruction without going back to a guest mode, but return to a guest
mode on each page boundary to allow interrupt injection. Pending
exception causes immediate guest entry too.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/include/asm/kvm_emulate.h | 1 +
arch/x86/kvm/emulate.c | 26 ++++++++++++++++----------
arch/x86/kvm/x86.c | 19 ++++++++++++++++++-
3 files changed, 35 insertions(+), 11 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 679245c..7fda16f 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -193,6 +193,7 @@ struct x86_emulate_ctxt {
/* interruptibility state, as a result of execution of STI or MOV SS */
int interruptibility;
+ bool restart; /* restart string instruction after writeback */
/* decode cache */
struct decode_cache decode;
};
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 9d8c7b6..5687b06 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -927,8 +927,11 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
int mode = ctxt->mode;
int def_op_bytes, def_ad_bytes, group;
- /* Shadow copy of register state. Committed on successful emulation. */
+ /* we cannot decode insn before we complete previous rep insn */
+ WARN_ON(ctxt->restart);
+
+ /* Shadow copy of register state. Committed on successful emulation. */
memset(c, 0, sizeof(struct decode_cache));
c->eip = ctxt->eip;
ctxt->cs_base = seg_base(ctxt, VCPU_SREG_CS);
@@ -2445,8 +2448,11 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
memop = c->modrm_ea;
if (c->rep_prefix && (c->d & String)) {
+ ctxt->restart = true;
/* All REP prefixes have the same first termination condition */
if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0) {
+ string_done:
+ ctxt->restart = false;
kvm_rip_write(ctxt->vcpu, c->eip);
goto done;
}
@@ -2458,17 +2464,13 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
* - if REPNE/REPNZ and ZF = 1 then done
*/
if ((c->b == 0xa6) || (c->b == 0xa7) ||
- (c->b == 0xae) || (c->b == 0xaf)) {
+ (c->b == 0xae) || (c->b == 0xaf)) {
if ((c->rep_prefix == REPE_PREFIX) &&
- ((ctxt->eflags & EFLG_ZF) == 0)) {
- kvm_rip_write(ctxt->vcpu, c->eip);
- goto done;
- }
+ ((ctxt->eflags & EFLG_ZF) == 0))
+ goto string_done;
if ((c->rep_prefix == REPNE_PREFIX) &&
- ((ctxt->eflags & EFLG_ZF) == EFLG_ZF)) {
- kvm_rip_write(ctxt->vcpu, c->eip);
- goto done;
- }
+ ((ctxt->eflags & EFLG_ZF) == EFLG_ZF))
+ goto string_done;
}
c->eip = ctxt->eip;
}
@@ -2904,6 +2906,8 @@ writeback:
c->src.ptr = (unsigned long *)
register_address(c, seg_override_base(ctxt, c),
c->regs[VCPU_REGS_RSI]);
+ if (!(c->regs[VCPU_REGS_RSI] & ~PAGE_MASK))
+ ctxt->restart = false;
}
if ((c->d & DstMask) == DstDI) {
@@ -2913,6 +2917,8 @@ writeback:
c->dst.ptr = (unsigned long *)
register_address(c, es_base(ctxt),
c->regs[VCPU_REGS_RDI]);
+ if (!(c->regs[VCPU_REGS_RDI] & ~PAGE_MASK))
+ ctxt->restart = false;
}
if (c->rep_prefix)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e38ba94..b158ef8 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3702,6 +3702,7 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
return EMULATE_DONE;
}
+restart:
r = x86_emulate_insn(&vcpu->arch.emulate_ctxt, &emulate_ops);
shadow_mask = vcpu->arch.emulate_ctxt.interruptibility;
@@ -3724,7 +3725,7 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
if (r) {
if (kvm_mmu_unprotect_page_virt(vcpu, cr2))
- return EMULATE_DONE;
+ goto done;
if (!vcpu->mmio_needed) {
kvm_report_emulation_failure(vcpu, "mmio");
return EMULATE_FAIL;
@@ -3739,6 +3740,13 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
return EMULATE_DO_MMIO;
}
+done:
+ if (vcpu->arch.exception.pending)
+ vcpu->arch.emulate_ctxt.restart = false;
+
+ if (vcpu->arch.emulate_ctxt.restart)
+ goto restart;
+
return EMULATE_DONE;
}
EXPORT_SYMBOL_GPL(emulate_instruction);
@@ -4507,6 +4515,15 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
goto out;
}
}
+ if (vcpu->arch.emulate_ctxt.restart) {
+ vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
+ r = emulate_instruction(vcpu, 0, 0, EMULTYPE_NO_DECODE);
+ srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
+ if (r == EMULATE_DO_MMIO) {
+ r = 0;
+ goto out;
+ }
+ }
if (kvm_run->exit_reason == KVM_EXIT_HYPERCALL)
kvm_register_write(vcpu, VCPU_REGS_RAX,
kvm_run->hypercall.ret);
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 29/30] KVM: x86 emulator: introduce pio in string read ahead.
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (27 preceding siblings ...)
2010-03-14 16:21 ` [PATCH v2 28/30] KVM: x86 emulator: restart string instruction without going back to a guest Gleb Natapov
@ 2010-03-14 16:21 ` Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 30/30] KVM: small kvm_arch_vcpu_ioctl_run() cleanup Gleb Natapov
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:21 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
To optimize "rep ins" instruction do IO in big chunks ahead of time
instead of doing it only when required during instruction emulation.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/include/asm/kvm_emulate.h | 7 +++++++
arch/x86/kvm/emulate.c | 35 +++++++++++++++++++++++++++++++----
2 files changed, 38 insertions(+), 4 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 7fda16f..b5e12c5 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -151,6 +151,12 @@ struct fetch_cache {
unsigned long end;
};
+struct read_cache {
+ u8 data[1024];
+ unsigned long pos;
+ unsigned long end;
+};
+
struct decode_cache {
u8 twobyte;
u8 b;
@@ -178,6 +184,7 @@ struct decode_cache {
void *modrm_ptr;
unsigned long modrm_val;
struct fetch_cache fetch;
+ struct read_cache io_read;
};
struct x86_emulate_ctxt {
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 5687b06..819245c 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1257,6 +1257,34 @@ done:
return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
}
+static int pio_in_emulated(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops,
+ unsigned int size, unsigned short port,
+ void *dest)
+{
+ struct read_cache *rc = &ctxt->decode.io_read;
+
+ if (rc->pos == rc->end) { /* refill pio read ahead */
+ struct decode_cache *c = &ctxt->decode;
+ unsigned int in_page, n;
+ unsigned int count = c->rep_prefix ?
+ address_mask(c, c->regs[VCPU_REGS_RCX]) : 1;
+ in_page = (ctxt->eflags & EFLG_DF) ?
+ offset_in_page(c->regs[VCPU_REGS_RDI]) :
+ PAGE_SIZE - offset_in_page(c->regs[VCPU_REGS_RDI]);
+ n = min(min(in_page, (unsigned int)sizeof(rc->data)) / size,
+ count);
+ rc->pos = rc->end = 0;
+ if (!ops->pio_in_emulated(size, port, rc->data, n, ctxt->vcpu))
+ return 0;
+ rc->end = n * size;
+ }
+
+ memcpy(dest, rc->data + rc->pos, size);
+ rc->pos += size;
+ return 1;
+}
+
static u32 desc_limit_scaled(struct desc_struct *desc)
{
u32 limit = get_desc_limit(desc);
@@ -2611,8 +2639,8 @@ special_insn:
kvm_inject_gp(ctxt->vcpu, 0);
goto done;
}
- if (!ops->pio_in_emulated(c->dst.bytes, c->regs[VCPU_REGS_RDX],
- &c->dst.val, 1, ctxt->vcpu))
+ if (!pio_in_emulated(ctxt, ops, c->dst.bytes,
+ c->regs[VCPU_REGS_RDX], &c->dst.val))
goto done; /* IO is needed, skip writeback */
break;
case 0x6e: /* outsb */
@@ -2826,8 +2854,7 @@ special_insn:
kvm_inject_gp(ctxt->vcpu, 0);
goto done;
}
- ops->pio_in_emulated(c->dst.bytes, c->src.val, &c->dst.val, 1,
- ctxt->vcpu);
+ pio_in_emulated(ctxt, ops, c->dst.bytes, c->src.val, &c->dst.val);
break;
case 0xee: /* out al,dx */
case 0xef: /* out (e/r)ax,dx */
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 30/30] KVM: small kvm_arch_vcpu_ioctl_run() cleanup.
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
` (28 preceding siblings ...)
2010-03-14 16:21 ` [PATCH v2 29/30] KVM: x86 emulator: introduce pio in string read ahead Gleb Natapov
@ 2010-03-14 16:21 ` Gleb Natapov
29 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 16:21 UTC (permalink / raw)
To: avi, mtosatti; +Cc: kvm
Unify all conditions that get us back into emulator after returning from
userspace.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/x86.c | 32 ++++++--------------------------
1 files changed, 6 insertions(+), 26 deletions(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index b158ef8..01401c7 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4489,33 +4489,13 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
if (!irqchip_in_kernel(vcpu->kvm))
kvm_set_cr8(vcpu, kvm_run->cr8);
- if (vcpu->arch.pio.count) {
- vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
- r = emulate_instruction(vcpu, 0, 0, EMULTYPE_NO_DECODE);
- srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
- if (r == EMULATE_DO_MMIO) {
- r = 0;
- goto out;
+ if (vcpu->arch.pio.count || vcpu->mmio_needed ||
+ vcpu->arch.emulate_ctxt.restart) {
+ if (vcpu->mmio_needed) {
+ memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
+ vcpu->mmio_read_completed = 1;
+ vcpu->mmio_needed = 0;
}
- }
- if (vcpu->mmio_needed) {
- memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
- vcpu->mmio_read_completed = 1;
- vcpu->mmio_needed = 0;
-
- vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
- r = emulate_instruction(vcpu, vcpu->arch.mmio_fault_cr2, 0,
- EMULTYPE_NO_DECODE);
- srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
- if (r == EMULATE_DO_MMIO) {
- /*
- * Read-modify-write. Back to userspace.
- */
- r = 0;
- goto out;
- }
- }
- if (vcpu->arch.emulate_ctxt.restart) {
vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
r = emulate_instruction(vcpu, 0, 0, EMULTYPE_NO_DECODE);
srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
--
1.6.5
^ permalink raw reply related [flat|nested] 53+ messages in thread
* Re: [PATCH v2 24/30] KVM: x86 emulator: during rep emulation decrement ECX only if emulation succeeded
2010-03-14 16:21 ` [PATCH v2 24/30] KVM: x86 emulator: during rep emulation decrement ECX only if emulation succeeded Gleb Natapov
@ 2010-03-14 16:42 ` Avi Kivity
0 siblings, 0 replies; 53+ messages in thread
From: Avi Kivity @ 2010-03-14 16:42 UTC (permalink / raw)
To: Gleb Natapov; +Cc: mtosatti, kvm
On 03/14/2010 06:21 PM, Gleb Natapov wrote:
>
> @@ -2943,6 +2942,9 @@ writeback:
> c->regs[VCPU_REGS_RDI]);
> }
>
> + if (c->rep_prefix)
> + register_address_increment(c,&c->regs[VCPU_REGS_RCX], -1);
> +
>
Should be really (c->rep_prefix && (c->d & String)). Some sse
instructions accept rep prefix, as well as pause (rep; nop).
We don't emulate any of them now so breakage is only theoretical.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 25/30] KVM: x86 emulator: fix in/out emulation.
2010-03-14 16:21 ` [PATCH v2 25/30] KVM: x86 emulator: fix in/out emulation Gleb Natapov
@ 2010-03-14 16:54 ` Avi Kivity
2010-03-14 17:35 ` Gleb Natapov
0 siblings, 1 reply; 53+ messages in thread
From: Avi Kivity @ 2010-03-14 16:54 UTC (permalink / raw)
To: Gleb Natapov; +Cc: mtosatti, kvm
On 03/14/2010 06:21 PM, Gleb Natapov wrote:
> in/out emulation is broken now. The breakage is different depending
> on where IO device resides. If it is in userspace emulator reports
> emulation failure since it incorrectly interprets kvm_emulate_pio()
> return value. If IO device is in the kernel emulation of 'in' will do
> nothing since kvm_emulate_pio() stores result directly into vcpu
> registers, so emulator will overwrite result of emulation during
> commit of shadowed register.
>
>
> diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
> index 8f5e4c8..344e17b 100644
> --- a/arch/x86/kvm/emulate.c
> +++ b/arch/x86/kvm/emulate.c
> @@ -210,13 +210,13 @@ static u32 opcode_table[256] = {
> 0, 0, 0, 0, 0, 0, 0, 0,
> /* 0xE0 - 0xE7 */
> 0, 0, 0, 0,
> - ByteOp | SrcImmUByte, SrcImmUByte,
> - ByteOp | SrcImmUByte, SrcImmUByte,
> + ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
> + ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
>
REX prefix shouldn't expand DstAcc to 64 bits here. Might cause
problems further down in the pipeline.+
> port = io_info>> 16;
> size = (io_info& SVM_IOIO_SIZE_MASK)>> SVM_IOIO_SIZE_SHIFT;
> + svm->next_rip = svm->vmcb->control.exit_info_2;
> + skip_emulated_instruction(&svm->vcpu);
>
whitespace damage.
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 3c5ffa2..37c6178 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -3351,6 +3351,86 @@ emul_write:
> return emulator_write_emulated(addr, new, bytes, vcpu);
> }
>
> +static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
> +{
> + /* TODO: String I/O for in kernel device */
>
ISTR this is actually needed for something. Is this a regression?
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 28/30] KVM: x86 emulator: restart string instruction without going back to a guest.
2010-03-14 16:21 ` [PATCH v2 28/30] KVM: x86 emulator: restart string instruction without going back to a guest Gleb Natapov
@ 2010-03-14 16:56 ` Avi Kivity
2010-03-14 18:06 ` Gleb Natapov
0 siblings, 1 reply; 53+ messages in thread
From: Avi Kivity @ 2010-03-14 16:56 UTC (permalink / raw)
To: Gleb Natapov; +Cc: mtosatti, kvm
On 03/14/2010 06:21 PM, Gleb Natapov wrote:
> Currently when string instruction is only partially complete we go back
> to a guest mode, guest tries to reexecute instruction and exits again
> and at this point emulation continues. Avoid all of this by restarting
> instruction without going back to a guest mode, but return to a guest
> mode on each page boundary to allow interrupt injection. Pending
> exception causes immediate guest entry too.
>
> @@ -2913,6 +2917,8 @@ writeback:
> c->dst.ptr = (unsigned long *)
> register_address(c, es_base(ctxt),
> c->regs[VCPU_REGS_RDI]);
> + if (!(c->regs[VCPU_REGS_RDI]& ~PAGE_MASK))
> + ctxt->restart = false;
> }
>
What if rdi is odd and operand size != 1?
Suggest simply reentering every N executions.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 25/30] KVM: x86 emulator: fix in/out emulation.
2010-03-14 16:54 ` Avi Kivity
@ 2010-03-14 17:35 ` Gleb Natapov
2010-03-15 7:41 ` Avi Kivity
0 siblings, 1 reply; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 17:35 UTC (permalink / raw)
To: Avi Kivity; +Cc: mtosatti, kvm
On Sun, Mar 14, 2010 at 06:54:11PM +0200, Avi Kivity wrote:
> On 03/14/2010 06:21 PM, Gleb Natapov wrote:
> >in/out emulation is broken now. The breakage is different depending
> >on where IO device resides. If it is in userspace emulator reports
> >emulation failure since it incorrectly interprets kvm_emulate_pio()
> >return value. If IO device is in the kernel emulation of 'in' will do
> >nothing since kvm_emulate_pio() stores result directly into vcpu
> >registers, so emulator will overwrite result of emulation during
> >commit of shadowed register.
> >
> >
> >diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
> >index 8f5e4c8..344e17b 100644
> >--- a/arch/x86/kvm/emulate.c
> >+++ b/arch/x86/kvm/emulate.c
> >@@ -210,13 +210,13 @@ static u32 opcode_table[256] = {
> > 0, 0, 0, 0, 0, 0, 0, 0,
> > /* 0xE0 - 0xE7 */
> > 0, 0, 0, 0,
> >- ByteOp | SrcImmUByte, SrcImmUByte,
> >- ByteOp | SrcImmUByte, SrcImmUByte,
> >+ ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
> >+ ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
>
> REX prefix shouldn't expand DstAcc to 64 bits here. Might cause
> problems further down in the pipeline.+
Is REX prefix allowed with this opcodes?
If yes:
if (c->dst.bytes == 8)
c->dst.bytes = 4;
inside IN/OUT emulation will fix this.
> > port = io_info>> 16;
> > size = (io_info& SVM_IOIO_SIZE_MASK)>> SVM_IOIO_SIZE_SHIFT;
> >+ svm->next_rip = svm->vmcb->control.exit_info_2;
> >+ skip_emulated_instruction(&svm->vcpu);
>
> whitespace damage.
>
> >diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> >index 3c5ffa2..37c6178 100644
> >--- a/arch/x86/kvm/x86.c
> >+++ b/arch/x86/kvm/x86.c
> >@@ -3351,6 +3351,86 @@ emul_write:
> > return emulator_write_emulated(addr, new, bytes, vcpu);
> > }
> >
> >+static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
> >+{
> >+ /* TODO: String I/O for in kernel device */
>
> ISTR this is actually needed for something. Is this a regression?
>
This patch does not add this function, just moves it. The function exists
currently in the source with this comment. With my patch series applied
string pio to kernel device should work without problems.
--
Gleb.
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 28/30] KVM: x86 emulator: restart string instruction without going back to a guest.
2010-03-14 16:56 ` Avi Kivity
@ 2010-03-14 18:06 ` Gleb Natapov
2010-03-15 7:44 ` Avi Kivity
0 siblings, 1 reply; 53+ messages in thread
From: Gleb Natapov @ 2010-03-14 18:06 UTC (permalink / raw)
To: Avi Kivity; +Cc: mtosatti, kvm
On Sun, Mar 14, 2010 at 06:56:37PM +0200, Avi Kivity wrote:
> On 03/14/2010 06:21 PM, Gleb Natapov wrote:
> >Currently when string instruction is only partially complete we go back
> >to a guest mode, guest tries to reexecute instruction and exits again
> >and at this point emulation continues. Avoid all of this by restarting
> >instruction without going back to a guest mode, but return to a guest
> >mode on each page boundary to allow interrupt injection. Pending
> >exception causes immediate guest entry too.
> >
> >@@ -2913,6 +2917,8 @@ writeback:
> > c->dst.ptr = (unsigned long *)
> > register_address(c, es_base(ctxt),
> > c->regs[VCPU_REGS_RDI]);
> >+ if (!(c->regs[VCPU_REGS_RDI]& ~PAGE_MASK))
> >+ ctxt->restart = false;
> > }
>
> What if rdi is odd and operand size != 1?
>
Will change to if ((c->regs[VCPU_REGS_RDI]& ~PAGE_MASK) < c->dst.bytes)
> Suggest simply reentering every N executions.
>
This restart mechanism is, in fact, needed for ins read ahead to work.
After reading ahead from IO port we need to avoid entering decoder
until entire cache is consumed otherwise decoder will clear cache and
data will be lost. So we can't just enter guest in arbitrary times, only
when read ahead cache is empty. Since read ahead is never done across
page boundary this is save place to re-enter guest.
--
Gleb.
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 25/30] KVM: x86 emulator: fix in/out emulation.
2010-03-14 17:35 ` Gleb Natapov
@ 2010-03-15 7:41 ` Avi Kivity
2010-03-15 7:44 ` Gleb Natapov
0 siblings, 1 reply; 53+ messages in thread
From: Avi Kivity @ 2010-03-15 7:41 UTC (permalink / raw)
To: Gleb Natapov; +Cc: mtosatti, kvm
On 03/14/2010 07:35 PM, Gleb Natapov wrote:
> On Sun, Mar 14, 2010 at 06:54:11PM +0200, Avi Kivity wrote:
>
>> On 03/14/2010 06:21 PM, Gleb Natapov wrote:
>>
>>> in/out emulation is broken now. The breakage is different depending
>>> on where IO device resides. If it is in userspace emulator reports
>>> emulation failure since it incorrectly interprets kvm_emulate_pio()
>>> return value. If IO device is in the kernel emulation of 'in' will do
>>> nothing since kvm_emulate_pio() stores result directly into vcpu
>>> registers, so emulator will overwrite result of emulation during
>>> commit of shadowed register.
>>>
>>>
>>> diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
>>> index 8f5e4c8..344e17b 100644
>>> --- a/arch/x86/kvm/emulate.c
>>> +++ b/arch/x86/kvm/emulate.c
>>> @@ -210,13 +210,13 @@ static u32 opcode_table[256] = {
>>> 0, 0, 0, 0, 0, 0, 0, 0,
>>> /* 0xE0 - 0xE7 */
>>> 0, 0, 0, 0,
>>> - ByteOp | SrcImmUByte, SrcImmUByte,
>>> - ByteOp | SrcImmUByte, SrcImmUByte,
>>> + ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
>>> + ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
>>>
>> REX prefix shouldn't expand DstAcc to 64 bits here. Might cause
>> problems further down in the pipeline.+
>>
> Is REX prefix allowed with this opcodes?
>
> If yes:
>
> if (c->dst.bytes == 8)
> c->dst.bytes = 4;
>
> inside IN/OUT emulation will fix this.
>
I don't know, but I guess REX is allowed and ignored.
--
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 28/30] KVM: x86 emulator: restart string instruction without going back to a guest.
2010-03-14 18:06 ` Gleb Natapov
@ 2010-03-15 7:44 ` Avi Kivity
2010-03-15 9:44 ` Gleb Natapov
0 siblings, 1 reply; 53+ messages in thread
From: Avi Kivity @ 2010-03-15 7:44 UTC (permalink / raw)
To: Gleb Natapov; +Cc: mtosatti, kvm
On 03/14/2010 08:06 PM, Gleb Natapov wrote:
>> Suggest simply reentering every N executions.
>>
>>
> This restart mechanism is, in fact, needed for ins read ahead to work.
> After reading ahead from IO port we need to avoid entering decoder
> until entire cache is consumed otherwise decoder will clear cache and
> data will be lost. So we can't just enter guest in arbitrary times, only
> when read ahead cache is empty. Since read ahead is never done across
> page boundary this is save place to re-enter guest.
>
Please make the two depend on each other directly then. We can't expect
the reader of the emulator code know that.
Have the emulator ask the buffer when it is empty.
--
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 25/30] KVM: x86 emulator: fix in/out emulation.
2010-03-15 7:41 ` Avi Kivity
@ 2010-03-15 7:44 ` Gleb Natapov
0 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-15 7:44 UTC (permalink / raw)
To: Avi Kivity; +Cc: mtosatti, kvm
On Mon, Mar 15, 2010 at 09:41:51AM +0200, Avi Kivity wrote:
> On 03/14/2010 07:35 PM, Gleb Natapov wrote:
> >On Sun, Mar 14, 2010 at 06:54:11PM +0200, Avi Kivity wrote:
> >>On 03/14/2010 06:21 PM, Gleb Natapov wrote:
> >>>in/out emulation is broken now. The breakage is different depending
> >>>on where IO device resides. If it is in userspace emulator reports
> >>>emulation failure since it incorrectly interprets kvm_emulate_pio()
> >>>return value. If IO device is in the kernel emulation of 'in' will do
> >>>nothing since kvm_emulate_pio() stores result directly into vcpu
> >>>registers, so emulator will overwrite result of emulation during
> >>>commit of shadowed register.
> >>>
> >>>
> >>>diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
> >>>index 8f5e4c8..344e17b 100644
> >>>--- a/arch/x86/kvm/emulate.c
> >>>+++ b/arch/x86/kvm/emulate.c
> >>>@@ -210,13 +210,13 @@ static u32 opcode_table[256] = {
> >>> 0, 0, 0, 0, 0, 0, 0, 0,
> >>> /* 0xE0 - 0xE7 */
> >>> 0, 0, 0, 0,
> >>>- ByteOp | SrcImmUByte, SrcImmUByte,
> >>>- ByteOp | SrcImmUByte, SrcImmUByte,
> >>>+ ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
> >>>+ ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
> >>REX prefix shouldn't expand DstAcc to 64 bits here. Might cause
> >>problems further down in the pipeline.+
> >Is REX prefix allowed with this opcodes?
> >
> >If yes:
> >
> >if (c->dst.bytes == 8)
> > c->dst.bytes = 4;
> >
> >inside IN/OUT emulation will fix this.
>
> I don't know, but I guess REX is allowed and ignored.
>
Hmm, curious. I'll test.
--
Gleb.
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 28/30] KVM: x86 emulator: restart string instruction without going back to a guest.
2010-03-15 7:44 ` Avi Kivity
@ 2010-03-15 9:44 ` Gleb Natapov
2010-03-15 9:56 ` Avi Kivity
0 siblings, 1 reply; 53+ messages in thread
From: Gleb Natapov @ 2010-03-15 9:44 UTC (permalink / raw)
To: Avi Kivity; +Cc: mtosatti, kvm
On Mon, Mar 15, 2010 at 09:44:26AM +0200, Avi Kivity wrote:
> On 03/14/2010 08:06 PM, Gleb Natapov wrote:
> >>Suggest simply reentering every N executions.
> >>
> >This restart mechanism is, in fact, needed for ins read ahead to work.
> >After reading ahead from IO port we need to avoid entering decoder
> >until entire cache is consumed otherwise decoder will clear cache and
> >data will be lost. So we can't just enter guest in arbitrary times, only
> >when read ahead cache is empty. Since read ahead is never done across
> >page boundary this is save place to re-enter guest.
>
> Please make the two depend on each other directly then. We can't
> expect the reader of the emulator code know that.
>
We can document that. I wouldn't want to have different conditions for
guest re-entry for different opcodes.
> Have the emulator ask the buffer when it is empty.
>
It will be always empty for all string ops except INS.
--
Gleb.
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 28/30] KVM: x86 emulator: restart string instruction without going back to a guest.
2010-03-15 9:44 ` Gleb Natapov
@ 2010-03-15 9:56 ` Avi Kivity
2010-03-15 10:07 ` Gleb Natapov
0 siblings, 1 reply; 53+ messages in thread
From: Avi Kivity @ 2010-03-15 9:56 UTC (permalink / raw)
To: Gleb Natapov; +Cc: mtosatti, kvm
On 03/15/2010 11:44 AM, Gleb Natapov wrote:
> On Mon, Mar 15, 2010 at 09:44:26AM +0200, Avi Kivity wrote:
>
>> On 03/14/2010 08:06 PM, Gleb Natapov wrote:
>>
>>>> Suggest simply reentering every N executions.
>>>>
>>>>
>>> This restart mechanism is, in fact, needed for ins read ahead to work.
>>> After reading ahead from IO port we need to avoid entering decoder
>>> until entire cache is consumed otherwise decoder will clear cache and
>>> data will be lost. So we can't just enter guest in arbitrary times, only
>>> when read ahead cache is empty. Since read ahead is never done across
>>> page boundary this is save place to re-enter guest.
>>>
>> Please make the two depend on each other directly then. We can't
>> expect the reader of the emulator code know that.
>>
>>
> We can document that. I wouldn't want to have different conditions for
> guest re-entry for different opcodes.
>
We now have a write buffer size of one. It's just a matter of making
the emulator know the size of the buffer (extra parameter to
->write_emulated).
>
>> Have the emulator ask the buffer when it is empty.
>>
>>
> It will be always empty for all string ops except INS.
>
>
Or we can make the buffer larger for everyone (outside this patchset
though).
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 28/30] KVM: x86 emulator: restart string instruction without going back to a guest.
2010-03-15 9:56 ` Avi Kivity
@ 2010-03-15 10:07 ` Gleb Natapov
2010-03-15 10:15 ` Avi Kivity
0 siblings, 1 reply; 53+ messages in thread
From: Gleb Natapov @ 2010-03-15 10:07 UTC (permalink / raw)
To: Avi Kivity; +Cc: mtosatti, kvm
On Mon, Mar 15, 2010 at 11:56:32AM +0200, Avi Kivity wrote:
> On 03/15/2010 11:44 AM, Gleb Natapov wrote:
> >On Mon, Mar 15, 2010 at 09:44:26AM +0200, Avi Kivity wrote:
> >>On 03/14/2010 08:06 PM, Gleb Natapov wrote:
> >>>>Suggest simply reentering every N executions.
> >>>>
> >>>This restart mechanism is, in fact, needed for ins read ahead to work.
> >>>After reading ahead from IO port we need to avoid entering decoder
> >>>until entire cache is consumed otherwise decoder will clear cache and
> >>>data will be lost. So we can't just enter guest in arbitrary times, only
> >>>when read ahead cache is empty. Since read ahead is never done across
> >>>page boundary this is save place to re-enter guest.
> >>Please make the two depend on each other directly then. We can't
> >>expect the reader of the emulator code know that.
> >>
> >We can document that. I wouldn't want to have different conditions for
> >guest re-entry for different opcodes.
>
> We now have a write buffer size of one. It's just a matter of
> making the emulator know the size of the buffer (extra parameter to
> ->write_emulated).
>
The buffer is maintained inside emulator, so emulator knows about it and
can check it, but then for all other string instruction except INS we will
re-enter guest on each iteration.
> >>Have the emulator ask the buffer when it is empty.
> >>
> >It will be always empty for all string ops except INS.
> >
>
> Or we can make the buffer larger for everyone (outside this patchset
> though).
>
I am not sure what do you mean here. INS read ahead and MMIO read cache are
different beasts. Former is needed to speed-up string pio reads, later
(not yet implemented) is needed to reread previous MMIO read results in
case instruction emulation is restarted due to need to exit to userspace.
MMIO read cache need to be invalidated on each iteration of string
instruction.
--
Gleb.
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 28/30] KVM: x86 emulator: restart string instruction without going back to a guest.
2010-03-15 10:07 ` Gleb Natapov
@ 2010-03-15 10:15 ` Avi Kivity
2010-03-15 10:19 ` Gleb Natapov
0 siblings, 1 reply; 53+ messages in thread
From: Avi Kivity @ 2010-03-15 10:15 UTC (permalink / raw)
To: Gleb Natapov; +Cc: mtosatti, kvm
On 03/15/2010 12:07 PM, Gleb Natapov wrote:
>
>> Or we can make the buffer larger for everyone (outside this patchset
>> though).
>>
>>
> I am not sure what do you mean here. INS read ahead and MMIO read cache are
> different beasts. Former is needed to speed-up string pio reads, later
> (not yet implemented) is needed to reread previous MMIO read results in
> case instruction emulation is restarted due to need to exit to userspace.
> MMIO read cache need to be invalidated on each iteration of string
> instruction.
>
Instructions with multiple reads or writes need an mmio read/write
buffer that can be replayed on re-execution.
buffer != cache! A cache can be dropped (perhaps after flushing it to a
backing store), but a buffer in general cannot.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 28/30] KVM: x86 emulator: restart string instruction without going back to a guest.
2010-03-15 10:15 ` Avi Kivity
@ 2010-03-15 10:19 ` Gleb Natapov
2010-03-15 10:24 ` Avi Kivity
0 siblings, 1 reply; 53+ messages in thread
From: Gleb Natapov @ 2010-03-15 10:19 UTC (permalink / raw)
To: Avi Kivity; +Cc: mtosatti, kvm
On Mon, Mar 15, 2010 at 12:15:22PM +0200, Avi Kivity wrote:
> On 03/15/2010 12:07 PM, Gleb Natapov wrote:
> >
> >>Or we can make the buffer larger for everyone (outside this patchset
> >>though).
> >>
> >I am not sure what do you mean here. INS read ahead and MMIO read cache are
> >different beasts. Former is needed to speed-up string pio reads, later
> >(not yet implemented) is needed to reread previous MMIO read results in
> >case instruction emulation is restarted due to need to exit to userspace.
> >MMIO read cache need to be invalidated on each iteration of string
> >instruction.
>
> Instructions with multiple reads or writes need an mmio read/write
> buffer that can be replayed on re-execution.
>
> buffer != cache! A cache can be dropped (perhaps after flushing it
> to a backing store), but a buffer in general cannot.
>
That is just naming. Call it "buffer" if you want.
I still don't understand what do you mean by "Or we can make the buffer
larger for everyone". Who is this "everyone"? Different instruction need
different kind of buffers.
--
Gleb.
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 28/30] KVM: x86 emulator: restart string instruction without going back to a guest.
2010-03-15 10:19 ` Gleb Natapov
@ 2010-03-15 10:24 ` Avi Kivity
2010-03-15 10:33 ` Gleb Natapov
0 siblings, 1 reply; 53+ messages in thread
From: Avi Kivity @ 2010-03-15 10:24 UTC (permalink / raw)
To: Gleb Natapov; +Cc: mtosatti, kvm
On 03/15/2010 12:19 PM, Gleb Natapov wrote:
> On Mon, Mar 15, 2010 at 12:15:22PM +0200, Avi Kivity wrote:
>
>> On 03/15/2010 12:07 PM, Gleb Natapov wrote:
>>
>>>
>>>> Or we can make the buffer larger for everyone (outside this patchset
>>>> though).
>>>>
>>>>
>>> I am not sure what do you mean here. INS read ahead and MMIO read cache are
>>> different beasts. Former is needed to speed-up string pio reads, later
>>> (not yet implemented) is needed to reread previous MMIO read results in
>>> case instruction emulation is restarted due to need to exit to userspace.
>>> MMIO read cache need to be invalidated on each iteration of string
>>> instruction.
>>>
>> Instructions with multiple reads or writes need an mmio read/write
>> buffer that can be replayed on re-execution.
>>
>> buffer != cache! A cache can be dropped (perhaps after flushing it
>> to a backing store), but a buffer in general cannot.
>>
>>
> That is just naming. Call it "buffer" if you want.
>
> I still don't understand what do you mean by "Or we can make the buffer
> larger for everyone". Who is this "everyone"? Different instruction need
> different kind of buffers.
>
Many instructions can issue multiple reads, ins is just one of them. A
generic mmio buffer can be used by everyone.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 28/30] KVM: x86 emulator: restart string instruction without going back to a guest.
2010-03-15 10:24 ` Avi Kivity
@ 2010-03-15 10:33 ` Gleb Natapov
0 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-15 10:33 UTC (permalink / raw)
To: Avi Kivity; +Cc: mtosatti, kvm
On Mon, Mar 15, 2010 at 12:24:43PM +0200, Avi Kivity wrote:
> On 03/15/2010 12:19 PM, Gleb Natapov wrote:
> >On Mon, Mar 15, 2010 at 12:15:22PM +0200, Avi Kivity wrote:
> >>On 03/15/2010 12:07 PM, Gleb Natapov wrote:
> >>>>Or we can make the buffer larger for everyone (outside this patchset
> >>>>though).
> >>>>
> >>>I am not sure what do you mean here. INS read ahead and MMIO read cache are
> >>>different beasts. Former is needed to speed-up string pio reads, later
> >>>(not yet implemented) is needed to reread previous MMIO read results in
> >>>case instruction emulation is restarted due to need to exit to userspace.
> >>>MMIO read cache need to be invalidated on each iteration of string
> >>>instruction.
> >>Instructions with multiple reads or writes need an mmio read/write
> >>buffer that can be replayed on re-execution.
> >>
> >>buffer != cache! A cache can be dropped (perhaps after flushing it
> >>to a backing store), but a buffer in general cannot.
> >>
> >That is just naming. Call it "buffer" if you want.
> >
> >I still don't understand what do you mean by "Or we can make the buffer
> >larger for everyone". Who is this "everyone"? Different instruction need
> >different kind of buffers.
>
> Many instructions can issue multiple reads, ins is just one of them.
> A generic mmio buffer can be used by everyone.
>
No, ins can issue only _one_ io read during one iteration (i.e between
each pair of reads there is a commit point). But this is slow, so we do
non-architectural hack: do many reads ahead of time into a buffer and
use results from this buffer for emulation of subsequent iterations.
Other instruction can do multiple reads between instruction fetching and
commit of emulation result and need different kind of buffering
(actually caching is more appropriate here since we "cache" results of
reads from past attempts to emulation same instruction).
--
Gleb.
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 06/30] KVM: remove realmode_lmsw function.
2010-03-14 16:20 ` [PATCH v2 06/30] KVM: remove realmode_lmsw function Gleb Natapov
@ 2010-03-15 11:02 ` Andre Przywara
2010-03-15 11:41 ` Avi Kivity
0 siblings, 1 reply; 53+ messages in thread
From: Andre Przywara @ 2010-03-15 11:02 UTC (permalink / raw)
To: Gleb Natapov; +Cc: avi, mtosatti, kvm
Gleb Natapov wrote:
> Use (get|set)_cr callback to emulate lmsw inside emulator.
I see that vmx.c:handle_cr() is the only other user of kvm_lmsw(). If we
fix this place similar like you did below, we could get rid of
kvm_lmsw() entirely. But I am not sure whether it's OK to remove an
exported symbol.
Regards,
Andre.
>
> Signed-off-by: Gleb Natapov <gleb@redhat.com>
> ---
> arch/x86/include/asm/kvm_host.h | 2 --
> arch/x86/kvm/emulate.c | 4 ++--
> arch/x86/kvm/x86.c | 7 -------
> 3 files changed, 2 insertions(+), 11 deletions(-)
>
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index e8e108a..1e15a0a 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -582,8 +582,6 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
> void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context);
> void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
> void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
> -void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
> - unsigned long *rflags);
>
> void kvm_enable_efer_bits(u64);
> int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
> diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
> index 5b060e4..5e2fa61 100644
> --- a/arch/x86/kvm/emulate.c
> +++ b/arch/x86/kvm/emulate.c
> @@ -2486,8 +2486,8 @@ twobyte_insn:
> c->dst.val = ops->get_cr(0, ctxt->vcpu);
> break;
> case 6: /* lmsw */
> - realmode_lmsw(ctxt->vcpu, (u16)c->src.val,
> - &ctxt->eflags);
> + ops->set_cr(0, (ops->get_cr(0, ctxt->vcpu) & ~0x0ful) |
> + (c->src.val & 0x0f), ctxt->vcpu);
> c->dst.type = OP_NONE;
> break;
> case 7: /* invlpg*/
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index bf714df..b08f8a1 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -4045,13 +4045,6 @@ void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
> kvm_x86_ops->set_idt(vcpu, &dt);
> }
>
> -void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
> - unsigned long *rflags)
> -{
> - kvm_lmsw(vcpu, msw);
> - *rflags = kvm_get_rflags(vcpu);
> -}
> -
> static int move_to_next_stateful_cpuid_entry(struct kvm_vcpu *vcpu, int i)
> {
> struct kvm_cpuid_entry2 *e = &vcpu->arch.cpuid_entries[i];
--
Andre Przywara
AMD-OSRC (Dresden)
Tel: x29712
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 06/30] KVM: remove realmode_lmsw function.
2010-03-15 11:02 ` Andre Przywara
@ 2010-03-15 11:41 ` Avi Kivity
0 siblings, 0 replies; 53+ messages in thread
From: Avi Kivity @ 2010-03-15 11:41 UTC (permalink / raw)
To: Andre Przywara; +Cc: Gleb Natapov, mtosatti, kvm
On 03/15/2010 01:02 PM, Andre Przywara wrote:
> Gleb Natapov wrote:
>> Use (get|set)_cr callback to emulate lmsw inside emulator.
> I see that vmx.c:handle_cr() is the only other user of kvm_lmsw(). If
> we fix this place similar like you did below, we could get rid of
> kvm_lmsw() entirely. But I am not sure whether it's OK to remove an
> exported symbol.
Exported symbols can be changed or removed at will.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 05/30] KVM: Provide callback to get/set control registers in emulator ops.
2010-03-14 16:20 ` [PATCH v2 05/30] KVM: Provide callback to get/set control registers in emulator ops Gleb Natapov
@ 2010-03-15 13:06 ` Andre Przywara
2010-03-15 13:11 ` Gleb Natapov
2010-03-15 13:13 ` Avi Kivity
0 siblings, 2 replies; 53+ messages in thread
From: Andre Przywara @ 2010-03-15 13:06 UTC (permalink / raw)
To: Gleb Natapov; +Cc: avi, mtosatti, kvm
Gleb Natapov wrote:
> Use this callback instead of directly call kvm function. Also rename
> realmode_(set|get)_cr to emulator_(set|get)_cr since function has nothing
> to do with real mode.
Do you mind removing the static before emulator_{set,get}_cr and marking
it EXPORT_SYMBOL? Then one could use it in vmx.c (and soon in svm.c ;-)
while handling MOV-CR intercepts. Currently most of the code is actually
duplicated.
Also, shouldn't mk_cr_64() not be called mask_cr_64() for better
readability?
Regards,
Andre.
> Signed-off-by: Gleb Natapov <gleb@redhat.com>
> ---
> arch/x86/include/asm/kvm_emulate.h | 3 +-
> arch/x86/include/asm/kvm_host.h | 2 -
> arch/x86/kvm/emulate.c | 7 +-
> arch/x86/kvm/x86.c | 114 ++++++++++++++++++------------------
> 4 files changed, 63 insertions(+), 63 deletions(-)
>
> diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
> index 2666d7a..0c5caa4 100644
> --- a/arch/x86/include/asm/kvm_emulate.h
> +++ b/arch/x86/include/asm/kvm_emulate.h
> @@ -108,7 +108,8 @@ struct x86_emulate_ops {
> const void *new,
> unsigned int bytes,
> struct kvm_vcpu *vcpu);
> -
> + ulong (*get_cr)(int cr, struct kvm_vcpu *vcpu);
> + void (*set_cr)(int cr, ulong val, struct kvm_vcpu *vcpu);
> };
>
> /* Type, address-of, and value of an instruction's operand. */
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index 3b178d8..e8e108a 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -585,8 +585,6 @@ void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
> void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
> unsigned long *rflags);
>
> -unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr);
> -void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value);
> void kvm_enable_efer_bits(u64);
> int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
> int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
> diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
> index 91450b5..5b060e4 100644
> --- a/arch/x86/kvm/emulate.c
> +++ b/arch/x86/kvm/emulate.c
> @@ -2483,7 +2483,7 @@ twobyte_insn:
> break;
> case 4: /* smsw */
> c->dst.bytes = 2;
> - c->dst.val = realmode_get_cr(ctxt->vcpu, 0);
> + c->dst.val = ops->get_cr(0, ctxt->vcpu);
> break;
> case 6: /* lmsw */
> realmode_lmsw(ctxt->vcpu, (u16)c->src.val,
> @@ -2519,8 +2519,7 @@ twobyte_insn:
> case 0x20: /* mov cr, reg */
> if (c->modrm_mod != 3)
> goto cannot_emulate;
> - c->regs[c->modrm_rm] =
> - realmode_get_cr(ctxt->vcpu, c->modrm_reg);
> + c->regs[c->modrm_rm] = ops->get_cr(c->modrm_reg, ctxt->vcpu);
> c->dst.type = OP_NONE; /* no writeback */
> break;
> case 0x21: /* mov from dr to reg */
> @@ -2534,7 +2533,7 @@ twobyte_insn:
> case 0x22: /* mov reg, cr */
> if (c->modrm_mod != 3)
> goto cannot_emulate;
> - realmode_set_cr(ctxt->vcpu, c->modrm_reg, c->modrm_val);
> + ops->set_cr(c->modrm_reg, c->modrm_val, ctxt->vcpu);
> c->dst.type = OP_NONE;
> break;
> case 0x23: /* mov from reg to dr */
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index a1e671a..bf714df 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -3370,12 +3370,70 @@ void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
> }
> EXPORT_SYMBOL_GPL(kvm_report_emulation_failure);
>
> +static u64 mk_cr_64(u64 curr_cr, u32 new_val)
> +{
> + return (curr_cr & ~((1ULL << 32) - 1)) | new_val;
> +}
> +
> +static unsigned long emulator_get_cr(int cr, struct kvm_vcpu *vcpu)
> +{
> + unsigned long value;
> +
> + switch (cr) {
> + case 0:
> + value = kvm_read_cr0(vcpu);
> + break;
> + case 2:
> + value = vcpu->arch.cr2;
> + break;
> + case 3:
> + value = vcpu->arch.cr3;
> + break;
> + case 4:
> + value = kvm_read_cr4(vcpu);
> + break;
> + case 8:
> + value = kvm_get_cr8(vcpu);
> + break;
> + default:
> + vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
> + return 0;
> + }
> +
> + return value;
> +}
> +
> +static void emulator_set_cr(int cr, unsigned long val, struct kvm_vcpu *vcpu)
> +{
> + switch (cr) {
> + case 0:
> + kvm_set_cr0(vcpu, mk_cr_64(kvm_read_cr0(vcpu), val));
> + break;
> + case 2:
> + vcpu->arch.cr2 = val;
> + break;
> + case 3:
> + kvm_set_cr3(vcpu, val);
> + break;
> + case 4:
> + kvm_set_cr4(vcpu, mk_cr_64(kvm_read_cr4(vcpu), val));
> + break;
> + case 8:
> + kvm_set_cr8(vcpu, val & 0xfUL);
> + break;
> + default:
> + vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
> + }
> +}
> +
> static struct x86_emulate_ops emulate_ops = {
> .read_std = kvm_read_guest_virt_system,
> .fetch = kvm_fetch_guest_virt,
> .read_emulated = emulator_read_emulated,
> .write_emulated = emulator_write_emulated,
> .cmpxchg_emulated = emulator_cmpxchg_emulated,
> + .get_cr = emulator_get_cr,
> + .set_cr = emulator_set_cr,
> };
>
> static void cache_all_regs(struct kvm_vcpu *vcpu)
> @@ -3973,11 +4031,6 @@ int kvm_fix_hypercall(struct kvm_vcpu *vcpu)
> return emulator_write_emulated(rip, instruction, 3, vcpu);
> }
>
> -static u64 mk_cr_64(u64 curr_cr, u32 new_val)
> -{
> - return (curr_cr & ~((1ULL << 32) - 1)) | new_val;
> -}
> -
> void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
> {
> struct desc_ptr dt = { limit, base };
> @@ -3999,57 +4052,6 @@ void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
> *rflags = kvm_get_rflags(vcpu);
> }
>
> -unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
> -{
> - unsigned long value;
> -
> - switch (cr) {
> - case 0:
> - value = kvm_read_cr0(vcpu);
> - break;
> - case 2:
> - value = vcpu->arch.cr2;
> - break;
> - case 3:
> - value = vcpu->arch.cr3;
> - break;
> - case 4:
> - value = kvm_read_cr4(vcpu);
> - break;
> - case 8:
> - value = kvm_get_cr8(vcpu);
> - break;
> - default:
> - vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
> - return 0;
> - }
> -
> - return value;
> -}
> -
> -void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val)
> -{
> - switch (cr) {
> - case 0:
> - kvm_set_cr0(vcpu, mk_cr_64(kvm_read_cr0(vcpu), val));
> - break;
> - case 2:
> - vcpu->arch.cr2 = val;
> - break;
> - case 3:
> - kvm_set_cr3(vcpu, val);
> - break;
> - case 4:
> - kvm_set_cr4(vcpu, mk_cr_64(kvm_read_cr4(vcpu), val));
> - break;
> - case 8:
> - kvm_set_cr8(vcpu, val & 0xfUL);
> - break;
> - default:
> - vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
> - }
> -}
> -
> static int move_to_next_stateful_cpuid_entry(struct kvm_vcpu *vcpu, int i)
> {
> struct kvm_cpuid_entry2 *e = &vcpu->arch.cpuid_entries[i];
--
Andre Przywara
AMD-OSRC (Dresden)
Tel: x29712
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 05/30] KVM: Provide callback to get/set control registers in emulator ops.
2010-03-15 13:06 ` Andre Przywara
@ 2010-03-15 13:11 ` Gleb Natapov
2010-03-15 13:13 ` Avi Kivity
1 sibling, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-15 13:11 UTC (permalink / raw)
To: Andre Przywara; +Cc: avi, mtosatti, kvm
On Mon, Mar 15, 2010 at 02:06:48PM +0100, Andre Przywara wrote:
> Gleb Natapov wrote:
> >Use this callback instead of directly call kvm function. Also rename
> >realmode_(set|get)_cr to emulator_(set|get)_cr since function has nothing
> >to do with real mode.
> Do you mind removing the static before emulator_{set,get}_cr and
I don't, but this is not the goal of this patch series.
> marking it EXPORT_SYMBOL? Then one could use it in vmx.c (and soon
> in svm.c ;-) while handling MOV-CR intercepts. Currently most of the
> code is actually duplicated.
>
> Also, shouldn't mk_cr_64() not be called mask_cr_64() for better
> readability?
This is how it is called now, the patch only moves it. But this code
will be reworked by later patches anyway since functions called from
emulator should not inject exceptions behind emulator's back.
>
> Regards,
> Andre.
>
> >Signed-off-by: Gleb Natapov <gleb@redhat.com>
> >---
> > arch/x86/include/asm/kvm_emulate.h | 3 +-
> > arch/x86/include/asm/kvm_host.h | 2 -
> > arch/x86/kvm/emulate.c | 7 +-
> > arch/x86/kvm/x86.c | 114 ++++++++++++++++++------------------
> > 4 files changed, 63 insertions(+), 63 deletions(-)
> >
> >diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
> >index 2666d7a..0c5caa4 100644
> >--- a/arch/x86/include/asm/kvm_emulate.h
> >+++ b/arch/x86/include/asm/kvm_emulate.h
> >@@ -108,7 +108,8 @@ struct x86_emulate_ops {
> > const void *new,
> > unsigned int bytes,
> > struct kvm_vcpu *vcpu);
> >-
> >+ ulong (*get_cr)(int cr, struct kvm_vcpu *vcpu);
> >+ void (*set_cr)(int cr, ulong val, struct kvm_vcpu *vcpu);
> > };
> > /* Type, address-of, and value of an instruction's operand. */
> >diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> >index 3b178d8..e8e108a 100644
> >--- a/arch/x86/include/asm/kvm_host.h
> >+++ b/arch/x86/include/asm/kvm_host.h
> >@@ -585,8 +585,6 @@ void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
> > void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
> > unsigned long *rflags);
> >-unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr);
> >-void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value);
> > void kvm_enable_efer_bits(u64);
> > int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
> > int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
> >diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
> >index 91450b5..5b060e4 100644
> >--- a/arch/x86/kvm/emulate.c
> >+++ b/arch/x86/kvm/emulate.c
> >@@ -2483,7 +2483,7 @@ twobyte_insn:
> > break;
> > case 4: /* smsw */
> > c->dst.bytes = 2;
> >- c->dst.val = realmode_get_cr(ctxt->vcpu, 0);
> >+ c->dst.val = ops->get_cr(0, ctxt->vcpu);
> > break;
> > case 6: /* lmsw */
> > realmode_lmsw(ctxt->vcpu, (u16)c->src.val,
> >@@ -2519,8 +2519,7 @@ twobyte_insn:
> > case 0x20: /* mov cr, reg */
> > if (c->modrm_mod != 3)
> > goto cannot_emulate;
> >- c->regs[c->modrm_rm] =
> >- realmode_get_cr(ctxt->vcpu, c->modrm_reg);
> >+ c->regs[c->modrm_rm] = ops->get_cr(c->modrm_reg, ctxt->vcpu);
> > c->dst.type = OP_NONE; /* no writeback */
> > break;
> > case 0x21: /* mov from dr to reg */
> >@@ -2534,7 +2533,7 @@ twobyte_insn:
> > case 0x22: /* mov reg, cr */
> > if (c->modrm_mod != 3)
> > goto cannot_emulate;
> >- realmode_set_cr(ctxt->vcpu, c->modrm_reg, c->modrm_val);
> >+ ops->set_cr(c->modrm_reg, c->modrm_val, ctxt->vcpu);
> > c->dst.type = OP_NONE;
> > break;
> > case 0x23: /* mov from reg to dr */
> >diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> >index a1e671a..bf714df 100644
> >--- a/arch/x86/kvm/x86.c
> >+++ b/arch/x86/kvm/x86.c
> >@@ -3370,12 +3370,70 @@ void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
> > }
> > EXPORT_SYMBOL_GPL(kvm_report_emulation_failure);
> >+static u64 mk_cr_64(u64 curr_cr, u32 new_val)
> >+{
> >+ return (curr_cr & ~((1ULL << 32) - 1)) | new_val;
> >+}
> >+
> >+static unsigned long emulator_get_cr(int cr, struct kvm_vcpu *vcpu)
> >+{
> >+ unsigned long value;
> >+
> >+ switch (cr) {
> >+ case 0:
> >+ value = kvm_read_cr0(vcpu);
> >+ break;
> >+ case 2:
> >+ value = vcpu->arch.cr2;
> >+ break;
> >+ case 3:
> >+ value = vcpu->arch.cr3;
> >+ break;
> >+ case 4:
> >+ value = kvm_read_cr4(vcpu);
> >+ break;
> >+ case 8:
> >+ value = kvm_get_cr8(vcpu);
> >+ break;
> >+ default:
> >+ vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
> >+ return 0;
> >+ }
> >+
> >+ return value;
> >+}
> >+
> >+static void emulator_set_cr(int cr, unsigned long val, struct kvm_vcpu *vcpu)
> >+{
> >+ switch (cr) {
> >+ case 0:
> >+ kvm_set_cr0(vcpu, mk_cr_64(kvm_read_cr0(vcpu), val));
> >+ break;
> >+ case 2:
> >+ vcpu->arch.cr2 = val;
> >+ break;
> >+ case 3:
> >+ kvm_set_cr3(vcpu, val);
> >+ break;
> >+ case 4:
> >+ kvm_set_cr4(vcpu, mk_cr_64(kvm_read_cr4(vcpu), val));
> >+ break;
> >+ case 8:
> >+ kvm_set_cr8(vcpu, val & 0xfUL);
> >+ break;
> >+ default:
> >+ vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
> >+ }
> >+}
> >+
> > static struct x86_emulate_ops emulate_ops = {
> > .read_std = kvm_read_guest_virt_system,
> > .fetch = kvm_fetch_guest_virt,
> > .read_emulated = emulator_read_emulated,
> > .write_emulated = emulator_write_emulated,
> > .cmpxchg_emulated = emulator_cmpxchg_emulated,
> >+ .get_cr = emulator_get_cr,
> >+ .set_cr = emulator_set_cr,
> > };
> > static void cache_all_regs(struct kvm_vcpu *vcpu)
> >@@ -3973,11 +4031,6 @@ int kvm_fix_hypercall(struct kvm_vcpu *vcpu)
> > return emulator_write_emulated(rip, instruction, 3, vcpu);
> > }
> >-static u64 mk_cr_64(u64 curr_cr, u32 new_val)
> >-{
> >- return (curr_cr & ~((1ULL << 32) - 1)) | new_val;
> >-}
> >-
> > void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
> > {
> > struct desc_ptr dt = { limit, base };
> >@@ -3999,57 +4052,6 @@ void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
> > *rflags = kvm_get_rflags(vcpu);
> > }
> >-unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
> >-{
> >- unsigned long value;
> >-
> >- switch (cr) {
> >- case 0:
> >- value = kvm_read_cr0(vcpu);
> >- break;
> >- case 2:
> >- value = vcpu->arch.cr2;
> >- break;
> >- case 3:
> >- value = vcpu->arch.cr3;
> >- break;
> >- case 4:
> >- value = kvm_read_cr4(vcpu);
> >- break;
> >- case 8:
> >- value = kvm_get_cr8(vcpu);
> >- break;
> >- default:
> >- vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
> >- return 0;
> >- }
> >-
> >- return value;
> >-}
> >-
> >-void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val)
> >-{
> >- switch (cr) {
> >- case 0:
> >- kvm_set_cr0(vcpu, mk_cr_64(kvm_read_cr0(vcpu), val));
> >- break;
> >- case 2:
> >- vcpu->arch.cr2 = val;
> >- break;
> >- case 3:
> >- kvm_set_cr3(vcpu, val);
> >- break;
> >- case 4:
> >- kvm_set_cr4(vcpu, mk_cr_64(kvm_read_cr4(vcpu), val));
> >- break;
> >- case 8:
> >- kvm_set_cr8(vcpu, val & 0xfUL);
> >- break;
> >- default:
> >- vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
> >- }
> >-}
> >-
> > static int move_to_next_stateful_cpuid_entry(struct kvm_vcpu *vcpu, int i)
> > {
> > struct kvm_cpuid_entry2 *e = &vcpu->arch.cpuid_entries[i];
>
>
> --
> Andre Przywara
> AMD-OSRC (Dresden)
> Tel: x29712
--
Gleb.
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 05/30] KVM: Provide callback to get/set control registers in emulator ops.
2010-03-15 13:06 ` Andre Przywara
2010-03-15 13:11 ` Gleb Natapov
@ 2010-03-15 13:13 ` Avi Kivity
1 sibling, 0 replies; 53+ messages in thread
From: Avi Kivity @ 2010-03-15 13:13 UTC (permalink / raw)
To: Andre Przywara; +Cc: Gleb Natapov, mtosatti, kvm
On 03/15/2010 03:06 PM, Andre Przywara wrote:
> Gleb Natapov wrote:
>> Use this callback instead of directly call kvm function. Also rename
>> realmode_(set|get)_cr to emulator_(set|get)_cr since function has
>> nothing
>> to do with real mode.
> Do you mind removing the static before emulator_{set,get}_cr and
> marking it EXPORT_SYMBOL? Then one could use it in vmx.c (and soon in
> svm.c ;-) while handling MOV-CR intercepts. Currently most of the code
> is actually duplicated.
Just do that in your patch, that's standard practice.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 07/30] KVM: Provide x86_emulate_ctxt callback to get current cpl
2010-03-14 16:20 ` [PATCH v2 07/30] KVM: Provide x86_emulate_ctxt callback to get current cpl Gleb Natapov
@ 2010-03-15 13:16 ` Andre Przywara
2010-03-15 13:21 ` Gleb Natapov
0 siblings, 1 reply; 53+ messages in thread
From: Andre Przywara @ 2010-03-15 13:16 UTC (permalink / raw)
To: Gleb Natapov; +Cc: avi, mtosatti, kvm
Gleb,
what is the purpose of this patch? Is this a preparation for something
upcoming? I don't see a reason to change this, in my eyes it is not a
simplification.
Regards,
Andre.
Gleb Natapov wrote:
> Signed-off-by: Gleb Natapov <gleb@redhat.com>
> ---
> arch/x86/include/asm/kvm_emulate.h | 1 +
> arch/x86/kvm/emulate.c | 15 ++++++++-------
> arch/x86/kvm/x86.c | 6 ++++++
> 3 files changed, 15 insertions(+), 7 deletions(-)
>
> diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
> index 0c5caa4..b048fd2 100644
> --- a/arch/x86/include/asm/kvm_emulate.h
> +++ b/arch/x86/include/asm/kvm_emulate.h
> @@ -110,6 +110,7 @@ struct x86_emulate_ops {
> struct kvm_vcpu *vcpu);
> ulong (*get_cr)(int cr, struct kvm_vcpu *vcpu);
> void (*set_cr)(int cr, ulong val, struct kvm_vcpu *vcpu);
> + int (*cpl)(struct kvm_vcpu *vcpu);
> };
>
> /* Type, address-of, and value of an instruction's operand. */
> diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
> index 5e2fa61..8bd0557 100644
> --- a/arch/x86/kvm/emulate.c
> +++ b/arch/x86/kvm/emulate.c
> @@ -1257,7 +1257,7 @@ static int emulate_popf(struct x86_emulate_ctxt *ctxt,
> int rc;
> unsigned long val, change_mask;
> int iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
> - int cpl = kvm_x86_ops->get_cpl(ctxt->vcpu);
> + int cpl = ops->cpl(ctxt->vcpu);
>
> rc = emulate_pop(ctxt, ops, &val, len);
> if (rc != X86EMUL_CONTINUE)
> @@ -1758,7 +1758,8 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
> return X86EMUL_CONTINUE;
> }
>
> -static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt)
> +static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt,
> + struct x86_emulate_ops *ops)
> {
> int iopl;
> if (ctxt->mode == X86EMUL_MODE_REAL)
> @@ -1766,7 +1767,7 @@ static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt)
> if (ctxt->mode == X86EMUL_MODE_VM86)
> return true;
> iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
> - return kvm_x86_ops->get_cpl(ctxt->vcpu) > iopl;
> + return ops->cpl(ctxt->vcpu) > iopl;
> }
>
> static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt,
> @@ -1803,7 +1804,7 @@ static bool emulator_io_permited(struct x86_emulate_ctxt *ctxt,
> struct x86_emulate_ops *ops,
> u16 port, u16 len)
> {
> - if (emulator_bad_iopl(ctxt))
> + if (emulator_bad_iopl(ctxt, ops))
> if (!emulator_io_port_access_allowed(ctxt, ops, port, len))
> return false;
> return true;
> @@ -1842,7 +1843,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
> }
>
> /* Privileged instruction can be executed only in CPL=0 */
> - if ((c->d & Priv) && kvm_x86_ops->get_cpl(ctxt->vcpu)) {
> + if ((c->d & Priv) && ops->cpl(ctxt->vcpu)) {
> kvm_inject_gp(ctxt->vcpu, 0);
> goto done;
> }
> @@ -2378,7 +2379,7 @@ special_insn:
> c->dst.type = OP_NONE; /* Disable writeback. */
> break;
> case 0xfa: /* cli */
> - if (emulator_bad_iopl(ctxt))
> + if (emulator_bad_iopl(ctxt, ops))
> kvm_inject_gp(ctxt->vcpu, 0);
> else {
> ctxt->eflags &= ~X86_EFLAGS_IF;
> @@ -2386,7 +2387,7 @@ special_insn:
> }
> break;
> case 0xfb: /* sti */
> - if (emulator_bad_iopl(ctxt))
> + if (emulator_bad_iopl(ctxt, ops))
> kvm_inject_gp(ctxt->vcpu, 0);
> else {
> toggle_interruptibility(ctxt, KVM_X86_SHADOW_INT_STI);
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index b08f8a1..3f2a8d3 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -3426,6 +3426,11 @@ static void emulator_set_cr(int cr, unsigned long val, struct kvm_vcpu *vcpu)
> }
> }
>
> +static int emulator_get_cpl(struct kvm_vcpu *vcpu)
> +{
> + return kvm_x86_ops->get_cpl(vcpu);
> +}
> +
> static struct x86_emulate_ops emulate_ops = {
> .read_std = kvm_read_guest_virt_system,
> .fetch = kvm_fetch_guest_virt,
> @@ -3434,6 +3439,7 @@ static struct x86_emulate_ops emulate_ops = {
> .cmpxchg_emulated = emulator_cmpxchg_emulated,
> .get_cr = emulator_get_cr,
> .set_cr = emulator_set_cr,
> + .cpl = emulator_get_cpl,
> };
>
> static void cache_all_regs(struct kvm_vcpu *vcpu)
--
Andre Przywara
AMD-OSRC (Dresden)
Tel: x29712
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 07/30] KVM: Provide x86_emulate_ctxt callback to get current cpl
2010-03-15 13:16 ` Andre Przywara
@ 2010-03-15 13:21 ` Gleb Natapov
0 siblings, 0 replies; 53+ messages in thread
From: Gleb Natapov @ 2010-03-15 13:21 UTC (permalink / raw)
To: Andre Przywara; +Cc: avi, mtosatti, kvm
On Mon, Mar 15, 2010 at 02:16:01PM +0100, Andre Przywara wrote:
> Gleb,
>
> what is the purpose of this patch? Is this a preparation for
> something upcoming? I don't see a reason to change this, in my eyes
> it is not a simplification.
>
To make emulator independent of KVM. All direct calls from emulator to
KVM will be changed to callbacks.
> Regards,
> Andre.
>
>
> Gleb Natapov wrote:
> >Signed-off-by: Gleb Natapov <gleb@redhat.com>
> >---
> > arch/x86/include/asm/kvm_emulate.h | 1 +
> > arch/x86/kvm/emulate.c | 15 ++++++++-------
> > arch/x86/kvm/x86.c | 6 ++++++
> > 3 files changed, 15 insertions(+), 7 deletions(-)
> >
> >diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
> >index 0c5caa4..b048fd2 100644
> >--- a/arch/x86/include/asm/kvm_emulate.h
> >+++ b/arch/x86/include/asm/kvm_emulate.h
> >@@ -110,6 +110,7 @@ struct x86_emulate_ops {
> > struct kvm_vcpu *vcpu);
> > ulong (*get_cr)(int cr, struct kvm_vcpu *vcpu);
> > void (*set_cr)(int cr, ulong val, struct kvm_vcpu *vcpu);
> >+ int (*cpl)(struct kvm_vcpu *vcpu);
> > };
> > /* Type, address-of, and value of an instruction's operand. */
> >diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
> >index 5e2fa61..8bd0557 100644
> >--- a/arch/x86/kvm/emulate.c
> >+++ b/arch/x86/kvm/emulate.c
> >@@ -1257,7 +1257,7 @@ static int emulate_popf(struct x86_emulate_ctxt *ctxt,
> > int rc;
> > unsigned long val, change_mask;
> > int iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
> >- int cpl = kvm_x86_ops->get_cpl(ctxt->vcpu);
> >+ int cpl = ops->cpl(ctxt->vcpu);
> > rc = emulate_pop(ctxt, ops, &val, len);
> > if (rc != X86EMUL_CONTINUE)
> >@@ -1758,7 +1758,8 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
> > return X86EMUL_CONTINUE;
> > }
> >-static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt)
> >+static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt,
> >+ struct x86_emulate_ops *ops)
> > {
> > int iopl;
> > if (ctxt->mode == X86EMUL_MODE_REAL)
> >@@ -1766,7 +1767,7 @@ static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt)
> > if (ctxt->mode == X86EMUL_MODE_VM86)
> > return true;
> > iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
> >- return kvm_x86_ops->get_cpl(ctxt->vcpu) > iopl;
> >+ return ops->cpl(ctxt->vcpu) > iopl;
> > }
> > static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt,
> >@@ -1803,7 +1804,7 @@ static bool emulator_io_permited(struct x86_emulate_ctxt *ctxt,
> > struct x86_emulate_ops *ops,
> > u16 port, u16 len)
> > {
> >- if (emulator_bad_iopl(ctxt))
> >+ if (emulator_bad_iopl(ctxt, ops))
> > if (!emulator_io_port_access_allowed(ctxt, ops, port, len))
> > return false;
> > return true;
> >@@ -1842,7 +1843,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
> > }
> > /* Privileged instruction can be executed only in CPL=0 */
> >- if ((c->d & Priv) && kvm_x86_ops->get_cpl(ctxt->vcpu)) {
> >+ if ((c->d & Priv) && ops->cpl(ctxt->vcpu)) {
> > kvm_inject_gp(ctxt->vcpu, 0);
> > goto done;
> > }
> >@@ -2378,7 +2379,7 @@ special_insn:
> > c->dst.type = OP_NONE; /* Disable writeback. */
> > break;
> > case 0xfa: /* cli */
> >- if (emulator_bad_iopl(ctxt))
> >+ if (emulator_bad_iopl(ctxt, ops))
> > kvm_inject_gp(ctxt->vcpu, 0);
> > else {
> > ctxt->eflags &= ~X86_EFLAGS_IF;
> >@@ -2386,7 +2387,7 @@ special_insn:
> > }
> > break;
> > case 0xfb: /* sti */
> >- if (emulator_bad_iopl(ctxt))
> >+ if (emulator_bad_iopl(ctxt, ops))
> > kvm_inject_gp(ctxt->vcpu, 0);
> > else {
> > toggle_interruptibility(ctxt, KVM_X86_SHADOW_INT_STI);
> >diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> >index b08f8a1..3f2a8d3 100644
> >--- a/arch/x86/kvm/x86.c
> >+++ b/arch/x86/kvm/x86.c
> >@@ -3426,6 +3426,11 @@ static void emulator_set_cr(int cr, unsigned long val, struct kvm_vcpu *vcpu)
> > }
> > }
> >+static int emulator_get_cpl(struct kvm_vcpu *vcpu)
> >+{
> >+ return kvm_x86_ops->get_cpl(vcpu);
> >+}
> >+
> > static struct x86_emulate_ops emulate_ops = {
> > .read_std = kvm_read_guest_virt_system,
> > .fetch = kvm_fetch_guest_virt,
> >@@ -3434,6 +3439,7 @@ static struct x86_emulate_ops emulate_ops = {
> > .cmpxchg_emulated = emulator_cmpxchg_emulated,
> > .get_cr = emulator_get_cr,
> > .set_cr = emulator_set_cr,
> >+ .cpl = emulator_get_cpl,
> > };
> > static void cache_all_regs(struct kvm_vcpu *vcpu)
>
>
> --
> Andre Przywara
> AMD-OSRC (Dresden)
> Tel: x29712
--
Gleb.
^ permalink raw reply [flat|nested] 53+ messages in thread
end of thread, other threads:[~2010-03-15 13:21 UTC | newest]
Thread overview: 53+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-03-14 16:20 [PATCH v2 00/30] emulator cleanup Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 01/30] KVM: x86 emulator: Fix DstAcc decoding Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 02/30] KVM: x86 emulator: fix RCX access during rep emulation Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 03/30] KVM: x86 emulator: check return value against correct define Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 04/30] KVM: Remove pointer to rflags from realmode_set_cr parameters Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 05/30] KVM: Provide callback to get/set control registers in emulator ops Gleb Natapov
2010-03-15 13:06 ` Andre Przywara
2010-03-15 13:11 ` Gleb Natapov
2010-03-15 13:13 ` Avi Kivity
2010-03-14 16:20 ` [PATCH v2 06/30] KVM: remove realmode_lmsw function Gleb Natapov
2010-03-15 11:02 ` Andre Przywara
2010-03-15 11:41 ` Avi Kivity
2010-03-14 16:20 ` [PATCH v2 07/30] KVM: Provide x86_emulate_ctxt callback to get current cpl Gleb Natapov
2010-03-15 13:16 ` Andre Przywara
2010-03-15 13:21 ` Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 08/30] KVM: Provide current eip as part of emulator context Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 09/30] KVM: x86 emulator: fix mov r/m, sreg emulation Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 10/30] KVM: x86 emulator: fix 0f 01 /5 emulation Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 11/30] KVM: x86 emulator: 0f (20|21|22|23) ignore mod bits Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 12/30] KVM: x86 emulator: inject #UD on access to non-existing CR Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 13/30] KVM: x86 emulator: fix mov dr to inject #UD when needed Gleb Natapov
2010-03-14 16:20 ` [PATCH v2 14/30] KVM: x86 emulator: fix return values of syscall/sysenter/sysexit emulations Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 15/30] KVM: x86 emulator: do not call writeback if msr access fails Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 16/30] KVM: x86 emulator: If LOCK prefix is used dest arg should be memory Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 17/30] KVM: x86 emulator: cleanup grp3 return value Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 18/30] KVM: x86 emulator: Provide more callbacks for x86 emulator Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 19/30] KVM: x86 emulator: Emulate task switch in emulator.c Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 20/30] KVM: x86 emulator: Use load_segment_descriptor() instead of kvm_load_segment_descriptor() Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 21/30] KVM: Use task switch from emulator.c Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 22/30] KVM: x86 emulator: populate OP_MEM operand during decoding Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 23/30] KVM: x86 emulator: add decoding of X,Y parameters from Intel SDM Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 24/30] KVM: x86 emulator: during rep emulation decrement ECX only if emulation succeeded Gleb Natapov
2010-03-14 16:42 ` Avi Kivity
2010-03-14 16:21 ` [PATCH v2 25/30] KVM: x86 emulator: fix in/out emulation Gleb Natapov
2010-03-14 16:54 ` Avi Kivity
2010-03-14 17:35 ` Gleb Natapov
2010-03-15 7:41 ` Avi Kivity
2010-03-15 7:44 ` Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 26/30] KVM: x86 emulator: Move string pio emulation into emulator.c Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 27/30] KVM: x86 emulator: remove saved_eip Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 28/30] KVM: x86 emulator: restart string instruction without going back to a guest Gleb Natapov
2010-03-14 16:56 ` Avi Kivity
2010-03-14 18:06 ` Gleb Natapov
2010-03-15 7:44 ` Avi Kivity
2010-03-15 9:44 ` Gleb Natapov
2010-03-15 9:56 ` Avi Kivity
2010-03-15 10:07 ` Gleb Natapov
2010-03-15 10:15 ` Avi Kivity
2010-03-15 10:19 ` Gleb Natapov
2010-03-15 10:24 ` Avi Kivity
2010-03-15 10:33 ` Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 29/30] KVM: x86 emulator: introduce pio in string read ahead Gleb Natapov
2010-03-14 16:21 ` [PATCH v2 30/30] KVM: small kvm_arch_vcpu_ioctl_run() cleanup Gleb Natapov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox