1 #include <stdio.h>
2 #include <assert.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <stdint.h>
6 #include <inttypes.h>
7
8 /* The abstracted result of an MVCL insn */
9 typedef struct {
10 uint64_t addr1;
11 uint32_t len1;
12 uint64_t addr2;
13 uint32_t len2;
14 uint8_t pad;
15 uint32_t cc;
16 } mvcl_t;
17
18 /* Register contents after executing an MVCL insn */
19 typedef struct {
20 uint64_t r1;
21 uint64_t r1p1;
22 uint64_t r2;
23 uint64_t r2p1;
24 uint64_t cc;
25 } mvcl_regs;
26
27
28 /* Run a single MVCL insn and return its raw result. */
29 static mvcl_regs
do_mvcl(uint64_t r1,uint64_t r1p1,uint64_t r2,uint64_t r2p1)30 do_mvcl(uint64_t r1, uint64_t r1p1, uint64_t r2, uint64_t r2p1)
31 {
32 mvcl_regs regs;
33
34 register uint64_t a1 asm ("2") = r1;
35 register uint64_t l1 asm ("3") = r1p1;
36 register uint64_t a2 asm ("4") = r2;
37 register uint64_t l2 asm ("5") = r2p1;
38 register uint32_t cc asm ("7");
39
40 asm volatile( "mvcl %1,%3\n\t"
41 "ipm %0\n\t"
42 "srl %0,28\n\t"
43 :"=d"(cc), "+d"(a1), "+d"(l1), "+d"(a2), "+d"(l2)
44 :
45 : "memory", "cc");
46
47 regs.r1 = a1;
48 regs.r1p1 = l1;
49 regs.r2 = a2;
50 regs.r2p1 = l2;
51 regs.cc = cc;
52
53 return regs;
54 }
55
56 mvcl_t
result_from_regs(mvcl_regs regs)57 result_from_regs(mvcl_regs regs)
58 {
59 mvcl_t result;
60
61 result.addr1 = regs.r1;
62 result.len1 = regs.r1p1 & 0xFFFFFF;
63 result.addr2 = regs.r2;
64 result.len2 = regs.r2p1 & 0xFFFFFF;
65 result.pad = (regs.r2p1 & 0xFF000000u) >> 24;
66 result.cc = regs.cc;
67
68 return result;
69 }
70
71 /* Run MVCL twice using different fill bits for unused register bits.
72 Results ought to be the same */
73 static mvcl_t
mvcl(void * addr1,uint32_t len1,void * addr2,uint32_t len2,uint32_t pad)74 mvcl(void *addr1, uint32_t len1,
75 void *addr2, uint32_t len2, uint32_t pad)
76 {
77 mvcl_t result1, result2;
78 mvcl_regs regs;
79 uint64_t r1, r1p1, r2, r2p1;
80
81 /* Check input arguments */
82 assert((pad & 0xFF) == pad); /* an 8-byte value */
83 assert((len1 & 0xFFFFFF) == len1);
84 assert((len2 & 0xFFFFFF) == len2);
85
86 /* Make a copy of the input buffer */
87 void *copy = memcpy(malloc(len1), addr1, len1);
88
89 /* Build up register contents setting unused bits to 0 */
90 r1 = (uint64_t)addr1;
91 r1p1 = len1;
92 r2 = (uint64_t)addr2;
93 r2p1 = len2 | (pad << 24);
94
95 /* Run mvcl */
96 regs = do_mvcl(r1, r1p1, r2, r2p1);
97 result1 = result_from_regs(regs);
98
99 /* Check unused bits */
100 if ((regs.r1p1 >> 24) != 0)
101 printf("FAIL: r1[0:39] modified (unused bits 0)\n");
102 if ((regs.r2p1 >> 32) != 0)
103 printf("FAIL: r2[0:31] modified (unused bits 0)\n");
104
105 /* Check pad value */
106 if (result1.pad != pad)
107 printf("FAIL: pad byte modified (unused bits 0)\n");
108
109 /* Build up register contents setting unused bits to 1 */
110 memcpy(addr1, copy, len1);
111 r1p1 |= 0xFFFFFFFFFFULL << 24;
112 r2p1 |= ((uint64_t)0xFFFFFFFF) << 32;
113
114 /* Run mvcl again */
115 regs = do_mvcl(r1, r1p1, r2, r2p1);
116 result2 = result_from_regs(regs);
117
118 /* Check unused bits */
119 if ((regs.r1p1 >> 24) != 0xFFFFFFFFFFull)
120 printf("FAIL: r1[0:39] modified (unused bits 1)\n");
121 if ((regs.r2p1 >> 32) != 0xFFFFFFFFu)
122 printf("FAIL: r2[0:31] modified (unused bits 1)\n");
123
124 /* Check pad value */
125 if (result2.pad != pad)
126 printf("FAIL: pad byte modified (unused bits 1)\n");
127
128 /* Compare results */
129 if (result1.addr1 != result2.addr1)
130 printf("FAIL: addr1 result is different\n");
131 if (result1.addr2 != result2.addr2)
132 printf("FAIL: addr2 result is different\n");
133 if (result1.len1 != result2.len1)
134 printf("FAIL: len1 result is different\n");
135 if (result1.len2 != result2.len2)
136 printf("FAIL: len2 result is different\n");
137 if (result1.pad != result2.pad)
138 printf("FAIL: pad result is different\n");
139 if (result1.cc != result2.cc)
140 printf("FAIL: cc result is different\n");
141
142 return result1;
143 }
144
145 void
print_buf(const char * prefix,char * buf,uint32_t len)146 print_buf(const char *prefix, char *buf, uint32_t len)
147 {
148 uint32_t i;
149
150 if (len > 0) {
151 printf("%s |", prefix);
152 for (i = 0; i < len; ++i)
153 putchar(buf[i]);
154 printf("|\n");
155 }
156 }
157
158 void
run_test(void * dst,uint32_t dst_len,void * src,uint32_t src_len,uint32_t pad)159 run_test(void *dst, uint32_t dst_len, void *src, uint32_t src_len, uint32_t pad)
160 {
161 mvcl_t result;
162
163 result = mvcl(dst, dst_len, src, src_len, pad);
164
165 printf("cc: %"PRIu32", len1: %"PRIu32", len2: %"PRIu32
166 ", addr1 diff: %"PRId64", addr2 diff: %"PRId64"\n", result.cc,
167 result.len1, result.len2, (int64_t)result.addr1 - (int64_t)dst,
168 (int64_t)result.addr2 - (int64_t)src);
169 print_buf("dst buffer:", dst, dst_len);
170 }
171
main()172 int main()
173 {
174 uint8_t byte, buf[10], small[5], i;
175 uint32_t dst_offset, dst_len, src_offset, src_len;
176
177 /* Test 1: len1 == 0 */
178 printf("--- test 1 ---\n");
179 run_test(NULL, 0, NULL, 0, 0x00);
180 run_test(NULL, 0, NULL, 0, 0xFF);
181 run_test(NULL, 0, NULL, 5, 0x00);
182 run_test(NULL, 0, NULL, 5, 0xFF);
183 run_test(NULL, 0, buf, sizeof buf, 0x00);
184 run_test(NULL, 0, buf, sizeof buf, 0xFF);
185
186 /* Test 2: len1 != 0, len2 == 0 */
187 printf("--- test 2 ---\n");
188 run_test(&byte, 1, NULL, 0, 'a');
189 memset(buf, 'x', sizeof buf);
190 run_test(buf, sizeof buf, NULL, 0, 'a');
191
192 /* In the following: len1 != 0, len2 != 0 */
193
194 /* Test 3: src == dst */
195 printf("--- test 3 ---\n");
196 byte = 'x';
197 run_test(&byte, 1, &byte, 1, 'a');
198 memset(buf, 'x', sizeof buf);
199 for (i = 0; i <= sizeof buf; ++i)
200 run_test(buf, i, buf, sizeof buf, 'a');
201
202 /* Test 4: len1 > len2, no buffer overlap */
203 printf("--- test 4 ---\n");
204 memset(buf, 'b', sizeof buf);
205 memset(small, 's', sizeof small);
206 run_test(buf, sizeof buf, small, sizeof small, 'a');
207
208 /* Test 5: len1 < len2, no buffer overlap */
209 printf("--- test 5 ---\n");
210 memset(buf, 'b', sizeof buf);
211 memset(small, 's', sizeof small);
212 run_test(small, sizeof small, buf, sizeof buf, 'a');
213
214 /* Test 6: len1 > len2, non-destructive overlap */
215 printf("--- test 6 ---\n");
216 memcpy(buf, "0123456789", 10);
217 run_test(buf, sizeof buf, buf + 5, 5, 'x');
218
219 /* Test 7: len1 < len2, non-destructive overlap */
220 printf("--- test 7 ---\n");
221 memcpy(buf, "0123456789", 10);
222 run_test(buf, 5, buf + 4, 3, 'x');
223
224 /* Test 8: Misc checks for testing destructive overlap
225 Pad byte unused */
226 printf("--- test 8 ---\n");
227 memcpy(buf, "0123456789", 10);
228 run_test(buf + 3, 1, buf, 10, 'x'); // non-destructive
229 memcpy(buf, "0123456789", 10);
230 run_test(buf + 3, 2, buf, 10, 'x'); // non-destructive
231 memcpy(buf, "0123456789", 10);
232 run_test(buf + 3, 3, buf, 10, 'x'); // non-destructive
233 memcpy(buf, "0123456789", 10);
234 run_test(buf + 3, 4, buf, 10, 'x'); // destructive
235 memcpy(buf, "0123456789", 10);
236 run_test(buf + 3, 5, buf, 10, 'x'); // destructive
237 memcpy(buf, "0123456789", 10);
238 run_test(buf + 3, 6, buf, 10, 'x'); // destructive
239 memcpy(buf, "0123456789", 10);
240 run_test(buf + 3, 7, buf, 10, 'x'); // destructive
241
242 /* Test 9: More checks for testing destructive overlap
243 Pad byte used; len2 == 0 */
244 printf("--- test 9 ---\n");
245 memcpy(buf, "0123456789", 10);
246 run_test(buf + 3, 1, buf, 0, 'x'); // non-destructive
247 memcpy(buf, "0123456789", 10);
248 run_test(buf + 3, 2, buf, 0, 'x'); // non-destructive
249 memcpy(buf, "0123456789", 10);
250 run_test(buf + 3, 3, buf, 0, 'x'); // non-destructive
251 memcpy(buf, "0123456789", 10);
252 run_test(buf + 3, 4, buf, 0, 'x'); // non-destructive
253 memcpy(buf, "0123456789", 10);
254 run_test(buf + 3, 4, buf, 0, 'x'); // non-destructive
255 memcpy(buf, "0123456789", 10);
256 run_test(buf + 3, 5, buf, 0, 'x'); // non-destructive
257 memcpy(buf, "0123456789", 10);
258 run_test(buf + 3, 6, buf, 0, 'x'); // non-destructive
259 memcpy(buf, "0123456789", 10);
260 run_test(buf + 3, 7, buf, 0, 'x'); // non-destructive
261
262 /* Test 10; what the heck... Just try all combinations. */
263 printf("--- test 9 ---\n");
264 for (dst_offset = 0; dst_offset < sizeof buf; ++dst_offset)
265 for (dst_len = 0; dst_len <= sizeof buf - dst_offset; ++dst_len)
266 for (src_offset = 0; src_offset < sizeof buf; ++src_offset)
267 for (src_len = 0; src_len <= sizeof buf - src_offset; ++src_len)
268 run_test(buf + dst_offset, dst_len, buf + src_offset, src_len, 'x');
269
270 return 0;
271 }
272
273