Skip to content

Commit

Permalink
KVM: x86 emulator: lazily evaluate segment registers
Browse files Browse the repository at this point in the history
Instead of prefetching all segment bases before emulation, read them at the
last moment.  Since most of them are unneeded, we save some cycles on
Intel machines where this is a bit expensive.

Signed-off-by: Avi Kivity <avi@qumranet.com>
  • Loading branch information
Avi Kivity committed Jul 20, 2008
1 parent 0adc867 commit 7a5b56d
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 67 deletions.
21 changes: 0 additions & 21 deletions arch/x86/kvm/x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -2126,27 +2126,6 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
? X86EMUL_MODE_PROT64 : cs_db
? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;

if (vcpu->arch.emulate_ctxt.mode == X86EMUL_MODE_PROT64) {
vcpu->arch.emulate_ctxt.cs_base = 0;
vcpu->arch.emulate_ctxt.ds_base = 0;
vcpu->arch.emulate_ctxt.es_base = 0;
vcpu->arch.emulate_ctxt.ss_base = 0;
} else {
vcpu->arch.emulate_ctxt.cs_base =
get_segment_base(vcpu, VCPU_SREG_CS);
vcpu->arch.emulate_ctxt.ds_base =
get_segment_base(vcpu, VCPU_SREG_DS);
vcpu->arch.emulate_ctxt.es_base =
get_segment_base(vcpu, VCPU_SREG_ES);
vcpu->arch.emulate_ctxt.ss_base =
get_segment_base(vcpu, VCPU_SREG_SS);
}

vcpu->arch.emulate_ctxt.gs_base =
get_segment_base(vcpu, VCPU_SREG_GS);
vcpu->arch.emulate_ctxt.fs_base =
get_segment_base(vcpu, VCPU_SREG_FS);

r = x86_decode_insn(&vcpu->arch.emulate_ctxt, &emulate_ops);

/* Reject the instructions other than VMCALL/VMMCALL when
Expand Down
96 changes: 57 additions & 39 deletions arch/x86/kvm/x86_emulate.c
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,39 @@ static inline void jmp_rel(struct decode_cache *c, int rel)
register_address_increment(c, &c->eip, rel);
}

static void set_seg_override(struct decode_cache *c, int seg)
{
c->has_seg_override = true;
c->seg_override = seg;
}

static unsigned long seg_base(struct x86_emulate_ctxt *ctxt, int seg)
{
if (ctxt->mode == X86EMUL_MODE_PROT64 && seg < VCPU_SREG_FS)
return 0;

return kvm_x86_ops->get_segment_base(ctxt->vcpu, seg);
}

static unsigned long seg_override_base(struct x86_emulate_ctxt *ctxt,
struct decode_cache *c)
{
if (!c->has_seg_override)
return 0;

return seg_base(ctxt, c->seg_override);
}

static unsigned long es_base(struct x86_emulate_ctxt *ctxt)
{
return seg_base(ctxt, VCPU_SREG_ES);
}

static unsigned long ss_base(struct x86_emulate_ctxt *ctxt)
{
return seg_base(ctxt, VCPU_SREG_SS);
}

static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops,
unsigned long linear, u8 *dest)
Expand Down Expand Up @@ -735,8 +768,8 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
}
if (c->modrm_rm == 2 || c->modrm_rm == 3 ||
(c->modrm_rm == 6 && c->modrm_mod != 0))
if (!c->override_base)
c->override_base = &ctxt->ss_base;
if (!c->has_seg_override)
set_seg_override(c, VCPU_SREG_SS);
c->modrm_ea = (u16)c->modrm_ea;
} else {
/* 32/64-bit ModR/M decode. */
Expand Down Expand Up @@ -807,6 +840,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)

memset(c, 0, sizeof(struct decode_cache));
c->eip = ctxt->vcpu->arch.rip;
ctxt->cs_base = seg_base(ctxt, VCPU_SREG_CS);
memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);

switch (mode) {
Expand Down Expand Up @@ -845,23 +879,15 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
/* switch between 2/4 bytes */
c->ad_bytes = def_ad_bytes ^ 6;
break;
case 0x26: /* ES override */
case 0x2e: /* CS override */
c->override_base = &ctxt->cs_base;
break;
case 0x36: /* SS override */
case 0x3e: /* DS override */
c->override_base = &ctxt->ds_base;
break;
case 0x26: /* ES override */
c->override_base = &ctxt->es_base;
set_seg_override(c, (c->b >> 3) & 3);
break;
case 0x64: /* FS override */
c->override_base = &ctxt->fs_base;
break;
case 0x65: /* GS override */
c->override_base = &ctxt->gs_base;
break;
case 0x36: /* SS override */
c->override_base = &ctxt->ss_base;
set_seg_override(c, c->b & 7);
break;
case 0x40 ... 0x4f: /* REX */
if (mode != X86EMUL_MODE_PROT64)
Expand Down Expand Up @@ -933,15 +959,11 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
if (rc)
goto done;

if (!c->override_base)
c->override_base = &ctxt->ds_base;
if (mode == X86EMUL_MODE_PROT64 &&
c->override_base != &ctxt->fs_base &&
c->override_base != &ctxt->gs_base)
c->override_base = NULL;
if (!c->has_seg_override)
set_seg_override(c, VCPU_SREG_DS);

if (c->override_base && !(!c->twobyte && c->b == 0x8d))
c->modrm_ea += *c->override_base;
if (!(!c->twobyte && c->b == 0x8d))
c->modrm_ea += seg_override_base(ctxt, c);

if (c->ad_bytes != 8)
c->modrm_ea = (u32)c->modrm_ea;
Expand Down Expand Up @@ -1043,7 +1065,7 @@ static inline void emulate_push(struct x86_emulate_ctxt *ctxt)
c->dst.bytes = c->op_bytes;
c->dst.val = c->src.val;
register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes);
c->dst.ptr = (void *) register_address(c, ctxt->ss_base,
c->dst.ptr = (void *) register_address(c, ss_base(ctxt),
c->regs[VCPU_REGS_RSP]);
}

