aboutsummaryrefslogtreecommitdiffstats
path: root/executor
diff options
context:
space:
mode:
authorAlexander Potapenko <glider@google.com>2025-11-20 17:46:18 +0100
committerAlexander Potapenko <glider@google.com>2025-11-21 08:57:45 +0000
commit880e0a0225f6667373f85f9dfa78b5d9fb6e29e2 (patch)
tree349bf812194898ee4fb008dcc778bb63d6e0b71f /executor
parentf7a9f9c4982d10223771d3aa2287538bc08b9024 (diff)
executor: x86: factor out common code in rdmsr()/wrmsr()
While at it, fix a bug in rdmsr() that apparently lost the top 32 bits. Also fix a bug in Intel's Secondary Processor-based Controls: we were incorrectly using the top 32 bits of X86_MSR_IA32_VMX_PROCBASED_CTLS2 to enable all the available controls without additional setup. This only worked because rdmsr() zeroed out those top bits.
Diffstat (limited to 'executor')
-rw-r--r--executor/common_kvm_amd64_syzos.h58
1 files changed, 21 insertions, 37 deletions
diff --git a/executor/common_kvm_amd64_syzos.h b/executor/common_kvm_amd64_syzos.h
index 9971c1c7b..20b392eb4 100644
--- a/executor/common_kvm_amd64_syzos.h
+++ b/executor/common_kvm_amd64_syzos.h
@@ -249,11 +249,8 @@ GUEST_CODE static noinline void guest_handle_cpuid(uint32 eax, uint32 ecx)
: "rbx", "rdx");
}
-// Write val into an MSR register reg.
-GUEST_CODE static noinline void guest_handle_wrmsr(uint64 reg, uint64 val)
+GUEST_CODE static noinline void wrmsr(uint64 reg, uint64 val)
{
- // The wrmsr instruction takes its arguments in specific registers:
- // edx:eax contains the 64-bit value to write, ecx contains the MSR address.
asm volatile(
"wrmsr"
:
@@ -263,20 +260,26 @@ GUEST_CODE static noinline void guest_handle_wrmsr(uint64 reg, uint64 val)
: "memory");
}
-// Read an MSR register, ignore the result.
-GUEST_CODE static noinline void guest_handle_rdmsr(uint64 reg)
+// Write val into an MSR register reg.
+GUEST_CODE static noinline void guest_handle_wrmsr(uint64 reg, uint64 val)
{
- uint32 low = 0, high = 0;
- // The rdmsr instruction takes the MSR address in ecx.
+ wrmsr(reg, val);
+}
+
+GUEST_CODE static noinline uint64 rdmsr(uint64 msr_id)
+{
+ uint32 low = 0, high = 0; // nolint
+ // The RDMSR instruction takes the MSR address in ecx.
// It puts the lower 32 bits of the MSR value into eax, and the upper.
// 32 bits of the MSR value into edx.
- asm volatile(
- "rdmsr"
- : "=a"(low),
- "=d"(high)
- : "c"(reg)
- : // No explicit clobbers.
- );
+ asm volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(msr_id));
+ return ((uint64)high << 32) | low;
+}
+
+// Read an MSR register, ignore the result.
+GUEST_CODE static noinline void guest_handle_rdmsr(uint64 reg)
+{
+ (void)rdmsr(reg);
}
// Write to CRn control register.
@@ -488,24 +491,6 @@ GUEST_CODE static inline void write_cr4(uint64 val)
asm volatile("mov %0, %%cr4" : : "r"(val));
}
-GUEST_CODE static noinline void wrmsr(uint64 reg, uint64 val)
-{
- asm volatile(
- "wrmsr"
- :
- : "c"(reg),
- "a"((uint32)val),
- "d"((uint32)(val >> 32))
- : "memory");
-}
-
-GUEST_CODE static noinline uint64 rdmsr(uint32 msr_id)
-{
- uint64 msr_value;
- asm volatile("rdmsr" : "=A"(msr_value) : "c"(msr_id));
- return msr_value;
-}
-
GUEST_CODE static noinline void vmwrite(uint64 field, uint64 value)
{
uint8 error = 0; // nolint
@@ -678,10 +663,9 @@ GUEST_CODE static noinline void init_vmcs_control_fields(uint64 cpu_id, uint64 v
vmwrite(VMCS_PIN_BASED_VM_EXEC_CONTROL, (uint32)vmx_msr);
// Setup Secondary Processor-Based controls: enable EPT.
- vmx_msr = rdmsr(X86_MSR_IA32_VMX_PROCBASED_CTLS2);
- uint32 sec_exec_ctl = (uint32)(vmx_msr >> 32); // Must-be-1 bits.
- sec_exec_ctl |= ((uint32)vmx_msr & SECONDARY_EXEC_ENABLE_EPT); // Allowed bits.
- vmwrite(VMCS_SECONDARY_VM_EXEC_CONTROL, sec_exec_ctl);
+ vmx_msr = (uint32)rdmsr(X86_MSR_IA32_VMX_PROCBASED_CTLS2);
+ vmx_msr |= SECONDARY_EXEC_ENABLE_EPT;
+ vmwrite(VMCS_SECONDARY_VM_EXEC_CONTROL, vmx_msr);
// Read and write Primary Processor-Based controls from TRUE MSR.
// We also add the bit to enable the secondary controls.