Files
mckernel/test/sve/src/sve.c
Shiratori, Takehiro 7da5fede8b Test "Scalable Vector Extension (SVE) support." on arm64
Change-Id: I3abaca932985a06b06887b962e769f2eac96c738
2019-02-27 06:26:00 +00:00

390 lines
8.8 KiB
C

/* sve.c COPYRIGHT FUJITSU LIMITED 2016-2019 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <errno.h>
#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"
);
}