11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21ec454baSMasami Hiramatsu /* 31ec454baSMasami Hiramatsu * x86 decoder sanity test - based on test_get_insn.c 41ec454baSMasami Hiramatsu * 51ec454baSMasami Hiramatsu * Copyright (C) IBM Corporation, 2009 61ec454baSMasami Hiramatsu * Copyright (C) Hitachi, Ltd., 2011 71ec454baSMasami Hiramatsu */ 81ec454baSMasami Hiramatsu 91ec454baSMasami Hiramatsu #include <stdlib.h> 101ec454baSMasami Hiramatsu #include <stdio.h> 111ec454baSMasami Hiramatsu #include <string.h> 121ec454baSMasami Hiramatsu #include <assert.h> 131ec454baSMasami Hiramatsu #include <unistd.h> 141ec454baSMasami Hiramatsu #include <sys/types.h> 151ec454baSMasami Hiramatsu #include <sys/stat.h> 161ec454baSMasami Hiramatsu #include <fcntl.h> 171ec454baSMasami Hiramatsu #include <asm/insn.h> 181ec454baSMasami Hiramatsu #include <inat.c> 191ec454baSMasami Hiramatsu #include <insn.c> 201ec454baSMasami Hiramatsu 211ec454baSMasami Hiramatsu /* 221ec454baSMasami Hiramatsu * Test of instruction analysis against tampering. 231ec454baSMasami Hiramatsu * Feed random binary to instruction decoder and ensure not to 241ec454baSMasami Hiramatsu * access out-of-instruction-buffer. 251ec454baSMasami Hiramatsu */ 261ec454baSMasami Hiramatsu 271ec454baSMasami Hiramatsu #define DEFAULT_MAX_ITER 10000 281ec454baSMasami Hiramatsu #define INSN_NOP 0x90 291ec454baSMasami Hiramatsu 301ec454baSMasami Hiramatsu static const char *prog; /* Program name */ 311ec454baSMasami Hiramatsu static int verbose; /* Verbosity */ 321ec454baSMasami Hiramatsu static int x86_64; /* x86-64 bit mode flag */ 331ec454baSMasami Hiramatsu static unsigned int seed; /* Random seed */ 341ec454baSMasami Hiramatsu static unsigned long iter_start; /* Start of iteration number */ 351ec454baSMasami Hiramatsu static unsigned long iter_end = DEFAULT_MAX_ITER; /* End of iteration number */ 361ec454baSMasami Hiramatsu static FILE *input_file; /* Input file name */ 371ec454baSMasami Hiramatsu 381ec454baSMasami Hiramatsu static void usage(const char *err) 391ec454baSMasami Hiramatsu { 401ec454baSMasami Hiramatsu if (err) 4155a6e622SAndrew Morton fprintf(stderr, "%s: Error: %s\n\n", prog, err); 421ec454baSMasami Hiramatsu fprintf(stderr, "Usage: %s [-y|-n|-v] [-s seed[,no]] [-m max] [-i input]\n", prog); 431ec454baSMasami Hiramatsu fprintf(stderr, "\t-y 64bit mode\n"); 441ec454baSMasami Hiramatsu fprintf(stderr, "\t-n 32bit mode\n"); 459dde9dc0SMasami Hiramatsu fprintf(stderr, "\t-v Verbosity(-vv dumps any decoded result)\n"); 461ec454baSMasami Hiramatsu fprintf(stderr, "\t-s Give a random seed (and iteration number)\n"); 471ec454baSMasami Hiramatsu fprintf(stderr, "\t-m Give a maximum iteration number\n"); 481ec454baSMasami Hiramatsu fprintf(stderr, "\t-i Give an input file with decoded binary\n"); 491ec454baSMasami Hiramatsu exit(1); 501ec454baSMasami Hiramatsu } 511ec454baSMasami Hiramatsu 521ec454baSMasami Hiramatsu static void dump_field(FILE *fp, const char *name, const char *indent, 531ec454baSMasami Hiramatsu struct insn_field *field) 541ec454baSMasami Hiramatsu { 551ec454baSMasami Hiramatsu fprintf(fp, "%s.%s = {\n", indent, name); 561ec454baSMasami Hiramatsu fprintf(fp, "%s\t.value = %d, bytes[] = {%x, %x, %x, %x},\n", 571ec454baSMasami Hiramatsu indent, field->value, field->bytes[0], field->bytes[1], 581ec454baSMasami Hiramatsu field->bytes[2], field->bytes[3]); 591ec454baSMasami Hiramatsu fprintf(fp, "%s\t.got = %d, .nbytes = %d},\n", indent, 601ec454baSMasami Hiramatsu field->got, field->nbytes); 611ec454baSMasami Hiramatsu } 621ec454baSMasami Hiramatsu 631ec454baSMasami Hiramatsu static void dump_insn(FILE *fp, struct insn *insn) 641ec454baSMasami Hiramatsu { 651ec454baSMasami Hiramatsu fprintf(fp, "Instruction = {\n"); 661ec454baSMasami Hiramatsu dump_field(fp, "prefixes", "\t", &insn->prefixes); 671ec454baSMasami Hiramatsu dump_field(fp, "rex_prefix", "\t", &insn->rex_prefix); 681ec454baSMasami Hiramatsu dump_field(fp, "vex_prefix", "\t", &insn->vex_prefix); 691ec454baSMasami Hiramatsu dump_field(fp, "opcode", "\t", &insn->opcode); 701ec454baSMasami Hiramatsu dump_field(fp, "modrm", "\t", &insn->modrm); 711ec454baSMasami Hiramatsu dump_field(fp, "sib", "\t", &insn->sib); 721ec454baSMasami Hiramatsu dump_field(fp, "displacement", "\t", &insn->displacement); 731ec454baSMasami Hiramatsu dump_field(fp, "immediate1", "\t", &insn->immediate1); 741ec454baSMasami Hiramatsu dump_field(fp, "immediate2", "\t", &insn->immediate2); 751ec454baSMasami Hiramatsu fprintf(fp, "\t.attr = %x, .opnd_bytes = %d, .addr_bytes = %d,\n", 761ec454baSMasami Hiramatsu insn->attr, insn->opnd_bytes, insn->addr_bytes); 771ec454baSMasami Hiramatsu fprintf(fp, "\t.length = %d, .x86_64 = %d, .kaddr = %p}\n", 781ec454baSMasami Hiramatsu insn->length, insn->x86_64, insn->kaddr); 791ec454baSMasami Hiramatsu } 801ec454baSMasami Hiramatsu 811ec454baSMasami Hiramatsu static void dump_stream(FILE *fp, const char *msg, unsigned long nr_iter, 821fc654cfSIngo Molnar unsigned char *insn_buff, struct insn *insn) 831ec454baSMasami Hiramatsu { 841ec454baSMasami Hiramatsu int i; 851ec454baSMasami Hiramatsu 861ec454baSMasami Hiramatsu fprintf(fp, "%s:\n", msg); 871ec454baSMasami Hiramatsu 88e70825fcSMasami Hiramatsu dump_insn(fp, insn); 891ec454baSMasami Hiramatsu 901ec454baSMasami Hiramatsu fprintf(fp, "You can reproduce this with below command(s);\n"); 911ec454baSMasami Hiramatsu 921ec454baSMasami Hiramatsu /* Input a decoded instruction sequence directly */ 931ec454baSMasami Hiramatsu fprintf(fp, " $ echo "); 941ec454baSMasami Hiramatsu for (i = 0; i < MAX_INSN_SIZE; i++) 951fc654cfSIngo Molnar fprintf(fp, " %02x", insn_buff[i]); 961ec454baSMasami Hiramatsu fprintf(fp, " | %s -i -\n", prog); 971ec454baSMasami Hiramatsu 981ec454baSMasami Hiramatsu if (!input_file) { 991ec454baSMasami Hiramatsu fprintf(fp, "Or \n"); 1001ec454baSMasami Hiramatsu /* Give a seed and iteration number */ 1011ec454baSMasami Hiramatsu fprintf(fp, " $ %s -s 0x%x,%lu\n", prog, seed, nr_iter); 1021ec454baSMasami Hiramatsu } 1031ec454baSMasami Hiramatsu } 1041ec454baSMasami Hiramatsu 1051ec454baSMasami Hiramatsu static void init_random_seed(void) 1061ec454baSMasami Hiramatsu { 1071ec454baSMasami Hiramatsu int fd; 1081ec454baSMasami Hiramatsu 1091ec454baSMasami Hiramatsu fd = open("/dev/urandom", O_RDONLY); 1101ec454baSMasami Hiramatsu if (fd < 0) 1111ec454baSMasami Hiramatsu goto fail; 1121ec454baSMasami Hiramatsu 1131ec454baSMasami Hiramatsu if (read(fd, &seed, sizeof(seed)) != sizeof(seed)) 1141ec454baSMasami Hiramatsu goto fail; 1151ec454baSMasami Hiramatsu 1161ec454baSMasami Hiramatsu close(fd); 1171ec454baSMasami Hiramatsu return; 1181ec454baSMasami Hiramatsu fail: 1191ec454baSMasami Hiramatsu usage("Failed to open /dev/urandom"); 1201ec454baSMasami Hiramatsu } 1211ec454baSMasami Hiramatsu 1221ec454baSMasami Hiramatsu /* Read given instruction sequence from the input file */ 1231fc654cfSIngo Molnar static int read_next_insn(unsigned char *insn_buff) 1241ec454baSMasami Hiramatsu { 1251ec454baSMasami Hiramatsu char buf[256] = "", *tmp; 1261ec454baSMasami Hiramatsu int i; 1271ec454baSMasami Hiramatsu 1281ec454baSMasami Hiramatsu tmp = fgets(buf, ARRAY_SIZE(buf), input_file); 1291ec454baSMasami Hiramatsu if (tmp == NULL || feof(input_file)) 1301ec454baSMasami Hiramatsu return 0; 1311ec454baSMasami Hiramatsu 1321ec454baSMasami Hiramatsu for (i = 0; i < MAX_INSN_SIZE; i++) { 1331fc654cfSIngo Molnar insn_buff[i] = (unsigned char)strtoul(tmp, &tmp, 16); 1341ec454baSMasami Hiramatsu if (*tmp != ' ') 1351ec454baSMasami Hiramatsu break; 1361ec454baSMasami Hiramatsu } 1371ec454baSMasami Hiramatsu 1381ec454baSMasami Hiramatsu return i; 1391ec454baSMasami Hiramatsu } 1401ec454baSMasami Hiramatsu 1411fc654cfSIngo Molnar static int generate_insn(unsigned char *insn_buff) 1421ec454baSMasami Hiramatsu { 1431ec454baSMasami Hiramatsu int i; 1441ec454baSMasami Hiramatsu 1451ec454baSMasami Hiramatsu if (input_file) 1461fc654cfSIngo Molnar return read_next_insn(insn_buff); 1471ec454baSMasami Hiramatsu 1481ec454baSMasami Hiramatsu /* Fills buffer with random binary up to MAX_INSN_SIZE */ 1491ec454baSMasami Hiramatsu for (i = 0; i < MAX_INSN_SIZE - 1; i += 2) 1501fc654cfSIngo Molnar *(unsigned short *)(&insn_buff[i]) = random() & 0xffff; 1511ec454baSMasami Hiramatsu 1521ec454baSMasami Hiramatsu while (i < MAX_INSN_SIZE) 1531fc654cfSIngo Molnar insn_buff[i++] = random() & 0xff; 1541ec454baSMasami Hiramatsu 1551ec454baSMasami Hiramatsu return i; 1561ec454baSMasami Hiramatsu } 1571ec454baSMasami Hiramatsu 1581ec454baSMasami Hiramatsu static void parse_args(int argc, char **argv) 1591ec454baSMasami Hiramatsu { 1601ec454baSMasami Hiramatsu int c; 1611ec454baSMasami Hiramatsu char *tmp = NULL; 1621ec454baSMasami Hiramatsu int set_seed = 0; 1631ec454baSMasami Hiramatsu 1641ec454baSMasami Hiramatsu prog = argv[0]; 1651ec454baSMasami Hiramatsu while ((c = getopt(argc, argv, "ynvs:m:i:")) != -1) { 1661ec454baSMasami Hiramatsu switch (c) { 1671ec454baSMasami Hiramatsu case 'y': 1681ec454baSMasami Hiramatsu x86_64 = 1; 1691ec454baSMasami Hiramatsu break; 1701ec454baSMasami Hiramatsu case 'n': 1711ec454baSMasami Hiramatsu x86_64 = 0; 1721ec454baSMasami Hiramatsu break; 1731ec454baSMasami Hiramatsu case 'v': 1749dde9dc0SMasami Hiramatsu verbose++; 1751ec454baSMasami Hiramatsu break; 1761ec454baSMasami Hiramatsu case 'i': 1771ec454baSMasami Hiramatsu if (strcmp("-", optarg) == 0) 1781ec454baSMasami Hiramatsu input_file = stdin; 1791ec454baSMasami Hiramatsu else 1801ec454baSMasami Hiramatsu input_file = fopen(optarg, "r"); 1811ec454baSMasami Hiramatsu if (!input_file) 1821ec454baSMasami Hiramatsu usage("Failed to open input file"); 1831ec454baSMasami Hiramatsu break; 1841ec454baSMasami Hiramatsu case 's': 1851ec454baSMasami Hiramatsu seed = (unsigned int)strtoul(optarg, &tmp, 0); 1861ec454baSMasami Hiramatsu if (*tmp == ',') { 1871ec454baSMasami Hiramatsu optarg = tmp + 1; 1881ec454baSMasami Hiramatsu iter_start = strtoul(optarg, &tmp, 0); 1891ec454baSMasami Hiramatsu } 1901ec454baSMasami Hiramatsu if (*tmp != '\0' || tmp == optarg) 1911ec454baSMasami Hiramatsu usage("Failed to parse seed"); 1921ec454baSMasami Hiramatsu set_seed = 1; 1931ec454baSMasami Hiramatsu break; 1941ec454baSMasami Hiramatsu case 'm': 1951ec454baSMasami Hiramatsu iter_end = strtoul(optarg, &tmp, 0); 1961ec454baSMasami Hiramatsu if (*tmp != '\0' || tmp == optarg) 1971ec454baSMasami Hiramatsu usage("Failed to parse max_iter"); 1981ec454baSMasami Hiramatsu break; 1991ec454baSMasami Hiramatsu default: 2001ec454baSMasami Hiramatsu usage(NULL); 2011ec454baSMasami Hiramatsu } 2021ec454baSMasami Hiramatsu } 2031ec454baSMasami Hiramatsu 2041ec454baSMasami Hiramatsu /* Check errors */ 2051ec454baSMasami Hiramatsu if (iter_end < iter_start) 2061ec454baSMasami Hiramatsu usage("Max iteration number must be bigger than iter-num"); 2071ec454baSMasami Hiramatsu 2081ec454baSMasami Hiramatsu if (set_seed && input_file) 2091ec454baSMasami Hiramatsu usage("Don't use input file (-i) with random seed (-s)"); 2101ec454baSMasami Hiramatsu 2111ec454baSMasami Hiramatsu /* Initialize random seed */ 2121ec454baSMasami Hiramatsu if (!input_file) { 2131ec454baSMasami Hiramatsu if (!set_seed) /* No seed is given */ 2141ec454baSMasami Hiramatsu init_random_seed(); 2151ec454baSMasami Hiramatsu srand(seed); 2161ec454baSMasami Hiramatsu } 2171ec454baSMasami Hiramatsu } 2181ec454baSMasami Hiramatsu 2191ec454baSMasami Hiramatsu int main(int argc, char **argv) 2201ec454baSMasami Hiramatsu { 221*a277ce60SBorislav Petkov int insns = 0, ret; 2221ec454baSMasami Hiramatsu struct insn insn; 2231ec454baSMasami Hiramatsu int errors = 0; 2241ec454baSMasami Hiramatsu unsigned long i; 2251fc654cfSIngo Molnar unsigned char insn_buff[MAX_INSN_SIZE * 2]; 2261ec454baSMasami Hiramatsu 2271ec454baSMasami Hiramatsu parse_args(argc, argv); 2281ec454baSMasami Hiramatsu 2291ec454baSMasami Hiramatsu /* Prepare stop bytes with NOPs */ 2301fc654cfSIngo Molnar memset(insn_buff + MAX_INSN_SIZE, INSN_NOP, MAX_INSN_SIZE); 2311ec454baSMasami Hiramatsu 2321ec454baSMasami Hiramatsu for (i = 0; i < iter_end; i++) { 2331fc654cfSIngo Molnar if (generate_insn(insn_buff) <= 0) 2341ec454baSMasami Hiramatsu break; 2351ec454baSMasami Hiramatsu 2361ec454baSMasami Hiramatsu if (i < iter_start) /* Skip to given iteration number */ 2371ec454baSMasami Hiramatsu continue; 2381ec454baSMasami Hiramatsu 2391ec454baSMasami Hiramatsu /* Decode an instruction */ 240*a277ce60SBorislav Petkov ret = insn_decode(&insn, insn_buff, sizeof(insn_buff), 241*a277ce60SBorislav Petkov x86_64 ? INSN_MODE_64 : INSN_MODE_32); 2421ec454baSMasami Hiramatsu 2431ec454baSMasami Hiramatsu if (insn.next_byte <= insn.kaddr || 2441ec454baSMasami Hiramatsu insn.kaddr + MAX_INSN_SIZE < insn.next_byte) { 2451ec454baSMasami Hiramatsu /* Access out-of-range memory */ 2461fc654cfSIngo Molnar dump_stream(stderr, "Error: Found an access violation", i, insn_buff, &insn); 2471ec454baSMasami Hiramatsu errors++; 248*a277ce60SBorislav Petkov } else if (verbose && ret < 0) 2491fc654cfSIngo Molnar dump_stream(stdout, "Info: Found an undecodable input", i, insn_buff, &insn); 2509dde9dc0SMasami Hiramatsu else if (verbose >= 2) 2519dde9dc0SMasami Hiramatsu dump_insn(stdout, &insn); 2521ec454baSMasami Hiramatsu insns++; 2531ec454baSMasami Hiramatsu } 2541ec454baSMasami Hiramatsu 255bb12d674SPaul Bolle fprintf((errors) ? stderr : stdout, 256bb12d674SPaul Bolle "%s: %s: decoded and checked %d %s instructions with %d errors (seed:0x%x)\n", 25755a6e622SAndrew Morton prog, 25855a6e622SAndrew Morton (errors) ? "Failure" : "Success", 25955a6e622SAndrew Morton insns, 26055a6e622SAndrew Morton (input_file) ? "given" : "random", 26155a6e622SAndrew Morton errors, 26255a6e622SAndrew Morton seed); 2631ec454baSMasami Hiramatsu 2641ec454baSMasami Hiramatsu return errors ? 1 : 0; 2651ec454baSMasami Hiramatsu } 266