cregit-Linux how code gets into the kernel

Release 4.15 arch/s390/tools/gen_opcode_table.c

Directory: arch/s390/tools
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Generate opcode table initializers for the in-kernel disassembler.
 *
 *    Copyright IBM Corp. 2017
 *
 */

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>


#define STRING_SIZE_MAX 20


struct insn_type {
	
unsigned char byte;
	
unsigned char mask;
	
char **format;
};


struct insn {
	
struct insn_type *type;
	
char opcode[STRING_SIZE_MAX];
	
char name[STRING_SIZE_MAX];
	
char upper[STRING_SIZE_MAX];
	
char format[STRING_SIZE_MAX];
	
unsigned int name_len;
};


struct insn_group {
	
struct insn_type *type;
	
int offset;
	
int count;
	
char opcode[2];
};


struct insn_format {
	
char *format;
	
int type;
};


struct gen_opcode {
	
struct insn *insn;
	
int nr;
	
struct insn_group *group;
	
int nr_groups;
};

/*
 * Table of instruction format types. Each opcode is defined with at
 * least one byte (two nibbles), three nibbles, or two bytes (four
 * nibbles).
 * The byte member of each instruction format type entry defines
 * within which byte of an instruction the third (and fourth) nibble
 * of an opcode can be found. The mask member is the and-mask that
 * needs to be applied on this byte in order to get the third (and
 * fourth) nibble of the opcode.
 * The format array defines all instruction formats (as defined in the
 * Principles of Operation) which have the same position of the opcode
 * nibbles.
 * A special case are instruction formats with 1-byte opcodes. In this
 * case the byte member always is zero, so that the mask is applied on
 * the (only) byte that contains the opcode.
 */

static struct insn_type insn_type_table[] = {
	{
		.byte = 0,
		.mask = 0xff,
		.format = (char *[]) {
			"MII",
			"RR",
			"RS",
			"RSI",
			"RX",
			"SI",
			"SMI",
			"SS",
			NULL,
                },
        },
	{
		.byte = 1,
		.mask = 0x0f,
		.format = (char *[]) {
			"RI",
			"RIL",
			"SSF",
			NULL,
                },
        },
	{
		.byte = 1,
		.mask = 0xff,
		.format = (char *[]) {
			"E",
			"IE",
			"RRE",
			"RRF",
			"RRR",
			"S",
			"SIL",
			"SSE",
			NULL,
                },
        },
	{
		.byte = 5,
		.mask = 0xff,
		.format = (char *[]) {
			"RIE",
			"RIS",
			"RRS",
			"RSE",
			"RSL",
			"RSY",
			"RXE",
			"RXF",
			"RXY",
			"SIY",
			"VRI",
			"VRR",
			"VRS",
			"VRV",
			"VRX",
			"VSI",
			NULL,
                },
        },
};


static struct insn_type *insn_format_to_type(char *format) { char tmp[STRING_SIZE_MAX]; char *base_format, **ptr; int i; strcpy(tmp, format); base_format = tmp; base_format = strsep(&base_format, "_"); for (i = 0; i < sizeof(insn_type_table) / sizeof(insn_type_table[0]); i++) { ptr = insn_type_table[i].format; while (*ptr) { if (!strcmp(base_format, *ptr)) return &insn_type_table[i]; ptr++; } } exit(EXIT_FAILURE); }

Contributors

PersonTokensPropCommitsCommitProp
Heiko Carstens118100.00%1100.00%
Total118100.00%1100.00%


static void read_instructions(struct gen_opcode *desc) { struct insn insn; int rc, i; while (1) { rc = scanf("%s %s %s", insn.opcode, insn.name, insn.format); if (rc == EOF) break; if (rc != 3) exit(EXIT_FAILURE); insn.type = insn_format_to_type(insn.format); insn.name_len = strlen(insn.name); for (i = 0; i <= insn.name_len; i++) insn.upper[i] = toupper((unsigned char)insn.name[i]); desc->nr++; desc->insn = realloc(desc->insn, desc->nr * sizeof(*desc->insn)); if (!desc->insn) exit(EXIT_FAILURE); desc->insn[desc->nr - 1] = insn; } }

Contributors

PersonTokensPropCommitsCommitProp
Heiko Carstens174100.00%1100.00%
Total174100.00%1100.00%


static int cmpformat(const void *a, const void *b) { return strcmp(((struct insn *)a)->format, ((struct insn *)b)->format); }

Contributors

PersonTokensPropCommitsCommitProp
Heiko Carstens42100.00%1100.00%
Total42100.00%1100.00%


static void print_formats(struct gen_opcode *desc) { char *format; int i, count; qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmpformat); format = ""; count = 0; printf("enum {\n"); for (i = 0; i < desc->nr; i++) { if (!strcmp(format, desc->insn[i].format)) continue; count++; format = desc->insn[i].format; printf("\tINSTR_%s,\n", format); } printf("}; /* %d */\n\n", count); }

Contributors

PersonTokensPropCommitsCommitProp
Heiko Carstens117100.00%1100.00%
Total117100.00%1100.00%


