Greg Kroah-Hartman | b244131 | 2017-11-01 15:07:57 +0100 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 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) ({ \ |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 29 | const typeof(((type *)0)->member)*__mptr = (ptr); \ |
| 30 | (type *)((char *)__mptr - offsetof(type, member)); }) |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 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 | |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 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, |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 61 | struct list_head *prev, struct list_head *next) |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 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, |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 70 | struct list_head *prev, struct list_head *next); |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 71 | #endif |
| 72 | |
| 73 | /** |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 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 | |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 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. |
Andrey Utkin | 3943f42 | 2014-11-14 05:09:55 +0400 | [diff] [blame] | 90 | * @member: the name of the list_head within the struct. |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 91 | */ |
| 92 | #define list_entry(ptr, type, member) \ |
| 93 | container_of(ptr, type, member) |
| 94 | |
| 95 | /** |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 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. |
Andrey Utkin | 3943f42 | 2014-11-14 05:09:55 +0400 | [diff] [blame] | 99 | * @member: the name of the list_head within the struct. |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 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 | |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 106 | struct offset { |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 107 | struct list_head list; |
| 108 | unsigned offset; |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 109 | }; |
| 110 | |
| 111 | struct table { |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 112 | struct list_head offsets; |
| 113 | unsigned offset_max; |
| 114 | unsigned nentry; |
| 115 | unsigned *table; |
| 116 | char *gpu_prefix; |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 117 | }; |
| 118 | |
Josh Triplett | 0592e4c | 2009-10-16 15:12:13 -0700 | [diff] [blame] | 119 | static struct offset *offset_new(unsigned o) |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 120 | { |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 121 | struct offset *offset; |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 122 | |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 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; |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 129 | } |
| 130 | |
Josh Triplett | 0592e4c | 2009-10-16 15:12:13 -0700 | [diff] [blame] | 131 | static void table_offset_add(struct table *t, struct offset *offset) |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 132 | { |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 133 | list_add_tail(&offset->list, &t->offsets); |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 134 | } |
| 135 | |
Josh Triplett | 0592e4c | 2009-10-16 15:12:13 -0700 | [diff] [blame] | 136 | static void table_init(struct table *t) |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 137 | { |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 138 | INIT_LIST_HEAD(&t->offsets); |
| 139 | t->offset_max = 0; |
| 140 | t->nentry = 0; |
| 141 | t->table = NULL; |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 142 | } |
| 143 | |
Josh Triplett | 0592e4c | 2009-10-16 15:12:13 -0700 | [diff] [blame] | 144 | static void table_print(struct table *t) |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 145 | { |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 146 | unsigned nlloop, i, j, n, c, id; |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 147 | |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 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"); |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 167 | } |
| 168 | |
Josh Triplett | 0592e4c | 2009-10-16 15:12:13 -0700 | [diff] [blame] | 169 | static int table_build(struct table *t) |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 170 | { |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 171 | struct offset *offset; |
| 172 | unsigned i, m; |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 173 | |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 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; |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 186 | } |
| 187 | |
| 188 | static char gpu_name[10]; |
Josh Triplett | 0592e4c | 2009-10-16 15:12:13 -0700 | [diff] [blame] | 189 | static int parser_auth(struct table *t, const char *filename) |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 190 | { |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 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; |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 203 | |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 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); |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 217 | |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 218 | /* get header */ |
Alexander Beregalov | 059d233 | 2010-01-07 02:59:31 +0300 | [diff] [blame] | 219 | if (fgets(buf, 1024, file) == NULL) { |
| 220 | fclose(file); |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 221 | return -1; |
Alexander Beregalov | 059d233 | 2010-01-07 02:59:31 +0300 | [diff] [blame] | 222 | } |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 223 | |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 224 | /* first line will contain the last register |
| 225 | * and gpu name */ |
Alan | 6b64190 | 2013-12-17 15:05:39 +0000 | [diff] [blame] | 226 | sscanf(buf, "%9s %9s", gpu_name, last_reg_s); |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 227 | t->gpu_prefix = gpu_name; |
| 228 | last_reg = strtol(last_reg_s, NULL, 16); |
| 229 | |
| 230 | do { |
Jesper Juhl | e917fd3 | 2011-02-05 20:51:53 +0100 | [diff] [blame] | 231 | if (fgets(buf, 1024, file) == NULL) { |
| 232 | fclose(file); |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 233 | return -1; |
Jesper Juhl | e917fd3 | 2011-02-05 20:51:53 +0100 | [diff] [blame] | 234 | } |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 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); |
Jesper Juhl | e917fd3 | 2011-02-05 20:51:53 +0100 | [diff] [blame] | 245 | fclose(file); |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 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); |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 263 | } |
| 264 | |
| 265 | int main(int argc, char *argv[]) |
| 266 | { |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 267 | struct table t; |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 268 | |
Dave Airlie | 689d7c2 | 2009-08-27 11:51:23 +1000 | [diff] [blame] | 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; |
Dave Airlie | 50f1530 | 2009-08-21 13:21:01 +1000 | [diff] [blame] | 280 | } |