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