static int cmp_long_insn(const void *a, const void *b) { return strcmp(((struct insn *)a)->name, ((struct insn *)b)->name); }

Contributors

PersonTokensPropCommitsCommitProp
Heiko Carstens42100.00%1100.00%
Total42100.00%1100.00%


static void print_long_insn(struct gen_opcode *desc) { struct insn *insn; int i, count; qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmp_long_insn); count = 0; printf("enum {\n"); for (i = 0; i < desc->nr; i++) { insn = &desc->insn[i]; if (insn->name_len < 6) continue; printf("\tLONG_INSN_%s,\n", insn->upper); count++; } printf("}; /* %d */\n\n", count); printf("#define LONG_INSN_INITIALIZER { \\\n"); for (i = 0; i < desc->nr; i++) { insn = &desc->insn[i]; if (insn->name_len < 6) continue; printf("\t[LONG_INSN_%s] = \"%s\", \\\n", insn->upper, insn->name); } printf("}\n\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Heiko Carstens165100.00%1100.00%
Total165100.00%1100.00%


static void print_opcode(struct insn *insn, int nr) { char *opcode; opcode = insn->opcode; if (insn->type->byte != 0) opcode += 2; printf("\t[%4d] = { .opfrag = 0x%s, .format = INSTR_%s, ", nr, opcode, insn->format); if (insn->name_len < 6) printf(".name = \"%s\" ", insn->name); else printf(".offset = LONG_INSN_%s ", insn->upper); printf("}, \\\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Heiko Carstens83100.00%1100.00%
Total83100.00%1100.00%


static void add_to_group(struct gen_opcode *desc, struct insn *insn, int offset) { struct insn_group *group; group = desc->group ? &desc->group[desc->nr_groups - 1] : NULL; if (group && (!strncmp(group->opcode, insn->opcode, 2) || group->type->byte == 0)) { group->count++; return; } desc->nr_groups++; desc->group = realloc(desc->group, desc->nr_groups * sizeof(*desc->group)); if (!desc->group) exit(EXIT_FAILURE); group = &desc->group[desc->nr_groups - 1]; strncpy(group->opcode, insn->opcode, 2); group->type = insn->type; group->offset = offset; group->count = 1; }

Contributors

PersonTokensPropCommitsCommitProp
Heiko Carstens167100.00%1100.00%
Total167100.00%1100.00%


static int cmpopcode(const void *a, const void *b) { return strcmp(((struct insn *)a)->opcode, ((struct insn *)b)->opcode); }

Contributors

PersonTokensPropCommitsCommitProp
Heiko Carstens42100.00%1100.00%
Total42100.00%1100.00%


static void print_opcode_table(struct gen_opcode *desc) { char opcode[2] = ""; struct insn *insn; int i, offset; qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmpopcode); printf("#define OPCODE_TABLE_INITIALIZER { \\\n"); offset = 0; for (i = 0; i < desc->nr; i++) { insn = &desc->insn[i]; if (insn->type->byte == 0) continue; add_to_group(desc, insn, offset); if (strncmp(opcode, insn->opcode, 2)) { strncpy(opcode, insn->opcode, 2); printf("\t/* %.2s */ \\\n", opcode); } print_opcode(insn, offset); offset++; } printf("\t/* 1-byte opcode instructions */ \\\n"); for (i = 0; i < desc->nr; i++) { insn = &desc->insn[i]; if (insn->type->byte != 0) continue; add_to_group(desc, insn, offset); print_opcode(insn, offset); offset++; } printf("}\n\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Heiko Carstens216100.00%1100.00%
Total216100.00%1100.00%


static void print_opcode_table_offsets(struct gen_opcode *desc) { struct insn_group *group; int i; printf("#define OPCODE_OFFSET_INITIALIZER { \\\n"); for (i = 0; i < desc->nr_groups; i++) { group = &desc->group[i]; printf("\t{ .opcode = 0x%.2s, .mask = 0x%02x, .byte = %d, .offset = %d, .count = %d }, \\\n", group->opcode, group->type->mask, group->type->byte, group->offset, group->count); } printf("}\n\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Heiko Carstens85100.00%1100.00%
Total85100.00%1100.00%


int main(int argc, char **argv) { struct gen_opcode _desc = { 0 }; struct gen_opcode *desc = &_desc; read_instructions(desc); printf("#ifndef __S390_GENERATED_DIS_H__\n"); printf("#define __S390_GENERATED_DIS_H__\n"); printf("/*\n"); printf(" * DO NOT MODIFY.\n"); printf(" *\n"); printf(" * This file was generated by %s\n", __FILE__); printf(" */\n\n"); print_formats(desc); print_long_insn(desc); print_opcode_table(desc); print_opcode_table_offsets(desc); printf("#endif\n"); exit(EXIT_SUCCESS); }

Contributors

PersonTokensPropCommitsCommitProp
Heiko Carstens101100.00%1100.00%
Total101100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Heiko Carstens165599.94%150.00%
Martin Schwidefsky10.06%150.00%
Total1656100.00%2100.00%
Directory: arch/s390/tools
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.