// SPDX-License-Identifier: MIT /* utility to create the register check tables * this includes inlined list.h safe for userspace. * * Copyright 2009 Jerome Glisse * Copyright 2009 Red Hat Inc. * * Authors: * Jerome Glisse * Dave Airlie */ #include #include #include #include #include #include #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) /** * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. * @type: the type of the container struct this is embedded in. * @member: the name of the member within the struct. * */ #define container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member)*__mptr = (ptr); \ (type *)((char *)__mptr - offsetof(type, member)); }) /* * Simple doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ struct list_head { struct list_head *next, *prev; }; static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; } /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ #ifndef CONFIG_DEBUG_LIST static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } #else extern void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next); #endif /** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static inline void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); } /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_head within the struct. */ #define list_entry(ptr, type, member) \ container_of(ptr, type, member) /** * list_for_each_entry - iterate over list of given type * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_head within the struct. */ #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) struct offset { struct list_head list; unsigned offset; }; struct table { struct list_head offsets; unsigned offset_max; unsigned nentry; unsigned *table; char *gpu_prefix; }; static struct offset *offset_new(unsigned o) { struct offset *offset; offset = (struct offset *)malloc(sizeof(struct offset)); if (offset) { INIT_LIST_HEAD(&offset->list); offset->offset = o; } return offset; } static void table_offset_add(struct table *t, struct offset *offset) { list_add_tail(&offset->list, &t->offsets); } static void table_init(struct table *t) { INIT_LIST_HEAD(&t->offsets); t->offset_max = 0; t->nentry = 0; t->table = NULL; } static void table_print(struct table *t) { unsigned nlloop, i, j, n, c, id; nlloop = (t->nentry + 3) / 4; c = t->nentry; printf("static const unsigned %s_reg_safe_bm[%d] = {\n", t->gpu_prefix, t->nentry); for (i = 0, id = 0; i < nlloop; i++) { n = 4; if (n > c) n = c; c -= n; for (j = 0; j < n; j++) { if (j == 0) printf("\t"); else printf(" "); printf("0x%08X,", t->table[id++]); } printf("\n"); } printf("};\n"); } static int table_build(struct table *t) { struct offset *offset; unsigned i, m; t->nentry = ((t->offset_max >> 2) + 31) / 32; t->table = (unsigned *)malloc(sizeof(unsigned) * t->nentry); if (t->table == NULL) return -1; memset(t->table, 0xff, sizeof(unsigned) * t->nentry); list_for_each_entry(offset, &t->offsets, list) { i = (offset->offset >> 2) / 32; m = (offset->offset >> 2) & 31; m = 1 << m; t->table[i] ^= m; } return 0; } static char gpu_name[10]; static int parser_auth(struct table *t, const char *filename) { FILE *file; regex_t mask_rex; regmatch_t match[4]; char buf[1024]; size_t end; int len; int done = 0; int r; unsigned o; struct offset *offset; char last_reg_s[10]; int last_reg; if (regcomp (&mask_rex, "(0x[0-9a-fA-F]*) *([_a-zA-Z0-9]*)", REG_EXTENDED)) { fprintf(stderr, "Failed to compile regular expression\n"); return -1; } file = fopen(filename, "r"); if (file == NULL) { fprintf(stderr, "Failed to open: %s\n", filename); return -1; } fseek(file, 0, SEEK_END); end = ftell(file); fseek(file, 0, SEEK_SET); /* get header */ if (fgets(buf, 1024, file) == NULL) { fclose(file); return -1; } /* first line will contain the last register * and gpu name */ sscanf(buf, "%9s %9s", gpu_name, last_reg_s); t->gpu_prefix = gpu_name; last_reg = strtol(last_reg_s, NULL, 16); do { if (fgets(buf, 1024, file) == NULL) { fclose(file); return -1; } len = strlen(buf); if (ftell(file) == end) done = 1; if (len) { r = regexec(&mask_rex, buf, 4, match, 0); if (r == REG_NOMATCH) { } else if (r) { fprintf(stderr, "Error matching regular expression %d in %s\n", r, filename); fclose(file); return -1; } else { buf[match[0].rm_eo] = 0; buf[match[1].rm_eo] = 0; buf[match[2].rm_eo] = 0; o = strtol(&buf[match[1].rm_so], NULL, 16); offset = offset_new(o); table_offset_add(t, offset); if (o > t->offset_max) t->offset_max = o; } } } while (!done); fclose(file); if (t->offset_max < last_reg) t->offset_max = last_reg; return table_build(t); } int main(int argc, char *argv[]) { struct table t; if (argc != 2) { fprintf(stderr, "Usage: %s \n", argv[0]); exit(1); } table_init(&t); if (parser_auth(&t, argv[1])) { fprintf(stderr, "Failed to parse file %s\n", argv[1]); return -1; } table_print(&t); return 0; }