All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] Hexagon: fix signal context save & restore bug
@ 2022-12-29  9:20 Mukilan Thiyagarajan
  2022-12-29  9:20 ` [PATCH v2 1/2] linux-user/hexagon: fix signal context save & restore Mukilan Thiyagarajan
  2022-12-29  9:20 ` [PATCH v2 2/2] target/hexagon: rename aliased register HEX_REG_P3_0 Mukilan Thiyagarajan
  0 siblings, 2 replies; 3+ messages in thread
From: Mukilan Thiyagarajan @ 2022-12-29  9:20 UTC (permalink / raw)
  To: qemu-devel, tsimpson, laurent
  Cc: bcain, richard.henderson, alex.bennee, Mukilan Thiyagarajan

This patchset is to fix the issue discovered in this thread
when hexagon toolchain was upgraded to a newer version.

https://lists.gnu.org/archive/html/qemu-devel/2021-11/msg01102.html

Investigation revealed that the bug was not in the
toolchain as suspected in the above thread, but in the
hexagon specific logic in linux-user for saving & restoring
thread context during signal delivery.

The first patch contains the fix for the issue along with a
test case and the second patch contains the change to rename
the enum for HEX_REG_P3_0 register, to provide some warning
to new code that it is an aliased version of the
individual predicate registers.

- Mukilan

*** Changes in v2 ***
Addressed the following review comments:
1) Fixed year in copyright line of signal_context.c
2) Moved variable decls to top of function in signal_context.c
3) Added PASS/FAIL output to signal_context.c test case

Mukilan Thiyagarajan (2):
  linux-user/hexagon: fix signal context save & restore
  target/hexagon: rename aliased register HEX_REG_P3_0

 linux-user/hexagon/signal.c        | 17 +++---
 target/hexagon/cpu.c               |  6 +--
 target/hexagon/genptr.c            | 12 ++---
 target/hexagon/hex_regs.h          |  2 +-
 tests/tcg/hexagon/Makefile.target  |  1 +
 tests/tcg/hexagon/signal_context.c | 84 ++++++++++++++++++++++++++++++
 6 files changed, 106 insertions(+), 16 deletions(-)
 create mode 100644 tests/tcg/hexagon/signal_context.c

-- 
2.17.1



^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH v2 1/2] linux-user/hexagon: fix signal context save & restore
  2022-12-29  9:20 [PATCH v2 0/2] Hexagon: fix signal context save & restore bug Mukilan Thiyagarajan
@ 2022-12-29  9:20 ` Mukilan Thiyagarajan
  2022-12-29  9:20 ` [PATCH v2 2/2] target/hexagon: rename aliased register HEX_REG_P3_0 Mukilan Thiyagarajan
  1 sibling, 0 replies; 3+ messages in thread
From: Mukilan Thiyagarajan @ 2022-12-29  9:20 UTC (permalink / raw)
  To: qemu-devel, tsimpson, laurent
  Cc: bcain, richard.henderson, alex.bennee, Mukilan Thiyagarajan

This patch fixes the issue originally reported in
this thread:

https://lists.gnu.org/archive/html/qemu-devel/2021-11/msg01102.html

The root cause of the issue is a bug in the hexagon specific
logic for saving & restoring context during signal delivery.
The CPU state has two different representations for the
predicate registers. The current logic saves & restores only
the aliased HEX_REG_P3_O register, which is part of env->gpr[]
field in the CPU state, but not the individual byte-level
predicate registers (pO, p1, p2, p3) backed by env->pred[].

Since all predicated instructions refer only to the
indiviual registers, switching to and back from a signal handler
can clobber these registers if the signal handler writes to them
causing the normal application code to behave unpredictably when
context is restored.

In the reported issue with the 'signals' test, since the updated
hexagon toolchain had built musl with -O2, the functions called
from non_trivial_free were inlined. This meant that the code
emitted reused predicate P0 computed in the entry translation
block of the function non_trivial_free in one of the child TB
as part of an assertion. Since P0 is clobbered by the signal
handler in the signals test, the assertion in non_trivial_free
fails incorectly. Since musl for hexagon implements the 'abort'
function by deliberately writing to memory via null pointer,
this causes the test to fail with segmentation fault.

This patch modifies the signal context save & restore logic
to include the individual p0, p1, p2, p3 and excludes the
32b p3_0 register since its value is derived from the former
registers. It also adds a new test case that reliabily
reproduces the issue for all four predicate registers.

