Commit c3976232 authored by Catalin Marinas's avatar Catalin Marinas

Merge branch 'for-next/kselftest' into for-next/core

* for-next/kselftest: (28 commits)
  : Kselftest updates for arm64
  kselftest/arm64: Handle EINTR while reading data from children
  kselftest/arm64: Flag fp-stress as exiting when we begin finishing up
  kselftest/arm64: Don't repeat termination handler for fp-stress
  kselftest/arm64: Don't enable v8.5 for MTE selftest builds
  kselftest/arm64: Fix typo in hwcap check
  kselftest/arm64: Add hwcap test for RNG
  kselftest/arm64: Add SVE 2 to the tested hwcaps
  kselftest/arm64: Add missing newline in hwcap output
  kselftest/arm64: Fix spelling misakes of signal names
  kselftest/arm64: Enforce actual ABI for SVE syscalls
  kselftest/arm64: Correct buffer allocation for SVE Z registers
  kselftest/arm64: Include larger SVE and SME VLs in signal tests
  kselftest/arm64: Allow larger buffers in get_signal_context()
  kselftest/arm64: Preserve any EXTRA_CONTEXT in handle_signal_copyctx()
  kselftest/arm64: Validate contents of EXTRA_CONTEXT blocks
  kselftest/arm64: Only validate each signal context once
  kselftest/arm64: Remove unneeded protype for validate_extra_context()
  kselftest/arm64: Fix validation of EXTRA_CONTEXT signal context location
  kselftest/arm64: Fix validatation termination record after EXTRA_CONTEXT
  kselftest/arm64: Validate signal ucontext in place
  ...
