1 /*- 2 * Aic7xxx SCSI host adapter firmware asssembler symbol table implementation 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 * Copyright (c) 1997 Justin T. Gibbs. 7 * Copyright (c) 2002 Adaptec Inc. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions, and the following disclaimer, 15 * without modification. 16 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 17 * substantially similar to the "NO WARRANTY" disclaimer below 18 * ("Disclaimer") and any redistribution must be conditioned upon 19 * including a substantially similar Disclaimer requirement for further 20 * binary redistribution. 21 * 3. Neither the names of the above-listed copyright holders nor the names 22 * of any contributors may be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * Alternatively, this software may be distributed under the terms of the 26 * GNU General Public License ("GPL") version 2 as published by the Free 27 * Software Foundation. 28 * 29 * NO WARRANTY 30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 33 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 34 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 38 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 39 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 40 * POSSIBILITY OF SUCH DAMAGES. 41 * 42 * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_symbol.c#24 $ 43 * 44 * $FreeBSD$ 45 */ 46 47 #include <sys/types.h> 48 #include <sys/param.h> 49 #if defined(BSD) && !defined(__GNU__) 50 #include <db.h> 51 #else 52 #include <db_185.h> 53 #endif 54 #include <ctype.h> 55 #include <fcntl.h> 56 #include <inttypes.h> 57 #include <regex.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <sysexits.h> 62 63 #include "aicasm_symbol.h" 64 #include "aicasm.h" 65 66 static DB *symtable; 67 68 static symbol_t * 69 symbol_create(const char *name) 70 { 71 symbol_t *new_symbol; 72 73 new_symbol = (symbol_t *)malloc(sizeof(symbol_t)); 74 if (new_symbol == NULL) { 75 perror("Unable to create new symbol"); 76 exit(EX_SOFTWARE); 77 } 78 memset(new_symbol, 0, sizeof(*new_symbol)); 79 new_symbol->name = strdup(name); 80 if (new_symbol->name == NULL) 81 stop("Unable to strdup symbol name", EX_SOFTWARE); 82 new_symbol->type = UNINITIALIZED; 83 return (new_symbol); 84 } 85 86 void 87 symbol_delete(symbol_t *symbol) 88 { 89 if (symtable != NULL) { 90 DBT key; 91 92 key.data = symbol->name; 93 key.size = strlen(symbol->name); 94 symtable->del(symtable, &key, /*flags*/0); 95 } 96 switch(symbol->type) { 97 case SCBLOC: 98 case SRAMLOC: 99 case REGISTER: 100 if (symbol->info.rinfo != NULL) 101 free(symbol->info.rinfo); 102 break; 103 case ALIAS: 104 if (symbol->info.ainfo != NULL) 105 free(symbol->info.ainfo); 106 break; 107 case MASK: 108 case FIELD: 109 case ENUM: 110 case ENUM_ENTRY: 111 if (symbol->info.finfo != NULL) { 112 symlist_free(&symbol->info.finfo->symrefs); 113 free(symbol->info.finfo); 114 } 115 break; 116 case DOWNLOAD_CONST: 117 case CONST: 118 if (symbol->info.cinfo != NULL) 119 free(symbol->info.cinfo); 120 break; 121 case LABEL: 122 if (symbol->info.linfo != NULL) 123 free(symbol->info.linfo); 124 break; 125 case UNINITIALIZED: 126 default: 127 break; 128 } 129 free(symbol->name); 130 free(symbol); 131 } 132 133 void 134 symtable_open(void) 135 { 136 symtable = dbopen(/*filename*/NULL, 137 O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH, 138 /*openinfo*/NULL); 139 140 if (symtable == NULL) { 141 perror("Symbol table creation failed"); 142 exit(EX_SOFTWARE); 143 /* NOTREACHED */ 144 } 145 } 146 147 void 148 symtable_close(void) 149 { 150 if (symtable != NULL) { 151 DBT key; 152 DBT data; 153 154 while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) { 155 symbol_t *stored_ptr; 156 157 memcpy(&stored_ptr, data.data, sizeof(stored_ptr)); 158 symbol_delete(stored_ptr); 159 } 160 symtable->close(symtable); 161 } 162 } 163 164 /* 165 * The semantics of get is to return an uninitialized symbol entry 166 * if a lookup fails. 167 */ 168 symbol_t * 169 symtable_get(const char *name) 170 { 171 symbol_t *stored_ptr; 172 DBT key; 173 DBT data; 174 int retval; 175 176 key.data = strdup(name); 177 key.size = strlen(name); 178 179 if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) { 180 if (retval == -1) { 181 perror("Symbol table get operation failed"); 182 exit(EX_SOFTWARE); 183 /* NOTREACHED */ 184 } else if (retval == 1) { 185 /* Symbol wasn't found, so create a new one */ 186 symbol_t *new_symbol; 187 188 new_symbol = symbol_create(name); 189 data.data = &new_symbol; 190 data.size = sizeof(new_symbol); 191 if (symtable->put(symtable, &key, &data, 192 /*flags*/0) !=0) { 193 perror("Symtable put failed"); 194 exit(EX_SOFTWARE); 195 } 196 free(key.data); 197 return (new_symbol); 198 } else { 199 perror("Unexpected return value from db get routine"); 200 exit(EX_SOFTWARE); 201 /* NOTREACHED */ 202 } 203 } 204 memcpy(&stored_ptr, data.data, sizeof(stored_ptr)); 205 free(key.data); 206 return (stored_ptr); 207 } 208 209 symbol_node_t * 210 symlist_search(symlist_t *symlist, char *symname) 211 { 212 symbol_node_t *curnode; 213 214 curnode = SLIST_FIRST(symlist); 215 while(curnode != NULL) { 216 if (strcmp(symname, curnode->symbol->name) == 0) 217 break; 218 curnode = SLIST_NEXT(curnode, links); 219 } 220 return (curnode); 221 } 222 223 void 224 symlist_add(symlist_t *symlist, symbol_t *symbol, int how) 225 { 226 symbol_node_t *newnode; 227 228 newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t)); 229 if (newnode == NULL) { 230 stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE); 231 /* NOTREACHED */ 232 } 233 newnode->symbol = symbol; 234 if (how == SYMLIST_SORT) { 235 symbol_node_t *curnode; 236 int field; 237 238 field = FALSE; 239 switch(symbol->type) { 240 case REGISTER: 241 case SCBLOC: 242 case SRAMLOC: 243 break; 244 case FIELD: 245 case MASK: 246 case ENUM: 247 case ENUM_ENTRY: 248 field = TRUE; 249 break; 250 default: 251 stop("symlist_add: Invalid symbol type for sorting", 252 EX_SOFTWARE); 253 /* NOTREACHED */ 254 } 255 256 curnode = SLIST_FIRST(symlist); 257 if (curnode == NULL 258 || (field 259 && (curnode->symbol->type > newnode->symbol->type 260 || (curnode->symbol->type == newnode->symbol->type 261 && (curnode->symbol->info.finfo->value > 262 newnode->symbol->info.finfo->value)))) 263 || (!field && (curnode->symbol->info.rinfo->address > 264 newnode->symbol->info.rinfo->address))) { 265 SLIST_INSERT_HEAD(symlist, newnode, links); 266 return; 267 } 268 269 while (1) { 270 if (SLIST_NEXT(curnode, links) == NULL) { 271 SLIST_INSERT_AFTER(curnode, newnode, 272 links); 273 break; 274 } else { 275 symbol_t *cursymbol; 276 277 cursymbol = SLIST_NEXT(curnode, links)->symbol; 278 if ((field 279 && (cursymbol->type > symbol->type 280 || (cursymbol->type == symbol->type 281 && (cursymbol->info.finfo->value > 282 symbol->info.finfo->value)))) 283 || (!field 284 && (cursymbol->info.rinfo->address > 285 symbol->info.rinfo->address))) { 286 SLIST_INSERT_AFTER(curnode, newnode, 287 links); 288 break; 289 } 290 } 291 curnode = SLIST_NEXT(curnode, links); 292 } 293 } else { 294 SLIST_INSERT_HEAD(symlist, newnode, links); 295 } 296 } 297 298 void 299 symlist_free(symlist_t *symlist) 300 { 301 symbol_node_t *node1, *node2; 302 303 node1 = SLIST_FIRST(symlist); 304 while (node1 != NULL) { 305 node2 = SLIST_NEXT(node1, links); 306 free(node1); 307 node1 = node2; 308 } 309 SLIST_INIT(symlist); 310 } 311 312 void 313 symlist_merge(symlist_t *symlist_dest, symlist_t *symlist_src1, 314 symlist_t *symlist_src2) 315 { 316 symbol_node_t *node; 317 318 *symlist_dest = *symlist_src1; 319 while((node = SLIST_FIRST(symlist_src2)) != NULL) { 320 SLIST_REMOVE_HEAD(symlist_src2, links); 321 SLIST_INSERT_HEAD(symlist_dest, node, links); 322 } 323 324 /* These are now empty */ 325 SLIST_INIT(symlist_src1); 326 SLIST_INIT(symlist_src2); 327 } 328 329 static void 330 aic_print_file_prologue(FILE *ofile) 331 { 332 333 if (ofile == NULL) 334 return; 335 336 fprintf(ofile, 337 "/*\n" 338 " * DO NOT EDIT - This file is automatically generated\n" 339 " * from the following source files:\n" 340 " *\n" 341 "%s */\n", 342 versions); 343 } 344 345 static void 346 aic_print_include(FILE *dfile, char *header_file) 347 { 348 349 if (dfile == NULL) 350 return; 351 fprintf(dfile, "\n#include \"%s\"\n\n", header_file); 352 } 353 354 static void 355 aic_print_reg_dump_types(FILE *ofile) 356 { 357 if (ofile == NULL) 358 return; 359 360 fprintf(ofile, 361 "typedef int (%sreg_print_t)(u_int, u_int *, u_int);\n" 362 "typedef struct %sreg_parse_entry {\n" 363 " char *name;\n" 364 " uint8_t value;\n" 365 " uint8_t mask;\n" 366 "} %sreg_parse_entry_t;\n" 367 "\n", 368 prefix, prefix, prefix); 369 } 370 371 static void 372 aic_print_reg_dump_start(FILE *dfile, symbol_node_t *regnode) 373 { 374 if (dfile == NULL) 375 return; 376 377 fprintf(dfile, 378 "static %sreg_parse_entry_t %s_parse_table[] = {\n", 379 prefix, 380 regnode->symbol->name); 381 } 382 383 static void 384 aic_print_reg_dump_end(FILE *ofile, FILE *dfile, 385 symbol_node_t *regnode, u_int num_entries) 386 { 387 char *lower_name; 388 char *letter; 389 390 lower_name = strdup(regnode->symbol->name); 391 if (lower_name == NULL) 392 stop("Unable to strdup symbol name", EX_SOFTWARE); 393 394 for (letter = lower_name; *letter != '\0'; letter++) 395 *letter = tolower(*letter); 396 397 if (dfile != NULL) { 398 if (num_entries != 0) 399 fprintf(dfile, 400 "\n" 401 "};\n" 402 "\n"); 403 404 fprintf(dfile, 405 "int\n" 406 "%s%s_print(u_int regvalue, u_int *cur_col, u_int wrap)\n" 407 "{\n" 408 " return (%sprint_register(%s%s, %d, \"%s\",\n" 409 " 0x%02x, regvalue, cur_col, wrap));\n" 410 "}\n" 411 "\n", 412 prefix, 413 lower_name, 414 prefix, 415 num_entries != 0 ? regnode->symbol->name : "NULL", 416 num_entries != 0 ? "_parse_table" : "", 417 num_entries, 418 regnode->symbol->name, 419 regnode->symbol->info.rinfo->address); 420 } 421 422 fprintf(ofile, 423 "#if AIC_DEBUG_REGISTERS\n" 424 "%sreg_print_t %s%s_print;\n" 425 "#else\n" 426 "#define %s%s_print(regvalue, cur_col, wrap) \\\n" 427 " %sprint_register(NULL, 0, \"%s\", 0x%02x, regvalue, cur_col, wrap)\n" 428 "#endif\n" 429 "\n", 430 prefix, 431 prefix, 432 lower_name, 433 prefix, 434 lower_name, 435 prefix, 436 regnode->symbol->name, 437 regnode->symbol->info.rinfo->address); 438 } 439 440 static void 441 aic_print_reg_dump_entry(FILE *dfile, symbol_node_t *curnode) 442 { 443 int num_tabs; 444 445 if (dfile == NULL) 446 return; 447 448 fprintf(dfile, 449 " { \"%s\",", 450 curnode->symbol->name); 451 452 num_tabs = 3 - (strlen(curnode->symbol->name) + 5) / 8; 453 454 while (num_tabs-- > 0) 455 fputc('\t', dfile); 456 fprintf(dfile, "0x%02x, 0x%02x }", 457 curnode->symbol->info.finfo->value, 458 curnode->symbol->info.finfo->mask); 459 } 460 461 void 462 symtable_dump(FILE *ofile, FILE *dfile) 463 { 464 /* 465 * Sort the registers by address with a simple insertion sort. 466 * Put bitmasks next to the first register that defines them. 467 * Put constants at the end. 468 */ 469 symlist_t registers; 470 symlist_t masks; 471 symlist_t constants; 472 symlist_t download_constants; 473 symlist_t aliases; 474 symlist_t exported_labels; 475 symbol_node_t *curnode; 476 symbol_node_t *regnode; 477 DBT key; 478 DBT data; 479 int flag; 480 u_int i; 481 482 if (symtable == NULL) 483 return; 484 485 SLIST_INIT(®isters); 486 SLIST_INIT(&masks); 487 SLIST_INIT(&constants); 488 SLIST_INIT(&download_constants); 489 SLIST_INIT(&aliases); 490 SLIST_INIT(&exported_labels); 491 flag = R_FIRST; 492 while (symtable->seq(symtable, &key, &data, flag) == 0) { 493 symbol_t *cursym; 494 495 memcpy(&cursym, data.data, sizeof(cursym)); 496 switch(cursym->type) { 497 case REGISTER: 498 case SCBLOC: 499 case SRAMLOC: 500 symlist_add(®isters, cursym, SYMLIST_SORT); 501 break; 502 case MASK: 503 case FIELD: 504 case ENUM: 505 case ENUM_ENTRY: 506 symlist_add(&masks, cursym, SYMLIST_SORT); 507 break; 508 case CONST: 509 symlist_add(&constants, cursym, 510 SYMLIST_INSERT_HEAD); 511 break; 512 case DOWNLOAD_CONST: 513 symlist_add(&download_constants, cursym, 514 SYMLIST_INSERT_HEAD); 515 break; 516 case ALIAS: 517 symlist_add(&aliases, cursym, 518 SYMLIST_INSERT_HEAD); 519 break; 520 case LABEL: 521 if (cursym->info.linfo->exported == 0) 522 break; 523 symlist_add(&exported_labels, cursym, 524 SYMLIST_INSERT_HEAD); 525 break; 526 default: 527 break; 528 } 529 flag = R_NEXT; 530 } 531 532 /* Register dianostic functions/declarations first. */ 533 aic_print_file_prologue(ofile); 534 aic_print_reg_dump_types(ofile); 535 aic_print_file_prologue(dfile); 536 aic_print_include(dfile, stock_include_file); 537 SLIST_FOREACH(curnode, ®isters, links) { 538 switch(curnode->symbol->type) { 539 case REGISTER: 540 case SCBLOC: 541 case SRAMLOC: 542 { 543 symlist_t *fields; 544 symbol_node_t *fieldnode; 545 int num_entries; 546 547 num_entries = 0; 548 fields = &curnode->symbol->info.rinfo->fields; 549 SLIST_FOREACH(fieldnode, fields, links) { 550 if (num_entries == 0) 551 aic_print_reg_dump_start(dfile, 552 curnode); 553 else if (dfile != NULL) 554 fputs(",\n", dfile); 555 num_entries++; 556 aic_print_reg_dump_entry(dfile, fieldnode); 557 } 558 aic_print_reg_dump_end(ofile, dfile, 559 curnode, num_entries); 560 } 561 default: 562 break; 563 } 564 } 565 566 /* Fold in the masks and bits */ 567 while (SLIST_FIRST(&masks) != NULL) { 568 char *regname; 569 570 curnode = SLIST_FIRST(&masks); 571 SLIST_REMOVE_HEAD(&masks, links); 572 573 regnode = SLIST_FIRST(&curnode->symbol->info.finfo->symrefs); 574 regname = regnode->symbol->name; 575 regnode = symlist_search(®isters, regname); 576 SLIST_INSERT_AFTER(regnode, curnode, links); 577 } 578 579 /* Add the aliases */ 580 while (SLIST_FIRST(&aliases) != NULL) { 581 char *regname; 582 583 curnode = SLIST_FIRST(&aliases); 584 SLIST_REMOVE_HEAD(&aliases, links); 585 586 regname = curnode->symbol->info.ainfo->parent->name; 587 regnode = symlist_search(®isters, regname); 588 SLIST_INSERT_AFTER(regnode, curnode, links); 589 } 590 591 /* Output generated #defines. */ 592 while (SLIST_FIRST(®isters) != NULL) { 593 u_int value; 594 const char *tab_str; 595 const char *tab_str2; 596 597 curnode = SLIST_FIRST(®isters); 598 SLIST_REMOVE_HEAD(®isters, links); 599 switch(curnode->symbol->type) { 600 case REGISTER: 601 case SCBLOC: 602 case SRAMLOC: 603 fprintf(ofile, "\n"); 604 value = curnode->symbol->info.rinfo->address; 605 tab_str = "\t"; 606 tab_str2 = "\t\t"; 607 break; 608 case ALIAS: 609 { 610 symbol_t *parent; 611 612 parent = curnode->symbol->info.ainfo->parent; 613 value = parent->info.rinfo->address; 614 tab_str = "\t"; 615 tab_str2 = "\t\t"; 616 break; 617 } 618 case MASK: 619 case FIELD: 620 case ENUM: 621 case ENUM_ENTRY: 622 value = curnode->symbol->info.finfo->value; 623 tab_str = "\t\t"; 624 tab_str2 = "\t"; 625 break; 626 default: 627 value = 0; /* Quiet compiler */ 628 tab_str = NULL; 629 tab_str2 = NULL; 630 stop("symtable_dump: Invalid symbol type " 631 "encountered", EX_SOFTWARE); 632 break; 633 } 634 fprintf(ofile, "#define%s%-16s%s0x%02x\n", 635 tab_str, curnode->symbol->name, tab_str2, 636 value); 637 free(curnode); 638 } 639 fprintf(ofile, "\n\n"); 640 641 while (SLIST_FIRST(&constants) != NULL) { 642 curnode = SLIST_FIRST(&constants); 643 SLIST_REMOVE_HEAD(&constants, links); 644 fprintf(ofile, "#define\t%-8s\t0x%02x\n", 645 curnode->symbol->name, 646 curnode->symbol->info.cinfo->value); 647 free(curnode); 648 } 649 650 fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n"); 651 652 for (i = 0; SLIST_FIRST(&download_constants) != NULL; i++) { 653 curnode = SLIST_FIRST(&download_constants); 654 SLIST_REMOVE_HEAD(&download_constants, links); 655 fprintf(ofile, "#define\t%-8s\t0x%02x\n", 656 curnode->symbol->name, 657 curnode->symbol->info.cinfo->value); 658 free(curnode); 659 } 660 fprintf(ofile, "#define\tDOWNLOAD_CONST_COUNT\t0x%02x\n", i); 661 662 fprintf(ofile, "\n\n/* Exported Labels */\n"); 663 664 while (SLIST_FIRST(&exported_labels) != NULL) { 665 curnode = SLIST_FIRST(&exported_labels); 666 SLIST_REMOVE_HEAD(&exported_labels, links); 667 fprintf(ofile, "#define\tLABEL_%-8s\t0x%02x\n", 668 curnode->symbol->name, 669 curnode->symbol->info.linfo->address); 670 free(curnode); 671 } 672 } 673