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 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 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 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 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 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