1 #include <stdio.h>
2 #include <stdint.h>
3 #include <inttypes.h>
4 #include <assert.h>
5 
6 /* The golden logs were obtained by running this test natively. */
7 
8 /* The abstracted result of a CLCL 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 } clcl_t;
17 
18 /* Register contents after CLCL 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 } clcl_regs;
26 
27 /* Run a single CLCL insn and return its raw result. */
28 static clcl_regs
do_clcl(uint64_t r1,uint64_t r1p1,uint64_t r2,uint64_t r2p1)29 do_clcl(uint64_t r1, uint64_t r1p1, uint64_t r2, uint64_t r2p1)
30 {
31   clcl_regs regs;
32 
33   register uint64_t a1 asm ("2") = r1;
34   register uint64_t l1 asm ("3") = r1p1;
35   register uint64_t a2 asm ("4") = r2;
36   register uint64_t l2 asm ("5") = r2p1;
37   register uint32_t cc asm ("7");
38 
39   asm volatile(	"0: clcl 2,4\n\t"
40                 "jo 0b\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                 : : "memory", "cc");
45 
46   regs.r1   = a1;
47   regs.r1p1 = l1;
48   regs.r2   = a2;
49   regs.r2p1 = l2;
50   regs.cc   = cc;
51 
52   return regs;
53 }
54 
55 clcl_t
result_from_regs(clcl_regs regs)56 result_from_regs(clcl_regs regs)
57 {
58   clcl_t result;
59 
60   result.addr1 = regs.r1;
61   result.len1  = regs.r1p1 & 0xFFFFFF;
62   result.addr2 = regs.r2;
63   result.len2  = regs.r2p1 & 0xFFFFFF;
64   result.pad   = (regs.r2p1 & 0xFF000000u) >> 24;
65   result.cc    = regs.cc;
66 
67   return result;
68 }
69 
70 /* Run CLCL twice using different fill bits for unused register bits.
71    Results ought to be the same */
72 static clcl_t
clcl(void * addr1,uint32_t len1,void * addr2,uint32_t len2,uint32_t pad)73 clcl(void *addr1, uint32_t len1,
74      void *addr2, uint32_t len2, uint32_t pad)
75 {
76   clcl_t result1, result2;
77   clcl_regs regs;
78   uint64_t r1, r1p1, r2, r2p1;
79 
80   /* Check input arguments */
81   assert((pad & 0xFF) == pad);  /* an 8-byte value */
82   assert((len1 & 0xFFFFFF) == len1);
83   assert((len2 & 0xFFFFFF) == len2);
84 
85   /* Build up register contents setting unused bits to 0 */
86   r1   = (uint64_t)addr1;
87   r1p1 = len1;
88   r2   = (uint64_t)addr2;
89   r2p1 = len2 | (pad << 24);
90 
91   /* Run clcl */
92   regs = do_clcl(r1, r1p1, r2, r2p1);
93   result1 = result_from_regs(regs);
94 
95   /* Check unused bits */
96   if ((regs.r1p1 >> 24) != 0)
97     printf("FAIL: r1[0:39] modified (unused bits 0)\n");
98   if ((regs.r2p1 >> 32) != 0)
99     printf("FAIL: r2[0:31] modified (unused bits 0)\n");
100 
101   /* Check pad value */
102   if (result1.pad != pad)
103     printf("FAIL: pad byte modified (unused bits 0)\n");
104 
105   /* Build up register contents setting unused bits to 1 */
106   r1p1 |= 0xFFFFFFFFFFull << 24;
107   r2p1 |= ((uint64_t)0xFFFFFFFF) << 32;
108 
109   /* Run clcl again */
110   regs = do_clcl(r1, r1p1, r2, r2p1);
111   result2 = result_from_regs(regs);
112 
113   /* Check unused bits */
114   if ((regs.r1p1 >> 24) != 0xFFFFFFFFFFull)
115     printf("FAIL: r1[0:39] modified (unused bits 1)\n");
116   if ((regs.r2p1 >> 32) != 0xFFFFFFFFu)
117     printf("FAIL: r2[0:31] modified (unused bits 1)\n");
118 
119   /* Check pad value */
120   if (result2.pad != pad)
121     printf("FAIL: pad byte modified (unused bits 1)\n");
122 
123   /* Compare results */
124   if (result1.addr1 != result2.addr1)
125     printf("FAIL: addr1 result is different\n");
126   if (result1.addr2 != result2.addr2)
127     printf("FAIL: addr2 result is different\n");
128   if (result1.len1 != result2.len1)
129     printf("FAIL: len1 result is different\n");
130   if (result1.len2 != result2.len2)
131     printf("FAIL: len2 result is different\n");
132   if (result1.pad != result2.pad)
133     printf("FAIL: pad result is different\n");
134   if (result1.cc != result2.cc)
135     printf("FAIL: cc result is different\n");
136 
137   return result1;
138 }
139 
140 void
run_test(void * addr1,uint32_t len1,void * addr2,uint32_t len2,uint32_t pad)141 run_test(void *addr1, uint32_t len1, void *addr2, uint32_t len2, uint32_t pad)
142 {
143   clcl_t result;
144 
145   result = clcl(addr1, len1, addr2, len2, pad);
146 
147   printf("cc: %"PRIu32", len1: %"PRIu32", len2: %"PRIu32
148          ", addr1 diff: %"PRId64", addr2 diff: %"PRId64"\n", result.cc,
149          result.len1, result.len2, (int64_t)result.addr1 - (int64_t)addr1,
150          (int64_t)result.addr2 - (int64_t)addr2);
151 }
152 
main()153 int main()
154 {
155   uint8_t byte, byte1, byte2;
156 
157   /* Test 1: both lengths are 0; nothing loaded from memory */
158   printf("--- test 1 ---\n");
159   run_test(NULL, 0, NULL, 0, 0x00);
160   run_test(NULL, 0, NULL, 0, 0xff);
161 
162   /* Test 2: Compare two single bytes */
163   printf("--- test 2 ---\n");
164   byte1 = 10;
165   byte2 = 20;
166   run_test(&byte1, 1, &byte2, 1, 0x00);  // first operand low
167   run_test(&byte1, 1, &byte1, 1, 0x00);  // equal
168   run_test(&byte2, 1, &byte1, 1, 0x00);  // first operand high
169   run_test(&byte1, 1, &byte2, 1, 0xFF);  // first operand low
170   run_test(&byte1, 1, &byte1, 1, 0xFF);  // equal
171   run_test(&byte2, 1, &byte1, 1, 0xFF);  // first operand high
172 
173   /* Test 3: Compare a single byte against the pad byte */
174   printf("--- test 3 ---\n");
175   byte = 10;
176   run_test(NULL, 0, &byte, 1, 10);  // equal
177   run_test(NULL, 0, &byte, 1,  9);  // first operand low
178   run_test(NULL, 0, &byte, 1, 11);  // first operand high
179   /* Swap operands */
180   run_test(&byte, 1, NULL, 0, 10);  // equal
181   run_test(&byte, 1, NULL, 0,  9);  // first operand high
182   run_test(&byte, 1, NULL, 0, 11);  // first operand low
183 
184   /* Test 4: Make sure pad byte is interpreted as unsigned value */
185   printf("--- test 4 ---\n");
186   byte = 10;
187   run_test(&byte, 1, NULL, 0, 0xFF);  // first operand low
188   byte = 0xFF;
189   run_test(&byte, 1, NULL, 0, 0xFF);  // equal
190 
191   /* Test 5: Compare a buffer against the pad byte */
192   printf("--- test 5 ---\n");
193   uint8_t buf1[4] = "yyyy";
194   run_test(buf1, 4, NULL, 0, 'y');    // equal
195   run_test(buf1, 4, NULL, 0, 'x');    // greater
196   run_test(buf1, 4, NULL, 0, 'z');    // less
197 
198   /* Test 6: Compare two buffers of same size (difference in 1st byte) */
199   {
200   printf("--- test 6 ---\n");
201   uint8_t x[5] = "pqrst";
202   uint8_t y[5] = "abcde";
203   uint8_t z[5] = "abcde";
204   run_test(x, 5, y, 5, 'a');   // first operand low
205   run_test(y, 5, x, 5, 'a');   // first operand high
206   run_test(y, 5, z, 5, 'q');   // equal
207   }
208 
209   /* Test 7: Compare two buffers of same size (difference in last byte) */
210   {
211   printf("--- test 7 ---\n");
212   uint8_t x[5] = "abcdd";
213   uint8_t y[5] = "abcde";
214   uint8_t z[5] = "abcdf";
215   run_test(x, 5, y, 5, 'a');   // first operand low
216   run_test(z, 5, z, 5, 'a');   // first operand high
217   }
218 
219   /* Test 8: Compare two buffers of different size. The difference
220      is past the end of the shorter string. */
221   {
222   printf("--- test 8 ---\n");
223   uint8_t x[5] = "abcde";
224   uint8_t y[7] = "abcdeff";
225   run_test(x, 5, y, 7, 0);   // first operand low
226   run_test(y, 7, x, 5, 0);   // first operand high
227   run_test(x, 5, y, 7, 'f'); // equal
228   run_test(y, 7, x, 5, 'f'); // equal
229   }
230 
231   /* Test 9: Compare two buffers of different size. The difference
232      is before the end of the shorter string. */
233   {
234   printf("--- test 9 ---\n");
235   uint8_t x[5] = "abcab";
236   uint8_t y[7] = "abcdeff";
237   run_test(x, 5, y, 7, 0);   // first operand low
238   run_test(y, 7, x, 5, 0);   // first operand high
239   run_test(x, 5, y, 7, 'f'); // first operand low
240   run_test(y, 7, x, 5, 'f'); // first operand high
241   }
242 
243   return 0;
244 }
245