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

Commit aa20c04

Browse files
committed
Optimization: Cached segment reads
Signed-off-by: Alexandro Sanchez Bach <asanchez@kryptoslogic.com>
1 parent 4b39e35 commit aa20c04

4 files changed

Lines changed: 144 additions & 29 deletions

File tree

core/cpu.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -386,9 +386,6 @@ int cpu_vmx_execute(struct vcpu_t *vcpu, struct hax_tunnel *htun)
386386

387387
state->_rflags = vmread(vcpu, GUEST_RFLAGS);
388388
state->_rsp = vmread(vcpu, GUEST_RSP);
389-
VMREAD_SEG(vcpu, CS, state->_cs);
390-
VMREAD_SEG(vcpu, DS, state->_ds);
391-
VMREAD_SEG(vcpu, ES, state->_es);
392389
vmread_cr(vcpu);
393390

394391
if (vcpu->nr_pending_intrs > 0 || hax_intr_is_blocked(vcpu))

core/include/vcpu.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,4 +254,11 @@ bool vcpu_is_panic(struct vcpu_t *vcpu);
254254
void hax_panic_vcpu(struct vcpu_t *v, char *fmt, ...);
255255
#endif
256256

257+
// Extension-specific operations
258+
259+
uint16_t vcpu_get_seg_selector(struct vcpu_t *vcpu, int seg);
260+
mword vcpu_get_seg_base(struct vcpu_t *vcpu, int seg);
261+
uint32_t vcpu_get_seg_limit(struct vcpu_t *vcpu, int seg);
262+
uint32_t vcpu_get_seg_ar(struct vcpu_t *vcpu, int seg);
263+
257264
#endif // HAX_CORE_VCPU_H_

core/vcpu.c

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2096,41 +2096,43 @@ static int vcpu_emulate_insn(struct vcpu_t *vcpu)
20962096
em_context_t *em_ctxt = &vcpu->emulate_ctxt;
20972097
uint8_t instr[INSTR_MAX_LEN] = {0};
20982098
uint32_t exit_instr_length = vmcs_read(vcpu, VM_EXIT_INFO_INSTRUCTION_LENGTH);
2099-
uint64_t cs_base = vcpu->state->_cs.base;
21002099
uint64_t rip = vcpu->state->_rip;
2100+
segment_desc_t cs;
21012101
uint64_t va;
21022102

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

21072107
// Detect guest mode
2108+
cs.ar = vcpu_get_seg_ar(vcpu, SEG_CS);
21082109
if (!(vcpu->state->_cr0 & CR0_PE))
21092110
mode = EM_MODE_REAL;
2110-
else if (vcpu->state->_cs.long_mode == 1)
2111+
else if (cs.long_mode == 1)
21112112
mode = EM_MODE_PROT64;
2112-
else if (vcpu->state->_cs.operand_size == 1)
2113+
else if (cs.operand_size == 1)
21132114
mode = EM_MODE_PROT32;
21142115
else
21152116
mode = EM_MODE_PROT16;
21162117
em_ctxt->mode = mode;
21172118

