Re: [PATCH v2 1/2] KVM: nVMX: Disallow access to vmcs12 fields that aren't supported by "hardware"

From: Xiaoyao Li

Date: Wed Dec 31 2025 - 03:37:00 EST


On 12/31/2025 6:02 AM, Sean Christopherson wrote:
+/*
+ * Indexing into the vmcs12 uses the VMCS encoding rotated left by 6 as a very
+ * rudimentary compression of the range of indices. The compression ratio is
+ * good enough to allow KVM to use a (very sparsely populated) array without
+ * wasting too much memory, while the "algorithm" is fast enough to be used to
+ * lookup vmcs12 fields on-demand, e.g. for emulation.
+ */
#define ROL16(val, n) ((u16)(((u16)(val) << (n)) | ((u16)(val) >> (16 - (n)))))
+#define VMCS12_IDX_TO_ENC(idx) ((u16)(((u16)(idx) >> 6) | ((u16)(idx) << 10)))

Put them together is really good.

And ROL16(val, 16-n) is exactly undoing ROL16(val, n), so that we can further do

---8<---
diff --git a/arch/x86/kvm/vmx/vmcs.h b/arch/x86/kvm/vmx/vmcs.h
index 98281e019e38..be2f410f82cd 100644
--- a/arch/x86/kvm/vmx/vmcs.h
+++ b/arch/x86/kvm/vmx/vmcs.h
@@ -19,7 +19,8 @@
* lookup vmcs12 fields on-demand, e.g. for emulation.
*/
#define ROL16(val, n) ((u16)(((u16)(val) << (n)) | ((u16)(val) >> (16 - (n)))))
-#define VMCS12_IDX_TO_ENC(idx) ((u16)(((u16)(idx) >> 6) | ((u16)(idx) << 10)))
+#define ENC_TO_VMCS12_IDX(enc) ROL16(enc, 6)
+#define VMCS12_IDX_TO_ENC(idx) ROL16(idx,10)

struct vmcs_hdr {
u32 revision_id:31;
diff --git a/arch/x86/kvm/vmx/vmcs12.c b/arch/x86/kvm/vmx/vmcs12.c
index b92db4768346..1ebe67c384ad 100644
--- a/arch/x86/kvm/vmx/vmcs12.c
+++ b/arch/x86/kvm/vmx/vmcs12.c
@@ -4,10 +4,10 @@
#include "vmcs12.h"

#define VMCS12_OFFSET(x) offsetof(struct vmcs12, x)
-#define FIELD(number, name) [ROL16(number, 6)] = VMCS12_OFFSET(name)
+#define FIELD(number, name) [ENC_TO_VMCS12_IDX(number)] = VMCS12_OFFSET(name)
#define FIELD64(number, name) \
FIELD(number, name), \
- [ROL16(number##_HIGH, 6)] = VMCS12_OFFSET(name) + sizeof(u32)
+ [ENC_TO_VMCS12_IDX(number##_HIGH)] = VMCS12_OFFSET(name) + sizeof(u32)

static const u16 kvm_supported_vmcs12_field_offsets[] __initconst = {
FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id),