* Test the kernel's signal frame code.
*
* The kernel sets up two sets of ucontexts if the signal was to be
- * delivered while the thread was in a transaction.
+ * delivered while the thread was in a transaction (referred too as
+ * first and second contexts).
* Expected behaviour is that the checkpointed state is in the user
- * context passed to the signal handler. The speculated state can be
- * accessed with the uc_link pointer.
+ * context passed to the signal handler (first context). The speculated
+ * state can be accessed with the uc_link pointer (second context).
*
* The rationale for this is that if TM unaware code (which linked
* against TM libs) installs a signal handler it will not know of the
#define MAX_ATTEMPT 500000
-#define NV_FPU_REGS 18
+#define NV_FPU_REGS 18 /* Number of non-volatile FP registers */
+#define FPR14 14 /* First non-volatile FP register to check in f14-31 subset */
long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
-/* Be sure there are 2x as many as there are NV FPU regs (2x18) */
+/* Test only non-volatile registers, i.e. 18 fpr registers from f14 to f31 */
static double fps[] = {
+ /* First context will be set with these values, i.e. non-speculative */
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ /* Second context will be set with these values, i.e. speculative */
-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18
};
-static sig_atomic_t fail;
+static sig_atomic_t fail, broken;
static void signal_usr1(int signum, siginfo_t *info, void *uc)
{
ucontext_t *ucp = uc;
ucontext_t *tm_ucp = ucp->uc_link;
- for (i = 0; i < NV_FPU_REGS && !fail; i++) {
- fail = (ucp->uc_mcontext.fp_regs[i + 14] != fps[i]);
- fail |= (tm_ucp->uc_mcontext.fp_regs[i + 14] != fps[i + NV_FPU_REGS]);
- if (fail)
- printf("Failed on %d FP %g or %g\n", i, ucp->uc_mcontext.fp_regs[i + 14], tm_ucp->uc_mcontext.fp_regs[i + 14]);
+ for (i = 0; i < NV_FPU_REGS; i++) {
+ /* Check first context. Print all mismatches. */
+ fail = (ucp->uc_mcontext.fp_regs[FPR14 + i] != fps[i]);
+ if (fail) {
+ broken = 1;
+ printf("FPR%d (1st context) == %g instead of %g (expected)\n",
+ FPR14 + i, ucp->uc_mcontext.fp_regs[FPR14 + i], fps[i]);
+ }
+ }
+
+ for (i = 0; i < NV_FPU_REGS; i++) {
+ /* Check second context. Print all mismatches. */
+ fail = (tm_ucp->uc_mcontext.fp_regs[FPR14 + i] != fps[NV_FPU_REGS + i]);
+ if (fail) {
+ broken = 1;
+ printf("FPR%d (2nd context) == %g instead of %g (expected)\n",
+ FPR14 + i, tm_ucp->uc_mcontext.fp_regs[FPR14 + i], fps[NV_FPU_REGS + i]);
+ }
}
}
}
i = 0;
- while (i < MAX_ATTEMPT && !fail) {
+ while (i < MAX_ATTEMPT && !broken) {
+ /*
+ * tm_signal_self_context_load will set both first and second
+ * contexts accordingly to the values passed through non-NULL
+ * array pointers to it, in that case 'fps', and invoke the
+ * signal handler installed for SIGUSR1.
+ */
rc = tm_signal_self_context_load(pid, NULL, fps, NULL, NULL);
FAIL_IF(rc != pid);
i++;
}
- return fail;
+ return (broken);
}
int main(void)
* Test the kernel's signal frame code.
*
* The kernel sets up two sets of ucontexts if the signal was to be
- * delivered while the thread was in a transaction.
+ * delivered while the thread was in a transaction (referred too as
+ * first and second contexts).
* Expected behaviour is that the checkpointed state is in the user
- * context passed to the signal handler. The speculated state can be
- * accessed with the uc_link pointer.
+ * context passed to the signal handler (first context). The speculated
+ * state can be accessed with the uc_link pointer (second context).
*
* The rationale for this is that if TM unaware code (which linked
* against TM libs) installs a signal handler it will not know of the
#define MAX_ATTEMPT 500000
-#define NV_GPR_REGS 18
+#define NV_GPR_REGS 18 /* Number of non-volatile GPR registers */
+#define R14 14 /* First non-volatile register to check in r14-r31 subset */
long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
-static sig_atomic_t fail;
+static sig_atomic_t fail, broken;
-static long gps[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- -1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18};
+/* Test only non-volatile general purpose registers, i.e. r14-r31 */
+static long gprs[] = {
+ /* First context will be set with these values, i.e. non-speculative */
+ /* R14, R15, ... */
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ /* Second context will be set with these values, i.e. speculative */
+ /* R14, R15, ... */
+ -1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18
+};
static void signal_usr1(int signum, siginfo_t *info, void *uc)
{
ucontext_t *ucp = uc;
ucontext_t *tm_ucp = ucp->uc_link;
- for (i = 0; i < NV_GPR_REGS && !fail; i++) {
- fail = (ucp->uc_mcontext.gp_regs[i + 14] != gps[i]);
- fail |= (tm_ucp->uc_mcontext.gp_regs[i + 14] != gps[i + NV_GPR_REGS]);
- if (fail)
- printf("Failed on %d GPR %lu or %lu\n", i,
- ucp->uc_mcontext.gp_regs[i + 14], tm_ucp->uc_mcontext.gp_regs[i + 14]);
+ /* Check first context. Print all mismatches. */
+ for (i = 0; i < NV_GPR_REGS; i++) {
+ fail = (ucp->uc_mcontext.gp_regs[R14 + i] != gprs[i]);
+ if (fail) {
+ broken = 1;
+ printf("GPR%d (1st context) == %lu instead of %lu (expected)\n",
+ R14 + i, ucp->uc_mcontext.gp_regs[R14 + i], gprs[i]);
+ }
+ }
+
+ /* Check second context. Print all mismatches. */
+ for (i = 0; i < NV_GPR_REGS; i++) {
+ fail = (tm_ucp->uc_mcontext.gp_regs[R14 + i] != gprs[NV_GPR_REGS + i]);
+ if (fail) {
+ broken = 1;
+ printf("GPR%d (2nd context) == %lu instead of %lu (expected)\n",
+ R14 + i, tm_ucp->uc_mcontext.gp_regs[R14 + i], gprs[NV_GPR_REGS + i]);
+ }
}
}
}
i = 0;
- while (i < MAX_ATTEMPT && !fail) {
- rc = tm_signal_self_context_load(pid, gps, NULL, NULL, NULL);
+ while (i < MAX_ATTEMPT && !broken) {
+ /*
+ * tm_signal_self_context_load will set both first and second
+ * contexts accordingly to the values passed through non-NULL
+ * array pointers to it, in that case 'gprs', and invoke the
+ * signal handler installed for SIGUSR1.
+ */
+ rc = tm_signal_self_context_load(pid, gprs, NULL, NULL, NULL);
FAIL_IF(rc != pid);
i++;
}
- return fail;
+ return broken;
}
int main(void)
* Test the kernel's signal frame code.
*
* The kernel sets up two sets of ucontexts if the signal was to be
- * delivered while the thread was in a transaction.
+ * delivered while the thread was in a transaction (referred too as
+ * first and second contexts).
* Expected behaviour is that the checkpointed state is in the user
- * context passed to the signal handler. The speculated state can be
- * accessed with the uc_link pointer.
+ * context passed to the signal handler (first context). The speculated
+ * state can be accessed with the uc_link pointer (second context).
*
* The rationale for this is that if TM unaware code (which linked
* against TM libs) installs a signal handler it will not know of the
#define MAX_ATTEMPT 500000
-#define NV_VMX_REGS 12
+#define NV_VMX_REGS 12 /* Number of non-volatile VMX registers */
+#define VMX20 20 /* First non-volatile register to check in vr20-31 subset */
long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
-static sig_atomic_t fail;
+static sig_atomic_t fail, broken;
+/* Test only non-volatile registers, i.e. 12 vmx registers from vr20 to vr31 */
vector int vms[] = {
- {1, 2, 3, 4 },{5, 6, 7, 8 },{9, 10,11,12},
+ /* First context will be set with these values, i.e. non-speculative */
+ /* VMX20 , VMX21 , ... */
+ { 1, 2, 3, 4},{ 5, 6, 7, 8},{ 9,10,11,12},
{13,14,15,16},{17,18,19,20},{21,22,23,24},
{25,26,27,28},{29,30,31,32},{33,34,35,36},
{37,38,39,40},{41,42,43,44},{45,46,47,48},
- {-1, -2, -3, -4}, {-5, -6, -7, -8}, {-9, -10,-11,-12},
+ /* Second context will be set with these values, i.e. speculative */
+ /* VMX20 , VMX21 , ... */
+ { -1, -2, -3, -4},{ -5, -6, -7, -8},{ -9,-10,-11,-12},
{-13,-14,-15,-16},{-17,-18,-19,-20},{-21,-22,-23,-24},
{-25,-26,-27,-28},{-29,-30,-31,-32},{-33,-34,-35,-36},
{-37,-38,-39,-40},{-41,-42,-43,-44},{-45,-46,-47,-48}
static void signal_usr1(int signum, siginfo_t *info, void *uc)
{
- int i;
+ int i, j;
ucontext_t *ucp = uc;
ucontext_t *tm_ucp = ucp->uc_link;
- for (i = 0; i < NV_VMX_REGS && !fail; i++) {
- fail = memcmp(ucp->uc_mcontext.v_regs->vrregs[i + 20],
+ for (i = 0; i < NV_VMX_REGS; i++) {
+ /* Check first context. Print all mismatches. */
+ fail = memcmp(ucp->uc_mcontext.v_regs->vrregs[VMX20 + i],
&vms[i], sizeof(vector int));
- fail |= memcmp(tm_ucp->uc_mcontext.v_regs->vrregs[i + 20],
- &vms[i + NV_VMX_REGS], sizeof (vector int));
-
if (fail) {
- int j;
+ broken = 1;
+ printf("VMX%d (1st context) == 0x", VMX20 + i);
+ /* Print actual value in first context. */
+ for (j = 0; j < 4; j++)
+ printf("%08x", ucp->uc_mcontext.v_regs->vrregs[VMX20 + i][j]);
+ printf(" instead of 0x");
+ /* Print expected value. */
+ for (j = 0; j < 4; j++)
+ printf("%08x", vms[i][j]);
+ printf(" (expected)\n");
+ }
+ }
- fprintf(stderr, "Failed on %d vmx 0x", i);
+ for (i = 0; i < NV_VMX_REGS; i++) {
+ /* Check second context. Print all mismatches. */
+ fail = memcmp(tm_ucp->uc_mcontext.v_regs->vrregs[VMX20 + i],
+ &vms[NV_VMX_REGS + i], sizeof (vector int));
+ if (fail) {
+ broken = 1;
+ printf("VMX%d (2nd context) == 0x", NV_VMX_REGS + i);
+ /* Print actual value in second context. */
+ for (j = 0; j < 4; j++)
+ printf("%08x", tm_ucp->uc_mcontext.v_regs->vrregs[VMX20 + i][j]);
+ printf(" instead of 0x");
+ /* Print expected value. */
for (j = 0; j < 4; j++)
- fprintf(stderr, "%04x", ucp->uc_mcontext.v_regs->vrregs[i + 20][j]);
- fprintf(stderr, " vs 0x");
- for (j = 0 ; j < 4; j++)
- fprintf(stderr, "%04x", tm_ucp->uc_mcontext.v_regs->vrregs[i + 20][j]);
- fprintf(stderr, "\n");
+ printf("%08x", vms[NV_VMX_REGS + i][j]);
+ printf(" (expected)\n");
}
}
}
}
i = 0;
- while (i < MAX_ATTEMPT && !fail) {
+ while (i < MAX_ATTEMPT && !broken) {
+ /*
+ * tm_signal_self_context_load will set both first and second
+ * contexts accordingly to the values passed through non-NULL
+ * array pointers to it, in that case 'vms', and invoke the
+ * signal handler installed for SIGUSR1.
+ */
rc = tm_signal_self_context_load(pid, NULL, NULL, vms, NULL);
FAIL_IF(rc != pid);
i++;
}
- return fail;
+ return (broken);
}
int main(void)
* Test the kernel's signal frame code.
*
* The kernel sets up two sets of ucontexts if the signal was to be
- * delivered while the thread was in a transaction.
+ * delivered while the thread was in a transaction (referred too as
+ * first and second contexts).
* Expected behaviour is that the checkpointed state is in the user
- * context passed to the signal handler. The speculated state can be
- * accessed with the uc_link pointer.
+ * context passed to the signal handler (first context). The speculated
+ * state can be accessed with the uc_link pointer (second context).
*
* The rationale for this is that if TM unaware code (which linked
* against TM libs) installs a signal handler it will not know of the
#define MAX_ATTEMPT 500000
-#define NV_VSX_REGS 12
+#define NV_VSX_REGS 12 /* Number of VSX registers to check. */
+#define VSX20 20 /* First VSX register to check in vsr20-vsr31 subset */
+#define FPR20 20 /* FPR20 overlaps VSX20 most significant doubleword */
long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
-static sig_atomic_t fail;
+static sig_atomic_t fail, broken;
-vector int vss[] = {
- {1, 2, 3, 4 },{5, 6, 7, 8 },{9, 10,11,12},
+/* Test only 12 vsx registers from vsr20 to vsr31 */
+vector int vsxs[] = {
+ /* First context will be set with these values, i.e. non-speculative */
+ /* VSX20 , VSX21 , ... */
+ { 1, 2, 3, 4},{ 5, 6, 7, 8},{ 9,10,11,12},
{13,14,15,16},{17,18,19,20},{21,22,23,24},
{25,26,27,28},{29,30,31,32},{33,34,35,36},
{37,38,39,40},{41,42,43,44},{45,46,47,48},
+ /* Second context will be set with these values, i.e. speculative */
+ /* VSX20 , VSX21 , ... */
{-1, -2, -3, -4 },{-5, -6, -7, -8 },{-9, -10,-11,-12},
{-13,-14,-15,-16},{-17,-18,-19,-20},{-21,-22,-23,-24},
{-25,-26,-27,-28},{-29,-30,-31,-32},{-33,-34,-35,-36},
static void signal_usr1(int signum, siginfo_t *info, void *uc)
{
- int i;
- uint8_t vsc[sizeof(vector int)];
- uint8_t vst[sizeof(vector int)];
+ int i, j;
+ uint8_t vsx[sizeof(vector int)];
+ uint8_t vsx_tm[sizeof(vector int)];
ucontext_t *ucp = uc;
ucontext_t *tm_ucp = ucp->uc_link;
/*
- * The other half of the VSX regs will be after v_regs.
+ * FP registers and VMX registers overlap the VSX registers.
+ *
+ * FP registers (f0-31) overlap the most significant 64 bits of VSX
+ * registers vsr0-31, whilst VMX registers vr0-31, being 128-bit like
+ * the VSX registers, overlap fully the other half of VSX registers,
+ * i.e. vr0-31 overlaps fully vsr32-63.
+ *
+ * Due to compatibility and historical reasons (VMX/Altivec support
+ * appeared first on the architecture), VMX registers vr0-31 (so VSX
+ * half vsr32-63 too) are stored right after the v_regs pointer, in an
+ * area allocated for 'vmx_reverse' array (please see
+ * arch/powerpc/include/uapi/asm/sigcontext.h for details about the
+ * mcontext_t structure on Power).
+ *
+ * The other VSX half (vsr0-31) is hence stored below vr0-31/vsr32-63
+ * registers, but only the least significant 64 bits of vsr0-31. The
+ * most significant 64 bits of vsr0-31 (f0-31), as it overlaps the FP
+ * registers, is kept in fp_regs.
+ *
+ * v_regs is a 16 byte aligned pointer at the start of vmx_reserve
+ * (vmx_reserve may or may not be 16 aligned) where the v_regs structure
+ * exists, so v_regs points to where vr0-31 / vsr32-63 registers are
+ * fully stored. Since v_regs type is elf_vrregset_t, v_regs + 1
+ * skips all the slots used to store vr0-31 / vsr32-64 and points to
+ * part of one VSX half, i.e. v_regs + 1 points to the least significant
+ * 64 bits of vsr0-31. The other part of this half (the most significant
+ * part of vsr0-31) is stored in fp_regs.
*
- * In short, vmx_reserve array holds everything. v_regs is a 16
- * byte aligned pointer at the start of vmx_reserve (vmx_reserve
- * may or may not be 16 aligned) where the v_regs structure exists.
- * (half of) The VSX regsters are directly after v_regs so the
- * easiest way to find them below.
*/
+ /* Get pointer to least significant doubleword of vsr0-31 */
long *vsx_ptr = (long *)(ucp->uc_mcontext.v_regs + 1);
long *tm_vsx_ptr = (long *)(tm_ucp->uc_mcontext.v_regs + 1);
- for (i = 0; i < NV_VSX_REGS && !fail; i++) {
- memcpy(vsc, &ucp->uc_mcontext.fp_regs[i + 20], 8);
- memcpy(vsc + 8, &vsx_ptr[20 + i], 8);
- fail = memcmp(vsc, &vss[i], sizeof(vector int));
- memcpy(vst, &tm_ucp->uc_mcontext.fp_regs[i + 20], 8);
- memcpy(vst + 8, &tm_vsx_ptr[20 + i], 8);
- fail |= memcmp(vst, &vss[i + NV_VSX_REGS], sizeof(vector int));
- if (fail) {
- int j;
+ /* Check first context. Print all mismatches. */
+ for (i = 0; i < NV_VSX_REGS; i++) {
+ /*
+ * Copy VSX most significant doubleword from fp_regs and
+ * copy VSX least significant one from 64-bit slots below
+ * saved VMX registers.
+ */
+ memcpy(vsx, &ucp->uc_mcontext.fp_regs[FPR20 + i], 8);
+ memcpy(vsx + 8, &vsx_ptr[VSX20 + i], 8);
+
+ fail = memcmp(vsx, &vsxs[i], sizeof(vector int));
- fprintf(stderr, "Failed on %d vsx 0x", i);
+ if (fail) {
+ broken = 1;
+ printf("VSX%d (1st context) == 0x", VSX20 + i);
for (j = 0; j < 16; j++)
- fprintf(stderr, "%02x", vsc[j]);
- fprintf(stderr, " vs 0x");
+ printf("%02x", vsx[j]);
+ printf(" instead of 0x");
+ for (j = 0; j < 4; j++)
+ printf("%08x", vsxs[i][j]);
+ printf(" (expected)\n");
+ }
+ }
+
+ /* Check second context. Print all mismatches. */
+ for (i = 0; i < NV_VSX_REGS; i++) {
+ /*
+ * Copy VSX most significant doubleword from fp_regs and
+ * copy VSX least significant one from 64-bit slots below
+ * saved VMX registers.
+ */
+ memcpy(vsx_tm, &tm_ucp->uc_mcontext.fp_regs[FPR20 + i], 8);
+ memcpy(vsx_tm + 8, &tm_vsx_ptr[VSX20 + i], 8);
+
+ fail = memcmp(vsx_tm, &vsxs[NV_VSX_REGS + i], sizeof(vector int));
+
+ if (fail) {
+ broken = 1;
+ printf("VSX%d (2nd context) == 0x", VSX20 + i);
for (j = 0; j < 16; j++)
- fprintf(stderr, "%02x", vst[j]);
- fprintf(stderr, "\n");
+ printf("%02x", vsx_tm[j]);
+ printf(" instead of 0x");
+ for (j = 0; j < 4; j++)
+ printf("%08x", vsxs[NV_VSX_REGS + i][j]);
+ printf("(expected)\n");
}
}
}
}
i = 0;
- while (i < MAX_ATTEMPT && !fail) {
- rc = tm_signal_self_context_load(pid, NULL, NULL, NULL, vss);
+ while (i < MAX_ATTEMPT && !broken) {
+ /*
+ * tm_signal_self_context_load will set both first and second
+ * contexts accordingly to the values passed through non-NULL
+ * array pointers to it, in that case 'vsxs', and invoke the
+ * signal handler installed for SIGUSR1.
+ */
+ rc = tm_signal_self_context_load(pid, NULL, NULL, NULL, vsxs);
FAIL_IF(rc != pid);
i++;
}
- return fail;
+ return (broken);
}
int main(void)