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

Commit 689c04d

Browse files
committed
Optimization: Cached guest interruptibility/exit qualifier reads
Signed-off-by: Alexandro Sanchez Bach <asanchez@kryptoslogic.com>
1 parent 989eea9 commit 689c04d

6 files changed

Lines changed: 56 additions & 49 deletions

File tree

core/cpu.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -377,11 +377,6 @@ int cpu_vmx_execute(struct vcpu_t *vcpu, struct hax_tunnel *htun)
377377
*/
378378
hax_handle_idt_vectoring(vcpu);
379379

380-
vmx(vcpu, exit_qualification).raw = vmread(
381-
vcpu, VM_EXIT_INFO_QUALIFICATION);
382-
vmx(vcpu, interruptibility_state).raw = vmread(
383-
vcpu, GUEST_INTERRUPTIBILITY);
384-
385380
vmread_cr(vcpu);
386381

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

core/include/vmx.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ typedef enum component_index_t component_index_t;
320320
COMP(0, 0, W_UL, VMX_CR0_READ_SHADOW) \
321321
COMP(0, 0, W_UL, VMX_CR4_READ_SHADOW) \
322322
COMP(0, 0, W_UL, VMX_CR3_TARGET_VAL_BASE) \
323-
COMP(0, 0, W_UL, VM_EXIT_INFO_QUALIFICATION) \
323+
COMP(1, 0, W_UL, VM_EXIT_INFO_QUALIFICATION) \
324324
COMP(0, 0, W_UL, VM_EXIT_INFO_IO_ECX) \
325325
COMP(0, 0, W_UL, VM_EXIT_INFO_IO_ESI) \
326326
COMP(0, 0, W_UL, VM_EXIT_INFO_IO_EDI) \
@@ -405,7 +405,7 @@ typedef enum component_index_t component_index_t;
405405
COMP(0, 0, W_32, GUEST_IDTR_LIMIT) \
406406
COMP(0, 0, W_32, GUEST_SYSENTER_CS) \
407407
COMP(0, 0, W_32, GUEST_SMBASE) \
408-
COMP(0, 0, W_32, GUEST_INTERRUPTIBILITY) \
408+
COMP(1, 0, W_32, GUEST_INTERRUPTIBILITY) \
409409
COMP(0, 0, W_32, GUEST_ACTIVITY_STATE) \
410410
/* 16-bit components */ \
411411
COMP(0, 0, W_16, VMX_VPID) \

core/include/vtlb.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ void vcpu_invalidate_tlb_addr(struct vcpu_t *vcpu, hax_vaddr_t va);
100100
uint vcpu_vtlb_alloc(struct vcpu_t *vcpu);
101101
void vcpu_vtlb_free(struct vcpu_t *vcpu);
102102

103-
bool handle_vtlb(struct vcpu_t *vcpu);
103+
bool handle_vtlb(struct vcpu_t *vcpu, hax_vaddr_t addr);
104104

105-
uint vcpu_translate(struct vcpu_t *vcpu, hax_vaddr_t va, uint access, hax_paddr_t *pa,
106-
uint64_t *len, bool update);
105+
uint vcpu_translate(struct vcpu_t *vcpu, hax_vaddr_t va, uint access,
106+
hax_paddr_t *pa, uint64_t *len, bool update);
107107

108108
uint32_t vcpu_read_guest_virtual(struct vcpu_t *vcpu, hax_vaddr_t addr, void *dst,
109109
uint32_t dst_buflen, uint32_t size, uint flag);

core/intr_exc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ uint hax_intr_is_blocked(struct vcpu_t *vcpu)
126126
if (!(rflags & EFLAGS_IF))
127127
return 1;
128128

129-
intr_status = vmx(vcpu, interruptibility_state).raw;
129+
intr_status = vmcs_read(vcpu, GUEST_INTERRUPTIBILITY);
130130
if (intr_status & 3)
131131
return 1;
132132
return 0;

