1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright 2016, Cyril Bur, IBM Corp. |
4 | * |
5 | * Test the kernel's signal frame code. |
6 | * |
7 | * The kernel sets up two sets of ucontexts if the signal was to be |
8 | * delivered while the thread was in a transaction (referred too as |
9 | * first and second contexts). |
10 | * Expected behaviour is that the checkpointed state is in the user |
11 | * context passed to the signal handler (first context). The speculated |
12 | * state can be accessed with the uc_link pointer (second context). |
13 | * |
14 | * The rationale for this is that if TM unaware code (which linked |
15 | * against TM libs) installs a signal handler it will not know of the |
16 | * speculative nature of the 'live' registers and may infer the wrong |
17 | * thing. |
18 | */ |
19 | |
20 | #include <stdlib.h> |
21 | #include <stdio.h> |
22 | #include <string.h> |
23 | #include <signal.h> |
24 | #include <unistd.h> |
25 | |
26 | #include <altivec.h> |
27 | |
28 | #include "utils.h" |
29 | #include "tm.h" |
30 | |
31 | #define MAX_ATTEMPT 500000 |
32 | |
33 | #define NV_VSX_REGS 12 /* Number of VSX registers to check. */ |
34 | #define VSX20 20 /* First VSX register to check in vsr20-vsr31 subset */ |
35 | #define FPR20 20 /* FPR20 overlaps VSX20 most significant doubleword */ |
36 | |
37 | long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss); |
38 | |
39 | static sig_atomic_t fail, broken; |
40 | |
41 | /* Test only 12 vsx registers from vsr20 to vsr31 */ |
42 | vector int vsxs[] = { |
43 | /* First context will be set with these values, i.e. non-speculative */ |
44 | /* VSX20 , VSX21 , ... */ |
45 | { 1, 2, 3, 4},{ 5, 6, 7, 8},{ 9,10,11,12}, |
46 | {13,14,15,16},{17,18,19,20},{21,22,23,24}, |
47 | {25,26,27,28},{29,30,31,32},{33,34,35,36}, |
48 | {37,38,39,40},{41,42,43,44},{45,46,47,48}, |
49 | /* Second context will be set with these values, i.e. speculative */ |
50 | /* VSX20 , VSX21 , ... */ |
51 | {-1, -2, -3, -4 },{-5, -6, -7, -8 },{-9, -10,-11,-12}, |
52 | {-13,-14,-15,-16},{-17,-18,-19,-20},{-21,-22,-23,-24}, |
53 | {-25,-26,-27,-28},{-29,-30,-31,-32},{-33,-34,-35,-36}, |
54 | {-37,-38,-39,-40},{-41,-42,-43,-44},{-45,-46,-47,-48} |
55 | }; |
56 | |
57 | static void signal_usr1(int signum, siginfo_t *info, void *uc) |
58 | { |
59 | int i, j; |
60 | uint8_t vsx[sizeof(vector int)]; |
61 | uint8_t vsx_tm[sizeof(vector int)]; |
62 | ucontext_t *ucp = uc; |
63 | ucontext_t *tm_ucp = ucp->uc_link; |
64 | |
65 | /* |
66 | * FP registers and VMX registers overlap the VSX registers. |
67 | * |
68 | * FP registers (f0-31) overlap the most significant 64 bits of VSX |
69 | * registers vsr0-31, whilst VMX registers vr0-31, being 128-bit like |
70 | * the VSX registers, overlap fully the other half of VSX registers, |
71 | * i.e. vr0-31 overlaps fully vsr32-63. |
72 | * |
73 | * Due to compatibility and historical reasons (VMX/Altivec support |
74 | * appeared first on the architecture), VMX registers vr0-31 (so VSX |
75 | * half vsr32-63 too) are stored right after the v_regs pointer, in an |
76 | * area allocated for 'vmx_reverse' array (please see |
77 | * arch/powerpc/include/uapi/asm/sigcontext.h for details about the |
78 | * mcontext_t structure on Power). |
79 | * |
80 | * The other VSX half (vsr0-31) is hence stored below vr0-31/vsr32-63 |
81 | * registers, but only the least significant 64 bits of vsr0-31. The |
82 | * most significant 64 bits of vsr0-31 (f0-31), as it overlaps the FP |
83 | * registers, is kept in fp_regs. |
84 | * |
85 | * v_regs is a 16 byte aligned pointer at the start of vmx_reserve |
86 | * (vmx_reserve may or may not be 16 aligned) where the v_regs structure |
87 | * exists, so v_regs points to where vr0-31 / vsr32-63 registers are |
88 | * fully stored. Since v_regs type is elf_vrregset_t, v_regs + 1 |
89 | * skips all the slots used to store vr0-31 / vsr32-64 and points to |
90 | * part of one VSX half, i.e. v_regs + 1 points to the least significant |
91 | * 64 bits of vsr0-31. The other part of this half (the most significant |
92 | * part of vsr0-31) is stored in fp_regs. |
93 | * |
94 | */ |
95 | /* Get pointer to least significant doubleword of vsr0-31 */ |
96 | long *vsx_ptr = (long *)(ucp->uc_mcontext.v_regs + 1); |
97 | long *tm_vsx_ptr = (long *)(tm_ucp->uc_mcontext.v_regs + 1); |
98 | |
99 | /* Check first context. Print all mismatches. */ |
100 | for (i = 0; i < NV_VSX_REGS; i++) { |
101 | /* |
102 | * Copy VSX most significant doubleword from fp_regs and |
103 | * copy VSX least significant one from 64-bit slots below |
104 | * saved VMX registers. |
105 | */ |
106 | memcpy(vsx, &ucp->uc_mcontext.fp_regs[FPR20 + i], 8); |
107 | memcpy(vsx + 8, &vsx_ptr[VSX20 + i], 8); |
108 | |
109 | fail = memcmp(vsx, &vsxs[i], sizeof(vector int)); |
110 | |
111 | if (fail) { |
112 | broken = 1; |
113 | printf("VSX%d (1st context) == 0x" , VSX20 + i); |
114 | for (j = 0; j < 16; j++) |
115 | printf("%02x" , vsx[j]); |
116 | printf(" instead of 0x" ); |
117 | for (j = 0; j < 4; j++) |
118 | printf("%08x" , vsxs[i][j]); |
119 | printf(" (expected)\n" ); |
120 | } |
121 | } |
122 | |
123 | /* Check second context. Print all mismatches. */ |
124 | for (i = 0; i < NV_VSX_REGS; i++) { |
125 | /* |
126 | * Copy VSX most significant doubleword from fp_regs and |
127 | * copy VSX least significant one from 64-bit slots below |
128 | * saved VMX registers. |
129 | */ |
130 | memcpy(vsx_tm, &tm_ucp->uc_mcontext.fp_regs[FPR20 + i], 8); |
131 | memcpy(vsx_tm + 8, &tm_vsx_ptr[VSX20 + i], 8); |
132 | |
133 | fail = memcmp(vsx_tm, &vsxs[NV_VSX_REGS + i], sizeof(vector int)); |
134 | |
135 | if (fail) { |
136 | broken = 1; |
137 | printf("VSX%d (2nd context) == 0x" , VSX20 + i); |
138 | for (j = 0; j < 16; j++) |
139 | printf("%02x" , vsx_tm[j]); |
140 | printf(" instead of 0x" ); |
141 | for (j = 0; j < 4; j++) |
142 | printf("%08x" , vsxs[NV_VSX_REGS + i][j]); |
143 | printf("(expected)\n" ); |
144 | } |
145 | } |
146 | } |
147 | |
148 | static int tm_signal_context_chk() |
149 | { |
150 | struct sigaction act; |
151 | int i; |
152 | long rc; |
153 | pid_t pid = getpid(); |
154 | |
155 | SKIP_IF(!have_htm()); |
156 | SKIP_IF(htm_is_synthetic()); |
157 | |
158 | act.sa_sigaction = signal_usr1; |
159 | sigemptyset(&act.sa_mask); |
160 | act.sa_flags = SA_SIGINFO; |
161 | if (sigaction(SIGUSR1, &act, NULL) < 0) { |
162 | perror("sigaction sigusr1" ); |
163 | exit(1); |
164 | } |
165 | |
166 | i = 0; |
167 | while (i < MAX_ATTEMPT && !broken) { |
168 | /* |
169 | * tm_signal_self_context_load will set both first and second |
170 | * contexts accordingly to the values passed through non-NULL |
171 | * array pointers to it, in that case 'vsxs', and invoke the |
172 | * signal handler installed for SIGUSR1. |
173 | */ |
174 | rc = tm_signal_self_context_load(pid, NULL, NULL, NULL, vsxs); |
175 | FAIL_IF(rc != pid); |
176 | i++; |
177 | } |
178 | |
179 | return (broken); |
180 | } |
181 | |
182 | int main(void) |
183 | { |
184 | return test_harness(tm_signal_context_chk, "tm_signal_context_chk_vsx" ); |
185 | } |
186 | |