162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT 262306a36Sopenharmony_ci/* utility to create the register check tables 362306a36Sopenharmony_ci * this includes inlined list.h safe for userspace. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2009 Jerome Glisse 662306a36Sopenharmony_ci * Copyright 2009 Red Hat Inc. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Authors: 962306a36Sopenharmony_ci * Jerome Glisse 1062306a36Sopenharmony_ci * Dave Airlie 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <sys/types.h> 1462306a36Sopenharmony_ci#include <stdlib.h> 1562306a36Sopenharmony_ci#include <string.h> 1662306a36Sopenharmony_ci#include <stdio.h> 1762306a36Sopenharmony_ci#include <regex.h> 1862306a36Sopenharmony_ci#include <libgen.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 2162306a36Sopenharmony_ci/** 2262306a36Sopenharmony_ci * container_of - cast a member of a structure out to the containing structure 2362306a36Sopenharmony_ci * @ptr: the pointer to the member. 2462306a36Sopenharmony_ci * @type: the type of the container struct this is embedded in. 2562306a36Sopenharmony_ci * @member: the name of the member within the struct. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci#define container_of(ptr, type, member) ({ \ 2962306a36Sopenharmony_ci const typeof(((type *)0)->member)*__mptr = (ptr); \ 3062306a36Sopenharmony_ci (type *)((char *)__mptr - offsetof(type, member)); }) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* 3362306a36Sopenharmony_ci * Simple doubly linked list implementation. 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * Some of the internal functions ("__xxx") are useful when 3662306a36Sopenharmony_ci * manipulating whole lists rather than single entries, as 3762306a36Sopenharmony_ci * sometimes we already know the next/prev entries and we can 3862306a36Sopenharmony_ci * generate better code by using them directly rather than 3962306a36Sopenharmony_ci * using the generic single-entry routines. 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistruct list_head { 4362306a36Sopenharmony_ci struct list_head *next, *prev; 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic inline void INIT_LIST_HEAD(struct list_head *list) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci list->next = list; 5062306a36Sopenharmony_ci list->prev = list; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* 5462306a36Sopenharmony_ci * Insert a new entry between two known consecutive entries. 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * This is only for internal list manipulation where we know 5762306a36Sopenharmony_ci * the prev/next entries already! 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_ci#ifndef CONFIG_DEBUG_LIST 6062306a36Sopenharmony_cistatic inline void __list_add(struct list_head *new, 6162306a36Sopenharmony_ci struct list_head *prev, struct list_head *next) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci next->prev = new; 6462306a36Sopenharmony_ci new->next = next; 6562306a36Sopenharmony_ci new->prev = prev; 6662306a36Sopenharmony_ci prev->next = new; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci#else 6962306a36Sopenharmony_ciextern void __list_add(struct list_head *new, 7062306a36Sopenharmony_ci struct list_head *prev, struct list_head *next); 7162306a36Sopenharmony_ci#endif 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/** 7462306a36Sopenharmony_ci * list_add_tail - add a new entry 7562306a36Sopenharmony_ci * @new: new entry to be added 7662306a36Sopenharmony_ci * @head: list head to add it before 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * Insert a new entry before the specified head. 7962306a36Sopenharmony_ci * This is useful for implementing queues. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_cistatic inline void list_add_tail(struct list_head *new, struct list_head *head) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci __list_add(new, head->prev, head); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/** 8762306a36Sopenharmony_ci * list_entry - get the struct for this entry 8862306a36Sopenharmony_ci * @ptr: the &struct list_head pointer. 8962306a36Sopenharmony_ci * @type: the type of the struct this is embedded in. 9062306a36Sopenharmony_ci * @member: the name of the list_head within the struct. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci#define list_entry(ptr, type, member) \ 9362306a36Sopenharmony_ci container_of(ptr, type, member) 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci/** 9662306a36Sopenharmony_ci * list_for_each_entry - iterate over list of given type 9762306a36Sopenharmony_ci * @pos: the type * to use as a loop cursor. 9862306a36Sopenharmony_ci * @head: the head for your list. 9962306a36Sopenharmony_ci * @member: the name of the list_head within the struct. 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_ci#define list_for_each_entry(pos, head, member) \ 10262306a36Sopenharmony_ci for (pos = list_entry((head)->next, typeof(*pos), member); \ 10362306a36Sopenharmony_ci &pos->member != (head); \ 10462306a36Sopenharmony_ci pos = list_entry(pos->member.next, typeof(*pos), member)) 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistruct offset { 10762306a36Sopenharmony_ci struct list_head list; 10862306a36Sopenharmony_ci unsigned offset; 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistruct table { 11262306a36Sopenharmony_ci struct list_head offsets; 11362306a36Sopenharmony_ci unsigned offset_max; 11462306a36Sopenharmony_ci unsigned nentry; 11562306a36Sopenharmony_ci unsigned *table; 11662306a36Sopenharmony_ci char *gpu_prefix; 11762306a36Sopenharmony_ci}; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic struct offset *offset_new(unsigned o) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci struct offset *offset; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci offset = (struct offset *)malloc(sizeof(struct offset)); 12462306a36Sopenharmony_ci if (offset) { 12562306a36Sopenharmony_ci INIT_LIST_HEAD(&offset->list); 12662306a36Sopenharmony_ci offset->offset = o; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci return offset; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic void table_offset_add(struct table *t, struct offset *offset) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci list_add_tail(&offset->list, &t->offsets); 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic void table_init(struct table *t) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci INIT_LIST_HEAD(&t->offsets); 13962306a36Sopenharmony_ci t->offset_max = 0; 14062306a36Sopenharmony_ci t->nentry = 0; 14162306a36Sopenharmony_ci t->table = NULL; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic void table_print(struct table *t) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci unsigned nlloop, i, j, n, c, id; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci nlloop = (t->nentry + 3) / 4; 14962306a36Sopenharmony_ci c = t->nentry; 15062306a36Sopenharmony_ci printf("static const unsigned %s_reg_safe_bm[%d] = {\n", t->gpu_prefix, 15162306a36Sopenharmony_ci t->nentry); 15262306a36Sopenharmony_ci for (i = 0, id = 0; i < nlloop; i++) { 15362306a36Sopenharmony_ci n = 4; 15462306a36Sopenharmony_ci if (n > c) 15562306a36Sopenharmony_ci n = c; 15662306a36Sopenharmony_ci c -= n; 15762306a36Sopenharmony_ci for (j = 0; j < n; j++) { 15862306a36Sopenharmony_ci if (j == 0) 15962306a36Sopenharmony_ci printf("\t"); 16062306a36Sopenharmony_ci else 16162306a36Sopenharmony_ci printf(" "); 16262306a36Sopenharmony_ci printf("0x%08X,", t->table[id++]); 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci printf("\n"); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci printf("};\n"); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic int table_build(struct table *t) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct offset *offset; 17262306a36Sopenharmony_ci unsigned i, m; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci t->nentry = ((t->offset_max >> 2) + 31) / 32; 17562306a36Sopenharmony_ci t->table = (unsigned *)malloc(sizeof(unsigned) * t->nentry); 17662306a36Sopenharmony_ci if (t->table == NULL) 17762306a36Sopenharmony_ci return -1; 17862306a36Sopenharmony_ci memset(t->table, 0xff, sizeof(unsigned) * t->nentry); 17962306a36Sopenharmony_ci list_for_each_entry(offset, &t->offsets, list) { 18062306a36Sopenharmony_ci i = (offset->offset >> 2) / 32; 18162306a36Sopenharmony_ci m = (offset->offset >> 2) & 31; 18262306a36Sopenharmony_ci m = 1 << m; 18362306a36Sopenharmony_ci t->table[i] ^= m; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci return 0; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic char gpu_name[10]; 18962306a36Sopenharmony_cistatic int parser_auth(struct table *t, const char *filename) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci FILE *file; 19262306a36Sopenharmony_ci regex_t mask_rex; 19362306a36Sopenharmony_ci regmatch_t match[4]; 19462306a36Sopenharmony_ci char buf[1024]; 19562306a36Sopenharmony_ci size_t end; 19662306a36Sopenharmony_ci int len; 19762306a36Sopenharmony_ci int done = 0; 19862306a36Sopenharmony_ci int r; 19962306a36Sopenharmony_ci unsigned o; 20062306a36Sopenharmony_ci struct offset *offset; 20162306a36Sopenharmony_ci char last_reg_s[10]; 20262306a36Sopenharmony_ci int last_reg; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (regcomp 20562306a36Sopenharmony_ci (&mask_rex, "(0x[0-9a-fA-F]*) *([_a-zA-Z0-9]*)", REG_EXTENDED)) { 20662306a36Sopenharmony_ci fprintf(stderr, "Failed to compile regular expression\n"); 20762306a36Sopenharmony_ci return -1; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci file = fopen(filename, "r"); 21062306a36Sopenharmony_ci if (file == NULL) { 21162306a36Sopenharmony_ci fprintf(stderr, "Failed to open: %s\n", filename); 21262306a36Sopenharmony_ci return -1; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci fseek(file, 0, SEEK_END); 21562306a36Sopenharmony_ci end = ftell(file); 21662306a36Sopenharmony_ci fseek(file, 0, SEEK_SET); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* get header */ 21962306a36Sopenharmony_ci if (fgets(buf, 1024, file) == NULL) { 22062306a36Sopenharmony_ci fclose(file); 22162306a36Sopenharmony_ci return -1; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* first line will contain the last register 22562306a36Sopenharmony_ci * and gpu name */ 22662306a36Sopenharmony_ci sscanf(buf, "%9s %9s", gpu_name, last_reg_s); 22762306a36Sopenharmony_ci t->gpu_prefix = gpu_name; 22862306a36Sopenharmony_ci last_reg = strtol(last_reg_s, NULL, 16); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci do { 23162306a36Sopenharmony_ci if (fgets(buf, 1024, file) == NULL) { 23262306a36Sopenharmony_ci fclose(file); 23362306a36Sopenharmony_ci return -1; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci len = strlen(buf); 23662306a36Sopenharmony_ci if (ftell(file) == end) 23762306a36Sopenharmony_ci done = 1; 23862306a36Sopenharmony_ci if (len) { 23962306a36Sopenharmony_ci r = regexec(&mask_rex, buf, 4, match, 0); 24062306a36Sopenharmony_ci if (r == REG_NOMATCH) { 24162306a36Sopenharmony_ci } else if (r) { 24262306a36Sopenharmony_ci fprintf(stderr, 24362306a36Sopenharmony_ci "Error matching regular expression %d in %s\n", 24462306a36Sopenharmony_ci r, filename); 24562306a36Sopenharmony_ci fclose(file); 24662306a36Sopenharmony_ci return -1; 24762306a36Sopenharmony_ci } else { 24862306a36Sopenharmony_ci buf[match[0].rm_eo] = 0; 24962306a36Sopenharmony_ci buf[match[1].rm_eo] = 0; 25062306a36Sopenharmony_ci buf[match[2].rm_eo] = 0; 25162306a36Sopenharmony_ci o = strtol(&buf[match[1].rm_so], NULL, 16); 25262306a36Sopenharmony_ci offset = offset_new(o); 25362306a36Sopenharmony_ci table_offset_add(t, offset); 25462306a36Sopenharmony_ci if (o > t->offset_max) 25562306a36Sopenharmony_ci t->offset_max = o; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci } while (!done); 25962306a36Sopenharmony_ci fclose(file); 26062306a36Sopenharmony_ci if (t->offset_max < last_reg) 26162306a36Sopenharmony_ci t->offset_max = last_reg; 26262306a36Sopenharmony_ci return table_build(t); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ciint main(int argc, char *argv[]) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci struct table t; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (argc != 2) { 27062306a36Sopenharmony_ci fprintf(stderr, "Usage: %s <authfile>\n", argv[0]); 27162306a36Sopenharmony_ci exit(1); 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci table_init(&t); 27462306a36Sopenharmony_ci if (parser_auth(&t, argv[1])) { 27562306a36Sopenharmony_ci fprintf(stderr, "Failed to parse file %s\n", argv[1]); 27662306a36Sopenharmony_ci return -1; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci table_print(&t); 27962306a36Sopenharmony_ci return 0; 28062306a36Sopenharmony_ci} 281