Skip to content

Commit c21775a

Browse files
committed
Merge tag 'kvm-x86-selftests-6.4' of https://github.com/kvm-x86/linux into HEAD
KVM selftests, and an AMX/XCR0 bugfix, for 6.4: - Don't advertise XTILE_CFG in KVM_GET_SUPPORTED_CPUID if XTILE_DATA is not being reported due to userspace not opting in via prctl() - Overhaul the AMX selftests to improve coverage and cleanup the test - Misc cleanups
2 parents 48b1893 + 20aef20 commit c21775a

14 files changed

Lines changed: 326 additions & 97 deletions

File tree

arch/x86/kvm/cpuid.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -996,7 +996,7 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
996996
entry->eax = entry->ebx = entry->ecx = 0;
997997
break;
998998
case 0xd: {
999-
u64 permitted_xcr0 = kvm_caps.supported_xcr0 & xstate_get_guest_group_perm();
999+
u64 permitted_xcr0 = kvm_get_filtered_xcr0();
10001000
u64 permitted_xss = kvm_caps.supported_xss;
10011001

10021002
entry->eax &= permitted_xcr0;

arch/x86/kvm/x86.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4593,9 +4593,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
45934593
r = 0;
45944594
break;
45954595
case KVM_CAP_XSAVE2: {
4596-
u64 guest_perm = xstate_get_guest_group_perm();
4597-
4598-
r = xstate_required_size(kvm_caps.supported_xcr0 & guest_perm, false);
4596+
r = xstate_required_size(kvm_get_filtered_xcr0(), false);
45994597
if (r < sizeof(struct kvm_xsave))
46004598
r = sizeof(struct kvm_xsave);
46014599
break;

arch/x86/kvm/x86.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#define ARCH_X86_KVM_X86_H
44

55
#include <linux/kvm_host.h>
6+
#include <asm/fpu/xstate.h>
67
#include <asm/mce.h>
78
#include <asm/pvclock.h>
89
#include "kvm_cache_regs.h"
@@ -328,6 +329,34 @@ extern struct kvm_caps kvm_caps;
328329

329330
extern bool enable_pmu;
330331

332+
/*
333+
* Get a filtered version of KVM's supported XCR0 that strips out dynamic
334+
* features for which the current process doesn't (yet) have permission to use.
335+
* This is intended to be used only when enumerating support to userspace,
336+
* e.g. in KVM_GET_SUPPORTED_CPUID and KVM_CAP_XSAVE2, it does NOT need to be
337+
* used to check/restrict guest behavior as KVM rejects KVM_SET_CPUID{2} if
338+
* userspace attempts to enable unpermitted features.
339+
*/
340+
static inline u64 kvm_get_filtered_xcr0(void)
341+
{
342+
u64 permitted_xcr0 = kvm_caps.supported_xcr0;
343+
344+
BUILD_BUG_ON(XFEATURE_MASK_USER_DYNAMIC != XFEATURE_MASK_XTILE_DATA);
345+
346+
if (permitted_xcr0 & XFEATURE_MASK_USER_DYNAMIC) {
347+
permitted_xcr0 &= xstate_get_guest_group_perm();
348+
349+
/*
350+
* Treat XTILE_CFG as unsupported if the current process isn't
351+
* allowed to use XTILE_DATA, as attempting to set XTILE_CFG in
352+
* XCR0 without setting XTILE_DATA is architecturally illegal.
353+
*/
354+
if (!(permitted_xcr0 & XFEATURE_MASK_XTILE_DATA))
355+
permitted_xcr0 &= ~XFEATURE_MASK_XTILE_CFG;
356+
}
357+
return permitted_xcr0;
358+
}
359+
331360
static inline bool kvm_mpx_supported(void)
332361
{
333362
return (kvm_caps.supported_xcr0 & (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR))

tools/testing/selftests/kvm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test
105105
TEST_GEN_PROGS_x86_64 += x86_64/vmx_nested_tsc_scaling_test
106106
TEST_GEN_PROGS_x86_64 += x86_64/xapic_ipi_test
107107
TEST_GEN_PROGS_x86_64 += x86_64/xapic_state_test
108+
TEST_GEN_PROGS_x86_64 += x86_64/xcr0_cpuid_test
108109
TEST_GEN_PROGS_x86_64 += x86_64/xss_msr_test
109110
TEST_GEN_PROGS_x86_64 += x86_64/debug_regs
110111
TEST_GEN_PROGS_x86_64 += x86_64/tsc_msrs_test

tools/testing/selftests/kvm/demand_paging_test.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
194194
ts_diff.tv_sec, ts_diff.tv_nsec);
195195
pr_info("Overall demand paging rate: %f pgs/sec\n",
196196
memstress_args.vcpu_args[0].pages * nr_vcpus /
197-
((double)ts_diff.tv_sec + (double)ts_diff.tv_nsec / 100000000.0));
197+
((double)ts_diff.tv_sec + (double)ts_diff.tv_nsec / NSEC_PER_SEC));
198198

199199
memstress_destroy_vm(vm);
200200

tools/testing/selftests/kvm/include/kvm_util_base.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ extern const struct vm_guest_mode_params vm_guest_mode_params[];
213213
int open_path_or_exit(const char *path, int flags);
214214
int open_kvm_dev_path_or_exit(void);
215215

216+
bool get_kvm_param_bool(const char *param);
216217
bool get_kvm_intel_param_bool(const char *param);
217218
bool get_kvm_amd_param_bool(const char *param);
218219

tools/testing/selftests/kvm/include/x86_64/processor.h

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,35 @@ extern bool host_cpu_is_amd;
4848
#define X86_CR4_SMAP (1ul << 21)
4949
#define X86_CR4_PKE (1ul << 22)
5050

51+
struct xstate_header {
52+
u64 xstate_bv;
53+
u64 xcomp_bv;
54+
u64 reserved[6];
55+
} __attribute__((packed));
56+
57+
struct xstate {
58+
u8 i387[512];
59+
struct xstate_header header;
60+
u8 extended_state_area[0];
61+
} __attribute__ ((packed, aligned (64)));
62+
63+
#define XFEATURE_MASK_FP BIT_ULL(0)
64+
#define XFEATURE_MASK_SSE BIT_ULL(1)
65+
#define XFEATURE_MASK_YMM BIT_ULL(2)
66+
#define XFEATURE_MASK_BNDREGS BIT_ULL(3)
67+
#define XFEATURE_MASK_BNDCSR BIT_ULL(4)
68+
#define XFEATURE_MASK_OPMASK BIT_ULL(5)
69+
#define XFEATURE_MASK_ZMM_Hi256 BIT_ULL(6)
70+
#define XFEATURE_MASK_Hi16_ZMM BIT_ULL(7)
71+
#define XFEATURE_MASK_XTILE_CFG BIT_ULL(17)
72+
#define XFEATURE_MASK_XTILE_DATA BIT_ULL(18)
73+
74+
#define XFEATURE_MASK_AVX512 (XFEATURE_MASK_OPMASK | \
75+
XFEATURE_MASK_ZMM_Hi256 | \
76+
XFEATURE_MASK_Hi16_ZMM)
77+
#define XFEATURE_MASK_XTILE (XFEATURE_MASK_XTILE_DATA | \
78+
XFEATURE_MASK_XTILE_CFG)
79+
5180
/* Note, these are ordered alphabetically to match kvm_cpuid_entry2. Eww. */
5281
enum cpuid_output_regs {
5382
KVM_CPUID_EAX,
@@ -131,6 +160,7 @@ struct kvm_x86_cpu_feature {
131160
#define X86_FEATURE_XTILEDATA KVM_X86_CPU_FEATURE(0xD, 0, EAX, 18)
132161
#define X86_FEATURE_XSAVES KVM_X86_CPU_FEATURE(0xD, 1, EAX, 3)
133162
#define X86_FEATURE_XFD KVM_X86_CPU_FEATURE(0xD, 1, EAX, 4)
163+
#define X86_FEATURE_XTILEDATA_XFD KVM_X86_CPU_FEATURE(0xD, 18, ECX, 2)
134164

135165
/*
136166
* Extended Leafs, a.k.a. AMD defined
@@ -211,10 +241,14 @@ struct kvm_x86_cpu_property {
211241
#define X86_PROPERTY_PMU_NR_GP_COUNTERS KVM_X86_CPU_PROPERTY(0xa, 0, EAX, 8, 15)
212242
#define X86_PROPERTY_PMU_EBX_BIT_VECTOR_LENGTH KVM_X86_CPU_PROPERTY(0xa, 0, EAX, 24, 31)
213243

244+
#define X86_PROPERTY_SUPPORTED_XCR0_LO KVM_X86_CPU_PROPERTY(0xd, 0, EAX, 0, 31)
214245
#define X86_PROPERTY_XSTATE_MAX_SIZE_XCR0 KVM_X86_CPU_PROPERTY(0xd, 0, EBX, 0, 31)
215246
#define X86_PROPERTY_XSTATE_MAX_SIZE KVM_X86_CPU_PROPERTY(0xd, 0, ECX, 0, 31)
247+
#define X86_PROPERTY_SUPPORTED_XCR0_HI KVM_X86_CPU_PROPERTY(0xd, 0, EDX, 0, 31)
248+
216249
#define X86_PROPERTY_XSTATE_TILE_SIZE KVM_X86_CPU_PROPERTY(0xd, 18, EAX, 0, 31)
217250
#define X86_PROPERTY_XSTATE_TILE_OFFSET KVM_X86_CPU_PROPERTY(0xd, 18, EBX, 0, 31)
251+
#define X86_PROPERTY_AMX_MAX_PALETTE_TABLES KVM_X86_CPU_PROPERTY(0x1d, 0, EAX, 0, 31)
218252
#define X86_PROPERTY_AMX_TOTAL_TILE_BYTES KVM_X86_CPU_PROPERTY(0x1d, 1, EAX, 0, 15)
219253
#define X86_PROPERTY_AMX_BYTES_PER_TILE KVM_X86_CPU_PROPERTY(0x1d, 1, EAX, 16, 31)
220254
#define X86_PROPERTY_AMX_BYTES_PER_ROW KVM_X86_CPU_PROPERTY(0x1d, 1, EBX, 0, 15)
@@ -496,6 +530,24 @@ static inline void set_cr4(uint64_t val)
496530
__asm__ __volatile__("mov %0, %%cr4" : : "r" (val) : "memory");
497531
}
498532

533+
static inline u64 xgetbv(u32 index)
534+
{
535+
u32 eax, edx;
536+
537+
__asm__ __volatile__("xgetbv;"
538+
: "=a" (eax), "=d" (edx)
539+
: "c" (index));
540+
return eax | ((u64)edx << 32);
541+
}
542+
543+
static inline void xsetbv(u32 index, u64 value)
544+
{
545+
u32 eax = value;
546+
u32 edx = value >> 32;
547+
548+
__asm__ __volatile__("xsetbv" :: "a" (eax), "d" (edx), "c" (index));
549+
}
550+
499551
static inline struct desc_ptr get_gdt(void)
500552
{
501553
struct desc_ptr gdt;
@@ -632,6 +684,15 @@ static inline bool this_pmu_has(struct kvm_x86_pmu_feature feature)
632684
!this_cpu_has(feature.anti_feature);
633685
}
634686

687+
static __always_inline uint64_t this_cpu_supported_xcr0(void)
688+
{
689+
if (!this_cpu_has_p(X86_PROPERTY_SUPPORTED_XCR0_LO))
690+
return 0;
691+
692+
return this_cpu_property(X86_PROPERTY_SUPPORTED_XCR0_LO) |
693+
((uint64_t)this_cpu_property(X86_PROPERTY_SUPPORTED_XCR0_HI) << 32);
694+
}
695+
635696
typedef u32 __attribute__((vector_size(16))) sse128_t;
636697
#define __sse128_u union { sse128_t vec; u64 as_u64[2]; u32 as_u32[4]; }
637698
#define sse128_lo(x) ({ __sse128_u t; t.vec = x; t.as_u64[0]; })
@@ -1086,6 +1147,14 @@ static inline uint8_t wrmsr_safe(uint32_t msr, uint64_t val)
10861147
return kvm_asm_safe("wrmsr", "a"(val & -1u), "d"(val >> 32), "c"(msr));
10871148
}
10881149

1150+
static inline uint8_t xsetbv_safe(uint32_t index, uint64_t value)
1151+
{
1152+
u32 eax = value;
1153+
u32 edx = value >> 32;
1154+
1155+
return kvm_asm_safe("xsetbv", "a" (eax), "d" (edx), "c" (index));
1156+
}
1157+
10891158
bool kvm_is_tdp_enabled(void);
10901159

10911160
uint64_t *__vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr,
@@ -1097,10 +1166,10 @@ uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2,
10971166
uint64_t __xen_hypercall(uint64_t nr, uint64_t a0, void *a1);
10981167
void xen_hypercall(uint64_t nr, uint64_t a0, void *a1);
10991168

1100-
void __vm_xsave_require_permission(int bit, const char *name);
1169+
void __vm_xsave_require_permission(uint64_t xfeature, const char *name);
11011170

1102-
#define vm_xsave_require_permission(perm) \
1103-
__vm_xsave_require_permission(perm, #perm)
1171+
#define vm_xsave_require_permission(xfeature) \
1172+
__vm_xsave_require_permission(xfeature, #xfeature)
11041173

11051174
enum pg_level {
11061175
PG_LEVEL_NONE,
@@ -1137,14 +1206,6 @@ void virt_map_level(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
11371206
#define X86_CR0_CD (1UL<<30) /* Cache Disable */
11381207
#define X86_CR0_PG (1UL<<31) /* Paging */
11391208

1140-
#define XSTATE_XTILE_CFG_BIT 17
1141-
#define XSTATE_XTILE_DATA_BIT 18
1142-
1143-
#define XSTATE_XTILE_CFG_MASK (1ULL << XSTATE_XTILE_CFG_BIT)
1144-
#define XSTATE_XTILE_DATA_MASK (1ULL << XSTATE_XTILE_DATA_BIT)
1145-
#define XFEATURE_XTILE_MASK (XSTATE_XTILE_CFG_MASK | \
1146-
XSTATE_XTILE_DATA_MASK)
1147-
11481209
#define PFERR_PRESENT_BIT 0
11491210
#define PFERR_WRITE_BIT 1
11501211
#define PFERR_USER_BIT 2

tools/testing/selftests/kvm/lib/kvm_util.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ static bool get_module_param_bool(const char *module_name, const char *param)
8080
TEST_FAIL("Unrecognized value '%c' for boolean module param", value);
8181
}
8282

83+
bool get_kvm_param_bool(const char *param)
84+
{
85+
return get_module_param_bool("kvm", param);
86+
}
87+
8388
bool get_kvm_intel_param_bool(const char *param)
8489
{
8590
return get_module_param_bool("kvm_intel", param);

tools/testing/selftests/kvm/lib/x86_64/processor.c

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* Copyright (C) 2018, Google LLC.
66
*/
77

8+
#include "linux/bitmap.h"
89
#include "test_util.h"
910
#include "kvm_util.h"
1011
#include "processor.h"
@@ -573,14 +574,29 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id,
573574
DEFAULT_GUEST_STACK_VADDR_MIN,
574575
MEM_REGION_DATA);
575576

577+
stack_vaddr += DEFAULT_STACK_PGS * getpagesize();
578+
579+
/*
580+
* Align stack to match calling sequence requirements in section "The
581+
* Stack Frame" of the System V ABI AMD64 Architecture Processor
582+
* Supplement, which requires the value (%rsp + 8) to be a multiple of
583+
* 16 when control is transferred to the function entry point.
584+
*
585+
* If this code is ever used to launch a vCPU with 32-bit entry point it
586+
* may need to subtract 4 bytes instead of 8 bytes.
587+
*/
588+
TEST_ASSERT(IS_ALIGNED(stack_vaddr, PAGE_SIZE),
589+
"__vm_vaddr_alloc() did not provide a page-aligned address");
590+
stack_vaddr -= 8;
591+
576592
vcpu = __vm_vcpu_add(vm, vcpu_id);
577593
vcpu_init_cpuid(vcpu, kvm_get_supported_cpuid());
578594
vcpu_setup(vm, vcpu);
579595

