1#include <stdint.h> 2#include <inttypes.h> 3#include <stdlib.h> 4#include <string.h> 5#include <stdio.h> 6#include "opcodes.h" 7 8#ifndef M3 9#define M3 0 10#endif 11 12/* The abstracted result of an CU21 insn */ 13typedef struct { 14 uint64_t addr1; // target 15 uint64_t len1; 16 uint64_t addr2; // source 17 uint64_t len2; 18 uint32_t cc; 19} cu21_t; 20 21/* Define various input buffers. */ 22 23/* U+0000 to U+007f: Result is 1 byte for each uint16_t */ 24uint16_t pattern1[] = { 25 0x0000, 0x007f, /* corner cases */ 26 0x0047, 0x0056, 0x0045, 0x0021, 0x007b, 0x003a /* misc */ 27}; 28 29/* U+0080 to U+07ff: Result is 2 bytes for each uint16_t */ 30uint16_t pattern2[] = { 31 0x0080, 0x07ff, /* corner cases */ 32 0x07df, 0x008f, 0x0100, 0x017f, 0x052f, 0x0600, 0x06ff /* misc */ 33}; 34 35/* U+0800 to U+d7ff: Result is 3 bytes for each uint16_t 36 U+dc00 to U+ffff: Result is 3 bytes for each uint16_t */ 37uint16_t pattern3[] = { 38 0x0800, 0xd7ff, /* corner cases */ 39 0xdc00, 0xffff, /* corner cases */ 40 0x083f, 0x1a21, 0x1b10, 0x2200, 0x225e, 0x22c9, 0xe001 /* misc */ 41}; 42 43/* U+d800 to U+dbff: Result is 4 bytes for each uint16_t pair */ 44uint16_t pattern4[] = { 45 0xd800, 0xdc00, /* left corner case */ 46 0xdbff, 0xdfff, /* right corner case */ 47 0xdada, 0xdddd, 0xdeaf, 0xdcdc /* misc */ 48}; 49 50/* Invalid low surrogate */ 51uint16_t invalid[] = { 0xd801, 0x0098 }; 52 53/* Mixed bytes */ 54uint16_t mixed[] = { 55 0x0078 /* 1 byte */, 56 0x0200 /* 2 bytes */, 57 0xffff /* 3 bytes */, 58 0xd800, 0xdc01 /* 4 bytes */ 59}; 60 61/* This is the buffer for the converted bytes. */ 62uint8_t buff[1000]; /* Large so we con'don't have to worry about it */ 63 64void write_and_check(uint16_t *, unsigned, unsigned); 65 66 67static cu21_t 68do_cu21(uint8_t *dst, uint64_t dst_len, uint16_t *src, uint64_t src_len) 69{ 70 int cc = 42; 71 cu21_t regs; 72 73 /* build up the register pairs */ 74 register uint16_t *source asm("4") = src; 75 register uint64_t source_len asm("5") = src_len; 76 register uint8_t *dest asm("2") = dst; 77 register uint64_t dest_len asm("3") = dst_len; 78 79 asm volatile( 80 CU21(M3,2,4) 81 "ipm %2\n\t" 82 "srl %2,28\n\t" 83 : "+d"(dest), "+d"(source), "=d"(cc), 84 "+d"(source_len), "+d"(dest_len) 85 : 86 : "memory", "cc"); 87 88 /* Capture register contents at end of cu21 */ 89 regs.addr1 = (uint64_t)dest; 90 regs.len1 = dest_len; 91 regs.addr2 = (uint64_t)source; 92 regs.len2 = source_len; 93 regs.cc = cc; 94 95 return regs; 96} 97 98void 99run_test(uint8_t *dst, uint64_t dst_len, uint16_t *src, uint64_t src_len) 100{ 101 int i; 102 cu21_t result; 103 104 result = do_cu21(dst, dst_len, src, src_len); 105 106 // Write out the converted bytes, if any 107 printf("UTF8: "); 108 if (dst_len - result.len1 == 0) 109 printf(" <none>"); 110 else 111 for (i = 0; i < dst_len - result.len1; i++) { 112 printf(" %02x", dst[i]); 113 } 114 printf("\n"); 115 116 printf(" cc = %d\n", result.cc); 117 if (dst != NULL) 118 printf(" dst address difference: %"PRId64, result.addr1 - (uint64_t)dst); 119 printf(" dst len: %"PRId64"\n", result.len1); 120 121 if (src != NULL) 122 printf(" src address difference: %"PRId64, result.addr2 - (uint64_t)src); 123 printf(" src len: %"PRId64"\n", result.len2); 124} 125 126int main() 127{ 128 /* Length == 0, no memory should be read or written */ 129 printf("\n------------- test1 ----------------\n"); 130 run_test(NULL, 0, NULL, 0); 131 132 /* Test exhaustion of source length (source bytes are valid) */ 133 printf("\n------------- test2.1 ----------------\n"); 134 135 /* No character will be written to BUFF, i.e. loop in jitted code 136 is not iterated */ 137 run_test(buff, sizeof buff, NULL, 1); 138 run_test(buff, sizeof buff, pattern1, 1); 139 run_test(buff, sizeof buff, pattern2, 1); 140 run_test(buff, sizeof buff, pattern3, 1); 141 run_test(buff, sizeof buff, pattern4, 1); 142 run_test(buff, sizeof buff, pattern4, 2); 143 run_test(buff, sizeof buff, pattern4, 3); 144 145 printf("\n------------- test2.2 ----------------\n"); 146 /* At least one character will be written to BUFF, i.e. loop in jitted 147 code is iterated */ 148 run_test(buff, sizeof buff, pattern1, 3); 149 run_test(buff, sizeof buff, pattern2, 5); 150 run_test(buff, sizeof buff, pattern3, 7); 151 run_test(buff, sizeof buff, pattern4, 9); 152 run_test(buff, sizeof buff, pattern4, 10); 153 run_test(buff, sizeof buff, pattern4, 11); 154 155 /* Test exhaustion of destination length (source bytes are valid) */ 156 printf("\n------------- test3.1 ----------------\n"); 157 158 /* No character will be written to BUFF, i.e. loop in jitted code 159 is not iterated */ 160 161 /* Want to write a single byte */ 162 run_test(NULL, 0, pattern1, sizeof pattern1); 163 164 /* Want to write two bytes */ 165 run_test(NULL, 0, pattern2, sizeof pattern2); 166 run_test(NULL, 1, pattern2, sizeof pattern2); 167 168 /* Want to write three bytes */ 169 run_test(NULL, 0, pattern3, sizeof pattern3); 170 run_test(NULL, 1, pattern3, sizeof pattern3); 171 run_test(NULL, 2, pattern3, sizeof pattern3); 172 173 /* Want to write four bytes */ 174 run_test(NULL, 0, pattern4, sizeof pattern4); 175 run_test(NULL, 1, pattern4, sizeof pattern4); 176 run_test(NULL, 2, pattern4, sizeof pattern4); 177 run_test(NULL, 3, pattern4, sizeof pattern4); 178 179 printf("\n------------- test3.2 ----------------\n"); 180 /* At least one character will be written to BUFF, i.e. loop in jitted 181 code is iterated */ 182 run_test(buff, 3, pattern1, sizeof pattern1); 183 184 run_test(buff, 5, pattern2, sizeof pattern2); 185 186 run_test(buff, 7, pattern3, sizeof pattern3); 187 run_test(buff, 8, pattern3, sizeof pattern3); 188 189 run_test(buff, 9, pattern4, sizeof pattern4); 190 run_test(buff, 10, pattern4, sizeof pattern4); 191 run_test(buff, 11, pattern4, sizeof pattern4); 192 193 /* When both operands are exhausted, cc=0 takes precedence. 194 (test1 tests this for len == 0) */ 195 printf("\n------------- test4 ----------------\n"); 196 run_test(buff, 6, pattern1, 6); 197 198 /* Input has invalid low surrogate. */ 199 printf("\n------------- test5 ----------------\n"); 200 run_test(buff, sizeof buff, invalid, sizeof invalid); 201 run_test(buff, 0, invalid, sizeof invalid); 202 203 /* Convert all pattern buffers */ 204 printf("\n------------- test6 ----------------\n"); 205 run_test(buff, sizeof buff, pattern1, sizeof pattern1); 206 run_test(buff, sizeof buff, pattern2, sizeof pattern2); 207 run_test(buff, sizeof buff, pattern3, sizeof pattern3); 208 run_test(buff, sizeof buff, pattern4, sizeof pattern4); 209 run_test(buff, sizeof buff, mixed, sizeof mixed); 210 211 /* Make sure we only write the exact number of bytes (and not more) */ 212 uint16_t pat[2]; 213 214 /* Write 1 byte */ 215 printf("\n------------- test7.1 ----------------\n"); 216 pat[0] = 0x10; 217 write_and_check(pat, 2, 1); 218 219 /* Write 2 bytes */ 220 printf("\n------------- test7.2 ----------------\n"); 221 pat[0] = 0x8f; 222 write_and_check(pat, 2, 2); 223 224 /* Write 3 bytes */ 225 printf("\n------------- test7.3 ----------------\n"); 226 pat[0] = 0x842; 227 write_and_check(pat, 2, 3); 228 229 /* Write 4 bytes */ 230 printf("\n------------- test7.4 ----------------\n"); 231 pat[0] = 0xd842; 232 pat[1] = 0xdc42; 233 write_and_check(pat, 2, 4); 234 235 return 0; 236} 237 238 239void 240write_and_check_aux(uint16_t *input, unsigned num_input_bytes, 241 unsigned num_expected_output_bytes, 242 unsigned fill_byte) 243{ 244 int num_errors, i; 245 246 /* Fill output buffer with FILL_BYTE */ 247 memset(buff, fill_byte, sizeof buff); 248 249 /* Execute cu21 */ 250 run_test(buff, sizeof buff, input, num_input_bytes); 251 252 /* Make sure the rest of the buffer is unmodified. */ 253 num_errors = 0; 254 for (i = num_expected_output_bytes; i < sizeof buff; ++i) 255 if (buff[i] != fill_byte) ++num_errors; 256 if (num_errors) 257 fprintf(stderr, "*** wrote more than %u bytes\n", 258 num_expected_output_bytes); 259} 260 261void 262write_and_check(uint16_t *input, unsigned num_input_bytes, 263 unsigned num_expected_output_bytes) 264{ 265 write_and_check_aux(input, num_input_bytes, num_expected_output_bytes, 0x0); 266 267 /* Run again with different fill pattern to make sure we did not write 268 an extra 0x0 byte */ 269 write_and_check_aux(input, num_input_bytes, num_expected_output_bytes, 0xFF); 270} 271