21182119
// Fetch the instruction at guest CS:IP = CS.Base + IP, omitting segment
21192120
// limit and privilege checks
2120-
va = (mode == EM_MODE_PROT64) ? rip : cs_base + rip;
2121+
cs.base = vcpu_get_seg_base(vcpu, SEG_CS);
2122+
va = (mode == EM_MODE_PROT64) ? rip : cs.base + rip;
21212123
#ifdef CONFIG_HAX_EPT2
21222124
if (mmio_fetch_instruction(vcpu, va, instr, INSTR_MAX_LEN)) {
21232125
hax_panic_vcpu(vcpu, "%s: mmio_fetch_instruction() failed: vcpu_id=%u,"
21242126
" gva=0x%llx (CS:IP=0x%llx:0x%llx)\n",
2125-
__func__, vcpu->vcpu_id, va, cs_base, rip);
2127+
__func__, vcpu->vcpu_id, va, cs.base, rip);
21262128
dump_vmcs(vcpu);
21272129
return -1;
21282130
}
21292131
#else // !CONFIG_HAX_EPT2
21302132
if (!vcpu_read_guest_virtual(vcpu, va, &instr, INSTR_MAX_LEN, INSTR_MAX_LEN,
21312133
0)) {
21322134
hax_panic_vcpu(vcpu, "Error reading instruction at 0x%llx for decoding"
2133-
" (CS:IP=0x%llx:0x%llx)\n", va, cs_base, rip);
2135+
" (CS:IP=0x%llx:0x%llx)\n", va, cs.base, rip);
21342136
dump_vmcs(vcpu);
21352137
return -1;
21362138
}
@@ -2142,7 +2144,7 @@ static int vcpu_emulate_insn(struct vcpu_t *vcpu)
21422144
hax_panic_vcpu(vcpu, "em_decode_insn() failed: vcpu_id=%u,"
21432145
" len=%u, CS:IP=0x%llx:0x%llx, instr[0..5]="
21442146
"0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", vcpu->vcpu_id,
2145-
exit_instr_length, cs_base, rip, instr[0], instr[1],
2147+
exit_instr_length, cs.base, rip, instr[0], instr[1],
21462148
instr[2], instr[3], instr[4], instr[5]);
21472149
dump_vmcs(vcpu);
21482150
return HAX_RESUME;
@@ -2151,15 +2153,15 @@ static int vcpu_emulate_insn(struct vcpu_t *vcpu)
21512153
hax_debug("Inferred instruction length %u does not match VM-exit"
21522154
" instruction length %u (CS:IP=0x%llx:0x%llx, instr[0..5]="
21532155
"0x%x 0x%x 0x%x 0x%x 0x%x 0x%x)\n", em_ctxt->len,
2154-
exit_instr_length, cs_base, rip, instr[0], instr[1],
2156+
exit_instr_length, cs.base, rip, instr[0], instr[1],
21552157
instr[2], instr[3], instr[4], instr[5]);
21562158
}
21572159
rc = em_emulate_insn(em_ctxt);
21582160
if (rc < 0) {
21592161
hax_panic_vcpu(vcpu, "em_emulate_insn() failed: vcpu_id=%u,"
21602162
" len=%u, CS:IP=0x%llx:0x%llx, instr[0..5]="
21612163
"0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", vcpu->vcpu_id,
2162-
exit_instr_length, cs_base, rip, instr[0], instr[1],
2164+
exit_instr_length, cs.base, rip, instr[0], instr[1],
21632165
instr[2], instr[3], instr[4], instr[5]);
21642166
dump_vmcs(vcpu);
21652167
return HAX_RESUME;
@@ -2206,22 +2208,7 @@ void vcpu_write_rflags(void *obj, uint64_t value)
22062208
static uint64_t vcpu_get_segment_base(void *obj, uint32_t segment)
22072209
{
22082210
struct vcpu_t *vcpu = obj;
2209-
switch (segment) {
2210-
case SEG_CS:
2211-
return vcpu->state->_cs.base;
2212-
case SEG_DS:
2213-
return vcpu->state->_ds.base;
2214-
case SEG_ES:
2215-
return vcpu->state->_es.base;
2216-
case SEG_FS:
2217-
return vcpu->state->_fs.base;
2218-
case SEG_GS:
2219-
return vcpu->state->_gs.base;
2220-
case SEG_SS:
2221-
return vcpu->state->_ss.base;
2222-
default:
2223-
return vcpu->state->_ds.base;
2224-
}
2211+
return vcpu_get_seg_base(vcpu, segment);
22252212
}
22262213

22272214
static void vcpu_advance_rip(void *obj, uint64_t len)
@@ -3299,7 +3286,7 @@ static int handle_msr_read(struct vcpu_t *vcpu, uint32_t msr, uint64_t *val)
32993286
}
33003287
case IA32_FS_BASE: {
33013288
if (vcpu->fs_base_dirty)
3302-
*val = vcpu->state->_fs.base;
3289+
*val = vcpu_get_seg_base(vcpu, SEG_FS);
33033290
else
33043291
*val = vmread(vcpu, GUEST_FS_BASE);
33053292
break;

core/vmx.c

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,3 +326,127 @@ void vcpu_vmcs_flush_cache_w(struct vcpu_t *vcpu)
326326
}
327327
vcpu->vmx.vmcs_cache_w.dirty = 0;
328328
}
329+
330+
uint16_t vcpu_get_seg_selector(struct vcpu_t *vcpu, int seg)
331+
{
332+
uint16_t value;
333+
334+
switch (seg) {
335+
case SEG_CS:
336+
value = vmcs_read(vcpu, GUEST_CS_SELECTOR);
337+
break;
338+
case SEG_SS:
339+
value = vmcs_read(vcpu, GUEST_SS_SELECTOR);
340+
break;
341+
case SEG_DS:
342+
value = vmcs_read(vcpu, GUEST_DS_SELECTOR);
343+
break;
344+
case SEG_ES:
345+
value = vmcs_read(vcpu, GUEST_ES_SELECTOR);
346+
break;
347+
case SEG_FS:
348+
value = vmcs_read(vcpu, GUEST_FS_SELECTOR);
349+
break;
350+
case SEG_GS:
351+
value = vmcs_read(vcpu, GUEST_GS_SELECTOR);
352+
break;
353+
default:
354+
hax_error("vcpu_get_seg_selector: Unexpected segment (%d)\n", seg);
355+
value = 0;
356+
}
357+
return value;
358+
}
359+
360+
mword vcpu_get_seg_base(struct vcpu_t *vcpu, int seg)
361+
{
362+
mword value;
363+
364+
switch (seg) {
365+
case SEG_CS:
366+
value = vmcs_read(vcpu, GUEST_CS_BASE);
367+
break;
368+
case SEG_SS:
369+
value = vmcs_read(vcpu, GUEST_SS_BASE);
370+
break;
371+
case SEG_DS:
372+
value = vmcs_read(vcpu, GUEST_DS_BASE);
373+
break;
374+
case SEG_ES:
375+
value = vmcs_read(vcpu, GUEST_ES_BASE);
376+
break;
377+
case SEG_FS:
378+
value = vmcs_read(vcpu, GUEST_FS_BASE);
379+
break;
380+
case SEG_GS:
381+
value = vmcs_read(vcpu, GUEST_GS_BASE);
382+
break;
383+
default:
384+
hax_error("vcpu_get_seg_base: Unexpected segment (%d)\n", seg);
385+
value = 0;
386+
}
387+
return value;
388+
}
389+
390+
uint32_t vcpu_get_seg_limit(struct vcpu_t *vcpu, int seg)
391+
{
392+
uint32_t value;
393+
394+
switch (seg) {
395+
case SEG_CS:
396+
value = vmcs_read(vcpu, GUEST_CS_LIMIT);
397+
break;
398+
case SEG_SS:
399+
value = vmcs_read(vcpu, GUEST_SS_LIMIT);
400+
break;
401+
case SEG_DS:
402+
value = vmcs_read(vcpu, GUEST_DS_LIMIT);
403+
break;
404+
case SEG_ES:
405+
value = vmcs_read(vcpu, GUEST_ES_LIMIT);
406+
break;
407+
case SEG_FS:
408+
value = vmcs_read(vcpu, GUEST_FS_LIMIT);
409+
break;
410+
case SEG_GS:
411+
value = vmcs_read(vcpu, GUEST_GS_LIMIT);
412+
break;
413+
default:
414+
hax_error("vcpu_get_seg_limit: Unexpected segment (%d)\n", seg);
415+
value = 0;
416+
}
417+
return value;
418+
}
419+
420+
uint32_t vcpu_get_seg_ar(struct vcpu_t *vcpu, int seg)
421+
{
422+
uint32_t value;
423+
424+
switch (seg) {
425+
case SEG_CS:
426+
value = vmcs_read(vcpu, GUEST_CS_AR);
427+
break;
428+
case SEG_SS:
429+
value = vmcs_read(vcpu, GUEST_SS_AR);
430+
break;
431+
case SEG_DS:
432+
value = vmcs_read(vcpu, GUEST_DS_AR);
433+
break;
434+
case SEG_ES:
435+
value = vmcs_read(vcpu, GUEST_ES_AR);
436+
break;
437+
case SEG_FS:
438+
value = vmcs_read(vcpu, GUEST_FS_AR);
439+
break;
440+
case SEG_GS:
441+
value = vmcs_read(vcpu, GUEST_GS_AR);
442+
break;
443+
default:
444+
hax_error("vcpu_get_seg_ar: Unexpected segment (%d)\n", seg);
445+
value = 0;
446+
}
447+
448+
if (value & (1 << 16) /* ar.null */) {
449+
return 0;
450+
}
451+
return value;
452+
}

0 commit comments

Comments
 (0)