Entering a signal handler, the kernel saves xstate in signal frame. The
dynamic user state is better to be saved only when used. fpu->state_mask
can help to exclude unused states.

Returning from a signal handler, XRSTOR re-initializes the excluded state
components.

Add a test case to verify in the signal handler that the signal frame
excludes AMX data when the signaled thread has initialized AMX state.

Signed-off-by: Chang S. Bae <[email protected]>
Reviewed-by: Len Brown <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
---
Changes from v3:
* Removed 'no functional changes' in the changelog. (Borislav Petkov)

Changes from v1:
* Made it revertable (moved close to the end of the series).
* Included the test case.
---
 arch/x86/include/asm/fpu/internal.h |  2 +-
 tools/testing/selftests/x86/amx.c   | 66 +++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/fpu/internal.h 
b/arch/x86/include/asm/fpu/internal.h
index c467312d38d8..090eb5bb277b 100644
--- a/arch/x86/include/asm/fpu/internal.h
+++ b/arch/x86/include/asm/fpu/internal.h
@@ -354,7 +354,7 @@ static inline void copy_kernel_to_xregs(struct xregs_state 
*xstate, u64 mask)
  */
 static inline int copy_xregs_to_user(struct xregs_state __user *buf)
 {
-       u64 mask = xfeatures_mask_user();
+       u64 mask = current->thread.fpu.state_mask;
        u32 lmask = mask;
        u32 hmask = mask >> 32;
        int err;
diff --git a/tools/testing/selftests/x86/amx.c 
b/tools/testing/selftests/x86/amx.c
index f4ecdfd27ae9..a7386b886532 100644
--- a/tools/testing/selftests/x86/amx.c
+++ b/tools/testing/selftests/x86/amx.c
@@ -650,6 +650,71 @@ static void test_ptrace(void)
        test_tile_state_write(ptracee_loads_tiles);
 }
 
+/* Signal handling test */
+
+static int sigtrapped;
+struct tile_data sig_tiles, sighdl_tiles;
+
+static void handle_sigtrap(int sig, siginfo_t *info, void *ctx_void)
+{
+       ucontext_t *uctxt = (ucontext_t *)ctx_void;
+       struct xsave_data xdata;
+       struct tile_config cfg;
+       struct tile_data tiles;
+       u64 header;
+
+       header = __get_xsave_xstate_bv((void *)uctxt->uc_mcontext.fpregs);
+
+       if (header & (1 << XFEATURE_XTILE_DATA))
+               printf("[FAIL]\ttile data was written in sigframe\n");
+       else
+               printf("[OK]\ttile data was skipped in sigframe\n");
+
+       set_tilecfg(&cfg);
+       load_tilecfg(&cfg);
+       init_xdata(&xdata);
+
+       make_tiles(&tiles);
+       copy_tiles_to_xdata(&xdata, &tiles);
+       restore_xdata(&xdata);
+
+       save_xdata(&xdata);
+       if (compare_xdata_tiles(&xdata, &tiles))
+               err(1, "tile load file");
+
+       printf("\tsignal handler: load tile data\n");
+
+       sigtrapped = sig;
+}
+
+static void test_signal_handling(void)
+{
+       struct xsave_data xdata = { 0 };
+       struct tile_data tiles = { 0 };
+
+       sethandler(SIGTRAP, handle_sigtrap, 0);
+       sigtrapped = 0;
+
+       printf("[RUN]\tCheck tile state management in handling signal\n");
+
+       printf("\tbefore signal: initial tile data state\n");
+
+       raise(SIGTRAP);
+
+       if (sigtrapped == 0)
+               err(1, "sigtrap");
+
+       save_xdata(&xdata);
+       if (compare_xdata_tiles(&xdata, &tiles)) {
+               printf("[FAIL]\ttile data was not loaded at sigreturn\n");
+               nerrs++;
+       } else {
+               printf("[OK]\ttile data was re-initialized at sigreturn\n");
+       }
+
+       clearhandler(SIGTRAP);
+}
+
 int main(void)
 {
        /* Check hardware availability at first */
@@ -672,6 +737,7 @@ int main(void)
        test_fork();
        test_context_switch();
        test_ptrace();
+       test_signal_handling();
 
        return nerrs ? 1 : 0;
 }
-- 
2.17.1

Reply via email to