/* sve.c COPYRIGHT FUJITSU LIMITED 2016-2019 */ #include #include #include #include #include #include "sve.h" #include "common.h" static unsigned long sve_magic[] = { 0x1111111111111111, 0x2222222222222222, 0x3333333333333333, 0x4444444444444444, 0x5555555555555555, 0x6666666666666666, 0x7777777777777777, 0x8888888888888888, 0x9999999999999999, 0xaaaaaaaaaaaaaaaa, 0xbbbbbbbbbbbbbbbb, 0xcccccccccccccccc, 0xdddddddddddddddd, 0xeeeeeeeeeeeeeeee, 0xffffffffffffffff, 0x1111111122222222, 0x2222222233333333, 0x3333333344444444, 0x4444444455555555, 0x5555555566666666, 0x6666666677777777, 0x7777777788888888, 0x99999999aaaaaaaa, 0xaaaaaaaabbbbbbbb, 0xbbbbbbbbcccccccc, 0xccccccccdddddddd, 0xddddddddeeeeeeee, 0xeeeeeeeeffffffff, 0xffffffff11111111, 0x1111222233334444, 0x5555666677778888, 0x9999aaaabbbbcccc, 0xddddeeeeffff1111, 0xffffeeeeddddcccc, 0xbbbbaaaa99998888, 0x7777666655554444, 0x333322221111ffff, 0x1122334455667788, 0x99aabbccddeeff11, 0xffeeddccbbaa9988, 0x77665544332211ff, 0x123456789abcdef1, 0xfedcba987654321f, 0xcafecafecafecafe }; unsigned int gen_set_vl(const unsigned int vl) { switch (vl) { case VL_128_BIT: return VL_256_BIT; case VL_256_BIT: return VL_512_BIT; case VL_512_BIT: return VL_128_BIT; default: break; } return -1; } static int compare_vl_flags(const unsigned int exp, const unsigned int target, const unsigned int onexec_vl) { int ret = 0; const unsigned int exp_vl = PR_SVE_GET_VL_LEN(exp); unsigned int exp_flags = PR_SVE_GET_VL_FLAGS(exp); const unsigned int target_vl = PR_SVE_GET_VL_LEN(target); const unsigned int target_flags = PR_SVE_GET_VL_FLAGS(target); const unsigned int rd_vl = sve_get_vl(); unsigned int exp_rdvl = 0; /* PR_SVE_SET_VL_ONEXEC flag is set only. */ exp_flags &= ~PR_SVE_SET_VL_ONEXEC; if (onexec_vl == 0) { exp_rdvl = exp_vl; } else { exp_rdvl = onexec_vl; } if (exp_vl != target_vl) { printf("Expected VL(0x%x) != Target VL(0x%x).\n", exp_vl, target_vl); ret = -1; } if (exp_flags != target_flags) { printf("Expected FLAGS(0x%x) != Target FLAGS(0x%x).\n", exp_flags, target_flags); ret = -1; } if (exp_rdvl != rd_vl) { printf("Expected VL(0x%x) != VL on Register(0x%x).\n", exp_rdvl, rd_vl); ret = -1; } if (ret == -1) { printf("Expected VALUE (0x%x), Target VALUE (0x%x).\n", (exp & ~PR_SVE_SET_VL_ONEXEC), target); } return ret; } int get_and_compare_vl(const unsigned long exp_arg) { int ret = -1; int vl_flags = 0; vl_flags = prctl(PR_SVE_GET_VL); if (vl_flags == -1) { perror("prctl(PR_SVE_GET_VL)"); ret = errno; } else { printf("Get VL(0x%x), FLAGS(0x%x)\n", PR_SVE_GET_VL_LEN(vl_flags), PR_SVE_GET_VL_FLAGS(vl_flags)); ret = compare_vl_flags(exp_arg, vl_flags, 0); } return ret; } int set_and_compare_vl(const unsigned long set_arg) { int ret = 0; int vl_flags = 0; const int onexec = ((set_arg & PR_SVE_SET_VL_ONEXEC) ? 1 : 0); unsigned long exp_vl = PR_SVE_GET_VL_LEN(set_arg); unsigned long exp_flags = PR_SVE_GET_VL_FLAGS(set_arg); unsigned int onexec_vl = 0; printf("Set VL(0x%lx), FLAGS(0x%lx)\n", PR_SVE_GET_VL_LEN(set_arg), PR_SVE_GET_VL_FLAGS(set_arg)); if (onexec) { int exp_arg = 0; exp_arg = prctl(PR_SVE_GET_VL); if (exp_arg == -1) { perror("prctl(PR_SVE_GET_VL)"); ret = errno; goto out; } else { onexec_vl = PR_SVE_GET_VL_LEN(exp_arg); } } vl_flags = prctl(PR_SVE_SET_VL, set_arg); if (vl_flags == -1) { perror("prctl(PR_SVE_SET_VL)"); ret = errno; } else { ret = compare_vl_flags(exp_vl | exp_flags, vl_flags, onexec_vl); } out: return ret; } void gen_test_sve(void *buf, unsigned int vq) { struct fpsimd_sve_state(vq) * svereg = buf; unsigned long *pzreg = (unsigned long *)svereg->zregs; unsigned int sve_magic_num = ARRAY_SIZE(sve_magic); int i = 0, j = 0; /* zregs */ for (i = 0; i < 32; i++) { for (j = 0; j < vq * 2; j++) { int k = i * vq * 2; pzreg[k + j] = sve_magic[(k + j) % sve_magic_num]; } } /* pregs */ for (i = 0; i < 16; i++) { for (j = 0; j < vq; j++) { int k = i * vq; svereg->pregs[i][j] = (unsigned short) (sve_magic[(k + j) % sve_magic_num]); } } /* ffr */ for (i = 0; i < vq; i++) { svereg->ffr[i] = (unsigned short)(sve_magic[i % sve_magic_num]); } } void gen_test_sve_low_128(void *buf, unsigned int bf_vq, unsigned int af_vq) { struct fpsimd_sve_state(bf_vq) tmp_buf; struct fpsimd_sve_state(af_vq) * svereg = buf; int i = 0; memset(&tmp_buf, 0, sizeof(tmp_buf)); gen_test_sve(&tmp_buf, bf_vq); /* zregs */ for (i = 0; i < 32; i++) { svereg->zregs[i][0] = tmp_buf.zregs[i][0]; } } void gen_test_fpsimd(struct user_fpsimd_state *buf, unsigned int vq) { int i = 0; struct fpsimd_sve_state(vq) svereg; gen_test_sve(&svereg, vq); for (i = 0; i < 32; i++) { buf->vregs[i] = svereg.zregs[i][0]; } } void gen_test_sve_dirty(void *buf, unsigned int vq) { struct fpsimd_sve_state(vq) * svereg = buf; memset(svereg, 0xda, sizeof(*svereg)); } void write_sve(void *buf, unsigned int vq, unsigned int *fpscr) { struct fpsimd_sve_state(vq) * svereg = buf; sve_load_state(svereg->ffr, fpscr); } void read_sve(void *buf, unsigned int vq, unsigned int *fpscr) { struct fpsimd_sve_state(vq) * svereg = buf; sve_save_state(svereg->ffr, fpscr); } void show_sve(const void *buf, unsigned int vq, unsigned int *fpscr) { const struct fpsimd_sve_state(vq) * svereg = buf; int i = 0, j = 0; unsigned long *pzreg = (unsigned long *)svereg->zregs; /* zregs */ for (i = 0; i < 32; i++) { printf("z%2d: ", i); for (j = 0; j < vq * 2; j++) { int k = i * vq * 2; if ((j != 0) && (j % 4 == 0)) { printf("\n"); printf(" "); } printf("0x%016lx ", pzreg[k + j]); } printf("\n"); } /* pregs */ for (i = 0; i < 16; i++) { printf("p%2d: ", i); for (j = 0; j < vq; j++) { printf("0x%04x ", svereg->pregs[i][j]); } printf("\n"); } /* ffr */ for (i = 0; i < vq; i++) { printf("ffr%2d: 0x%04x\n", i, svereg->ffr[i]); } printf("fpsr: 0x%08x\n", fpscr[0]); printf("fpcr: 0x%08x\n", fpscr[1]); } void read_and_show_sve(void *buf, unsigned int vq, unsigned int *fpscr) { read_sve(buf, vq, fpscr); show_sve(buf, vq, fpscr); } int header_compare(const struct user_sve_header *target) { int ret = -1; unsigned int vq, max_vq; if (!sve_vl_valid(target->vl)) { printf("VL invalid.\n"); goto out; } vq = sve_vq_from_vl(target->vl); if (!sve_vl_valid(target->max_vl)) { printf("MAX-VL invalid.\n"); goto out; } max_vq = sve_vq_from_vl(target->max_vl); if (!(target->flags & SVE_PT_REGS_SVE)) { printf("FLAGS invalid.\n"); goto out; } if (target->size != SVE_PT_SIZE(vq, target->flags)) { printf("SIZE invalid.\n"); goto out; } if (target->max_size != SVE_PT_SIZE(max_vq, SVE_PT_REGS_SVE)) { printf("MAX-SIZE invalid.\n"); goto out; } ret = 0; out: return ret; } int sve_compare(const void *expect, const void *target, unsigned int vq) { int i = 0, ret = 0; const struct fpsimd_sve_state(vq) * exp = expect; const struct fpsimd_sve_state(vq) * tgt = target; /* compare low 64 bits of z8-z15 */ for (i = 8; i <= 15; i++) { unsigned long e = (unsigned long)exp->zregs[i][0]; unsigned long t = (unsigned long)tgt->zregs[i][0]; if (e != t) { printf("Compare Failed, z%2d exp 0x%016lx " "val 0x%016lx\n", i, e, t); ret = -1; } } return ret; } int fpsimd_compare(const struct user_fpsimd_state *expect, const struct user_fpsimd_state *target, size_t n) { int i = 0; if (memcmp(expect, target, n)) { const unsigned long *exp = (const unsigned long *)expect; const unsigned long *tgt = (const unsigned long *)target; printf("Compare Failed !!\n"); printf("[show expect values]\n"); for (i = 0; i < 64; i += 2) { printf("q%2d: 0x%016lx 0x%016lx\n", i / 2, exp[i], exp[i + 1]); } printf("fpsr: 0x%08x\n", expect->fpsr); printf("fpcr: 0x%08x\n", expect->fpcr); printf("[show target values]\n"); for (i = 0; i < 64; i += 2) { printf("q%2d: 0x%016lx 0x%016lx\n", i / 2, tgt[i], tgt[i + 1]); } printf("fpsr: 0x%08x\n", target->fpsr); printf("fpcr: 0x%08x\n", target->fpcr); return -1; } return 0; } void read_fpsimd(struct user_fpsimd_state *regs) { asm volatile( "stp q0, q1, [%0, #16 * 0]\n" "stp q2, q3, [%0, #16 * 2]\n" "stp q4, q5, [%0, #16 * 4]\n" "stp q6, q7, [%0, #16 * 6]\n" "stp q8, q9, [%0, #16 * 8]\n" "stp q10, q11, [%0, #16 * 10]\n" "stp q12, q13, [%0, #16 * 12]\n" "stp q14, q15, [%0, #16 * 14]\n" "stp q16, q17, [%0, #16 * 16]\n" "stp q18, q19, [%0, #16 * 18]\n" "stp q20, q21, [%0, #16 * 20]\n" "stp q22, q23, [%0, #16 * 22]\n" "stp q24, q25, [%0, #16 * 24]\n" "stp q26, q27, [%0, #16 * 26]\n" "stp q28, q29, [%0, #16 * 28]\n" "stp q30, q31, [%0, #16 * 30]\n" "mrs x8, fpsr\n" "str w8, [%0, #512]\n" "mrs x8, fpcr\n" "str w8, [%0, #516]\n" : : "r" (regs) : "x8", "memory" ); }