/[dynamips]/trunk/dev_c2691.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_c2691.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (hide annotations)
Sat Oct 6 16:23:47 2007 UTC (16 years, 6 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7-RC1/dev_c2691.c
File MIME type: text/plain
File size: 35263 byte(s)
dynamips-0.2.7-RC1

1 dpavlin 4 /*
2     * Cisco 2691 simulation platform.
3     * Copyright (c) 2006 Christophe Fillot (cf@utc.fr)
4     *
5     * Generic Cisco 2691 routines and definitions (EEPROM,...).
6     */
7    
8     #include <stdio.h>
9     #include <stdlib.h>
10     #include <string.h>
11     #include <unistd.h>
12     #include <sys/types.h>
13     #include <assert.h>
14    
15 dpavlin 7 #include "cpu.h"
16     #include "vm.h"
17 dpavlin 4 #include "dynamips.h"
18     #include "memory.h"
19     #include "device.h"
20     #include "pci_io.h"
21     #include "dev_gt.h"
22     #include "cisco_eeprom.h"
23 dpavlin 7 #include "dev_rom.h"
24 dpavlin 4 #include "dev_c2691.h"
25     #include "dev_vtty.h"
26     #include "registry.h"
27    
28     /* ======================================================================== */
29     /* EEPROM definitions */
30     /* ======================================================================== */
31    
32     /* Cisco 2691 mainboard EEPROM */
33     static m_uint16_t eeprom_c2691_mainboard_data[] = {
34     0x04FF, 0xC18B, 0x5858, 0x5858, 0x5858, 0x5858, 0x5858, 0x5809,
35     0x6640, 0x0258, 0xC046, 0x0320, 0x0025, 0x9002, 0x4246, 0x3085,
36     0x1C10, 0x8206, 0x80FF, 0xFFFF, 0xFFC4, 0x08FF, 0xFFFF, 0xFFFF,
37     0xFFFF, 0xFF81, 0xFFFF, 0xFFFF, 0x03FF, 0x04FF, 0xC28B, 0x5858,
38     0x5858, 0x5858, 0x5858, 0x5858, 0x58C3, 0x0600, 0x1280, 0xD387,
39     0xC043, 0x0020, 0xC508, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x4100,
40     0x0101, 0x01FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
41     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
42     };
43    
44     struct cisco_eeprom eeprom_c2691_mainboard = {
45     "C2691 Backplane",
46     eeprom_c2691_mainboard_data,
47     sizeof(eeprom_c2691_mainboard_data)/2,
48     };
49    
50     /* ======================================================================== */
51     /* Network Module Drivers */
52     /* ======================================================================== */
53     static struct c2691_nm_driver *nm_drivers[] = {
54     &dev_c2691_nm_1fe_tx_driver,
55     &dev_c2691_nm_16esw_driver,
56     &dev_c2691_gt96100_fe_driver,
57     &dev_c2691_nm_4t_driver,
58     NULL,
59     };
60    
61     /* ======================================================================== */
62     /* Cisco 2691 router instances */
63     /* ======================================================================== */
64    
65     /* Directly extract the configuration from the NVRAM device */
66     ssize_t c2691_nvram_extract_config(vm_instance_t *vm,char **buffer)
67     {
68     u_char *base_ptr,*ios_ptr,*cfg_ptr,*end_ptr;
69     m_uint32_t start,nvlen;
70     m_uint16_t magic1,magic2;
71     struct vdevice *nvram_dev;
72     off_t nvram_size;
73     int fd;
74    
75     if ((nvram_dev = dev_get_by_name(vm,"rom")))
76     dev_sync(nvram_dev);
77    
78     fd = vm_mmap_open_file(vm,"rom",&base_ptr,&nvram_size);
79    
80     if (fd == -1)
81     return(-1);
82    
83     ios_ptr = base_ptr + C2691_NVRAM_OFFSET;
84     end_ptr = base_ptr + nvram_size;
85    
86     if ((ios_ptr + 0x30) >= end_ptr) {
87     vm_error(vm,"NVRAM file too small\n");
88     return(-1);
89     }
90    
91     magic1 = ntohs(*PTR_ADJUST(m_uint16_t *,ios_ptr,0x06));
92     magic2 = ntohs(*PTR_ADJUST(m_uint16_t *,ios_ptr,0x08));
93    
94     if ((magic1 != 0xF0A5) || (magic2 != 0xABCD)) {
95     vm_error(vm,"unable to find IOS magic numbers (0x%x,0x%x)!\n",
96     magic1,magic2);
97     return(-1);
98     }
99    
100     start = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x10)) + 1;
101     nvlen = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x18));
102    
103     if (!(*buffer = malloc(nvlen+1))) {
104     vm_error(vm,"unable to allocate config buffer (%u bytes)\n",nvlen);
105     return(-1);
106     }
107    
108     cfg_ptr = ios_ptr + start + 0x08;
109    
110     if ((cfg_ptr + nvlen) > end_ptr) {
111     vm_error(vm,"NVRAM file too small\n");
112     return(-1);
113     }
114    
115     memcpy(*buffer,cfg_ptr,nvlen-1);
116     (*buffer)[nvlen-1] = 0;
117     return(nvlen-1);
118     }
119    
120     static int c2691_nvram_push_config_part(vm_instance_t *vm,
121     char *buffer,size_t len,
122     u_char *ios_ptr)
123     {
124     m_uint32_t cfg_offset,cklen,tmp;
125     m_uint16_t cksum;
126     u_char *cfg_ptr;
127    
128     cfg_offset = 0x2c;
129     cfg_ptr = ios_ptr + cfg_offset;
130    
131     /* Write IOS tag, uncompressed config... */
132     *PTR_ADJUST(m_uint16_t *,ios_ptr,0x06) = htons(0xF0A5);
133     *PTR_ADJUST(m_uint16_t *,ios_ptr,0x08) = htons(0xABCD);
134     *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0a) = htons(0x0001);
135     *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0c) = htons(0x0000);
136     *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0e) = htons(0x0c04);
137    
138     /* Store file contents to NVRAM */
139     memcpy(cfg_ptr,buffer,len);
140    
141     /* Write config addresses + size */
142     tmp = cfg_offset - 0x08;
143    
144     *PTR_ADJUST(m_uint32_t *,ios_ptr,0x10) = htonl(tmp);
145     *PTR_ADJUST(m_uint32_t *,ios_ptr,0x14) = htonl(tmp + len);
146     *PTR_ADJUST(m_uint32_t *,ios_ptr,0x18) = htonl(len);
147    
148     /* Compute the checksum */
149     cklen = C2691_NVRAM_SIZE - 0x08;
150     cksum = nvram_cksum((m_uint16_t *)(ios_ptr+0x08),cklen);
151     *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0c) = htons(cksum);
152     return(0);
153     }
154    
155     /* Directly push the IOS configuration to the NVRAM device */
156     int c2691_nvram_push_config(vm_instance_t *vm,char *buffer,size_t len)
157     {
158     u_char *base_ptr,*ios_ptr;
159     int fd;
160    
161     fd = vm_mmap_create_file(vm,"rom",vm->rom_size*1048576,&base_ptr);
162    
163     if (fd == -1)
164     return(-1);
165    
166     ios_ptr = base_ptr + C2691_NVRAM_OFFSET;
167    
168     /* Normal config */
169     c2691_nvram_push_config_part(vm,buffer,len,ios_ptr);
170    
171     /* Backup config */
172     c2691_nvram_push_config_part(vm,buffer,len,ios_ptr + C2691_NVRAM_SIZE);
173    
174     vm_mmap_close_file(fd,base_ptr,vm->rom_size*1048576);
175     return(0);
176     }
177    
178     /* Check for empty config */
179     int c2691_nvram_check_empty_config(vm_instance_t *vm)
180     {
181     struct vdevice *rom_dev;
182     m_uint64_t addr;
183     size_t len;
184    
185     if (!(rom_dev = dev_get_by_name(vm,"rom")))
186     return(-1);
187    
188     addr = rom_dev->phys_addr + C2691_NVRAM_OFFSET;
189     len = C2691_NVRAM_SIZE;
190    
191     while(len > 0) {
192     if (physmem_copy_u32_from_vm(vm,addr) != 0)
193     return(0);
194    
195     addr += sizeof(m_uint32_t);
196     len -= sizeof(m_uint32_t);
197     }
198    
199     /* Empty NVRAM */
200     vm->conf_reg |= 0x0040;
201     printf("NVRAM is empty, setting config register to 0x%x\n",vm->conf_reg);
202     return(0);
203     }
204    
205     /* Create a new router instance */
206     c2691_t *c2691_create_instance(char *name,int instance_id)
207     {
208     c2691_t *router;
209    
210     if (!(router = malloc(sizeof(*router)))) {
211     fprintf(stderr,"C2691 '%s': Unable to create new instance!\n",name);
212     return NULL;
213     }
214    
215     memset(router,0,sizeof(*router));
216    
217     if (!(router->vm = vm_create(name,instance_id,VM_TYPE_C2691))) {
218     fprintf(stderr,"C2691 '%s': unable to create VM instance!\n",name);
219     goto err_vm;
220     }
221    
222     c2691_init_defaults(router);
223     router->vm->hw_data = router;
224     return router;
225    
226     err_vm:
227     free(router);
228     return NULL;
229     }
230    
231     /* Free resources used by a router instance */
232     static int c2691_free_instance(void *data,void *arg)
233     {
234     vm_instance_t *vm = data;
235     c2691_t *router;
236     int i;
237    
238     if (vm->type == VM_TYPE_C2691) {
239     router = VM_C2691(vm);
240    
241     /* Stop all CPUs */
242     if (vm->cpu_group != NULL) {
243     vm_stop(vm);
244    
245     if (cpu_group_sync_state(vm->cpu_group) == -1) {
246     vm_error(vm,"unable to sync with system CPUs.\n");
247     return(FALSE);
248     }
249     }
250    
251     /* Remove NIO bindings */
252     for(i=0;i<C2691_MAX_NM_BAYS;i++)
253     c2691_nm_remove_all_nio_bindings(router,i);
254    
255     /* Shutdown all Network Modules */
256     c2691_nm_shutdown_all(router);
257    
258     /* Free mainboard EEPROM */
259     cisco_eeprom_free(&router->mb_eeprom);
260    
261     /* Free all resources used by VM */
262     vm_free(vm);
263    
264     /* Free the router structure */
265     free(router);
266     return(TRUE);
267     }
268    
269     return(FALSE);
270     }
271    
272     /* Delete a router instance */
273     int c2691_delete_instance(char *name)
274     {
275     return(registry_delete_if_unused(name,OBJ_TYPE_VM,
276     c2691_free_instance,NULL));
277     }
278    
279     /* Delete all router instances */
280     int c2691_delete_all_instances(void)
281     {
282     return(registry_delete_type(OBJ_TYPE_VM,c2691_free_instance,NULL));
283     }
284    
285     /* Save configuration of a C2691 instance */
286     void c2691_save_config(c2691_t *router,FILE *fd)
287     {
288     vm_instance_t *vm = router->vm;
289     struct c2691_nio_binding *nb;
290     struct c2691_nm_bay *bay;
291     int i;
292    
293     /* General settings */
294     fprintf(fd,"c2691 create %s %u\n",vm->name,vm->instance_id);
295    
296     /* VM configuration */
297     vm_save_config(vm,fd);
298    
299     /* Network Module settings */
300     for(i=0;i<C2691_MAX_NM_BAYS;i++) {
301     if (!(bay = c2691_nm_get_info(router,i)))
302     continue;
303    
304     if (bay->dev_type) {
305     fprintf(fd,"c2691 add_nm_binding %s %u %s\n",
306     vm->name,i,bay->dev_type);
307     }
308    
309     for(nb=bay->nio_list;nb;nb=nb->next) {
310     fprintf(fd,"c2691 add_nio_binding %s %u %u %s\n",
311     vm->name,i,nb->port_id,nb->nio->name);
312     }
313     }
314    
315     fprintf(fd,"\n");
316     }
317    
318     /* Save configurations of all C2691 instances */
319     static void c2691_reg_save_config(registry_entry_t *entry,void *opt,int *err)
320     {
321     vm_instance_t *vm = entry->data;
322     c2691_t *router = VM_C2691(vm);
323    
324     if (vm->type == VM_TYPE_C2691)
325     c2691_save_config(router,(FILE *)opt);
326     }
327    
328     void c2691_save_config_all(FILE *fd)
329     {
330     registry_foreach_type(OBJ_TYPE_VM,c2691_reg_save_config,fd,NULL);
331     }
332    
333     /* Set NM EEPROM definition */
334     int c2691_nm_set_eeprom(c2691_t *router,u_int nm_bay,
335     const struct cisco_eeprom *eeprom)
336     {
337     if (nm_bay != 1) {
338     vm_error(router->vm,"c2691_nm_set_eeprom: invalid NM Bay %u.\n",nm_bay);
339     return(-1);
340     }
341    
342     if (cisco_eeprom_copy(&router->nm_bay[nm_bay].eeprom,eeprom) == -1) {
343     vm_error(router->vm,"c2691_nm_set_eeprom: no memory.\n");
344     return(-1);
345     }
346    
347     return(0);
348     }
349    
350     /* Unset NM EEPROM definition (empty bay) */
351     int c2691_nm_unset_eeprom(c2691_t *router,u_int nm_bay)
352     {
353     if (nm_bay != 1) {
354     vm_error(router->vm,"c2691_nm_set_eeprom: invalid NM Bay %u.\n",nm_bay);
355     return(-1);
356     }
357    
358     cisco_eeprom_free(&router->nm_bay[nm_bay].eeprom);
359     return(0);
360     }
361    
362     /* Check if a bay has a port adapter */
363     int c2691_nm_check_eeprom(c2691_t *router,u_int nm_bay)
364     {
365     if (nm_bay != 1)
366     return(FALSE);
367    
368     return(cisco_eeprom_valid(&router->nm_bay[nm_bay].eeprom));
369     }
370    
371     /* Get bay info */
372     struct c2691_nm_bay *c2691_nm_get_info(c2691_t *router,u_int nm_bay)
373     {
374     if (nm_bay >= C2691_MAX_NM_BAYS)
375     return NULL;
376    
377     return(&router->nm_bay[nm_bay]);
378     }
379    
380     /* Get NM type */
381     char *c2691_nm_get_type(c2691_t *router,u_int nm_bay)
382     {
383     struct c2691_nm_bay *bay;
384    
385     bay = c2691_nm_get_info(router,nm_bay);
386     return((bay != NULL) ? bay->dev_type : NULL);
387     }
388    
389     /* Get driver info about the specified slot */
390     void *c2691_nm_get_drvinfo(c2691_t *router,u_int nm_bay)
391     {
392     struct c2691_nm_bay *bay;
393    
394     bay = c2691_nm_get_info(router,nm_bay);
395     return((bay != NULL) ? bay->drv_info : NULL);
396     }
397    
398     /* Set driver info for the specified slot */
399     int c2691_nm_set_drvinfo(c2691_t *router,u_int nm_bay,void *drv_info)
400     {
401     struct c2691_nm_bay *bay;
402    
403     if (!(bay = c2691_nm_get_info(router,nm_bay)))
404     return(-1);
405    
406     bay->drv_info = drv_info;
407     return(0);
408     }
409    
410     /* Get a NM driver */
411     static struct c2691_nm_driver *c2691_nm_get_driver(char *dev_type)
412     {
413     int i;
414    
415     for(i=0;nm_drivers[i];i++)
416     if (!strcmp(nm_drivers[i]->dev_type,dev_type))
417     return nm_drivers[i];
418    
419     return NULL;
420     }
421    
422     /* Add a NM binding */
423     int c2691_nm_add_binding(c2691_t *router,char *dev_type,u_int nm_bay)
424     {
425     struct c2691_nm_driver *nm_driver;
426     struct c2691_nm_bay *bay;
427    
428     if (!(bay = c2691_nm_get_info(router,nm_bay)))
429     return(-1);
430    
431     /* check that this bay is empty */
432     if (bay->dev_type != NULL) {
433     vm_error(router->vm,"a NM already exists in slot %u.\n",nm_bay);
434     return(-1);
435     }
436    
437     /* find the NM driver */
438     if (!(nm_driver = c2691_nm_get_driver(dev_type))) {
439     vm_error(router->vm,"unknown NM type '%s'.\n",dev_type);
440     return(-1);
441     }
442    
443     bay->dev_type = nm_driver->dev_type;
444     bay->nm_driver = nm_driver;
445     return(0);
446     }
447    
448     /* Remove a NM binding */
449     int c2691_nm_remove_binding(c2691_t *router,u_int nm_bay)
450     {
451     struct c2691_nm_bay *bay;
452    
453     if (!(bay = c2691_nm_get_info(router,nm_bay)))
454     return(-1);
455    
456     /* stop if this bay is still active */
457     if (bay->drv_info != NULL) {
458     vm_error(router->vm,"slot %u still active.\n",nm_bay);
459     return(-1);
460     }
461    
462     /* check that this bay is not empty */
463     if (bay->dev_type == NULL) {
464     vm_error(router->vm,"slot %u is empty.\n",nm_bay);
465     return(-1);
466     }
467    
468     /* remove all NIOs bindings */
469     c2691_nm_remove_all_nio_bindings(router,nm_bay);
470    
471     bay->dev_type = NULL;
472     bay->nm_driver = NULL;
473     return(0);
474     }
475    
476     /* Find a NIO binding */
477     struct c2691_nio_binding *
478     c2691_nm_find_nio_binding(c2691_t *router,u_int nm_bay,u_int port_id)
479     {
480     struct c2691_nio_binding *nb;
481     struct c2691_nm_bay *bay;
482    
483     if (!(bay = c2691_nm_get_info(router,nm_bay)))
484     return NULL;
485    
486     for(nb=bay->nio_list;nb;nb=nb->next)
487     if (nb->port_id == port_id)
488     return nb;
489    
490     return NULL;
491     }
492    
493     /* Add a network IO binding */
494     int c2691_nm_add_nio_binding(c2691_t *router,u_int nm_bay,u_int port_id,
495     char *nio_name)
496     {
497     struct c2691_nio_binding *nb;
498     struct c2691_nm_bay *bay;
499     netio_desc_t *nio;
500    
501     if (!(bay = c2691_nm_get_info(router,nm_bay)))
502     return(-1);
503    
504     /* check that a NIO is not already bound to this port */
505     if (c2691_nm_find_nio_binding(router,nm_bay,port_id) != NULL) {
506     vm_error(router->vm,"a NIO already exists for interface %u/%u.\n",
507     nm_bay,port_id);
508     return(-1);
509     }
510    
511     /* acquire a reference on the NIO object */
512     if (!(nio = netio_acquire(nio_name))) {
513     vm_error(router->vm,"unable to find NIO '%s'.\n",nio_name);
514     return(-1);
515     }
516    
517     /* create a new binding */
518     if (!(nb = malloc(sizeof(*nb)))) {
519     vm_error(router->vm,"unable to create NIO binding "
520     "for interface %u/%u.\n",nm_bay,port_id);
521     netio_release(nio_name);
522     return(-1);
523     }
524    
525     memset(nb,0,sizeof(*nb));
526     nb->nio = nio;
527     nb->port_id = port_id;
528     nb->next = bay->nio_list;
529     if (nb->next) nb->next->prev = nb;
530     bay->nio_list = nb;
531     return(0);
532     }
533    
534     /* Remove a NIO binding */
535     int c2691_nm_remove_nio_binding(c2691_t *router,u_int nm_bay,u_int port_id)
536     {
537     struct c2691_nio_binding *nb;
538     struct c2691_nm_bay *bay;
539    
540     if (!(bay = c2691_nm_get_info(router,nm_bay)))
541     return(-1);
542    
543     if (!(nb = c2691_nm_find_nio_binding(router,nm_bay,port_id)))
544     return(-1); /* no nio binding for this slot/port */
545    
546     /* tell the NM driver to stop using this NIO */
547     if (bay->nm_driver)
548     bay->nm_driver->nm_unset_nio(router,nm_bay,port_id);
549    
550     /* remove this entry from the double linked list */
551     if (nb->next)
552     nb->next->prev = nb->prev;
553    
554     if (nb->prev) {
555     nb->prev->next = nb->next;
556     } else {
557     bay->nio_list = nb->next;
558     }
559    
560     /* unreference NIO object */
561     netio_release(nb->nio->name);
562     free(nb);
563     return(0);
564     }
565    
566     /* Remove all NIO bindings for the specified NM */
567     int c2691_nm_remove_all_nio_bindings(c2691_t *router,u_int nm_bay)
568     {
569     struct c2691_nio_binding *nb,*next;
570     struct c2691_nm_bay *bay;
571    
572     if (!(bay = c2691_nm_get_info(router,nm_bay)))
573     return(-1);
574    
575     for(nb=bay->nio_list;nb;nb=next) {
576     next = nb->next;
577    
578     /* tell the NM driver to stop using this NIO */
579     if (bay->nm_driver)
580     bay->nm_driver->nm_unset_nio(router,nm_bay,nb->port_id);
581    
582     /* unreference NIO object */
583     netio_release(nb->nio->name);
584     free(nb);
585     }
586    
587     bay->nio_list = NULL;
588     return(0);
589     }
590    
591     /* Enable a Network IO descriptor for a Network Module */
592     int c2691_nm_enable_nio(c2691_t *router,u_int nm_bay,u_int port_id)
593     {
594     struct c2691_nio_binding *nb;
595     struct c2691_nm_bay *bay;
596    
597     if (!(bay = c2691_nm_get_info(router,nm_bay)))
598     return(-1);
599    
600     /* check that we have an NIO binding for this interface */
601     if (!(nb = c2691_nm_find_nio_binding(router,nm_bay,port_id)))
602     return(-1);
603    
604     /* check that the driver is defined and successfully initialized */
605     if (!bay->nm_driver || !bay->drv_info)
606     return(-1);
607    
608     return(bay->nm_driver->nm_set_nio(router,nm_bay,port_id,nb->nio));
609     }
610    
611     /* Disable Network IO descriptor of a Network Module */
612     int c2691_nm_disable_nio(c2691_t *router,u_int nm_bay,u_int port_id)
613     {
614     struct c2691_nm_bay *bay;
615    
616     if (!(bay = c2691_nm_get_info(router,nm_bay)))
617     return(-1);
618    
619     /* check that the driver is defined and successfully initialized */
620     if (!bay->nm_driver || !bay->drv_info)
621     return(-1);
622    
623     return(bay->nm_driver->nm_unset_nio(router,nm_bay,port_id));
624     }
625    
626     /* Enable all NIO of the specified NM */
627     int c2691_nm_enable_all_nio(c2691_t *router,u_int nm_bay)
628     {
629     struct c2691_nio_binding *nb;
630     struct c2691_nm_bay *bay;
631    
632     if (!(bay = c2691_nm_get_info(router,nm_bay)))
633     return(-1);
634    
635     /* check that the driver is defined and successfully initialized */
636     if (!bay->nm_driver || !bay->drv_info)
637     return(-1);
638    
639     for(nb=bay->nio_list;nb;nb=nb->next)
640     bay->nm_driver->nm_set_nio(router,nm_bay,nb->port_id,nb->nio);
641    
642     return(0);
643     }
644    
645     /* Disable all NIO of the specified NM */
646     int c2691_nm_disable_all_nio(c2691_t *router,u_int nm_bay)
647     {
648     struct c2691_nio_binding *nb;
649     struct c2691_nm_bay *bay;
650    
651     if (!(bay = c2691_nm_get_info(router,nm_bay)))
652     return(-1);
653    
654     /* check that the driver is defined and successfully initialized */
655     if (!bay->nm_driver || !bay->drv_info)
656     return(-1);
657    
658     for(nb=bay->nio_list;nb;nb=nb->next)
659     bay->nm_driver->nm_unset_nio(router,nm_bay,nb->port_id);
660    
661     return(0);
662     }
663    
664     /* Initialize a Network Module */
665     int c2691_nm_init(c2691_t *router,u_int nm_bay)
666     {
667     struct c2691_nm_bay *bay;
668     size_t len;
669    
670     if (!(bay = c2691_nm_get_info(router,nm_bay)))
671     return(-1);
672    
673     /* Check that a device type is defined for this bay */
674     if (!bay->dev_type || !bay->nm_driver) {
675     vm_error(router->vm,"trying to init empty slot %u.\n",nm_bay);
676     return(-1);
677     }
678    
679     /* Allocate device name */
680     len = strlen(bay->dev_type) + 10;
681     if (!(bay->dev_name = malloc(len))) {
682     vm_error(router->vm,"unable to allocate device name.\n");
683     return(-1);
684     }
685    
686     snprintf(bay->dev_name,len,"%s(%u)",bay->dev_type,nm_bay);
687    
688     /* Initialize NM driver */
689     if (bay->nm_driver->nm_init(router,bay->dev_name,nm_bay) == 1) {
690     vm_error(router->vm,"unable to initialize NM %u.\n",nm_bay);
691     return(-1);
692     }
693    
694     /* Enable all NIO */
695     c2691_nm_enable_all_nio(router,nm_bay);
696     return(0);
697     }
698    
699     /* Shutdown a Network Module */
700     int c2691_nm_shutdown(c2691_t *router,u_int nm_bay)
701     {
702     struct c2691_nm_bay *bay;
703    
704     if (!(bay = c2691_nm_get_info(router,nm_bay)))
705     return(-1);
706    
707     /* Check that a device type is defined for this bay */
708     if (!bay->dev_type || !bay->nm_driver) {
709     vm_error(router->vm,"trying to shut down empty slot %u.\n",nm_bay);
710     return(-1);
711     }
712    
713     /* Disable all NIO */
714     c2691_nm_disable_all_nio(router,nm_bay);
715    
716     /* Shutdown the NM driver */
717     if (bay->drv_info && (bay->nm_driver->nm_shutdown(router,nm_bay) == -1)) {
718     vm_error(router->vm,"unable to shutdown NM %u.\n",nm_bay);
719     return(-1);
720     }
721    
722     free(bay->dev_name);
723     bay->dev_name = NULL;
724     bay->drv_info = NULL;
725     return(0);
726     }
727    
728     /* Shutdown all NM of a router */
729     int c2691_nm_shutdown_all(c2691_t *router)
730     {
731     int i;
732    
733     for(i=0;i<C2691_MAX_NM_BAYS;i++) {
734     if (!router->nm_bay[i].dev_type)
735     continue;
736    
737     c2691_nm_shutdown(router,i);
738     }
739    
740     return(0);
741     }
742    
743     /* Show info about all NMs */
744     int c2691_nm_show_all_info(c2691_t *router)
745     {
746     struct c2691_nm_bay *bay;
747     int i;
748    
749     for(i=0;i<C2691_MAX_NM_BAYS;i++) {
750     if (!(bay = c2691_nm_get_info(router,i)) || !bay->nm_driver)
751     continue;
752    
753     if (bay->nm_driver->nm_show_info != NULL)
754     bay->nm_driver->nm_show_info(router,i);
755     }
756    
757     return(0);
758     }
759    
760     /* Maximum number of tokens in a NM description */
761     #define NM_DESC_MAX_TOKENS 8
762    
763     /* Create a Network Module (command line) */
764     int c2691_cmd_nm_create(c2691_t *router,char *str)
765     {
766     char *tokens[NM_DESC_MAX_TOKENS];
767     int i,count,res;
768     u_int nm_bay;
769    
770     /* A port adapter description is like "1:NM-1FE" */
771     if ((count = m_strsplit(str,':',tokens,NM_DESC_MAX_TOKENS)) != 2) {
772     vm_error(router->vm,"unable to parse NM description '%s'.\n",str);
773     return(-1);
774     }
775    
776     /* Parse the NM bay id */
777     nm_bay = atoi(tokens[0]);
778    
779     /* Add this new NM to the current NM list */
780     res = c2691_nm_add_binding(router,tokens[1],nm_bay);
781    
782     /* The complete array was cleaned by strsplit */
783     for(i=0;i<NM_DESC_MAX_TOKENS;i++)
784     free(tokens[i]);
785    
786     return(res);
787     }
788    
789     /* Add a Network IO descriptor binding (command line) */
790     int c2691_cmd_add_nio(c2691_t *router,char *str)
791     {
792     char *tokens[NM_DESC_MAX_TOKENS];
793     int i,count,nio_type,res=-1;
794     u_int nm_bay,port_id;
795     netio_desc_t *nio;
796     char nio_name[128];
797    
798     /* A port adapter description is like "1:3:tap:tap0" */
799     if ((count = m_strsplit(str,':',tokens,NM_DESC_MAX_TOKENS)) < 3) {
800     vm_error(router->vm,"unable to parse NIO description '%s'.\n",str);
801     return(-1);
802     }
803    
804     /* Parse the NM bay */
805     nm_bay = atoi(tokens[0]);
806    
807     /* Parse the NM port id */
808     port_id = atoi(tokens[1]);
809    
810     /* Autogenerate a NIO name */
811     snprintf(nio_name,sizeof(nio_name),"c2691-i%u/%u/%u",
812     router->vm->instance_id,nm_bay,port_id);
813    
814     /* Create the Network IO descriptor */
815     nio = NULL;
816     nio_type = netio_get_type(tokens[2]);
817    
818     switch(nio_type) {
819     case NETIO_TYPE_UNIX:
820     if (count != 5) {
821     vm_error(router->vm,
822     "invalid number of arguments for UNIX NIO '%s'\n",str);
823     goto done;
824     }
825    
826     nio = netio_desc_create_unix(nio_name,tokens[3],tokens[4]);
827     break;
828    
829     case NETIO_TYPE_VDE:
830     if (count != 5) {
831     vm_error(router->vm,
832     "invalid number of arguments for VDE NIO '%s'\n",str);
833     goto done;
834     }
835    
836     nio = netio_desc_create_vde(nio_name,tokens[3],tokens[4]);
837     break;
838    
839     case NETIO_TYPE_TAP:
840     if (count != 4) {
841     vm_error(router->vm,
842     "invalid number of arguments for TAP NIO '%s'\n",str);
843     goto done;
844     }
845    
846     nio = netio_desc_create_tap(nio_name,tokens[3]);
847     break;
848    
849     case NETIO_TYPE_UDP:
850     if (count != 6) {
851     vm_error(router->vm,
852     "invalid number of arguments for UDP NIO '%s'\n",str);
853     goto done;
854     }
855    
856     nio = netio_desc_create_udp(nio_name,atoi(tokens[3]),
857     tokens[4],atoi(tokens[5]));
858     break;
859    
860     case NETIO_TYPE_TCP_CLI:
861     if (count != 5) {
862     vm_error(router->vm,
863     "invalid number of arguments for TCP CLI NIO '%s'\n",str);
864     goto done;
865     }
866    
867     nio = netio_desc_create_tcp_cli(nio_name,tokens[3],tokens[4]);
868     break;
869    
870     case NETIO_TYPE_TCP_SER:
871     if (count != 4) {
872     vm_error(router->vm,
873     "invalid number of arguments for TCP SER NIO '%s'\n",str);
874     goto done;
875     }
876    
877     nio = netio_desc_create_tcp_ser(nio_name,tokens[3]);
878     break;
879    
880     case NETIO_TYPE_NULL:
881     nio = netio_desc_create_null(nio_name);
882     break;
883    
884     #ifdef LINUX_ETH
885     case NETIO_TYPE_LINUX_ETH:
886     if (count != 4) {
887     vm_error(router->vm,
888     "invalid number of arguments for Linux Eth NIO '%s'\n",
889     str);
890     goto done;
891     }
892    
893     nio = netio_desc_create_lnxeth(nio_name,tokens[3]);
894     break;
895     #endif
896    
897     #ifdef GEN_ETH
898     case NETIO_TYPE_GEN_ETH:
899     if (count != 4) {
900     vm_error(router->vm,
901     "invalid number of arguments for Generic Eth NIO '%s'\n",
902     str);
903     goto done;
904     }
905    
906     nio = netio_desc_create_geneth(nio_name,tokens[3]);
907     break;
908     #endif
909    
910     default:
911     vm_error(router->vm,"unknown NETIO type '%s'\n",tokens[2]);
912     goto done;
913     }
914    
915     if (!nio) {
916     vm_error(router->vm,"unable to create NETIO "
917     "descriptor for NM slot %u\n",nm_bay);
918     goto done;
919     }
920    
921     if (c2691_nm_add_nio_binding(router,nm_bay,port_id,nio_name) == -1) {
922     vm_error(router->vm,"unable to add NETIO binding for slot %u\n",nm_bay);
923     netio_release(nio_name);
924     netio_delete(nio_name);
925     goto done;
926     }
927    
928     netio_release(nio_name);
929     res = 0;
930    
931     done:
932     /* The complete array was cleaned by strsplit */
933     for(i=0;i<NM_DESC_MAX_TOKENS;i++)
934     free(tokens[i]);
935    
936     return(res);
937     }
938    
939     /* Show the list of available NM drivers */
940     void c2691_nm_show_drivers(void)
941     {
942     int i;
943    
944     printf("Available C2691 Network Module drivers:\n");
945    
946     for(i=0;nm_drivers[i];i++) {
947     printf(" * %s %s\n",
948     nm_drivers[i]->dev_type,
949     !nm_drivers[i]->supported ? "(NOT WORKING)" : "");
950     }
951    
952     printf("\n");
953     }
954    
955     /* Set the base MAC address of the chassis */
956     static int c2691_burn_mac_addr(c2691_t *router,n_eth_addr_t *addr)
957     {
958     m_uint8_t eeprom_ver;
959     size_t offset;
960    
961     /* Read EEPROM format version */
962     cisco_eeprom_get_byte(&router->mb_eeprom,0,&eeprom_ver);
963    
964     switch(eeprom_ver) {
965     case 0:
966     cisco_eeprom_set_region(&router->mb_eeprom,2,addr->eth_addr_byte,6);
967     break;
968    
969     case 4:
970     if (!cisco_eeprom_v4_find_field(&router->mb_eeprom,0xC3,&offset)) {
971     cisco_eeprom_set_region(&router->mb_eeprom,offset,
972     addr->eth_addr_byte,6);
973     }
974     break;
975    
976     default:
977     vm_error(router->vm,"c2691_burn_mac_addr: unable to handle "
978     "EEPROM version %u\n",eeprom_ver);
979     return(-1);
980     }
981    
982     return(0);
983     }
984    
985     /* Set chassis MAC address */
986     int c2691_chassis_set_mac_addr(c2691_t *router,char *mac_addr)
987     {
988     if (parse_mac_addr(&router->mac_addr,mac_addr) == -1) {
989     vm_error(router->vm,"unable to parse MAC address '%s'.\n",mac_addr);
990     return(-1);
991     }
992    
993     /* Set the chassis base MAC address */
994     c2691_burn_mac_addr(router,&router->mac_addr);
995     return(0);
996     }
997    
998     /* Create the two main PCI busses for a GT64120 based system */
999     static int c2691_init_gt96100(c2691_t *router)
1000     {
1001     vm_instance_t *vm = router->vm;
1002    
1003     vm->pci_bus[0] = pci_bus_create("PCI bus #0",0);
1004     vm->pci_bus[1] = pci_bus_create("PCI bus #1",0);
1005    
1006     if (!vm->pci_bus[0] || !vm->pci_bus[1]) {
1007     vm_error(router->vm,"unable to create PCI data.\n");
1008     return(-1);
1009     }
1010    
1011     return(dev_gt96100_init(vm,"gt96100",C2691_GT96K_ADDR,0x200000,
1012     C2691_GT96K_IRQ,C2691_NETIO_IRQ));
1013     }
1014    
1015     /* Initialize a Cisco 2691 */
1016     static int c2691_init(c2691_t *router)
1017     {
1018     vm_instance_t *vm = router->vm;
1019    
1020     /* Set the processor type: R7000 */
1021 dpavlin 7 mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R7000);
1022 dpavlin 4
1023     /* Initialize the Galileo GT-96100 PCI controller */
1024     if (c2691_init_gt96100(router) == -1)
1025     return(-1);
1026    
1027     /* Initialize PCI map (NM slot 1) */
1028     router->nm_bay[1].pci_map = vm->pci_bus[1];
1029    
1030     vm->elf_machine_id = C2691_ELF_MACHINE_ID;
1031     return(0);
1032     }
1033    
1034     /* Show C2691 hardware info */
1035     void c2691_show_hardware(c2691_t *router)
1036     {
1037     vm_instance_t *vm = router->vm;
1038    
1039     printf("C2691 instance '%s' (id %d):\n",vm->name,vm->instance_id);
1040    
1041     printf(" VM Status : %d\n",vm->status);
1042     printf(" RAM size : %u Mb\n",vm->ram_size);
1043     printf(" NVRAM size : %u Kb\n",vm->nvram_size);
1044     printf(" IOS image : %s\n\n",vm->ios_image);
1045    
1046     if (vm->debug_level > 0) {
1047     dev_show_list(vm);
1048     pci_dev_show_list(vm->pci_bus[0]);
1049     pci_dev_show_list(vm->pci_bus[1]);
1050     printf("\n");
1051     }
1052     }
1053    
1054     /* Initialize default parameters for a C2691 */
1055     void c2691_init_defaults(c2691_t *router)
1056     {
1057     vm_instance_t *vm = router->vm;
1058     n_eth_addr_t *m;
1059     m_uint16_t pid;
1060    
1061     pid = (m_uint16_t)getpid();
1062    
1063     /* Generate a chassis MAC address based on the instance ID */
1064     m = &router->mac_addr;
1065     m->eth_addr_byte[0] = vm_get_mac_addr_msb(vm);
1066     m->eth_addr_byte[1] = vm->instance_id & 0xFF;
1067     m->eth_addr_byte[2] = pid >> 8;
1068     m->eth_addr_byte[3] = pid & 0xFF;
1069     m->eth_addr_byte[4] = 0x00;
1070     m->eth_addr_byte[5] = 0x00;
1071    
1072     c2691_init_eeprom_groups(router);
1073     cisco_eeprom_copy(&router->mb_eeprom,&eeprom_c2691_mainboard);
1074     c2691_burn_mac_addr(router,&router->mac_addr);
1075    
1076     vm->ram_mmap = C2691_DEFAULT_RAM_MMAP;
1077     vm->ram_size = C2691_DEFAULT_RAM_SIZE;
1078     vm->rom_size = C2691_DEFAULT_ROM_SIZE;
1079     vm->nvram_size = C2691_DEFAULT_NVRAM_SIZE;
1080     vm->conf_reg_setup = C2691_DEFAULT_CONF_REG;
1081     vm->clock_divisor = C2691_DEFAULT_CLOCK_DIV;
1082     vm->nvram_rom_space = C2691_NVRAM_ROM_RES_SIZE;
1083     router->nm_iomem_size = C2691_DEFAULT_IOMEM_SIZE;
1084    
1085     vm->pcmcia_disk_size[0] = C2691_DEFAULT_DISK0_SIZE;
1086     vm->pcmcia_disk_size[1] = C2691_DEFAULT_DISK1_SIZE;
1087    
1088     /* Enable NVRAM operations to load/store configs */
1089     vm->nvram_extract_config = c2691_nvram_extract_config;
1090     vm->nvram_push_config = c2691_nvram_push_config;
1091     }
1092    
1093     /* Initialize the C2691 Platform */
1094     int c2691_init_platform(c2691_t *router)
1095     {
1096     vm_instance_t *vm = router->vm;
1097     struct c2691_nm_bay *nm_bay;
1098     cpu_mips_t *cpu;
1099 dpavlin 7 cpu_gen_t *gen;
1100 dpavlin 4 vm_obj_t *obj;
1101     int i;
1102    
1103     /* Copy config register setup into "active" config register */
1104     vm->conf_reg = vm->conf_reg_setup;
1105    
1106     /* Create Console and AUX ports */
1107     vm_init_vtty(vm);
1108    
1109     /* Create a CPU group */
1110     vm->cpu_group = cpu_group_create("System CPU");
1111    
1112     /* Initialize the virtual MIPS processor */
1113 dpavlin 7 if (!(gen = cpu_create(vm,CPU_TYPE_MIPS64,0))) {
1114 dpavlin 4 vm_error(vm,"unable to create CPU!\n");
1115     return(-1);
1116     }
1117    
1118 dpavlin 7 cpu = CPU_MIPS64(gen);
1119    
1120 dpavlin 4 /* Add this CPU to the system CPU group */
1121 dpavlin 7 cpu_group_add(vm->cpu_group,gen);
1122     vm->boot_cpu = gen;
1123 dpavlin 4
1124 dpavlin 7 /* Initialize the IRQ routing vectors */
1125     vm->set_irq = mips64_vm_set_irq;
1126     vm->clear_irq = mips64_vm_clear_irq;
1127    
1128 dpavlin 4 /* Mark the Network IO interrupt as high priority */
1129     cpu->irq_idle_preempt[C2691_NETIO_IRQ] = TRUE;
1130     cpu->irq_idle_preempt[C2691_GT96K_IRQ] = TRUE;
1131     cpu->irq_idle_preempt[C2691_DUART_IRQ] = TRUE;
1132    
1133     /* Copy some parameters from VM to CPU (idle PC, ...) */
1134     cpu->idle_pc = vm->idle_pc;
1135    
1136     if (vm->timer_irq_check_itv)
1137     cpu->timer_irq_check_itv = vm->timer_irq_check_itv;
1138    
1139     /* Remote emulator control */
1140     dev_remote_control_init(vm,0x16000000,0x1000);
1141    
1142     /* Specific Storage Area (SSA) */
1143 dpavlin 7 dev_ram_init(vm,"ssa",TRUE,FALSE,NULL,FALSE,0x16001000ULL,0x7000);
1144 dpavlin 4
1145     /* IO FPGA */
1146     if (dev_c2691_iofpga_init(router,C2691_IOFPGA_ADDR,0x40000) == -1)
1147     return(-1);
1148    
1149     #if 0
1150     /* PCI IO space */
1151     if (!(vm->pci_io_space = pci_io_data_init(vm,C2691_PCI_IO_ADDR)))
1152     return(-1);
1153     #endif
1154    
1155     /* Initialize the chassis */
1156     if (c2691_init(router) == -1)
1157     return(-1);
1158    
1159     /* Initialize RAM */
1160     vm_ram_init(vm,0x00000000ULL);
1161    
1162     /* Initialize ROM (as a Flash) */
1163     if (!(obj = dev_flash_init(vm,"rom",C2691_ROM_ADDR,vm->rom_size*1048576)))
1164     return(-1);
1165    
1166 dpavlin 7 dev_flash_copy_data(obj,0,mips64_microcode,mips64_microcode_len);
1167 dpavlin 4 c2691_nvram_check_empty_config(vm);
1168    
1169     /* Initialize the NS16552 DUART */
1170     dev_ns16552_init(vm,C2691_DUART_ADDR,0x1000,3,C2691_DUART_IRQ,
1171     vm->vtty_con,vm->vtty_aux);
1172    
1173     /* PCMCIA Slot 0 */
1174     dev_pcmcia_disk_init(vm,"slot0",C2691_SLOT0_ADDR,0x200000,
1175     vm->pcmcia_disk_size[0],1);
1176    
1177     /* PCMCIA Slot 1 */
1178     dev_pcmcia_disk_init(vm,"slot1",C2691_SLOT1_ADDR,0x200000,
1179     vm->pcmcia_disk_size[1],1);
1180    
1181     /* The GT96100 system controller has 2 integrated FastEthernet ports */
1182     c2691_nm_add_binding(router,"GT96100-FE",0);
1183    
1184     /* Initialize Network Modules */
1185     for(i=0;i<C2691_MAX_NM_BAYS;i++) {
1186     nm_bay = &router->nm_bay[i];
1187    
1188     if (!nm_bay->dev_type)
1189     continue;
1190    
1191     if (c2691_nm_init(router,i) == -1) {
1192     vm_error(vm,"unable to create Network Module \"%s\"\n",
1193     nm_bay->dev_type);
1194     return(-1);
1195     }
1196     }
1197    
1198     /* Show device list */
1199     c2691_show_hardware(router);
1200     return(0);
1201     }
1202    
1203     /* Boot the IOS image */
1204     int c2691_boot_ios(c2691_t *router)
1205     {
1206     vm_instance_t *vm = router->vm;
1207 dpavlin 7 cpu_mips_t *cpu;
1208 dpavlin 4
1209     if (!vm->boot_cpu)
1210     return(-1);
1211    
1212     /* Suspend CPU activity since we will restart directly from ROM */
1213     vm_suspend(vm);
1214    
1215     /* Check that CPU activity is really suspended */
1216     if (cpu_group_sync_state(vm->cpu_group) == -1) {
1217     vm_error(vm,"unable to sync with system CPUs.\n");
1218     return(-1);
1219     }
1220    
1221     /* Reset the boot CPU */
1222 dpavlin 7 cpu = CPU_MIPS64(vm->boot_cpu);
1223     mips64_reset(cpu);
1224 dpavlin 4
1225     /* Load IOS image */
1226 dpavlin 7 if (mips64_load_elf_image(cpu,vm->ios_image,
1227 dpavlin 4 (vm->ghost_status == VM_GHOST_RAM_USE),
1228     &vm->ios_entry_point) < 0)
1229     {
1230     vm_error(vm,"failed to load Cisco IOS image '%s'.\n",vm->ios_image);
1231     return(-1);
1232     }
1233    
1234     /* Launch the simulation */
1235     printf("\nC2691 '%s': starting simulation (CPU0 PC=0x%llx), "
1236     "JIT %sabled.\n",
1237 dpavlin 7 vm->name,cpu->pc,vm->jit_use ? "en":"dis");
1238 dpavlin 4
1239     vm_log(vm,"C2691_BOOT",
1240     "starting instance (CPU0 PC=0x%llx,idle_pc=0x%llx,JIT %s)\n",
1241 dpavlin 7 cpu->pc,cpu->idle_pc,vm->jit_use ? "on":"off");
1242 dpavlin 4
1243     /* Start main CPU */
1244     if (vm->ghost_status != VM_GHOST_RAM_GENERATE) {
1245     vm->status = VM_STATUS_RUNNING;
1246     cpu_start(vm->boot_cpu);
1247     } else {
1248     vm->status = VM_STATUS_SHUTDOWN;
1249     }
1250     return(0);
1251     }
1252    
1253     /* Initialize a Cisco 2691 instance */
1254     int c2691_init_instance(c2691_t *router)
1255     {
1256     vm_instance_t *vm = router->vm;
1257     m_uint32_t rom_entry_point;
1258     cpu_mips_t *cpu0;
1259    
1260     if (!vm->ios_image) {
1261     vm_error(vm,"no Cisco IOS image defined.");
1262     return(-1);
1263     }
1264    
1265     /* Initialize the C2691 platform */
1266     if (c2691_init_platform(router) == -1) {
1267     vm_error(vm,"unable to initialize the platform hardware.\n");
1268     return(-1);
1269     }
1270    
1271     /* Load IOS configuration file */
1272     if (vm->ios_config != NULL) {
1273     vm_nvram_push_config(vm,vm->ios_config);
1274     vm->conf_reg &= ~0x40;
1275     }
1276    
1277     /* Load ROM (ELF image or embedded) */
1278 dpavlin 7 cpu0 = CPU_MIPS64(vm->boot_cpu);
1279 dpavlin 4 rom_entry_point = (m_uint32_t)MIPS_ROM_PC;
1280    
1281     if ((vm->rom_filename != NULL) &&
1282     (mips64_load_elf_image(cpu0,vm->rom_filename,0,&rom_entry_point) < 0))
1283     {
1284     vm_error(vm,"unable to load alternate ROM '%s', "
1285     "fallback to embedded ROM.\n\n",vm->rom_filename);
1286     vm->rom_filename = NULL;
1287     }
1288    
1289     /* Load symbol file */
1290     if (vm->sym_filename) {
1291     mips64_sym_load_file(cpu0,vm->sym_filename);
1292     cpu0->sym_trace = 1;
1293     }
1294    
1295     return(c2691_boot_ios(router));
1296     }
1297    
1298     /* Stop a Cisco 2691 instance */
1299     int c2691_stop_instance(c2691_t *router)
1300     {
1301     vm_instance_t *vm = router->vm;
1302    
1303     printf("\nC2691 '%s': stopping simulation.\n",vm->name);
1304     vm_log(vm,"C2691_STOP","stopping simulation.\n");
1305    
1306     /* Stop all CPUs */
1307     if (vm->cpu_group != NULL) {
1308     vm_stop(vm);
1309    
1310     if (cpu_group_sync_state(vm->cpu_group) == -1) {
1311     vm_error(vm,"unable to sync with system CPUs.\n");
1312     return(-1);
1313     }
1314     }
1315    
1316     /* Free resources that were used during execution to emulate hardware */
1317     c2691_nm_shutdown_all(router);
1318     vm_hardware_shutdown(vm);
1319     return(0);
1320     }

  ViewVC Help
Powered by ViewVC 1.1.26