Skip to content

Commit d6da04b

Browse files
brooniewilldeacon
authored andcommitted
kselftest/arm64: Exit streaming mode after collecting signal context
When we collect a signal context with one of the SME modes enabled we will have enabled that mode behind the compiler and libc's back so they may issue some instructions not valid in streaming mode, causing spurious failures. For the code prior to issuing the BRK to trigger signal handling we need to stay in streaming mode if we were already there since that's a part of the signal context the caller is trying to collect. Unfortunately this code includes a memset() which is likely to be heavily optimised and is likely to use FP instructions incompatible with streaming mode. We can avoid this happening by open coding the memset(), inserting a volatile assembly statement to avoid the compiler recognising what's being done and doing something in optimisation. This code is not performance critical so the inefficiency should not be an issue. After collecting the context we can simply exit streaming mode, avoiding these issues. Use a full SMSTOP for safety to prevent any issues appearing with ZA. Reported-by: Will Deacon <[email protected]> Signed-off-by: Mark Brown <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent d189051 commit d6da04b

File tree

1 file changed

+24
-1
lines changed

1 file changed

+24
-1
lines changed

tools/testing/selftests/arm64/signal/test_signals_utils.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,25 @@ static __always_inline bool get_current_context(struct tdescr *td,
6060
size_t dest_sz)
6161
{
6262
static volatile bool seen_already;
63+
int i;
64+
char *uc = (char *)dest_uc;
6365

6466
assert(td && dest_uc);
6567
/* it's a genuine invocation..reinit */
6668
seen_already = 0;
6769
td->live_uc_valid = 0;
6870
td->live_sz = dest_sz;
69-
memset(dest_uc, 0x00, td->live_sz);
71+
72+
/*
73+
* This is a memset() but we don't want the compiler to
74+
* optimise it into either instructions or a library call
75+
* which might be incompatible with streaming mode.
76+
*/
77+
for (i = 0; i < td->live_sz; i++) {
78+
uc[i] = 0;
79+
__asm__ ("" : "=r" (uc[i]) : "0" (uc[i]));
80+
}
81+
7082
td->live_uc = dest_uc;
7183
/*
7284
* Grab ucontext_t triggering a SIGTRAP.
@@ -103,6 +115,17 @@ static __always_inline bool get_current_context(struct tdescr *td,
103115
:
104116
: "memory");
105117

118+
/*
119+
* If we were grabbing a streaming mode context then we may
120+
* have entered streaming mode behind the system's back and
121+
* libc or compiler generated code might decide to do
122+
* something invalid in streaming mode, or potentially even
123+
* the state of ZA. Issue a SMSTOP to exit both now we have
124+
* grabbed the state.
125+
*/
126+
if (td->feats_supported & FEAT_SME)
127+
asm volatile("msr S0_3_C4_C6_3, xzr");
128+
106129
/*
107130
* If we get here with seen_already==1 it implies the td->live_uc
108131
* context has been used to get back here....this probably means

0 commit comments

Comments
 (0)