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