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