diff mbox series

[04/11] i386/hvf: Pre-fetch emulated instructions

Message ID 20241209203629.74436-5-phil@philjordan.eu (mailing list archive)
State New
Headers show
Series hvf and APIC fixes, improvements, and optimisations | expand

Commit Message

Phil Dennis-Jordan Dec. 9, 2024, 8:36 p.m. UTC
From: Phil Dennis-Jordan <phil@philjordan.eu>

The HVF x86 instruction decoder has previously read each instruction
component a few bytes at a time. The HVF vCPU VM exit reports the length
of the faulted instruction, so we can just pre-fetch the memory for the
whole thing in one go, saving extra round-trips for most instructions.

The old code path is retained in case there is a race between VM exit
and another thread overwriting the faulted instruction. In this case,
the instruction length could be wrong, so we allow fetching additional
instruction bytes the traditional way if the prefetched bytes are
overrun.

Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
---
 target/i386/hvf/hvf.c        |  6 +++---
 target/i386/hvf/x86_decode.c | 18 +++++++++++++++---
 target/i386/hvf/x86_decode.h |  5 ++++-
 3 files changed, 22 insertions(+), 7 deletions(-)
diff mbox series

Patch

diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c
index 936c31dbdd..095f934923 100644
--- a/target/i386/hvf/hvf.c
+++ b/target/i386/hvf/hvf.c
@@ -522,7 +522,7 @@  int hvf_vcpu_exec(CPUState *cpu)
                 struct x86_decode decode;
 
                 load_regs(cpu);
-                decode_instruction(env, &decode);
+                decode_instruction(env, &decode, ins_len);
                 exec_instruction(env, &decode);
                 store_regs(cpu);
                 break;
@@ -562,7 +562,7 @@  int hvf_vcpu_exec(CPUState *cpu)
             struct x86_decode decode;
 
             load_regs(cpu);
-            decode_instruction(env, &decode);
+            decode_instruction(env, &decode, ins_len);
             assert(ins_len == decode.len);
             exec_instruction(env, &decode);
             store_regs(cpu);
@@ -667,7 +667,7 @@  int hvf_vcpu_exec(CPUState *cpu)
             struct x86_decode decode;
 
             load_regs(cpu);
-            decode_instruction(env, &decode);
+            decode_instruction(env, &decode, ins_len);
             exec_instruction(env, &decode);
             store_regs(cpu);
             break;
diff --git a/target/i386/hvf/x86_decode.c b/target/i386/hvf/x86_decode.c
index a4a28f113f..79dfc30408 100644
--- a/target/i386/hvf/x86_decode.c
+++ b/target/i386/hvf/x86_decode.c
@@ -73,8 +73,13 @@  static inline uint64_t decode_bytes(CPUX86State *env, struct x86_decode *decode,
         VM_PANIC_EX("%s invalid size %d\n", __func__, size);
         break;
     }
-    target_ulong va  = linear_rip(env_cpu(env), env->eip) + decode->len;
-    vmx_read_mem(env_cpu(env), &val, va, size);
+
+    if (decode->len + size < decode->prefetch_len) {
+        memcpy(&val, decode->prefetch_buf + decode->len, size);
+    } else {
+        target_ulong va  = linear_rip(env_cpu(env), env->eip) + decode->len;
+        vmx_read_mem(env_cpu(env), &val, va, size);
+    }
     decode->len += size;
     
     return val;
@@ -2099,9 +2104,16 @@  static void decode_opcodes(CPUX86State *env, struct x86_decode *decode)
     }
 }
 
-uint32_t decode_instruction(CPUX86State *env, struct x86_decode *decode)
+uint32_t decode_instruction(CPUX86State *env, x86_decode *decode,
+                            uint32_t ins_len)
 {
     memset(decode, 0, sizeof(*decode));
+
+    target_ulong va = linear_rip(env_cpu(env), env->eip);
+    uint32_t prefetch_len = MIN(ins_len, sizeof(sizeof(decode->prefetch_buf)));
+    vmx_read_mem(env_cpu(env), decode->prefetch_buf, va, prefetch_len);
+    decode->prefetch_len = prefetch_len;
+
     decode_prefix(env, decode);
     set_addressing_size(env, decode);
     set_operand_size(env, decode);
diff --git a/target/i386/hvf/x86_decode.h b/target/i386/hvf/x86_decode.h
index a2d7a2a27b..0ff368210b 100644
--- a/target/i386/hvf/x86_decode.h
+++ b/target/i386/hvf/x86_decode.h
@@ -297,11 +297,14 @@  typedef struct x86_decode {
     bool is_fpu;
     uint32_t flags_mask;
 
+    uint8_t prefetch_buf[16];
+    uint16_t prefetch_len;
 } x86_decode;
 
 uint64_t sign(uint64_t val, int size);
 
-uint32_t decode_instruction(CPUX86State *env, struct x86_decode *decode);
+uint32_t decode_instruction(CPUX86State *env, x86_decode *decode,
+                            uint32_t ins_len);
 
 target_ulong get_reg_ref(CPUX86State *env, int reg, int rex_present,
                          int is_extended, int size);