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