xref: /linux/tools/testing/selftests/kvm/loongarch/fpu_test.c (revision 7bb6284aa7b3c369b41e7f33fcbe193161f008e7)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <stdio.h>
4 #include <string.h>
5 #include "kvm_util.h"
6 #include "processor.h"
7 #include "loongarch/processor.h"
8 
9 struct kvm_fpureg __aligned(64) vector = {{1, 2, 3, 4 }};
10 
11 static void guest_code(void)
12 {
13 	unsigned long val;
14 	struct kvm_fpureg *fp = &vector;
15 
16 	val = csr_read(LOONGARCH_CSR_EUEN);
17 	val |= CSR_EUEN_FPEN | CSR_EUEN_LSXEN | CSR_EUEN_LASXEN;
18 	csr_write(val, LOONGARCH_CSR_EUEN);
19 
20 	__asm__ __volatile__("fld.d $f0, %0, 0\n" : : "r"(fp) : "$f0");
21 	GUEST_SYNC(0);
22 
23 	__asm__ __volatile__("vld $vr0, %0, 0\n" : : "r"(fp) : "$vr0");
24 	GUEST_SYNC(1);
25 
26 	__asm__ __volatile__("xvld $xr0, %0, 0\n" : : "r"(fp) : "$xr0");
27 	GUEST_SYNC(2);
28 
29 	__asm__ __volatile__("fst.d $f0, %0, 0\n" : : "r"(fp) : "memory");
30 	GUEST_SYNC(3);
31 
32 	__asm__ __volatile__("vst $vr0, %0, 0\n" : : "r"(fp) : "memory");
33 	GUEST_SYNC(4);
34 
35 	__asm__ __volatile__("xvst $xr0, %0, 0\n" : : "r"(fp) : "memory");
36 	GUEST_SYNC(5);
37 
38 	GUEST_DONE();
39 }
40 
41 static void run_vcpu(struct kvm_vcpu *vcpu)
42 {
43 	int cont = 1;
44 	struct ucall uc;
45 
46 	while (cont) {
47 		vcpu_run(vcpu);
48 
49 		switch (get_ucall(vcpu, &uc)) {
50 		case UCALL_PRINTF:
51 			printf("%s", (const char *)uc.buffer);
52 			break;
53 		case UCALL_DONE:
54 			printf("FPU test PASSED\n");
55 			fallthrough;
56 		case UCALL_SYNC:
57 			cont = 0;
58 			break;
59 		case UCALL_ABORT:
60 			REPORT_GUEST_ASSERT(uc);
61 		default:
62 			TEST_ASSERT(false, "Unexpected exit: %s",
63 				exit_reason_str(vcpu->run->exit_reason));
64 		}
65 	}
66 }
67 
68 int main(void)
69 {
70 	int ret;
71 	struct kvm_vm *vm;
72 	struct kvm_vcpu *vcpu;
73 	struct kvm_fpu fpu;
74 	struct kvm_fpureg *fp = &vector;
75 
76 	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
77 
78 	ret = __kvm_has_device_attr(vm->fd, KVM_LOONGARCH_VM_FEAT_CTRL, KVM_LOONGARCH_VM_FEAT_LSX);
79 	__TEST_REQUIRE(!ret, "LSX not available, skipping test\n");
80 
81 	ret = __kvm_has_device_attr(vm->fd, KVM_LOONGARCH_VM_FEAT_CTRL, KVM_LOONGARCH_VM_FEAT_LASX);
82 	__TEST_REQUIRE(!ret, "LASX not available, skipping test\n");
83 
84 	run_vcpu(vcpu);
85 	vcpu_fpu_get(vcpu, &fpu);
86 	TEST_ASSERT(!memcmp(fpu.fpr, fp, 8), "Wanted 0x%llx from f0, got 0x%llx",
87 			fp->val64[0], fpu.fpr[0].val64[0]);
88 
89 	run_vcpu(vcpu);
90 	vcpu_fpu_get(vcpu, &fpu);
91 	TEST_ASSERT(!memcmp(fpu.fpr, fp, 16), "Wanted 0x%llx %llx from vr0, got 0x%llx %llx",
92 			fp->val64[0], fp->val64[1],
93 			fpu.fpr[0].val64[0], fpu.fpr[0].val64[1]);
94 
95 	run_vcpu(vcpu);
96 	vcpu_fpu_get(vcpu, &fpu);
97 	TEST_ASSERT(!memcmp(fpu.fpr, fp, 32),
98 			"Wanted 0x%llx %llx %llx %llx from xr0, got 0x%llx %llx %llx %llx",
99 			fp->val64[0], fp->val64[1], fp->val64[2], fp->val64[3],
100 			fpu.fpr[0].val64[0], fpu.fpr[0].val64[1], fpu.fpr[0].val64[2], fpu.fpr[0].val64[3]);
101 
102 	fpu.fpr[0].val64[0] += random();
103 	vcpu_fpu_set(vcpu, &fpu);
104 	run_vcpu(vcpu);
105 	vcpu_fpu_get(vcpu, &fpu);
106 	sync_global_from_guest(vm, *fp);
107 	TEST_ASSERT(!memcmp(fpu.fpr, fp, 8), "Wanted 0x%llx from f0, got 0x%llx",
108 			fp->val64[0], fpu.fpr[0].val64[0]);
109 
110 	fpu.fpr[0].val64[0] += random();
111 	fpu.fpr[0].val64[1] += random();
112 	vcpu_fpu_set(vcpu, &fpu);
113 	run_vcpu(vcpu);
114 	vcpu_fpu_get(vcpu, &fpu);
115 	sync_global_from_guest(vm, *fp);
116 	TEST_ASSERT(!memcmp(fpu.fpr, fp, 16), "Wanted 0x%llx %llx from vr0, got 0x%llx %llx",
117 			fp->val64[0], fp->val64[1],
118 			fpu.fpr[0].val64[0], fpu.fpr[0].val64[1]);
119 
120 	fpu.fpr[0].val64[0] += random();
121 	fpu.fpr[0].val64[1] += random();
122 	fpu.fpr[0].val64[2] += random();
123 	fpu.fpr[0].val64[3] += random();
124 	vcpu_fpu_set(vcpu, &fpu);
125 	run_vcpu(vcpu);
126 	vcpu_fpu_get(vcpu, &fpu);
127 	sync_global_from_guest(vm, *fp);
128 	TEST_ASSERT(!memcmp(fpu.fpr, fp, 32),
129 			"Wanted 0x%llx %llx %llx %llx from xr0, got 0x%llx %llx %llx %llx",
130 			fp->val64[0], fp->val64[1], fp->val64[2], fp->val64[3],
131 			fpu.fpr[0].val64[0], fpu.fpr[0].val64[1], fpu.fpr[0].val64[2], fpu.fpr[0].val64[3]);
132 
133 	run_vcpu(vcpu);
134 	kvm_vm_free(vm);
135 
136 	return 0;
137 }
138