parents b23ec74c a7119874
hwcap
ptrace ptrace
syscall-abi syscall-abi
tpidr2 tpidr2
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2021 ARM Limited # Copyright (C) 2021 ARM Limited
TEST_GEN_PROGS := ptrace syscall-abi tpidr2 TEST_GEN_PROGS := hwcap ptrace syscall-abi tpidr2
include ../../lib.mk include ../../lib.mk
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2022 ARM Limited.
*/
#include <errno.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/auxv.h>
#include <sys/prctl.h>
#include <asm/hwcap.h>
#include <asm/sigcontext.h>
#include <asm/unistd.h>
#include "../../kselftest.h"
#define TESTS_PER_HWCAP 2
/*
* Function expected to generate SIGILL when the feature is not
* supported and return when it is supported. If SIGILL is generated
* then the handler must be able to skip over the instruction safely.
*
* Note that it is expected that for many architecture extensions
* there are no specific traps due to no architecture state being
* added so we may not fault if running on a kernel which doesn't know
* to add the hwcap.
*/
typedef void (*sigill_fn)(void);
static void rng_sigill(void)
{
asm volatile("mrs x0, S3_3_C2_C4_0" : : : "x0");
}
static void sme_sigill(void)
{
/* RDSVL x0, #0 */
asm volatile(".inst 0x04bf5800" : : : "x0");
}
static void sve_sigill(void)
{
/* RDVL x0, #0 */
asm volatile(".inst 0x04bf5000" : : : "x0");
}
static void sve2_sigill(void)
{
/* SQABS Z0.b, P0/M, Z0.B */
asm volatile(".inst 0x4408A000" : : : "z0");
}
static void sveaes_sigill(void)
{
/* AESD z0.b, z0.b, z0.b */
asm volatile(".inst 0x4522e400" : : : "z0");
}
static void svepmull_sigill(void)
{
/* PMULLB Z0.Q, Z0.D, Z0.D */
asm volatile(".inst 0x45006800" : : : "z0");
}
static void svebitperm_sigill(void)
{
/* BDEP Z0.B, Z0.B, Z0.B */
asm volatile(".inst 0x4500b400" : : : "z0");
}
static void svesha3_sigill(void)
{
/* EOR3 Z0.D, Z0.D, Z0.D, Z0.D */
asm volatile(".inst 0x4203800" : : : "z0");
}
static void svesm4_sigill(void)
{
/* SM4E Z0.S, Z0.S, Z0.S */
asm volatile(".inst 0x4523e000" : : : "z0");
}
static void svei8mm_sigill(void)
{
/* USDOT Z0.S, Z0.B, Z0.B[0] */
asm volatile(".inst 0x44a01800" : : : "z0");
}
static void svef32mm_sigill(void)
{
/* FMMLA Z0.S, Z0.S, Z0.S */
asm volatile(".inst 0x64a0e400" : : : "z0");
}
static void svef64mm_sigill(void)
{
/* FMMLA Z0.D, Z0.D, Z0.D */
asm volatile(".inst 0x64e0e400" : : : "z0");
}
static void svebf16_sigill(void)
{
/* BFCVT Z0.H, P0/M, Z0.S */
asm volatile(".inst 0x658aa000" : : : "z0");
}
static const struct hwcap_data {
const char *name;
unsigned long at_hwcap;
unsigned long hwcap_bit;
const char *cpuinfo;
sigill_fn sigill_fn;
bool sigill_reliable;
} hwcaps[] = {
{
.name = "RNG",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_RNG,
.cpuinfo = "rng",
.sigill_fn = rng_sigill,
},
{
.name = "SME",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_SME,
.cpuinfo = "sme",
.sigill_fn = sme_sigill,
.sigill_reliable = true,
},
{
.name = "SVE",
.at_hwcap = AT_HWCAP,
.hwcap_bit = HWCAP_SVE,
.cpuinfo = "sve",
.sigill_fn = sve_sigill,
.sigill_reliable = true,
},
{
.name = "SVE 2",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_SVE2,
.cpuinfo = "sve2",
.sigill_fn = sve2_sigill,
},
{
.name = "SVE AES",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_SVEAES,
.cpuinfo = "sveaes",
.sigill_fn = sveaes_sigill,
},
{
.name = "SVE2 PMULL",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_SVEPMULL,
.cpuinfo = "svepmull",
.sigill_fn = svepmull_sigill,
},
{
.name = "SVE2 BITPERM",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_SVEBITPERM,
.cpuinfo = "svebitperm",
.sigill_fn = svebitperm_sigill,
},
{
.name = "SVE2 SHA3",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_SVESHA3,
.cpuinfo = "svesha3",
.sigill_fn = svesha3_sigill,
},
{
.name = "SVE2 SM4",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_SVESM4,
.cpuinfo = "svesm4",
.sigill_fn = svesm4_sigill,
},
{
.name = "SVE2 I8MM",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_SVEI8MM,
.cpuinfo = "svei8mm",
.sigill_fn = svei8mm_sigill,
},
{
.name = "SVE2 F32MM",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_SVEF32MM,
.cpuinfo = "svef32mm",
.sigill_fn = svef32mm_sigill,
},
{
.name = "SVE2 F64MM",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_SVEF64MM,
.cpuinfo = "svef64mm",
.sigill_fn = svef64mm_sigill,
},
{
.name = "SVE2 BF16",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_SVEBF16,
.cpuinfo = "svebf16",
.sigill_fn = svebf16_sigill,
},
{
.name = "SVE2 EBF16",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_SVE_EBF16,
.cpuinfo = "sveebf16",
},
};
static bool seen_sigill;
static void handle_sigill(int sig, siginfo_t *info, void *context)
{
ucontext_t *uc = context;
seen_sigill = true;
/* Skip over the offending instruction */
uc->uc_mcontext.pc += 4;
}
bool cpuinfo_present(const char *name)
{
FILE *f;
char buf[2048], name_space[30], name_newline[30];
char *s;
/*
* The feature should appear with a leading space and either a
* trailing space or a newline.
*/
snprintf(name_space, sizeof(name_space), " %s ", name);
snprintf(name_newline, sizeof(name_newline), " %s\n", name);
f = fopen("/proc/cpuinfo", "r");
if (!f) {
ksft_print_msg("Failed to open /proc/cpuinfo\n");
return false;
}
while (fgets(buf, sizeof(buf), f)) {
/* Features: line? */
if (strncmp(buf, "Features\t:", strlen("Features\t:")) != 0)
continue;
/* All CPUs should be symmetric, don't read any more */
fclose(f);
s = strstr(buf, name_space);
if (s)
return true;
s = strstr(buf, name_newline);
if (s)
return true;
return false;
}
ksft_print_msg("Failed to find Features in /proc/cpuinfo\n");
fclose(f);
return false;
}
int main(void)
{
const struct hwcap_data *hwcap;
int i, ret;
bool have_cpuinfo, have_hwcap;
struct sigaction sa;
ksft_print_header();
ksft_set_plan(ARRAY_SIZE(hwcaps) * TESTS_PER_HWCAP);
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = handle_sigill;
sa.sa_flags = SA_RESTART | SA_SIGINFO;
sigemptyset(&sa.sa_mask);
ret = sigaction(SIGILL, &sa, NULL);
if (ret < 0)
ksft_exit_fail_msg("Failed to install SIGILL handler: %s (%d)\n",
strerror(errno), errno);
for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
hwcap = &hwcaps[i];
have_hwcap = getauxval(hwcap->at_hwcap) & hwcap->hwcap_bit;
have_cpuinfo = cpuinfo_present(hwcap->cpuinfo);
if (have_hwcap)
ksft_print_msg("%s present\n", hwcap->name);
ksft_test_result(have_hwcap == have_cpuinfo,
"cpuinfo_match_%s\n", hwcap->name);
if (hwcap->sigill_fn) {
seen_sigill = false;
hwcap->sigill_fn();
if (have_hwcap) {
/* Should be able to use the extension */
ksft_test_result(!seen_sigill, "sigill_%s\n",
hwcap->name);
} else if (hwcap->sigill_reliable) {
/* Guaranteed a SIGILL */
ksft_test_result(seen_sigill, "sigill_%s\n",
hwcap->name);
} else {
/* Missing SIGILL might be fine */
ksft_print_msg("SIGILL %sreported for %s\n",
seen_sigill ? "" : "not ",
hwcap->name);
ksft_test_result_skip("sigill_%s\n",
hwcap->name);
}
} else {
ksft_test_result_skip("sigill_%s\n",
hwcap->name);
}
}
ksft_print_cnts();
return 0;
}
...@@ -112,9 +112,11 @@ static int check_fpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl, ...@@ -112,9 +112,11 @@ static int check_fpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
return errors; return errors;
} }
#define SVE_Z_SHARED_BYTES (128 / 8)
static uint8_t z_zero[__SVE_ZREG_SIZE(SVE_VQ_MAX)]; static uint8_t z_zero[__SVE_ZREG_SIZE(SVE_VQ_MAX)];
uint8_t z_in[SVE_NUM_PREGS * __SVE_ZREG_SIZE(SVE_VQ_MAX)]; uint8_t z_in[SVE_NUM_ZREGS * __SVE_ZREG_SIZE(SVE_VQ_MAX)];
uint8_t z_out[SVE_NUM_PREGS * __SVE_ZREG_SIZE(SVE_VQ_MAX)]; uint8_t z_out[SVE_NUM_ZREGS * __SVE_ZREG_SIZE(SVE_VQ_MAX)];
static void setup_z(struct syscall_cfg *cfg, int sve_vl, int sme_vl, static void setup_z(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
uint64_t svcr) uint64_t svcr)
...@@ -133,22 +135,39 @@ static int check_z(struct syscall_cfg *cfg, int sve_vl, int sme_vl, ...@@ -133,22 +135,39 @@ static int check_z(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
if (!sve_vl) if (!sve_vl)
return 0; return 0;
/*
* After a syscall the low 128 bits of the Z registers should
* be preserved and the rest be zeroed or preserved, except if
* we were in streaming mode in which case the low 128 bits may
* also be cleared by the transition out of streaming mode.
*/
for (i = 0; i < SVE_NUM_ZREGS; i++) { for (i = 0; i < SVE_NUM_ZREGS; i++) {
void *in = &z_in[reg_size * i]; uint8_t *in = &z_in[reg_size * i];
void *out = &z_out[reg_size * i]; uint8_t *out = &z_out[reg_size * i];
if ((memcmp(in, out, SVE_VQ_BYTES) != 0) && if (svcr & SVCR_SM_MASK) {
!((svcr & SVCR_SM_MASK) && /*
memcmp(z_zero, out, SVE_VQ_BYTES) == 0)) { * In streaming mode the whole register should
ksft_print_msg("%s SVE VL %d Z%d low 128 bits changed\n", * be cleared by the transition out of
cfg->name, sve_vl, i); * streaming mode.
errors++; */
if (memcmp(z_zero, out, reg_size) != 0) {
ksft_print_msg("%s SVE VL %d Z%d non-zero\n",
cfg->name, sve_vl, i);
errors++;
}
} else {
/*
* For standard SVE the low 128 bits should be
* preserved and any additional bits cleared.
*/
if (memcmp(in, out, SVE_Z_SHARED_BYTES) != 0) {
ksft_print_msg("%s SVE VL %d Z%d low 128 bits changed\n",
cfg->name, sve_vl, i);
errors++;
}
if (reg_size > SVE_Z_SHARED_BYTES &&
(memcmp(z_zero, out + SVE_Z_SHARED_BYTES,
reg_size - SVE_Z_SHARED_BYTES) != 0)) {
ksft_print_msg("%s SVE VL %d Z%d high bits non-zero\n",
cfg->name, sve_vl, i);
errors++;
}
} }
} }
...@@ -176,9 +195,9 @@ static int check_p(struct syscall_cfg *cfg, int sve_vl, int sme_vl, ...@@ -176,9 +195,9 @@ static int check_p(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
if (!sve_vl) if (!sve_vl)
return 0; return 0;
/* After a syscall the P registers should be preserved or zeroed */ /* After a syscall the P registers should be zeroed */
for (i = 0; i < SVE_NUM_PREGS * reg_size; i++) for (i = 0; i < SVE_NUM_PREGS * reg_size; i++)
if (p_out[i] && (p_in[i] != p_out[i])) if (p_out[i])
errors++; errors++;
if (errors) if (errors)
ksft_print_msg("%s SVE VL %d predicate registers non-zero\n", ksft_print_msg("%s SVE VL %d predicate registers non-zero\n",
...@@ -226,9 +245,9 @@ static int check_ffr(struct syscall_cfg *cfg, int sve_vl, int sme_vl, ...@@ -226,9 +245,9 @@ static int check_ffr(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
!(getauxval(AT_HWCAP2) & HWCAP2_SME_FA64)) !(getauxval(AT_HWCAP2) & HWCAP2_SME_FA64))
return 0; return 0;
/* After a syscall the P registers should be preserved or zeroed */ /* After a syscall FFR should be zeroed */
for (i = 0; i < reg_size; i++) for (i = 0; i < reg_size; i++)
if (ffr_out[i] && (ffr_in[i] != ffr_out[i])) if (ffr_out[i])
errors++; errors++;
if (errors) if (errors)
ksft_print_msg("%s SVE VL %d FFR non-zero\n", ksft_print_msg("%s SVE VL %d FFR non-zero\n",
......
fp-pidbench fp-pidbench
fp-stress
fpsimd-test fpsimd-test
rdvl-sme rdvl-sme
rdvl-sve rdvl-sve
......
...@@ -5,7 +5,10 @@ top_srcdir = $(realpath ../../../../../) ...@@ -5,7 +5,10 @@ top_srcdir = $(realpath ../../../../../)
CFLAGS += -I$(top_srcdir)/usr/include/ CFLAGS += -I$(top_srcdir)/usr/include/
TEST_GEN_PROGS := sve-ptrace sve-probe-vls vec-syscfg za-fork za-ptrace TEST_GEN_PROGS := fp-stress \
sve-ptrace sve-probe-vls \
vec-syscfg \
za-fork za-ptrace
TEST_GEN_PROGS_EXTENDED := fp-pidbench fpsimd-test \ TEST_GEN_PROGS_EXTENDED := fp-pidbench fpsimd-test \
rdvl-sme rdvl-sve \ rdvl-sme rdvl-sve \
sve-test \ sve-test \
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#define sa_handler 0 #define sa_handler 0
#define sa_mask_sz 8 #define sa_mask_sz 8
#define SIGUSR1 10 #define SIGUSR1 10
#define SIGUSR2 12
#define SIGTERM 15 #define SIGTERM 15
#define SIGINT 2 #define SIGINT 2
#define SIGABRT 6 #define SIGABRT 6
......
This diff is collapsed.
...@@ -151,6 +151,15 @@ function irritator_handler ...@@ -151,6 +151,15 @@ function irritator_handler
ret ret
endfunction endfunction
function tickle_handler
// Increment the signal count (x23):
ldr x0, [x2, #ucontext_regs + 8 * 23]
add x0, x0, #1
str x0, [x2, #ucontext_regs + 8 * 23]
ret
endfunction
function terminate_handler function terminate_handler
mov w21, w0 mov w21, w0
mov x20, x2 mov x20, x2
...@@ -207,6 +216,30 @@ endfunction ...@@ -207,6 +216,30 @@ endfunction
.globl _start .globl _start
function _start function _start
_start: _start:
mov x23, #0 // signal count
mov w0, #SIGINT
adr x1, terminate_handler
mov w2, #SA_SIGINFO
bl setsignal
mov w0, #SIGTERM
adr x1, terminate_handler
mov w2, #SA_SIGINFO
bl setsignal
mov w0, #SIGUSR1
adr x1, irritator_handler
mov w2, #SA_SIGINFO
orr w2, w2, #SA_NODEFER
bl setsignal
mov w0, #SIGUSR2
adr x1, tickle_handler
mov w2, #SA_SIGINFO
orr w2, w2, #SA_NODEFER
bl setsignal
// Sanity-check and report the vector length // Sanity-check and report the vector length
mov x19, #128 mov x19, #128
...@@ -237,24 +270,6 @@ _start: ...@@ -237,24 +270,6 @@ _start:
mov x0, x20 mov x0, x20
bl putdecn bl putdecn
mov x23, #0 // Irritation signal count
mov w0, #SIGINT
adr x1, terminate_handler
mov w2, #SA_SIGINFO
bl setsignal
mov w0, #SIGTERM
adr x1, terminate_handler
mov w2, #SA_SIGINFO
bl setsignal
mov w0, #SIGUSR1
adr x1, irritator_handler
mov w2, #SA_SIGINFO
orr w2, w2, #SA_NODEFER
bl setsignal
mov x22, #0 // generation number, increments per iteration mov x22, #0 // generation number, increments per iteration
.Ltest_loop: .Ltest_loop:
......
...@@ -314,6 +314,15 @@ function irritator_handler ...@@ -314,6 +314,15 @@ function irritator_handler
ret ret
endfunction endfunction
function tickle_handler
// Increment the signal count (x23):
ldr x0, [x2, #ucontext_regs + 8 * 23]
add x0, x0, #1
str x0, [x2, #ucontext_regs + 8 * 23]
ret
endfunction
function terminate_handler function terminate_handler
mov w21, w0 mov w21, w0
mov x20, x2 mov x20, x2
...@@ -370,6 +379,30 @@ endfunction ...@@ -370,6 +379,30 @@ endfunction
.globl _start .globl _start
function _start function _start
_start: _start:
mov x23, #0 // Irritation signal count
mov w0, #SIGINT
adr x1, terminate_handler
mov w2, #SA_SIGINFO
bl setsignal
mov w0, #SIGTERM
adr x1, terminate_handler
mov w2, #SA_SIGINFO
bl setsignal
mov w0, #SIGUSR1
adr x1, irritator_handler
mov w2, #SA_SIGINFO
orr w2, w2, #SA_NODEFER
bl setsignal
mov w0, #SIGUSR2
adr x1, tickle_handler
mov w2, #SA_SIGINFO
orr w2, w2, #SA_NODEFER
bl setsignal
#ifdef SSVE #ifdef SSVE
puts "Streaming mode " puts "Streaming mode "
smstart_sm smstart_sm
...@@ -405,24 +438,6 @@ _start: ...@@ -405,24 +438,6 @@ _start:
mov x0, x20 mov x0, x20
bl putdecn bl putdecn
mov x23, #0 // Irritation signal count
mov w0, #SIGINT
adr x1, terminate_handler
mov w2, #SA_SIGINFO
bl setsignal
mov w0, #SIGTERM
adr x1, terminate_handler
mov w2, #SA_SIGINFO
bl setsignal
mov w0, #SIGUSR1
adr x1, irritator_handler
mov w2, #SA_SIGINFO
orr w2, w2, #SA_NODEFER
bl setsignal
#ifdef SSVE #ifdef SSVE
smstart_sm // syscalls will have exited streaming mode smstart_sm // syscalls will have exited streaming mode
#endif #endif
......
...@@ -167,6 +167,15 @@ function irritator_handler ...@@ -167,6 +167,15 @@ function irritator_handler
ret ret
endfunction endfunction
function tickle_handler
// Increment the signal count (x23):
ldr x0, [x2, #ucontext_regs + 8 * 23]
add x0, x0, #1
str x0, [x2, #ucontext_regs + 8 * 23]
ret
endfunction
function terminate_handler function terminate_handler
mov w21, w0 mov w21, w0
mov x20, x2 mov x20, x2
...@@ -223,6 +232,30 @@ endfunction ...@@ -223,6 +232,30 @@ endfunction
.globl _start .globl _start
function _start function _start
_start: _start:
mov x23, #0 // signal count
mov w0, #SIGINT
adr x1, terminate_handler
mov w2, #SA_SIGINFO
bl setsignal
mov w0, #SIGTERM
adr x1, terminate_handler
mov w2, #SA_SIGINFO
bl setsignal
mov w0, #SIGUSR1
adr x1, irritator_handler
mov w2, #SA_SIGINFO
orr w2, w2, #SA_NODEFER
bl setsignal
mov w0, #SIGUSR2
adr x1, tickle_handler
mov w2, #SA_SIGINFO
orr w2, w2, #SA_NODEFER
bl setsignal
puts "Streaming mode " puts "Streaming mode "
smstart_za smstart_za
...@@ -255,24 +288,6 @@ _start: ...@@ -255,24 +288,6 @@ _start:
mov x0, x20 mov x0, x20
bl putdecn bl putdecn
mov x23, #0 // Irritation signal count
mov w0, #SIGINT
adr x1, terminate_handler
mov w2, #SA_SIGINFO
bl setsignal
mov w0, #SIGTERM
adr x1, terminate_handler
mov w2, #SA_SIGINFO
bl setsignal
mov w0, #SIGUSR1
adr x1, irritator_handler
mov w2, #SA_SIGINFO
orr w2, w2, #SA_NODEFER
bl setsignal
mov x22, #0 // generation number, increments per iteration mov x22, #0 // generation number, increments per iteration
.Ltest_loop: .Ltest_loop:
rdsvl 0, 8 rdsvl 0, 8
...@@ -287,12 +302,7 @@ _start: ...@@ -287,12 +302,7 @@ _start:
subs x21, x21, #1 subs x21, x21, #1
b.ne 0b b.ne 0b
and x8, x22, #127 // Every 128 interations... mov x8, #__NR_sched_yield // encourage preemption
cbz x8, 0f
mov x8, #__NR_getpid // (otherwise minimal syscall)
b 1f
0:
mov x8, #__NR_sched_yield // ...encourage preemption
1: 1:
svc #0 svc #0
......
...@@ -11,11 +11,8 @@ LDFLAGS += -pthread ...@@ -11,11 +11,8 @@ LDFLAGS += -pthread
SRCS := $(filter-out mte_common_util.c,$(wildcard *.c)) SRCS := $(filter-out mte_common_util.c,$(wildcard *.c))
PROGS := $(patsubst %.c,%,$(SRCS)) PROGS := $(patsubst %.c,%,$(SRCS))
#Add mte compiler option
CFLAGS += -march=armv8.5-a+memtag
#check if the compiler works well #check if the compiler works well
mte_cc_support := $(shell if ($(CC) $(CFLAGS) -E -x c /dev/null -o /dev/null 2>&1) then echo "1"; fi) mte_cc_support := $(shell if ($(CC) $(CFLAGS) -march=armv8.5-a+memtag -E -x c /dev/null -o /dev/null 2>&1) then echo "1"; fi)
ifeq ($(mte_cc_support),1) ifeq ($(mte_cc_support),1)
# Generated binaries to be installed by top KSFT script # Generated binaries to be installed by top KSFT script
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
#include "mte_def.h" #include "mte_def.h"
.arch armv8.5-a+memtag
#define ENTRY(name) \ #define ENTRY(name) \
.globl name ;\ .globl name ;\
.p2align 2;\ .p2align 2;\
......
...@@ -165,15 +165,64 @@ static bool handle_signal_ok(struct tdescr *td, ...@@ -165,15 +165,64 @@ static bool handle_signal_ok(struct tdescr *td,
} }
static bool handle_signal_copyctx(struct tdescr *td, static bool handle_signal_copyctx(struct tdescr *td,
siginfo_t *si, void *uc) siginfo_t *si, void *uc_in)
{ {
ucontext_t *uc = uc_in;
struct _aarch64_ctx *head;
struct extra_context *extra, *copied_extra;
size_t offset = 0;
size_t to_copy;
ASSERT_GOOD_CONTEXT(uc);
/* Mangling PC to avoid loops on original BRK instr */ /* Mangling PC to avoid loops on original BRK instr */
((ucontext_t *)uc)->uc_mcontext.pc += 4; uc->uc_mcontext.pc += 4;
memcpy(td->live_uc, uc, td->live_sz);
ASSERT_GOOD_CONTEXT(td->live_uc); /*
* Check for an preserve any extra data too with fixups.
*/
head = (struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
head = get_header(head, EXTRA_MAGIC, td->live_sz, &offset);
if (head) {
extra = (struct extra_context *)head;
/*
* The extra buffer must be immediately after the
* extra_context and a 16 byte terminator. Include it
* in the copy, this was previously validated in
* ASSERT_GOOD_CONTEXT().
*/
to_copy = offset + sizeof(struct extra_context) + 16 +
extra->size;
copied_extra = (struct extra_context *)&(td->live_uc->uc_mcontext.__reserved[offset]);
} else {
copied_extra = NULL;
to_copy = sizeof(ucontext_t);
}
if (to_copy > td->live_sz) {
fprintf(stderr,
"Not enough space to grab context, %lu/%lu bytes\n",
td->live_sz, to_copy);
return false;
}
memcpy(td->live_uc, uc, to_copy);
/*
* If there was any EXTRA_CONTEXT fix up the size to be the
* struct extra_context and the following terminator record,
* this means that the rest of the code does not need to have
* special handling for the record and we don't need to fix up
* datap for the new location.
*/
if (copied_extra)
copied_extra->head.size = sizeof(*copied_extra) + 16;
td->live_uc_valid = 1; td->live_uc_valid = 1;
fprintf(stderr, fprintf(stderr,
"GOOD CONTEXT grabbed from sig_copyctx handler\n"); "%lu byte GOOD CONTEXT grabbed from sig_copyctx handler\n",
to_copy);
return true; return true;
} }
......
...@@ -56,7 +56,8 @@ static inline bool feats_ok(struct tdescr *td) ...@@ -56,7 +56,8 @@ static inline bool feats_ok(struct tdescr *td)
* at sizeof(ucontext_t). * at sizeof(ucontext_t).
*/ */
static __always_inline bool get_current_context(struct tdescr *td, static __always_inline bool get_current_context(struct tdescr *td,
ucontext_t *dest_uc) ucontext_t *dest_uc,
size_t dest_sz)
{ {
static volatile bool seen_already; static volatile bool seen_already;
...@@ -64,7 +65,7 @@ static __always_inline bool get_current_context(struct tdescr *td, ...@@ -64,7 +65,7 @@ static __always_inline bool get_current_context(struct tdescr *td,
/* it's a genuine invocation..reinit */ /* it's a genuine invocation..reinit */
seen_already = 0; seen_already = 0;
td->live_uc_valid = 0; td->live_uc_valid = 0;
td->live_sz = sizeof(*dest_uc); td->live_sz = dest_sz;
memset(dest_uc, 0x00, td->live_sz); memset(dest_uc, 0x00, td->live_sz);
td->live_uc = dest_uc; td->live_uc = dest_uc;
/* /*
......
...@@ -21,7 +21,7 @@ static int fake_sigreturn_bad_magic_run(struct tdescr *td, ...@@ -21,7 +21,7 @@ static int fake_sigreturn_bad_magic_run(struct tdescr *td,
struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head; struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
/* just to fill the ucontext_t with something real */ /* just to fill the ucontext_t with something real */
if (!get_current_context(td, &sf.uc)) if (!get_current_context(td, &sf.uc, sizeof(sf.uc)))
return 1; return 1;
/* need at least 2*HDR_SZ space: KSFT_BAD_MAGIC + terminator. */ /* need at least 2*HDR_SZ space: KSFT_BAD_MAGIC + terminator. */
......
...@@ -24,7 +24,7 @@ static int fake_sigreturn_bad_size_run(struct tdescr *td, ...@@ -24,7 +24,7 @@ static int fake_sigreturn_bad_size_run(struct tdescr *td,
struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head; struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
/* just to fill the ucontext_t with something real */ /* just to fill the ucontext_t with something real */
if (!get_current_context(td, &sf.uc)) if (!get_current_context(td, &sf.uc, sizeof(sf.uc)))
return 1; return 1;
resv_sz = GET_SF_RESV_SIZE(sf); resv_sz = GET_SF_RESV_SIZE(sf);
......
...@@ -21,7 +21,7 @@ static int fake_sigreturn_bad_size_for_magic0_run(struct tdescr *td, ...@@ -21,7 +21,7 @@ static int fake_sigreturn_bad_size_for_magic0_run(struct tdescr *td,
struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head; struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
/* just to fill the ucontext_t with something real */ /* just to fill the ucontext_t with something real */
if (!get_current_context(td, &sf.uc)) if (!get_current_context(td, &sf.uc, sizeof(sf.uc)))
return 1; return 1;
/* at least HDR_SZ for the badly sized terminator. */ /* at least HDR_SZ for the badly sized terminator. */
......
...@@ -21,7 +21,7 @@ static int fake_sigreturn_duplicated_fpsimd_run(struct tdescr *td, ...@@ -21,7 +21,7 @@ static int fake_sigreturn_duplicated_fpsimd_run(struct tdescr *td,
struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head; struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
/* just to fill the ucontext_t with something real */ /* just to fill the ucontext_t with something real */
if (!get_current_context(td, &sf.uc)) if (!get_current_context(td, &sf.uc, sizeof(sf.uc)))
return 1; return 1;
head = get_starting_head(shead, sizeof(struct fpsimd_context) + HDR_SZ, head = get_starting_head(shead, sizeof(struct fpsimd_context) + HDR_SZ,
......
...@@ -19,7 +19,7 @@ static int fake_sigreturn_misaligned_run(struct tdescr *td, ...@@ -19,7 +19,7 @@ static int fake_sigreturn_misaligned_run(struct tdescr *td,
siginfo_t *si, ucontext_t *uc) siginfo_t *si, ucontext_t *uc)
{ {
/* just to fill the ucontext_t with something real */ /* just to fill the ucontext_t with something real */
if (!get_current_context(td, &sf.uc)) if (!get_current_context(td, &sf.uc, sizeof(sf.uc)))
return 1; return 1;
/* Forcing sigframe on misaligned SP (16 + 3) */ /* Forcing sigframe on misaligned SP (16 + 3) */
......
...@@ -23,7 +23,7 @@ static int fake_sigreturn_missing_fpsimd_run(struct tdescr *td, ...@@ -23,7 +23,7 @@ static int fake_sigreturn_missing_fpsimd_run(struct tdescr *td,
struct _aarch64_ctx *head = GET_SF_RESV_HEAD(sf); struct _aarch64_ctx *head = GET_SF_RESV_HEAD(sf);
/* just to fill the ucontext_t with something real */ /* just to fill the ucontext_t with something real */
if (!get_current_context(td, &sf.uc)) if (!get_current_context(td, &sf.uc, sizeof(sf.uc)))
return 1; return 1;
resv_sz = GET_SF_RESV_SIZE(sf); resv_sz = GET_SF_RESV_SIZE(sf);
......
...@@ -54,7 +54,7 @@ static int fake_sigreturn_ssve_change_vl(struct tdescr *td, ...@@ -54,7 +54,7 @@ static int fake_sigreturn_ssve_change_vl(struct tdescr *td,
struct sve_context *sve; struct sve_context *sve;
/* Get a signal context with a SME ZA frame in it */ /* Get a signal context with a SME ZA frame in it */
if (!get_current_context(td, &sf.uc)) if (!get_current_context(td, &sf.uc, sizeof(sf.uc)))
return 1; return 1;
resv_sz = GET_SF_RESV_SIZE(sf); resv_sz = GET_SF_RESV_SIZE(sf);
......
...@@ -56,7 +56,7 @@ static int fake_sigreturn_sve_change_vl(struct tdescr *td, ...@@ -56,7 +56,7 @@ static int fake_sigreturn_sve_change_vl(struct tdescr *td,
struct sve_context *sve; struct sve_context *sve;
/* Get a signal context with a SVE frame in it */ /* Get a signal context with a SVE frame in it */
if (!get_current_context(td, &sf.uc)) if (!get_current_context(td, &sf.uc, sizeof(sf.uc)))
return 1; return 1;
resv_sz = GET_SF_RESV_SIZE(sf); resv_sz = GET_SF_RESV_SIZE(sf);
......
...@@ -34,7 +34,7 @@ static int sme_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc) ...@@ -34,7 +34,7 @@ static int sme_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc)
struct za_context *za; struct za_context *za;
/* Get a signal context which should have a ZA frame in it */ /* Get a signal context which should have a ZA frame in it */
if (!get_current_context(td, &sf.uc)) if (!get_current_context(td, &sf.uc, sizeof(sf.uc)))
return 1; return 1;
resv_sz = GET_SF_RESV_SIZE(sf); resv_sz = GET_SF_RESV_SIZE(sf);
......
...@@ -13,7 +13,10 @@ ...@@ -13,7 +13,10 @@
#include "test_signals_utils.h" #include "test_signals_utils.h"
#include "testcases.h" #include "testcases.h"
struct fake_sigframe sf; static union {
ucontext_t uc;
char buf[1024 * 64];
} context;
static unsigned int vls[SVE_VQ_MAX]; static unsigned int vls[SVE_VQ_MAX];
unsigned int nvls = 0; unsigned int nvls = 0;
...@@ -55,8 +58,8 @@ static void setup_ssve_regs(void) ...@@ -55,8 +58,8 @@ static void setup_ssve_regs(void)
static int do_one_sme_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc, static int do_one_sme_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc,
unsigned int vl) unsigned int vl)
{ {
size_t resv_sz, offset; size_t offset;
struct _aarch64_ctx *head = GET_SF_RESV_HEAD(sf); struct _aarch64_ctx *head = GET_BUF_RESV_HEAD(context);
struct sve_context *ssve; struct sve_context *ssve;
int ret; int ret;
...@@ -73,11 +76,11 @@ static int do_one_sme_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc, ...@@ -73,11 +76,11 @@ static int do_one_sme_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc,
* in it. * in it.
*/ */
setup_ssve_regs(); setup_ssve_regs();
if (!get_current_context(td, &sf.uc)) if (!get_current_context(td, &context.uc, sizeof(context)))
return 1; return 1;
resv_sz = GET_SF_RESV_SIZE(sf); head = get_header(head, SVE_MAGIC, GET_BUF_RESV_SIZE(context),
head = get_header(head, SVE_MAGIC, resv_sz, &offset); &offset);
if (!head) { if (!head) {
fprintf(stderr, "No SVE context\n"); fprintf(stderr, "No SVE context\n");
return 1; return 1;
...@@ -101,16 +104,6 @@ static int sme_regs(struct tdescr *td, siginfo_t *si, ucontext_t *uc) ...@@ -101,16 +104,6 @@ static int sme_regs(struct tdescr *td, siginfo_t *si, ucontext_t *uc)
int i; int i;
for (i = 0; i < nvls; i++) { for (i = 0; i < nvls; i++) {
/*
* TODO: the signal test helpers can't currently cope
* with signal frames bigger than struct sigcontext,
* skip VLs that will trigger that.
*/
if (vls[i] > 64) {
printf("Skipping VL %u due to stack size\n", vls[i]);
continue;
}
if (do_one_sme_vl(td, si, uc, vls[i])) if (do_one_sme_vl(td, si, uc, vls[i]))
return 1; return 1;
} }
......
...@@ -13,7 +13,10 @@ ...@@ -13,7 +13,10 @@
#include "test_signals_utils.h" #include "test_signals_utils.h"
#include "testcases.h" #include "testcases.h"
struct fake_sigframe sf; static union {
ucontext_t uc;
char buf[1024 * 64];
} context;
static unsigned int vls[SVE_VQ_MAX]; static unsigned int vls[SVE_VQ_MAX];
unsigned int nvls = 0; unsigned int nvls = 0;
...@@ -55,8 +58,8 @@ static void setup_sve_regs(void) ...@@ -55,8 +58,8 @@ static void setup_sve_regs(void)
static int do_one_sve_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc, static int do_one_sve_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc,
unsigned int vl) unsigned int vl)
{ {
size_t resv_sz, offset; size_t offset;
struct _aarch64_ctx *head = GET_SF_RESV_HEAD(sf); struct _aarch64_ctx *head = GET_BUF_RESV_HEAD(context);
struct sve_context *sve; struct sve_context *sve;
fprintf(stderr, "Testing VL %d\n", vl); fprintf(stderr, "Testing VL %d\n", vl);
...@@ -71,11 +74,11 @@ static int do_one_sve_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc, ...@@ -71,11 +74,11 @@ static int do_one_sve_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc,
* in it. * in it.
*/ */
setup_sve_regs(); setup_sve_regs();
if (!get_current_context(td, &sf.uc)) if (!get_current_context(td, &context.uc, sizeof(context)))
return 1; return 1;
resv_sz = GET_SF_RESV_SIZE(sf); head = get_header(head, SVE_MAGIC, GET_BUF_RESV_SIZE(context),
head = get_header(head, SVE_MAGIC, resv_sz, &offset); &offset);
if (!head) { if (!head) {
fprintf(stderr, "No SVE context\n"); fprintf(stderr, "No SVE context\n");
return 1; return 1;
...@@ -99,14 +102,6 @@ static int sve_regs(struct tdescr *td, siginfo_t *si, ucontext_t *uc) ...@@ -99,14 +102,6 @@ static int sve_regs(struct tdescr *td, siginfo_t *si, ucontext_t *uc)
int i; int i;
for (i = 0; i < nvls; i++) { for (i = 0; i < nvls; i++) {
/*
* TODO: the signal test helpers can't currently cope
* with signal frames bigger than struct sigcontext,
* skip VLs that will trigger that.
*/
if (vls[i] > 64)
continue;
if (do_one_sve_vl(td, si, uc, vls[i])) if (do_one_sve_vl(td, si, uc, vls[i]))
return 1; return 1;
} }
......
...@@ -34,7 +34,7 @@ static int sve_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc) ...@@ -34,7 +34,7 @@ static int sve_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc)
struct sve_context *sve; struct sve_context *sve;
/* Get a signal context which should have a SVE frame in it */ /* Get a signal context which should have a SVE frame in it */
if (!get_current_context(td, &sf.uc)) if (!get_current_context(td, &sf.uc, sizeof(sf.uc)))
return 1; return 1;
resv_sz = GET_SF_RESV_SIZE(sf); resv_sz = GET_SF_RESV_SIZE(sf);
......
...@@ -25,7 +25,8 @@ struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic, ...@@ -25,7 +25,8 @@ struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
return found; return found;
} }
bool validate_extra_context(struct extra_context *extra, char **err) bool validate_extra_context(struct extra_context *extra, char **err,
void **extra_data, size_t *extra_size)
{ {
struct _aarch64_ctx *term; struct _aarch64_ctx *term;
...@@ -33,7 +34,7 @@ bool validate_extra_context(struct extra_context *extra, char **err) ...@@ -33,7 +34,7 @@ bool validate_extra_context(struct extra_context *extra, char **err)
return false; return false;
fprintf(stderr, "Validating EXTRA...\n"); fprintf(stderr, "Validating EXTRA...\n");
term = GET_RESV_NEXT_HEAD(extra); term = GET_RESV_NEXT_HEAD(&extra->head);
if (!term || term->magic || term->size) { if (!term || term->magic || term->size) {
*err = "Missing terminator after EXTRA context"; *err = "Missing terminator after EXTRA context";
return false; return false;
...@@ -42,11 +43,14 @@ bool validate_extra_context(struct extra_context *extra, char **err) ...@@ -42,11 +43,14 @@ bool validate_extra_context(struct extra_context *extra, char **err)
*err = "Extra DATAP misaligned"; *err = "Extra DATAP misaligned";
else if (extra->size & 0x0fUL) else if (extra->size & 0x0fUL)
*err = "Extra SIZE misaligned"; *err = "Extra SIZE misaligned";
else if (extra->datap != (uint64_t)term + sizeof(*term)) else if (extra->datap != (uint64_t)term + 0x10UL)
*err = "Extra DATAP misplaced (not contiguous)"; *err = "Extra DATAP misplaced (not contiguous)";
if (*err) if (*err)
return false; return false;
*extra_data = (void *)extra->datap;
*extra_size = extra->size;
return true; return true;
} }
...@@ -105,11 +109,14 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err) ...@@ -105,11 +109,14 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
bool terminated = false; bool terminated = false;
size_t offs = 0; size_t offs = 0;
int flags = 0; int flags = 0;
int new_flags;
struct extra_context *extra = NULL; struct extra_context *extra = NULL;
struct sve_context *sve = NULL; struct sve_context *sve = NULL;
struct za_context *za = NULL; struct za_context *za = NULL;
struct _aarch64_ctx *head = struct _aarch64_ctx *head =
(struct _aarch64_ctx *)uc->uc_mcontext.__reserved; (struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
void *extra_data = NULL;
size_t extra_sz = 0;
if (!err) if (!err)
return false; return false;
...@@ -120,12 +127,24 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err) ...@@ -120,12 +127,24 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
return false; return false;
} }
new_flags = 0;
switch (head->magic) { switch (head->magic) {
case 0: case 0:
if (head->size) if (head->size) {
*err = "Bad size for terminator"; *err = "Bad size for terminator";
else } else if (extra_data) {
/* End of main data, walking the extra data */
head = extra_data;
resv_sz = extra_sz;
offs = 0;
extra_data = NULL;
extra_sz = 0;
continue;
} else {
terminated = true; terminated = true;
}
break; break;
case FPSIMD_MAGIC: case FPSIMD_MAGIC:
if (flags & FPSIMD_CTX) if (flags & FPSIMD_CTX)
...@@ -133,7 +152,7 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err) ...@@ -133,7 +152,7 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
else if (head->size != else if (head->size !=
sizeof(struct fpsimd_context)) sizeof(struct fpsimd_context))
*err = "Bad size for fpsimd_context"; *err = "Bad size for fpsimd_context";
flags |= FPSIMD_CTX; new_flags |= FPSIMD_CTX;
break; break;
case ESR_MAGIC: case ESR_MAGIC:
if (head->size != sizeof(struct esr_context)) if (head->size != sizeof(struct esr_context))
...@@ -144,14 +163,14 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err) ...@@ -144,14 +163,14 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
*err = "Multiple SVE_MAGIC"; *err = "Multiple SVE_MAGIC";
/* Size is validated in validate_sve_context() */ /* Size is validated in validate_sve_context() */
sve = (struct sve_context *)head; sve = (struct sve_context *)head;
flags |= SVE_CTX; new_flags |= SVE_CTX;
break; break;
case ZA_MAGIC: case ZA_MAGIC:
if (flags & ZA_CTX) if (flags & ZA_CTX)
*err = "Multiple ZA_MAGIC"; *err = "Multiple ZA_MAGIC";
/* Size is validated in validate_za_context() */ /* Size is validated in validate_za_context() */
za = (struct za_context *)head; za = (struct za_context *)head;
flags |= ZA_CTX; new_flags |= ZA_CTX;
break; break;
case EXTRA_MAGIC: case EXTRA_MAGIC:
if (flags & EXTRA_CTX) if (flags & EXTRA_CTX)
...@@ -159,7 +178,7 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err) ...@@ -159,7 +178,7 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
else if (head->size != else if (head->size !=
sizeof(struct extra_context)) sizeof(struct extra_context))
*err = "Bad size for extra_context"; *err = "Bad size for extra_context";
flags |= EXTRA_CTX; new_flags |= EXTRA_CTX;
extra = (struct extra_context *)head; extra = (struct extra_context *)head;
break; break;
case KSFT_BAD_MAGIC: case KSFT_BAD_MAGIC:
...@@ -192,16 +211,19 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err) ...@@ -192,16 +211,19 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
return false; return false;
} }
if (flags & EXTRA_CTX) if (new_flags & EXTRA_CTX)
if (!validate_extra_context(extra, err)) if (!validate_extra_context(extra, err,
&extra_data, &extra_sz))
return false; return false;
if (flags & SVE_CTX) if (new_flags & SVE_CTX)
if (!validate_sve_context(sve, err)) if (!validate_sve_context(sve, err))
return false; return false;
if (flags & ZA_CTX) if (new_flags & ZA_CTX)
if (!validate_za_context(za, err)) if (!validate_za_context(za, err))
return false; return false;
flags |= new_flags;
head = GET_RESV_NEXT_HEAD(head); head = GET_RESV_NEXT_HEAD(head);
} }
......
...@@ -30,6 +30,13 @@ ...@@ -30,6 +30,13 @@
#define GET_SF_RESV_SIZE(sf) \ #define GET_SF_RESV_SIZE(sf) \
sizeof((sf).uc.uc_mcontext.__reserved) sizeof((sf).uc.uc_mcontext.__reserved)
#define GET_BUF_RESV_HEAD(buf) \
(struct _aarch64_ctx *)(&(buf).uc.uc_mcontext.__reserved)
#define GET_BUF_RESV_SIZE(buf) \
(sizeof(buf) - sizeof(buf.uc) + \
sizeof((buf).uc.uc_mcontext.__reserved))
#define GET_UCP_RESV_SIZE(ucp) \ #define GET_UCP_RESV_SIZE(ucp) \
sizeof((ucp)->uc_mcontext.__reserved) sizeof((ucp)->uc_mcontext.__reserved)
...@@ -79,8 +86,6 @@ struct fake_sigframe { ...@@ -79,8 +86,6 @@ struct fake_sigframe {
bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err); bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err);
bool validate_extra_context(struct extra_context *extra, char **err);
struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic, struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
size_t resv_sz, size_t *offset); size_t resv_sz, size_t *offset);
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 ARM Limited
*
* Verify that the ZA register context in signal frames is set up as
* expected.
*/
#include <signal.h>
#include <ucontext.h>
#include <sys/prctl.h>
#include "test_signals_utils.h"
#include "testcases.h"
static union {
ucontext_t uc;
char buf[1024 * 128];
} context;
static unsigned int vls[SVE_VQ_MAX];
unsigned int nvls = 0;
static bool sme_get_vls(struct tdescr *td)
{
int vq, vl;
/*
* Enumerate up to SME_VQ_MAX vector lengths
*/
for (vq = SVE_VQ_MAX; vq > 0; --vq) {
vl = prctl(PR_SME_SET_VL, vq * 16);
if (vl == -1)
return false;
vl &= PR_SME_VL_LEN_MASK;
/* Skip missing VLs */
vq = sve_vq_from_vl(vl);
vls[nvls++] = vl;
}
/* We need at least one VL */
if (nvls < 1) {
fprintf(stderr, "Only %d VL supported\n", nvls);
return false;
}
return true;
}
static int do_one_sme_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc,
unsigned int vl)
{
size_t offset;
struct _aarch64_ctx *head = GET_BUF_RESV_HEAD(context);
struct za_context *za;
fprintf(stderr, "Testing VL %d\n", vl);
if (prctl(PR_SME_SET_VL, vl) != vl) {
fprintf(stderr, "Failed to set VL\n");
return 1;
}
/*
* Get a signal context which should have a SVE frame and registers
* in it.
*/
if (!get_current_context(td, &context.uc, sizeof(context)))
return 1;
head = get_header(head, ZA_MAGIC, GET_BUF_RESV_SIZE(context), &offset);
if (!head) {
fprintf(stderr, "No ZA context\n");
return 1;
}
za = (struct za_context *)head;
if (za->vl != vl) {
fprintf(stderr, "Got VL %d, expected %d\n", za->vl, vl);
return 1;
}
if (head->size != ZA_SIG_REGS_OFFSET) {
fprintf(stderr, "Context size %u, expected %lu\n",
head->size, ZA_SIG_REGS_OFFSET);
return 1;
}
/* The actual size validation is done in get_current_context() */
fprintf(stderr, "Got expected size %u and VL %d\n",
head->size, za->vl);
return 0;
}
static int sme_regs(struct tdescr *td, siginfo_t *si, ucontext_t *uc)
{
int i;
for (i = 0; i < nvls; i++) {
if (do_one_sme_vl(td, si, uc, vls[i]))
return 1;
}
td->pass = 1;
return 0;
}
struct tdescr tde = {
.name = "ZA registers - ZA disabled",
.descr = "Check ZA context with ZA disabled",
.feats_required = FEAT_SME,
.timeout = 3,
.init = sme_get_vls,
.run = sme_regs,
};
...@@ -13,7 +13,10 @@ ...@@ -13,7 +13,10 @@
#include "test_signals_utils.h" #include "test_signals_utils.h"
#include "testcases.h" #include "testcases.h"
struct fake_sigframe sf; static union {
ucontext_t uc;
char buf[1024 * 128];
} context;
static unsigned int vls[SVE_VQ_MAX]; static unsigned int vls[SVE_VQ_MAX];
unsigned int nvls = 0; unsigned int nvls = 0;
...@@ -22,10 +25,10 @@ static bool sme_get_vls(struct tdescr *td) ...@@ -22,10 +25,10 @@ static bool sme_get_vls(struct tdescr *td)
int vq, vl; int vq, vl;
/* /*
* Enumerate up to SVE_VQ_MAX vector lengths * Enumerate up to SME_VQ_MAX vector lengths
*/ */
for (vq = SVE_VQ_MAX; vq > 0; --vq) { for (vq = SVE_VQ_MAX; vq > 0; --vq) {
vl = prctl(PR_SVE_SET_VL, vq * 16); vl = prctl(PR_SME_SET_VL, vq * 16);
if (vl == -1) if (vl == -1)
return false; return false;
...@@ -52,11 +55,13 @@ static void setup_za_regs(void) ...@@ -52,11 +55,13 @@ static void setup_za_regs(void)
asm volatile(".inst 0xd503457f" : : : ); asm volatile(".inst 0xd503457f" : : : );
} }
static char zeros[ZA_SIG_REGS_SIZE(SVE_VQ_MAX)];
static int do_one_sme_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc, static int do_one_sme_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc,
unsigned int vl) unsigned int vl)
{ {
size_t resv_sz, offset; size_t offset;
struct _aarch64_ctx *head = GET_SF_RESV_HEAD(sf); struct _aarch64_ctx *head = GET_BUF_RESV_HEAD(context);
struct za_context *za; struct za_context *za;
fprintf(stderr, "Testing VL %d\n", vl); fprintf(stderr, "Testing VL %d\n", vl);
...@@ -71,11 +76,10 @@ static int do_one_sme_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc, ...@@ -71,11 +76,10 @@ static int do_one_sme_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc,
* in it. * in it.
*/ */
setup_za_regs(); setup_za_regs();
if (!get_current_context(td, &sf.uc)) if (!get_current_context(td, &context.uc, sizeof(context)))
return 1; return 1;
resv_sz = GET_SF_RESV_SIZE(sf); head = get_header(head, ZA_MAGIC, GET_BUF_RESV_SIZE(context), &offset);
head = get_header(head, ZA_MAGIC, resv_sz, &offset);
if (!head) { if (!head) {
fprintf(stderr, "No ZA context\n"); fprintf(stderr, "No ZA context\n");
return 1; return 1;
...@@ -87,10 +91,22 @@ static int do_one_sme_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc, ...@@ -87,10 +91,22 @@ static int do_one_sme_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc,
return 1; return 1;
} }
/* The actual size validation is done in get_current_context() */ if (head->size != ZA_SIG_CONTEXT_SIZE(sve_vq_from_vl(vl))) {
fprintf(stderr, "ZA context size %u, expected %lu\n",
head->size, ZA_SIG_CONTEXT_SIZE(sve_vq_from_vl(vl)));
return 1;
}
fprintf(stderr, "Got expected size %u and VL %d\n", fprintf(stderr, "Got expected size %u and VL %d\n",
head->size, za->vl); head->size, za->vl);
/* We didn't load any data into ZA so it should be all zeros */
if (memcmp(zeros, (char *)za + ZA_SIG_REGS_OFFSET,
ZA_SIG_REGS_SIZE(sve_vq_from_vl(za->vl))) != 0) {
fprintf(stderr, "ZA data invalid\n");
return 1;
}
return 0; return 0;
} }
...@@ -99,16 +115,6 @@ static int sme_regs(struct tdescr *td, siginfo_t *si, ucontext_t *uc) ...@@ -99,16 +115,6 @@ static int sme_regs(struct tdescr *td, siginfo_t *si, ucontext_t *uc)
int i; int i;
for (i = 0; i < nvls; i++) { for (i = 0; i < nvls; i++) {
/*
* TODO: the signal test helpers can't currently cope
* with signal frames bigger than struct sigcontext,
* skip VLs that will trigger that.
*/
if (vls[i] > 32) {
printf("Skipping VL %u due to stack size\n", vls[i]);
continue;
}
if (do_one_sme_vl(td, si, uc, vls[i])) if (do_one_sme_vl(td, si, uc, vls[i]))
return 1; return 1;
} }
......
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