Skip to content
This repository has been archived by the owner on Jan 28, 2023. It is now read-only.

Commit

Permalink
Optimization: Cached segment reads
Browse files Browse the repository at this point in the history
Signed-off-by: Alexandro Sanchez Bach <asanchez@kryptoslogic.com>
  • Loading branch information
AlexAltea committed Nov 22, 2018
1 parent 4b39e35 commit aa20c04
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 29 deletions.
3 changes: 0 additions & 3 deletions core/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -386,9 +386,6 @@ int cpu_vmx_execute(struct vcpu_t *vcpu, struct hax_tunnel *htun)

state->_rflags = vmread(vcpu, GUEST_RFLAGS);
state->_rsp = vmread(vcpu, GUEST_RSP);
VMREAD_SEG(vcpu, CS, state->_cs);
VMREAD_SEG(vcpu, DS, state->_ds);
VMREAD_SEG(vcpu, ES, state->_es);
vmread_cr(vcpu);

if (vcpu->nr_pending_intrs > 0 || hax_intr_is_blocked(vcpu))
Expand Down
7 changes: 7 additions & 0 deletions core/include/vcpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,4 +254,11 @@ bool vcpu_is_panic(struct vcpu_t *vcpu);
void hax_panic_vcpu(struct vcpu_t *v, char *fmt, ...);
#endif

// Extension-specific operations

uint16_t vcpu_get_seg_selector(struct vcpu_t *vcpu, int seg);
mword vcpu_get_seg_base(struct vcpu_t *vcpu, int seg);
uint32_t vcpu_get_seg_limit(struct vcpu_t *vcpu, int seg);
uint32_t vcpu_get_seg_ar(struct vcpu_t *vcpu, int seg);

#endif // HAX_CORE_VCPU_H_
39 changes: 13 additions & 26 deletions core/vcpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -2096,41 +2096,43 @@ static int vcpu_emulate_insn(struct vcpu_t *vcpu)
em_context_t *em_ctxt = &vcpu->emulate_ctxt;
uint8_t instr[INSTR_MAX_LEN] = {0};
uint32_t exit_instr_length = vmcs_read(vcpu, VM_EXIT_INFO_INSTRUCTION_LENGTH);
uint64_t cs_base = vcpu->state->_cs.base;
uint64_t rip = vcpu->state->_rip;
segment_desc_t cs;
uint64_t va;

// Clean up the emulation context of the previous MMIO instruction, so that
// even if things go wrong, the behavior will still be predictable.
vcpu_init_emulator(vcpu);

// Detect guest mode
cs.ar = vcpu_get_seg_ar(vcpu, SEG_CS);
if (!(vcpu->state->_cr0 & CR0_PE))
mode = EM_MODE_REAL;
else if (vcpu->state->_cs.long_mode == 1)
else if (cs.long_mode == 1)
mode = EM_MODE_PROT64;
else if (vcpu->state->_cs.operand_size == 1)
else if (cs.operand_size == 1)
mode = EM_MODE_PROT32;
else
mode = EM_MODE_PROT16;
em_ctxt->mode = mode;

// Fetch the instruction at guest CS:IP = CS.Base + IP, omitting segment
// limit and privilege checks
va = (mode == EM_MODE_PROT64) ? rip : cs_base + rip;
cs.base = vcpu_get_seg_base(vcpu, SEG_CS);
va = (mode == EM_MODE_PROT64) ? rip : cs.base + rip;
#ifdef CONFIG_HAX_EPT2
if (mmio_fetch_instruction(vcpu, va, instr, INSTR_MAX_LEN)) {
hax_panic_vcpu(vcpu, "%s: mmio_fetch_instruction() failed: vcpu_id=%u,"
" gva=0x%llx (CS:IP=0x%llx:0x%llx)\n",
__func__, vcpu->vcpu_id, va, cs_base, rip);
__func__, vcpu->vcpu_id, va, cs.base, rip);
dump_vmcs(vcpu);
return -1;
}
#else // !CONFIG_HAX_EPT2
if (!vcpu_read_guest_virtual(vcpu, va, &instr, INSTR_MAX_LEN, INSTR_MAX_LEN,
0)) {
hax_panic_vcpu(vcpu, "Error reading instruction at 0x%llx for decoding"
" (CS:IP=0x%llx:0x%llx)\n", va, cs_base, rip);
" (CS:IP=0x%llx:0x%llx)\n", va, cs.base, rip);
dump_vmcs(vcpu);
return -1;
}
Expand All @@ -2142,7 +2144,7 @@ static int vcpu_emulate_insn(struct vcpu_t *vcpu)
hax_panic_vcpu(vcpu, "em_decode_insn() failed: vcpu_id=%u,"
" len=%u, CS:IP=0x%llx:0x%llx, instr[0..5]="
"0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", vcpu->vcpu_id,
exit_instr_length, cs_base, rip, instr[0], instr[1],
exit_instr_length, cs.base, rip, instr[0], instr[1],
instr[2], instr[3], instr[4], instr[5]);
dump_vmcs(vcpu);
return HAX_RESUME;
Expand All @@ -2151,15 +2153,15 @@ static int vcpu_emulate_insn(struct vcpu_t *vcpu)
hax_debug("Inferred instruction length %u does not match VM-exit"
" instruction length %u (CS:IP=0x%llx:0x%llx, instr[0..5]="
"0x%x 0x%x 0x%x 0x%x 0x%x 0x%x)\n", em_ctxt->len,
exit_instr_length, cs_base, rip, instr[0], instr[1],
exit_instr_length, cs.base, rip, instr[0], instr[1],
instr[2], instr[3], instr[4], instr[5]);
}
rc = em_emulate_insn(em_ctxt);
if (rc < 0) {
hax_panic_vcpu(vcpu, "em_emulate_insn() failed: vcpu_id=%u,"
" len=%u, CS:IP=0x%llx:0x%llx, instr[0..5]="
"0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", vcpu->vcpu_id,
exit_instr_length, cs_base, rip, instr[0], instr[1],
exit_instr_length, cs.base, rip, instr[0], instr[1],
instr[2], instr[3], instr[4], instr[5]);
dump_vmcs(vcpu);
return HAX_RESUME;
Expand Down Expand Up @@ -2206,22 +2208,7 @@ void vcpu_write_rflags(void *obj, uint64_t value)
static uint64_t vcpu_get_segment_base(void *obj, uint32_t segment)
{
struct vcpu_t *vcpu = obj;
switch (segment) {
case SEG_CS:
return vcpu->state->_cs.base;
case SEG_DS:
return vcpu->state->_ds.base;
case SEG_ES:
return vcpu->state->_es.base;
case SEG_FS:
return vcpu->state->_fs.base;
case SEG_GS:
return vcpu->state->_gs.base;
case SEG_SS:
return vcpu->state->_ss.base;
default:
return vcpu->state->_ds.base;
}
return vcpu_get_seg_base(vcpu, segment);
}

static void vcpu_advance_rip(void *obj, uint64_t len)
Expand Down Expand Up @@ -3299,7 +3286,7 @@ static int handle_msr_read(struct vcpu_t *vcpu, uint32_t msr, uint64_t *val)
}
case IA32_FS_BASE: {
if (vcpu->fs_base_dirty)
*val = vcpu->state->_fs.base;
*val = vcpu_get_seg_base(vcpu, SEG_FS);
else
*val = vmread(vcpu, GUEST_FS_BASE);
break;
Expand Down
124 changes: 124 additions & 0 deletions core/vmx.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,3 +326,127 @@ void vcpu_vmcs_flush_cache_w(struct vcpu_t *vcpu)
}
vcpu->vmx.vmcs_cache_w.dirty = 0;
}

uint16_t vcpu_get_seg_selector(struct vcpu_t *vcpu, int seg)
{
uint16_t value;

switch (seg) {
case SEG_CS:
value = vmcs_read(vcpu, GUEST_CS_SELECTOR);
break;
case SEG_SS:
value = vmcs_read(vcpu, GUEST_SS_SELECTOR);
break;
case SEG_DS:
value = vmcs_read(vcpu, GUEST_DS_SELECTOR);
break;
case SEG_ES:
value = vmcs_read(vcpu, GUEST_ES_SELECTOR);
break;
case SEG_FS:
value = vmcs_read(vcpu, GUEST_FS_SELECTOR);
break;
case SEG_GS:
value = vmcs_read(vcpu, GUEST_GS_SELECTOR);
break;
default:
hax_error("vcpu_get_seg_selector: Unexpected segment (%d)\n", seg);
value = 0;
}
return value;
}

mword vcpu_get_seg_base(struct vcpu_t *vcpu, int seg)
{
mword value;

switch (seg) {
case SEG_CS:
value = vmcs_read(vcpu, GUEST_CS_BASE);
break;
case SEG_SS:
value = vmcs_read(vcpu, GUEST_SS_BASE);
break;
case SEG_DS:
value = vmcs_read(vcpu, GUEST_DS_BASE);
break;
case SEG_ES:
value = vmcs_read(vcpu, GUEST_ES_BASE);
break;
case SEG_FS:
value = vmcs_read(vcpu, GUEST_FS_BASE);
break;
case SEG_GS:
value = vmcs_read(vcpu, GUEST_GS_BASE);
break;
default:
hax_error("vcpu_get_seg_base: Unexpected segment (%d)\n", seg);
value = 0;
}
return value;
}

uint32_t vcpu_get_seg_limit(struct vcpu_t *vcpu, int seg)
{
uint32_t value;

switch (seg) {
case SEG_CS:
value = vmcs_read(vcpu, GUEST_CS_LIMIT);
break;
case SEG_SS:
value = vmcs_read(vcpu, GUEST_SS_LIMIT);
break;
case SEG_DS:
value = vmcs_read(vcpu, GUEST_DS_LIMIT);
break;
case SEG_ES:
value = vmcs_read(vcpu, GUEST_ES_LIMIT);
break;
case SEG_FS:
value = vmcs_read(vcpu, GUEST_FS_LIMIT);
break;
case SEG_GS:
value = vmcs_read(vcpu, GUEST_GS_LIMIT);
break;
default:
hax_error("vcpu_get_seg_limit: Unexpected segment (%d)\n", seg);
value = 0;
}
return value;
}

uint32_t vcpu_get_seg_ar(struct vcpu_t *vcpu, int seg)
{
uint32_t value;

switch (seg) {
case SEG_CS:
value = vmcs_read(vcpu, GUEST_CS_AR);
break;
case SEG_SS:
value = vmcs_read(vcpu, GUEST_SS_AR);
break;
case SEG_DS:
value = vmcs_read(vcpu, GUEST_DS_AR);
break;
case SEG_ES:
value = vmcs_read(vcpu, GUEST_ES_AR);
break;
case SEG_FS:
value = vmcs_read(vcpu, GUEST_FS_AR);
break;
case SEG_GS:
value = vmcs_read(vcpu, GUEST_GS_AR);
break;
default:
hax_error("vcpu_get_seg_ar: Unexpected segment (%d)\n", seg);
value = 0;
}

if (value & (1 << 16) /* ar.null */) {
return 0;
}
return value;
}

0 comments on commit aa20c04

Please sign in to comment.