Skip to content

Commit 43d97b2

Browse files
committed
Merge tag 'kvm-x86-pat_vmx_msrs-6.12' of https://github.com/kvm-x86/linux into HEAD
KVM VMX and x86 PAT MSR macro cleanup for 6.12: - Add common defines for the x86 architectural memory types, i.e. the types that are shared across PAT, MTRRs, VMCSes, and EPTPs. - Clean up the various VMX MSR macros to make the code self-documenting (inasmuch as possible), and to make it less painful to add new macros.
2 parents 5d55a05 + 566975f commit 43d97b2

File tree

10 files changed

+132
-95
lines changed

10 files changed

+132
-95
lines changed

arch/x86/include/asm/msr-index.h

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,20 @@
3636
#define EFER_FFXSR (1<<_EFER_FFXSR)
3737
#define EFER_AUTOIBRS (1<<_EFER_AUTOIBRS)
3838

39+
/*
40+
* Architectural memory types that are common to MTRRs, PAT, VMX MSRs, etc.
41+
* Most MSRs support/allow only a subset of memory types, but the values
42+
* themselves are common across all relevant MSRs.
43+
*/
44+
#define X86_MEMTYPE_UC 0ull /* Uncacheable, a.k.a. Strong Uncacheable */
45+
#define X86_MEMTYPE_WC 1ull /* Write Combining */
46+
/* RESERVED 2 */
47+
/* RESERVED 3 */
48+
#define X86_MEMTYPE_WT 4ull /* Write Through */
49+
#define X86_MEMTYPE_WP 5ull /* Write Protected */
50+
#define X86_MEMTYPE_WB 6ull /* Write Back */
51+
#define X86_MEMTYPE_UC_MINUS 7ull /* Weak Uncacheabled (PAT only) */
52+
3953
/* FRED MSRs */
4054
#define MSR_IA32_FRED_RSP0 0x1cc /* Level 0 stack pointer */
4155
#define MSR_IA32_FRED_RSP1 0x1cd /* Level 1 stack pointer */
@@ -363,6 +377,12 @@
363377

364378
#define MSR_IA32_CR_PAT 0x00000277
365379

