xref: /freebsd/sys/dev/aic7xxx/aicasm/aicasm_symbol.c (revision 1b6c76a2fe091c74f08427e6c870851025a9cf67)
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 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#4 $
32  *
33  * $FreeBSD$
34  */
35 
36 #include <sys/types.h>
37 
38 #ifdef __linux__
39 #include <db1/db.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   */\n");
394 		while (SLIST_FIRST(&registers) != NULL) {
395 			symbol_node_t *curnode;
396 			u_int8_t value;
397 			char *tab_str;
398 			char *tab_str2;
399 
400 			curnode = SLIST_FIRST(&registers);
401 			SLIST_REMOVE_HEAD(&registers, links);
402 			switch(curnode->symbol->type) {
403 			case REGISTER:
404 			case SCBLOC:
405 			case SRAMLOC:
406 				fprintf(ofile, "\n");
407 				value = curnode->symbol->info.rinfo->address;
408 				tab_str = "\t";
409 				tab_str2 = "\t\t";
410 				break;
411 			case ALIAS:
412 			{
413 				symbol_t *parent;
414 
415 				parent = curnode->symbol->info.ainfo->parent;
416 				value = parent->info.rinfo->address;
417 				tab_str = "\t";
418 				tab_str2 = "\t\t";
419 				break;
420 			}
421 			case MASK:
422 			case BIT:
423 				value = curnode->symbol->info.minfo->mask;
424 				tab_str = "\t\t";
425 				tab_str2 = "\t";
426 				break;
427 			default:
428 				value = 0; /* Quiet compiler */
429 				tab_str = NULL;
430 				tab_str2 = NULL;
431 				stop("symtable_dump: Invalid symbol type "
432 				     "encountered", EX_SOFTWARE);
433 				break;
434 			}
435 			fprintf(ofile, "#define%s%-16s%s0x%02x\n",
436 				tab_str, curnode->symbol->name, tab_str2,
437 				value);
438 			free(curnode);
439 		}
440 		fprintf(ofile, "\n\n");
441 
442 		while (SLIST_FIRST(&constants) != NULL) {
443 			symbol_node_t *curnode;
444 
445 			curnode = SLIST_FIRST(&constants);
446 			SLIST_REMOVE_HEAD(&constants, links);
447 			fprintf(ofile, "#define\t%-8s\t0x%02x\n",
448 				curnode->symbol->name,
449 				curnode->symbol->info.cinfo->value);
450 			free(curnode);
451 		}
452 
453 
454 		fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n");
455 
456 		while (SLIST_FIRST(&download_constants) != NULL) {
457 			symbol_node_t *curnode;
458 
459 			curnode = SLIST_FIRST(&download_constants);
460 			SLIST_REMOVE_HEAD(&download_constants, links);
461 			fprintf(ofile, "#define\t%-8s\t0x%02x\n",
462 				curnode->symbol->name,
463 				curnode->symbol->info.cinfo->value);
464 			free(curnode);
465 		}
466 	}
467 }
468 
469