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_VMX_REGS 12 /* Number of non-volatile VMX registers */ |
34 | #define VMX20 20 /* First non-volatile register to check in vr20-31 subset */ |
35 | |
36 | long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss); |
37 | |
38 | static sig_atomic_t fail, broken; |
39 | |
40 | /* Test only non-volatile registers, i.e. 12 vmx registers from vr20 to vr31 */ |
41 | vector int vms[] = { |
42 | /* First context will be set with these values, i.e. non-speculative */ |
43 | /* VMX20 , VMX21 , ... */ |
44 | { 1, 2, 3, 4},{ 5, 6, 7, 8},{ 9,10,11,12}, |
45 | {13,14,15,16},{17,18,19,20},{21,22,23,24}, |
46 | {25,26,27,28},{29,30,31,32},{33,34,35,36}, |
47 | {37,38,39,40},{41,42,43,44},{45,46,47,48}, |
48 | /* Second context will be set with these values, i.e. speculative */ |
49 | /* VMX20 , VMX21 , ... */ |
50 | { -1, -2, -3, -4},{ -5, -6, -7, -8},{ -9,-10,-11,-12}, |
51 | {-13,-14,-15,-16},{-17,-18,-19,-20},{-21,-22,-23,-24}, |
52 | {-25,-26,-27,-28},{-29,-30,-31,-32},{-33,-34,-35,-36}, |
53 | {-37,-38,-39,-40},{-41,-42,-43,-44},{-45,-46,-47,-48} |
54 | }; |
55 | |
56 | static void signal_usr1(int signum, siginfo_t *info, void *uc) |
57 | { |
58 | int i, j; |
59 | ucontext_t *ucp = uc; |
60 | ucontext_t *tm_ucp = ucp->uc_link; |
61 | |
62 | for (i = 0; i < NV_VMX_REGS; i++) { |
63 | /* Check first context. Print all mismatches. */ |
64 | fail = memcmp(ucp->uc_mcontext.v_regs->vrregs[VMX20 + i], |
65 | &vms[i], sizeof(vector int)); |
66 | if (fail) { |
67 | broken = 1; |
68 | printf("VMX%d (1st context) == 0x" , VMX20 + i); |
69 | /* Print actual value in first context. */ |
70 | for (j = 0; j < 4; j++) |
71 | printf("%08x" , ucp->uc_mcontext.v_regs->vrregs[VMX20 + i][j]); |
72 | printf(" instead of 0x" ); |
73 | /* Print expected value. */ |
74 | for (j = 0; j < 4; j++) |
75 | printf("%08x" , vms[i][j]); |
76 | printf(" (expected)\n" ); |
77 | } |
78 | } |
79 | |
80 | for (i = 0; i < NV_VMX_REGS; i++) { |
81 | /* Check second context. Print all mismatches. */ |
82 | fail = memcmp(tm_ucp->uc_mcontext.v_regs->vrregs[VMX20 + i], |
83 | &vms[NV_VMX_REGS + i], sizeof (vector int)); |
84 | if (fail) { |
85 | broken = 1; |
86 | printf("VMX%d (2nd context) == 0x" , NV_VMX_REGS + i); |
87 | /* Print actual value in second context. */ |
88 | for (j = 0; j < 4; j++) |
89 | printf("%08x" , tm_ucp->uc_mcontext.v_regs->vrregs[VMX20 + i][j]); |
90 | printf(" instead of 0x" ); |
91 | /* Print expected value. */ |
92 | for (j = 0; j < 4; j++) |
93 | printf("%08x" , vms[NV_VMX_REGS + i][j]); |
94 | printf(" (expected)\n" ); |
95 | } |
96 | } |
97 | } |
98 | |
99 | static int tm_signal_context_chk() |
100 | { |
101 | struct sigaction act; |
102 | int i; |
103 | long rc; |
104 | pid_t pid = getpid(); |
105 | |
106 | SKIP_IF(!have_htm()); |
107 | SKIP_IF(htm_is_synthetic()); |
108 | |
109 | act.sa_sigaction = signal_usr1; |
110 | sigemptyset(&act.sa_mask); |
111 | act.sa_flags = SA_SIGINFO; |
112 | if (sigaction(SIGUSR1, &act, NULL) < 0) { |
113 | perror("sigaction sigusr1" ); |
114 | exit(1); |
115 | } |
116 | |
117 | i = 0; |
118 | while (i < MAX_ATTEMPT && !broken) { |
119 | /* |
120 | * tm_signal_self_context_load will set both first and second |
121 | * contexts accordingly to the values passed through non-NULL |
122 | * array pointers to it, in that case 'vms', and invoke the |
123 | * signal handler installed for SIGUSR1. |
124 | */ |
125 | rc = tm_signal_self_context_load(pid, NULL, NULL, vms, NULL); |
126 | FAIL_IF(rc != pid); |
127 | i++; |
128 | } |
129 | |
130 | return (broken); |
131 | } |
132 | |
133 | int main(void) |
134 | { |
135 | return test_harness(tm_signal_context_chk, "tm_signal_context_chk_vmx" ); |
136 | } |
137 | |