File: /usr/src/linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c

1     /*
2      * Aic7xxx SCSI host adapter firmware asssembler symbol table implementation
3      *
4      * Copyright (c) 1997 Justin T. Gibbs.
5      * All rights reserved.
6      *
7      * Redistribution and use in source and binary forms, with or without
8      * modification, are permitted provided that the following conditions
9      * are met:
10      * 1. Redistributions of source code must retain the above copyright
11      *    notice, this list of conditions, and the following disclaimer,
12      *    without modification.
13      * 2. The name of the author may not be used to endorse or promote products
14      *    derived from this software without specific prior written permission.
15      *
16      * Alternatively, this software may be distributed under the terms of the
17      * GNU General Public License ("GPL").
18      *
19      * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20      * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21      * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22      * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23      * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24      * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25      * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26      * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27      * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28      * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29      * SUCH DAMAGE.
30      *
31      * $Id: //depot/src/aic7xxx/aicasm/aicasm_symbol.c#7 $
32      *
33      * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.c,v 1.11 2000/09/22 22:19:54 gibbs Exp $
34      */
35     
36     #include <sys/types.h>
37     
38     #ifdef __linux__
39     #include "aicdb.h"
40     #else
41     #include <db.h>
42     #endif
43     #include <fcntl.h>
44     #include <stdio.h>
45     #include <stdlib.h>
46     #include <string.h>
47     #include <sysexits.h>
48     
49     #include "aicasm_symbol.h"
50     #include "aicasm.h"
51     
52     static DB *symtable;
53     
54     symbol_t *
55     symbol_create(char *name)
56     {
57     	symbol_t *new_symbol;
58     
59     	new_symbol = (symbol_t *)malloc(sizeof(symbol_t));
60     	if (new_symbol == NULL) {
61     		perror("Unable to create new symbol");
62     		exit(EX_SOFTWARE);
63     	}
64     	memset(new_symbol, 0, sizeof(*new_symbol));
65     	new_symbol->name = strdup(name);
66     	new_symbol->type = UNINITIALIZED;
67     	return (new_symbol);
68     }
69     
70     void
71     symbol_delete(symbol_t *symbol)
72     {
73     	if (symtable != NULL) {
74     		DBT	 key;
75     
76     		key.data = symbol->name;
77     		key.size = strlen(symbol->name);
78     		symtable->del(symtable, &key, /*flags*/0);
79     	}
80     	switch(symbol->type) {
81     	case SCBLOC:
82     	case SRAMLOC:
83     	case REGISTER:
84     		if (symbol->info.rinfo != NULL)
85     			free(symbol->info.rinfo);
86     		break;
87     	case ALIAS:
88     		if (symbol->info.ainfo != NULL)
89     			free(symbol->info.ainfo);
90     		break;
91     	case MASK:
92     	case BIT:
93     		if (symbol->info.minfo != NULL) {
94     			symlist_free(&symbol->info.minfo->symrefs);
95     			free(symbol->info.minfo);
96     		}
97     		break;
98     	case DOWNLOAD_CONST:
99     	case CONST:
100     		if (symbol->info.cinfo != NULL)
101     			free(symbol->info.cinfo);
102     		break;
103     	case LABEL:
104     		if (symbol->info.linfo != NULL)
105     			free(symbol->info.linfo);
106     		break;
107     	case UNINITIALIZED:
108     	default:
109     		break;
110     	}
111     	free(symbol->name);
112     	free(symbol);
113     }
114     
115     void
116     symtable_open()
117     {
118     	symtable = dbopen(/*filename*/NULL,
119     			  O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH,
120     			  /*openinfo*/NULL);
121     
122     	if (symtable == NULL) {
123     		perror("Symbol table creation failed");
124     		exit(EX_SOFTWARE);
125     		/* NOTREACHED */
126     	}
127     }
128     
129     void
130     symtable_close()
131     {
132     	if (symtable != NULL) {
133     		DBT	 key;
134     		DBT	 data;
135     
136     		while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) {
137     			symbol_t *stored_ptr;
138     
139     			memcpy(&stored_ptr, data.data, sizeof(stored_ptr));
140     			symbol_delete(stored_ptr);
141     		}
142     		symtable->close(symtable);
143     	}
144     }
145     
146     /*
147      * The semantics of get is to return an uninitialized symbol entry
148      * if a lookup fails.
149      */
150     symbol_t *
151     symtable_get(char *name)
152     {
153     	symbol_t *stored_ptr;
154     	DBT	  key;
155     	DBT	  data;
156     	int	  retval;
157     
158     	key.data = (void *)name;
159     	key.size = strlen(name);
160     
161     	if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) {
162     		if (retval == -1) {
163     			perror("Symbol table get operation failed");
164     			exit(EX_SOFTWARE);
165     			/* NOTREACHED */
166     		} else if (retval == 1) {
167     			/* Symbol wasn't found, so create a new one */
168     			symbol_t *new_symbol;
169     
170     			new_symbol = symbol_create(name);
171     			data.data = &new_symbol;
172     			data.size = sizeof(new_symbol);
173     			if (symtable->put(symtable, &key, &data,
174     					  /*flags*/0) !=0) {
175     				perror("Symtable put failed");
176     				exit(EX_SOFTWARE);
177     			}
178     			return (new_symbol);
179     		} else {
180     			perror("Unexpected return value from db get routine");
181     			exit(EX_SOFTWARE);
182     			/* NOTREACHED */
183     		}
184     	}
185     	memcpy(&stored_ptr, data.data, sizeof(stored_ptr));
186     	return (stored_ptr);
187     }
188     
189     symbol_node_t *
190     symlist_search(symlist_t *symlist, char *symname)
191     {
192     	symbol_node_t *curnode;
193     
194     	curnode = SLIST_FIRST(symlist);
195     	while(curnode != NULL) {
196     		if (strcmp(symname, curnode->symbol->name) == 0)
197     			break;
198     		curnode = SLIST_NEXT(curnode, links);
199     	}
200     	return (curnode);
201     }
202     
203     void
204     symlist_add(symlist_t *symlist, symbol_t *symbol, int how)
205     {
206     	symbol_node_t *newnode;
207     
208     	newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t));
209     	if (newnode == NULL) {
210     		stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE);
211     		/* NOTREACHED */
212     	}
213     	newnode->symbol = symbol;
214     	if (how == SYMLIST_SORT) {
215     		symbol_node_t *curnode;
216     		int mask;
217     
218     		mask = FALSE;
219     		switch(symbol->type) {
220     		case REGISTER:
221     		case SCBLOC:
222     		case SRAMLOC:
223     			break;
224     		case BIT:
225     		case MASK:
226     			mask = TRUE;
227     			break;
228     		default:
229     			stop("symlist_add: Invalid symbol type for sorting",
230     			     EX_SOFTWARE);
231     			/* NOTREACHED */
232     		}
233     
234     		curnode = SLIST_FIRST(symlist);
235     		if (curnode == NULL
236     		 || (mask && (curnode->symbol->info.minfo->mask >
237     		              newnode->symbol->info.minfo->mask))
238     		 || (!mask && (curnode->symbol->info.rinfo->address >
239     		               newnode->symbol->info.rinfo->address))) {
240     			SLIST_INSERT_HEAD(symlist, newnode, links);
241     			return;
242     		}
243     
244     		while (1) {
245     			if (SLIST_NEXT(curnode, links) == NULL) {
246     				SLIST_INSERT_AFTER(curnode, newnode,
247     						   links);
248     				break;
249     			} else {
250     				symbol_t *cursymbol;
251     
252     				cursymbol = SLIST_NEXT(curnode, links)->symbol;
253     				if ((mask && (cursymbol->info.minfo->mask >
254     				              symbol->info.minfo->mask))
255     				 || (!mask &&(cursymbol->info.rinfo->address >
256     				              symbol->info.rinfo->address))){
257     					SLIST_INSERT_AFTER(curnode, newnode,
258     							   links);
259     					break;
260     				}
261     			}
262     			curnode = SLIST_NEXT(curnode, links);
263     		}
264     	} else {
265     		SLIST_INSERT_HEAD(symlist, newnode, links);
266     	}
267     }
268     
269     void
270     symlist_free(symlist_t *symlist)
271     {
272     	symbol_node_t *node1, *node2;
273     
274     	node1 = SLIST_FIRST(symlist);
275     	while (node1 != NULL) {
276     		node2 = SLIST_NEXT(node1, links);
277     		free(node1);
278     		node1 = node2;
279     	}
280     	SLIST_INIT(symlist);
281     }
282     
283     void
284     symlist_merge(symlist_t *symlist_dest, symlist_t *symlist_src1,
285     	      symlist_t *symlist_src2)
286     {
287     	symbol_node_t *node;
288     
289     	*symlist_dest = *symlist_src1;
290     	while((node = SLIST_FIRST(symlist_src2)) != NULL) {
291     		SLIST_REMOVE_HEAD(symlist_src2, links);
292     		SLIST_INSERT_HEAD(symlist_dest, node, links);
293     	}
294     
295     	/* These are now empty */
296     	SLIST_INIT(symlist_src1);
297     	SLIST_INIT(symlist_src2);
298     }
299     
300     void
301     symtable_dump(FILE *ofile)
302     {
303     	/*
304     	 * Sort the registers by address with a simple insertion sort.
305     	 * Put bitmasks next to the first register that defines them.
306     	 * Put constants at the end.
307     	 */
308     	symlist_t registers;
309     	symlist_t masks;
310     	symlist_t constants;
311     	symlist_t download_constants;
312     	symlist_t aliases;
313     
314     	SLIST_INIT(&registers);
315     	SLIST_INIT(&masks);
316     	SLIST_INIT(&constants);
317     	SLIST_INIT(&download_constants);
318     	SLIST_INIT(&aliases);
319     
320     	if (symtable != NULL) {
321     		DBT	 key;
322     		DBT	 data;
323     		int	 flag = R_FIRST;
324     
325     		while (symtable->seq(symtable, &key, &data, flag) == 0) {
326     			symbol_t *cursym;
327     
328     			memcpy(&cursym, data.data, sizeof(cursym));
329     			switch(cursym->type) {
330     			case REGISTER:
331     			case SCBLOC:
332     			case SRAMLOC:
333     				symlist_add(&registers, cursym, SYMLIST_SORT);
334     				break;
335     			case MASK:
336     			case BIT:
337     				symlist_add(&masks, cursym, SYMLIST_SORT);
338     				break;
339     			case CONST:
340     				if (cursym->info.cinfo->define == FALSE) {
341     					symlist_add(&constants, cursym,
342     						    SYMLIST_INSERT_HEAD);
343     				}
344     				break;
345     			case DOWNLOAD_CONST:
346     				symlist_add(&download_constants, cursym,
347     					    SYMLIST_INSERT_HEAD);
348     				break;
349     			case ALIAS:
350     				symlist_add(&aliases, cursym,
351     					    SYMLIST_INSERT_HEAD);
352     				break;
353     			default:
354     				break;
355     			}
356     			flag = R_NEXT;
357     		}
358     
359     		/* Put in the masks and bits */
360     		while (SLIST_FIRST(&masks) != NULL) {
361     			symbol_node_t *curnode;
362     			symbol_node_t *regnode;
363     			char *regname;
364     
365     			curnode = SLIST_FIRST(&masks);
366     			SLIST_REMOVE_HEAD(&masks, links);
367     
368     			regnode =
369     			    SLIST_FIRST(&curnode->symbol->info.minfo->symrefs);
370     			regname = regnode->symbol->name;
371     			regnode = symlist_search(&registers, regname);
372     			SLIST_INSERT_AFTER(regnode, curnode, links);
373     		}
374     
375     		/* Add the aliases */
376     		while (SLIST_FIRST(&aliases) != NULL) {
377     			symbol_node_t *curnode;
378     			symbol_node_t *regnode;
379     			char *regname;
380     
381     			curnode = SLIST_FIRST(&aliases);
382     			SLIST_REMOVE_HEAD(&aliases, links);
383     
384     			regname = curnode->symbol->info.ainfo->parent->name;
385     			regnode = symlist_search(&registers, regname);
386     			SLIST_INSERT_AFTER(regnode, curnode, links);
387     		}
388     
389     		/* Output what we have */
390     		fprintf(ofile,
391     "/*
392      * DO NOT EDIT - This file is automatically generated
393      *		 from the following source files:
394      *
395     %s */\n", versions);
396     		while (SLIST_FIRST(&registers) != NULL) {
397     			symbol_node_t *curnode;
398     			u_int8_t value;
399     			char *tab_str;
400     			char *tab_str2;
401     
402     			curnode = SLIST_FIRST(&registers);
403     			SLIST_REMOVE_HEAD(&registers, links);
404     			switch(curnode->symbol->type) {
405     			case REGISTER:
406     			case SCBLOC:
407     			case SRAMLOC:
408     				fprintf(ofile, "\n");
409     				value = curnode->symbol->info.rinfo->address;
410     				tab_str = "\t";
411     				tab_str2 = "\t\t";
412     				break;
413     			case ALIAS:
414     			{
415     				symbol_t *parent;
416     
417     				parent = curnode->symbol->info.ainfo->parent;
418     				value = parent->info.rinfo->address;
419     				tab_str = "\t";
420     				tab_str2 = "\t\t";
421     				break;
422     			}
423     			case MASK:
424     			case BIT:
425     				value = curnode->symbol->info.minfo->mask;
426     				tab_str = "\t\t";
427     				tab_str2 = "\t";
428     				break;
429     			default:
430     				value = 0; /* Quiet compiler */
431     				tab_str = NULL;
432     				tab_str2 = NULL;
433     				stop("symtable_dump: Invalid symbol type "
434     				     "encountered", EX_SOFTWARE);
435     				break;
436     			}
437     			fprintf(ofile, "#define%s%-16s%s0x%02x\n",
438     				tab_str, curnode->symbol->name, tab_str2,
439     				value);
440     			free(curnode);
441     		}
442     		fprintf(ofile, "\n\n");
443     
444     		while (SLIST_FIRST(&constants) != NULL) {
445     			symbol_node_t *curnode;
446     
447     			curnode = SLIST_FIRST(&constants);
448     			SLIST_REMOVE_HEAD(&constants, links);
449     			fprintf(ofile, "#define\t%-8s\t0x%02x\n",
450     				curnode->symbol->name,
451     				curnode->symbol->info.cinfo->value);
452     			free(curnode);
453     		}
454     
455     		
456     		fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n");
457     
458     		while (SLIST_FIRST(&download_constants) != NULL) {
459     			symbol_node_t *curnode;
460     
461     			curnode = SLIST_FIRST(&download_constants);
462     			SLIST_REMOVE_HEAD(&download_constants, links);
463     			fprintf(ofile, "#define\t%-8s\t0x%02x\n",
464     				curnode->symbol->name,
465     				curnode->symbol->info.cinfo->value);
466     			free(curnode);
467     		}
468     	}
469     }
470     
471