|
|
1.1 root 1: /*
2: * Cisco router simulation platform.
3: * Copyright (c) 2007 Christophe Fillot ([email protected])
4: *
5: * Generic MSFC1 routines and definitions (EEPROM,...).
6: *
7: * This is not a working platform! I only added it to play, since it is very
8: * similar to an NPE-200. I think that could work with a functional CatOS SP.
9: */
10:
11: #include <stdio.h>
12: #include <stdlib.h>
13: #include <string.h>
14: #include <unistd.h>
15: #include <sys/types.h>
16: #include <assert.h>
17:
18: #include "cpu.h"
19: #include "vm.h"
20: #include "dynamips.h"
21: #include "memory.h"
22: #include "device.h"
23: #include "pci_io.h"
24: #include "dev_gt.h"
25: #include "cisco_eeprom.h"
26: #include "dev_rom.h"
27: #include "dev_dec21140.h"
28: #include "dev_i8254x.h"
29: #include "dev_c6msfc1.h"
30: #include "dev_c6msfc1_mpfpga.h"
31: #include "dev_vtty.h"
32: #include "registry.h"
33: #include "net.h"
34:
35: /* MSFC1 EEPROM */
36: static m_uint16_t eeprom_msfc1_data[128] = {
37: 0xabab, 0x0190, 0x1262, 0x0100, 0x0002, 0x6003, 0x00cf, 0x4369,
38: 0x7363, 0x6f20, 0x5379, 0x7374, 0x656d, 0x732c, 0x2049, 0x6e63,
39: 0x2e00, 0x5753, 0x2d46, 0x3630, 0x3031, 0x2d52, 0x5346, 0x4300,
40: 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
41: 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3733, 0x2d37, 0x3135,
42: 0x302d, 0x3036, 0x0000, 0x0000, 0x0000, 0x4130, 0x3100, 0x0000,
43: 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
44: 0x0000, 0x0000, 0x012d, 0x0000, 0x0000, 0x0009, 0x0005, 0x0001,
45: 0x0003, 0x0001, 0x0001, 0x0002, 0x00cf, 0xffbf, 0x0000, 0x0000,
46: 0x6003, 0x0162, 0x0afd, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
47: 0x0000, 0x0000, 0x0000, 0x0005, 0x00e0, 0xaabb, 0xcc00, 0x0100,
48: 0x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
49: 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
50: 0x1401, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
51: 0x1000, 0x4b3c, 0x4132, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080,
52: 0x8080, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
53: };
54:
55: static struct cisco_eeprom msfc1_eeprom = {
56: "msfc1", eeprom_msfc1_data, sizeof(eeprom_msfc1_data)/2,
57: };
58:
59: /* ====================================================================== */
60: /* EOBC - Ethernet Out of Band Channel */
61: /* ====================================================================== */
62: static int dev_c6msfc1_eobc_init(vm_instance_t *vm,struct cisco_card *card)
63: {
64: struct dec21140_data *data;
65:
66: /* Create the DEC21140 chip */
67: data = dev_dec21140_init(vm,card->dev_name,vm->pci_bus[0],6,
68: c6msfc1_net_irq_for_slot_port(0,0));
69: if (!data) return(-1);
70:
71: /* Store device info into the router structure */
72: card->drv_info = data;
73: return(0);
74: }
75:
76: /* Remove EOBC */
77: static int dev_c6msfc1_eobc_shutdown(vm_instance_t *vm,struct cisco_card *card)
78: {
79: struct dec21140_data *data = card->drv_info;
80: dev_dec21140_remove(data);
81: return(0);
82: }
83:
84: /* Bind a Network IO descriptor */
85: static int dev_c6msfc1_eobc_set_nio(vm_instance_t *vm,struct cisco_card *card,
86: u_int port_id,netio_desc_t *nio)
87: {
88: struct dec21140_data *d = card->drv_info;
89:
90: if (!d || (port_id != 0))
91: return(-1);
92:
93: return(dev_dec21140_set_nio(d,nio));
94: }
95:
96: /* Unbind a Network IO descriptor */
97: static int dev_c6msfc1_eobc_unset_nio(vm_instance_t *vm,
98: struct cisco_card *card,
99: u_int port_id)
100: {
101: struct dec21140_data *d = card->drv_info;
102:
103: if (!d || (port_id != 0))
104: return(-1);
105:
106: dev_dec21140_unset_nio(d);
107: return(0);
108: }
109:
110: /* EOBC driver */
111: struct cisco_card_driver dev_c6msfc1_eobc = {
112: "C6MSFC1_EOBC", 0, 0,
113: dev_c6msfc1_eobc_init,
114: dev_c6msfc1_eobc_shutdown,
115: NULL,
116: dev_c6msfc1_eobc_set_nio,
117: dev_c6msfc1_eobc_unset_nio,
118: NULL,
119: };
120:
121: /* ====================================================================== */
122: /* IBC - InBand Channel */
123: /* ====================================================================== */
124: static int dev_c6msfc1_ibc_init(vm_instance_t *vm,struct cisco_card *card)
125: {
126: struct i8254x_data *data;
127:
128: /* Create the Intel Wiseman/Livengood chip */
129: data = dev_i8254x_init(vm,card->dev_name,0,vm->pci_bus_pool[24],1,
130: c6msfc1_net_irq_for_slot_port(1,0));
131: if (!data) return(-1);
132:
133: /* Store device info into the router structure */
134: card->drv_info = data;
135: return(0);
136: }
137:
138: /* Remove EOBC */
139: static int dev_c6msfc1_ibc_shutdown(vm_instance_t *vm,struct cisco_card *card)
140: {
141: struct i8254x_data *data = card->drv_info;
142: dev_i8254x_remove(data);
143: return(0);
144: }
145:
146: /* Bind a Network IO descriptor */
147: static int dev_c6msfc1_ibc_set_nio(vm_instance_t *vm,struct cisco_card *card,
148: u_int port_id,netio_desc_t *nio)
149: {
150: struct i8254x_data *d = card->drv_info;
151:
152: if (!d || (port_id != 0))
153: return(-1);
154:
155: return(dev_i8254x_set_nio(d,nio));
156: }
157:
158: /* Unbind a Network IO descriptor */
159: static int dev_c6msfc1_ibc_unset_nio(vm_instance_t *vm,
160: struct cisco_card *card,
161: u_int port_id)
162: {
163: struct i8254x_data *d = card->drv_info;
164:
165: if (!d || (port_id != 0))
166: return(-1);
167:
168: dev_i8254x_unset_nio(d);
169: return(0);
170: }
171:
172: /* IBC driver */
173: struct cisco_card_driver dev_c6msfc1_ibc = {
174: "C6MSFC1_IBC", 0, 0,
175: dev_c6msfc1_ibc_init,
176: dev_c6msfc1_ibc_shutdown,
177: NULL,
178: dev_c6msfc1_ibc_set_nio,
179: dev_c6msfc1_ibc_unset_nio,
180: NULL,
181: };
182:
183: /* ======================================================================== */
184: /* Port Adapter Drivers */
185: /* ======================================================================== */
186: static struct cisco_card_driver *pa_drivers[] = {
187: &dev_c6msfc1_eobc,
188: &dev_c6msfc1_ibc,
189: NULL,
190: };
191:
192: /* ======================================================================== */
193: /* C6MSFC1 router instances */
194: /* ======================================================================== */
195:
196: /* Initialize default parameters for a MSFC1 */
197: static void c6msfc1_init_defaults(c6msfc1_t *router);
198:
199: /* Directly extract the configuration from the NVRAM device */
200: static ssize_t c6msfc1_nvram_extract_config(vm_instance_t *vm,u_char **buffer)
201: {
202: u_char *base_ptr,*ios_ptr,*cfg_ptr,*end_ptr;
203: m_uint32_t start,end,nvlen,clen;
204: m_uint16_t magic1,magic2;
205: struct vdevice *nvram_dev;
206: m_uint64_t nvram_addr;
207: off_t nvram_size;
208: int fd;
209:
210: if ((nvram_dev = dev_get_by_name(vm,"nvram")))
211: dev_sync(nvram_dev);
212:
213: fd = vm_mmap_open_file(vm,"nvram",&base_ptr,&nvram_size);
214:
215: if (fd == -1)
216: return(-1);
217:
218: nvram_addr = C6MSFC1_NVRAM_ADDR;
219: ios_ptr = base_ptr + vm->nvram_rom_space;
220: end_ptr = base_ptr + nvram_size;
221:
222: if ((ios_ptr + 0x30) >= end_ptr) {
223: vm_error(vm,"NVRAM file too small\n");
224: return(-1);
225: }
226:
227: magic1 = ntohs(*PTR_ADJUST(m_uint16_t *,ios_ptr,0x06));
228: magic2 = ntohs(*PTR_ADJUST(m_uint16_t *,ios_ptr,0x08));
229:
230: if ((magic1 != 0xF0A5) || (magic2 != 0xABCD)) {
231: vm_error(vm,"unable to find IOS magic numbers (0x%x,0x%x)!\n",
232: magic1,magic2);
233: return(-1);
234: }
235:
236: start = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x10)) + 1;
237: end = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x14));
238: nvlen = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x18));
239: clen = end - start;
240:
241: if ((clen + 1) != nvlen) {
242: vm_error(vm,"invalid configuration size (0x%x)\n",nvlen);
243: return(-1);
244: }
245:
246: if (!(*buffer = malloc(clen+1))) {
247: vm_error(vm,"unable to allocate config buffer (%u bytes)\n",clen);
248: return(-1);
249: }
250:
251: cfg_ptr = base_ptr + (start - nvram_addr);
252:
253: if ((start < nvram_addr) || ((cfg_ptr + clen) > end_ptr)) {
254: vm_error(vm,"NVRAM file too small\n");
255: return(-1);
256: }
257:
258: memcpy(*buffer,cfg_ptr,clen);
259: (*buffer)[clen] = 0;
260: return(clen);
261: }
262:
263: /* Directly push the IOS configuration to the NVRAM device */
264: static int c6msfc1_nvram_push_config(vm_instance_t *vm,
265: u_char *buffer,size_t len)
266: {
267: u_char *base_ptr,*ios_ptr,*cfg_ptr;
268: m_uint32_t cfg_addr,cfg_offset;
269: m_uint32_t nvram_addr,cklen;
270: m_uint16_t cksum;
271: int fd;
272:
273: fd = vm_mmap_create_file(vm,"nvram",vm->nvram_size*1024,&base_ptr);
274:
275: if (fd == -1)
276: return(-1);
277:
278: cfg_offset = 0x2c;
279: ios_ptr = base_ptr + vm->nvram_rom_space;
280: cfg_ptr = ios_ptr + cfg_offset;
281:
282: nvram_addr = C6MSFC1_NVRAM_ADDR;
283: cfg_addr = nvram_addr + vm->nvram_rom_space + cfg_offset;
284:
285: /* Write IOS tag, uncompressed config... */
286: *PTR_ADJUST(m_uint16_t *,ios_ptr,0x06) = htons(0xF0A5);
287: *PTR_ADJUST(m_uint16_t *,ios_ptr,0x08) = htons(0xABCD);
288: *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0a) = htons(0x0001);
289: *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0c) = htons(0x0000);
290: *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0e) = htons(0x0000);
291:
292: /* Store file contents to NVRAM */
293: memcpy(cfg_ptr,buffer,len);
294:
295: /* Write config addresses + size */
296: *PTR_ADJUST(m_uint32_t *,ios_ptr,0x10) = htonl(cfg_addr);
297: *PTR_ADJUST(m_uint32_t *,ios_ptr,0x14) = htonl(cfg_addr + len);
298: *PTR_ADJUST(m_uint32_t *,ios_ptr,0x18) = htonl(len);
299:
300: /* Compute the checksum */
301: cklen = (vm->nvram_size*1024) - (vm->nvram_rom_space + 0x08);
302: cksum = nvram_cksum((m_uint16_t *)(ios_ptr+0x08),cklen);
303: *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0c) = htons(cksum);
304:
305: vm_mmap_close_file(fd,base_ptr,vm->nvram_size*1024);
306: return(0);
307: }
308:
309: /* Get slot/port corresponding to specified network IRQ */
310: static inline void
311: c6msfc1_net_irq_get_slot_port(u_int irq,u_int *slot,u_int *port)
312: {
313: *slot = irq - C6MSFC1_NETIO_IRQ_BASE;
314: *port = 0;
315: }
316:
317: /* Get network IRQ for specified slot/port */
318: u_int c6msfc1_net_irq_for_slot_port(u_int slot,u_int port)
319: {
320: u_int irq;
321:
322: irq = C6MSFC1_NETIO_IRQ_BASE + slot;
323: return(irq);
324: }
325:
326: /* Set MSFC eeprom definition */
327: static int c6msfc1_set_eeprom(c6msfc1_t *router)
328: {
329: if (cisco_eeprom_copy(&router->cpu_eeprom,&msfc1_eeprom) == -1) {
330: vm_error(router->vm,"unable to set NPE EEPROM.\n");
331: return(-1);
332: }
333:
334: return(0);
335: }
336:
337: /* Set the base MAC address of the chassis */
338: static int c6msfc1_burn_mac_addr(c6msfc1_t *router,n_eth_addr_t *addr)
339: {
340: m_uint8_t eeprom_ver;
341:
342: /* Read EEPROM format version */
343: cisco_eeprom_get_byte(&router->mp_eeprom,0,&eeprom_ver);
344:
345: if (eeprom_ver != 1) {
346: vm_error(router->vm,"c6msfc1_burn_mac_addr: unable to handle "
347: "EEPROM version %u\n",eeprom_ver);
348: return(-1);
349: }
350:
351: cisco_eeprom_set_region(&router->mp_eeprom,12,addr->eth_addr_byte,6);
352: return(0);
353: }
354:
355: /* Create a new router instance */
356: static int c6msfc1_create_instance(vm_instance_t *vm)
357: {
358: c6msfc1_t *router;
359:
360: if (!(router = malloc(sizeof(*router)))) {
361: fprintf(stderr,"C6MFC1 '%s': Unable to create new instance!\n",vm->name);
362: return(-1);
363: }
364:
365: memset(router,0,sizeof(*router));
366: router->vm = vm;
367: vm->hw_data = router;
368: vm->elf_machine_id = C6MSFC1_ELF_MACHINE_ID;
369:
370: c6msfc1_init_defaults(router);
371: return(0);
372: }
373:
374: /* Free resources used by a router instance */
375: static int c6msfc1_delete_instance(vm_instance_t *vm)
376: {
377: c6msfc1_t *router = VM_C6MSFC1(vm);
378: int i;
379:
380: /* Stop all CPUs */
381: if (vm->cpu_group != NULL) {
382: vm_stop(vm);
383:
384: if (cpu_group_sync_state(vm->cpu_group) == -1) {
385: vm_error(vm,"unable to sync with system CPUs.\n");
386: return(FALSE);
387: }
388: }
389:
390: /* Remove NIO bindings */
391: for(i=0;i<C6MSFC1_MAX_PA_BAYS;i++)
392: vm_slot_remove_all_nio_bindings(vm,i);
393:
394: /* Shutdown all Network Modules */
395: vm_slot_shutdown_all(vm);
396:
397: /* Free EEPROMs */
398: cisco_eeprom_free(&router->cpu_eeprom);
399: cisco_eeprom_free(&router->mp_eeprom);
400: cisco_eeprom_free(&router->pem_eeprom);
401:
402: /* Free all resources used by VM */
403: vm_free(vm);
404:
405: /* Free the router structure */
406: free(router);
407: return(TRUE);
408: }
409:
410: /* Create the main PCI bus for a GT64010 based system */
411: static int c6msfc1_init_gt64010(c6msfc1_t *router)
412: {
413: vm_instance_t *vm = router->vm;
414:
415: if (!(vm->pci_bus[0] = pci_bus_create("PCI Bus 0",0))) {
416: vm_error(vm,"unable to create PCI data.\n");
417: return(-1);
418: }
419:
420: return(dev_gt64010_init(vm,"gt64010",C6MSFC1_GT64K_ADDR,0x1000,
421: C6MSFC1_GT64K_IRQ));
422: }
423:
424: /* Initialize a MSFC1 board */
425: static int c6msfc1_init_hw(c6msfc1_t *router)
426: {
427: vm_instance_t *vm = router->vm;
428:
429: /* Set the processor type: R5000 */
430: mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R5000);
431:
432: /* Initialize the Galileo GT-64010 PCI controller */
433: if (c6msfc1_init_gt64010(router) == -1)
434: return(-1);
435:
436: /* Create PCI bus 1 */
437: vm->pci_bus_pool[24] = pci_bus_create("PCI Bus 1",-1);
438: dev_dec21154_init(vm->pci_bus[0],1,vm->pci_bus_pool[24]);
439:
440: /* Initialize SRAM (4Mb) */
441: dev_c7200_sram_init(vm,"sram",C6MSFC1_SRAM_ADDR,C6MSFC1_SRAM_SIZE,
442: vm->pci_bus_pool[24],0);
443:
444: /* PCI IO space */
445: if (!(vm->pci_io_space = pci_io_data_init(vm,C6MSFC1_PCI_IO_ADDR)))
446: return(-1);
447:
448: /* Cirrus Logic PD6729 (PCI-to-PCMCIA host adapter) */
449: dev_clpd6729_init(vm,vm->pci_bus[0],5,vm->pci_io_space,0x402,0x403);
450:
451: return(0);
452: }
453:
454: /* Show MSFC1 hardware info */
455: void c6msfc1_show_hardware(c6msfc1_t *router)
456: {
457: vm_instance_t *vm = router->vm;
458:
459: printf("C6MSFC1 instance '%s' (id %d):\n",vm->name,vm->instance_id);
460:
461: printf(" VM Status : %d\n",vm->status);
462: printf(" RAM size : %u Mb\n",vm->ram_size);
463: printf(" IOMEM size : %u Mb\n",vm->iomem_size);
464: printf(" NVRAM size : %u Kb\n",vm->nvram_size);
465: printf(" IOS image : %s\n\n",vm->ios_image);
466:
467: if (vm->debug_level > 0) {
468: dev_show_list(vm);
469: pci_dev_show_list(vm->pci_bus[0]);
470: pci_dev_show_list(vm->pci_bus[1]);
471: printf("\n");
472: }
473: }
474:
475: /* Initialize default parameters for a MSFC1 */
476: static void c6msfc1_init_defaults(c6msfc1_t *router)
477: {
478: vm_instance_t *vm = router->vm;
479: n_eth_addr_t *m;
480: m_uint16_t pid;
481:
482: /* Set platform slots characteristics */
483: vm->nr_slots = C6MSFC1_MAX_PA_BAYS;
484: vm->slots_type = CISCO_CARD_TYPE_PA;
485: vm->slots_drivers = pa_drivers;
486:
487: pid = (m_uint16_t)getpid();
488:
489: /* Generate a chassis MAC address based on the instance ID */
490: m = &router->mac_addr;
491: m->eth_addr_byte[0] = vm_get_mac_addr_msb(vm);
492: m->eth_addr_byte[1] = vm->instance_id & 0xFF;
493: m->eth_addr_byte[2] = pid >> 8;
494: m->eth_addr_byte[3] = pid & 0xFF;
495: m->eth_addr_byte[4] = 0x00;
496: m->eth_addr_byte[5] = 0x00;
497:
498: /* Default slot: 1 */
499: router->msfc_slot = 1;
500:
501: c6msfc1_set_eeprom(router);
502: c6msfc1_init_eeprom_groups(router);
503:
504: /* Create EOBC and IBC interfaces */
505: vm_slot_add_binding(vm,"C6MSFC1_EOBC",0,0);
506: vm_slot_add_binding(vm,"C6MSFC1_IBC",1,0);
507:
508: vm->ram_mmap = C6MSFC1_DEFAULT_RAM_MMAP;
509: vm->ram_size = C6MSFC1_DEFAULT_RAM_SIZE;
510: vm->rom_size = C6MSFC1_DEFAULT_ROM_SIZE;
511: vm->nvram_size = C6MSFC1_DEFAULT_NVRAM_SIZE;
512: vm->iomem_size = 0;
513: vm->conf_reg_setup = C6MSFC1_DEFAULT_CONF_REG;
514: vm->clock_divisor = C6MSFC1_DEFAULT_CLOCK_DIV;
515: vm->nvram_rom_space = C6MSFC1_NVRAM_ROM_RES_SIZE;
516: }
517:
518: /* Run the checklist */
519: static int c6msfc1_checklist(c6msfc1_t *router)
520: {
521: struct vm_instance *vm = router->vm;
522: int res = 0;
523:
524: res += vm_object_check(vm,"ram");
525: res += vm_object_check(vm,"rom");
526: res += vm_object_check(vm,"nvram");
527: res += vm_object_check(vm,"zero");
528:
529: if (res < 0)
530: vm_error(vm,"incomplete initialization (no memory?)\n");
531:
532: return(res);
533: }
534:
535: /* Initialize Port Adapters */
536: static int c6msfc1_init_platform_pa(c6msfc1_t *router)
537: {
538: return(vm_slot_init_all(router->vm));
539: }
540:
541: /* Initialize the MSFC1 Platform */
542: static int c6msfc1_init_platform(c6msfc1_t *router)
543: {
544: struct vm_instance *vm = router->vm;
545: cpu_mips_t *cpu0;
546: cpu_gen_t *gen0;
547: vm_obj_t *obj;
548:
549: /* Copy config register setup into "active" config register */
550: vm->conf_reg = vm->conf_reg_setup;
551:
552: /* Create Console and AUX ports */
553: vm_init_vtty(vm);
554:
555: /* Create a CPU group */
556: vm->cpu_group = cpu_group_create("System CPU");
557:
558: /* Initialize the virtual MIPS processor */
559: if (!(gen0 = cpu_create(vm,CPU_TYPE_MIPS64,0))) {
560: vm_error(vm,"unable to create CPU0!\n");
561: return(-1);
562: }
563:
564: cpu0 = CPU_MIPS64(gen0);
565:
566: /* Add this CPU to the system CPU group */
567: cpu_group_add(vm->cpu_group,gen0);
568: vm->boot_cpu = gen0;
569:
570: /* Initialize the IRQ routing vectors */
571: vm->set_irq = mips64_vm_set_irq;
572: vm->clear_irq = mips64_vm_clear_irq;
573:
574: /* Mark the Network IO interrupt as high priority */
575: cpu0->irq_idle_preempt[C6MSFC1_NETIO_IRQ] = TRUE;
576: cpu0->irq_idle_preempt[C6MSFC1_GT64K_IRQ] = TRUE;
577:
578: /* Copy some parameters from VM to CPU0 (idle PC, ...) */
579: cpu0->idle_pc = vm->idle_pc;
580:
581: if (vm->timer_irq_check_itv)
582: cpu0->timer_irq_check_itv = vm->timer_irq_check_itv;
583:
584: /*
585: * On the MSFC1, bit 33 of physical addresses is used to bypass L2 cache.
586: * We clear it systematically.
587: */
588: cpu0->addr_bus_mask = C6MSFC1_ADDR_BUS_MASK;
589:
590: /* Remote emulator control */
591: dev_remote_control_init(vm,0x16000000,0x1000);
592:
593: /* Bootflash (8 Mb) */
594: dev_bootflash_init(vm,"bootflash","c7200-bootflash-8mb",
595: C6MSFC1_BOOTFLASH_ADDR);
596:
597: /* NVRAM and calendar */
598: dev_nvram_init(vm,"nvram",C6MSFC1_NVRAM_ADDR,
599: vm->nvram_size*1024,&vm->conf_reg);
600:
601: /* Bit-bucket zone */
602: dev_zero_init(vm,"zero",C6MSFC1_BITBUCKET_ADDR,0xc00000);
603:
604: /* Initialize the NPE board */
605: if (c6msfc1_init_hw(router) == -1)
606: return(-1);
607:
608: /* Initialize RAM */
609: vm_ram_init(vm,0x00000000ULL);
610:
611: /* Initialize ROM */
612: if (!vm->rom_filename) {
613: /* use embedded ROM */
614: dev_rom_init(vm,"rom",C6MSFC1_ROM_ADDR,vm->rom_size*1048576,
615: mips64_microcode,mips64_microcode_len);
616: } else {
617: /* use alternate ROM */
618: dev_ram_init(vm,"rom",TRUE,TRUE,NULL,FALSE,
619: C6MSFC1_ROM_ADDR,vm->rom_size*1048576);
620: }
621:
622: /* Byte swapping */
623: dev_bswap_init(vm,"mem_bswap",C6MSFC1_BSWAP_ADDR,1024*1048576,0x00000000ULL);
624:
625: /* PCI IO space */
626: if (!(vm->pci_io_space = pci_io_data_init(vm,C6MSFC1_PCI_IO_ADDR)))
627: return(-1);
628:
629: /* Initialize the Port Adapters */
630: if (c6msfc1_init_platform_pa(router) == -1)
631: return(-1);
632:
633: /* Verify the check list */
634: if (c6msfc1_checklist(router) == -1)
635: return(-1);
636:
637: /* Midplane FPGA */
638: if (dev_c6msfc1_mpfpga_init(router,C6MSFC1_MPFPGA_ADDR,0x1000) == -1)
639: return(-1);
640:
641: if (!(obj = vm_object_find(router->vm,"mp_fpga")))
642: return(-1);
643:
644: router->mpfpga_data = obj->data;
645:
646: /* IO FPGA */
647: if (dev_c6msfc1_iofpga_init(router,C6MSFC1_IOFPGA_ADDR,0x1000) == -1)
648: return(-1);
649:
650: /* Show device list */
651: c6msfc1_show_hardware(router);
652: return(0);
653: }
654:
655: /* Boot the IOS image */
656: static int c6msfc1_boot_ios(c6msfc1_t *router)
657: {
658: vm_instance_t *vm = router->vm;
659: cpu_mips_t *cpu;
660:
661: if (!vm->boot_cpu)
662: return(-1);
663:
664: /* Suspend CPU activity since we will restart directly from ROM */
665: vm_suspend(vm);
666:
667: /* Check that CPU activity is really suspended */
668: if (cpu_group_sync_state(vm->cpu_group) == -1) {
669: vm_error(vm,"unable to sync with system CPUs.\n");
670: return(-1);
671: }
672:
673: /* Reset the boot CPU */
674: cpu = CPU_MIPS64(vm->boot_cpu);
675: mips64_reset(cpu);
676:
677: /* Load IOS image */
678: if (mips64_load_elf_image(cpu,vm->ios_image,
679: (vm->ghost_status == VM_GHOST_RAM_USE),
680: &vm->ios_entry_point) < 0)
681: {
682: vm_error(vm,"failed to load Cisco IOS image '%s'.\n",vm->ios_image);
683: return(-1);
684: }
685:
686: /* Launch the simulation */
687: printf("\nC6MSFC1 '%s': starting simulation (CPU0 PC=0x%llx), "
688: "JIT %sabled.\n",
689: vm->name,cpu->pc,vm->jit_use ? "en":"dis");
690:
691: vm_log(vm,"C6MSFC1_BOOT",
692: "starting instance (CPU0 PC=0x%llx,idle_pc=0x%llx,JIT %s)\n",
693: cpu->pc,cpu->idle_pc,vm->jit_use ? "on":"off");
694:
695: /* Start main CPU */
696: if (vm->ghost_status != VM_GHOST_RAM_GENERATE) {
697: vm->status = VM_STATUS_RUNNING;
698: cpu_start(vm->boot_cpu);
699: } else {
700: vm->status = VM_STATUS_SHUTDOWN;
701: }
702: return(0);
703: }
704:
705: /* Set an IRQ */
706: static void c6msfc1_set_irq(vm_instance_t *vm,u_int irq)
707: {
708: c6msfc1_t *router = VM_C6MSFC1(vm);
709: cpu_mips_t *cpu0 = CPU_MIPS64(vm->boot_cpu);
710: u_int slot,port;
711:
712: switch(irq) {
713: case 0 ... 7:
714: mips64_set_irq(cpu0,irq);
715:
716: if (cpu0->irq_idle_preempt[irq])
717: cpu_idle_break_wait(cpu0->gen);
718: break;
719:
720: case C6MSFC1_NETIO_IRQ_BASE ... C6MSFC1_NETIO_IRQ_END:
721: c6msfc1_net_irq_get_slot_port(irq,&slot,&port);
722: dev_c6msfc1_mpfpga_net_set_irq(router->mpfpga_data,slot,port);
723: break;
724: }
725: }
726:
727: /* Clear an IRQ */
728: static void c6msfc1_clear_irq(vm_instance_t *vm,u_int irq)
729: {
730: c6msfc1_t *router = VM_C6MSFC1(vm);
731: cpu_mips_t *cpu0 = CPU_MIPS64(vm->boot_cpu);
732: u_int slot,port;
733:
734: switch(irq) {
735: case 0 ... 7:
736: mips64_clear_irq(cpu0,irq);
737: break;
738:
739: case C6MSFC1_NETIO_IRQ_BASE ... C6MSFC1_NETIO_IRQ_END:
740: c6msfc1_net_irq_get_slot_port(irq,&slot,&port);
741: dev_c6msfc1_mpfpga_net_clear_irq(router->mpfpga_data,slot,port);
742: break;
743: }
744: }
745:
746: /* Initialize a MSFC1 instance */
747: static int c6msfc1_init_instance(vm_instance_t *vm)
748: {
749: c6msfc1_t *router = VM_C6MSFC1(vm);
750: m_uint32_t rom_entry_point;
751: cpu_mips_t *cpu0;
752:
753: /* Initialize the MSFC1 platform */
754: if (c6msfc1_init_platform(router) == -1) {
755: vm_error(vm,"unable to initialize the platform hardware.\n");
756: return(-1);
757: }
758:
759: /* IRQ routing */
760: vm->set_irq = c6msfc1_set_irq;
761: vm->clear_irq = c6msfc1_clear_irq;
762:
763: /* Load IOS configuration file */
764: if (vm->ios_config != NULL) {
765: vm_nvram_push_config(vm,vm->ios_config);
766: vm->conf_reg &= ~0x40;
767: }
768:
769: /* Load ROM (ELF image or embedded) */
770: cpu0 = CPU_MIPS64(vm->boot_cpu);
771: rom_entry_point = (m_uint32_t)MIPS_ROM_PC;
772:
773: if ((vm->rom_filename != NULL) &&
774: (mips64_load_elf_image(cpu0,vm->rom_filename,0,&rom_entry_point) < 0))
775: {
776: vm_error(vm,"unable to load alternate ROM '%s', "
777: "fallback to embedded ROM.\n\n",vm->rom_filename);
778: vm->rom_filename = NULL;
779: }
780:
781: /* Load symbol file */
782: if (vm->sym_filename) {
783: mips64_sym_load_file(cpu0,vm->sym_filename);
784: cpu0->sym_trace = 1;
785: }
786:
787: return(c6msfc1_boot_ios(router));
788: }
789:
790: /* Stop a MSFC1 instance */
791: static int c6msfc1_stop_instance(vm_instance_t *vm)
792: {
793: printf("\nC6MSFC1 '%s': stopping simulation.\n",vm->name);
794: vm_log(vm,"C6MSFC1_STOP","stopping simulation.\n");
795:
796: /* Stop all CPUs */
797: if (vm->cpu_group != NULL) {
798: vm_stop(vm);
799:
800: if (cpu_group_sync_state(vm->cpu_group) == -1) {
801: vm_error(vm,"unable to sync with system CPUs.\n");
802: return(-1);
803: }
804: }
805:
806: /* Free resources that were used during execution to emulate hardware */
807: vm_slot_shutdown_all(vm);
808: vm_hardware_shutdown(vm);
809: return(0);
810: }
811:
812: /* Get MAC address MSB */
813: static u_int c6msfc1_get_mac_addr_msb(void)
814: {
815: return(0xC6);
816: }
817:
818: /* Show specific CLI options */
819: static void c6msfc1_cli_show_options(vm_instance_t *vm)
820: {
821: printf(" -s <pa_nio> : Bind a Network IO interface to a "
822: "Port Adapter\n");
823: }
824:
825: /* Platform definition */
826: static vm_platform_t c6msfc1_platform = {
827: "c6msfc1", "C6MSFC1", "C6MSFC1",
828: c6msfc1_create_instance,
829: c6msfc1_delete_instance,
830: c6msfc1_init_instance,
831: c6msfc1_stop_instance,
832: c6msfc1_nvram_extract_config,
833: c6msfc1_nvram_push_config,
834: c6msfc1_get_mac_addr_msb,
835: NULL,
836: NULL,
837: c6msfc1_cli_show_options,
838: NULL,
839: };
840:
841: /* Register the C6-MSFC1 platform */
842: int c6msfc1_platform_register(void)
843: {
844: return(vm_platform_register(&c6msfc1_platform));
845: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.