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