core/vcpu.c

Lines changed: 48 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ static void handle_machine_check(struct vcpu_t *vcpu);
107107

108108
static void handle_cpuid_virtual(struct vcpu_t *vcpu, uint32_t eax, uint32_t ecx);
109109
static void handle_mem_fault(struct vcpu_t *vcpu, struct hax_tunnel *htun);
110-
static void check_flush(struct vcpu_t *vcpu, uint32_t bits);
110+
static void check_flush(struct vcpu_t *vcpu, int cr, uint32_t bits);
111111
static void vmwrite_efer(struct vcpu_t *vcpu);
112112

113113
static int handle_msr_read(struct vcpu_t *vcpu, uint32_t msr, uint64_t *val);
@@ -1272,8 +1272,6 @@ void vcpu_save_host_state(struct vcpu_t *vcpu)
12721272
vmwrite(vcpu, HOST_IDTR_BASE, get_kernel_idtr_base());
12731273

12741274
// Handle SYSENTER/SYSEXIT MSR
1275-
vmwrite(vcpu, HOST_SYSENTER_CS, ia32_rdmsr(IA32_SYSENTER_CS));
1276-
vmwrite(vcpu, HOST_SYSENTER_EIP, ia32_rdmsr(IA32_SYSENTER_EIP));
12771275
vmwrite(vcpu, HOST_SYSENTER_ESP, ia32_rdmsr(IA32_SYSENTER_ESP));
12781276

12791277
// LDTR is unusable from spec, do we need ldt for host?
@@ -1414,6 +1412,9 @@ static void fill_common_vmcs(struct vcpu_t *vcpu)
14141412
vmwrite(vcpu, HOST_GDTR_BASE, get_kernel_gdtr_base());
14151413
vmwrite(vcpu, HOST_IDTR_BASE, get_kernel_idtr_base());
14161414