Buglink: https://github.com/quic/toolchain_for_hexagon/issues/6
Signed-off-by: Mukilan Thiyagarajan <quic_mthiyaga@quicinc.com>
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
---
 linux-user/hexagon/signal.c        | 17 +++---
 tests/tcg/hexagon/Makefile.target  |  1 +
 tests/tcg/hexagon/signal_context.c | 84 ++++++++++++++++++++++++++++++
 3 files changed, 96 insertions(+), 6 deletions(-)
 create mode 100644 tests/tcg/hexagon/signal_context.c

diff --git a/linux-user/hexagon/signal.c b/linux-user/hexagon/signal.c
index ad4e3822d5..60fa7e1bce 100644
--- a/linux-user/hexagon/signal.c
+++ b/linux-user/hexagon/signal.c
@@ -39,15 +39,12 @@ struct target_sigcontext {
     target_ulong m0;
     target_ulong m1;
     target_ulong usr;
-    target_ulong p3_0;
     target_ulong gp;
     target_ulong ugp;
     target_ulong pc;
     target_ulong cause;
     target_ulong badva;
-    target_ulong pad1;
-    target_ulong pad2;
-    target_ulong pad3;
+    target_ulong pred[NUM_PREGS];
 };
 
 struct target_ucontext {
@@ -118,10 +115,14 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPUHexagonState *env)
     __put_user(env->gpr[HEX_REG_M0], &sc->m0);
     __put_user(env->gpr[HEX_REG_M1], &sc->m1);
     __put_user(env->gpr[HEX_REG_USR], &sc->usr);
-    __put_user(env->gpr[HEX_REG_P3_0], &sc->p3_0);
     __put_user(env->gpr[HEX_REG_GP], &sc->gp);
     __put_user(env->gpr[HEX_REG_UGP], &sc->ugp);
     __put_user(env->gpr[HEX_REG_PC], &sc->pc);