380+
#define PAT_VALUE(p0, p1, p2, p3, p4, p5, p6, p7) \
381+
((X86_MEMTYPE_ ## p0) | (X86_MEMTYPE_ ## p1 << 8) | \
382+
(X86_MEMTYPE_ ## p2 << 16) | (X86_MEMTYPE_ ## p3 << 24) | \
383+
(X86_MEMTYPE_ ## p4 << 32) | (X86_MEMTYPE_ ## p5 << 40) | \
384+
(X86_MEMTYPE_ ## p6 << 48) | (X86_MEMTYPE_ ## p7 << 56))
385+
366386
#define MSR_IA32_DEBUGCTLMSR 0x000001d9
367387
#define MSR_IA32_LASTBRANCHFROMIP 0x000001db
368388
#define MSR_IA32_LASTBRANCHTOIP 0x000001dc
@@ -1157,15 +1177,6 @@
11571177
#define MSR_IA32_VMX_VMFUNC 0x00000491
11581178
#define MSR_IA32_VMX_PROCBASED_CTLS3 0x00000492
11591179

1160-
/* VMX_BASIC bits and bitmasks */
1161-
#define VMX_BASIC_VMCS_SIZE_SHIFT 32
1162-
#define VMX_BASIC_TRUE_CTLS (1ULL << 55)
1163-
#define VMX_BASIC_64 0x0001000000000000LLU
1164-
#define VMX_BASIC_MEM_TYPE_SHIFT 50
1165-
#define VMX_BASIC_MEM_TYPE_MASK 0x003c000000000000LLU
1166-
#define VMX_BASIC_MEM_TYPE_WB 6LLU
1167-
#define VMX_BASIC_INOUT 0x0040000000000000LLU
1168-
11691180
/* Resctrl MSRs: */
11701181
/* - Intel: */
11711182
#define MSR_IA32_L3_QOS_CFG 0xc81
@@ -1183,11 +1194,6 @@
11831194
#define MSR_IA32_SMBA_BW_BASE 0xc0000280
11841195
#define MSR_IA32_EVT_CFG_BASE 0xc0000400
11851196

1186-
/* MSR_IA32_VMX_MISC bits */
1187-
#define MSR_IA32_VMX_MISC_INTEL_PT (1ULL << 14)
1188-
#define MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS (1ULL << 29)
1189-
#define MSR_IA32_VMX_MISC_PREEMPTION_TIMER_SCALE 0x1F
1190-
11911197
/* AMD-V MSRs */
11921198
#define MSR_VM_CR 0xc0010114
11931199
#define MSR_VM_IGNNE 0xc0010115

arch/x86/include/asm/vmx.h

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -122,19 +122,17 @@
122122

123123
#define VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR 0x000011ff
124124

125-
#define VMX_MISC_PREEMPTION_TIMER_RATE_MASK 0x0000001f
126-
#define VMX_MISC_SAVE_EFER_LMA 0x00000020
127-
#define VMX_MISC_ACTIVITY_HLT 0x00000040
128-
#define VMX_MISC_ACTIVITY_WAIT_SIPI 0x00000100
129-
#define VMX_MISC_ZERO_LEN_INS 0x40000000
130-
#define VMX_MISC_MSR_LIST_MULTIPLIER 512
131-
132125
/* VMFUNC functions */
133126
#define VMFUNC_CONTROL_BIT(x) BIT((VMX_FEATURE_##x & 0x1f) - 28)
134127

135128
#define VMX_VMFUNC_EPTP_SWITCHING VMFUNC_CONTROL_BIT(EPTP_SWITCHING)
136129
#define VMFUNC_EPTP_ENTRIES 512
137130

131+
#define VMX_BASIC_32BIT_PHYS_ADDR_ONLY BIT_ULL(48)
132+
#define VMX_BASIC_DUAL_MONITOR_TREATMENT BIT_ULL(49)
133+
#define VMX_BASIC_INOUT BIT_ULL(54)
134+
#define VMX_BASIC_TRUE_CTLS BIT_ULL(55)
135+
138136
static inline u32 vmx_basic_vmcs_revision_id(u64 vmx_basic)
139137
{
140138
return vmx_basic & GENMASK_ULL(30, 0);
@@ -145,9 +143,30 @@ static inline u32 vmx_basic_vmcs_size(u64 vmx_basic)
145143
return (vmx_basic & GENMASK_ULL(44, 32)) >> 32;
146144
}
147145

146+
static inline u32 vmx_basic_vmcs_mem_type(u64 vmx_basic)
147+
{
148+
return (vmx_basic & GENMASK_ULL(53, 50)) >> 50;
149+
}
150+
151+
static inline u64 vmx_basic_encode_vmcs_info(u32 revision, u16 size, u8 memtype)
152+
{
153+
return revision | ((u64)size << 32) | ((u64)memtype << 50);
154+
}
155+
156+
#define VMX_MISC_SAVE_EFER_LMA BIT_ULL(5)
157+
#define VMX_MISC_ACTIVITY_HLT BIT_ULL(6)
158+
#define VMX_MISC_ACTIVITY_SHUTDOWN BIT_ULL(7)
159+
#define VMX_MISC_ACTIVITY_WAIT_SIPI BIT_ULL(8)
160+
#define VMX_MISC_INTEL_PT BIT_ULL(14)
161+
#define VMX_MISC_RDMSR_IN_SMM BIT_ULL(15)
162+
#define VMX_MISC_VMXOFF_BLOCK_SMI BIT_ULL(28)
163+
#define VMX_MISC_VMWRITE_SHADOW_RO_FIELDS BIT_ULL(29)
164+
#define VMX_MISC_ZERO_LEN_INS BIT_ULL(30)
165+
#define VMX_MISC_MSR_LIST_MULTIPLIER 512
166+
148167
static inline int vmx_misc_preemption_timer_rate(u64 vmx_misc)
149168
{
150-
return vmx_misc & VMX_MISC_PREEMPTION_TIMER_RATE_MASK;
169+
return vmx_misc & GENMASK_ULL(4, 0);
151170
}
152171

153172
static inline int vmx_misc_cr3_count(u64 vmx_misc)
@@ -508,9 +527,10 @@ enum vmcs_field {
508527
#define VMX_EPTP_PWL_4 0x18ull
509528
#define VMX_EPTP_PWL_5 0x20ull
510529
#define VMX_EPTP_AD_ENABLE_BIT (1ull << 6)
530+
/* The EPTP memtype is encoded in bits 2:0, i.e. doesn't need to be shifted. */
511531
#define VMX_EPTP_MT_MASK 0x7ull
512-
#define VMX_EPTP_MT_WB 0x6ull
513-
#define VMX_EPTP_MT_UC 0x0ull
532+
#define VMX_EPTP_MT_WB X86_MEMTYPE_WB
533+
#define VMX_EPTP_MT_UC X86_MEMTYPE_UC
514534
#define VMX_EPT_READABLE_MASK 0x1ull
515535
#define VMX_EPT_WRITABLE_MASK 0x2ull
516536
#define VMX_EPT_EXECUTABLE_MASK 0x4ull

arch/x86/kernel/cpu/mtrr/mtrr.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@
5555

5656
#include "mtrr.h"
5757

58+
static_assert(X86_MEMTYPE_UC == MTRR_TYPE_UNCACHABLE);
59+
static_assert(X86_MEMTYPE_WC == MTRR_TYPE_WRCOMB);
60+
static_assert(X86_MEMTYPE_WT == MTRR_TYPE_WRTHROUGH);
61+
static_assert(X86_MEMTYPE_WP == MTRR_TYPE_WRPROT);
62+
static_assert(X86_MEMTYPE_WB == MTRR_TYPE_WRBACK);
63+
5864
/* arch_phys_wc_add returns an MTRR register index plus this offset. */
5965
#define MTRR_TO_PHYS_WC_OFFSET 1000
6066

arch/x86/kvm/vmx/capabilities.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,7 @@ struct nested_vmx_msrs {
5454
};
5555

5656
struct vmcs_config {
57-
int size;
58-
u32 basic_cap;
59-
u32 revision_id;
57+
u64 basic;
6058
u32 pin_based_exec_ctrl;
6159
u32 cpu_based_exec_ctrl;
6260
u32 cpu_based_2nd_exec_ctrl;
@@ -76,7 +74,7 @@ extern struct vmx_capability vmx_capability __ro_after_init;
7674

7775
static inline bool cpu_has_vmx_basic_inout(void)
7876
{
79-
return (((u64)vmcs_config.basic_cap << 32) & VMX_BASIC_INOUT);
77+
return vmcs_config.basic & VMX_BASIC_INOUT;
8078
}
8179

8280
static inline bool cpu_has_virtual_nmis(void)
@@ -225,7 +223,7 @@ static inline bool cpu_has_vmx_vmfunc(void)
225223
static inline bool cpu_has_vmx_shadow_vmcs(void)
226224
{
227225
/* check if the cpu supports writing r/o exit information fields */
228-
if (!(vmcs_config.misc & MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS))
226+
if (!(vmcs_config.misc & VMX_MISC_VMWRITE_SHADOW_RO_FIELDS))
229227
return false;
230228

231229
return vmcs_config.cpu_based_2nd_exec_ctrl &
@@ -367,7 +365,7 @@ static inline bool cpu_has_vmx_invvpid_global(void)
367365

368366
static inline bool cpu_has_vmx_intel_pt(void)
369367
{
370-
return (vmcs_config.misc & MSR_IA32_VMX_MISC_INTEL_PT) &&
368+
return (vmcs_config.misc & VMX_MISC_INTEL_PT) &&
371369
(vmcs_config.cpu_based_2nd_exec_ctrl & SECONDARY_EXEC_PT_USE_GPA) &&
372370
(vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_RTIT_CTL);
373371
}

arch/x86/kvm/vmx/nested.c

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,21 +1251,32 @@ static bool is_bitwise_subset(u64 superset, u64 subset, u64 mask)
12511251

12521252
static int vmx_restore_vmx_basic(struct vcpu_vmx *vmx, u64 data)
12531253
{
1254-
const u64 feature_and_reserved =
1255-
/* feature (except bit 48; see below) */
1256-
BIT_ULL(49) | BIT_ULL(54) | BIT_ULL(55) |
1257-
/* reserved */
1258-
BIT_ULL(31) | GENMASK_ULL(47, 45) | GENMASK_ULL(63, 56);
1254+
const u64 feature_bits = VMX_BASIC_DUAL_MONITOR_TREATMENT |
1255+
VMX_BASIC_INOUT |
1256+
VMX_BASIC_TRUE_CTLS;
1257+
1258+
const u64 reserved_bits = GENMASK_ULL(63, 56) |
1259+
GENMASK_ULL(47, 45) |
1260+
BIT_ULL(31);
1261+
12591262
u64 vmx_basic = vmcs_config.nested.basic;
12601263

1261-
if (!is_bitwise_subset(vmx_basic, data, feature_and_reserved))
1264+
BUILD_BUG_ON(feature_bits & reserved_bits);
1265+
1266+
/*
1267+
* Except for 32BIT_PHYS_ADDR_ONLY, which is an anti-feature bit (has
1268+
* inverted polarity), the incoming value must not set feature bits or
1269+
* reserved bits that aren't allowed/supported by KVM. Fields, i.e.
1270+
* multi-bit values, are explicitly checked below.
1271+
*/
1272+
if (!is_bitwise_subset(vmx_basic, data, feature_bits | reserved_bits))
12621273
return -EINVAL;
12631274

12641275
/*
12651276
* KVM does not emulate a version of VMX that constrains physical
12661277
* addresses of VMX structures (e.g. VMCS) to 32-bits.
12671278
*/
1268-
if (data & BIT_ULL(48))
1279+
if (data & VMX_BASIC_32BIT_PHYS_ADDR_ONLY)
12691280
return -EINVAL;
12701281

12711282
if (vmx_basic_vmcs_revision_id(vmx_basic) !=
@@ -1334,16 +1345,29 @@ vmx_restore_control_msr(struct vcpu_vmx *vmx, u32 msr_index, u64 data)
13341345

13351346
static int vmx_restore_vmx_misc(struct vcpu_vmx *vmx, u64 data)
13361347
{
1337-
const u64 feature_and_reserved_bits =
1338-
/* feature */
1339-
BIT_ULL(5) | GENMASK_ULL(8, 6) | BIT_ULL(14) | BIT_ULL(15) |
1340-
BIT_ULL(28) | BIT_ULL(29) | BIT_ULL(30) |
1341-
/* reserved */
1342-
GENMASK_ULL(13, 9) | BIT_ULL(31);
1348+
const u64 feature_bits = VMX_MISC_SAVE_EFER_LMA |
1349+
VMX_MISC_ACTIVITY_HLT |
1350+
VMX_MISC_ACTIVITY_SHUTDOWN |
1351+
VMX_MISC_ACTIVITY_WAIT_SIPI |
1352+
VMX_MISC_INTEL_PT |
1353+
VMX_MISC_RDMSR_IN_SMM |
1354+
VMX_MISC_VMWRITE_SHADOW_RO_FIELDS |
1355+
VMX_MISC_VMXOFF_BLOCK_SMI |
1356+
VMX_MISC_ZERO_LEN_INS;
1357+
1358+
const u64 reserved_bits = BIT_ULL(31) | GENMASK_ULL(13, 9);
1359+
13431360
u64 vmx_misc = vmx_control_msr(vmcs_config.nested.misc_low,
13441361
vmcs_config.nested.misc_high);
13451362

1346-
if (!is_bitwise_subset(vmx_misc, data, feature_and_reserved_bits))
1363+
BUILD_BUG_ON(feature_bits & reserved_bits);
1364+
1365+
/*
1366+
* The incoming value must not set feature bits or reserved bits that
1367+
* aren't allowed/supported by KVM. Fields, i.e. multi-bit values, are
1368+
* explicitly checked below.
1369+
*/
1370+
if (!is_bitwise_subset(vmx_misc, data, feature_bits | reserved_bits))
13471371
return -EINVAL;
13481372

13491373
if ((vmx->nested.msrs.pinbased_ctls_high &
@@ -7051,7 +7075,7 @@ static void nested_vmx_setup_misc_data(struct vmcs_config *vmcs_conf,
70517075
{
70527076
msrs->misc_low = (u32)vmcs_conf->misc & VMX_MISC_SAVE_EFER_LMA;
70537077
msrs->misc_low |=
7054-
MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS |
7078+
VMX_MISC_VMWRITE_SHADOW_RO_FIELDS |
70557079
VMX_MISC_EMULATED_PREEMPTION_TIMER_RATE |
70567080
VMX_MISC_ACTIVITY_HLT |
70577081
VMX_MISC_ACTIVITY_WAIT_SIPI;
@@ -7066,12 +7090,10 @@ static void nested_vmx_setup_basic(struct nested_vmx_msrs *msrs)
70667090
* guest, and the VMCS structure we give it - not about the
70677091
* VMX support of the underlying hardware.
70687092
*/
7069-
msrs->basic =
7070-
VMCS12_REVISION |
7071-
VMX_BASIC_TRUE_CTLS |
7072-
((u64)VMCS12_SIZE << VMX_BASIC_VMCS_SIZE_SHIFT) |
7073-
(VMX_BASIC_MEM_TYPE_WB << VMX_BASIC_MEM_TYPE_SHIFT);
7093+
msrs->basic = vmx_basic_encode_vmcs_info(VMCS12_REVISION, VMCS12_SIZE,
7094+
X86_MEMTYPE_WB);
70747095

7096+
msrs->basic |= VMX_BASIC_TRUE_CTLS;
70757097
if (cpu_has_vmx_basic_inout())
70767098
msrs->basic |= VMX_BASIC_INOUT;
70777099
}

arch/x86/kvm/vmx/nested.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ static inline unsigned nested_cpu_vmx_misc_cr3_count(struct kvm_vcpu *vcpu)
109109
static inline bool nested_cpu_has_vmwrite_any_field(struct kvm_vcpu *vcpu)
110110
{
111111
return to_vmx(vcpu)->nested.msrs.misc_low &
112-
MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS;
112+
VMX_MISC_VMWRITE_SHADOW_RO_FIELDS;
113113
}
114114

115115
static inline bool nested_cpu_has_zero_length_injection(struct kvm_vcpu *vcpu)

arch/x86/kvm/vmx/vmx.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2605,13 +2605,13 @@ static u64 adjust_vmx_controls64(u64 ctl_opt, u32 msr)
26052605
static int setup_vmcs_config(struct vmcs_config *vmcs_conf,
26062606
struct vmx_capability *vmx_cap)
26072607
{
2608-
u32 vmx_msr_low, vmx_msr_high;
26092608
u32 _pin_based_exec_control = 0;
26102609
u32 _cpu_based_exec_control = 0;
26112610
u32 _cpu_based_2nd_exec_control = 0;
26122611
u64 _cpu_based_3rd_exec_control = 0;
26132612
u32 _vmexit_control = 0;
26142613
u32 _vmentry_control = 0;
2614+
u64 basic_msr;
26152615
u64 misc_msr;
26162616
int i;
26172617

@@ -2734,29 +2734,29 @@ static int setup_vmcs_config(struct vmcs_config *vmcs_conf,
27342734
_vmexit_control &= ~x_ctrl;
27352735
}
27362736

2737-
rdmsr(MSR_IA32_VMX_BASIC, vmx_msr_low, vmx_msr_high);
2737+
rdmsrl(MSR_IA32_VMX_BASIC, basic_msr);
27382738

27392739
/* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */
2740-
if ((vmx_msr_high & 0x1fff) > PAGE_SIZE)
2740+
if (vmx_basic_vmcs_size(basic_msr) > PAGE_SIZE)
27412741
return -EIO;
27422742

27432743
#ifdef CONFIG_X86_64
2744-
/* IA-32 SDM Vol 3B: 64-bit CPUs always have VMX_BASIC_MSR[48]==0. */
2745-
if (vmx_msr_high & (1u<<16))
2744+
/*
2745+
* KVM expects to be able to shove all legal physical addresses into
2746+
* VMCS fields for 64-bit kernels, and per the SDM, "This bit is always
2747+
* 0 for processors that support Intel 64 architecture".
2748+
*/
2749+
if (basic_msr & VMX_BASIC_32BIT_PHYS_ADDR_ONLY)
27462750
return -EIO;
27472751
#endif
27482752

27492753
/* Require Write-Back (WB) memory type for VMCS accesses. */
2750-
if (((vmx_msr_high >> 18) & 15) != 6)
2754+
if (vmx_basic_vmcs_mem_type(basic_msr) != X86_MEMTYPE_WB)
27512755
return -EIO;
27522756

27532757
rdmsrl(MSR_IA32_VMX_MISC, misc_msr);
27542758

2755-
vmcs_conf->size = vmx_msr_high & 0x1fff;
2756-
vmcs_conf->basic_cap = vmx_msr_high & ~0x1fff;
2757-
2758-
vmcs_conf->revision_id = vmx_msr_low;
2759-
2759+
vmcs_conf->basic = basic_msr;
27602760
vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control;
27612761
vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control;
27622762
vmcs_conf->cpu_based_2nd_exec_ctrl = _cpu_based_2nd_exec_control;
@@ -2903,13 +2903,13 @@ struct vmcs *alloc_vmcs_cpu(bool shadow, int cpu, gfp_t flags)
29032903
if (!pages)
29042904
return NULL;
29052905
vmcs = page_address(pages);
2906-
memset(vmcs, 0, vmcs_config.size);
2906+
memset(vmcs, 0, vmx_basic_vmcs_size(vmcs_config.basic));
29072907

29082908
/* KVM supports Enlightened VMCS v1 only */
29092909
if (kvm_is_using_evmcs())
29102910
vmcs->hdr.revision_id = KVM_EVMCS_VERSION;
29112911
else
2912-
vmcs->hdr.revision_id = vmcs_config.revision_id;
2912+
vmcs->hdr.revision_id = vmx_basic_vmcs_revision_id(vmcs_config.basic);
29132913

29142914
if (shadow)
29152915
vmcs->hdr.shadow_vmcs = 1;
@@ -3002,7 +3002,7 @@ static __init int alloc_kvm_area(void)
30023002
* physical CPU.
30033003
*/
30043004
if (kvm_is_using_evmcs())
3005-
vmcs->hdr.revision_id = vmcs_config.revision_id;
3005+
vmcs->hdr.revision_id = vmx_basic_vmcs_revision_id(vmcs_config.basic);
30063006

30073007
per_cpu(vmxarea, cpu) = vmcs;
30083008
}
@@ -8519,7 +8519,7 @@ __init int vmx_hardware_setup(void)
85198519
u64 use_timer_freq = 5000ULL * 1000 * 1000;
85208520

85218521
cpu_preemption_timer_multi =
8522-
vmcs_config.misc & VMX_MISC_PREEMPTION_TIMER_RATE_MASK;
8522+
vmx_misc_preemption_timer_rate(vmcs_config.misc);
85238523

85248524
if (tsc_khz)
85258525
use_timer_freq = (u64)tsc_khz * 1000;

0 commit comments

Comments
 (0)