mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-08 10:35:54 -04:00
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: Sean Christopherson <seanjc@google.com> Signed-off-by: Mingwei Zhang <mizhang@google.com> Link: https://lore.kernel.org/r/20230221163655.920289-3-mizhang@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
committed by
Sean Christopherson
parent
735b0e0f2d
commit
5de4a3765b
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user