Commit 8a86aea9 authored by Paolo Bonzini's avatar Paolo Bonzini

KVM: vmx: detect mismatched size in VMCS read/write

Signed-off-by: default avatarPaolo Bonzini <pbonzini@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.
parent 845c5b40
...@@ -1447,7 +1447,51 @@ static inline void ept_sync_context(u64 eptp) ...@@ -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; unsigned long value;
...@@ -1458,23 +1502,32 @@ static __always_inline unsigned long vmcs_readl(unsigned long field) ...@@ -1458,23 +1502,32 @@ static __always_inline unsigned long vmcs_readl(unsigned long field)
static __always_inline u16 vmcs_read16(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) 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) static __always_inline u64 vmcs_read64(unsigned long field)
{ {
vmcs_check64(field);
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
return vmcs_readl(field); return __vmcs_readl(field);
#else #else
return vmcs_readl(field) | ((u64)vmcs_readl(field+1) << 32); return __vmcs_readl(field) | ((u64)__vmcs_readl(field+1) << 32);
#endif #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) static noinline void vmwrite_error(unsigned long field, unsigned long value)
{ {
printk(KERN_ERR "vmwrite error: reg %lx value %lx (err %d)\n", 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) ...@@ -1482,7 +1535,7 @@ static noinline void vmwrite_error(unsigned long field, unsigned long value)
dump_stack(); 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; u8 error;
...@@ -1492,33 +1545,46 @@ static void vmcs_writel(unsigned long field, unsigned long value) ...@@ -1492,33 +1545,46 @@ static void vmcs_writel(unsigned long field, unsigned long value)
vmwrite_error(field, 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 #ifndef CONFIG_X86_64
asm volatile (""); asm volatile ("");
vmcs_writel(field+1, value >> 32); __vmcs_writel(field+1, value >> 32);
#endif #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) static inline void vm_entry_controls_init(struct vcpu_vmx *vmx, u32 val)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment