Commit 1f2bbbbb authored by Sean Christopherson's avatar Sean Christopherson
Browse files

KVM: x86: Merge 'selftests' into 'cet' to pick up ex_str()

Merge the queue of KVM selftests changes for 6.18 to pick up the ex_str()
helper so that it can be used to pretty print expected versus actual
exceptions in a new MSR selftest.  CET virtualization will add support for
several MSRs with non-trivial semantics, along with new uAPI for accessing
the guest's Shadow Stack Pointer (SSP) from userspace.
parents 5dca3808 df1f2940
Loading
Loading
Loading
Loading
+11 −6
Original line number Diff line number Diff line
@@ -260,13 +260,18 @@ int __open_path_or_exit(const char *path, int flags, const char *enoent_help);
int open_path_or_exit(const char *path, int flags);
int open_kvm_dev_path_or_exit(void);

bool get_kvm_param_bool(const char *param);
bool get_kvm_intel_param_bool(const char *param);
bool get_kvm_amd_param_bool(const char *param);
int kvm_get_module_param_integer(const char *module_name, const char *param);
bool kvm_get_module_param_bool(const char *module_name, const char *param);

int get_kvm_param_integer(const char *param);
int get_kvm_intel_param_integer(const char *param);
int get_kvm_amd_param_integer(const char *param);
static inline bool get_kvm_param_bool(const char *param)
{
	return kvm_get_module_param_bool("kvm", param);
}

static inline int get_kvm_param_integer(const char *param)
{
	return kvm_get_module_param_integer("kvm", param);
}

unsigned int kvm_check_cap(long cap);

+26 −0
Original line number Diff line number Diff line
@@ -5,8 +5,11 @@
#ifndef SELFTEST_KVM_PMU_H
#define SELFTEST_KVM_PMU_H

#include <stdbool.h>
#include <stdint.h>

#include <linux/bits.h>

#define KVM_PMU_EVENT_FILTER_MAX_EVENTS			300

/*
@@ -61,6 +64,11 @@
#define	INTEL_ARCH_BRANCHES_RETIRED		RAW_EVENT(0xc4, 0x00)
#define	INTEL_ARCH_BRANCHES_MISPREDICTED	RAW_EVENT(0xc5, 0x00)
#define	INTEL_ARCH_TOPDOWN_SLOTS		RAW_EVENT(0xa4, 0x01)
#define	INTEL_ARCH_TOPDOWN_BE_BOUND		RAW_EVENT(0xa4, 0x02)
#define	INTEL_ARCH_TOPDOWN_BAD_SPEC		RAW_EVENT(0x73, 0x00)
#define	INTEL_ARCH_TOPDOWN_FE_BOUND		RAW_EVENT(0x9c, 0x01)
#define	INTEL_ARCH_TOPDOWN_RETIRING		RAW_EVENT(0xc2, 0x02)
#define	INTEL_ARCH_LBR_INSERTS			RAW_EVENT(0xe4, 0x01)

#define	AMD_ZEN_CORE_CYCLES			RAW_EVENT(0x76, 0x00)
#define	AMD_ZEN_INSTRUCTIONS_RETIRED		RAW_EVENT(0xc0, 0x00)
@@ -80,6 +88,11 @@ enum intel_pmu_architectural_events {
	INTEL_ARCH_BRANCHES_RETIRED_INDEX,
	INTEL_ARCH_BRANCHES_MISPREDICTED_INDEX,
	INTEL_ARCH_TOPDOWN_SLOTS_INDEX,
	INTEL_ARCH_TOPDOWN_BE_BOUND_INDEX,
	INTEL_ARCH_TOPDOWN_BAD_SPEC_INDEX,
	INTEL_ARCH_TOPDOWN_FE_BOUND_INDEX,
	INTEL_ARCH_TOPDOWN_RETIRING_INDEX,
	INTEL_ARCH_LBR_INSERTS_INDEX,
	NR_INTEL_ARCH_EVENTS,
};

@@ -94,4 +107,17 @@ enum amd_pmu_zen_events {
extern const uint64_t intel_pmu_arch_events[];
extern const uint64_t amd_pmu_zen_events[];

enum pmu_errata {
	INSTRUCTIONS_RETIRED_OVERCOUNT,
	BRANCHES_RETIRED_OVERCOUNT,
};
extern uint64_t pmu_errata_mask;

void kvm_init_pmu_errata(void);

static inline bool this_pmu_has_errata(enum pmu_errata errata)
{
	return pmu_errata_mask & BIT_ULL(errata);
}

#endif /* SELFTEST_KVM_PMU_H */
+34 −1
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@ extern uint64_t guest_tsc_khz;