1415+
vmwrite(vcpu, HOST_SYSENTER_CS, ia32_rdmsr(IA32_SYSENTER_CS));
1416+
vmwrite(vcpu, HOST_SYSENTER_EIP, ia32_rdmsr(IA32_SYSENTER_EIP));
1417+
14171418
// The host RIP, used during VM-exit events, is only updated if HAXM
14181419
// is reloaded. Thus never changes during the lifetime of the VCPU.
14191420
vmwrite(vcpu, HOST_RIP, (mword)vmx_get_rip());
@@ -1744,7 +1745,7 @@ int vtlb_active(struct vcpu_t *vcpu)
17441745
static void advance_rip(struct vcpu_t *vcpu)
17451746
{
17461747
struct vcpu_state_t *state = vcpu->state;
1747-
uint32_t interruptibility = vmx(vcpu, interruptibility_state).raw;
1748+
uint32_t interruptibility = vmcs_read(vcpu, GUEST_INTERRUPTIBILITY);
17481749

17491750
if (interruptibility & 3u) {
17501751
interruptibility &= ~3u;
@@ -2320,6 +2321,8 @@ static void vcpu_init_emulator(struct vcpu_t *vcpu)
23202321
static int exit_exc_nmi(struct vcpu_t *vcpu, struct hax_tunnel *htun)
23212322
{
23222323
struct vcpu_state_t *state = vcpu->state;
2324+
exit_qualification_t qual = { .raw =
2325+
vmcs_read(vcpu, VM_EXIT_INFO_QUALIFICATION) };
23232326
interruption_info_t exit_intr_info;
23242327

23252328
exit_intr_info.raw = vmcs_read(vcpu, VM_EXIT_INFO_INTERRUPT_INFO);
@@ -2333,7 +2336,7 @@ static int exit_exc_nmi(struct vcpu_t *vcpu, struct hax_tunnel *htun)
23332336
}
23342337
case VECTOR_PF: {
23352338
if (vtlb_active(vcpu)) {
2336-
if (handle_vtlb(vcpu))
2339+
if (handle_vtlb(vcpu, qual.address))
23372340
return HAX_RESUME;
23382341

23392342
return vcpu_emulate_insn(vcpu);
@@ -2358,7 +2361,7 @@ static int exit_exc_nmi(struct vcpu_t *vcpu, struct hax_tunnel *htun)
23582361
case VECTOR_DB: {
23592362
htun->_exit_status = HAX_EXIT_DEBUG;
23602363
htun->debug.rip = vcpu_get_rip(vcpu);
2361-
htun->debug.dr6 = vmx(vcpu, exit_qualification).raw;
2364+
htun->debug.dr6 = qual.raw;
23622365
htun->debug.dr7 = vmread(vcpu, GUEST_DR7);
23632366
return HAX_EXIT;
23642367
}
@@ -2372,7 +2375,7 @@ static int exit_exc_nmi(struct vcpu_t *vcpu, struct hax_tunnel *htun)
23722375
}
23732376

23742377
if (exit_intr_info.vector == VECTOR_PF) {
2375-
state->_cr2 = vmx(vcpu, exit_qualification.address);
2378+
state->_cr2 = qual.address;
23762379
}
23772380

23782381
return HAX_RESUME;
@@ -2738,8 +2741,11 @@ static int exit_hlt(struct vcpu_t *vcpu, struct hax_tunnel *htun)
27382741

27392742
static int exit_invlpg(struct vcpu_t *vcpu, struct hax_tunnel *htun)
27402743
{
2744+
exit_qualification_t qual = { .raw =
2745+
vmcs_read(vcpu, VM_EXIT_INFO_QUALIFICATION) };
2746+
27412747
advance_rip(vcpu);
2742-
vcpu_invalidate_tlb_addr(vcpu, vmx(vcpu, exit_qualification).address);
2748+
vcpu_invalidate_tlb_addr(vcpu, qual.address);
27432749
htun->_exit_reason = vmx(vcpu, exit_reason).basic_reason;
27442750
return HAX_RESUME;
27452751
}
@@ -2750,9 +2756,9 @@ static int exit_rdtsc(struct vcpu_t *vcpu, struct hax_tunnel *htun)
27502756
return HAX_RESUME;
27512757
}
27522758

2753-
static void check_flush(struct vcpu_t *vcpu, uint32_t bits)
2759+
static void check_flush(struct vcpu_t *vcpu, int cr, uint32_t bits)
27542760
{
2755-
switch (vmx(vcpu, exit_qualification).cr.creg) {
2761+
switch (cr) {
27562762
case 0: {
27572763
if (bits & (CR0_PE | CR0_PG)) {
27582764
vcpu_invalidate_tlb(vcpu, 1);
@@ -2783,18 +2789,20 @@ static int exit_cr_access(struct vcpu_t *vcpu, struct hax_tunnel *htun)
27832789
uint64_t cr_ptr;
27842790
int cr;
27852791
struct vcpu_state_t *state = vcpu->state;
2792+
exit_qualification_t qual = { .raw =
2793+
vmcs_read(vcpu, VM_EXIT_INFO_QUALIFICATION) };
27862794
bool is_ept_pae = false;
27872795
preempt_flag flags;
27882796
uint32_t vmcs_err = 0;
27892797

27902798
htun->_exit_reason = vmx(vcpu, exit_reason).basic_reason;
27912799

2792-
cr = vmx(vcpu, exit_qualification).cr.creg;
2800+
cr = qual.cr.creg;
27932801
cr_ptr = vcpu_read_cr(state, cr);
27942802

2795-
switch (vmx(vcpu, exit_qualification).cr.type) {
2803+
switch (qual.cr.type) {
27962804
case 0: { // MOV CR <- GPR
2797-
uint64_t val = state->_regs[(vmx(vcpu, exit_qualification).cr.gpr)];
2805+
uint64_t val = state->_regs[qual.cr.gpr];
27982806

27992807
hax_debug("cr_access W CR%d: %08llx -> %08llx\n", cr, cr_ptr, val);
28002808
if (cr == 0) {
@@ -2859,7 +2867,7 @@ static int exit_cr_access(struct vcpu_t *vcpu, struct hax_tunnel *htun)
28592867
hax_error("Unsupported CR%d access\n", cr);
28602868
break;
28612869
}
2862-
check_flush(vcpu, cr_ptr ^ val);
2870+
check_flush(vcpu, cr, cr_ptr ^ val);
28632871
vcpu_write_cr(state, cr, val);
28642872

28652873
if (is_ept_pae) {
@@ -2899,7 +2907,7 @@ static int exit_cr_access(struct vcpu_t *vcpu, struct hax_tunnel *htun)
28992907
case 1: { // MOV CR -> GPR
29002908
hax_info("cr_access R CR%d\n", cr);
29012909

2902-
state->_regs[vmx(vcpu, exit_qualification).cr.gpr] = cr_ptr;
2910+
state->_regs[qual.cr.gpr] = cr_ptr;
29032911
if (cr == 8) {
29042912
hax_info("Unsupported CR%d access\n", cr);
29052913
break;
@@ -2926,7 +2934,7 @@ static int exit_cr_access(struct vcpu_t *vcpu, struct hax_tunnel *htun)
29262934
case 3: { // LMSW
29272935
hax_info("LMSW\n");
29282936
state->_cr0 = (state->_cr0 & ~0xfULL) |
2929-
(vmx(vcpu, exit_qualification).cr.lmsw_source & 0xf);
2937+
(qual.cr.lmsw_source & 0xf);
29302938
if ((vmcs_err = load_vmcs(vcpu, &flags))) {
29312939
hax_panic_vcpu(vcpu, "load_vmcs failed while LMSW %x\n",
29322940
vmcs_err);
@@ -2954,8 +2962,10 @@ static int exit_cr_access(struct vcpu_t *vcpu, struct hax_tunnel *htun)
29542962
static int exit_dr_access(struct vcpu_t *vcpu, struct hax_tunnel *htun)
29552963
{
29562964
uint64_t *dr = NULL;
2957-
int dreg = vmx(vcpu, exit_qualification.dr.dreg);
2958-
int gpr_reg = vmx(vcpu, exit_qualification).dr.gpr;
2965+
exit_qualification_t qual = { .raw =
2966+
vmcs_read(vcpu, VM_EXIT_INFO_QUALIFICATION) };
2967+
int dreg = qual.dr.dreg;
2968+
int gpr_reg = qual.dr.gpr;
29592969
bool hbreak_enabled = !!(vcpu->debug_control & HAX_DEBUG_USE_HW_BP);
29602970
struct vcpu_state_t *state = vcpu->state;
29612971

@@ -3017,7 +3027,7 @@ static int exit_dr_access(struct vcpu_t *vcpu, struct hax_tunnel *htun)
30173027
}
30183028
}
30193029

3020-
if (vmx(vcpu, exit_qualification.dr.direction)) {
3030+
if (qual.dr.direction) {
30213031
// MOV DR -> GPR
30223032
if (hbreak_enabled) {
30233033
// HAX hardware breakpoint enabled, return dr default value
@@ -3046,7 +3056,7 @@ static int exit_dr_access(struct vcpu_t *vcpu, struct hax_tunnel *htun)
30463056
return HAX_RESUME;
30473057
}
30483058

3049-
static int handle_string_io(struct vcpu_t *vcpu, exit_qualification_t *qual,
3059+
static int handle_string_io(struct vcpu_t *vcpu, exit_qualification_t qual,
30503060
struct hax_tunnel *htun)
30513061
{
30523062
struct vcpu_state_t *state = vcpu->state;
@@ -3058,7 +3068,7 @@ static int handle_string_io(struct vcpu_t *vcpu, exit_qualification_t *qual,
30583068
// 1 indicates string I/O (i.e. OUTS or INS)
30593069
htun->io._flags = 1;
30603070

3061-
count = qual->io.rep ? state->_rcx : 1;
3071+
count = qual.io.rep ? state->_rcx : 1;
30623072
elem_size = htun->io._size;
30633073
total_size = count * elem_size;
30643074

@@ -3086,7 +3096,7 @@ static int handle_string_io(struct vcpu_t *vcpu, exit_qualification_t *qual,
30863096
// For INS (see handle_io_post())
30873097
htun->io._vaddr = start_gva;
30883098

3089-
if (qual->io.direction == HAX_IO_OUT) {
3099+
if (qual.io.direction == HAX_IO_OUT) {
30903100
if (!vcpu_read_guest_virtual(vcpu, start_gva, vcpu->io_buf,
30913101
IOS_MAX_BUFFER, copy_size, 0)) {
30923102
hax_panic_vcpu(vcpu, "%s: vcpu_read_guest_virtual() failed,"
@@ -3103,13 +3113,13 @@ static int handle_string_io(struct vcpu_t *vcpu, exit_qualification_t *qual,
31033113
}
31043114

31053115
if (rflags & EFLAGS_DF) {
3106-
if (qual->io.direction == HAX_IO_OUT) {
3116+
if (qual.io.direction == HAX_IO_OUT) {
31073117
state->_rsi -= copy_size;
31083118
} else {
31093119
state->_rdi -= copy_size;
31103120
}
31113121
} else {
3112-
if (qual->io.direction == HAX_IO_OUT) {
3122+
if (qual.io.direction == HAX_IO_OUT) {
31133123
state->_rsi += copy_size;
31143124
} else {
31153125
state->_rdi += copy_size;
@@ -3120,15 +3130,15 @@ static int handle_string_io(struct vcpu_t *vcpu, exit_qualification_t *qual,
31203130
return HAX_EXIT;
31213131
}
31223132

3123-
static int handle_io(struct vcpu_t *vcpu, exit_qualification_t *qual,
3133+
static int handle_io(struct vcpu_t *vcpu, exit_qualification_t qual,
31243134
struct hax_tunnel *htun)
31253135
{
31263136
struct vcpu_state_t *state = vcpu->state;
31273137
htun->io._count = 1;
31283138
htun->io._flags = 0;
31293139

3130-
if (qual->io.direction == HAX_IO_OUT) {
3131-
switch (qual->io.size + 1) {
3140+
if (qual.io.direction == HAX_IO_OUT) {
3141+
switch (qual.io.size + 1) {
31323142
case 1: {
31333143
*((uint8_t *)vcpu->io_buf) = state->_al;
31343144
break;
@@ -3154,7 +3164,8 @@ static int handle_io(struct vcpu_t *vcpu, exit_qualification_t *qual,
31543164
static int exit_io_access(struct vcpu_t *vcpu, struct hax_tunnel *htun)
31553165
{
31563166
struct vcpu_state_t *state = vcpu->state;
3157-
exit_qualification_t *qual = &vmx(vcpu, exit_qualification);
3167+
exit_qualification_t qual = { .raw =
3168+
vmcs_read(vcpu, VM_EXIT_INFO_QUALIFICATION) };
31583169

31593170
htun->_exit_reason = vmx(vcpu, exit_reason).basic_reason;
31603171

@@ -3165,14 +3176,14 @@ static int exit_io_access(struct vcpu_t *vcpu, struct hax_tunnel *htun)
31653176
htun->io._size = 0;
31663177
htun->io._count = 0;
31673178

3168-
htun->io._port = qual->io.encoding ? qual->io.port : state->_dx;
3169-
htun->io._size = qual->io.size + 1;
3170-
htun->io._direction = qual->io.direction;
3179+
htun->io._port = qual.io.encoding ? qual.io.port : state->_dx;
3180+
htun->io._size = qual.io.size + 1;
3181+
htun->io._direction = qual.io.direction;
31713182

31723183
hax_debug("exit_io_access port %x, size %d\n", htun->io._port,
31733184
htun->io._size);
31743185

3175-
if (qual->io.string)
3186+
if (qual.io.string)
31763187
return handle_string_io(vcpu, qual, htun);
31773188

31783189
return handle_io(vcpu, qual, htun);
@@ -3700,7 +3711,8 @@ static int exit_ept_misconfiguration(struct vcpu_t *vcpu,
37003711

37013712
static int exit_ept_violation(struct vcpu_t *vcpu, struct hax_tunnel *htun)
37023713
{
3703-
exit_qualification_t *qual = &vmx(vcpu, exit_qualification);
3714+
exit_qualification_t qual = { .raw =
3715+
vmcs_read(vcpu, VM_EXIT_INFO_QUALIFICATION) };
37043716
hax_paddr_t gpa;
37053717
int ret = 0;
37063718
#ifdef CONFIG_HAX_EPT2
@@ -3709,7 +3721,7 @@ static int exit_ept_violation(struct vcpu_t *vcpu, struct hax_tunnel *htun)
37093721

37103722
htun->_exit_reason = vmx(vcpu, exit_reason).basic_reason;
37113723

3712-
if (qual->ept.gla1 == 0 && qual->ept.gla2 == 1) {
3724+
if (qual.ept.gla1 == 0 && qual.ept.gla2 == 1) {
37133725
hax_panic_vcpu(vcpu, "Incorrect EPT seting\n");
37143726
dump_vmcs(vcpu);
37153727
return HAX_RESUME;
@@ -3719,12 +3731,12 @@ static int exit_ept_violation(struct vcpu_t *vcpu, struct hax_tunnel *htun)
37193731

37203732
#ifdef CONFIG_HAX_EPT2
37213733
ret = ept_handle_access_violation(&vcpu->vm->gpa_space, &vcpu->vm->ept_tree,
3722-
*qual, gpa, &fault_gfn);
3734+
qual, gpa, &fault_gfn);
37233735
if (ret == -EFAULT) {
37243736
// Extract bits 5..0 from Exit Qualification. They indicate the type of
37253737
// the faulting access (HAX_PAGEFAULT_ACC_R/W/X) and the types of access
37263738
// allowed (HAX_PAGEFAULT_PERM_R/W/X).
3727-
htun->pagefault.flags = qual->raw & 0x3f;
3739+
htun->pagefault.flags = qual.raw & 0x3f;
37283740
htun->pagefault.gpa = fault_gfn << PG_ORDER_4K;
37293741
htun->pagefault.reserved1 = 0;
37303742
htun->pagefault.reserved2 = 0;

core/vtlb.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -779,12 +779,12 @@ static uint32_t vcpu_mmu_walk(struct vcpu_t *vcpu, hax_vaddr_t va, uint32_t acce
779779
return TF_OK;
780780
}
781781

782-
bool handle_vtlb(struct vcpu_t *vcpu)
782+
bool handle_vtlb(struct vcpu_t *vcpu, hax_vaddr_t addr)
783783
{
784784
uint32_t access = vmcs_read(vcpu, VM_EXIT_INFO_EXCEPTION_ERROR_CODE);
785785
pagemode_t mode = vcpu_get_pagemode(vcpu);
786786
hax_paddr_t pdir = vcpu->state->_cr3 & (mode == PM_PAE ? ~0x1fULL : ~0xfffULL);
787-
hax_vaddr_t cr2 = vmx(vcpu, exit_qualification).address;
787+
hax_vaddr_t cr2 = addr;
788788

789789
uint32_t ret = vtlb_handle_page_fault(vcpu, mode, pdir, cr2, access);
790790

0 commit comments

Comments
 (0)