mvcl.c revision b32f58018498ea2225959b0ba11c18f0c433deef
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 */
9typedef 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 */
19typedef 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. */
29static mvcl_regs
30do_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
56mvcl_t
57result_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 */
73static mvcl_t
74mvcl(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
145void
146print_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
158void
159run_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
172int 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