#define NMI_VECTOR		0x02

const char *ex_str(int vector);

#define X86_EFLAGS_FIXED	 (1u << 1)

#define X86_CR4_VME		(1ul << 0)
@@ -265,7 +267,7 @@ struct kvm_x86_cpu_property {
#define X86_PROPERTY_PMU_NR_GP_COUNTERS		KVM_X86_CPU_PROPERTY(0xa, 0, EAX, 8, 15)
#define X86_PROPERTY_PMU_GP_COUNTERS_BIT_WIDTH	KVM_X86_CPU_PROPERTY(0xa, 0, EAX, 16, 23)
#define X86_PROPERTY_PMU_EBX_BIT_VECTOR_LENGTH	KVM_X86_CPU_PROPERTY(0xa, 0, EAX, 24, 31)
#define X86_PROPERTY_PMU_EVENTS_MASK		KVM_X86_CPU_PROPERTY(0xa, 0, EBX, 0, 7)
#define X86_PROPERTY_PMU_EVENTS_MASK		KVM_X86_CPU_PROPERTY(0xa, 0, EBX, 0, 12)
#define X86_PROPERTY_PMU_FIXED_COUNTERS_BITMASK	KVM_X86_CPU_PROPERTY(0xa, 0, ECX, 0, 31)
#define X86_PROPERTY_PMU_NR_FIXED_COUNTERS	KVM_X86_CPU_PROPERTY(0xa, 0, EDX, 0, 4)
#define X86_PROPERTY_PMU_FIXED_COUNTERS_BIT_WIDTH	KVM_X86_CPU_PROPERTY(0xa, 0, EDX, 5, 12)
@@ -332,6 +334,11 @@ struct kvm_x86_pmu_feature {
#define X86_PMU_FEATURE_BRANCH_INSNS_RETIRED		KVM_X86_PMU_FEATURE(EBX, 5)
#define X86_PMU_FEATURE_BRANCHES_MISPREDICTED		KVM_X86_PMU_FEATURE(EBX, 6)
#define X86_PMU_FEATURE_TOPDOWN_SLOTS			KVM_X86_PMU_FEATURE(EBX, 7)
#define X86_PMU_FEATURE_TOPDOWN_BE_BOUND		KVM_X86_PMU_FEATURE(EBX, 8)
#define X86_PMU_FEATURE_TOPDOWN_BAD_SPEC		KVM_X86_PMU_FEATURE(EBX, 9)
#define X86_PMU_FEATURE_TOPDOWN_FE_BOUND		KVM_X86_PMU_FEATURE(EBX, 10)
#define X86_PMU_FEATURE_TOPDOWN_RETIRING		KVM_X86_PMU_FEATURE(EBX, 11)
#define X86_PMU_FEATURE_LBR_INSERTS			KVM_X86_PMU_FEATURE(EBX, 12)

#define X86_PMU_FEATURE_INSNS_RETIRED_FIXED		KVM_X86_PMU_FEATURE(ECX, 0)
#define X86_PMU_FEATURE_CPU_CYCLES_FIXED		KVM_X86_PMU_FEATURE(ECX, 1)
@@ -1179,6 +1186,12 @@ struct idt_entry {
void vm_install_exception_handler(struct kvm_vm *vm, int vector,
			void (*handler)(struct ex_regs *));

/*
 * Exception fixup morphs #DE to an arbitrary magic vector so that '0' can be
 * used to signal "no expcetion".
 */
#define KVM_MAGIC_DE_VECTOR 0xff

/* If a toddler were to say "abracadabra". */
#define KVM_EXCEPTION_MAGIC 0xabacadabaULL

@@ -1314,6 +1327,26 @@ static inline uint8_t xsetbv_safe(uint32_t index, uint64_t value)

bool kvm_is_tdp_enabled(void);

static inline bool get_kvm_intel_param_bool(const char *param)
{
	return kvm_get_module_param_bool("kvm_intel", param);
}

static inline bool get_kvm_amd_param_bool(const char *param)
{
	return kvm_get_module_param_bool("kvm_amd", param);
}

static inline int get_kvm_intel_param_integer(const char *param)
{
	return kvm_get_module_param_integer("kvm_intel", param);
}

static inline int get_kvm_amd_param_integer(const char *param)
{
	return kvm_get_module_param_integer("kvm_amd", param);
}

static inline bool kvm_is_pmu_enabled(void)
{
	return get_kvm_param_bool("enable_pmu");
+6 −36
Original line number Diff line number Diff line
@@ -24,7 +24,7 @@ uint32_t guest_random_seed;
struct guest_random_state guest_rng;
static uint32_t last_guest_seed;

static int vcpu_mmap_sz(void);
static size_t vcpu_mmap_sz(void);

int __open_path_or_exit(const char *path, int flags, const char *enoent_help)
{
@@ -95,7 +95,7 @@ static ssize_t get_module_param(const char *module_name, const char *param,
	return bytes_read;
}

static int get_module_param_integer(const char *module_name, const char *param)
int kvm_get_module_param_integer(const char *module_name, const char *param)
{
	/*
	 * 16 bytes to hold a 64-bit value (1 byte per char), 1 byte for the
@@ -119,7 +119,7 @@ static int get_module_param_integer(const char *module_name, const char *param)
	return atoi_paranoid(value);
}

static bool get_module_param_bool(const char *module_name, const char *param)
bool kvm_get_module_param_bool(const char *module_name, const char *param)
{
	char value;
	ssize_t r;
@@ -135,36 +135,6 @@ static bool get_module_param_bool(const char *module_name, const char *param)
	TEST_FAIL("Unrecognized value '%c' for boolean module param", value);
}

bool get_kvm_param_bool(const char *param)
{
	return get_module_param_bool("kvm", param);
}

bool get_kvm_intel_param_bool(const char *param)
{
	return get_module_param_bool("kvm_intel", param);
}

bool get_kvm_amd_param_bool(const char *param)
{
	return get_module_param_bool("kvm_amd", param);
}

int get_kvm_param_integer(const char *param)
{
	return get_module_param_integer("kvm", param);
}

int get_kvm_intel_param_integer(const char *param)
{
	return get_module_param_integer("kvm_intel", param);
}

int get_kvm_amd_param_integer(const char *param)
{
	return get_module_param_integer("kvm_amd", param);
}

/*
 * Capability
 *
@@ -1321,14 +1291,14 @@ void vm_guest_mem_fallocate(struct kvm_vm *vm, uint64_t base, uint64_t size,
}

/* Returns the size of a vCPU's kvm_run structure. */
static int vcpu_mmap_sz(void)
static size_t vcpu_mmap_sz(void)
{
	int dev_fd, ret;

	dev_fd = open_kvm_dev_path_or_exit();

	ret = ioctl(dev_fd, KVM_GET_VCPU_MMAP_SIZE, NULL);
	TEST_ASSERT(ret >= sizeof(struct kvm_run),
	TEST_ASSERT(ret >= 0 && ret >= sizeof(struct kvm_run),
		    KVM_IOCTL_ERROR(KVM_GET_VCPU_MMAP_SIZE, ret));

	close(dev_fd);
@@ -1369,7 +1339,7 @@ struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
	TEST_ASSERT_VM_VCPU_IOCTL(vcpu->fd >= 0, KVM_CREATE_VCPU, vcpu->fd, vm);

	TEST_ASSERT(vcpu_mmap_sz() >= sizeof(*vcpu->run), "vcpu mmap size "
		"smaller than expected, vcpu_mmap_sz: %i expected_min: %zi",
		"smaller than expected, vcpu_mmap_sz: %zi expected_min: %zi",
		vcpu_mmap_sz(), sizeof(*vcpu->run));
	vcpu->run = (struct kvm_run *) mmap(NULL, vcpu_mmap_sz(),
		PROT_READ | PROT_WRITE, MAP_SHARED, vcpu->fd, 0);
+49 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include <linux/kernel.h>

#include "kvm_util.h"
#include "processor.h"
#include "pmu.h"

const uint64_t intel_pmu_arch_events[] = {
@@ -19,6 +20,11 @@ const uint64_t intel_pmu_arch_events[] = {
	INTEL_ARCH_BRANCHES_RETIRED,
	INTEL_ARCH_BRANCHES_MISPREDICTED,
	INTEL_ARCH_TOPDOWN_SLOTS,
	INTEL_ARCH_TOPDOWN_BE_BOUND,
	INTEL_ARCH_TOPDOWN_BAD_SPEC,
	INTEL_ARCH_TOPDOWN_FE_BOUND,
	INTEL_ARCH_TOPDOWN_RETIRING,
	INTEL_ARCH_LBR_INSERTS,
};
kvm_static_assert(ARRAY_SIZE(intel_pmu_arch_events) == NR_INTEL_ARCH_EVENTS);

@@ -29,3 +35,46 @@ const uint64_t amd_pmu_zen_events[] = {
	AMD_ZEN_BRANCHES_MISPREDICTED,
};
kvm_static_assert(ARRAY_SIZE(amd_pmu_zen_events) == NR_AMD_ZEN_EVENTS);

/*
 * For Intel Atom CPUs, the PMU events "Instruction Retired" or
 * "Branch Instruction Retired" may be overcounted for some certain
 * instructions, like FAR CALL/JMP, RETF, IRET, VMENTRY/VMEXIT/VMPTRLD
 * and complex SGX/SMX/CSTATE instructions/flows.
 *
 * The detailed information can be found in the errata (section SRF7):
 * https://edc.intel.com/content/www/us/en/design/products-and-solutions/processors-and-chipsets/sierra-forest/xeon-6700-series-processor-with-e-cores-specification-update/errata-details/
 *
 * For the Atom platforms before Sierra Forest (including Sierra Forest),
 * Both 2 events "Instruction Retired" and "Branch Instruction Retired" would
 * be overcounted on these certain instructions, but for Clearwater Forest
 * only "Instruction Retired" event is overcounted on these instructions.
 */
static uint64_t get_pmu_errata(void)
{
	if (!this_cpu_is_intel())
		return 0;

	if (this_cpu_family() != 0x6)
		return 0;

	switch (this_cpu_model()) {
	case 0xDD: /* Clearwater Forest */
		return BIT_ULL(INSTRUCTIONS_RETIRED_OVERCOUNT);
	case 0xAF: /* Sierra Forest */
	case 0x4D: /* Avaton, Rangely */
	case 0x5F: /* Denverton */
	case 0x86: /* Jacobsville */
		return BIT_ULL(INSTRUCTIONS_RETIRED_OVERCOUNT) |
		       BIT_ULL(BRANCHES_RETIRED_OVERCOUNT);
	default:
		return 0;
	}
}

uint64_t pmu_errata_mask;

void kvm_init_pmu_errata(void)
{
	pmu_errata_mask = get_pmu_errata();
}
Loading