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

Commit b6733f4

Browse files
committed
Optimization: Cached CR reads
Signed-off-by: Alexandro Sanchez Bach <asanchez@kryptoslogic.com>
1 parent 61779ca commit b6733f4

File tree

7 files changed

+87
-68
lines changed

7 files changed

+87
-68
lines changed

core/cpu.c

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -186,29 +186,6 @@ void cpu_pmu_init(void *arg)
186186
pmu_info->cpuid_edx = cpuid_args.edx;
187187
}
188188

189-
static void vmread_cr(struct vcpu_t *vcpu)
190-
{
191-
struct vcpu_state_t *state = vcpu->state;
192-
mword cr4, cr4_mask;
193-
194-
// Update only the bits the guest is allowed to change
195-
// This must use the actual cr0 mask, not _cr0_mask.
196-
mword cr0 = vmread(vcpu, GUEST_CR0);
197-
mword cr0_mask = vmread(vcpu, VMX_CR0_MASK); // should cache this
198-
hax_debug("vmread_cr cr0 %lx, cr0_mask %lx, state->_cr0 %llx\n", cr0,
199-
cr0_mask, state->_cr0);
200-
state->_cr0 = (cr0 & ~cr0_mask) | (state->_cr0 & cr0_mask);
201-
hax_debug("vmread_cr, state->_cr0 %llx\n", state->_cr0);
202-
203-
// update CR3 only if guest is allowed to change it
204-
if (!(vmx(vcpu, pcpu_ctls) & CR3_LOAD_EXITING))
205-
state->_cr3 = vmread(vcpu, GUEST_CR3);
206-
207-
cr4 = vmread(vcpu, GUEST_CR4);
208-
cr4_mask = vmread(vcpu, VMX_CR4_MASK); // should cache this
209-
state->_cr4 = (cr4 & ~cr4_mask) | (state->_cr4 & cr4_mask);
210-
}
211-
212189
vmx_result_t cpu_vmx_vmptrld(struct per_cpu_data *cpu_data, hax_paddr_t vmcs,
213190
struct vcpu_t *vcpu)
214191
{
@@ -376,8 +353,6 @@ int cpu_vmx_execute(struct vcpu_t *vcpu, struct hax_tunnel *htun)
376353
*/
377354
hax_handle_idt_vectoring(vcpu);
378355

379-
vmread_cr(vcpu);
380-
381356
if (vcpu->nr_pending_intrs > 0 || hax_intr_is_blocked(vcpu))
382357
htun->ready_for_interrupt_injection = 0;
383358
else

core/include/vcpu.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@ void hax_panic_vcpu(struct vcpu_t *v, char *fmt, ...);
256256

257257
// Extension-specific operations
258258

259+
mword vcpu_get_cr0(struct vcpu_t *vcpu);
260+
mword vcpu_get_cr3(struct vcpu_t *vcpu);
261+
mword vcpu_get_cr4(struct vcpu_t *vcpu);
259262
mword vcpu_get_rflags(struct vcpu_t *vcpu);
260263
mword vcpu_get_rsp(struct vcpu_t *vcpu);
261264
mword vcpu_get_rip(struct vcpu_t *vcpu);

core/include/vmx.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -315,8 +315,8 @@ typedef enum component_index_t component_index_t;
315315
COMP(0, 0, W_64, GUEST_PDPTE2) \
316316
COMP(0, 0, W_64, GUEST_PDPTE3) \
317317
/* Natural-width components */ \
318-
COMP(0, 0, W_UL, VMX_CR0_MASK) \
319-
COMP(0, 0, W_UL, VMX_CR4_MASK) \
318+
COMP(1, 0, W_UL, VMX_CR0_MASK) \
319+
COMP(1, 0, W_UL, VMX_CR4_MASK) \
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) \
@@ -341,9 +341,9 @@ typedef enum component_index_t component_index_t;
341341
COMP(1, 0, W_UL, GUEST_RIP) \
342342
COMP(1, 0, W_UL, GUEST_RFLAGS) \
343343
COMP(1, 0, W_UL, GUEST_RSP) \
344-
COMP(0, 0, W_UL, GUEST_CR0) \
345-
COMP(0, 0, W_UL, GUEST_CR3) \
346-
COMP(0, 0, W_UL, GUEST_CR4) \
344+
COMP(1, 0, W_UL, GUEST_CR0) \
345+
COMP(1, 0, W_UL, GUEST_CR3) \
346+
COMP(1, 0, W_UL, GUEST_CR4) \
347347
COMP(1, 0, W_UL, GUEST_ES_BASE) \
348348
COMP(1, 0, W_UL, GUEST_CS_BASE) \
349349
COMP(1, 0, W_UL, GUEST_SS_BASE) \

core/page_walker.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -569,9 +569,9 @@ uint32_t pw_perform_page_walk(
569569
uint64_t efer_value = vcpu->state->_efer;
570570
bool is_nxe = ((efer_value & IA32_EFER_XD) != 0);
571571
bool is_lme = ((efer_value & IA32_EFER_LME) != 0);
572-
uint64_t cr0 = vcpu->state->_cr0;
573-
uint64_t cr3 = vcpu->state->_cr3;
574-
uint64_t cr4 = vcpu->state->_cr4;
572+
uint64_t cr0 = vcpu_get_cr0(vcpu);
573+
uint64_t cr3 = vcpu_get_cr3(vcpu);
574+
uint64_t cr4 = vcpu_get_cr4(vcpu);
575575
bool is_wp = ((cr0 & CR0_WP) != 0);
576576
bool is_pae = ((cr4 & CR4_PAE) != 0);
577577
bool is_pse = ((cr4 & CR4_PSE) != 0);

core/vcpu.c

Lines changed: 37 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -172,35 +172,28 @@ static inline void set_idt(struct vcpu_state_t *state, uint64_t base,
172172
state->_idt.limit = limit;
173173
}
174174

175-
static uint64_t vcpu_read_cr(struct vcpu_state_t *state, uint32_t n)
175+
static uint64_t vcpu_read_cr(struct vcpu_t *vcpu, uint32_t n)
176176
{
177177
uint64_t val = 0;
178178

179179
switch (n) {
180-
case 0: {
181-
val = state->_cr0;
182-
break;
183-
}
184-
case 2: {
185-
val = state->_cr2;
186-
break;
187-
}
188-
case 3: {
189-
val = state->_cr3;
190-
break;
191-
}
192-
case 4: {
193-
val = state->_cr4;
194-
break;
195-
}
196-
default: {
197-
hax_error("Unsupported CR%d access\n", n);
198-
break;
199-
}
180+
case 0:
181+
val = vcpu_get_cr0(vcpu);
182+
break;
183+
case 2:
184+
val = vcpu->state->_cr2;
185+
break;
186+
case 3:
187+
val = vcpu_get_cr3(vcpu);
188+
break;
189+
case 4:
190+
val = vcpu_get_cr4(vcpu);
191+
break;
192+
default:
193+
hax_error("Unsupported CR%d access\n", n);
194+
break;
200195
}
201-
202196
hax_debug("vcpu_read_cr cr %x val %llx\n", n, val);
203-
204197
return val;
205198
}
206199

@@ -1665,7 +1658,7 @@ int vcpu_execute(struct vcpu_t *vcpu)
16651658
hax_mutex_lock(vcpu->tmutex);
16661659
hax_debug("vcpu begin to run....\n");
16671660
// QEMU will do realmode stuff for us
1668-
if (!hax->ug_enable_flag && !(vcpu->state->_cr0 & CR0_PE)) {
1661+
if (!hax->ug_enable_flag && !(vcpu_get_cr0(vcpu) & CR0_PE)) {
16691662
htun->_exit_reason = 0;
16701663
htun->_exit_status = HAX_EXIT_REALMODE;
16711664
hax_debug("Guest is in realmode.\n");
@@ -1723,14 +1716,14 @@ int vcpu_vmexit_handler(struct vcpu_t *vcpu, exit_reason_t exit_reason,
17231716

17241717
int vtlb_active(struct vcpu_t *vcpu)
17251718
{
1726-
struct vcpu_state_t *state = vcpu->state;
17271719
struct per_cpu_data *cpu_data = current_cpu_data();
1720+
uint64_t cr0 = vcpu_get_cr0(vcpu);
17281721

17291722
if (hax->ug_enable_flag)
17301723
return 0;
17311724

1732-
hax_debug("vtlb active: cr0, %llx\n", state->_cr0);
1733-
if ((state->_cr0 & CR0_PG) == 0)
1725+
hax_debug("vtlb active: cr0, %llx\n", cr0);
1726+
if ((cr0 & CR0_PG) == 0)
17341727
return 1;
17351728

17361729
if (config.disable_ept)
@@ -2099,6 +2092,7 @@ static int vcpu_emulate_insn(struct vcpu_t *vcpu)
20992092
em_context_t *em_ctxt = &vcpu->emulate_ctxt;
21002093
uint8_t instr[INSTR_MAX_LEN] = {0};
21012094
uint32_t exit_instr_length = vmcs_read(vcpu, VM_EXIT_INFO_INSTRUCTION_LENGTH);
2095+
uint64_t cr0 = vcpu_get_cr0(vcpu);
21022096
uint64_t rip = vcpu_get_rip(vcpu);
21032097
segment_desc_t cs;
21042098
uint64_t va;
@@ -2109,7 +2103,7 @@ static int vcpu_emulate_insn(struct vcpu_t *vcpu)
21092103

21102104
// Detect guest mode
21112105
cs.ar = vcpu_get_seg_ar(vcpu, SEG_CS);
2112-
if (!(vcpu->state->_cr0 & CR0_PE))
2106+
if (!(cr0 & CR0_PE))
21132107
mode = EM_MODE_REAL;
21142108
else if (cs.long_mode == 1)
21152109
mode = EM_MODE_PROT64;
@@ -2794,11 +2788,14 @@ static int exit_cr_access(struct vcpu_t *vcpu, struct hax_tunnel *htun)
27942788
bool is_ept_pae = false;
27952789
preempt_flag flags;
27962790
uint32_t vmcs_err = 0;
2791+
state->_cr0 = vcpu_get_cr0(vcpu);
2792+
state->_cr3 = vcpu_get_cr3(vcpu);
2793+
state->_cr4 = vcpu_get_cr4(vcpu);
27972794

27982795
htun->_exit_reason = vmx(vcpu, exit_reason).basic_reason;
27992796

28002797
cr = qual.cr.creg;
2801-
cr_ptr = vcpu_read_cr(state, cr);
2798+
cr_ptr = vcpu_read_cr(vcpu, cr);
28022799

28032800
switch (qual.cr.type) {
28042801
case 0: { // MOV CR <- GPR
@@ -3259,6 +3256,7 @@ static int handle_msr_read(struct vcpu_t *vcpu, uint32_t msr, uint64_t *val)
32593256
int index, r = 0;
32603257
struct vcpu_state_t *state = vcpu->state;
32613258
struct gstate *gstate = &vcpu->gstate;
3259+
uint64_t cr0, cr4;
32623260

32633261
switch (msr) {
32643262
case IA32_TSC: {
@@ -3278,7 +3276,9 @@ static int handle_msr_read(struct vcpu_t *vcpu, uint32_t msr, uint64_t *val)
32783276
break;
32793277
}
32803278
case IA32_EFER: {
3281-
if (!(state->_cr4 & CR4_PAE) && (state->_cr0 & CR0_PG)) {
3279+
cr0 = vcpu_get_cr0(vcpu);
3280+
cr4 = vcpu_get_cr4(vcpu);
3281+
if (!(cr4 & CR4_PAE) && (cr0 & CR0_PG)) {
32823282
r = 1;
32833283
} else {
32843284
*val = state->_efer;
@@ -3462,8 +3462,9 @@ static int handle_msr_read(struct vcpu_t *vcpu, uint32_t msr, uint64_t *val)
34623462
static void vmwrite_efer(struct vcpu_t *vcpu)
34633463
{
34643464
struct vcpu_state_t *state = vcpu->state;
3465+
uint64_t cr0 = vcpu_get_cr0(vcpu);
34653466

3466-
if ((state->_cr0 & CR0_PG) && (state->_efer & IA32_EFER_LME)) {
3467+
if ((state->_efer & IA32_EFER_LME) && (cr0 & CR0_PG)) {
34673468
state->_efer |= IA32_EFER_LMA;
34683469

34693470
vmwrite(vcpu, VMX_ENTRY_CONTROLS, vmread(vcpu, VMX_ENTRY_CONTROLS) |
@@ -3515,6 +3516,7 @@ static int handle_msr_write(struct vcpu_t *vcpu, uint32_t msr, uint64_t val)
35153516
int index, r = 0;
35163517
struct vcpu_state_t *state = vcpu->state;
35173518
struct gstate *gstate = &vcpu->gstate;
3519+
uint64_t cr0, cr4;
35183520

35193521
switch (msr) {
35203522
case IA32_TSC: {
@@ -3539,10 +3541,12 @@ static int handle_msr_write(struct vcpu_t *vcpu, uint32_t msr, uint64_t val)
35393541
break;
35403542
}
35413543
case IA32_EFER: {
3544+
cr0 = vcpu_get_cr0(vcpu);
3545+
cr4 = vcpu_get_cr4(vcpu);
35423546
hax_info("Guest writing to EFER[%u]: 0x%x -> 0x%llx, _cr0=0x%llx,"
35433547
" _cr4=0x%llx\n", vcpu->vcpu_id, state->_efer, val,
3544-
state->_cr0, state->_cr4);
3545-
if ((state->_cr0 & CR0_PG) && !(state->_cr4 & CR4_PAE)) {
3548+
cr0, cr4);
3549+
if ((cr0 & CR0_PG) && !(cr4 & CR4_PAE)) {
35463550
state->_efer = 0;
35473551
} else {
35483552
state->_efer = val;

core/vmx.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,40 @@ void vcpu_vmcs_flush_cache_w(struct vcpu_t *vcpu)
327327
vcpu->vmx.vmcs_cache_w.dirty = 0;
328328
}
329329

330+
mword vcpu_get_cr0(struct vcpu_t *vcpu)
331+
{
332+
struct vcpu_state_t *state = vcpu->state;
333+
mword cr0, cr0_mask;
334+
335+
// Update only the bits the guest is allowed to change
336+
// This must use the actual cr0 mask, not _cr0_mask.
337+
cr0 = vmcs_read(vcpu, GUEST_CR0);
338+
cr0_mask = vmcs_read(vcpu, VMX_CR0_MASK); // should cache this
339+
state->_cr0 = (cr0 & ~cr0_mask) | (state->_cr0 & cr0_mask);
340+
return state->_cr0;
341+
}
342+
343+
mword vcpu_get_cr3(struct vcpu_t *vcpu)
344+
{
345+
struct vcpu_state_t *state = vcpu->state;
346+
347+
// update CR3 only if guest is allowed to change it
348+
if (!(vmx(vcpu, pcpu_ctls) & CR3_LOAD_EXITING))
349+
state->_cr3 = vmread(vcpu, GUEST_CR3);
350+
return state->_cr3;
351+
}
352+
353+
mword vcpu_get_cr4(struct vcpu_t *vcpu)
354+
{
355+
struct vcpu_state_t *state = vcpu->state;
356+
mword cr4, cr4_mask;
357+
358+
cr4 = vmread(vcpu, GUEST_CR4);
359+
cr4_mask = vmread(vcpu, VMX_CR4_MASK); // should cache this
360+
state->_cr4 = (cr4 & ~cr4_mask) | (state->_cr4 & cr4_mask);
361+
return state->_cr4;
362+
}
363+
330364
mword vcpu_get_rflags(struct vcpu_t *vcpu)
331365
{
332366
return vmcs_read(vcpu, GUEST_RFLAGS);

core/vtlb.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,10 +1162,13 @@ uint vcpu_translate(struct vcpu_t *vcpu, hax_vaddr_t va, uint access, hax_paddr_
11621162

11631163
pagemode_t vcpu_get_pagemode(struct vcpu_t *vcpu)
11641164
{
1165-
if (!(vcpu->state->_cr0 & CR0_PG))
1165+
uint64_t cr0 = vcpu_get_cr0(vcpu);
1166+
uint64_t cr4 = vcpu_get_cr4(vcpu);
1167+
1168+
if (!(cr0 & CR0_PG))
11661169
return PM_FLAT;
11671170

1168-
if (!(vcpu->state->_cr4 & CR4_PAE))
1171+
if (!(cr4 & CR4_PAE))
11691172
return PM_2LVL;
11701173

11711174
// Only support pure 32-bit paging. May support PAE paging in future.

0 commit comments

Comments
 (0)