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