• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2016 Intel Corporation
3  * Copyright © 2017 Broadcom
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include "v3d_decoder.h"
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <stdbool.h>
30 #include <stdint.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #ifdef WITH_LIBEXPAT
34 #include <expat.h>
35 #endif
36 #include <inttypes.h>
37 #include <zlib.h>
38 
39 #include <util/macros.h>
40 #include <util/ralloc.h>
41 #include <util/u_debug.h>
42 
43 #include "v3d_packet_helpers.h"
44 #include "v3d_xml.h"
45 #include "broadcom/clif/clif_private.h"
46 
47 struct v3d_spec {
48         uint32_t ver;
49 
50         int ncommands;
51         struct v3d_group *commands[256];
52         int nstructs;
53         struct v3d_group *structs[256];
54         int nregisters;
55         struct v3d_group *registers[256];
56         int nenums;
57         struct v3d_enum *enums[256];
58 };
59 
60 #ifdef WITH_LIBEXPAT
61 
62 struct location {
63         const char *filename;
64         int line_number;
65 };
66 
67 struct parser_context {
68         XML_Parser parser;
69         const struct v3d_device_info *devinfo;
70         int foo;
71         struct location loc;
72 
73         struct v3d_group *group;
74         struct v3d_enum *enoom;
75 
76         int nvalues;
77         struct v3d_value *values[256];
78 
79         struct v3d_spec *spec;
80 
81         int parse_depth;
82         int parse_skip_depth;
83 };
84 
85 #endif /* WITH_LIBEXPAT */
86 
87 const char *
v3d_group_get_name(struct v3d_group * group)88 v3d_group_get_name(struct v3d_group *group)
89 {
90         return group->name;
91 }
92 
93 uint8_t
v3d_group_get_opcode(struct v3d_group * group)94 v3d_group_get_opcode(struct v3d_group *group)
95 {
96         return group->opcode;
97 }
98 
99 struct v3d_group *
v3d_spec_find_struct(struct v3d_spec * spec,const char * name)100 v3d_spec_find_struct(struct v3d_spec *spec, const char *name)
101 {
102         for (int i = 0; i < spec->nstructs; i++)
103                 if (strcmp(spec->structs[i]->name, name) == 0)
104                         return spec->structs[i];
105 
106         return NULL;
107 }
108 
109 struct v3d_group *
v3d_spec_find_register(struct v3d_spec * spec,uint32_t offset)110 v3d_spec_find_register(struct v3d_spec *spec, uint32_t offset)
111 {
112         for (int i = 0; i < spec->nregisters; i++)
113                 if (spec->registers[i]->register_offset == offset)
114                         return spec->registers[i];
115 
116         return NULL;
117 }
118 
119 struct v3d_group *
v3d_spec_find_register_by_name(struct v3d_spec * spec,const char * name)120 v3d_spec_find_register_by_name(struct v3d_spec *spec, const char *name)
121 {
122         for (int i = 0; i < spec->nregisters; i++) {
123                 if (strcmp(spec->registers[i]->name, name) == 0)
124                         return spec->registers[i];
125         }
126 
127         return NULL;
128 }
129 
130 struct v3d_enum *
v3d_spec_find_enum(struct v3d_spec * spec,const char * name)131 v3d_spec_find_enum(struct v3d_spec *spec, const char *name)
132 {
133         for (int i = 0; i < spec->nenums; i++)
134                 if (strcmp(spec->enums[i]->name, name) == 0)
135                         return spec->enums[i];
136 
137         return NULL;
138 }
139 
140 #ifdef WITH_LIBEXPAT
141 
142 static void __attribute__((noreturn))
fail(struct location * loc,const char * msg,...)143 fail(struct location *loc, const char *msg, ...)
144 {
145         va_list ap;
146 
147         va_start(ap, msg);
148         fprintf(stderr, "%s:%d: error: ",
149                 loc->filename, loc->line_number);
150         vfprintf(stderr, msg, ap);
151         fprintf(stderr, "\n");
152         va_end(ap);
153         exit(EXIT_FAILURE);
154 }
155 
156 static void *
fail_on_null(void * p)157 fail_on_null(void *p)
158 {
159         if (p == NULL) {
160                 fprintf(stderr, "aubinator: out of memory\n");
161                 exit(EXIT_FAILURE);
162         }
163 
164         return p;
165 }
166 
167 static char *
xstrdup(const char * s)168 xstrdup(const char *s)
169 {
170         return fail_on_null(strdup(s));
171 }
172 
173 static void *
zalloc(size_t s)174 zalloc(size_t s)
175 {
176         return calloc(s, 1);
177 }
178 
179 static void *
xzalloc(size_t s)180 xzalloc(size_t s)
181 {
182         return fail_on_null(zalloc(s));
183 }
184 
185 /* We allow fields to have either a bit index, or append "b" for a byte index.
186  */
187 static bool
is_byte_offset(const char * value)188 is_byte_offset(const char *value)
189 {
190         return value[strlen(value) - 1] == 'b';
191 }
192 
193 static void
get_group_offset_count(const char ** atts,uint32_t * offset,uint32_t * count,uint32_t * size,bool * variable)194 get_group_offset_count(const char **atts, uint32_t *offset, uint32_t *count,
195                        uint32_t *size, bool *variable)
196 {
197         char *p;
198         int i;
199 
200         for (i = 0; atts[i]; i += 2) {
201                 if (strcmp(atts[i], "count") == 0) {
202                         *count = strtoul(atts[i + 1], &p, 0);
203                         if (*count == 0)
204                                 *variable = true;
205                 } else if (strcmp(atts[i], "start") == 0) {
206                         *offset = strtoul(atts[i + 1], &p, 0);
207                 } else if (strcmp(atts[i], "size") == 0) {
208                         *size = strtoul(atts[i + 1], &p, 0);
209                 }
210         }
211         return;
212 }
213 
214 static struct v3d_group *
create_group(struct parser_context * ctx,const char * name,const char ** atts,struct v3d_group * parent)215 create_group(struct parser_context *ctx,
216              const char *name,
217              const char **atts,
218              struct v3d_group *parent)
219 {
220         struct v3d_group *group;
221 
222         group = xzalloc(sizeof(*group));
223         if (name)
224                 group->name = xstrdup(name);
225 
226         group->spec = ctx->spec;
227         group->group_offset = 0;
228         group->group_count = 0;
229         group->variable = false;
230 
231         if (parent) {
232                 group->parent = parent;
233                 get_group_offset_count(atts,
234                                        &group->group_offset,
235                                        &group->group_count,
236                                        &group->group_size,
237                                        &group->variable);
238         }
239 
240         return group;
241 }
242 
243 static struct v3d_enum *
create_enum(struct parser_context * ctx,const char * name,const char ** atts)244 create_enum(struct parser_context *ctx, const char *name, const char **atts)
245 {
246         struct v3d_enum *e;
247 
248         e = xzalloc(sizeof(*e));
249         if (name)
250                 e->name = xstrdup(name);
251 
252         e->nvalues = 0;
253 
254         return e;
255 }
256 
257 static void
get_register_offset(const char ** atts,uint32_t * offset)258 get_register_offset(const char **atts, uint32_t *offset)
259 {
260         char *p;
261         int i;
262 
263         for (i = 0; atts[i]; i += 2) {
264                 if (strcmp(atts[i], "num") == 0)
265                         *offset = strtoul(atts[i + 1], &p, 0);
266         }
267         return;
268 }
269 
270 static struct v3d_type
string_to_type(struct parser_context * ctx,const char * s)271 string_to_type(struct parser_context *ctx, const char *s)
272 {
273         int i, f;
274         struct v3d_group *g;
275         struct v3d_enum *e;
276 
277         if (strcmp(s, "int") == 0)
278                 return (struct v3d_type) { .kind = V3D_TYPE_INT };
279         else if (strcmp(s, "uint") == 0)
280                 return (struct v3d_type) { .kind = V3D_TYPE_UINT };
281         else if (strcmp(s, "bool") == 0)
282                 return (struct v3d_type) { .kind = V3D_TYPE_BOOL };
283         else if (strcmp(s, "float") == 0)
284                 return (struct v3d_type) { .kind = V3D_TYPE_FLOAT };
285         else if (strcmp(s, "f187") == 0)
286                 return (struct v3d_type) { .kind = V3D_TYPE_F187 };
287         else if (strcmp(s, "address") == 0)
288                 return (struct v3d_type) { .kind = V3D_TYPE_ADDRESS };
289         else if (strcmp(s, "offset") == 0)
290                 return (struct v3d_type) { .kind = V3D_TYPE_OFFSET };
291         else if (sscanf(s, "u%d.%d", &i, &f) == 2)
292                 return (struct v3d_type) { .kind = V3D_TYPE_UFIXED, .i = i, .f = f };
293         else if (sscanf(s, "s%d.%d", &i, &f) == 2)
294                 return (struct v3d_type) { .kind = V3D_TYPE_SFIXED, .i = i, .f = f };
295         else if (g = v3d_spec_find_struct(ctx->spec, s), g != NULL)
296                 return (struct v3d_type) { .kind = V3D_TYPE_STRUCT, .v3d_struct = g };
297         else if (e = v3d_spec_find_enum(ctx->spec, s), e != NULL)
298                 return (struct v3d_type) { .kind = V3D_TYPE_ENUM, .v3d_enum = e };
299         else if (strcmp(s, "mbo") == 0)
300                 return (struct v3d_type) { .kind = V3D_TYPE_MBO };
301         else
302                 fail(&ctx->loc, "invalid type: %s", s);
303 }
304 
305 static struct v3d_field *
create_field(struct parser_context * ctx,const char ** atts)306 create_field(struct parser_context *ctx, const char **atts)
307 {
308         struct v3d_field *field;
309         char *p;
310         int i;
311         uint32_t size = 0;
312 
313         field = xzalloc(sizeof(*field));
314 
315         for (i = 0; atts[i]; i += 2) {
316                 if (strcmp(atts[i], "name") == 0)
317                         field->name = xstrdup(atts[i + 1]);
318                 else if (strcmp(atts[i], "start") == 0) {
319                         field->start = strtoul(atts[i + 1], &p, 0);
320                         if (is_byte_offset(atts[i + 1]))
321                                 field->start *= 8;
322                 } else if (strcmp(atts[i], "end") == 0) {
323                         field->end = strtoul(atts[i + 1], &p, 0) - 1;
324                         if (is_byte_offset(atts[i + 1]))
325                                 field->end *= 8;
326                 } else if (strcmp(atts[i], "size") == 0) {
327                         size = strtoul(atts[i + 1], &p, 0);
328                         if (is_byte_offset(atts[i + 1]))
329                                 size *= 8;
330                 } else if (strcmp(atts[i], "type") == 0)
331                         field->type = string_to_type(ctx, atts[i + 1]);
332                 else if (strcmp(atts[i], "default") == 0) {
333                         field->has_default = true;
334                         field->default_value = strtoul(atts[i + 1], &p, 0);
335                 } else if (strcmp(atts[i], "minus_one") == 0) {
336                         assert(strcmp(atts[i + 1], "true") == 0);
337                         field->minus_one = true;
338                 }
339         }
340 
341         if (size)
342                 field->end = field->start + size - 1;
343 
344         return field;
345 }
346 
347 static struct v3d_value *
create_value(struct parser_context * ctx,const char ** atts)348 create_value(struct parser_context *ctx, const char **atts)
349 {
350         struct v3d_value *value = xzalloc(sizeof(*value));
351 
352         for (int i = 0; atts[i]; i += 2) {
353                 if (strcmp(atts[i], "name") == 0)
354                         value->name = xstrdup(atts[i + 1]);
355                 else if (strcmp(atts[i], "value") == 0)
356                         value->value = strtoul(atts[i + 1], NULL, 0);
357         }
358 
359         return value;
360 }
361 
362 static void
create_and_append_field(struct parser_context * ctx,const char ** atts)363 create_and_append_field(struct parser_context *ctx,
364                         const char **atts)
365 {
366         if (ctx->group->nfields == ctx->group->fields_size) {
367                 ctx->group->fields_size = MAX2(ctx->group->fields_size * 2, 2);
368                 ctx->group->fields =
369                         (struct v3d_field **) realloc(ctx->group->fields,
370                                                       sizeof(ctx->group->fields[0]) *
371                                                       ctx->group->fields_size);
372         }
373 
374         ctx->group->fields[ctx->group->nfields++] = create_field(ctx, atts);
375 }
376 
377 static void
set_group_opcode(struct v3d_group * group,const char ** atts)378 set_group_opcode(struct v3d_group *group, const char **atts)
379 {
380         char *p;
381         int i;
382 
383         for (i = 0; atts[i]; i += 2) {
384                 if (strcmp(atts[i], "code") == 0)
385                         group->opcode = strtoul(atts[i + 1], &p, 0);
386         }
387         return;
388 }
389 
390 static bool
ver_in_range(int ver,int min_ver,int max_ver)391 ver_in_range(int ver, int min_ver, int max_ver)
392 {
393         return ((min_ver == 0 || ver >= min_ver) &&
394                 (max_ver == 0 || ver <= max_ver));
395 }
396 
397 static bool
skip_if_ver_mismatch(struct parser_context * ctx,int min_ver,int max_ver)398 skip_if_ver_mismatch(struct parser_context *ctx, int min_ver, int max_ver)
399 {
400         if (!ctx->parse_skip_depth && !ver_in_range(ctx->devinfo->ver,
401                                                     min_ver, max_ver)) {
402                 assert(ctx->parse_depth != 0);
403                 ctx->parse_skip_depth = ctx->parse_depth;
404         }
405 
406         return ctx->parse_skip_depth;
407 }
408 
409 static void
start_element(void * data,const char * element_name,const char ** atts)410 start_element(void *data, const char *element_name, const char **atts)
411 {
412         struct parser_context *ctx = data;
413         int i;
414         const char *name = NULL;
415         const char *ver = NULL;
416         int min_ver = 0;
417         int max_ver = 0;
418 
419         ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser);
420 
421         for (i = 0; atts[i]; i += 2) {
422                 if (strcmp(atts[i], "shortname") == 0)
423                         name = atts[i + 1];
424                 else if (strcmp(atts[i], "name") == 0 && !name)
425                         name = atts[i + 1];
426                 else if (strcmp(atts[i], "gen") == 0)
427                         ver = atts[i + 1];
428                 else if (strcmp(atts[i], "min_ver") == 0)
429                         min_ver = strtoul(atts[i + 1], NULL, 0);
430                 else if (strcmp(atts[i], "max_ver") == 0)
431                         max_ver = strtoul(atts[i + 1], NULL, 0);
432         }
433 
434         if (skip_if_ver_mismatch(ctx, min_ver, max_ver))
435                 goto skip;
436 
437         if (strcmp(element_name, "vcxml") == 0) {
438                 if (ver == NULL)
439                         fail(&ctx->loc, "no ver given");
440 
441                 /* Make sure that we picked an XML that matched our version.
442                  */
443                 assert(ver_in_range(ctx->devinfo->ver, min_ver, max_ver));
444 
445                 int major, minor;
446                 int n = sscanf(ver, "%d.%d", &major, &minor);
447                 if (n == 0)
448                         fail(&ctx->loc, "invalid ver given: %s", ver);
449                 if (n == 1)
450                         minor = 0;
451 
452                 ctx->spec->ver = major * 10 + minor;
453         } else if (strcmp(element_name, "packet") == 0 ||
454                    strcmp(element_name, "struct") == 0) {
455                 ctx->group = create_group(ctx, name, atts, NULL);
456 
457                 if (strcmp(element_name, "packet") == 0)
458                         set_group_opcode(ctx->group, atts);
459         } else if (strcmp(element_name, "register") == 0) {
460                 ctx->group = create_group(ctx, name, atts, NULL);
461                 get_register_offset(atts, &ctx->group->register_offset);
462         } else if (strcmp(element_name, "group") == 0) {
463                 struct v3d_group *previous_group = ctx->group;
464                 while (previous_group->next)
465                         previous_group = previous_group->next;
466 
467                 struct v3d_group *group = create_group(ctx, "", atts,
468                                                        ctx->group);
469                 previous_group->next = group;
470                 ctx->group = group;
471         } else if (strcmp(element_name, "field") == 0) {
472                 create_and_append_field(ctx, atts);
473         } else if (strcmp(element_name, "enum") == 0) {
474                 ctx->enoom = create_enum(ctx, name, atts);
475         } else if (strcmp(element_name, "value") == 0) {
476                 ctx->values[ctx->nvalues++] = create_value(ctx, atts);
477                 assert(ctx->nvalues < ARRAY_SIZE(ctx->values));
478         }
479 
480 skip:
481         ctx->parse_depth++;
482 }
483 
484 static int
field_offset_compare(const void * a,const void * b)485 field_offset_compare(const void *a, const void *b)
486 {
487         return ((*(const struct v3d_field **)a)->start -
488                 (*(const struct v3d_field **)b)->start);
489 }
490 
491 static void
end_element(void * data,const char * name)492 end_element(void *data, const char *name)
493 {
494         struct parser_context *ctx = data;
495         struct v3d_spec *spec = ctx->spec;
496 
497         ctx->parse_depth--;
498 
499         if (ctx->parse_skip_depth) {
500                 if (ctx->parse_skip_depth == ctx->parse_depth)
501                         ctx->parse_skip_depth = 0;
502                 return;
503         }
504 
505         if (strcmp(name, "packet") == 0 ||
506             strcmp(name, "struct") == 0 ||
507             strcmp(name, "register") == 0) {
508                 struct v3d_group *group = ctx->group;
509 
510                 ctx->group = ctx->group->parent;
511 
512                 if (strcmp(name, "packet") == 0) {
513                         spec->commands[spec->ncommands++] = group;
514 
515                         /* V3D packet XML has the packet contents with offsets
516                          * starting from the first bit after the opcode, to
517                          * match the spec.  Shift the fields up now.
518                          */
519                         for (int i = 0; i < group->nfields; i++) {
520                                 group->fields[i]->start += 8;
521                                 group->fields[i]->end += 8;
522                         }
523                 }
524                 else if (strcmp(name, "struct") == 0)
525                         spec->structs[spec->nstructs++] = group;
526                 else if (strcmp(name, "register") == 0)
527                         spec->registers[spec->nregisters++] = group;
528 
529                 /* Sort the fields in increasing offset order.  The XML might
530                  * be specified in any order, but we'll want to iterate from
531                  * the bottom.
532                  */
533                 qsort(group->fields, group->nfields, sizeof(*group->fields),
534                       field_offset_compare);
535 
536                 assert(spec->ncommands < ARRAY_SIZE(spec->commands));
537                 assert(spec->nstructs < ARRAY_SIZE(spec->structs));
538                 assert(spec->nregisters < ARRAY_SIZE(spec->registers));
539         } else if (strcmp(name, "group") == 0) {
540                 ctx->group = ctx->group->parent;
541         } else if (strcmp(name, "field") == 0) {
542                 assert(ctx->group->nfields > 0);
543                 struct v3d_field *field = ctx->group->fields[ctx->group->nfields - 1];
544                 size_t size = ctx->nvalues * sizeof(ctx->values[0]);
545                 field->inline_enum.values = xzalloc(size);
546                 field->inline_enum.nvalues = ctx->nvalues;
547                 memcpy(field->inline_enum.values, ctx->values, size);
548                 ctx->nvalues = 0;
549         } else if (strcmp(name, "enum") == 0) {
550                 struct v3d_enum *e = ctx->enoom;
551                 size_t size = ctx->nvalues * sizeof(ctx->values[0]);
552                 e->values = xzalloc(size);
553                 e->nvalues = ctx->nvalues;
554                 memcpy(e->values, ctx->values, size);
555                 ctx->nvalues = 0;
556                 ctx->enoom = NULL;
557                 spec->enums[spec->nenums++] = e;
558         }
559 }
560 
561 static void
character_data(void * data,const XML_Char * s,int len)562 character_data(void *data, const XML_Char *s, int len)
563 {
564 }
565 
zlib_inflate(const void * compressed_data,uint32_t compressed_len,void ** out_ptr)566 static uint32_t zlib_inflate(const void *compressed_data,
567                              uint32_t compressed_len,
568                              void **out_ptr)
569 {
570         struct z_stream_s zstream;
571         void *out;
572 
573         memset(&zstream, 0, sizeof(zstream));
574 
575         zstream.next_in = (unsigned char *)compressed_data;
576         zstream.avail_in = compressed_len;
577 
578         if (inflateInit(&zstream) != Z_OK)
579                 return 0;
580 
581         out = malloc(4096);
582         zstream.next_out = out;
583         zstream.avail_out = 4096;
584 
585         do {
586                 switch (inflate(&zstream, Z_SYNC_FLUSH)) {
587                 case Z_STREAM_END:
588                         goto end;
589                 case Z_OK:
590                         break;
591                 default:
592                         inflateEnd(&zstream);
593                         return 0;
594                 }
595 
596                 if (zstream.avail_out)
597                         break;
598 
599                 out = realloc(out, 2*zstream.total_out);
600                 if (out == NULL) {
601                         inflateEnd(&zstream);
602                         return 0;
603                 }
604 
605                 zstream.next_out = (unsigned char *)out + zstream.total_out;
606                 zstream.avail_out = zstream.total_out;
607         } while (1);
608  end:
609         inflateEnd(&zstream);
610         *out_ptr = out;
611         return zstream.total_out;
612 }
613 
614 #endif /* WITH_LIBEXPAT */
615 
616 struct v3d_spec *
v3d_spec_load(const struct v3d_device_info * devinfo)617 v3d_spec_load(const struct v3d_device_info *devinfo)
618 {
619         struct v3d_spec *spec = calloc(1, sizeof(struct v3d_spec));
620         if (!spec)
621                 return NULL;
622 
623 #ifdef WITH_LIBEXPAT
624         struct parser_context ctx;
625         void *buf;
626         uint8_t *text_data = NULL;
627         uint32_t text_offset = 0, text_length = 0;
628         ASSERTED uint32_t total_length;
629 
630         for (int i = 0; i < ARRAY_SIZE(genxml_files_table); i++) {
631                 if (i != 0) {
632                         assert(genxml_files_table[i - 1].ver_10 <
633                                genxml_files_table[i].ver_10);
634                 }
635 
636                 if (genxml_files_table[i].ver_10 <= devinfo->ver) {
637                         text_offset = genxml_files_table[i].offset;
638                         text_length = genxml_files_table[i].length;
639                 }
640         }
641 
642         if (text_length == 0) {
643                 fprintf(stderr, "unable to find gen (%u) data\n", devinfo->ver);
644                 free(spec);
645                 return NULL;
646         }
647 
648         memset(&ctx, 0, sizeof ctx);
649         ctx.parser = XML_ParserCreate(NULL);
650         ctx.devinfo = devinfo;
651         XML_SetUserData(ctx.parser, &ctx);
652         if (ctx.parser == NULL) {
653                 fprintf(stderr, "failed to create parser\n");
654                 free(spec);
655                 return NULL;
656         }
657 
658         XML_SetElementHandler(ctx.parser, start_element, end_element);
659         XML_SetCharacterDataHandler(ctx.parser, character_data);
660 
661         ctx.spec = spec;
662 
663         total_length = zlib_inflate(compress_genxmls,
664                                     sizeof(compress_genxmls),
665                                     (void **) &text_data);
666         assert(text_offset + text_length <= total_length);
667 
668         buf = XML_GetBuffer(ctx.parser, text_length);
669         memcpy(buf, &text_data[text_offset], text_length);
670 
671         if (XML_ParseBuffer(ctx.parser, text_length, true) == 0) {
672                 fprintf(stderr,
673                         "Error parsing XML at line %ld col %ld byte %ld/%u: %s\n",
674                         XML_GetCurrentLineNumber(ctx.parser),
675                         XML_GetCurrentColumnNumber(ctx.parser),
676                         XML_GetCurrentByteIndex(ctx.parser), text_length,
677                         XML_ErrorString(XML_GetErrorCode(ctx.parser)));
678                 XML_ParserFree(ctx.parser);
679                 free(text_data);
680                 free(spec);
681                 return NULL;
682         }
683 
684         XML_ParserFree(ctx.parser);
685         free(text_data);
686 
687         return ctx.spec;
688 #else /* !WITH_LIBEXPAT */
689         debug_warn_once("CLIF dumping not supported due to missing libexpat");
690         return spec;
691 #endif /* !WITH_LIBEXPAT */
692 }
693 
694 struct v3d_group *
v3d_spec_find_instruction(struct v3d_spec * spec,const uint8_t * p)695 v3d_spec_find_instruction(struct v3d_spec *spec, const uint8_t *p)
696 {
697         uint8_t opcode = *p;
698 
699         for (int i = 0; i < spec->ncommands; i++) {
700                 struct v3d_group *group = spec->commands[i];
701 
702                 if (opcode != group->opcode)
703                         continue;
704 
705                 /* If there's a "sub-id" field, make sure that it matches the
706                  * instruction being decoded.
707                  */
708                 struct v3d_field *subid = NULL;
709                 for (int j = 0; j < group->nfields; j++) {
710                         struct v3d_field *field = group->fields[j];
711                         if (strcmp(field->name, "sub-id") == 0) {
712                                 subid = field;
713                                 break;
714                         }
715                 }
716 
717                 if (subid && (__gen_unpack_uint(p, subid->start, subid->end) !=
718                               subid->default_value)) {
719                         continue;
720                 }
721 
722                 return group;
723         }
724 
725         return NULL;
726 }
727 
728 /** Returns the size of a V3D packet. */
729 int
v3d_group_get_length(struct v3d_group * group)730 v3d_group_get_length(struct v3d_group *group)
731 {
732         int last_bit = 0;
733         for (int i = 0; i < group->nfields; i++) {
734                 struct v3d_field *field = group->fields[i];
735 
736                 last_bit = MAX2(last_bit, field->end);
737         }
738         return last_bit / 8 + 1;
739 }
740 
741 void
v3d_field_iterator_init(struct v3d_field_iterator * iter,struct v3d_group * group,const uint8_t * p)742 v3d_field_iterator_init(struct v3d_field_iterator *iter,
743                         struct v3d_group *group,
744                         const uint8_t *p)
745 {
746         memset(iter, 0, sizeof(*iter));
747 
748         iter->group = group;
749         iter->p = p;
750 }
751 
752 static const char *
v3d_get_enum_name(struct v3d_enum * e,uint64_t value)753 v3d_get_enum_name(struct v3d_enum *e, uint64_t value)
754 {
755         for (int i = 0; i < e->nvalues; i++) {
756                 if (e->values[i]->value == value) {
757                         return e->values[i]->name;
758                 }
759         }
760         return NULL;
761 }
762 
763 static bool
iter_more_fields(const struct v3d_field_iterator * iter)764 iter_more_fields(const struct v3d_field_iterator *iter)
765 {
766         return iter->field_iter < iter->group->nfields;
767 }
768 
769 static uint32_t
iter_group_offset_bits(const struct v3d_field_iterator * iter,uint32_t group_iter)770 iter_group_offset_bits(const struct v3d_field_iterator *iter,
771                        uint32_t group_iter)
772 {
773         return iter->group->group_offset + (group_iter *
774                                             iter->group->group_size);
775 }
776 
777 static bool
iter_more_groups(const struct v3d_field_iterator * iter)778 iter_more_groups(const struct v3d_field_iterator *iter)
779 {
780         if (iter->group->variable) {
781                 return iter_group_offset_bits(iter, iter->group_iter + 1) <
782                         (v3d_group_get_length(iter->group) * 8);
783         } else {
784                 return (iter->group_iter + 1) < iter->group->group_count ||
785                         iter->group->next != NULL;
786         }
787 }
788 
789 static void
iter_advance_group(struct v3d_field_iterator * iter)790 iter_advance_group(struct v3d_field_iterator *iter)
791 {
792         if (iter->group->variable)
793                 iter->group_iter++;
794         else {
795                 if ((iter->group_iter + 1) < iter->group->group_count) {
796                         iter->group_iter++;
797                 } else {
798                         iter->group = iter->group->next;
799                         iter->group_iter = 0;
800                 }
801         }
802 
803         iter->field_iter = 0;
804 }
805 
806 static bool
iter_advance_field(struct v3d_field_iterator * iter)807 iter_advance_field(struct v3d_field_iterator *iter)
808 {
809         while (!iter_more_fields(iter)) {
810                 if (!iter_more_groups(iter))
811                         return false;
812 
813                 iter_advance_group(iter);
814         }
815 
816         iter->field = iter->group->fields[iter->field_iter++];
817         if (iter->field->name)
818                 snprintf(iter->name, sizeof(iter->name), "%s", iter->field->name);
819         else
820                 memset(iter->name, 0, sizeof(iter->name));
821         iter->offset = iter_group_offset_bits(iter, iter->group_iter) / 8 +
822                 iter->field->start / 8;
823         iter->struct_desc = NULL;
824 
825         return true;
826 }
827 
828 bool
v3d_field_iterator_next(struct clif_dump * clif,struct v3d_field_iterator * iter)829 v3d_field_iterator_next(struct clif_dump *clif, struct v3d_field_iterator *iter)
830 {
831         if (!iter_advance_field(iter))
832                 return false;
833 
834         const char *enum_name = NULL;
835 
836         int group_member_offset =
837                 iter_group_offset_bits(iter, iter->group_iter);
838         int s = group_member_offset + iter->field->start;
839         int e = group_member_offset + iter->field->end;
840 
841         assert(!iter->field->minus_one ||
842                iter->field->type.kind == V3D_TYPE_INT ||
843                iter->field->type.kind == V3D_TYPE_UINT);
844 
845         switch (iter->field->type.kind) {
846         case V3D_TYPE_UNKNOWN:
847         case V3D_TYPE_INT: {
848                 uint32_t value = __gen_unpack_sint(iter->p, s, e);
849                 if (iter->field->minus_one)
850                         value++;
851                 snprintf(iter->value, sizeof(iter->value), "%d", value);
852                 enum_name = v3d_get_enum_name(&iter->field->inline_enum, value);
853                 break;
854         }
855         case V3D_TYPE_UINT: {
856                 uint32_t value = __gen_unpack_uint(iter->p, s, e);
857                 if (iter->field->minus_one)
858                         value++;
859                 if (strcmp(iter->field->name, "Vec size") == 0 && value == 0)
860                         value = 1 << (e - s + 1);
861                 snprintf(iter->value, sizeof(iter->value), "%u", value);
862                 enum_name = v3d_get_enum_name(&iter->field->inline_enum, value);
863                 break;
864         }
865         case V3D_TYPE_BOOL:
866                 snprintf(iter->value, sizeof(iter->value), "%s",
867                          __gen_unpack_uint(iter->p, s, e) ?
868                          "1 /* true */" : "0 /* false */");
869                 break;
870         case V3D_TYPE_FLOAT:
871                 snprintf(iter->value, sizeof(iter->value), "%f",
872                          __gen_unpack_float(iter->p, s, e));
873                 break;
874 
875         case V3D_TYPE_F187:
876                 snprintf(iter->value, sizeof(iter->value), "%f",
877                          __gen_unpack_f187(iter->p, s, e));
878                 break;
879 
880         case V3D_TYPE_ADDRESS: {
881                 uint32_t addr =
882                         __gen_unpack_uint(iter->p, s, e) << (31 - (e - s));
883                 struct clif_bo *bo = clif_lookup_bo(clif, addr);
884                 if (bo) {
885                         snprintf(iter->value, sizeof(iter->value),
886                                  "[%s+0x%08x] /* 0x%08x */",
887                                  bo->name, addr - bo->offset, addr);
888                 } else if (addr) {
889                         snprintf(iter->value, sizeof(iter->value),
890                                  "/* XXX: BO unknown */ 0x%08x", addr);
891                 } else {
892                         snprintf(iter->value, sizeof(iter->value),
893                                  "[null]");
894                 }
895 
896                 break;
897         }
898 
899         case V3D_TYPE_OFFSET:
900                 snprintf(iter->value, sizeof(iter->value), "0x%08"PRIx64,
901                          __gen_unpack_uint(iter->p, s, e) << (31 - (e - s)));
902                 break;
903         case V3D_TYPE_STRUCT:
904                 snprintf(iter->value, sizeof(iter->value), "<struct %s>",
905                          iter->field->type.v3d_struct->name);
906                 iter->struct_desc =
907                         v3d_spec_find_struct(iter->group->spec,
908                                              iter->field->type.v3d_struct->name);
909                 break;
910         case V3D_TYPE_SFIXED:
911                 if (clif->pretty) {
912                         snprintf(iter->value, sizeof(iter->value), "%f",
913                                  __gen_unpack_sfixed(iter->p, s, e,
914                                                      iter->field->type.f));
915                 } else {
916                         snprintf(iter->value, sizeof(iter->value), "%u",
917                                  (unsigned)__gen_unpack_uint(iter->p, s, e));
918                 }
919                 break;
920         case V3D_TYPE_UFIXED:
921                 if (clif->pretty) {
922                         snprintf(iter->value, sizeof(iter->value), "%f",
923                                  __gen_unpack_ufixed(iter->p, s, e,
924                                                      iter->field->type.f));
925                 } else {
926                         snprintf(iter->value, sizeof(iter->value), "%u",
927                                  (unsigned)__gen_unpack_uint(iter->p, s, e));
928                 }
929                 break;
930         case V3D_TYPE_MBO:
931                 break;
932         case V3D_TYPE_ENUM: {
933                 uint32_t value = __gen_unpack_uint(iter->p, s, e);
934                 snprintf(iter->value, sizeof(iter->value), "%d", value);
935                 enum_name = v3d_get_enum_name(iter->field->type.v3d_enum, value);
936                 break;
937         }
938         }
939 
940         if (strlen(iter->group->name) == 0) {
941                 int length = strlen(iter->name);
942                 snprintf(iter->name + length, sizeof(iter->name) - length,
943                          "[%i]", iter->group_iter);
944         }
945 
946         if (enum_name) {
947                 int length = strlen(iter->value);
948                 snprintf(iter->value + length, sizeof(iter->value) - length,
949                          " /* %s */", enum_name);
950         }
951 
952         return true;
953 }
954 
955 void
v3d_print_group(struct clif_dump * clif,struct v3d_group * group,uint64_t offset,const uint8_t * p)956 v3d_print_group(struct clif_dump *clif, struct v3d_group *group,
957                 uint64_t offset, const uint8_t *p)
958 {
959         struct v3d_field_iterator iter;
960 
961         v3d_field_iterator_init(&iter, group, p);
962         while (v3d_field_iterator_next(clif, &iter)) {
963                 /* Clif parsing uses the packet name, and expects no
964                  * sub-id.
965                  */
966                 if (strcmp(iter.field->name, "sub-id") == 0 ||
967                     strcmp(iter.field->name, "unused") == 0 ||
968                     strcmp(iter.field->name, "Pad") == 0)
969                         continue;
970 
971                 if (clif->pretty) {
972                         fprintf(clif->out, "    %s: %s\n",
973                                 iter.name, iter.value);
974                 } else {
975                         fprintf(clif->out, "  /* %30s: */ %s\n",
976                                 iter.name, iter.value);
977                 }
978                 if (iter.struct_desc) {
979                         uint64_t struct_offset = offset + iter.offset;
980                         v3d_print_group(clif, iter.struct_desc,
981                                         struct_offset,
982                                         &p[iter.offset]);
983                 }
984         }
985 }
986