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