1 // SPDX-License-Identifier: MIT 2 /* utility to create the register check tables 3 * this includes inlined list.h safe for userspace. 4 * 5 * Copyright 2009 Jerome Glisse 6 * Copyright 2009 Red Hat Inc. 7 * 8 * Authors: 9 * Jerome Glisse 10 * Dave Airlie 11 */ 12 13 #include <sys/types.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <stdio.h> 17 #include <regex.h> 18 #include <libgen.h> 19 20 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 21 /** 22 * container_of - cast a member of a structure out to the containing structure 23 * @ptr: the pointer to the member. 24 * @type: the type of the container struct this is embedded in. 25 * @member: the name of the member within the struct. 26 * 27 */ 28 #define container_of(ptr, type, member) ({ \ 29 const typeof(((type *)0)->member)*__mptr = (ptr); \ 30 (type *)((char *)__mptr - offsetof(type, member)); }) 31 32 /* 33 * Simple doubly linked list implementation. 34 * 35 * Some of the internal functions ("__xxx") are useful when 36 * manipulating whole lists rather than single entries, as 37 * sometimes we already know the next/prev entries and we can 38 * generate better code by using them directly rather than 39 * using the generic single-entry routines. 40 */ 41 42 struct list_head { 43 struct list_head *next, *prev; 44 }; 45 46 47 static inline void INIT_LIST_HEAD(struct list_head *list) 48 { 49 list->next = list; 50 list->prev = list; 51 } 52 53 /* 54 * Insert a new entry between two known consecutive entries. 55 * 56 * This is only for internal list manipulation where we know 57 * the prev/next entries already! 58 */ 59 #ifndef CONFIG_DEBUG_LIST 60 static inline void __list_add(struct list_head *new, 61 struct list_head *prev, struct list_head *next) 62 { 63 next->prev = new; 64 new->next = next; 65 new->prev = prev; 66 prev->next = new; 67 } 68 #else 69 extern void __list_add(struct list_head *new, 70 struct list_head *prev, struct list_head *next); 71 #endif 72 73 /** 74 * list_add_tail - add a new entry 75 * @new: new entry to be added 76 * @head: list head to add it before 77 * 78 * Insert a new entry before the specified head. 79 * This is useful for implementing queues. 80 */ 81 static inline void list_add_tail(struct list_head *new, struct list_head *head) 82 { 83 __list_add(new, head->prev, head); 84 } 85 86 /** 87 * list_entry - get the struct for this entry 88 * @ptr: the &struct list_head pointer. 89 * @type: the type of the struct this is embedded in. 90 * @member: the name of the list_head within the struct. 91 */ 92 #define list_entry(ptr, type, member) \ 93 container_of(ptr, type, member) 94 95 /** 96 * list_for_each_entry - iterate over list of given type 97 * @pos: the type * to use as a loop cursor. 98 * @head: the head for your list. 99 * @member: the name of the list_head within the struct. 100 */ 101 #define list_for_each_entry(pos, head, member) \ 102 for (pos = list_entry((head)->next, typeof(*pos), member); \ 103 &pos->member != (head); \ 104 pos = list_entry(pos->member.next, typeof(*pos), member)) 105 106 struct offset { 107 struct list_head list; 108 unsigned offset; 109 }; 110 111 struct table { 112 struct list_head offsets; 113 unsigned offset_max; 114 unsigned nentry; 115 unsigned *table; 116 char *gpu_prefix; 117 }; 118 119 static struct offset *offset_new(unsigned o) 120 { 121 struct offset *offset; 122 123 offset = (struct offset *)malloc(sizeof(struct offset)); 124 if (offset) { 125 INIT_LIST_HEAD(&offset->list); 126 offset->offset = o; 127 } 128 return offset; 129 } 130 131 static void table_offset_add(struct table *t, struct offset *offset) 132 { 133 list_add_tail(&offset->list, &t->offsets); 134 } 135 136 static void table_init(struct table *t) 137 { 138 INIT_LIST_HEAD(&t->offsets); 139 t->offset_max = 0; 140 t->nentry = 0; 141 t->table = NULL; 142 } 143 144 static void table_print(struct table *t) 145 { 146 unsigned nlloop, i, j, n, c, id; 147 148 nlloop = (t->nentry + 3) / 4; 149 c = t->nentry; 150 printf("static const unsigned %s_reg_safe_bm[%d] = {\n", t->gpu_prefix, 151 t->nentry); 152 for (i = 0, id = 0; i < nlloop; i++) { 153 n = 4; 154 if (n > c) 155 n = c; 156 c -= n; 157 for (j = 0; j < n; j++) { 158 if (j == 0) 159 printf("\t"); 160 else 161 printf(" "); 162 printf("0x%08X,", t->table[id++]); 163 } 164 printf("\n"); 165 } 166 printf("};\n"); 167 } 168 169 static int table_build(struct table *t) 170 { 171 struct offset *offset; 172 unsigned i, m; 173 174 t->nentry = ((t->offset_max >> 2) + 31) / 32; 175 t->table = (unsigned *)malloc(sizeof(unsigned) * t->nentry); 176 if (t->table == NULL) 177 return -1; 178 memset(t->table, 0xff, sizeof(unsigned) * t->nentry); 179 list_for_each_entry(offset, &t->offsets, list) { 180 i = (offset->offset >> 2) / 32; 181 m = (offset->offset >> 2) & 31; 182 m = 1 << m; 183 t->table[i] ^= m; 184 } 185 return 0; 186 } 187 188 static char gpu_name[10]; 189 static int parser_auth(struct table *t, const char *filename) 190 { 191 FILE *file; 192 regex_t mask_rex; 193 regmatch_t match[4]; 194 char buf[1024]; 195 size_t end; 196 int len; 197 int done = 0; 198 int r; 199 unsigned o; 200 struct offset *offset; 201 char last_reg_s[10]; 202 int last_reg; 203 204 if (regcomp 205 (&mask_rex, "(0x[0-9a-fA-F]*) *([_a-zA-Z0-9]*)", REG_EXTENDED)) { 206 fprintf(stderr, "Failed to compile regular expression\n"); 207 return -1; 208 } 209 file = fopen(filename, "r"); 210 if (file == NULL) { 211 fprintf(stderr, "Failed to open: %s\n", filename); 212 return -1; 213 } 214 fseek(file, 0, SEEK_END); 215 end = ftell(file); 216 fseek(file, 0, SEEK_SET); 217 218 /* get header */ 219 if (fgets(buf, 1024, file) == NULL) { 220 fclose(file); 221 return -1; 222 } 223 224 /* first line will contain the last register 225 * and gpu name */ 226 sscanf(buf, "%9s %9s", gpu_name, last_reg_s); 227 t->gpu_prefix = gpu_name; 228 last_reg = strtol(last_reg_s, NULL, 16); 229 230 do { 231 if (fgets(buf, 1024, file) == NULL) { 232 fclose(file); 233 return -1; 234 } 235 len = strlen(buf); 236 if (ftell(file) == end) 237 done = 1; 238 if (len) { 239 r = regexec(&mask_rex, buf, 4, match, 0); 240 if (r == REG_NOMATCH) { 241 } else if (r) { 242 fprintf(stderr, 243 "Error matching regular expression %d in %s\n", 244 r, filename); 245 fclose(file); 246 return -1; 247 } else { 248 buf[match[0].rm_eo] = 0; 249 buf[match[1].rm_eo] = 0; 250 buf[match[2].rm_eo] = 0; 251 o = strtol(&buf[match[1].rm_so], NULL, 16); 252 offset = offset_new(o); 253 table_offset_add(t, offset); 254 if (o > t->offset_max) 255 t->offset_max = o; 256 } 257 } 258 } while (!done); 259 fclose(file); 260 if (t->offset_max < last_reg) 261 t->offset_max = last_reg; 262 return table_build(t); 263 } 264 265 int main(int argc, char *argv[]) 266 { 267 struct table t; 268 269 if (argc != 2) { 270 fprintf(stderr, "Usage: %s <authfile>\n", argv[0]); 271 exit(1); 272 } 273 table_init(&t); 274 if (parser_auth(&t, argv[1])) { 275 fprintf(stderr, "Failed to parse file %s\n", argv[1]); 276 return -1; 277 } 278 table_print(&t); 279 return 0; 280 } 281