Commit 5de4a376 authored by Mingwei Zhang's avatar Mingwei Zhang Committed by Sean Christopherson
Browse files

KVM: selftests: Add a fully functional "struct xstate" for x86



Add a working xstate data structure for the usage of AMX and potential
future usage on other xstate components. AMX selftest requires checking
both the xstate_bv and xcomp_bv. Existing code relies on pointer
arithmetics to fetch xstate_bv and does not support xcomp_bv.

So, add a working xstate data structure into processor.h for x86.

Suggested-by: default avatarSean Christopherson <seanjc@google.com>
Signed-off-by: default avatarMingwei Zhang <mizhang@google.com>
Link: https://lore.kernel.org/r/20230221163655.920289-3-mizhang@google.com


Signed-off-by: default avatarSean Christopherson <seanjc@google.com>
parent 735b0e0f
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -48,6 +48,18 @@ extern bool host_cpu_is_amd;
#define X86_CR4_SMAP		(1ul << 21)
#define X86_CR4_PKE		(1ul << 22)

struct xstate_header {
	u64				xstate_bv;
	u64				xcomp_bv;
	u64				reserved[6];
} __attribute__((packed));

struct xstate {
	u8				i387[512];
	struct xstate_header		header;
	u8				extended_state_area[0];
} __attribute__ ((packed, aligned (64)));

/* Note, these are ordered alphabetically to match kvm_cpuid_entry2.  Eww. */
enum cpuid_output_regs {
	KVM_CPUID_EAX,
+11 −25
Original line number Diff line number Diff line
@@ -41,10 +41,6 @@

#define XSAVE_HDR_OFFSET		512

struct xsave_data {
	u8 area[XSAVE_SIZE];
} __aligned(64);

struct tile_config {
	u8  palette_id;
	u8  start_row;
@@ -103,13 +99,13 @@ static inline void __tilerelease(void)
	asm volatile(".byte 0xc4, 0xe2, 0x78, 0x49, 0xc0" ::);
}

static inline void __xsavec(struct xsave_data *data, uint64_t rfbm)
static inline void __xsavec(struct xstate *xstate, uint64_t rfbm)
{
	uint32_t rfbm_lo = rfbm;
	uint32_t rfbm_hi = rfbm >> 32;

	asm volatile("xsavec (%%rdi)"
		     : : "D" (data), "a" (rfbm_lo), "d" (rfbm_hi)
		     : : "D" (xstate), "a" (rfbm_lo), "d" (rfbm_hi)
		     : "memory");
}

@@ -158,16 +154,6 @@ static void set_tilecfg(struct tile_config *cfg)
	}
}

static void set_xstatebv(void *data, uint64_t bv)
{
	*(uint64_t *)(data + XSAVE_HDR_OFFSET) = bv;
}

static u64 get_xstatebv(void *data)
{
	return *(u64 *)(data + XSAVE_HDR_OFFSET);
}

static void init_regs(void)
{
	uint64_t cr4, xcr0;
@@ -184,7 +170,7 @@ static void init_regs(void)

static void __attribute__((__flatten__)) guest_code(struct tile_config *amx_cfg,
						    struct tile_data *tiledata,
						    struct xsave_data *xsave_data)
						    struct xstate *xstate)
{
	init_regs();
	check_cpuid_xsave();
@@ -205,9 +191,9 @@ static void __attribute__((__flatten__)) guest_code(struct tile_config *amx_cfg,
	__tilerelease();
	GUEST_SYNC(5);
	/* bit 18 not in the XCOMP_BV after xsavec() */
	set_xstatebv(xsave_data, XFEATURE_MASK_XTILEDATA);
	__xsavec(xsave_data, XFEATURE_MASK_XTILEDATA);
	GUEST_ASSERT((get_xstatebv(xsave_data) & XFEATURE_MASK_XTILEDATA) == 0);
	xstate->header.xstate_bv = XFEATURE_MASK_XTILEDATA;
	__xsavec(xstate, XFEATURE_MASK_XTILEDATA);
	GUEST_ASSERT(!(xstate->header.xstate_bv & XFEATURE_MASK_XTILEDATA));

	/* xfd=0x40000, disable amx tiledata */
	wrmsr(MSR_IA32_XFD, XFEATURE_MASK_XTILEDATA);
@@ -243,7 +229,7 @@ int main(int argc, char *argv[])
	struct kvm_vm *vm;
	struct kvm_x86_state *state;
	int xsave_restore_size;
	vm_vaddr_t amx_cfg, tiledata, xsavedata;
	vm_vaddr_t amx_cfg, tiledata, xstate;
	struct ucall uc;
	u32 amx_offset;
	int stage, ret;
@@ -282,10 +268,10 @@ int main(int argc, char *argv[])
	tiledata = vm_vaddr_alloc_pages(vm, 2);
	memset(addr_gva2hva(vm, tiledata), rand() | 1, 2 * getpagesize());

	/* xsave data for guest_code */
	xsavedata = vm_vaddr_alloc_pages(vm, 3);
	memset(addr_gva2hva(vm, xsavedata), 0, 3 * getpagesize());
	vcpu_args_set(vcpu, 3, amx_cfg, tiledata, xsavedata);
	/* XSAVE state for guest_code */
	xstate = vm_vaddr_alloc_pages(vm, DIV_ROUND_UP(XSAVE_SIZE, PAGE_SIZE));
	memset(addr_gva2hva(vm, xstate), 0, PAGE_SIZE * DIV_ROUND_UP(XSAVE_SIZE, PAGE_SIZE));
	vcpu_args_set(vcpu, 3, amx_cfg, tiledata, xstate);

	for (stage = 1; ; stage++) {
		vcpu_run(vcpu);