Signed-off-by: Paolo Bonzini <pbonz...@redhat.com>
---
        I am sending this as RFC because the error messages it produces are
        very ugly.  Because of inlining, the original line is lost.  The
        alternative is to change vmcs_read/write/checkXX into macros, but
        then you need to have a single huge BUILD_BUG_ON or BUILD_BUG_ON_MSG
        because multiple BUILD_BUG_ON* with the same __LINE__ are not
        supported well.
---
 arch/x86/kvm/vmx.c | 100 ++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 83 insertions(+), 17 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index b1a453d78155..62d958a1ec0f 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -1447,7 +1447,51 @@ static inline void ept_sync_context(u64 eptp)
        }
 }
 
-static __always_inline unsigned long vmcs_readl(unsigned long field)
+static __always_inline void vmcs_check16(unsigned long field)
+{
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 
0x2000,
+                        "16-bit accessor invalid for 64-bit field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 
0x2001,
+                        "16-bit accessor invalid for 64-bit high field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 
0x4000,
+                        "16-bit accessor invalid for 32-bit high field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 
0x6000,
+                        "16-bit accessor invalid for natural width field");
+}
+
+static __always_inline void vmcs_check32(unsigned long field)
+{
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 
0,
+                        "32-bit accessor invalid for 16-bit field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 
0x6000,
+                        "32-bit accessor invalid for natural width field");
+}
+
+static __always_inline void vmcs_check64(unsigned long field)
+{
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 
0,
+                        "64-bit accessor invalid for 16-bit field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 
0x2001,
+                        "64-bit accessor invalid for 64-bit high field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 
0x4000,
+                        "64-bit accessor invalid for 32-bit field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 
0x6000,
+                        "64-bit accessor invalid for natural width field");
+}
+
+static __always_inline void vmcs_checkl(unsigned long field)
+{
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 
0,
+                        "Natural width accessor invalid for 16-bit field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 
0x2000,
+                        "Natural width accessor invalid for 64-bit field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 
0x2001,
+                        "Natural width accessor invalid for 64-bit high 
field");
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 
0x4000,
+                        "Natural width accessor invalid for 32-bit field");
+}
+
+static __always_inline unsigned long __vmcs_readl(unsigned long field)
 {
        unsigned long value;
 
@@ -1458,23 +1502,32 @@ static __always_inline unsigned long 
vmcs_readl(unsigned long field)
 
 static __always_inline u16 vmcs_read16(unsigned long field)
 {
-       return vmcs_readl(field);
+       vmcs_check16(field);
+       return __vmcs_readl(field);
 }
 
 static __always_inline u32 vmcs_read32(unsigned long field)
 {
-       return vmcs_readl(field);
+       vmcs_check32(field);
+       return __vmcs_readl(field);
 }
 
 static __always_inline u64 vmcs_read64(unsigned long field)
 {
+       vmcs_check64(field);
 #ifdef CONFIG_X86_64
-       return vmcs_readl(field);
+       return __vmcs_readl(field);
 #else
-       return vmcs_readl(field) | ((u64)vmcs_readl(field+1) << 32);
+       return __vmcs_readl(field) | ((u64)__vmcs_readl(field+1) << 32);
 #endif
 }
 
+static __always_inline unsigned long vmcs_readl(unsigned long field)
+{
+       vmcs_checkl(field);
+       return __vmcs_readl(field);
+}
+
 static noinline void vmwrite_error(unsigned long field, unsigned long value)
 {
        printk(KERN_ERR "vmwrite error: reg %lx value %lx (err %d)\n",
@@ -1482,7 +1535,7 @@ static noinline void vmwrite_error(unsigned long field, 
unsigned long value)
        dump_stack();
 }
 
-static void vmcs_writel(unsigned long field, unsigned long value)
+static __always_inline void __vmcs_writel(unsigned long field, unsigned long 
value)
 {
        u8 error;
 
@@ -1492,33 +1545,46 @@ static void vmcs_writel(unsigned long field, unsigned 
long value)
                vmwrite_error(field, value);
 }
 
-static void vmcs_write16(unsigned long field, u16 value)
+static __always_inline void vmcs_write16(unsigned long field, u16 value)
 {
-       vmcs_writel(field, value);
+       vmcs_check16(field);
+       __vmcs_writel(field, value);
 }
 
-static void vmcs_write32(unsigned long field, u32 value)
+static __always_inline void vmcs_write32(unsigned long field, u32 value)
 {
-       vmcs_writel(field, value);
+       vmcs_check32(field);
+       __vmcs_writel(field, value);
 }
 
-static void vmcs_write64(unsigned long field, u64 value)
+static __always_inline void vmcs_write64(unsigned long field, u64 value)
 {
-       vmcs_writel(field, value);
+       vmcs_check64(field);
+       __vmcs_writel(field, value);
 #ifndef CONFIG_X86_64
        asm volatile ("");
-       vmcs_writel(field+1, value >> 32);
+       __vmcs_writel(field+1, value >> 32);
 #endif
 }
 
-static void vmcs_clear_bits(unsigned long field, u32 mask)
+static __always_inline void vmcs_writel(unsigned long field, unsigned long 
value)
+{
+       vmcs_checkl(field);
+       __vmcs_writel(field, value);
+}
+
+static __always_inline void vmcs_clear_bits(unsigned long field, u32 mask)
 {
-       vmcs_writel(field, vmcs_readl(field) & ~mask);
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 
0x2000,
+                        "vmcs_clear_bits does not support 64-bit fields");
+       __vmcs_writel(field, __vmcs_readl(field) & ~mask);
 }
 
-static void vmcs_set_bits(unsigned long field, u32 mask)
+static __always_inline void vmcs_set_bits(unsigned long field, u32 mask)
 {
-       vmcs_writel(field, vmcs_readl(field) | mask);
+        BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 
0x2000,
+                        "vmcs_set_bits does not support 64-bit fields");
+       __vmcs_writel(field, __vmcs_readl(field) | mask);
 }
 
 static inline void vm_entry_controls_init(struct vcpu_vmx *vmx, u32 val)
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to