|
|
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.