mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
KVM: LoongArch: selftests: Add FPU/LSX/LASX test cases
Add FPU/LSX/LASX test cases and verify FPU register get and set APIs, the FPU width supports 64/128/256 bits. Signed-off-by: Bibo Mao <maobibo@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
This commit is contained in:
parent
7513f2298c
commit
c5959723aa
|
|
@ -228,7 +228,8 @@ TEST_GEN_PROGS_riscv += mmu_stress_test
|
|||
TEST_GEN_PROGS_riscv += rseq_test
|
||||
TEST_GEN_PROGS_riscv += steal_time
|
||||
|
||||
TEST_GEN_PROGS_loongarch = loongarch/pmu_test
|
||||
TEST_GEN_PROGS_loongarch = loongarch/fpu_test
|
||||
TEST_GEN_PROGS_loongarch += loongarch/pmu_test
|
||||
TEST_GEN_PROGS_loongarch += arch_timer
|
||||
TEST_GEN_PROGS_loongarch += coalesced_io_test
|
||||
TEST_GEN_PROGS_loongarch += demand_paging_test
|
||||
|
|
|
|||
|
|
@ -92,6 +92,14 @@
|
|||
#define PLV_MASK 0x3
|
||||
#define LOONGARCH_CSR_PRMD 0x1
|
||||
#define LOONGARCH_CSR_EUEN 0x2
|
||||
#define CSR_EUEN_LBTEN_SHIFT 3
|
||||
#define CSR_EUEN_LBTEN BIT_ULL(CSR_EUEN_LBTEN_SHIFT)
|
||||
#define CSR_EUEN_LASXEN_SHIFT 2
|
||||
#define CSR_EUEN_LASXEN BIT_ULL(CSR_EUEN_LASXEN_SHIFT)
|
||||
#define CSR_EUEN_LSXEN_SHIFT 1
|
||||
#define CSR_EUEN_LSXEN BIT_ULL(CSR_EUEN_LSXEN_SHIFT)
|
||||
#define CSR_EUEN_FPEN_SHIFT 0
|
||||
#define CSR_EUEN_FPEN BIT_ULL(CSR_EUEN_FPEN_SHIFT)
|
||||
#define LOONGARCH_CSR_ECFG 0x4
|
||||
#define ECFGB_PMU 10
|
||||
#define ECFGF_PMU (BIT_ULL(ECFGB_PMU))
|
||||
|
|
|
|||
137
tools/testing/selftests/kvm/loongarch/fpu_test.c
Normal file
137
tools/testing/selftests/kvm/loongarch/fpu_test.c
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "kvm_util.h"
|
||||
#include "processor.h"
|
||||
#include "loongarch/processor.h"
|
||||
|
||||
struct kvm_fpureg __aligned(64) vector = {{1, 2, 3, 4 }};
|
||||
|
||||
static void guest_code(void)
|
||||
{
|
||||
unsigned long val;
|
||||
struct kvm_fpureg *fp = &vector;
|
||||
|
||||
val = csr_read(LOONGARCH_CSR_EUEN);
|
||||
val |= CSR_EUEN_FPEN | CSR_EUEN_LSXEN | CSR_EUEN_LASXEN;
|
||||
csr_write(val, LOONGARCH_CSR_EUEN);
|
||||
|
||||
__asm__ __volatile__("fld.d $f0, %0, 0\n" : : "r"(fp) : "$f0");
|
||||
GUEST_SYNC(0);
|
||||
|
||||
__asm__ __volatile__("vld $vr0, %0, 0\n" : : "r"(fp) : "$vr0");
|
||||
GUEST_SYNC(1);
|
||||
|
||||
__asm__ __volatile__("xvld $xr0, %0, 0\n" : : "r"(fp) : "$xr0");
|
||||
GUEST_SYNC(2);
|
||||
|
||||
__asm__ __volatile__("fst.d $f0, %0, 0\n" : : "r"(fp) : "memory");
|
||||
GUEST_SYNC(3);
|
||||
|
||||
__asm__ __volatile__("vst $vr0, %0, 0\n" : : "r"(fp) : "memory");
|
||||
GUEST_SYNC(4);
|
||||
|
||||
__asm__ __volatile__("xvst $xr0, %0, 0\n" : : "r"(fp) : "memory");
|
||||
GUEST_SYNC(5);
|
||||
|
||||
GUEST_DONE();
|
||||
}
|
||||
|
||||
static void run_vcpu(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int cont = 1;
|
||||
struct ucall uc;
|
||||
|
||||
while (cont) {
|
||||
vcpu_run(vcpu);
|
||||
|
||||
switch (get_ucall(vcpu, &uc)) {
|
||||
case UCALL_PRINTF:
|
||||
printf("%s", (const char *)uc.buffer);
|
||||
break;
|
||||
case UCALL_DONE:
|
||||
printf("FPU test PASSED\n");
|
||||
fallthrough;
|
||||
case UCALL_SYNC:
|
||||
cont = 0;
|
||||
break;
|
||||
case UCALL_ABORT:
|
||||
REPORT_GUEST_ASSERT(uc);
|
||||
default:
|
||||
TEST_ASSERT(false, "Unexpected exit: %s",
|
||||
exit_reason_str(vcpu->run->exit_reason));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int ret;
|
||||
struct kvm_vm *vm;
|
||||
struct kvm_vcpu *vcpu;
|
||||
struct kvm_fpu fpu;
|
||||
struct kvm_fpureg *fp = &vector;
|
||||
|
||||
vm = vm_create_with_one_vcpu(&vcpu, guest_code);
|
||||
|
||||
ret = __kvm_has_device_attr(vm->fd, KVM_LOONGARCH_VM_FEAT_CTRL, KVM_LOONGARCH_VM_FEAT_LSX);
|
||||
__TEST_REQUIRE(!ret, "LSX not available, skipping test\n");
|
||||
|
||||
ret = __kvm_has_device_attr(vm->fd, KVM_LOONGARCH_VM_FEAT_CTRL, KVM_LOONGARCH_VM_FEAT_LASX);
|
||||
__TEST_REQUIRE(!ret, "LASX not available, skipping test\n");
|
||||
|
||||
run_vcpu(vcpu);
|
||||
vcpu_fpu_get(vcpu, &fpu);
|
||||
TEST_ASSERT(!memcmp(fpu.fpr, fp, 8), "Wanted 0x%llx from f0, got 0x%llx",
|
||||
fp->val64[0], fpu.fpr[0].val64[0]);
|
||||
|
||||
run_vcpu(vcpu);
|
||||
vcpu_fpu_get(vcpu, &fpu);
|
||||
TEST_ASSERT(!memcmp(fpu.fpr, fp, 16), "Wanted 0x%llx %llx from vr0, got 0x%llx %llx",
|
||||
fp->val64[0], fp->val64[1],
|
||||
fpu.fpr[0].val64[0], fpu.fpr[0].val64[1]);
|
||||
|
||||
run_vcpu(vcpu);
|
||||
vcpu_fpu_get(vcpu, &fpu);
|
||||
TEST_ASSERT(!memcmp(fpu.fpr, fp, 32),
|
||||
"Wanted 0x%llx %llx %llx %llx from xr0, got 0x%llx %llx %llx %llx",
|
||||
fp->val64[0], fp->val64[1], fp->val64[2], fp->val64[3],
|
||||
fpu.fpr[0].val64[0], fpu.fpr[0].val64[1], fpu.fpr[0].val64[2], fpu.fpr[0].val64[3]);
|
||||
|
||||
fpu.fpr[0].val64[0] += random();
|
||||
vcpu_fpu_set(vcpu, &fpu);
|
||||
run_vcpu(vcpu);
|
||||
vcpu_fpu_get(vcpu, &fpu);
|
||||
sync_global_from_guest(vm, *fp);
|
||||
TEST_ASSERT(!memcmp(fpu.fpr, fp, 8), "Wanted 0x%llx from f0, got 0x%llx",
|
||||
fp->val64[0], fpu.fpr[0].val64[0]);
|
||||
|
||||
fpu.fpr[0].val64[0] += random();
|
||||
fpu.fpr[0].val64[1] += random();
|
||||
vcpu_fpu_set(vcpu, &fpu);
|
||||
run_vcpu(vcpu);
|
||||
vcpu_fpu_get(vcpu, &fpu);
|
||||
sync_global_from_guest(vm, *fp);
|
||||
TEST_ASSERT(!memcmp(fpu.fpr, fp, 16), "Wanted 0x%llx %llx from vr0, got 0x%llx %llx",
|
||||
fp->val64[0], fp->val64[1],
|
||||
fpu.fpr[0].val64[0], fpu.fpr[0].val64[1]);
|
||||
|
||||
fpu.fpr[0].val64[0] += random();
|
||||
fpu.fpr[0].val64[1] += random();
|
||||
fpu.fpr[0].val64[2] += random();
|
||||
fpu.fpr[0].val64[3] += random();
|
||||
vcpu_fpu_set(vcpu, &fpu);
|
||||
run_vcpu(vcpu);
|
||||
vcpu_fpu_get(vcpu, &fpu);
|
||||
sync_global_from_guest(vm, *fp);
|
||||
TEST_ASSERT(!memcmp(fpu.fpr, fp, 32),
|
||||
"Wanted 0x%llx %llx %llx %llx from xr0, got 0x%llx %llx %llx %llx",
|
||||
fp->val64[0], fp->val64[1], fp->val64[2], fp->val64[3],
|
||||
fpu.fpr[0].val64[0], fpu.fpr[0].val64[1], fpu.fpr[0].val64[2], fpu.fpr[0].val64[3]);
|
||||
|
||||
run_vcpu(vcpu);
|
||||
kvm_vm_free(vm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user