Skip to content

Commit 892a42c

Browse files
vittyvkbonzini
authored andcommitted
KVM: nVMX: Implement evmcs_field_offset() suitable for handle_vmread()
In preparation to allowing reads from Enlightened VMCS from handle_vmread(), implement evmcs_field_offset() to get the correct read offset. get_evmcs_offset(), which is being used by KVM-on-Hyper-V, is almost what's needed but a few things need to be adjusted. First, WARN_ON() is unacceptable for handle_vmread() as any field can (in theory) be supplied by the guest and not all fields are defined in eVMCS v1. Second, we need to handle 'holes' in eVMCS (missing fields). It also sounds like a good idea to WARN_ON() if such fields are ever accessed by KVM-on-Hyper-V. Implement dedicated evmcs_field_offset() helper. No functional change intended. Signed-off-by: Vitaly Kuznetsov <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 2423a4c commit 892a42c

File tree

2 files changed

+25
-10
lines changed

2 files changed

+25
-10
lines changed

arch/x86/kvm/vmx/evmcs.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212

1313
DEFINE_STATIC_KEY_FALSE(enable_evmcs);
1414

15-
#if IS_ENABLED(CONFIG_HYPERV)
16-
1715
#define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x)
1816
#define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \
1917
{EVMCS1_OFFSET(name), clean_field}
@@ -296,6 +294,7 @@ const struct evmcs_field vmcs_field_to_evmcs_1[] = {
296294
};
297295
const unsigned int nr_evmcs_1_fields = ARRAY_SIZE(vmcs_field_to_evmcs_1);
298296

297+
#if IS_ENABLED(CONFIG_HYPERV)
299298
__init void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf)
300299
{
301300
vmcs_conf->pin_based_exec_ctrl &= ~EVMCS1_UNSUPPORTED_PINCTRL;

arch/x86/kvm/vmx/evmcs.h

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,6 @@ DECLARE_STATIC_KEY_FALSE(enable_evmcs);
6565
#define EVMCS1_UNSUPPORTED_VMENTRY_CTRL (VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL)
6666
#define EVMCS1_UNSUPPORTED_VMFUNC (VMX_VMFUNC_EPTP_SWITCHING)
6767

68-
#if IS_ENABLED(CONFIG_HYPERV)
69-
7068
struct evmcs_field {
7169
u16 offset;
7270
u16 clean_field;
@@ -75,26 +73,44 @@ struct evmcs_field {
7573
extern const struct evmcs_field vmcs_field_to_evmcs_1[];
7674
extern const unsigned int nr_evmcs_1_fields;
7775

78-
static __always_inline int get_evmcs_offset(unsigned long field,
79-
u16 *clean_field)
76+
static __always_inline int evmcs_field_offset(unsigned long field,
77+
u16 *clean_field)
8078
{
8179
unsigned int index = ROL16(field, 6);
8280
const struct evmcs_field *evmcs_field;
8381

84-
if (unlikely(index >= nr_evmcs_1_fields)) {
85-
WARN_ONCE(1, "KVM: accessing unsupported EVMCS field %lx\n",
86-
field);
82+
if (unlikely(index >= nr_evmcs_1_fields))
8783
return -ENOENT;
88-
}
8984

9085
evmcs_field = &vmcs_field_to_evmcs_1[index];
9186

87+
/*
88+
* Use offset=0 to detect holes in eVMCS. This offset belongs to
89+
* 'revision_id' but this field has no encoding and is supposed to
90+
* be accessed directly.
91+
*/
92+
if (unlikely(!evmcs_field->offset))
93+
return -ENOENT;
94+
9295
if (clean_field)
9396
*clean_field = evmcs_field->clean_field;
9497

9598
return evmcs_field->offset;
9699
}
97100

101+
#if IS_ENABLED(CONFIG_HYPERV)
102+
103+
static __always_inline int get_evmcs_offset(unsigned long field,
104+
u16 *clean_field)
105+
{
106+
int offset = evmcs_field_offset(field, clean_field);
107+
108+
WARN_ONCE(offset < 0, "KVM: accessing unsupported EVMCS field %lx\n",
109+
field);
110+
111+
return offset;
112+
}
113+
98114
static __always_inline void evmcs_write64(unsigned long field, u64 value)
99115
{
100116
u16 clean_field;

0 commit comments

Comments
 (0)