/[dynamips]/trunk/dev_msfc1.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/dev_msfc1.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 11 - (hide annotations)
Sat Oct 6 16:33:40 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.8-RC1/dev_msfc1.c
File MIME type: text/plain
File size: 38047 byte(s)
dynamips-0.2.8-RC1

1 dpavlin 8 /*
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_msfc1.h"
30     #include "dev_vtty.h"
31     #include "registry.h"
32     #include "net.h"
33    
34     /* MSFC1 EEPROM */
35     static m_uint16_t eeprom_msfc1_data[128] = {
36     0xabab, 0x0190, 0x1262, 0x0100, 0x0002, 0x6003, 0x00cf, 0x4369,
37     0x7363, 0x6f20, 0x5379, 0x7374, 0x656d, 0x732c, 0x2049, 0x6e63,
38     0x2e00, 0x5753, 0x2d46, 0x3630, 0x3031, 0x2d52, 0x5346, 0x4300,
39     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
40     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3733, 0x2d37, 0x3135,
41     0x302d, 0x3036, 0x0000, 0x0000, 0x0000, 0x4130, 0x3100, 0x0000,
42     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
43     0x0000, 0x0000, 0x012d, 0x0000, 0x0000, 0x0009, 0x0005, 0x0001,
44     0x0003, 0x0001, 0x0001, 0x0002, 0x00cf, 0xffbf, 0x0000, 0x0000,
45     0x6003, 0x0162, 0x0afd, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
46     0x0000, 0x0000, 0x0000, 0x0005, 0x00e0, 0xaabb, 0xcc00, 0x0100,
47     0x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
48     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
49     0x1401, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
50     0x1000, 0x4b3c, 0x4132, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080,
51     0x8080, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
52     };
53    
54     static struct cisco_eeprom msfc1_eeprom = {
55     "msfc1", eeprom_msfc1_data, sizeof(eeprom_msfc1_data)/2,
56     };
57    
58     /* ====================================================================== */
59     /* EOBC - Ethernet Out of Band Channel */
60     /* ====================================================================== */
61     static int dev_msfc1_eobc_init(msfc1_t *router,char *name,u_int pa_bay)
62     {
63     vm_instance_t *vm = router->vm;
64     struct dec21140_data *data;
65    
66     /* Create the DEC21140 chip */
67     data = dev_dec21140_init(vm,name,vm->pci_bus[0],6,MSFC1_NETIO_IRQ);
68     if (!data) return(-1);
69    
70     /* Store device info into the router structure */
71     return(msfc1_pa_set_drvinfo(router,pa_bay,data));
72     }
73    
74     /* Remove EOBC */
75     static int dev_msfc1_eobc_shutdown(msfc1_t *router,u_int pa_bay)
76     {
77     struct msfc1_pa_bay *bay;
78    
79     if (!(bay = msfc1_pa_get_info(router,pa_bay)))
80     return(-1);
81    
82     dev_dec21140_remove(bay->drv_info);
83     return(0);
84     }
85    
86     /* Bind a Network IO descriptor */
87     static int dev_msfc1_eobc_set_nio(msfc1_t *router,u_int pa_bay,u_int port_id,
88     netio_desc_t *nio)
89     {
90     struct dec21140_data *d;
91    
92     if ((port_id != 0) || !(d = msfc1_pa_get_drvinfo(router,pa_bay)))
93     return(-1);
94    
95     return(dev_dec21140_set_nio(d,nio));
96     }
97    
98     /* Unbind a Network IO descriptor */
99     static int dev_msfc1_eobc_unset_nio(msfc1_t *router,u_int pa_bay,
100     u_int port_id)
101     {
102     struct dec21140_data *d;
103    
104     if ((port_id != 0) || !(d = msfc1_pa_get_drvinfo(router,pa_bay)))
105     return(-1);
106    
107     dev_dec21140_unset_nio(d);
108     return(0);
109     }
110    
111     /* EOBC driver */
112     struct msfc1_pa_driver dev_msfc1_eobc = {
113     "MSFC1_EOBC", 0,
114     dev_msfc1_eobc_init,
115     dev_msfc1_eobc_shutdown,
116     dev_msfc1_eobc_set_nio,
117     dev_msfc1_eobc_unset_nio,
118     NULL,
119     };
120    
121     /* ====================================================================== */
122     /* IBC - InBand Channel */
123     /* ====================================================================== */
124     static int dev_msfc1_ibc_init(msfc1_t *router,char *name,u_int pa_bay)
125     {
126     vm_instance_t *vm = router->vm;
127     struct i8254x_data *data;
128    
129     /* Create the Intel Wiseman/Livengood chip */
130     data = dev_i8254x_init(vm,name,0,vm->pci_bus_pool[24],1,MSFC1_NETIO_IRQ);
131     if (!data) return(-1);
132    
133     /* Store device info into the router structure */
134     return(msfc1_pa_set_drvinfo(router,pa_bay,data));
135     }
136    
137     /* Remove EOBC */
138     static int dev_msfc1_ibc_shutdown(msfc1_t *router,u_int pa_bay)
139     {
140     struct msfc1_pa_bay *bay;
141    
142     if (!(bay = msfc1_pa_get_info(router,pa_bay)))
143     return(-1);
144    
145     dev_i8254x_remove(bay->drv_info);
146     return(0);
147     }
148    
149     /* Bind a Network IO descriptor */
150     static int dev_msfc1_ibc_set_nio(msfc1_t *router,u_int pa_bay,u_int port_id,
151     netio_desc_t *nio)
152     {
153     struct i8254x_data *d;
154    
155     if ((port_id != 1) || !(d = msfc1_pa_get_drvinfo(router,pa_bay)))
156     return(-1);
157    
158     return(dev_i8254x_set_nio(d,nio));
159     }
160    
161     /* Unbind a Network IO descriptor */
162     static int dev_msfc1_ibc_unset_nio(msfc1_t *router,u_int pa_bay,
163     u_int port_id)
164     {
165     struct i8254x_data *d;
166    
167     if ((port_id != 0) || !(d = msfc1_pa_get_drvinfo(router,pa_bay)))
168     return(-1);
169    
170     dev_i8254x_unset_nio(d);
171     return(0);
172     }
173    
174     /* IBC driver */
175     struct msfc1_pa_driver dev_msfc1_ibc = {
176     "MSFC1_IBC", 0,
177     dev_msfc1_ibc_init,
178     dev_msfc1_ibc_shutdown,
179     dev_msfc1_ibc_set_nio,
180     dev_msfc1_ibc_unset_nio,
181     NULL,
182     };
183    
184     /* ======================================================================== */
185     /* Port Adapter Drivers */
186     /* ======================================================================== */
187     static struct msfc1_pa_driver *pa_drivers[] = {
188     &dev_msfc1_eobc,
189     &dev_msfc1_ibc,
190     NULL,
191     };
192    
193     /* ======================================================================== */
194     /* MSFC1 router instances */
195     /* ======================================================================== */
196    
197     /* Directly extract the configuration from the NVRAM device */
198     ssize_t msfc1_nvram_extract_config(vm_instance_t *vm,char **buffer)
199     {
200     u_char *base_ptr,*ios_ptr,*cfg_ptr,*end_ptr;
201     m_uint32_t start,end,nvlen,clen;
202     m_uint16_t magic1,magic2;
203     struct vdevice *nvram_dev;
204     m_uint64_t nvram_addr;
205     off_t nvram_size;
206     int fd;
207    
208     if ((nvram_dev = dev_get_by_name(vm,"nvram")))
209     dev_sync(nvram_dev);
210    
211     fd = vm_mmap_open_file(vm,"nvram",&base_ptr,&nvram_size);
212    
213     if (fd == -1)
214     return(-1);
215    
216     nvram_addr = MSFC1_NVRAM_ADDR;
217     ios_ptr = base_ptr + vm->nvram_rom_space;
218     end_ptr = base_ptr + nvram_size;
219    
220     if ((ios_ptr + 0x30) >= end_ptr) {
221     vm_error(vm,"NVRAM file too small\n");
222     return(-1);
223     }
224    
225     magic1 = ntohs(*PTR_ADJUST(m_uint16_t *,ios_ptr,0x06));
226     magic2 = ntohs(*PTR_ADJUST(m_uint16_t *,ios_ptr,0x08));
227    
228     if ((magic1 != 0xF0A5) || (magic2 != 0xABCD)) {
229     vm_error(vm,"unable to find IOS magic numbers (0x%x,0x%x)!\n",
230     magic1,magic2);
231     return(-1);
232     }
233    
234     start = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x10)) + 1;
235     end = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x14));
236     nvlen = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x18));
237     clen = end - start;
238    
239     if ((clen + 1) != nvlen) {
240     vm_error(vm,"invalid configuration size (0x%x)\n",nvlen);
241     return(-1);
242     }
243    
244     if (!(*buffer = malloc(clen+1))) {
245     vm_error(vm,"unable to allocate config buffer (%u bytes)\n",clen);
246     return(-1);
247     }
248    
249     cfg_ptr = base_ptr + (start - nvram_addr);
250    
251     if ((start < nvram_addr) || ((cfg_ptr + clen) > end_ptr)) {
252     vm_error(vm,"NVRAM file too small\n");
253     return(-1);
254     }
255    
256     memcpy(*buffer,cfg_ptr,clen);
257     (*buffer)[clen] = 0;
258     return(clen);
259     }
260    
261     /* Directly push the IOS configuration to the NVRAM device */
262     int msfc1_nvram_push_config(vm_instance_t *vm,char *buffer,size_t len)
263     {
264     u_char *base_ptr,*ios_ptr,*cfg_ptr;
265     m_uint32_t cfg_addr,cfg_offset;
266     m_uint32_t nvram_addr,cklen;
267     m_uint16_t cksum;
268     int fd;
269    
270     fd = vm_mmap_create_file(vm,"nvram",vm->nvram_size*1024,&base_ptr);
271    
272     if (fd == -1)
273     return(-1);
274    
275     cfg_offset = 0x2c;
276     ios_ptr = base_ptr + vm->nvram_rom_space;
277     cfg_ptr = ios_ptr + cfg_offset;
278    
279     nvram_addr = MSFC1_NVRAM_ADDR;
280     cfg_addr = nvram_addr + vm->nvram_rom_space + cfg_offset;
281    
282     /* Write IOS tag, uncompressed config... */
283     *PTR_ADJUST(m_uint16_t *,ios_ptr,0x06) = htons(0xF0A5);
284     *PTR_ADJUST(m_uint16_t *,ios_ptr,0x08) = htons(0xABCD);
285     *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0a) = htons(0x0001);
286     *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0c) = htons(0x0000);
287     *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0e) = htons(0x0000);
288    
289     /* Store file contents to NVRAM */
290     memcpy(cfg_ptr,buffer,len);
291    
292     /* Write config addresses + size */
293     *PTR_ADJUST(m_uint32_t *,ios_ptr,0x10) = htonl(cfg_addr);
294     *PTR_ADJUST(m_uint32_t *,ios_ptr,0x14) = htonl(cfg_addr + len);
295     *PTR_ADJUST(m_uint32_t *,ios_ptr,0x18) = htonl(len);
296    
297     /* Compute the checksum */
298     cklen = (vm->nvram_size*1024) - (vm->nvram_rom_space + 0x08);
299     cksum = nvram_cksum((m_uint16_t *)(ios_ptr+0x08),cklen);
300     *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0c) = htons(cksum);
301    
302     vm_mmap_close_file(fd,base_ptr,vm->nvram_size*1024);
303     return(0);
304     }
305    
306     /* Set MSFC eeprom definition */
307     static int msfc1_set_eeprom(msfc1_t *router)
308     {
309     if (cisco_eeprom_copy(&router->cpu_eeprom,&msfc1_eeprom) == -1) {
310     vm_error(router->vm,"unable to set NPE EEPROM.\n");
311     return(-1);
312     }
313    
314     return(0);
315     }
316    
317     /* Set the base MAC address of the chassis */
318     static int msfc1_burn_mac_addr(msfc1_t *router,n_eth_addr_t *addr)
319     {
320     m_uint8_t eeprom_ver;
321    
322     /* Read EEPROM format version */
323     cisco_eeprom_get_byte(&router->mp_eeprom,0,&eeprom_ver);
324    
325     if (eeprom_ver != 1) {
326     vm_error(router->vm,"msfc1_burn_mac_addr: unable to handle "
327     "EEPROM version %u\n",eeprom_ver);
328     return(-1);
329     }
330    
331     cisco_eeprom_set_region(&router->mp_eeprom,12,addr->eth_addr_byte,6);
332     return(0);
333     }
334    
335     /* Free specific hardware resources used by MSFC1 */
336     static void msfc1_free_hw_ressources(msfc1_t *router)
337     {
338     /* Shutdown all Port Adapters */
339     msfc1_pa_shutdown_all(router);
340     }
341    
342     /* Create a new router instance */
343     msfc1_t *msfc1_create_instance(char *name,int instance_id)
344     {
345     msfc1_t *router;
346    
347     if (!(router = malloc(sizeof(*router)))) {
348     fprintf(stderr,"MSFC1 '%s': Unable to create new instance!\n",name);
349     return NULL;
350     }
351    
352     memset(router,0,sizeof(*router));
353    
354     if (!(router->vm = vm_create(name,instance_id,VM_TYPE_MSFC1))) {
355     fprintf(stderr,"MSFC1 '%s': unable to create VM instance!\n",name);
356     goto err_vm;
357     }
358    
359     msfc1_init_defaults(router);
360     router->vm->hw_data = router;
361     router->vm->elf_machine_id = MSFC1_ELF_MACHINE_ID;
362     return router;
363    
364     err_vm:
365     free(router);
366     return NULL;
367     }
368    
369     /* Free resources used by a router instance */
370     static int msfc1_free_instance(void *data,void *arg)
371     {
372     vm_instance_t *vm = data;
373     msfc1_t *router;
374     int i;
375    
376     if (vm->type == VM_TYPE_MSFC1) {
377     router = VM_MSFC1(vm);
378    
379     /* Stop all CPUs */
380     if (vm->cpu_group != NULL) {
381     vm_stop(vm);
382    
383     if (cpu_group_sync_state(vm->cpu_group) == -1) {
384     vm_error(vm,"unable to sync with system CPUs.\n");
385     return(FALSE);
386     }
387     }
388    
389     /* Remove NIO bindings */
390     for(i=0;i<MSFC1_MAX_PA_BAYS;i++)
391     msfc1_pa_remove_all_nio_bindings(router,i);
392    
393     /* Free specific HW resources */
394     msfc1_free_hw_ressources(router);
395    
396     /* Free EEPROMs */
397     cisco_eeprom_free(&router->cpu_eeprom);
398     cisco_eeprom_free(&router->mp_eeprom);
399     cisco_eeprom_free(&router->pem_eeprom);
400    
401     /* Free all resources used by VM */
402     vm_free(vm);
403    
404     /* Free the router structure */
405     free(router);
406     return(TRUE);
407     }
408    
409     return(FALSE);
410     }
411    
412     /* Delete a router instance */
413     int msfc1_delete_instance(char *name)
414     {
415     return(registry_delete_if_unused(name,OBJ_TYPE_VM,
416     msfc1_free_instance,NULL));
417     }
418    
419     /* Delete all router instances */
420     int msfc1_delete_all_instances(void)
421     {
422     return(registry_delete_type(OBJ_TYPE_VM,msfc1_free_instance,NULL));
423     }
424    
425     /* Save configuration of a MSFC1 instance */
426     void msfc1_save_config(msfc1_t *router,FILE *fd)
427     {
428     vm_instance_t *vm = router->vm;
429     struct msfc1_nio_binding *nb;
430     struct msfc1_pa_bay *bay;
431     int i;
432    
433     /* General settings */
434     fprintf(fd,"msfc1 create %s %u\n",vm->name,vm->instance_id);
435    
436     /* VM configuration */
437     vm_save_config(vm,fd);
438    
439     /* Port Adapter settings */
440     for(i=0;i<MSFC1_MAX_PA_BAYS;i++) {
441     if (!(bay = msfc1_pa_get_info(router,i)))
442     continue;
443    
444     if (bay->dev_type) {
445     fprintf(fd,"msfc1 add_pa_binding %s %u %s\n",
446     vm->name,i,bay->dev_type);
447     }
448    
449     for(nb=bay->nio_list;nb;nb=nb->next) {
450     fprintf(fd,"msfc1 add_nio_binding %s %u %u %s\n",
451     vm->name,i,nb->port_id,nb->nio->name);
452     }
453     }
454    
455     fprintf(fd,"\n");
456     }
457    
458     /* Save configurations of all MSFC1 instances */
459     static void msfc1_reg_save_config(registry_entry_t *entry,void *opt,int *err)
460     {
461     vm_instance_t *vm = entry->data;
462     msfc1_t *router = VM_MSFC1(vm);
463    
464     if (vm->type == VM_TYPE_MSFC1)
465     msfc1_save_config(router,(FILE *)opt);
466     }
467    
468     /* Unset PA EEPROM definition (empty bay) */
469     int msfc1_pa_unset_eeprom(msfc1_t *router,u_int pa_bay)
470     {
471     if (pa_bay >= MSFC1_MAX_PA_BAYS) {
472     vm_error(router->vm,"msfc1_pa_set_eeprom: invalid PA Bay %u.\n",pa_bay);
473     return(-1);
474     }
475    
476     cisco_eeprom_free(&router->pa_bay[pa_bay].eeprom);
477     return(0);
478     }
479    
480     /* Check if a bay has a port adapter */
481     int msfc1_pa_check_eeprom(msfc1_t *router,u_int pa_bay)
482     {
483     if (pa_bay >= MSFC1_MAX_PA_BAYS)
484     return(FALSE);
485    
486     return(cisco_eeprom_valid(&router->pa_bay[pa_bay].eeprom));
487     }
488    
489     /* Get bay info */
490     struct msfc1_pa_bay *msfc1_pa_get_info(msfc1_t *router,u_int pa_bay)
491     {
492     if (pa_bay >= MSFC1_MAX_PA_BAYS)
493     return NULL;
494    
495     return(&router->pa_bay[pa_bay]);
496     }
497    
498     /* Get PA type */
499     char *msfc1_pa_get_type(msfc1_t *router,u_int pa_bay)
500     {
501     struct msfc1_pa_bay *bay;
502    
503     bay = msfc1_pa_get_info(router,pa_bay);
504     return((bay != NULL) ? bay->dev_type : NULL);
505     }
506    
507     /* Get driver info about the specified slot */
508     void *msfc1_pa_get_drvinfo(msfc1_t *router,u_int pa_bay)
509     {
510     struct msfc1_pa_bay *bay;
511    
512     bay = msfc1_pa_get_info(router,pa_bay);
513     return((bay != NULL) ? bay->drv_info : NULL);
514     }
515    
516     /* Set driver info for the specified slot */
517     int msfc1_pa_set_drvinfo(msfc1_t *router,u_int pa_bay,void *drv_info)
518     {
519     struct msfc1_pa_bay *bay;
520    
521     if (!(bay = msfc1_pa_get_info(router,pa_bay)))
522     return(-1);
523    
524     bay->drv_info = drv_info;
525     return(0);
526     }
527    
528     /* Get a PA driver */
529     static struct msfc1_pa_driver *msfc1_pa_get_driver(char *dev_type)
530     {
531     int i;
532    
533     for(i=0;pa_drivers[i];i++)
534     if (!strcmp(pa_drivers[i]->dev_type,dev_type))
535     return pa_drivers[i];
536    
537     return NULL;
538     }
539    
540     /* Add a PA binding */
541     int msfc1_pa_add_binding(msfc1_t *router,char *dev_type,u_int pa_bay)
542     {
543     struct msfc1_pa_driver *pa_driver;
544     struct msfc1_pa_bay *bay;
545    
546     if (!(bay = msfc1_pa_get_info(router,pa_bay)))
547     return(-1);
548    
549     /* check that this bay is empty */
550     if (bay->dev_type != NULL) {
551     vm_error(router->vm,"a PA already exists in slot %u.\n",pa_bay);
552     return(-1);
553     }
554    
555     /* find the PA driver */
556     if (!(pa_driver = msfc1_pa_get_driver(dev_type))) {
557     vm_error(router->vm,"unknown PA type '%s'.\n",dev_type);
558     return(-1);
559     }
560    
561     bay->dev_type = pa_driver->dev_type;
562     bay->pa_driver = pa_driver;
563     return(0);
564     }
565    
566     /* Remove a PA binding */
567     int msfc1_pa_remove_binding(msfc1_t *router,u_int pa_bay)
568     {
569     struct msfc1_pa_bay *bay;
570    
571     if (!(bay = msfc1_pa_get_info(router,pa_bay)))
572     return(-1);
573    
574     /* stop if this bay is still active */
575     if (bay->drv_info != NULL) {
576     vm_error(router->vm,"slot %u still active.\n",pa_bay);
577     return(-1);
578     }
579    
580     /* check that this bay is not empty */
581     if (bay->dev_type == NULL) {
582     vm_error(router->vm,"slot %u is empty.\n",pa_bay);
583     return(-1);
584     }
585    
586     /* remove all NIOs bindings */
587     msfc1_pa_remove_all_nio_bindings(router,pa_bay);
588    
589     bay->dev_type = NULL;
590     bay->pa_driver = NULL;
591     return(0);
592     }
593    
594     /* Find a NIO binding */
595     struct msfc1_nio_binding *
596     msfc1_pa_find_nio_binding(msfc1_t *router,u_int pa_bay,u_int port_id)
597     {
598     struct msfc1_nio_binding *nb;
599     struct msfc1_pa_bay *bay;
600    
601     if (!(bay = msfc1_pa_get_info(router,pa_bay)))
602     return NULL;
603    
604     for(nb=bay->nio_list;nb;nb=nb->next)
605     if (nb->port_id == port_id)
606     return nb;
607    
608     return NULL;
609     }
610    
611     /* Add a network IO binding */
612     int msfc1_pa_add_nio_binding(msfc1_t *router,u_int pa_bay,u_int port_id,
613     char *nio_name)
614     {
615     struct msfc1_nio_binding *nb;
616     struct msfc1_pa_bay *bay;
617     netio_desc_t *nio;
618    
619     if (!(bay = msfc1_pa_get_info(router,pa_bay)))
620     return(-1);
621    
622     /* check that a NIO is not already bound to this port */
623     if (msfc1_pa_find_nio_binding(router,pa_bay,port_id) != NULL) {
624     vm_error(router->vm,"a NIO already exists for interface %u/%u\n",
625     pa_bay,port_id);
626     return(-1);
627     }
628    
629     /* acquire a reference on the NIO object */
630     if (!(nio = netio_acquire(nio_name))) {
631     vm_error(router->vm,"unable to find NIO '%s'.\n",nio_name);
632     return(-1);
633     }
634    
635     /* create a new binding */
636     if (!(nb = malloc(sizeof(*nb)))) {
637     vm_error(router->vm,"unable to create NIO binding "
638     "for interface %u/%u.\n",pa_bay,port_id);
639     netio_release(nio_name);
640     return(-1);
641     }
642    
643     memset(nb,0,sizeof(*nb));
644     nb->nio = nio;
645     nb->port_id = port_id;
646     nb->next = bay->nio_list;
647     if (nb->next) nb->next->prev = nb;
648     bay->nio_list = nb;
649     return(0);
650     }
651    
652     /* Remove a NIO binding */
653     int msfc1_pa_remove_nio_binding(msfc1_t *router,u_int pa_bay,u_int port_id)
654     {
655     struct msfc1_nio_binding *nb;
656     struct msfc1_pa_bay *bay;
657    
658     if (!(bay = msfc1_pa_get_info(router,pa_bay)))
659     return(-1);
660    
661     if (!(nb = msfc1_pa_find_nio_binding(router,pa_bay,port_id)))
662     return(-1); /* no nio binding for this slot/port */
663    
664     /* tell the PA driver to stop using this NIO */
665     if (bay->pa_driver)
666     bay->pa_driver->pa_unset_nio(router,pa_bay,port_id);
667    
668     /* remove this entry from the double linked list */
669     if (nb->next)
670     nb->next->prev = nb->prev;
671    
672     if (nb->prev) {
673     nb->prev->next = nb->next;
674     } else {
675     bay->nio_list = nb->next;
676     }
677    
678     /* unreference NIO object */
679     netio_release(nb->nio->name);
680     free(nb);
681     return(0);
682     }
683    
684     /* Remove all NIO bindings for the specified PA */
685     int msfc1_pa_remove_all_nio_bindings(msfc1_t *router,u_int pa_bay)
686     {
687     struct msfc1_nio_binding *nb,*next;
688     struct msfc1_pa_bay *bay;
689    
690     if (!(bay = msfc1_pa_get_info(router,pa_bay)))
691     return(-1);
692    
693     for(nb=bay->nio_list;nb;nb=next) {
694     next = nb->next;
695    
696     /* tell the PA driver to stop using this NIO */
697     if (bay->pa_driver)
698     bay->pa_driver->pa_unset_nio(router,pa_bay,nb->port_id);
699    
700     /* unreference NIO object */
701     netio_release(nb->nio->name);
702     free(nb);
703     }
704    
705     bay->nio_list = NULL;
706     return(0);
707     }
708    
709     /* Enable a Network IO descriptor for a Port Adapter */
710     int msfc1_pa_enable_nio(msfc1_t *router,u_int pa_bay,u_int port_id)
711     {
712     struct msfc1_nio_binding *nb;
713     struct msfc1_pa_bay *bay;
714    
715     if (!(bay = msfc1_pa_get_info(router,pa_bay)))
716     return(-1);
717    
718     /* check that we have an NIO binding for this interface */
719     if (!(nb = msfc1_pa_find_nio_binding(router,pa_bay,port_id)))
720     return(-1);
721    
722     /* check that the driver is defined and successfully initialized */
723     if (!bay->pa_driver || !bay->drv_info)
724     return(-1);
725    
726     return(bay->pa_driver->pa_set_nio(router,pa_bay,port_id,nb->nio));
727     }
728    
729     /* Disable Network IO descriptor of a Port Adapter */
730     int msfc1_pa_disable_nio(msfc1_t *router,u_int pa_bay,u_int port_id)
731     {
732     struct msfc1_pa_bay *bay;
733    
734     if (!(bay = msfc1_pa_get_info(router,pa_bay)))
735     return(-1);
736    
737     /* check that the driver is defined and successfully initialized */
738     if (!bay->pa_driver || !bay->drv_info)
739     return(-1);
740    
741     return(bay->pa_driver->pa_unset_nio(router,pa_bay,port_id));
742     }
743    
744     /* Enable all NIO of the specified PA */
745     int msfc1_pa_enable_all_nio(msfc1_t *router,u_int pa_bay)
746     {
747     struct msfc1_nio_binding *nb;
748     struct msfc1_pa_bay *bay;
749    
750     if (!(bay = msfc1_pa_get_info(router,pa_bay)))
751     return(-1);
752    
753     /* check that the driver is defined and successfully initialized */
754     if (!bay->pa_driver || !bay->drv_info)
755     return(-1);
756    
757     for(nb=bay->nio_list;nb;nb=nb->next)
758     bay->pa_driver->pa_set_nio(router,pa_bay,nb->port_id,nb->nio);
759    
760     return(0);
761     }
762    
763     /* Disable all NIO of the specified PA */
764     int msfc1_pa_disable_all_nio(msfc1_t *router,u_int pa_bay)
765     {
766     struct msfc1_nio_binding *nb;
767     struct msfc1_pa_bay *bay;
768    
769     if (!(bay = msfc1_pa_get_info(router,pa_bay)))
770     return(-1);
771    
772     /* check that the driver is defined and successfully initialized */
773     if (!bay->pa_driver || !bay->drv_info)
774     return(-1);
775    
776     for(nb=bay->nio_list;nb;nb=nb->next)
777     bay->pa_driver->pa_unset_nio(router,pa_bay,nb->port_id);
778    
779     return(0);
780     }
781    
782     /* Initialize a Port Adapter */
783     int msfc1_pa_init(msfc1_t *router,u_int pa_bay)
784     {
785     struct msfc1_pa_bay *bay;
786     size_t len;
787    
788     if (!(bay = msfc1_pa_get_info(router,pa_bay)))
789     return(-1);
790    
791     /* Check that a device type is defined for this bay */
792     if (!bay->dev_type || !bay->pa_driver) {
793     vm_error(router->vm,"trying to init empty slot %u.\n",pa_bay);
794     return(-1);
795     }
796    
797     /* Allocate device name */
798     len = strlen(bay->dev_type) + 10;
799     if (!(bay->dev_name = malloc(len))) {
800     vm_error(router->vm,"unable to allocate device name.\n");
801     return(-1);
802     }
803    
804     snprintf(bay->dev_name,len,"%s(%u)",bay->dev_type,pa_bay);
805    
806     /* Initialize PA driver */
807     if (bay->pa_driver->pa_init(router,bay->dev_name,pa_bay) == -1) {
808     vm_error(router->vm,"unable to initialize PA %u.\n",pa_bay);
809     return(-1);
810     }
811    
812     /* Enable all NIO */
813     msfc1_pa_enable_all_nio(router,pa_bay);
814     return(0);
815     }
816    
817     /* Shutdown a Port Adapter */
818     int msfc1_pa_shutdown(msfc1_t *router,u_int pa_bay)
819     {
820     struct msfc1_pa_bay *bay;
821    
822     if (!(bay = msfc1_pa_get_info(router,pa_bay)))
823     return(-1);
824    
825     /* Check that a device type is defined for this bay */
826     if (!bay->dev_type || !bay->pa_driver) {
827     vm_error(router->vm,"trying to shut down an empty bay %u.\n",pa_bay);
828     return(-1);
829     }
830    
831     /* Disable all NIO */
832     msfc1_pa_disable_all_nio(router,pa_bay);
833    
834     /* Shutdown the PA driver */
835     if (bay->drv_info && (bay->pa_driver->pa_shutdown(router,pa_bay) == -1)) {
836     vm_error(router->vm,"unable to shutdown PA %u.\n",pa_bay);
837     return(-1);
838     }
839    
840     free(bay->dev_name);
841     bay->dev_name = NULL;
842     bay->drv_info = NULL;
843     return(0);
844     }
845    
846     /* Shutdown all PA of a router */
847     int msfc1_pa_shutdown_all(msfc1_t *router)
848     {
849     int i;
850    
851     for(i=0;i<MSFC1_MAX_PA_BAYS;i++) {
852     if (!router->pa_bay[i].dev_type)
853     continue;
854    
855     msfc1_pa_shutdown(router,i);
856     }
857    
858     return(0);
859     }
860    
861     /* Show info about all NMs */
862     int msfc1_pa_show_all_info(msfc1_t *router)
863     {
864     struct msfc1_pa_bay *bay;
865     int i;
866    
867     for(i=0;i<MSFC1_MAX_PA_BAYS;i++) {
868     if (!(bay = msfc1_pa_get_info(router,i)) || !bay->pa_driver)
869     continue;
870    
871     if (bay->pa_driver->pa_show_info != NULL)
872     bay->pa_driver->pa_show_info(router,i);
873     }
874    
875     return(0);
876     }
877    
878     /* Maximum number of tokens in a PA description */
879     #define PA_DESC_MAX_TOKENS 8
880    
881     /* Create a Port Adapter (command line) */
882     int msfc1_cmd_pa_create(msfc1_t *router,char *str)
883     {
884     char *tokens[PA_DESC_MAX_TOKENS];
885     int i,count,res;
886     u_int pa_bay;
887    
888     /* A port adapter description is like "1:PA-FE-TX" */
889     if ((count = m_strsplit(str,':',tokens,PA_DESC_MAX_TOKENS)) != 2) {
890     vm_error(router->vm,"unable to parse PA description '%s'.\n",str);
891     return(-1);
892     }
893    
894     /* Parse the PA bay id */
895     pa_bay = atoi(tokens[0]);
896    
897     /* Add this new PA to the current PA list */
898     res = msfc1_pa_add_binding(router,tokens[1],pa_bay);
899    
900     /* The complete array was cleaned by strsplit */
901     for(i=0;i<PA_DESC_MAX_TOKENS;i++)
902     free(tokens[i]);
903    
904     return(res);
905     }
906    
907     /* Add a Network IO descriptor binding (command line) */
908     int msfc1_cmd_add_nio(msfc1_t *router,char *str)
909     {
910     char *tokens[PA_DESC_MAX_TOKENS];
911     int i,count,nio_type,res=-1;
912     u_int pa_bay,port_id;
913     netio_desc_t *nio;
914     char nio_name[128];
915    
916     /* A port adapter description is like "1:3:tap:tap0" */
917     if ((count = m_strsplit(str,':',tokens,PA_DESC_MAX_TOKENS)) < 3) {
918     vm_error(router->vm,"unable to parse NIO description '%s'.\n",str);
919     return(-1);
920     }
921    
922     /* Parse the PA bay */
923     pa_bay = atoi(tokens[0]);
924    
925     /* Parse the PA port id */
926     port_id = atoi(tokens[1]);
927    
928     /* Autogenerate a NIO name */
929     snprintf(nio_name,sizeof(nio_name),"msfc1-i%u/%u/%u",
930     router->vm->instance_id,pa_bay,port_id);
931    
932     /* Create the Network IO descriptor */
933     nio = NULL;
934     nio_type = netio_get_type(tokens[2]);
935    
936     switch(nio_type) {
937     case NETIO_TYPE_UNIX:
938     if (count != 5) {
939     vm_error(router->vm,
940     "invalid number of arguments for UNIX NIO '%s'\n",str);
941     goto done;
942     }
943    
944     nio = netio_desc_create_unix(nio_name,tokens[3],tokens[4]);
945     break;
946    
947     case NETIO_TYPE_VDE:
948     if (count != 5) {
949     vm_error(router->vm,
950     "invalid number of arguments for VDE NIO '%s'\n",str);
951     goto done;
952     }
953    
954     nio = netio_desc_create_vde(nio_name,tokens[3],tokens[4]);
955     break;
956    
957     case NETIO_TYPE_TAP:
958     if (count != 4) {
959     vm_error(router->vm,
960     "invalid number of arguments for TAP NIO '%s'\n",str);
961     goto done;
962     }
963    
964     nio = netio_desc_create_tap(nio_name,tokens[3]);
965     break;
966    
967     case NETIO_TYPE_UDP:
968     if (count != 6) {
969     vm_error(router->vm,
970     "invalid number of arguments for UDP NIO '%s'\n",str);
971     goto done;
972     }
973    
974     nio = netio_desc_create_udp(nio_name,atoi(tokens[3]),
975     tokens[4],atoi(tokens[5]));
976     break;
977    
978     case NETIO_TYPE_TCP_CLI:
979     if (count != 5) {
980     vm_error(router->vm,
981     "invalid number of arguments for TCP CLI NIO '%s'\n",str);
982     goto done;
983     }
984    
985     nio = netio_desc_create_tcp_cli(nio_name,tokens[3],tokens[4]);
986     break;
987    
988     case NETIO_TYPE_TCP_SER:
989     if (count != 4) {
990     vm_error(router->vm,
991     "invalid number of arguments for TCP SER NIO '%s'\n",str);
992     goto done;
993     }
994    
995     nio = netio_desc_create_tcp_ser(nio_name,tokens[3]);
996     break;
997    
998     case NETIO_TYPE_NULL:
999     nio = netio_desc_create_null(nio_name);
1000     break;
1001    
1002     #ifdef LINUX_ETH
1003     case NETIO_TYPE_LINUX_ETH:
1004     if (count != 4) {
1005     vm_error(router->vm,
1006     "invalid number of arguments for Linux Eth NIO '%s'\n",
1007     str);
1008     goto done;
1009     }
1010    
1011     nio = netio_desc_create_lnxeth(nio_name,tokens[3]);
1012     break;
1013     #endif
1014    
1015     #ifdef GEN_ETH
1016     case NETIO_TYPE_GEN_ETH:
1017     if (count != 4) {
1018     vm_error(router->vm,"invalid number of "
1019     "arguments for Generic Eth NIO '%s'\n",str);
1020     goto done;
1021     }
1022    
1023     nio = netio_desc_create_geneth(nio_name,tokens[3]);
1024     break;
1025     #endif
1026    
1027     default:
1028     vm_error(router->vm,"unknown NETIO type '%s'\n",tokens[2]);
1029     goto done;
1030     }
1031    
1032     if (!nio) {
1033     fprintf(stderr,"msfc1_cmd_add_nio: unable to create NETIO "
1034     "descriptor for PA bay %u\n",pa_bay);
1035     goto done;
1036     }
1037    
1038     if (msfc1_pa_add_nio_binding(router,pa_bay,port_id,nio_name) == -1) {
1039     vm_error(router->vm,"unable to add NETIO binding for slot %u\n",pa_bay);
1040     netio_release(nio_name);
1041     netio_delete(nio_name);
1042     goto done;
1043     }
1044    
1045     netio_release(nio_name);
1046     res = 0;
1047    
1048     done:
1049     /* The complete array was cleaned by strsplit */
1050     for(i=0;i<PA_DESC_MAX_TOKENS;i++)
1051     free(tokens[i]);
1052    
1053     return(res);
1054     }
1055    
1056     /* Create the main PCI bus for a GT64010 based system */
1057     static int msfc1_init_gt64010(msfc1_t *router)
1058     {
1059     vm_instance_t *vm = router->vm;
1060    
1061     if (!(vm->pci_bus[0] = pci_bus_create("PCI Bus 0",0))) {
1062     vm_error(vm,"unable to create PCI data.\n");
1063     return(-1);
1064     }
1065    
1066     return(dev_gt64010_init(vm,"gt64010",MSFC1_GT64K_ADDR,0x1000,
1067     MSFC1_GT64K_IRQ));
1068     }
1069    
1070     /* Initialize a MSFC1 board */
1071     int msfc1_init_hw(msfc1_t *router)
1072     {
1073     vm_instance_t *vm = router->vm;
1074    
1075     /* Set the processor type: R5000 */
1076     mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R5000);
1077    
1078     /* Initialize the Galileo GT-64010 PCI controller */
1079     if (msfc1_init_gt64010(router) == -1)
1080     return(-1);
1081    
1082     /* Create PCI bus 1 */
1083     vm->pci_bus_pool[24] = pci_bus_create("PCI Bus 1",-1);
1084     dev_dec21154_init(vm->pci_bus[0],1,vm->pci_bus_pool[24]);
1085    
1086     /* Initialize SRAM (4Mb) */
1087     dev_c7200_sram_init(vm,"sram",MSFC1_SRAM_ADDR,MSFC1_SRAM_SIZE,
1088     vm->pci_bus_pool[24],0);
1089    
1090     /* PCI IO space */
1091     if (!(vm->pci_io_space = pci_io_data_init(vm,MSFC1_PCI_IO_ADDR)))
1092     return(-1);
1093    
1094     /* Cirrus Logic PD6729 (PCI-to-PCMCIA host adapter) */
1095     dev_clpd6729_init(vm,vm->pci_bus[0],5,vm->pci_io_space,0x402,0x403);
1096    
1097     return(0);
1098     }
1099    
1100     /* Show MSFC1 hardware info */
1101     void msfc1_show_hardware(msfc1_t *router)
1102     {
1103     vm_instance_t *vm = router->vm;
1104    
1105     printf("MSFC1 instance '%s' (id %d):\n",vm->name,vm->instance_id);
1106    
1107     printf(" VM Status : %d\n",vm->status);
1108     printf(" RAM size : %u Mb\n",vm->ram_size);
1109     printf(" IOMEM size : %u Mb\n",vm->iomem_size);
1110     printf(" NVRAM size : %u Kb\n",vm->nvram_size);
1111     printf(" IOS image : %s\n\n",vm->ios_image);
1112    
1113     if (vm->debug_level > 0) {
1114     dev_show_list(vm);
1115     pci_dev_show_list(vm->pci_bus[0]);
1116     pci_dev_show_list(vm->pci_bus[1]);
1117     printf("\n");
1118     }
1119     }
1120    
1121     /* Initialize default parameters for a MSFC1 */
1122     void msfc1_init_defaults(msfc1_t *router)
1123     {
1124     vm_instance_t *vm = router->vm;
1125     n_eth_addr_t *m;
1126     m_uint16_t pid;
1127    
1128     pid = (m_uint16_t)getpid();
1129    
1130     /* Generate a chassis MAC address based on the instance ID */
1131     m = &router->mac_addr;
1132     m->eth_addr_byte[0] = vm_get_mac_addr_msb(vm);
1133     m->eth_addr_byte[1] = vm->instance_id & 0xFF;
1134     m->eth_addr_byte[2] = pid >> 8;
1135     m->eth_addr_byte[3] = pid & 0xFF;
1136     m->eth_addr_byte[4] = 0x00;
1137     m->eth_addr_byte[5] = 0x00;
1138    
1139     msfc1_set_eeprom(router);
1140     msfc1_init_eeprom_groups(router);
1141     vm->ram_mmap = MSFC1_DEFAULT_RAM_MMAP;
1142     vm->ram_size = MSFC1_DEFAULT_RAM_SIZE;
1143     vm->rom_size = MSFC1_DEFAULT_ROM_SIZE;
1144     vm->nvram_size = MSFC1_DEFAULT_NVRAM_SIZE;
1145     vm->iomem_size = 0;
1146     vm->conf_reg_setup = MSFC1_DEFAULT_CONF_REG;
1147     vm->clock_divisor = MSFC1_DEFAULT_CLOCK_DIV;
1148     vm->nvram_rom_space = MSFC1_NVRAM_ROM_RES_SIZE;
1149    
1150     /* Enable NVRAM operations to load/store configs */
1151     vm->nvram_extract_config = msfc1_nvram_extract_config;
1152     vm->nvram_push_config = msfc1_nvram_push_config;
1153     }
1154    
1155     /* Run the checklist */
1156     static int msfc1_checklist(msfc1_t *router)
1157     {
1158     struct vm_instance *vm = router->vm;
1159     int res = 0;
1160    
1161     res += vm_object_check(vm,"ram");
1162     res += vm_object_check(vm,"rom");
1163     res += vm_object_check(vm,"nvram");
1164     res += vm_object_check(vm,"zero");
1165    
1166     if (res < 0)
1167     vm_error(vm,"incomplete initialization (no memory?)\n");
1168    
1169     return(res);
1170     }
1171    
1172     /* Initialize Port Adapters */
1173     static int msfc1_init_platform_pa(msfc1_t *router)
1174     {
1175     /* Create EOBC interface */
1176     msfc1_pa_add_binding(router,"MSFC1_EOBC",0);
1177     msfc1_pa_init(router,0);
1178    
1179     /* Create IBC interface */
1180     msfc1_pa_add_binding(router,"MSFC1_IBC",1);
1181     msfc1_pa_init(router,1);
1182     return(0);
1183     }
1184    
1185     /* Initialize the MSFC1 Platform */
1186     static int msfc1_init_platform(msfc1_t *router)
1187     {
1188     struct vm_instance *vm = router->vm;
1189     cpu_mips_t *cpu0;
1190     cpu_gen_t *gen0;
1191    
1192     /* Copy config register setup into "active" config register */
1193     vm->conf_reg = vm->conf_reg_setup;
1194    
1195     /* Create Console and AUX ports */
1196     vm_init_vtty(vm);
1197    
1198     /* Create a CPU group */
1199     vm->cpu_group = cpu_group_create("System CPU");
1200    
1201     /* Initialize the virtual MIPS processor */
1202     if (!(gen0 = cpu_create(vm,CPU_TYPE_MIPS64,0))) {
1203     vm_error(vm,"unable to create CPU0!\n");
1204     return(-1);
1205     }
1206    
1207     cpu0 = CPU_MIPS64(gen0);
1208    
1209     /* Add this CPU to the system CPU group */
1210     cpu_group_add(vm->cpu_group,gen0);
1211     vm->boot_cpu = gen0;
1212    
1213     /* Initialize the IRQ routing vectors */
1214     vm->set_irq = mips64_vm_set_irq;
1215     vm->clear_irq = mips64_vm_clear_irq;
1216    
1217     /* Mark the Network IO interrupt as high priority */
1218     cpu0->irq_idle_preempt[MSFC1_NETIO_IRQ] = TRUE;
1219     cpu0->irq_idle_preempt[MSFC1_GT64K_IRQ] = TRUE;
1220    
1221     /* Copy some parameters from VM to CPU0 (idle PC, ...) */
1222     cpu0->idle_pc = vm->idle_pc;
1223    
1224     if (vm->timer_irq_check_itv)
1225     cpu0->timer_irq_check_itv = vm->timer_irq_check_itv;
1226    
1227     /*
1228     * On the MSFC1, bit 33 of physical addresses is used to bypass L2 cache.
1229     * We clear it systematically.
1230     */
1231     cpu0->addr_bus_mask = MSFC1_ADDR_BUS_MASK;
1232    
1233     /* Remote emulator control */
1234     dev_remote_control_init(vm,0x16000000,0x1000);
1235    
1236     /* Bootflash */
1237     dev_bootflash_init(vm,"bootflash",MSFC1_BOOTFLASH_ADDR,(8 * 1048576));
1238    
1239     /* NVRAM and calendar */
1240     dev_nvram_init(vm,"nvram",MSFC1_NVRAM_ADDR,
1241     vm->nvram_size*1024,&vm->conf_reg);
1242    
1243     /* Bit-bucket zone */
1244     dev_zero_init(vm,"zero",MSFC1_BITBUCKET_ADDR,0xc00000);
1245    
1246     /* Initialize the NPE board */
1247     if (msfc1_init_hw(router) == -1)
1248     return(-1);
1249    
1250     /* Initialize RAM */
1251     vm_ram_init(vm,0x00000000ULL);
1252    
1253     /* Initialize ROM */
1254     if (!vm->rom_filename) {
1255     /* use embedded ROM */
1256     dev_rom_init(vm,"rom",MSFC1_ROM_ADDR,vm->rom_size*1048576,
1257     mips64_microcode,mips64_microcode_len);
1258     } else {
1259     /* use alternate ROM */
1260     dev_ram_init(vm,"rom",TRUE,TRUE,NULL,FALSE,
1261     MSFC1_ROM_ADDR,vm->rom_size*1048576);
1262     }
1263    
1264     /* Byte swapping */
1265     dev_bswap_init(vm,"mem_bswap",MSFC1_BSWAP_ADDR,1024*1048576,0x00000000ULL);
1266    
1267     /* PCI IO space */
1268     if (!(vm->pci_io_space = pci_io_data_init(vm,MSFC1_PCI_IO_ADDR)))
1269     return(-1);
1270    
1271     /* Initialize the Port Adapters */
1272     if (msfc1_init_platform_pa(router) == -1)
1273     return(-1);
1274    
1275     /* Verify the check list */
1276     if (msfc1_checklist(router) == -1)
1277     return(-1);
1278    
1279     /* Midplane FPGA */
1280     if (dev_msfc1_mpfpga_init(router,MSFC1_MPFPGA_ADDR,0x1000) == -1)
1281     return(-1);
1282    
1283     /* IO FPGA */
1284     if (dev_msfc1_iofpga_init(router,MSFC1_IOFPGA_ADDR,0x1000) == -1)
1285     return(-1);
1286    
1287     /* Show device list */
1288     msfc1_show_hardware(router);
1289     return(0);
1290     }
1291    
1292     /* Boot the IOS image */
1293     static int msfc1_boot_ios(msfc1_t *router)
1294     {
1295     vm_instance_t *vm = router->vm;
1296     cpu_mips_t *cpu;
1297    
1298     if (!vm->boot_cpu)
1299     return(-1);
1300    
1301     /* Suspend CPU activity since we will restart directly from ROM */
1302     vm_suspend(vm);
1303    
1304     /* Check that CPU activity is really suspended */
1305     if (cpu_group_sync_state(vm->cpu_group) == -1) {
1306     vm_error(vm,"unable to sync with system CPUs.\n");
1307     return(-1);
1308     }
1309    
1310     /* Reset the boot CPU */
1311     cpu = CPU_MIPS64(vm->boot_cpu);
1312     mips64_reset(cpu);
1313    
1314     /* Load IOS image */
1315     if (mips64_load_elf_image(cpu,vm->ios_image,
1316     (vm->ghost_status == VM_GHOST_RAM_USE),
1317     &vm->ios_entry_point) < 0)
1318     {
1319     vm_error(vm,"failed to load Cisco IOS image '%s'.\n",vm->ios_image);
1320     return(-1);
1321     }
1322    
1323     /* Launch the simulation */
1324     printf("\nMSFC1 '%s': starting simulation (CPU0 PC=0x%llx), "
1325     "JIT %sabled.\n",
1326     vm->name,cpu->pc,vm->jit_use ? "en":"dis");
1327    
1328     vm_log(vm,"MSFC1_BOOT",
1329     "starting instance (CPU0 PC=0x%llx,idle_pc=0x%llx,JIT %s)\n",
1330     cpu->pc,cpu->idle_pc,vm->jit_use ? "on":"off");
1331    
1332     /* Start main CPU */
1333     if (vm->ghost_status != VM_GHOST_RAM_GENERATE) {
1334     vm->status = VM_STATUS_RUNNING;
1335     cpu_start(vm->boot_cpu);
1336     } else {
1337     vm->status = VM_STATUS_SHUTDOWN;
1338     }
1339     return(0);
1340     }
1341    
1342     /* Initialize a MSFC1 instance */
1343     int msfc1_init_instance(msfc1_t *router)
1344     {
1345     vm_instance_t *vm = router->vm;
1346     m_uint32_t rom_entry_point;
1347     cpu_mips_t *cpu0;
1348    
1349     /* Initialize the MSFC1 platform */
1350     if (msfc1_init_platform(router) == -1) {
1351     vm_error(vm,"unable to initialize the platform hardware.\n");
1352     return(-1);
1353     }
1354    
1355     /* Load IOS configuration file */
1356     if (vm->ios_config != NULL) {
1357     vm_nvram_push_config(vm,vm->ios_config);
1358     vm->conf_reg &= ~0x40;
1359     }
1360    
1361     /* Load ROM (ELF image or embedded) */
1362     cpu0 = CPU_MIPS64(vm->boot_cpu);
1363     rom_entry_point = (m_uint32_t)MIPS_ROM_PC;
1364    
1365     if ((vm->rom_filename != NULL) &&
1366     (mips64_load_elf_image(cpu0,vm->rom_filename,0,&rom_entry_point) < 0))
1367     {
1368     vm_error(vm,"unable to load alternate ROM '%s', "
1369     "fallback to embedded ROM.\n\n",vm->rom_filename);
1370     vm->rom_filename = NULL;
1371     }
1372    
1373     /* Load symbol file */
1374     if (vm->sym_filename) {
1375     mips64_sym_load_file(cpu0,vm->sym_filename);
1376     cpu0->sym_trace = 1;
1377     }
1378    
1379     return(msfc1_boot_ios(router));
1380     }
1381    
1382     /* Stop a MSFC1 instance */
1383     int msfc1_stop_instance(msfc1_t *router)
1384     {
1385     vm_instance_t *vm = router->vm;
1386    
1387     printf("\nMSFC1 '%s': stopping simulation.\n",vm->name);
1388     vm_log(vm,"MSFC1_STOP","stopping simulation.\n");
1389    
1390     /* Stop all CPUs */
1391     if (vm->cpu_group != NULL) {
1392     vm_stop(vm);
1393    
1394     if (cpu_group_sync_state(vm->cpu_group) == -1) {
1395     vm_error(vm,"unable to sync with system CPUs.\n");
1396     return(-1);
1397     }
1398     }
1399    
1400     /* Free resources that were used during execution to emulate hardware */
1401     msfc1_free_hw_ressources(router);
1402     vm_hardware_shutdown(vm);
1403     return(0);
1404     }

  ViewVC Help
Powered by ViewVC 1.1.26