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