Commit 024e4a15 authored by Mark Brown's avatar Mark Brown Committed by Catalin Marinas

kselftest/arm64: Verify SME only ABI in syscall-abi

Currently syscall-abi only covers SME in the case where the system supports
SVE however it is architecturally valid to support SME without SVE. Update
the program to cover this case, this requires adjustments in the code to
check for SVCR.SM being set when deciding if we're handling the FPSIMD or
SVE registers and the addition of new test cases for the SME only case.

Note that in the SME only case we should not save the SVE registers after a
syscall since even if we were in streaming mode and therefore set them the
syscall should have exited streaming mode, we check that we have done so by
looking at SVCR.
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20221223-arm64-syscall-abi-sme-only-v1-3-4fabfbd62087@kernel.orgSigned-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent fae491e5
...@@ -92,8 +92,11 @@ do_syscall: ...@@ -92,8 +92,11 @@ do_syscall:
str x29, [x2], #8 // FP str x29, [x2], #8 // FP
str x30, [x2], #8 // LR str x30, [x2], #8 // LR
// Load FPRs if we're not doing SVE // Load FPRs if we're not doing neither SVE nor streaming SVE
cbnz x0, 1f cbnz x0, 1f
ldr x2, =svcr_in
tbnz x2, #SVCR_SM_SHIFT, 1f
ldr x2, =fpr_in ldr x2, =fpr_in
ldp q0, q1, [x2] ldp q0, q1, [x2]
ldp q2, q3, [x2, #16 * 2] ldp q2, q3, [x2, #16 * 2]
...@@ -111,10 +114,11 @@ do_syscall: ...@@ -111,10 +114,11 @@ do_syscall:
ldp q26, q27, [x2, #16 * 26] ldp q26, q27, [x2, #16 * 26]
ldp q28, q29, [x2, #16 * 28] ldp q28, q29, [x2, #16 * 28]
ldp q30, q31, [x2, #16 * 30] ldp q30, q31, [x2, #16 * 30]
b 2f
1: 1:
// Load the SVE registers if we're doing SVE/SME // Load the SVE registers if we're doing SVE/SME
cbz x0, 1f
ldr x2, =z_in ldr x2, =z_in
ldr z0, [x2, #0, MUL VL] ldr z0, [x2, #0, MUL VL]
...@@ -155,9 +159,9 @@ do_syscall: ...@@ -155,9 +159,9 @@ do_syscall:
ldr x2, =ffr_in ldr x2, =ffr_in
ldr p0, [x2] ldr p0, [x2]
ldr x2, [x2, #0] ldr x2, [x2, #0]
cbz x2, 2f cbz x2, 1f
wrffr p0.b wrffr p0.b
2: 1:
ldr x2, =p_in ldr x2, =p_in
ldr p0, [x2, #0, MUL VL] ldr p0, [x2, #0, MUL VL]
...@@ -176,7 +180,7 @@ do_syscall: ...@@ -176,7 +180,7 @@ do_syscall:
ldr p13, [x2, #13, MUL VL] ldr p13, [x2, #13, MUL VL]
ldr p14, [x2, #14, MUL VL] ldr p14, [x2, #14, MUL VL]
ldr p15, [x2, #15, MUL VL] ldr p15, [x2, #15, MUL VL]
1: 2:
// Do the syscall // Do the syscall
svc #0 svc #0
......
...@@ -88,6 +88,7 @@ static int check_gpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl, uint64_t s ...@@ -88,6 +88,7 @@ static int check_gpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl, uint64_t s
#define NUM_FPR 32 #define NUM_FPR 32
uint64_t fpr_in[NUM_FPR * 2]; uint64_t fpr_in[NUM_FPR * 2];
uint64_t fpr_out[NUM_FPR * 2]; uint64_t fpr_out[NUM_FPR * 2];
uint64_t fpr_zero[NUM_FPR * 2];
static void setup_fpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl, static void setup_fpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
uint64_t svcr) uint64_t svcr)
...@@ -102,7 +103,7 @@ static int check_fpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl, ...@@ -102,7 +103,7 @@ static int check_fpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
int errors = 0; int errors = 0;
int i; int i;
if (!sve_vl) { if (!sve_vl && !(svcr & SVCR_SM_MASK)) {
for (i = 0; i < ARRAY_SIZE(fpr_in); i++) { for (i = 0; i < ARRAY_SIZE(fpr_in); i++) {
if (fpr_in[i] != fpr_out[i]) { if (fpr_in[i] != fpr_out[i]) {
ksft_print_msg("%s Q%d/%d mismatch %llx != %llx\n", ksft_print_msg("%s Q%d/%d mismatch %llx != %llx\n",
...@@ -114,6 +115,18 @@ static int check_fpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl, ...@@ -114,6 +115,18 @@ static int check_fpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
} }
} }
/*
* In streaming mode the whole register set should be cleared
* by the transition out of streaming mode.
*/
if (svcr & SVCR_SM_MASK) {
if (memcmp(fpr_zero, fpr_out, sizeof(fpr_out)) != 0) {
ksft_print_msg("%s FPSIMD registers non-zero exiting SM\n",
cfg->name);
errors++;
}
}
return errors; return errors;
} }
...@@ -400,6 +413,24 @@ static void test_one_syscall(struct syscall_cfg *cfg) ...@@ -400,6 +413,24 @@ static void test_one_syscall(struct syscall_cfg *cfg)
sme_vls[sme]); sme_vls[sme]);
} }
} }
for (sme = 0; sme < sme_vl_count; sme++) {
ret = prctl(PR_SME_SET_VL, sme_vls[sme]);
if (ret == -1)
ksft_exit_fail_msg("PR_SME_SET_VL failed: %s (%d)\n",
strerror(errno), errno);
ksft_test_result(do_test(cfg, 0, sme_vls[sme],
SVCR_ZA_MASK | SVCR_SM_MASK),
"%s SME VL %d SM+ZA\n",
cfg->name, sme_vls[sme]);
ksft_test_result(do_test(cfg, 0, sme_vls[sme], SVCR_SM_MASK),
"%s SME VL %d SM\n",
cfg->name, sme_vls[sme]);
ksft_test_result(do_test(cfg, 0, sme_vls[sme], SVCR_ZA_MASK),
"%s SME VL %d ZA\n",
cfg->name, sme_vls[sme]);
}
} }
void sve_count_vls(void) void sve_count_vls(void)
...@@ -474,6 +505,7 @@ int main(void) ...@@ -474,6 +505,7 @@ int main(void)
sme_count_vls(); sme_count_vls();
tests += sve_vl_count; tests += sve_vl_count;
tests += sme_vl_count * 3;
tests += (sve_vl_count * sme_vl_count) * 3; tests += (sve_vl_count * sme_vl_count) * 3;
ksft_set_plan(ARRAY_SIZE(syscalls) * tests); ksft_set_plan(ARRAY_SIZE(syscalls) * tests);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment