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, prev: head->prev, next: 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(size: sizeof(struct offset)); |
124 | if (offset) { |
125 | INIT_LIST_HEAD(list: &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(new: &offset->list, head: &t->offsets); |
134 | } |
135 | |
136 | static void table_init(struct table *t) |
137 | { |
138 | INIT_LIST_HEAD(list: &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(format: "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(format: "\t" ); |
160 | else |
161 | printf(format: " " ); |
162 | printf(format: "0x%08X," , t->table[id++]); |
163 | } |
164 | printf(format: "\n" ); |
165 | } |
166 | printf(format: "};\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(size: sizeof(unsigned) * t->nentry); |
176 | if (t->table == NULL) |
177 | return -1; |
178 | memset(s: t->table, c: 0xff, n: 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 | (preg: &mask_rex, pattern: "(0x[0-9a-fA-F]*) *([_a-zA-Z0-9]*)" , REG_EXTENDED)) { |
206 | fprintf(stderr, format: "Failed to compile regular expression\n" ); |
207 | return -1; |
208 | } |
209 | file = fopen(filename: filename, modes: "r" ); |
210 | if (file == NULL) { |
211 | fprintf(stderr, format: "Failed to open: %s\n" , filename); |
212 | return -1; |
213 | } |
214 | fseek(stream: file, off: 0, SEEK_END); |
215 | end = ftell(stream: file); |
216 | fseek(stream: file, off: 0, SEEK_SET); |
217 | |
218 | /* get header */ |
219 | if (fgets(s: buf, n: 1024, stream: file) == NULL) { |
220 | fclose(stream: file); |
221 | return -1; |
222 | } |
223 | |
224 | /* first line will contain the last register |
225 | * and gpu name */ |
226 | sscanf(s: buf, format: "%9s %9s" , gpu_name, last_reg_s); |
227 | t->gpu_prefix = gpu_name; |
228 | last_reg = strtol(nptr: last_reg_s, NULL, base: 16); |
229 | |
230 | do { |
231 | if (fgets(s: buf, n: 1024, stream: file) == NULL) { |
232 | fclose(stream: file); |
233 | return -1; |
234 | } |
235 | len = strlen(s: buf); |
236 | if (ftell(stream: file) == end) |
237 | done = 1; |
238 | if (len) { |
239 | r = regexec(preg: &mask_rex, String: buf, nmatch: 4, pmatch: match, eflags: 0); |
240 | if (r == REG_NOMATCH) { |
241 | } else if (r) { |
242 | fprintf(stderr, |
243 | format: "Error matching regular expression %d in %s\n" , |
244 | r, filename); |
245 | fclose(stream: 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(nptr: &buf[match[1].rm_so], NULL, base: 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(stream: 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, format: "Usage: %s <authfile>\n" , argv[0]); |
271 | exit(status: 1); |
272 | } |
273 | table_init(t: &t); |
274 | if (parser_auth(t: &t, filename: argv[1])) { |
275 | fprintf(stderr, format: "Failed to parse file %s\n" , argv[1]); |
276 | return -1; |
277 | } |
278 | table_print(t: &t); |
279 | return 0; |
280 | } |
281 | |