|
|
1.1 ! root 1: /* ! 2: * Cisco 7200 (Predator) simulation platform. ! 3: * Copyright (c) 2005,2006 Christophe Fillot ([email protected]) ! 4: * ! 5: * Many thanks to Nicolas Szalay for his patch ! 6: * for the command line parsing and virtual machine ! 7: * settings (RAM, ROM, NVRAM, ...) ! 8: */ ! 9: ! 10: #include <stdio.h> ! 11: #include <stdlib.h> ! 12: #include <unistd.h> ! 13: #include <string.h> ! 14: #include <sys/types.h> ! 15: #include <sys/stat.h> ! 16: #include <sys/mman.h> ! 17: #include <signal.h> ! 18: #include <fcntl.h> ! 19: #include <assert.h> ! 20: ! 21: #include ARCH_INC_FILE ! 22: ! 23: #include "rbtree.h" ! 24: #include "cp0.h" ! 25: #include "memory.h" ! 26: #include "cpu.h" ! 27: #include "device.h" ! 28: #include "mips64_exec.h" ! 29: #include "dev_c7200.h" ! 30: #include "dev_c7200_bay.h" ! 31: #include "dev_vtty.h" ! 32: #include "ptask.h" ! 33: #include "atm.h" ! 34: #include "net_io_bridge.h" ! 35: ! 36: #ifdef PROFILE ! 37: #include "profiler.h" ! 38: #endif ! 39: ! 40: /* Default name for logfile */ ! 41: #define LOGFILE_DEFAULT_NAME "pred_log0.txt" ! 42: ! 43: /* Software version */ ! 44: static const char *sw_version = "0.2.3b-"JIT_ARCH; ! 45: ! 46: /* Log file */ ! 47: FILE *log_file = NULL; ! 48: ! 49: /* Instruction block trace (produces tons of logs!) */ ! 50: int insn_itrace = 0; ! 51: ! 52: /* JIT use */ ! 53: int jit_use = JIT_SUPPORT; ! 54: ! 55: /* VM flags */ ! 56: volatile int vm_save_state = 0; ! 57: volatile int vm_running = 0; ! 58: ! 59: /* Cisco 7200 router instance */ ! 60: c7200_t c7200_router; ! 61: ! 62: /* By default, use embedded ROM */ ! 63: char *rom_filename = NULL; ! 64: ! 65: /* RAM size (in Mb, by default 256) */ ! 66: u_int ram_size = 256; ! 67: ! 68: /* ROM size (in Mb, by default 4) */ ! 69: u_int rom_size = 4; ! 70: ! 71: /* NVRAM size (in Kb, by default 128) */ ! 72: u_int nvram_size = 128; ! 73: ! 74: /* Config register */ ! 75: u_int conf_reg = 0x2102; ! 76: ! 77: /* Clock divisor (see cp0.c) */ ! 78: u_int clock_divisor = 2; ! 79: ! 80: /* Port Adapter descriptions */ ! 81: static char *pa_desc[MAX_PA_BAYS]; ! 82: static int pa_index = 0; ! 83: ! 84: /* Console port VTTY type and parameters */ ! 85: int vtty_con_type = VTTY_TYPE_TERM; ! 86: int vtty_con_tcp_port; ! 87: ! 88: /* AUX port VTTY type and parameters */ ! 89: int vtty_aux_type = VTTY_TYPE_NONE; ! 90: int vtty_aux_tcp_port; ! 91: ! 92: /* Symbols */ ! 93: rbtree_tree *sym_tree = NULL; ! 94: ! 95: /* ELF entry point */ ! 96: m_uint32_t ios_entry_point; ! 97: ! 98: /* Symbol lookup */ ! 99: struct symbol *sym_lookup(m_uint64_t addr) ! 100: { ! 101: return(rbtree_lookup(sym_tree,&addr)); ! 102: } ! 103: ! 104: /* Insert a new symbol */ ! 105: struct symbol *sym_insert(char *name,m_uint64_t addr) ! 106: { ! 107: struct symbol *sym; ! 108: size_t len; ! 109: ! 110: len = strlen(name); ! 111: ! 112: if (!(sym = malloc(len + sizeof(*sym)))) ! 113: return NULL; ! 114: ! 115: memcpy(sym->name,name,len+1); ! 116: sym->addr = addr; ! 117: ! 118: if (rbtree_insert(sym_tree,sym,sym) == -1) { ! 119: free(sym); ! 120: return NULL; ! 121: } ! 122: ! 123: return sym; ! 124: } ! 125: ! 126: /* Symbol comparison function */ ! 127: static int sym_compare(m_uint64_t *a1,struct symbol *sym) ! 128: { ! 129: if (*a1 > sym->addr) ! 130: return(1); ! 131: ! 132: if (*a1 < sym->addr) ! 133: return(-1); ! 134: ! 135: return(0); ! 136: } ! 137: ! 138: /* Create the symbol tree */ ! 139: int sym_create_tree(void) ! 140: { ! 141: sym_tree = rbtree_create((tree_fcompare)sym_compare,NULL); ! 142: return(sym_tree ? 0 : -1); ! 143: } ! 144: ! 145: /* Generic signal handler */ ! 146: void signal_gen_handler(int sig) ! 147: { ! 148: switch(sig) { ! 149: case SIGHUP: ! 150: insn_itrace = 1 - insn_itrace; ! 151: printf("Instruction block trace %sabled\n", ! 152: insn_itrace ? "en" : "dis"); ! 153: break; ! 154: ! 155: case SIGQUIT: ! 156: /* save VM context */ ! 157: vm_save_state = TRUE; ! 158: vm_running = FALSE; ! 159: break; ! 160: ! 161: default: ! 162: fprintf(stderr,"Unhandled signal %d\n",sig); ! 163: } ! 164: } ! 165: ! 166: /* Setups signals */ ! 167: static void setup_signals(void) ! 168: { ! 169: struct sigaction act; ! 170: ! 171: memset(&act,0,sizeof(act)); ! 172: act.sa_handler = signal_gen_handler; ! 173: act.sa_flags = SA_RESTART; ! 174: sigaction(SIGHUP,&act,NULL); ! 175: sigaction(SIGQUIT,&act,NULL); ! 176: } ! 177: ! 178: /* Load a raw image into the simulated memory */ ! 179: int load_raw_image(cpu_mips_t *cpu,char *filename,m_uint64_t vaddr) ! 180: { ! 181: struct stat file_info; ! 182: size_t len,clen; ! 183: void *haddr; ! 184: FILE *bfd; ! 185: ! 186: if (!(bfd = fopen(filename,"r"))) { ! 187: perror("fopen"); ! 188: return(-1); ! 189: } ! 190: ! 191: if (fstat(fileno(bfd),&file_info) == -1) { ! 192: perror("stat"); ! 193: return(-1); ! 194: } ! 195: ! 196: len = file_info.st_size; ! 197: ! 198: printf("Loading RAW file '%s' at virtual address 0x%llx (size=%lu)\n", ! 199: filename,vaddr,(u_long)len); ! 200: ! 201: while(len > 0) ! 202: { ! 203: haddr = cpu->mem_op_lookup(cpu,vaddr); ! 204: ! 205: if (!haddr) { ! 206: fprintf(stderr,"load_raw_image: invalid load address 0x%llx\n", ! 207: vaddr); ! 208: return(-1); ! 209: } ! 210: ! 211: if (len > MIPS_MIN_PAGE_SIZE) ! 212: clen = MIPS_MIN_PAGE_SIZE; ! 213: else ! 214: clen = len; ! 215: ! 216: clen = fread((u_char *)haddr,clen,1,bfd); ! 217: ! 218: if (clen != 1) ! 219: break; ! 220: ! 221: vaddr += MIPS_MIN_PAGE_SIZE; ! 222: len -= clen; ! 223: } ! 224: ! 225: fclose(bfd); ! 226: return(0); ! 227: } ! 228: ! 229: /* Load an ELF image into the simulated memory */ ! 230: int load_elf_image(cpu_mips_t *cpu,char *filename,m_uint32_t *entry_point) ! 231: { ! 232: m_uint64_t vaddr; ! 233: void *haddr; ! 234: Elf32_Ehdr *ehdr; ! 235: Elf32_Phdr *phdr; ! 236: Elf *img_elf; ! 237: size_t len,clen; ! 238: int i,fd; ! 239: FILE *bfd; ! 240: ! 241: if ((fd = open(filename,O_RDONLY)) == -1) ! 242: return(-1); ! 243: ! 244: if (elf_version(EV_CURRENT) == EV_NONE) { ! 245: fprintf(stderr,"load_elf_image: library out of date\n"); ! 246: return(-1); ! 247: } ! 248: ! 249: if (!(img_elf = elf_begin(fd,ELF_C_READ,NULL))) { ! 250: fprintf(stderr,"load_elf_image: elf_begin: %s\n", ! 251: elf_errmsg(elf_errno())); ! 252: return(-1); ! 253: } ! 254: ! 255: if (!(phdr = elf32_getphdr(img_elf))) { ! 256: fprintf(stderr,"load_elf_image: elf32_getphdr: %s\n", ! 257: elf_errmsg(elf_errno())); ! 258: return(-1); ! 259: } ! 260: ! 261: ehdr = elf32_getehdr(img_elf); ! 262: phdr = elf32_getphdr(img_elf); ! 263: ! 264: printf("Loading ELF file '%s'...\n",filename); ! 265: bfd = fdopen(fd,"rb"); ! 266: ! 267: if (!bfd) { ! 268: perror("load_elf_image: fdopen"); ! 269: return(-1); ! 270: } ! 271: ! 272: for(i=0;i<ehdr->e_phnum;i++,phdr++) ! 273: { ! 274: fseek(bfd,phdr->p_offset,SEEK_SET); ! 275: ! 276: vaddr = (m_uint64_t)phdr->p_vaddr; ! 277: len = phdr->p_filesz; ! 278: ! 279: printf(" * Adding section at virtual address 0x%llx\n",vaddr); ! 280: ! 281: while(len > 0) ! 282: { ! 283: haddr = cpu->mem_op_lookup(cpu,vaddr); ! 284: ! 285: if (!haddr) { ! 286: fprintf(stderr,"load_elf_image: invalid load address 0x%llx\n", ! 287: vaddr); ! 288: return(-1); ! 289: } ! 290: ! 291: if (len > MIPS_MIN_PAGE_SIZE) ! 292: clen = MIPS_MIN_PAGE_SIZE; ! 293: else ! 294: clen = len; ! 295: ! 296: clen = fread((u_char *)haddr,clen,1,bfd); ! 297: ! 298: if (clen != 1) ! 299: break; ! 300: ! 301: vaddr += MIPS_MIN_PAGE_SIZE; ! 302: len -= clen; ! 303: } ! 304: } ! 305: ! 306: printf("ELF entry point: 0x%x\n",ehdr->e_entry); ! 307: ! 308: if (entry_point) ! 309: *entry_point = ehdr->e_entry; ! 310: ! 311: return(0); ! 312: } ! 313: ! 314: /* Load a symbol file */ ! 315: int load_sym_file(char *filename) ! 316: { ! 317: char buffer[4096],func_name[128]; ! 318: m_uint64_t addr; ! 319: char sym_type; ! 320: FILE *fd; ! 321: ! 322: if ((!sym_tree) && (sym_create_tree() == -1)) { ! 323: fprintf(stderr,"Unable to create symbol tree.\n"); ! 324: return(-1); ! 325: } ! 326: ! 327: if (!(fd = fopen(filename,"r"))) { ! 328: perror("load_sym_file: fopen"); ! 329: return(-1); ! 330: } ! 331: ! 332: while(!feof(fd)) { ! 333: fgets(buffer,sizeof(buffer),fd); ! 334: ! 335: if (sscanf(buffer,"%llx %c %s",&addr,&sym_type,func_name) == 3) { ! 336: sym_insert(func_name,addr); ! 337: } ! 338: } ! 339: ! 340: fclose(fd); ! 341: return(0); ! 342: } ! 343: ! 344: /* Display the command line use */ ! 345: static void show_usage(int argc,char *argv[]) ! 346: { ! 347: printf("Usage: %s [options] <ios_image>\n\n",argv[0]); ! 348: ! 349: printf("Available options:\n" ! 350: " -r <ram_size> : Set the virtual RAM size (default is %d Mb)\n" ! 351: " -o <rom_size> : Set the virtual ROM size (default is %d Mb)\n" ! 352: " -n <nvram_size> : Set the NVRAM size (default is %d Kb)\n" ! 353: " -l <log_file> : Set logging file (default is %s)\n" ! 354: " -C <cfg_file> : Import an IOS configuration file into NVRAM\n" ! 355: " -R <rom_file> : Load an alternate ROM (default is embedded)\n" ! 356: " -s <sym_file> : Load symbol file\n" ! 357: " -c <conf_reg> : Set the configuration register " ! 358: "(default is 0x%04x)\n" ! 359: " -m <mac_addr> : Set the MAC address of the chassis " ! 360: "(IOS chooses default)\n" ! 361: " -k <clock_div> : Set the clock divisor (default is %d)\n" ! 362: " -T <port> : Console is on TCP <port> " ! 363: "(default is on the terminal)\n" ! 364: " -A <port> : AUX is on TCP <port> (default is no AUX port)\n" ! 365: " -i : Instruction block trace, very slow\n" ! 366: " -j : Disable the JIT compiler, very slow\n" ! 367: " -t <npe_type> : Select NPE type\n" ! 368: " -M <midplane> : Select Midplane (\"std\" or \"vxr\")\n" ! 369: " -p <pa_desc> : Define a Port Adapter\n" ! 370: " -a <cfg_file> : Virtual ATM switch configuration file\n" ! 371: " -b <cfg_file> : Virtual bridge configuration file\n" ! 372: "\n", ! 373: ram_size,rom_size,nvram_size,LOGFILE_DEFAULT_NAME, ! 374: conf_reg,clock_divisor); ! 375: ! 376: printf("<pa_desc> format:\n" ! 377: " \"slot:pa_driver:netio_type{:netio_parameters}\"\n" ! 378: "\n"); ! 379: ! 380: /* Show the possible NPE drivers */ ! 381: c7200_npe_show_drivers(); ! 382: ! 383: /* Show the possible PA drivers */ ! 384: c7200_pa_show_drivers(); ! 385: ! 386: /* Show the possible NETIO types */ ! 387: netio_show_types(); ! 388: } ! 389: ! 390: int main(int argc,char *argv[]) ! 391: { ! 392: char *options_list = "r:o:n:c:m:l:C:ijt:p:k:T:A:a:b:s:R:M:"; ! 393: char *log_file_name = NULL; ! 394: char *ios_image_name; ! 395: char *ios_cfg_file = NULL; ! 396: char *mac_addr = NULL; ! 397: int option; ! 398: cpu_mips_t *cpu0; ! 399: m_uint32_t rom_entry_point; ! 400: ! 401: #ifdef PROFILE ! 402: atexit(profiler_savestat); ! 403: #endif ! 404: ! 405: printf("Cisco 7200 Simulation Platform (version %s)\n",sw_version); ! 406: printf("Copyright (c) 2005,2006 Christophe Fillot.\n\n"); ! 407: ! 408: memset(&c7200_router,0,sizeof(c7200_router)); ! 409: ! 410: /* Initialize ATM code */ ! 411: atm_init(); ! 412: ! 413: /* Command line arguments : early try */ ! 414: opterr = 0; ! 415: ! 416: while((option = getopt(argc,argv,options_list)) != -1) { ! 417: switch(option) ! 418: { ! 419: /* RAM size */ ! 420: case 'r': ! 421: ram_size = strtol(optarg, NULL, 10); ! 422: printf("Virtual RAM size set to %d MB.\n",ram_size); ! 423: break; ! 424: ! 425: /* ROM size */ ! 426: case 'o': ! 427: rom_size = strtol(optarg, NULL, 10); ! 428: printf("Virtual ROM size set to %d MB.\n",rom_size); ! 429: break; ! 430: ! 431: /* NVRAM size */ ! 432: case 'n': ! 433: nvram_size = strtol(optarg, NULL, 10); ! 434: printf("NVRAM size set to %d KB.\n", nvram_size); ! 435: break; ! 436: ! 437: /* Config Register */ ! 438: case 'c': ! 439: conf_reg = strtol(optarg, NULL, 0); ! 440: printf("Config. Register set to 0x%x.\n",conf_reg); ! 441: break; ! 442: ! 443: /* Set the base MAC address */ ! 444: case 'm': ! 445: mac_addr = optarg; ! 446: printf("MAC address set to '%s'.\n",mac_addr); ! 447: break; ! 448: ! 449: /* Log file */ ! 450: case 'l': ! 451: if (!(log_file_name = malloc(strlen(optarg)+1))) { ! 452: fprintf(stderr,"Unable to set log file name.\n"); ! 453: exit(EXIT_FAILURE); ! 454: } ! 455: strcpy(log_file_name, optarg); ! 456: printf("Log file: writing to %s\n",log_file_name); ! 457: break; ! 458: ! 459: /* IOS configuration file */ ! 460: case 'C': ! 461: ios_cfg_file = optarg; ! 462: break; ! 463: ! 464: /* Alternate ROM */ ! 465: case 'R': ! 466: rom_filename = optarg; ! 467: break; ! 468: ! 469: /* Symbol file */ ! 470: case 's': ! 471: load_sym_file(optarg); ! 472: break; ! 473: ! 474: /* Instruction block trace */ ! 475: case 'i': ! 476: insn_itrace = TRUE; ! 477: break; ! 478: ! 479: /* Disable JIT */ ! 480: case 'j': ! 481: jit_use = FALSE; ! 482: break; ! 483: ! 484: /* NPE type */ ! 485: case 't': ! 486: c7200_router.npe_type = optarg; ! 487: break; ! 488: ! 489: /* Midplane type */ ! 490: case 'M': ! 491: c7200_router.midplane_type = optarg; ! 492: break; ! 493: ! 494: /* PA settings */ ! 495: case 'p': ! 496: if (pa_index == MAX_PA_BAYS) ! 497: fprintf(stderr,"All PA slots are filled.\n"); ! 498: else ! 499: pa_desc[pa_index++] = optarg; ! 500: break; ! 501: ! 502: /* Clock divisor */ ! 503: case 'k': ! 504: clock_divisor = atoi(optarg); ! 505: ! 506: if (!clock_divisor) { ! 507: fprintf(stderr,"Invalid Clock Divisor specified!\n"); ! 508: exit(EXIT_FAILURE); ! 509: } ! 510: ! 511: printf("Using a clock divisor of %d.\n",clock_divisor); ! 512: break; ! 513: ! 514: /* TCP server for Console Port */ ! 515: case 'T': ! 516: vtty_con_type = VTTY_TYPE_TCP; ! 517: vtty_con_tcp_port = atoi(optarg); ! 518: break; ! 519: ! 520: /* TCP server for AUX Port */ ! 521: case 'A': ! 522: vtty_aux_type = VTTY_TYPE_TCP; ! 523: vtty_aux_tcp_port = atoi(optarg); ! 524: break; ! 525: ! 526: /* Virtual ATM switch */ ! 527: case 'a': ! 528: if (atmsw_start(optarg) == -1) ! 529: exit(EXIT_FAILURE); ! 530: break; ! 531: ! 532: /* Virtual bridge */ ! 533: case 'b': ! 534: if (netio_bridge_start(optarg) == -1) ! 535: exit(EXIT_FAILURE); ! 536: break; ! 537: ! 538: /* Oops ! */ ! 539: case '?': ! 540: show_usage(argc,argv); ! 541: exit(EXIT_FAILURE); ! 542: } ! 543: } ! 544: ! 545: /* Last argument, this is the IOS filename */ ! 546: if (optind == (argc - 1)) { ! 547: /* setting IOS image file */ ! 548: ios_image_name = argv[optind]; ! 549: printf("IOS image file: %s\n\n", ios_image_name); ! 550: } else { ! 551: /* IOS missing */ ! 552: fprintf(stderr,"Please specify an IOS image filename\n"); ! 553: show_usage(argc,argv); ! 554: exit(EXIT_FAILURE); ! 555: } ! 556: ! 557: /* Set the default value of the log file name */ ! 558: if (!log_file_name) { ! 559: if (!(log_file_name = malloc(strlen(LOGFILE_DEFAULT_NAME)+1))) { ! 560: fprintf(stderr,"Unable to set log file name.\n"); ! 561: exit(EXIT_FAILURE); ! 562: } ! 563: strcpy(log_file_name,LOGFILE_DEFAULT_NAME); ! 564: } ! 565: ! 566: if (!(log_file = fopen(log_file_name,"w"))) { ! 567: fprintf(stderr,"Unable to create log file.\n"); ! 568: exit(EXIT_FAILURE); ! 569: } ! 570: ! 571: /* Periodic tasks initialization */ ! 572: if (ptask_init(0) == -1) ! 573: exit(EXIT_FAILURE); ! 574: ! 575: /* Create instruction lookup tables */ ! 576: mips64_jit_create_ilt(); ! 577: mips64_exec_create_ilt(); ! 578: ! 579: /* Create a CPU group */ ! 580: sys_cpu_group = cpu_group_create("System CPU Group"); ! 581: ! 582: /* Initialize the virtual MIPS processor */ ! 583: if (!(cpu0 = cpu_create(0))) { ! 584: fprintf(stderr,"Unable to create CPU0!\n"); ! 585: exit(EXIT_FAILURE); ! 586: } ! 587: ! 588: /* Add this CPU to the system CPU group */ ! 589: cpu_group_add(sys_cpu_group,cpu0); ! 590: c7200_router.cpu_group = sys_cpu_group; ! 591: ! 592: /* Initialize the C7200 platform */ ! 593: if (c7200_init_platform(&c7200_router,pa_desc,mac_addr) == -1) { ! 594: fprintf(stderr,"Unable to initialize the C7200 platform hardware.\n"); ! 595: exit(EXIT_FAILURE); ! 596: } ! 597: ! 598: /* Load IOS configuration file */ ! 599: if (ios_cfg_file != NULL) { ! 600: dev_nvram_push_config(sys_cpu_group,ios_cfg_file); ! 601: conf_reg &= ~0x40; ! 602: } ! 603: ! 604: /* Load ROM (ELF image or embedded) */ ! 605: rom_entry_point = 0xbfc00000; ! 606: ! 607: if (rom_filename) { ! 608: if (load_elf_image(cpu0,rom_filename,&rom_entry_point) < 0) { ! 609: fprintf(stderr,"Unable to load alternate ROM '%s', " ! 610: "fallback to embedded ROM.\n\n",rom_filename); ! 611: rom_filename = NULL; ! 612: } ! 613: } ! 614: ! 615: /* Load IOS image */ ! 616: if (load_elf_image(cpu0,ios_image_name,&ios_entry_point) < 0) { ! 617: fprintf(stderr,"Cisco IOS load failed.\n"); ! 618: exit(EXIT_FAILURE); ! 619: } ! 620: ! 621: cpu0->pc = sign_extend(rom_entry_point,32); ! 622: cpu0->cp0.reg[MIPS_CP0_PRID] = 0x2012ULL; ! 623: cpu0->cp0.reg[MIPS_CP0_CONFIG] = 0x00c08ff0ULL; ! 624: ! 625: setup_signals(); ! 626: ! 627: /* Launch the simulation */ ! 628: printf("\nStarting simulation (CPU0 PC=0x%llx), JIT is %sabled.\n", ! 629: cpu0->pc,jit_use ? "en":"dis"); ! 630: ! 631: cpu_start(cpu0); ! 632: ! 633: /* Run until all CPU of the system CPU group are halted */ ! 634: while(!cpu_group_check_state(sys_cpu_group,MIPS_CPU_HALTED)) ! 635: usleep(200000); ! 636: ! 637: printf("\n\nSimulation halted (CPU0 PC=0x%llx).\n\n",cpu0->pc); ! 638: return(0); ! 639: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.