+
+    int i;
+    for (i = 0; i < NUM_PREGS; i++) {
+        __put_user(env->pred[i], &(sc->pred[i]));
+    }
 }
 
 static void setup_ucontext(struct target_ucontext *uc,
@@ -230,10 +231,14 @@ static void restore_sigcontext(CPUHexagonState *env,
     __get_user(env->gpr[HEX_REG_M0], &sc->m0);
     __get_user(env->gpr[HEX_REG_M1], &sc->m1);
     __get_user(env->gpr[HEX_REG_USR], &sc->usr);
-    __get_user(env->gpr[HEX_REG_P3_0], &sc->p3_0);
     __get_user(env->gpr[HEX_REG_GP], &sc->gp);
     __get_user(env->gpr[HEX_REG_UGP], &sc->ugp);
     __get_user(env->gpr[HEX_REG_PC], &sc->pc);
+
+    int i;
+    for (i = 0; i < NUM_PREGS; i++) {
+        __get_user(env->pred[i], &(sc->pred[i]));
+    }
 }
 
 static void restore_ucontext(CPUHexagonState *env, struct target_ucontext *uc)
diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target
index 9ee1faa1e1..f1378d86a9 100644
--- a/tests/tcg/hexagon/Makefile.target
+++ b/tests/tcg/hexagon/Makefile.target
@@ -43,6 +43,7 @@ HEX_TESTS += load_align
 HEX_TESTS += atomics
 HEX_TESTS += fpstuff
 HEX_TESTS += overflow
+HEX_TESTS += signal_context
 
 HEX_TESTS += test_abs
 HEX_TESTS += test_bitcnt
diff --git a/tests/tcg/hexagon/signal_context.c b/tests/tcg/hexagon/signal_context.c
new file mode 100644
index 0000000000..7202fa64b6
--- /dev/null
+++ b/tests/tcg/hexagon/signal_context.c
@@ -0,0 +1,84 @@
+/*
+ *  Copyright(c) 2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <time.h>
+
+void sig_user(int sig, siginfo_t *info, void *puc)
+{
+    asm("r7 = #0\n\t"
+        "p0 = r7\n\t"
+        "p1 = r7\n\t"
+        "p2 = r7\n\t"
+        "p3 = r7\n\t"
+        : : : "r7", "p0", "p1", "p2", "p3");
+}
+
+int main()
+{
+    int err = 0;
+    unsigned int i = 100000;
+    struct sigaction act;
+    struct itimerspec it;
+    timer_t tid;
+    struct sigevent sev;
+
+    act.sa_sigaction = sig_user;
+    sigemptyset(&act.sa_mask);
+    act.sa_flags = SA_SIGINFO;
+    sigaction(SIGUSR1, &act, NULL);
+    sev.sigev_notify = SIGEV_SIGNAL;
+    sev.sigev_signo = SIGUSR1;
+    sev.sigev_value.sival_ptr = &tid;
+    timer_create(CLOCK_REALTIME, &sev, &tid);
+    it.it_interval.tv_sec = 0;
+    it.it_interval.tv_nsec = 100000;
+    it.it_value.tv_sec = 0;
+    it.it_value.tv_nsec = 100000;
+    timer_settime(tid, 0, &it, NULL);
+
+    asm("loop0(1f, %1)\n\t"
+        "1: r8 = #0xff\n\t"
+        "   p0 = r8\n\t"
+        "   p1 = r8\n\t"
+        "   p2 = r8\n\t"
+        "   p3 = r8\n\t"
+        "   jump 3f\n\t"
+        "2: memb(%0) = #1\n\t"
+        "   jump 4f\n\t"
+        "3:\n\t"
+        "   r8 = p0\n\t"
+        "   p0 = cmp.eq(r8, #0xff)\n\t"
+        "   if (!p0) jump 2b\n\t"
+        "   r8 = p1\n\t"
+        "   p0 = cmp.eq(r8, #0xff)\n\t"
+        "   if (!p0) jump 2b\n\t"
+        "   r8 = p2\n\t"
+        "   p0 = cmp.eq(r8, #0xff)\n\t"
+        "   if (!p0) jump 2b\n\t"
+        "   r8 = p3\n\t"
+        "   p0 = cmp.eq(r8, #0xff)\n\t"
+        "   if (!p0) jump 2b\n\t"
+        "4: {}: endloop0\n\t"
+        :
+        : "r"(&err), "r"(i)
+        : "memory", "r8", "p0", "p1", "p2", "p3");
+
+    puts(err ? "FAIL" : "PASS");
+    return err;
+}
-- 
2.17.1



^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v2 2/2] target/hexagon: rename aliased register HEX_REG_P3_0
  2022-12-29  9:20 [PATCH v2 0/2] Hexagon: fix signal context save & restore bug Mukilan Thiyagarajan
  2022-12-29  9:20 ` [PATCH v2 1/2] linux-user/hexagon: fix signal context save & restore Mukilan Thiyagarajan
@ 2022-12-29  9:20 ` Mukilan Thiyagarajan
  1 sibling, 0 replies; 3+ messages in thread
From: Mukilan Thiyagarajan @ 2022-12-29  9:20 UTC (permalink / raw)
  To: qemu-devel, tsimpson, laurent
  Cc: bcain, richard.henderson, alex.bennee, Mukilan Thiyagarajan

The patch renames the identifier of the 32bit register
HEX_REG_P3_0 to HEX_REG_P3_0_ALIASED.

This change is to intended to provide some warning that
HEX_REG_P3_0 is an aliased register which has multiple
representations in CPU state and therefore might require
special handling in some contexts. The hope is to prevent
accidental misuse of this register e.g the issue reported
for the signals tests failure [here][1].

[1]: https://lists.gnu.org/archive/html/qemu-devel/2021-11/msg01102.html

Signed-off-by: Mukilan Thiyagarajan <quic_mthiyaga@quicinc.com>
Reviewed-by: Taylor Simpson <tsimpson@quicinc.com>
---
 target/hexagon/cpu.c      |  6 +++---
 target/hexagon/genptr.c   | 12 ++++++------
 target/hexagon/hex_regs.h |  2 +-
 3 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 658ca4ff78..807037c586 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -86,7 +86,7 @@ static target_ulong adjust_stack_ptrs(CPUHexagonState *env, target_ulong addr)
     return addr;
 }
 
-/* HEX_REG_P3_0 (aka C4) is an alias for the predicate registers */
+/* HEX_REG_P3_0_ALIASED (aka C4) is an alias for the predicate registers */
 static target_ulong read_p3_0(CPUHexagonState *env)
 {
     int32_t control_reg = 0;
@@ -102,7 +102,7 @@ static void print_reg(FILE *f, CPUHexagonState *env, int regnum)
 {
     target_ulong value;
 
-    if (regnum == HEX_REG_P3_0) {
+    if (regnum == HEX_REG_P3_0_ALIASED) {
         value = read_p3_0(env);
     } else {
         value = regnum < 32 ? adjust_stack_ptrs(env, env->gpr[regnum])
@@ -198,7 +198,7 @@ static void hexagon_dump(CPUHexagonState *env, FILE *f, int flags)
     print_reg(f, env, HEX_REG_M0);
     print_reg(f, env, HEX_REG_M1);
     print_reg(f, env, HEX_REG_USR);
-    print_reg(f, env, HEX_REG_P3_0);
+    print_reg(f, env, HEX_REG_P3_0_ALIASED);
     print_reg(f, env, HEX_REG_GP);
     print_reg(f, env, HEX_REG_UGP);
     print_reg(f, env, HEX_REG_PC);
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 6cf2e0ed43..66a968c884 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -163,7 +163,7 @@ static inline void gen_read_p3_0(TCGv control_reg)
 
 /*
  * Certain control registers require special handling on read
- *     HEX_REG_P3_0          aliased to the predicate registers
+ *     HEX_REG_P3_0_ALIASED  aliased to the predicate registers
  *                           -> concat the 4 predicate registers together
  *     HEX_REG_PC            actual value stored in DisasContext
  *                           -> assign from ctx->base.pc_next
@@ -173,7 +173,7 @@ static inline void gen_read_p3_0(TCGv control_reg)
 static inline void gen_read_ctrl_reg(DisasContext *ctx, const int reg_num,
                                      TCGv dest)
 {
-    if (reg_num == HEX_REG_P3_0) {
+    if (reg_num == HEX_REG_P3_0_ALIASED) {
         gen_read_p3_0(dest);
     } else if (reg_num == HEX_REG_PC) {
         tcg_gen_movi_tl(dest, ctx->base.pc_next);
@@ -194,7 +194,7 @@ static inline void gen_read_ctrl_reg(DisasContext *ctx, const int reg_num,
 static inline void gen_read_ctrl_reg_pair(DisasContext *ctx, const int reg_num,
                                           TCGv_i64 dest)
 {
-    if (reg_num == HEX_REG_P3_0) {
+    if (reg_num == HEX_REG_P3_0_ALIASED) {
         TCGv p3_0 = tcg_temp_new();
         gen_read_p3_0(p3_0);
         tcg_gen_concat_i32_i64(dest, p3_0, hex_gpr[reg_num + 1]);
@@ -238,7 +238,7 @@ static void gen_write_p3_0(DisasContext *ctx, TCGv control_reg)
 
 /*
  * Certain control registers require special handling on write
- *     HEX_REG_P3_0          aliased to the predicate registers
+ *     HEX_REG_P3_0_ALIASED  aliased to the predicate registers
  *                           -> break the value across 4 predicate registers
  *     HEX_REG_QEMU_*_CNT    changes in current TB in DisasContext
  *                            -> clear the changes
@@ -246,7 +246,7 @@ static void gen_write_p3_0(DisasContext *ctx, TCGv control_reg)
 static inline void gen_write_ctrl_reg(DisasContext *ctx, int reg_num,
                                       TCGv val)
 {
-    if (reg_num == HEX_REG_P3_0) {
+    if (reg_num == HEX_REG_P3_0_ALIASED) {
         gen_write_p3_0(ctx, val);
     } else {
         gen_log_reg_write(reg_num, val);
@@ -266,7 +266,7 @@ static inline void gen_write_ctrl_reg(DisasContext *ctx, int reg_num,
 static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num,
                                            TCGv_i64 val)
 {
-    if (reg_num == HEX_REG_P3_0) {
+    if (reg_num == HEX_REG_P3_0_ALIASED) {
         TCGv val32 = tcg_temp_new();
         tcg_gen_extrl_i64_i32(val32, val);
         gen_write_p3_0(ctx, val32);
diff --git a/target/hexagon/hex_regs.h b/target/hexagon/hex_regs.h
index a63c2c0fd5..bddfc28021 100644
--- a/target/hexagon/hex_regs.h
+++ b/target/hexagon/hex_regs.h
@@ -58,7 +58,7 @@ enum {
     HEX_REG_LC0              = 33,
     HEX_REG_SA1              = 34,
     HEX_REG_LC1              = 35,
-    HEX_REG_P3_0             = 36,
+    HEX_REG_P3_0_ALIASED     = 36,
     HEX_REG_M0               = 38,
     HEX_REG_M1               = 39,
     HEX_REG_USR              = 40,
-- 
2.17.1



^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-12-29  9:24 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-29  9:20 [PATCH v2 0/2] Hexagon: fix signal context save & restore bug Mukilan Thiyagarajan
2022-12-29  9:20 ` [PATCH v2 1/2] linux-user/hexagon: fix signal context save & restore Mukilan Thiyagarajan
2022-12-29  9:20 ` [PATCH v2 2/2] target/hexagon: rename aliased register HEX_REG_P3_0 Mukilan Thiyagarajan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.