580596
/* Setup guest general purpose registers */
581597
vcpu_regs_get(vcpu, &regs);
582598
regs.rflags = regs.rflags | 0x2;
583-
regs.rsp = stack_vaddr + (DEFAULT_STACK_PGS * getpagesize());
599+
regs.rsp = stack_vaddr;
584600
regs.rip = (unsigned long) guest_code;
585601
vcpu_regs_set(vcpu, &regs);
586602

@@ -681,20 +697,23 @@ uint64_t kvm_get_feature_msr(uint64_t msr_index)
681697
return buffer.entry.data;
682698
}
683699

684-
void __vm_xsave_require_permission(int bit, const char *name)
700+
void __vm_xsave_require_permission(uint64_t xfeature, const char *name)
685701
{
686702
int kvm_fd;
687703
u64 bitmask;
688704
long rc;
689705
struct kvm_device_attr attr = {
690706
.group = 0,
691707
.attr = KVM_X86_XCOMP_GUEST_SUPP,
692-
.addr = (unsigned long) &bitmask
708+
.addr = (unsigned long) &bitmask,
693709
};
694710

695711
TEST_ASSERT(!kvm_supported_cpuid,
696712
"kvm_get_supported_cpuid() cannot be used before ARCH_REQ_XCOMP_GUEST_PERM");
697713

714+
TEST_ASSERT(is_power_of_2(xfeature),
715+
"Dynamic XFeatures must be enabled one at a time");
716+
698717
kvm_fd = open_kvm_dev_path_or_exit();
699718
rc = __kvm_ioctl(kvm_fd, KVM_GET_DEVICE_ATTR, &attr);
700719
close(kvm_fd);
@@ -704,16 +723,16 @@ void __vm_xsave_require_permission(int bit, const char *name)
704723

705724
TEST_ASSERT(rc == 0, "KVM_GET_DEVICE_ATTR(0, KVM_X86_XCOMP_GUEST_SUPP) error: %ld", rc);
706725

707-
__TEST_REQUIRE(bitmask & (1ULL << bit),
726+
__TEST_REQUIRE(bitmask & xfeature,
708727
"Required XSAVE feature '%s' not supported", name);
709728

710-
TEST_REQUIRE(!syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_GUEST_PERM, bit));
729+
TEST_REQUIRE(!syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_GUEST_PERM, ilog2(xfeature)));
711730

