18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT
28c2ecf20Sopenharmony_ci/* utility to create the register check tables
38c2ecf20Sopenharmony_ci * this includes inlined list.h safe for userspace.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2009 Jerome Glisse
68c2ecf20Sopenharmony_ci * Copyright 2009 Red Hat Inc.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Authors:
98c2ecf20Sopenharmony_ci * 	Jerome Glisse
108c2ecf20Sopenharmony_ci * 	Dave Airlie
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <sys/types.h>
148c2ecf20Sopenharmony_ci#include <stdlib.h>
158c2ecf20Sopenharmony_ci#include <string.h>
168c2ecf20Sopenharmony_ci#include <stdio.h>
178c2ecf20Sopenharmony_ci#include <regex.h>
188c2ecf20Sopenharmony_ci#include <libgen.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
218c2ecf20Sopenharmony_ci/**
228c2ecf20Sopenharmony_ci * container_of - cast a member of a structure out to the containing structure
238c2ecf20Sopenharmony_ci * @ptr:    the pointer to the member.
248c2ecf20Sopenharmony_ci * @type:   the type of the container struct this is embedded in.
258c2ecf20Sopenharmony_ci * @member: the name of the member within the struct.
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_ci#define container_of(ptr, type, member) ({          \
298c2ecf20Sopenharmony_ci	const typeof(((type *)0)->member)*__mptr = (ptr);    \
308c2ecf20Sopenharmony_ci		     (type *)((char *)__mptr - offsetof(type, member)); })
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/*
338c2ecf20Sopenharmony_ci * Simple doubly linked list implementation.
348c2ecf20Sopenharmony_ci *
358c2ecf20Sopenharmony_ci * Some of the internal functions ("__xxx") are useful when
368c2ecf20Sopenharmony_ci * manipulating whole lists rather than single entries, as
378c2ecf20Sopenharmony_ci * sometimes we already know the next/prev entries and we can
388c2ecf20Sopenharmony_ci * generate better code by using them directly rather than
398c2ecf20Sopenharmony_ci * using the generic single-entry routines.
408c2ecf20Sopenharmony_ci */
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistruct list_head {
438c2ecf20Sopenharmony_ci	struct list_head *next, *prev;
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic inline void INIT_LIST_HEAD(struct list_head *list)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	list->next = list;
508c2ecf20Sopenharmony_ci	list->prev = list;
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci/*
548c2ecf20Sopenharmony_ci * Insert a new entry between two known consecutive entries.
558c2ecf20Sopenharmony_ci *
568c2ecf20Sopenharmony_ci * This is only for internal list manipulation where we know
578c2ecf20Sopenharmony_ci * the prev/next entries already!
588c2ecf20Sopenharmony_ci */
598c2ecf20Sopenharmony_ci#ifndef CONFIG_DEBUG_LIST
608c2ecf20Sopenharmony_cistatic inline void __list_add(struct list_head *new,
618c2ecf20Sopenharmony_ci			      struct list_head *prev, struct list_head *next)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	next->prev = new;
648c2ecf20Sopenharmony_ci	new->next = next;
658c2ecf20Sopenharmony_ci	new->prev = prev;
668c2ecf20Sopenharmony_ci	prev->next = new;
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci#else
698c2ecf20Sopenharmony_ciextern void __list_add(struct list_head *new,
708c2ecf20Sopenharmony_ci		       struct list_head *prev, struct list_head *next);
718c2ecf20Sopenharmony_ci#endif
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/**
748c2ecf20Sopenharmony_ci * list_add_tail - add a new entry
758c2ecf20Sopenharmony_ci * @new: new entry to be added
768c2ecf20Sopenharmony_ci * @head: list head to add it before
778c2ecf20Sopenharmony_ci *
788c2ecf20Sopenharmony_ci * Insert a new entry before the specified head.
798c2ecf20Sopenharmony_ci * This is useful for implementing queues.
808c2ecf20Sopenharmony_ci */
818c2ecf20Sopenharmony_cistatic inline void list_add_tail(struct list_head *new, struct list_head *head)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	__list_add(new, head->prev, head);
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci/**
878c2ecf20Sopenharmony_ci * list_entry - get the struct for this entry
888c2ecf20Sopenharmony_ci * @ptr:	the &struct list_head pointer.
898c2ecf20Sopenharmony_ci * @type:	the type of the struct this is embedded in.
908c2ecf20Sopenharmony_ci * @member:	the name of the list_head within the struct.
918c2ecf20Sopenharmony_ci */
928c2ecf20Sopenharmony_ci#define list_entry(ptr, type, member) \
938c2ecf20Sopenharmony_ci	container_of(ptr, type, member)
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci/**
968c2ecf20Sopenharmony_ci * list_for_each_entry	-	iterate over list of given type
978c2ecf20Sopenharmony_ci * @pos:	the type * to use as a loop cursor.
988c2ecf20Sopenharmony_ci * @head:	the head for your list.
998c2ecf20Sopenharmony_ci * @member:	the name of the list_head within the struct.
1008c2ecf20Sopenharmony_ci */
1018c2ecf20Sopenharmony_ci#define list_for_each_entry(pos, head, member)				\
1028c2ecf20Sopenharmony_ci	for (pos = list_entry((head)->next, typeof(*pos), member);	\
1038c2ecf20Sopenharmony_ci	     &pos->member != (head); 	\
1048c2ecf20Sopenharmony_ci	     pos = list_entry(pos->member.next, typeof(*pos), member))
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistruct offset {
1078c2ecf20Sopenharmony_ci	struct list_head list;
1088c2ecf20Sopenharmony_ci	unsigned offset;
1098c2ecf20Sopenharmony_ci};
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistruct table {
1128c2ecf20Sopenharmony_ci	struct list_head offsets;
1138c2ecf20Sopenharmony_ci	unsigned offset_max;
1148c2ecf20Sopenharmony_ci	unsigned nentry;
1158c2ecf20Sopenharmony_ci	unsigned *table;
1168c2ecf20Sopenharmony_ci	char *gpu_prefix;
1178c2ecf20Sopenharmony_ci};
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic struct offset *offset_new(unsigned o)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	struct offset *offset;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	offset = (struct offset *)malloc(sizeof(struct offset));
1248c2ecf20Sopenharmony_ci	if (offset) {
1258c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&offset->list);
1268c2ecf20Sopenharmony_ci		offset->offset = o;
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci	return offset;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic void table_offset_add(struct table *t, struct offset *offset)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	list_add_tail(&offset->list, &t->offsets);
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic void table_init(struct table *t)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&t->offsets);
1398c2ecf20Sopenharmony_ci	t->offset_max = 0;
1408c2ecf20Sopenharmony_ci	t->nentry = 0;
1418c2ecf20Sopenharmony_ci	t->table = NULL;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic void table_print(struct table *t)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	unsigned nlloop, i, j, n, c, id;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	nlloop = (t->nentry + 3) / 4;
1498c2ecf20Sopenharmony_ci	c = t->nentry;
1508c2ecf20Sopenharmony_ci	printf("static const unsigned %s_reg_safe_bm[%d] = {\n", t->gpu_prefix,
1518c2ecf20Sopenharmony_ci	       t->nentry);
1528c2ecf20Sopenharmony_ci	for (i = 0, id = 0; i < nlloop; i++) {
1538c2ecf20Sopenharmony_ci		n = 4;
1548c2ecf20Sopenharmony_ci		if (n > c)
1558c2ecf20Sopenharmony_ci			n = c;
1568c2ecf20Sopenharmony_ci		c -= n;
1578c2ecf20Sopenharmony_ci		for (j = 0; j < n; j++) {
1588c2ecf20Sopenharmony_ci			if (j == 0)
1598c2ecf20Sopenharmony_ci				printf("\t");
1608c2ecf20Sopenharmony_ci			else
1618c2ecf20Sopenharmony_ci				printf(" ");
1628c2ecf20Sopenharmony_ci			printf("0x%08X,", t->table[id++]);
1638c2ecf20Sopenharmony_ci		}
1648c2ecf20Sopenharmony_ci		printf("\n");
1658c2ecf20Sopenharmony_ci	}
1668c2ecf20Sopenharmony_ci	printf("};\n");
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic int table_build(struct table *t)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	struct offset *offset;
1728c2ecf20Sopenharmony_ci	unsigned i, m;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	t->nentry = ((t->offset_max >> 2) + 31) / 32;
1758c2ecf20Sopenharmony_ci	t->table = (unsigned *)malloc(sizeof(unsigned) * t->nentry);
1768c2ecf20Sopenharmony_ci	if (t->table == NULL)
1778c2ecf20Sopenharmony_ci		return -1;
1788c2ecf20Sopenharmony_ci	memset(t->table, 0xff, sizeof(unsigned) * t->nentry);
1798c2ecf20Sopenharmony_ci	list_for_each_entry(offset, &t->offsets, list) {
1808c2ecf20Sopenharmony_ci		i = (offset->offset >> 2) / 32;
1818c2ecf20Sopenharmony_ci		m = (offset->offset >> 2) & 31;
1828c2ecf20Sopenharmony_ci		m = 1 << m;
1838c2ecf20Sopenharmony_ci		t->table[i] ^= m;
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci	return 0;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic char gpu_name[10];
1898c2ecf20Sopenharmony_cistatic int parser_auth(struct table *t, const char *filename)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	FILE *file;
1928c2ecf20Sopenharmony_ci	regex_t mask_rex;
1938c2ecf20Sopenharmony_ci	regmatch_t match[4];
1948c2ecf20Sopenharmony_ci	char buf[1024];
1958c2ecf20Sopenharmony_ci	size_t end;
1968c2ecf20Sopenharmony_ci	int len;
1978c2ecf20Sopenharmony_ci	int done = 0;
1988c2ecf20Sopenharmony_ci	int r;
1998c2ecf20Sopenharmony_ci	unsigned o;
2008c2ecf20Sopenharmony_ci	struct offset *offset;
2018c2ecf20Sopenharmony_ci	char last_reg_s[10];
2028c2ecf20Sopenharmony_ci	int last_reg;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	if (regcomp
2058c2ecf20Sopenharmony_ci	    (&mask_rex, "(0x[0-9a-fA-F]*) *([_a-zA-Z0-9]*)", REG_EXTENDED)) {
2068c2ecf20Sopenharmony_ci		fprintf(stderr, "Failed to compile regular expression\n");
2078c2ecf20Sopenharmony_ci		return -1;
2088c2ecf20Sopenharmony_ci	}
2098c2ecf20Sopenharmony_ci	file = fopen(filename, "r");
2108c2ecf20Sopenharmony_ci	if (file == NULL) {
2118c2ecf20Sopenharmony_ci		fprintf(stderr, "Failed to open: %s\n", filename);
2128c2ecf20Sopenharmony_ci		return -1;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci	fseek(file, 0, SEEK_END);
2158c2ecf20Sopenharmony_ci	end = ftell(file);
2168c2ecf20Sopenharmony_ci	fseek(file, 0, SEEK_SET);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	/* get header */
2198c2ecf20Sopenharmony_ci	if (fgets(buf, 1024, file) == NULL) {
2208c2ecf20Sopenharmony_ci		fclose(file);
2218c2ecf20Sopenharmony_ci		return -1;
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	/* first line will contain the last register
2258c2ecf20Sopenharmony_ci	 * and gpu name */
2268c2ecf20Sopenharmony_ci	sscanf(buf, "%9s %9s", gpu_name, last_reg_s);
2278c2ecf20Sopenharmony_ci	t->gpu_prefix = gpu_name;
2288c2ecf20Sopenharmony_ci	last_reg = strtol(last_reg_s, NULL, 16);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	do {
2318c2ecf20Sopenharmony_ci		if (fgets(buf, 1024, file) == NULL) {
2328c2ecf20Sopenharmony_ci			fclose(file);
2338c2ecf20Sopenharmony_ci			return -1;
2348c2ecf20Sopenharmony_ci		}
2358c2ecf20Sopenharmony_ci		len = strlen(buf);
2368c2ecf20Sopenharmony_ci		if (ftell(file) == end)
2378c2ecf20Sopenharmony_ci			done = 1;
2388c2ecf20Sopenharmony_ci		if (len) {
2398c2ecf20Sopenharmony_ci			r = regexec(&mask_rex, buf, 4, match, 0);
2408c2ecf20Sopenharmony_ci			if (r == REG_NOMATCH) {
2418c2ecf20Sopenharmony_ci			} else if (r) {
2428c2ecf20Sopenharmony_ci				fprintf(stderr,
2438c2ecf20Sopenharmony_ci					"Error matching regular expression %d in %s\n",
2448c2ecf20Sopenharmony_ci					r, filename);
2458c2ecf20Sopenharmony_ci				fclose(file);
2468c2ecf20Sopenharmony_ci				return -1;
2478c2ecf20Sopenharmony_ci			} else {
2488c2ecf20Sopenharmony_ci				buf[match[0].rm_eo] = 0;
2498c2ecf20Sopenharmony_ci				buf[match[1].rm_eo] = 0;
2508c2ecf20Sopenharmony_ci				buf[match[2].rm_eo] = 0;
2518c2ecf20Sopenharmony_ci				o = strtol(&buf[match[1].rm_so], NULL, 16);
2528c2ecf20Sopenharmony_ci				offset = offset_new(o);
2538c2ecf20Sopenharmony_ci				table_offset_add(t, offset);
2548c2ecf20Sopenharmony_ci				if (o > t->offset_max)
2558c2ecf20Sopenharmony_ci					t->offset_max = o;
2568c2ecf20Sopenharmony_ci			}
2578c2ecf20Sopenharmony_ci		}
2588c2ecf20Sopenharmony_ci	} while (!done);
2598c2ecf20Sopenharmony_ci	fclose(file);
2608c2ecf20Sopenharmony_ci	if (t->offset_max < last_reg)
2618c2ecf20Sopenharmony_ci		t->offset_max = last_reg;
2628c2ecf20Sopenharmony_ci	return table_build(t);
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ciint main(int argc, char *argv[])
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct table t;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	if (argc != 2) {
2708c2ecf20Sopenharmony_ci		fprintf(stderr, "Usage: %s <authfile>\n", argv[0]);
2718c2ecf20Sopenharmony_ci		exit(1);
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci	table_init(&t);
2748c2ecf20Sopenharmony_ci	if (parser_auth(&t, argv[1])) {
2758c2ecf20Sopenharmony_ci		fprintf(stderr, "Failed to parse file %s\n", argv[1]);
2768c2ecf20Sopenharmony_ci		return -1;
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci	table_print(&t);
2798c2ecf20Sopenharmony_ci	return 0;
2808c2ecf20Sopenharmony_ci}
281