Expand All @@ -1053,7 +1075,7 @@ static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt,
struct decode_cache *c = &ctxt->decode;
int rc;

rc = ops->read_std(register_address(c, ctxt->ss_base,
rc = ops->read_std(register_address(c, ss_base(ctxt),
c->regs[VCPU_REGS_RSP]),
&c->dst.val, c->dst.bytes, ctxt->vcpu);
if (rc != 0)
Expand Down Expand Up @@ -1375,11 +1397,11 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
register_address_increment(c, &c->regs[VCPU_REGS_RSP],
-c->op_bytes);
c->dst.ptr = (void *) register_address(
c, ctxt->ss_base, c->regs[VCPU_REGS_RSP]);
c, ss_base(ctxt), c->regs[VCPU_REGS_RSP]);
break;
case 0x58 ... 0x5f: /* pop reg */
pop_instruction:
if ((rc = ops->read_std(register_address(c, ctxt->ss_base,
if ((rc = ops->read_std(register_address(c, ss_base(ctxt),
c->regs[VCPU_REGS_RSP]), c->dst.ptr,
c->op_bytes, ctxt->vcpu)) != 0)
goto done;
Expand All @@ -1405,7 +1427,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
c->rep_prefix ?
address_mask(c, c->regs[VCPU_REGS_RCX]) : 1,
(ctxt->eflags & EFLG_DF),
register_address(c, ctxt->es_base,
register_address(c, es_base(ctxt),
c->regs[VCPU_REGS_RDI]),
c->rep_prefix,
c->regs[VCPU_REGS_RDX]) == 0) {
Expand All @@ -1421,9 +1443,8 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
c->rep_prefix ?
address_mask(c, c->regs[VCPU_REGS_RCX]) : 1,
(ctxt->eflags & EFLG_DF),
register_address(c, c->override_base ?
*c->override_base :
ctxt->ds_base,
register_address(c,
seg_override_base(ctxt, c),
c->regs[VCPU_REGS_RSI]),
c->rep_prefix,
c->regs[VCPU_REGS_RDX]) == 0) {
Expand Down Expand Up @@ -1559,11 +1580,10 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
c->dst.type = OP_MEM;
c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
c->dst.ptr = (unsigned long *)register_address(c,
ctxt->es_base,
es_base(ctxt),
c->regs[VCPU_REGS_RDI]);
if ((rc = ops->read_emulated(register_address(c,
c->override_base ? *c->override_base :
ctxt->ds_base,
seg_override_base(ctxt, c),
c->regs[VCPU_REGS_RSI]),
&c->dst.val,
c->dst.bytes, ctxt->vcpu)) != 0)
Expand All @@ -1579,8 +1599,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
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,
c->override_base ? *c->override_base :
ctxt->ds_base,
seg_override_base(ctxt, c),
c->regs[VCPU_REGS_RSI]);
if ((rc = ops->read_emulated((unsigned long)c->src.ptr,
&c->src.val,
Expand All @@ -1591,7 +1610,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
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,
ctxt->es_base,
es_base(ctxt),
c->regs[VCPU_REGS_RDI]);
if ((rc = ops->read_emulated((unsigned long)c->dst.ptr,
&c->dst.val,
Expand All @@ -1615,7 +1634,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
c->dst.type = OP_MEM;
c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
c->dst.ptr = (unsigned long *)register_address(c,
ctxt->es_base,
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],
Expand All @@ -1627,8 +1646,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
if ((rc = ops->read_emulated(register_address(c,
c->override_base ? *c->override_base :
ctxt->ds_base,
seg_override_base(ctxt, c),
c->regs[VCPU_REGS_RSI]),
&c->dst.val,
c->dst.bytes,
Expand Down
10 changes: 3 additions & 7 deletions include/asm-x86/kvm_x86_emulate.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ struct decode_cache {
u8 rex_prefix;
struct operand src;
struct operand dst;
unsigned long *override_base;
bool has_seg_override;
u8 seg_override;
unsigned int d;
unsigned long regs[NR_VCPU_REGS];
unsigned long eip;
Expand All @@ -151,12 +152,7 @@ struct x86_emulate_ctxt {
/* Emulated execution mode, represented by an X86EMUL_MODE value. */
int mode;

unsigned long cs_base;
unsigned long ds_base;
unsigned long es_base;
unsigned long ss_base;
unsigned long gs_base;
unsigned long fs_base;
u32 cs_base;

/* decode cache */

Expand Down

0 comments on commit 7a5b56d

Please sign in to comment.