KVM: nVMX: Track vmcs12 offsets for shadowed VMCS fields
The vmcs12 fields offsets are constant and known at compile time. Store the associated offset for each shadowed field to avoid the costly lookup in vmcs_field_to_offset() when copying between vmcs12 and the shadow VMCS. Avoiding the costly lookup reduces the latency of copying by ~100 cycles in each direction. Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:

committed by
Paolo Bonzini

parent
b643780562
commit
1c6f0b47fb
@@ -394,69 +394,48 @@ static inline short vmcs_field_to_offset(unsigned long field)
|
||||
|
||||
#undef ROL16
|
||||
|
||||
/*
|
||||
* Read a vmcs12 field. Since these can have varying lengths and we return
|
||||
* one type, we chose the biggest type (u64) and zero-extend the return value
|
||||
* to that size. Note that the caller, handle_vmread, might need to use only
|
||||
* some of the bits we return here (e.g., on 32-bit guests, only 32 bits of
|
||||
* 64-bit fields are to be returned).
|
||||
*/
|
||||
static inline int vmcs12_read_any(struct vmcs12 *vmcs12,
|
||||
unsigned long field, u64 *ret)
|
||||
static inline u64 vmcs12_read_any(struct vmcs12 *vmcs12, unsigned long field,
|
||||
u16 offset)
|
||||
{
|
||||
short offset = vmcs_field_to_offset(field);
|
||||
char *p;
|
||||
|
||||
if (offset < 0)
|
||||
return offset;
|
||||
|
||||
p = (char *)vmcs12 + offset;
|
||||
char *p = (char *)vmcs12 + offset;
|
||||
|
||||
switch (vmcs_field_width(field)) {
|
||||
case VMCS_FIELD_WIDTH_NATURAL_WIDTH:
|
||||
*ret = *((natural_width *)p);
|
||||
return 0;
|
||||
return *((natural_width *)p);
|
||||
case VMCS_FIELD_WIDTH_U16:
|
||||
*ret = *((u16 *)p);
|
||||
return 0;
|
||||
return *((u16 *)p);
|
||||
case VMCS_FIELD_WIDTH_U32:
|
||||
*ret = *((u32 *)p);
|
||||
return 0;
|
||||
return *((u32 *)p);
|
||||
case VMCS_FIELD_WIDTH_U64:
|
||||
*ret = *((u64 *)p);
|
||||
return 0;
|
||||
return *((u64 *)p);
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return -ENOENT;
|
||||
WARN_ON_ONCE(1);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int vmcs12_write_any(struct vmcs12 *vmcs12,
|
||||
unsigned long field, u64 field_value){
|
||||
short offset = vmcs_field_to_offset(field);
|
||||
static inline void vmcs12_write_any(struct vmcs12 *vmcs12, unsigned long field,
|
||||
u16 offset, u64 field_value)
|
||||
{
|
||||
char *p = (char *)vmcs12 + offset;
|
||||
|
||||
if (offset < 0)
|
||||
return offset;
|
||||
|
||||
switch (vmcs_field_width(field)) {
|
||||
case VMCS_FIELD_WIDTH_U16:
|
||||
*(u16 *)p = field_value;
|
||||
return 0;
|
||||
break;
|
||||
case VMCS_FIELD_WIDTH_U32:
|
||||
*(u32 *)p = field_value;
|
||||
return 0;
|
||||
break;
|
||||
case VMCS_FIELD_WIDTH_U64:
|
||||
*(u64 *)p = field_value;
|
||||
return 0;
|
||||
break;
|
||||
case VMCS_FIELD_WIDTH_NATURAL_WIDTH:
|
||||
*(natural_width *)p = field_value;
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return -ENOENT;
|
||||
WARN_ON_ONCE(1);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* __KVM_X86_VMX_VMCS12_H */
|
||||
|
Reference in New Issue
Block a user