18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT 28c2ecf20Sopenharmony_ci/* utility to create the register check tables 38c2ecf20Sopenharmony_ci * this includes inlined list.h safe for userspace. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2009 Jerome Glisse 68c2ecf20Sopenharmony_ci * Copyright 2009 Red Hat Inc. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Authors: 98c2ecf20Sopenharmony_ci * Jerome Glisse 108c2ecf20Sopenharmony_ci * Dave Airlie 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <sys/types.h> 148c2ecf20Sopenharmony_ci#include <stdlib.h> 158c2ecf20Sopenharmony_ci#include <string.h> 168c2ecf20Sopenharmony_ci#include <stdio.h> 178c2ecf20Sopenharmony_ci#include <regex.h> 188c2ecf20Sopenharmony_ci#include <libgen.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 218c2ecf20Sopenharmony_ci/** 228c2ecf20Sopenharmony_ci * container_of - cast a member of a structure out to the containing structure 238c2ecf20Sopenharmony_ci * @ptr: the pointer to the member. 248c2ecf20Sopenharmony_ci * @type: the type of the container struct this is embedded in. 258c2ecf20Sopenharmony_ci * @member: the name of the member within the struct. 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci#define container_of(ptr, type, member) ({ \ 298c2ecf20Sopenharmony_ci const typeof(((type *)0)->member)*__mptr = (ptr); \ 308c2ecf20Sopenharmony_ci (type *)((char *)__mptr - offsetof(type, member)); }) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * Simple doubly linked list implementation. 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * Some of the internal functions ("__xxx") are useful when 368c2ecf20Sopenharmony_ci * manipulating whole lists rather than single entries, as 378c2ecf20Sopenharmony_ci * sometimes we already know the next/prev entries and we can 388c2ecf20Sopenharmony_ci * generate better code by using them directly rather than 398c2ecf20Sopenharmony_ci * using the generic single-entry routines. 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistruct list_head { 438c2ecf20Sopenharmony_ci struct list_head *next, *prev; 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic inline void INIT_LIST_HEAD(struct list_head *list) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci list->next = list; 508c2ecf20Sopenharmony_ci list->prev = list; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* 548c2ecf20Sopenharmony_ci * Insert a new entry between two known consecutive entries. 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * This is only for internal list manipulation where we know 578c2ecf20Sopenharmony_ci * the prev/next entries already! 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_ci#ifndef CONFIG_DEBUG_LIST 608c2ecf20Sopenharmony_cistatic inline void __list_add(struct list_head *new, 618c2ecf20Sopenharmony_ci struct list_head *prev, struct list_head *next) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci next->prev = new; 648c2ecf20Sopenharmony_ci new->next = next; 658c2ecf20Sopenharmony_ci new->prev = prev; 668c2ecf20Sopenharmony_ci prev->next = new; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci#else 698c2ecf20Sopenharmony_ciextern void __list_add(struct list_head *new, 708c2ecf20Sopenharmony_ci struct list_head *prev, struct list_head *next); 718c2ecf20Sopenharmony_ci#endif 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/** 748c2ecf20Sopenharmony_ci * list_add_tail - add a new entry 758c2ecf20Sopenharmony_ci * @new: new entry to be added 768c2ecf20Sopenharmony_ci * @head: list head to add it before 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * Insert a new entry before the specified head. 798c2ecf20Sopenharmony_ci * This is useful for implementing queues. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_cistatic inline void list_add_tail(struct list_head *new, struct list_head *head) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci __list_add(new, head->prev, head); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/** 878c2ecf20Sopenharmony_ci * list_entry - get the struct for this entry 888c2ecf20Sopenharmony_ci * @ptr: the &struct list_head pointer. 898c2ecf20Sopenharmony_ci * @type: the type of the struct this is embedded in. 908c2ecf20Sopenharmony_ci * @member: the name of the list_head within the struct. 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_ci#define list_entry(ptr, type, member) \ 938c2ecf20Sopenharmony_ci container_of(ptr, type, member) 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/** 968c2ecf20Sopenharmony_ci * list_for_each_entry - iterate over list of given type 978c2ecf20Sopenharmony_ci * @pos: the type * to use as a loop cursor. 988c2ecf20Sopenharmony_ci * @head: the head for your list. 998c2ecf20Sopenharmony_ci * @member: the name of the list_head within the struct. 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_ci#define list_for_each_entry(pos, head, member) \ 1028c2ecf20Sopenharmony_ci for (pos = list_entry((head)->next, typeof(*pos), member); \ 1038c2ecf20Sopenharmony_ci &pos->member != (head); \ 1048c2ecf20Sopenharmony_ci pos = list_entry(pos->member.next, typeof(*pos), member)) 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistruct offset { 1078c2ecf20Sopenharmony_ci struct list_head list; 1088c2ecf20Sopenharmony_ci unsigned offset; 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistruct table { 1128c2ecf20Sopenharmony_ci struct list_head offsets; 1138c2ecf20Sopenharmony_ci unsigned offset_max; 1148c2ecf20Sopenharmony_ci unsigned nentry; 1158c2ecf20Sopenharmony_ci unsigned *table; 1168c2ecf20Sopenharmony_ci char *gpu_prefix; 1178c2ecf20Sopenharmony_ci}; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic struct offset *offset_new(unsigned o) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct offset *offset; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci offset = (struct offset *)malloc(sizeof(struct offset)); 1248c2ecf20Sopenharmony_ci if (offset) { 1258c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&offset->list); 1268c2ecf20Sopenharmony_ci offset->offset = o; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci return offset; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic void table_offset_add(struct table *t, struct offset *offset) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci list_add_tail(&offset->list, &t->offsets); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic void table_init(struct table *t) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&t->offsets); 1398c2ecf20Sopenharmony_ci t->offset_max = 0; 1408c2ecf20Sopenharmony_ci t->nentry = 0; 1418c2ecf20Sopenharmony_ci t->table = NULL; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic void table_print(struct table *t) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci unsigned nlloop, i, j, n, c, id; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci nlloop = (t->nentry + 3) / 4; 1498c2ecf20Sopenharmony_ci c = t->nentry; 1508c2ecf20Sopenharmony_ci printf("static const unsigned %s_reg_safe_bm[%d] = {\n", t->gpu_prefix, 1518c2ecf20Sopenharmony_ci t->nentry); 1528c2ecf20Sopenharmony_ci for (i = 0, id = 0; i < nlloop; i++) { 1538c2ecf20Sopenharmony_ci n = 4; 1548c2ecf20Sopenharmony_ci if (n > c) 1558c2ecf20Sopenharmony_ci n = c; 1568c2ecf20Sopenharmony_ci c -= n; 1578c2ecf20Sopenharmony_ci for (j = 0; j < n; j++) { 1588c2ecf20Sopenharmony_ci if (j == 0) 1598c2ecf20Sopenharmony_ci printf("\t"); 1608c2ecf20Sopenharmony_ci else 1618c2ecf20Sopenharmony_ci printf(" "); 1628c2ecf20Sopenharmony_ci printf("0x%08X,", t->table[id++]); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci printf("\n"); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci printf("};\n"); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic int table_build(struct table *t) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct offset *offset; 1728c2ecf20Sopenharmony_ci unsigned i, m; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci t->nentry = ((t->offset_max >> 2) + 31) / 32; 1758c2ecf20Sopenharmony_ci t->table = (unsigned *)malloc(sizeof(unsigned) * t->nentry); 1768c2ecf20Sopenharmony_ci if (t->table == NULL) 1778c2ecf20Sopenharmony_ci return -1; 1788c2ecf20Sopenharmony_ci memset(t->table, 0xff, sizeof(unsigned) * t->nentry); 1798c2ecf20Sopenharmony_ci list_for_each_entry(offset, &t->offsets, list) { 1808c2ecf20Sopenharmony_ci i = (offset->offset >> 2) / 32; 1818c2ecf20Sopenharmony_ci m = (offset->offset >> 2) & 31; 1828c2ecf20Sopenharmony_ci m = 1 << m; 1838c2ecf20Sopenharmony_ci t->table[i] ^= m; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic char gpu_name[10]; 1898c2ecf20Sopenharmony_cistatic int parser_auth(struct table *t, const char *filename) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci FILE *file; 1928c2ecf20Sopenharmony_ci regex_t mask_rex; 1938c2ecf20Sopenharmony_ci regmatch_t match[4]; 1948c2ecf20Sopenharmony_ci char buf[1024]; 1958c2ecf20Sopenharmony_ci size_t end; 1968c2ecf20Sopenharmony_ci int len; 1978c2ecf20Sopenharmony_ci int done = 0; 1988c2ecf20Sopenharmony_ci int r; 1998c2ecf20Sopenharmony_ci unsigned o; 2008c2ecf20Sopenharmony_ci struct offset *offset; 2018c2ecf20Sopenharmony_ci char last_reg_s[10]; 2028c2ecf20Sopenharmony_ci int last_reg; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci if (regcomp 2058c2ecf20Sopenharmony_ci (&mask_rex, "(0x[0-9a-fA-F]*) *([_a-zA-Z0-9]*)", REG_EXTENDED)) { 2068c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to compile regular expression\n"); 2078c2ecf20Sopenharmony_ci return -1; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci file = fopen(filename, "r"); 2108c2ecf20Sopenharmony_ci if (file == NULL) { 2118c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to open: %s\n", filename); 2128c2ecf20Sopenharmony_ci return -1; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci fseek(file, 0, SEEK_END); 2158c2ecf20Sopenharmony_ci end = ftell(file); 2168c2ecf20Sopenharmony_ci fseek(file, 0, SEEK_SET); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* get header */ 2198c2ecf20Sopenharmony_ci if (fgets(buf, 1024, file) == NULL) { 2208c2ecf20Sopenharmony_ci fclose(file); 2218c2ecf20Sopenharmony_ci return -1; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* first line will contain the last register 2258c2ecf20Sopenharmony_ci * and gpu name */ 2268c2ecf20Sopenharmony_ci sscanf(buf, "%9s %9s", gpu_name, last_reg_s); 2278c2ecf20Sopenharmony_ci t->gpu_prefix = gpu_name; 2288c2ecf20Sopenharmony_ci last_reg = strtol(last_reg_s, NULL, 16); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci do { 2318c2ecf20Sopenharmony_ci if (fgets(buf, 1024, file) == NULL) { 2328c2ecf20Sopenharmony_ci fclose(file); 2338c2ecf20Sopenharmony_ci return -1; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci len = strlen(buf); 2368c2ecf20Sopenharmony_ci if (ftell(file) == end) 2378c2ecf20Sopenharmony_ci done = 1; 2388c2ecf20Sopenharmony_ci if (len) { 2398c2ecf20Sopenharmony_ci r = regexec(&mask_rex, buf, 4, match, 0); 2408c2ecf20Sopenharmony_ci if (r == REG_NOMATCH) { 2418c2ecf20Sopenharmony_ci } else if (r) { 2428c2ecf20Sopenharmony_ci fprintf(stderr, 2438c2ecf20Sopenharmony_ci "Error matching regular expression %d in %s\n", 2448c2ecf20Sopenharmony_ci r, filename); 2458c2ecf20Sopenharmony_ci fclose(file); 2468c2ecf20Sopenharmony_ci return -1; 2478c2ecf20Sopenharmony_ci } else { 2488c2ecf20Sopenharmony_ci buf[match[0].rm_eo] = 0; 2498c2ecf20Sopenharmony_ci buf[match[1].rm_eo] = 0; 2508c2ecf20Sopenharmony_ci buf[match[2].rm_eo] = 0; 2518c2ecf20Sopenharmony_ci o = strtol(&buf[match[1].rm_so], NULL, 16); 2528c2ecf20Sopenharmony_ci offset = offset_new(o); 2538c2ecf20Sopenharmony_ci table_offset_add(t, offset); 2548c2ecf20Sopenharmony_ci if (o > t->offset_max) 2558c2ecf20Sopenharmony_ci t->offset_max = o; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci } while (!done); 2598c2ecf20Sopenharmony_ci fclose(file); 2608c2ecf20Sopenharmony_ci if (t->offset_max < last_reg) 2618c2ecf20Sopenharmony_ci t->offset_max = last_reg; 2628c2ecf20Sopenharmony_ci return table_build(t); 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ciint main(int argc, char *argv[]) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci struct table t; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (argc != 2) { 2708c2ecf20Sopenharmony_ci fprintf(stderr, "Usage: %s <authfile>\n", argv[0]); 2718c2ecf20Sopenharmony_ci exit(1); 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci table_init(&t); 2748c2ecf20Sopenharmony_ci if (parser_auth(&t, argv[1])) { 2758c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to parse file %s\n", argv[1]); 2768c2ecf20Sopenharmony_ci return -1; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci table_print(&t); 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci} 281