712731
rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_GUEST_PERM, &bitmask);
713732
TEST_ASSERT(rc == 0, "prctl(ARCH_GET_XCOMP_GUEST_PERM) error: %ld", rc);
714-
TEST_ASSERT(bitmask & (1ULL << bit),
715-
"prctl(ARCH_REQ_XCOMP_GUEST_PERM) failure bitmask=0x%lx",
716-
bitmask);
733+
TEST_ASSERT(bitmask & xfeature,
734+
"'%s' (0x%lx) not permitted after prctl(ARCH_REQ_XCOMP_GUEST_PERM) permitted=0x%lx",
735+
name, xfeature, bitmask);
717736
}
718737

719738
void vcpu_init_cpuid(struct kvm_vcpu *vcpu, const struct kvm_cpuid2 *cpuid)
@@ -954,6 +973,7 @@ struct kvm_x86_state *vcpu_save_state(struct kvm_vcpu *vcpu)
954973
vcpu_run_complete_io(vcpu);
955974

956975
state = malloc(sizeof(*state) + msr_list->nmsrs * sizeof(state->msrs.entries[0]));
976+
TEST_ASSERT(state, "-ENOMEM when allocating kvm state");
957977

958978
vcpu_events_get(vcpu, &state->events);
959979
vcpu_mp_state_get(vcpu, &state->mp_state);

0 commit comments

Comments
 (0)