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