/[dynamips]/upstream/dynamips-0.2.5/dev_c3600.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 /upstream/dynamips-0.2.5/dev_c3600.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Sat Oct 6 16:01:44 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 40394 byte(s)
import 0.2.5 from upstream

1 dpavlin 1 /*
2     * Cisco 3600 simulation platform.
3     * Copyright (c) 2006 Christophe Fillot (cf@utc.fr)
4     *
5     * Generic Cisco 3600 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     #include "mips64.h"
16     #include "dynamips.h"
17     #include "memory.h"
18     #include "device.h"
19     #include "pci_io.h"
20     #include "cisco_eeprom.h"
21     #include "dev_c3600.h"
22     #include "dev_c3600_bay.h"
23     #include "dev_vtty.h"
24     #include "registry.h"
25    
26     /* ======================================================================== */
27     /* EEPROM definitions */
28     /* ======================================================================== */
29    
30     /* Cisco 3620 mainboard EEPROM */
31     static m_uint16_t eeprom_c3620_mainboard[64] = {
32     0x0001, 0x0000, 0x0000, 0x0000, 0x0AFF, 0x7318, 0x5011, 0x0020,
33     0x0000, 0x0000, 0xA0FF, 0x9904, 0x19FF, 0xFFFF, 0xFFFF, 0x0002,
34     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
35     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
36     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
37     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
38     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
39     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
40     };
41    
42     /* Cisco 3640 mainboard EEPROM */
43     static m_uint16_t eeprom_c3640_mainboard[64] = {
44     0x0001, 0x0000, 0x0000, 0x0000, 0x0AFF, 0x7316, 0x8514, 0x0040,
45     0x0000, 0x0000, 0xA1FF, 0x0102, 0x22FF, 0xFFFF, 0xFFFF, 0x0002,
46     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
47     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
48     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
49     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
50     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
51     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
52     };
53    
54     /* Cisco 3660 backplane EEPROM */
55     static m_uint16_t eeprom_c3660_backplane[64] = {
56     0x04FF, 0x4000, 0xC841, 0x0100, 0xC046, 0x0320, 0x0012, 0x8402,
57     0x4243, 0x3080, 0x0000, 0x0000, 0x0202, 0xC18B, 0x4841, 0x4430,
58     0x3434, 0x3431, 0x3135, 0x4A03, 0x0081, 0x0000, 0x0000, 0x0400,
59     0xC28B, 0x4A41, 0x4230, 0x3434, 0x3643, 0x304C, 0x32C3, 0x0600,
60     0x044D, 0x0EC2, 0xD043, 0x0070, 0xC408, 0x0000, 0x0000, 0x0000,
61     0x0000, 0x851C, 0x0A5B, 0x0201, 0x06FF, 0xFFFF, 0xFFFF, 0xFFFF,
62     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
63     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
64     };
65    
66     /* ======================================================================== */
67     /* Chassis Drivers */
68     /* ======================================================================== */
69     static int c3620_init(c3600_t *router);
70     static int c3640_init(c3600_t *router);
71     static int c3660_init(c3600_t *router);
72    
73     static struct c3600_chassis_driver chassis_drivers[] = {
74     { "3620" , 3620, 1, c3620_init,
75     eeprom_c3620_mainboard, sizeof(eeprom_c3620_mainboard)/2 },
76     { "3640" , 3640, 1, c3640_init,
77     eeprom_c3640_mainboard, sizeof(eeprom_c3640_mainboard)/2 },
78     { "3660" , 3660, 1, c3660_init,
79     eeprom_c3660_backplane, sizeof(eeprom_c3660_backplane)/2 },
80    
81     { NULL , -1, 0, NULL },
82     };
83    
84     /* ======================================================================== */
85     /* Network Module Drivers */
86     /* ======================================================================== */
87     static struct c3600_nm_driver *nm_drivers[] = {
88     &dev_c3600_nm_1e_driver,
89     &dev_c3600_nm_4e_driver,
90     &dev_c3600_nm_1fe_tx_driver,
91     &dev_c3600_nm_4t_driver,
92     &dev_c3600_leopard_2fe_driver,
93     NULL,
94     };
95    
96     /* ======================================================================== */
97     /* Cisco 3600 router instances */
98     /* ======================================================================== */
99    
100     /* Directly extract the configuration from the NVRAM device */
101     ssize_t c3600_nvram_extract_config(vm_instance_t *vm,char **buffer)
102     {
103     struct vdevice *nvram_dev;
104     m_uint32_t start,end,clen,nvlen;
105     m_uint16_t magic1,magic2;
106     m_uint64_t addr;
107    
108     if (!(nvram_dev = dev_get_by_name(vm,"nvram")))
109     return(-1);
110    
111     addr = nvram_dev->phys_addr + vm->nvram_rom_space;
112     magic1 = physmem_copy_u16_from_vm(vm,addr+0x06);
113     magic2 = physmem_copy_u16_from_vm(vm,addr+0x08);
114    
115     if ((magic1 != 0xF0A5) || (magic2 != 0xABCD)) {
116     vm_error(vm,"unable to find IOS magic numbers (0x%x,0x%x)!\n",
117     magic1,magic2);
118     return(-1);
119     }
120    
121     start = physmem_copy_u32_from_vm(vm,addr+0x10) + 1;
122     end = physmem_copy_u32_from_vm(vm,addr+0x14);
123     nvlen = physmem_copy_u32_from_vm(vm,addr+0x18);
124     clen = end - start;
125    
126     if ((clen + 1) != nvlen) {
127     vm_error(vm,"invalid configuration size (0x%x)\n",nvlen);
128     return(-1);
129     }
130    
131     if (!(*buffer = malloc(clen+1))) {
132     vm_error(vm,"unable to allocate config buffer (%u bytes)\n",clen);
133     return(-1);
134     }
135    
136     physmem_copy_from_vm(vm,*buffer,addr+start+0x08,clen);
137     (*buffer)[clen] = 0;
138     return(clen);
139     }
140    
141     /* Compute NVRAM checksum */
142     static u_int16_t nvram_cksum(vm_instance_t *vm,m_uint64_t addr,size_t count)
143     {
144     m_uint32_t sum = 0;
145    
146     while(count > 1) {
147     sum = sum + physmem_copy_u16_from_vm(vm,addr);
148     addr += sizeof(m_uint16_t);
149     count -= sizeof(m_uint16_t);
150     }
151    
152     if (count > 0)
153     sum = sum + ((physmem_copy_u16_from_vm(vm,addr) & 0xFF) << 8);
154    
155     while(sum>>16)
156     sum = (sum & 0xffff) + (sum >> 16);
157    
158     return(~sum);
159     }
160    
161    
162     /* Directly push the IOS configuration to the NVRAM device */
163     int c3600_nvram_push_config(vm_instance_t *vm,char *buffer,size_t len)
164     {
165     struct vdevice *nvram_dev;
166     m_uint64_t addr,cfg_addr;
167     m_uint32_t tmp,cfg_offset;
168     m_uint32_t cklen;
169     m_uint16_t cksum;
170    
171     if (!(nvram_dev = dev_get_by_name(vm,"nvram")))
172     return(-1);
173    
174     addr = nvram_dev->phys_addr + vm->nvram_rom_space;
175     cfg_offset = 0x2c;
176     cfg_addr = addr + cfg_offset;;
177    
178     /* Write IOS tag, uncompressed config... */
179     physmem_copy_u16_to_vm(vm,addr+0x06,0xF0A5);
180     physmem_copy_u16_to_vm(vm,addr+0x08,0xABCD); /* Magic number */
181     physmem_copy_u16_to_vm(vm,addr+0x0a,0x0001); /* ??? */
182     physmem_copy_u16_to_vm(vm,addr+0x0c,0x0000); /* Checksum */
183     physmem_copy_u16_to_vm(vm,addr+0x0e,0x0c04); /* IOS version */
184    
185     /* Store file contents to NVRAM */
186     physmem_copy_to_vm(vm,buffer,cfg_addr,len);
187    
188     /* Write config addresses + size */
189     tmp = cfg_addr - addr - 0x08;
190    
191     physmem_copy_u32_to_vm(vm,addr+0x10,tmp);
192     physmem_copy_u32_to_vm(vm,addr+0x14,tmp + len);
193     physmem_copy_u32_to_vm(vm,addr+0x18,len);
194    
195     /* Compute the checksum */
196     cklen = nvram_dev->phys_len - (vm->nvram_rom_space + 0x08);
197     cksum = nvram_cksum(vm,addr+0x08,cklen);
198     physmem_copy_u16_to_vm(vm,addr+0x0c,cksum);
199     return(0);
200     }
201    
202     /* Create a new router instance */
203     c3600_t *c3600_create_instance(char *name,int instance_id)
204     {
205     c3600_t *router;
206    
207     if (!(router = malloc(sizeof(*router)))) {
208     fprintf(stderr,"C3600 '%s': Unable to create new instance!\n",name);
209     return NULL;
210     }
211    
212     memset(router,0,sizeof(*router));
213    
214     if (!(router->vm = vm_create(name,instance_id,VM_TYPE_C3600))) {
215     fprintf(stderr,"C3600 '%s': unable to create VM instance!\n",name);
216     goto err_vm;
217     }
218    
219     c3600_init_defaults(router);
220     router->vm->hw_data = router;
221     return router;
222    
223     err_vm:
224     free(router);
225     return NULL;
226     }
227    
228     /* Free resources used by a router instance */
229     static int c3600_free_instance(void *data,void *arg)
230     {
231     vm_instance_t *vm = data;
232     c3600_t *router;
233     int i;
234    
235     if (vm->type == VM_TYPE_C3600) {
236     router = VM_C3600(vm);
237    
238     /* Stop all CPUs */
239     if (vm->cpu_group != NULL) {
240     vm_stop(vm);
241    
242     if (cpu_group_sync_state(vm->cpu_group) == -1) {
243     vm_error(vm,"unable to sync with system CPUs.\n");
244     return(FALSE);
245     }
246     }
247    
248     /* Remove NIO bindings */
249     for(i=0;i<C3600_MAX_NM_BAYS;i++)
250     c3600_nm_remove_all_nio_bindings(router,i);
251    
252     /* Shutdown all Network Modules */
253     c3600_nm_shutdown_all(router);
254    
255     /* Free all resources used by VM */
256     vm_free(vm);
257    
258     /* Free the router structure */
259     free(router);
260     return(TRUE);
261     }
262    
263     return(FALSE);
264     }
265    
266     /* Delete a router instance */
267     int c3600_delete_instance(char *name)
268     {
269     return(registry_delete_if_unused(name,OBJ_TYPE_VM,
270     c3600_free_instance,NULL));
271     }
272    
273     /* Delete all router instances */
274     int c3600_delete_all_instances(void)
275     {
276     return(registry_delete_type(OBJ_TYPE_VM,c3600_free_instance,NULL));
277     }
278    
279     /* Save configuration of a C3600 instance */
280     void c3600_save_config(c3600_t *router,FILE *fd)
281     {
282     vm_instance_t *vm = router->vm;
283     struct c3600_nio_binding *nb;
284     struct c3600_nm_bay *bay;
285     int i;
286    
287     /* General settings */
288     fprintf(fd,"c3600 create %s %u\n",vm->name,vm->instance_id);
289    
290     fprintf(fd,"c3600 set_chassis %s %s\n",
291     vm->name,router->chassis_driver->chassis_type);
292    
293     /* VM configuration */
294     vm_save_config(vm,fd);
295    
296     /* Network Module settings */
297     for(i=0;i<C3600_MAX_NM_BAYS;i++) {
298     if (!(bay = c3600_nm_get_info(router,i)))
299     continue;
300    
301     if (bay->dev_type) {
302     fprintf(fd,"c3600 add_nm_binding %s %u %s\n",
303     vm->name,i,bay->dev_type);
304     }
305    
306     for(nb=bay->nio_list;nb;nb=nb->next) {
307     fprintf(fd,"c3600 add_nio_binding %s %u %u %s\n",
308     vm->name,i,nb->port_id,nb->nio->name);
309     }
310     }
311    
312     fprintf(fd,"\n");
313     }
314    
315     /* Save configurations of all C3600 instances */
316     static void c3600_reg_save_config(registry_entry_t *entry,void *opt,int *err)
317     {
318     vm_instance_t *vm = entry->data;
319     c3600_t *router = VM_C3600(vm);
320    
321     if (vm->type == VM_TYPE_C3600)
322     c3600_save_config(router,(FILE *)opt);
323     }
324    
325     void c3600_save_config_all(FILE *fd)
326     {
327     registry_foreach_type(OBJ_TYPE_VM,c3600_reg_save_config,fd,NULL);
328     }
329    
330     /* Set NM EEPROM definition */
331     int c3600_nm_set_eeprom(c3600_t *router,u_int nm_bay,
332     const struct c3600_eeprom *eeprom)
333     {
334     if (nm_bay >= C3600_MAX_NM_BAYS) {
335     vm_error(router->vm,"c3600_nm_set_eeprom: invalid NM Bay %u.\n",nm_bay);
336     return(-1);
337     }
338    
339     /* 3620/3640 */
340     router->nm_bay[nm_bay].eeprom_data = eeprom->data;
341     router->nm_bay[nm_bay].eeprom_data_len = eeprom->len;
342    
343     /* 3660 */
344     router->c3660_nm_eeprom_def[nm_bay].data = eeprom->data;
345     router->c3660_nm_eeprom_def[nm_bay].data_len = eeprom->len;
346     return(0);
347     }
348    
349     /* Unset NM EEPROM definition (empty bay) */
350     int c3600_nm_unset_eeprom(c3600_t *router,u_int nm_bay)
351     {
352     if (nm_bay >= C3600_MAX_NM_BAYS) {
353     vm_error(router->vm,"c3600_nm_set_eeprom: invalid NM Bay %u.\n",nm_bay);
354     return(-1);
355     }
356    
357     /* 3620/3640 */
358     router->nm_bay[nm_bay].eeprom_data = NULL;
359     router->nm_bay[nm_bay].eeprom_data_len = 0;
360    
361     /* 3660 */
362     router->c3660_nm_eeprom_def[nm_bay].data = NULL;
363     router->c3660_nm_eeprom_def[nm_bay].data_len = 0;
364     return(0);
365     }
366    
367     /* Check if a bay has a port adapter */
368     int c3600_nm_check_eeprom(c3600_t *router,u_int nm_bay)
369     {
370     if (nm_bay >= C3600_MAX_NM_BAYS)
371     return(FALSE);
372    
373     return((router->nm_bay[nm_bay].eeprom_data != NULL) ? TRUE : FALSE);
374     }
375    
376     /* Get bay info */
377     struct c3600_nm_bay *c3600_nm_get_info(c3600_t *router,u_int nm_bay)
378     {
379     if (nm_bay >= C3600_MAX_NM_BAYS)
380     return NULL;
381    
382     return(&router->nm_bay[nm_bay]);
383     }
384    
385     /* Get NM type */
386     char *c3600_nm_get_type(c3600_t *router,u_int nm_bay)
387     {
388     struct c3600_nm_bay *bay;
389    
390     bay = c3600_nm_get_info(router,nm_bay);
391     return((bay != NULL) ? bay->dev_type : NULL);
392     }
393    
394     /* Get driver info about the specified slot */
395     void *c3600_nm_get_drvinfo(c3600_t *router,u_int nm_bay)
396     {
397     struct c3600_nm_bay *bay;
398    
399     bay = c3600_nm_get_info(router,nm_bay);
400     return((bay != NULL) ? bay->drv_info : NULL);
401     }
402    
403     /* Set driver info for the specified slot */
404     int c3600_nm_set_drvinfo(c3600_t *router,u_int nm_bay,void *drv_info)
405     {
406     struct c3600_nm_bay *bay;
407    
408     if (!(bay = c3600_nm_get_info(router,nm_bay)))
409     return(-1);
410    
411     bay->drv_info = drv_info;
412     return(0);
413     }
414    
415     /* Get a NM driver */
416     static struct c3600_nm_driver *c3600_nm_get_driver(char *dev_type)
417     {
418     int i;
419    
420     for(i=0;nm_drivers[i];i++)
421     if (!strcmp(nm_drivers[i]->dev_type,dev_type))
422     return nm_drivers[i];
423    
424     return NULL;
425     }
426    
427     /* Add a NM binding */
428     int c3600_nm_add_binding(c3600_t *router,char *dev_type,u_int nm_bay)
429     {
430     struct c3600_nm_driver *nm_driver;
431     struct c3600_nm_bay *bay;
432    
433     if (!(bay = c3600_nm_get_info(router,nm_bay)))
434     return(-1);
435    
436     /* check that this bay is empty */
437     if (bay->dev_type != NULL) {
438     vm_error(router->vm,"a NM already exists in slot %u.\n",nm_bay);
439     return(-1);
440     }
441    
442     /* find the NM driver */
443     if (!(nm_driver = c3600_nm_get_driver(dev_type))) {
444     vm_error(router->vm,"unknown NM type '%s'.\n",dev_type);
445     return(-1);
446     }
447    
448     bay->dev_type = nm_driver->dev_type;
449     bay->nm_driver = nm_driver;
450     return(0);
451     }
452    
453     /* Remove a NM binding */
454     int c3600_nm_remove_binding(c3600_t *router,u_int nm_bay)
455     {
456     struct c3600_nm_bay *bay;
457    
458     if (!(bay = c3600_nm_get_info(router,nm_bay)))
459     return(-1);
460    
461     /* stop if this bay is still active */
462     if (bay->drv_info != NULL) {
463     vm_error(router->vm,"slot %u still active.\n",nm_bay);
464     return(-1);
465     }
466    
467     /* check that this bay is not empty */
468     if (bay->dev_type == NULL) {
469     vm_error(router->vm,"slot %u is empty.\n",nm_bay);
470     return(-1);
471     }
472    
473     /* remove all NIOs bindings */
474     c3600_nm_remove_all_nio_bindings(router,nm_bay);
475    
476     bay->dev_type = NULL;
477     bay->nm_driver = NULL;
478     return(0);
479     }
480    
481     /* Find a NIO binding */
482     struct c3600_nio_binding *
483     c3600_nm_find_nio_binding(c3600_t *router,u_int nm_bay,u_int port_id)
484     {
485     struct c3600_nio_binding *nb;
486     struct c3600_nm_bay *bay;
487    
488     if (!(bay = c3600_nm_get_info(router,nm_bay)))
489     return NULL;
490    
491     for(nb=bay->nio_list;nb;nb=nb->next)
492     if (nb->port_id == port_id)
493     return nb;
494    
495     return NULL;
496     }
497    
498     /* Add a network IO binding */
499     int c3600_nm_add_nio_binding(c3600_t *router,u_int nm_bay,u_int port_id,
500     char *nio_name)
501     {
502     struct c3600_nio_binding *nb;
503     struct c3600_nm_bay *bay;
504     netio_desc_t *nio;
505    
506     if (!(bay = c3600_nm_get_info(router,nm_bay)))
507     return(-1);
508    
509     /* check that a NIO is not already bound to this port */
510     if (c3600_nm_find_nio_binding(router,nm_bay,port_id) != NULL) {
511     vm_error(router->vm,"a NIO already exists for interface %u/%u.\n",
512     nm_bay,port_id);
513     return(-1);
514     }
515    
516     /* acquire a reference on the NIO object */
517     if (!(nio = netio_acquire(nio_name))) {
518     vm_error(router->vm,"unable to find NIO '%s'.\n",nio_name);
519     return(-1);
520     }
521    
522     /* create a new binding */
523     if (!(nb = malloc(sizeof(*nb)))) {
524     vm_error(router->vm,"unable to create NIO binding "
525     "for interface %u/%u.\n",nm_bay,port_id);
526     netio_release(nio_name);
527     return(-1);
528     }
529    
530     memset(nb,0,sizeof(*nb));
531     nb->nio = nio;
532     nb->port_id = port_id;
533     nb->next = bay->nio_list;
534     if (nb->next) nb->next->prev = nb;
535     bay->nio_list = nb;
536     return(0);
537     }
538    
539     /* Remove a NIO binding */
540     int c3600_nm_remove_nio_binding(c3600_t *router,u_int nm_bay,u_int port_id)
541     {
542     struct c3600_nio_binding *nb;
543     struct c3600_nm_bay *bay;
544    
545     if (!(bay = c3600_nm_get_info(router,nm_bay)))
546     return(-1);
547    
548     if (!(nb = c3600_nm_find_nio_binding(router,nm_bay,port_id)))
549     return(-1); /* no nio binding for this slot/port */
550    
551     /* tell the NM driver to stop using this NIO */
552     if (bay->nm_driver)
553     bay->nm_driver->nm_unset_nio(router,nm_bay,port_id);
554    
555     /* remove this entry from the double linked list */
556     if (nb->next)
557     nb->next->prev = nb->prev;
558    
559     if (nb->prev) {
560     nb->prev->next = nb->next;
561     } else {
562     bay->nio_list = nb->next;
563     }
564    
565     /* unreference NIO object */
566     netio_release(nb->nio->name);
567     free(nb);
568     return(0);
569     }
570    
571     /* Remove all NIO bindings for the specified NM */
572     int c3600_nm_remove_all_nio_bindings(c3600_t *router,u_int nm_bay)
573     {
574     struct c3600_nio_binding *nb,*next;
575     struct c3600_nm_bay *bay;
576    
577     if (!(bay = c3600_nm_get_info(router,nm_bay)))
578     return(-1);
579    
580     for(nb=bay->nio_list;nb;nb=next) {
581     next = nb->next;
582    
583     /* tell the NM driver to stop using this NIO */
584     if (bay->nm_driver)
585     bay->nm_driver->nm_unset_nio(router,nm_bay,nb->port_id);
586    
587     /* unreference NIO object */
588     netio_release(nb->nio->name);
589     free(nb);
590     }
591    
592     bay->nio_list = NULL;
593     return(0);
594     }
595    
596     /* Enable a Network IO descriptor for a Network Module */
597     int c3600_nm_enable_nio(c3600_t *router,u_int nm_bay,u_int port_id)
598     {
599     struct c3600_nio_binding *nb;
600     struct c3600_nm_bay *bay;
601    
602     if (!(bay = c3600_nm_get_info(router,nm_bay)))
603     return(-1);
604    
605     /* check that we have an NIO binding for this interface */
606     if (!(nb = c3600_nm_find_nio_binding(router,nm_bay,port_id)))
607     return(-1);
608    
609     /* check that the driver is defined and successfully initialized */
610     if (!bay->nm_driver || !bay->drv_info)
611     return(-1);
612    
613     return(bay->nm_driver->nm_set_nio(router,nm_bay,port_id,nb->nio));
614     }
615    
616     /* Disable Network IO descriptor of a Network Module */
617     int c3600_nm_disable_nio(c3600_t *router,u_int nm_bay,u_int port_id)
618     {
619     struct c3600_nm_bay *bay;
620    
621     if (!(bay = c3600_nm_get_info(router,nm_bay)))
622     return(-1);
623    
624     /* check that the driver is defined and successfully initialized */
625     if (!bay->nm_driver || !bay->drv_info)
626     return(-1);
627    
628     return(bay->nm_driver->nm_unset_nio(router,nm_bay,port_id));
629     }
630    
631     /* Enable all NIO of the specified NM */
632     int c3600_nm_enable_all_nio(c3600_t *router,u_int nm_bay)
633     {
634     struct c3600_nio_binding *nb;
635     struct c3600_nm_bay *bay;
636    
637     if (!(bay = c3600_nm_get_info(router,nm_bay)))
638     return(-1);
639    
640     /* check that the driver is defined and successfully initialized */
641     if (!bay->nm_driver || !bay->drv_info)
642     return(-1);
643    
644     for(nb=bay->nio_list;nb;nb=nb->next)
645     bay->nm_driver->nm_set_nio(router,nm_bay,nb->port_id,nb->nio);
646    
647     return(0);
648     }
649    
650     /* Disable all NIO of the specified NM */
651     int c3600_nm_disable_all_nio(c3600_t *router,u_int nm_bay)
652     {
653     struct c3600_nio_binding *nb;
654     struct c3600_nm_bay *bay;
655    
656     if (!(bay = c3600_nm_get_info(router,nm_bay)))
657     return(-1);
658    
659     /* check that the driver is defined and successfully initialized */
660     if (!bay->nm_driver || !bay->drv_info)
661     return(-1);
662    
663     for(nb=bay->nio_list;nb;nb=nb->next)
664     bay->nm_driver->nm_unset_nio(router,nm_bay,nb->port_id);
665    
666     return(0);
667     }
668    
669     /* Initialize a Network Module */
670     int c3600_nm_init(c3600_t *router,u_int nm_bay)
671     {
672     struct c3600_nm_bay *bay;
673     size_t len;
674    
675     if (!(bay = c3600_nm_get_info(router,nm_bay)))
676     return(-1);
677    
678     /* Check that a device type is defined for this bay */
679     if (!bay->dev_type || !bay->nm_driver) {
680     vm_error(router->vm,"trying to init empty slot %u.\n",nm_bay);
681     return(-1);
682     }
683    
684     /* Allocate device name */
685     len = strlen(bay->dev_type) + 10;
686     if (!(bay->dev_name = malloc(len))) {
687     vm_error(router->vm,"unable to allocate device name.\n");
688     return(-1);
689     }
690    
691     snprintf(bay->dev_name,len,"%s(%u)",bay->dev_type,nm_bay);
692    
693     /* Initialize NM driver */
694     if (bay->nm_driver->nm_init(router,bay->dev_name,nm_bay) == 1) {
695     vm_error(router->vm,"unable to initialize NM %u.\n",nm_bay);
696     return(-1);
697     }
698    
699     /* Enable all NIO */
700     c3600_nm_enable_all_nio(router,nm_bay);
701     return(0);
702     }
703    
704     /* Shutdown a Network Module */
705     int c3600_nm_shutdown(c3600_t *router,u_int nm_bay)
706     {
707     struct c3600_nm_bay *bay;
708    
709     if (!(bay = c3600_nm_get_info(router,nm_bay)))
710     return(-1);
711    
712     /* Check that a device type is defined for this bay */
713     if (!bay->dev_type || !bay->nm_driver) {
714     vm_error(router->vm,"trying to shut down empty slot %u.\n",nm_bay);
715     return(-1);
716     }
717    
718     /* Disable all NIO */
719     c3600_nm_disable_all_nio(router,nm_bay);
720    
721     /* Shutdown the NM driver */
722     if (bay->drv_info && (bay->nm_driver->nm_shutdown(router,nm_bay) == -1)) {
723     vm_error(router->vm,"unable to shutdown NM %u.\n",nm_bay);
724     return(-1);
725     }
726    
727     free(bay->dev_name);
728     bay->dev_name = NULL;
729     bay->drv_info = NULL;
730     return(0);
731     }
732    
733     /* Shutdown all NM of a router */
734     int c3600_nm_shutdown_all(c3600_t *router)
735     {
736     int i;
737    
738     for(i=0;i<C3600_MAX_NM_BAYS;i++) {
739     if (!router->nm_bay[i].dev_type)
740     continue;
741    
742     c3600_nm_shutdown(router,i);
743     }
744    
745     return(0);
746     }
747    
748     /* Maximum number of tokens in a NM description */
749     #define NM_DESC_MAX_TOKENS 8
750    
751     /* Create a Network Module (command line) */
752     int c3600_cmd_nm_create(c3600_t *router,char *str)
753     {
754     char *tokens[NM_DESC_MAX_TOKENS];
755     int i,count,res;
756     u_int nm_bay;
757    
758     /* A port adapter description is like "1:NM-1FE" */
759     if ((count = m_strsplit(str,':',tokens,NM_DESC_MAX_TOKENS)) != 2) {
760     vm_error(router->vm,"unable to parse NM description '%s'.\n",str);
761     return(-1);
762     }
763    
764     /* Parse the NM bay id */
765     nm_bay = atoi(tokens[0]);
766    
767     /* Add this new NM to the current NM list */
768     res = c3600_nm_add_binding(router,tokens[1],nm_bay);
769    
770     /* The complete array was cleaned by strsplit */
771     for(i=0;i<NM_DESC_MAX_TOKENS;i++)
772     free(tokens[i]);
773    
774     return(res);
775     }
776    
777     /* Add a Network IO descriptor binding (command line) */
778     int c3600_cmd_add_nio(c3600_t *router,char *str)
779     {
780     char *tokens[NM_DESC_MAX_TOKENS];
781     int i,count,nio_type,res=-1;
782     u_int nm_bay,port_id;
783     netio_desc_t *nio;
784     char nio_name[128];
785    
786     /* A port adapter description is like "1:3:tap:tap0" */
787     if ((count = m_strsplit(str,':',tokens,NM_DESC_MAX_TOKENS)) < 3) {
788     vm_error(router->vm,"unable to parse NIO description '%s'.\n",str);
789     return(-1);
790     }
791    
792     /* Parse the NM bay */
793     nm_bay = atoi(tokens[0]);
794    
795     /* Parse the NM port id */
796     port_id = atoi(tokens[1]);
797    
798     /* Autogenerate a NIO name */
799     snprintf(nio_name,sizeof(nio_name),"c3600-i%u/%u/%u",
800     router->vm->instance_id,nm_bay,port_id);
801    
802     /* Create the Network IO descriptor */
803     nio = NULL;
804     nio_type = netio_get_type(tokens[2]);
805    
806     switch(nio_type) {
807     case NETIO_TYPE_UNIX:
808     if (count != 5) {
809     vm_error(router->vm,
810     "invalid number of arguments for UNIX NIO '%s'\n",str);
811     goto done;
812     }
813    
814     nio = netio_desc_create_unix(nio_name,tokens[3],tokens[4]);
815     break;
816    
817     case NETIO_TYPE_VDE:
818     if (count != 5) {
819     vm_error(router->vm,
820     "invalid number of arguments for VDE NIO '%s'\n",str);
821     goto done;
822     }
823    
824     nio = netio_desc_create_vde(nio_name,tokens[3],tokens[4]);
825     break;
826    
827     case NETIO_TYPE_TAP:
828     if (count != 4) {
829     vm_error(router->vm,
830     "invalid number of arguments for TAP NIO '%s'\n",str);
831     goto done;
832     }
833    
834     nio = netio_desc_create_tap(nio_name,tokens[3]);
835     break;
836    
837     case NETIO_TYPE_UDP:
838     if (count != 6) {
839     vm_error(router->vm,
840     "invalid number of arguments for UDP NIO '%s'\n",str);
841     goto done;
842     }
843    
844     nio = netio_desc_create_udp(nio_name,atoi(tokens[3]),
845     tokens[4],atoi(tokens[5]));
846     break;
847    
848     case NETIO_TYPE_TCP_CLI:
849     if (count != 5) {
850     vm_error(router->vm,
851     "invalid number of arguments for TCP CLI NIO '%s'\n",str);
852     goto done;
853     }
854    
855     nio = netio_desc_create_tcp_cli(nio_name,tokens[3],tokens[4]);
856     break;
857    
858     case NETIO_TYPE_TCP_SER:
859     if (count != 4) {
860     vm_error(router->vm,
861     "invalid number of arguments for TCP SER NIO '%s'\n",str);
862     goto done;
863     }
864    
865     nio = netio_desc_create_tcp_ser(nio_name,tokens[3]);
866     break;
867    
868     case NETIO_TYPE_NULL:
869     nio = netio_desc_create_null(nio_name);
870     break;
871    
872     #ifdef LINUX_ETH
873     case NETIO_TYPE_LINUX_ETH:
874     if (count != 4) {
875     vm_error(router->vm,
876     "invalid number of arguments for Linux Eth NIO '%s'\n",
877     str);
878     goto done;
879     }
880    
881     nio = netio_desc_create_lnxeth(nio_name,tokens[3]);
882     break;
883     #endif
884    
885     #ifdef GEN_ETH
886     case NETIO_TYPE_GEN_ETH:
887     if (count != 4) {
888     vm_error(router->vm,
889     "invalid number of arguments for Generic Eth NIO '%s'\n",
890     str);
891     goto done;
892     }
893    
894     nio = netio_desc_create_geneth(nio_name,tokens[3]);
895     break;
896     #endif
897    
898     default:
899     vm_error(router->vm,"unknown NETIO type '%s'\n",tokens[2]);
900     goto done;
901     }
902    
903     if (!nio) {
904     vm_error(router->vm,"unable to create NETIO "
905     "descriptor for NM slot %u\n",nm_bay);
906     goto done;
907     }
908    
909     if (c3600_nm_add_nio_binding(router,nm_bay,port_id,nio_name) == -1) {
910     vm_error(router->vm,"unable to add NETIO binding for slot %u\n",nm_bay);
911     netio_release(nio_name);
912     netio_delete(nio_name);
913     goto done;
914     }
915    
916     netio_release(nio_name);
917     res = 0;
918    
919     done:
920     /* The complete array was cleaned by strsplit */
921     for(i=0;i<NM_DESC_MAX_TOKENS;i++)
922     free(tokens[i]);
923    
924     return(res);
925     }
926    
927     /* Show the list of available NM drivers */
928     void c3600_nm_show_drivers(void)
929     {
930     int i;
931    
932     printf("Available C3600 Network Module drivers:\n");
933    
934     for(i=0;nm_drivers[i];i++) {
935     printf(" * %s %s\n",
936     nm_drivers[i]->dev_type,
937     !nm_drivers[i]->supported ? "(NOT WORKING)" : "");
938     }
939    
940     printf("\n");
941     }
942    
943     /* Get a chassis driver */
944     struct c3600_chassis_driver *c3600_chassis_get_driver(char *chassis_type)
945     {
946     int i;
947    
948     for(i=0;chassis_drivers[i].chassis_type;i++)
949     if (!strcmp(chassis_drivers[i].chassis_type,chassis_type))
950     return(&chassis_drivers[i]);
951    
952     return NULL;
953     }
954    
955     /* Set the base MAC address of the chassis */
956     static int c3600_burn_mac_addr(m_uint16_t *data,size_t data_len,
957     n_eth_addr_t *addr)
958     {
959     m_uint8_t eeprom_ver;
960     size_t offset;
961    
962     /* Read EEPROM format version */
963     cisco_eeprom_get_byte(data,data_len,0,&eeprom_ver);
964    
965     switch(eeprom_ver) {
966     case 0:
967     cisco_eeprom_set_region(data,data_len,2,addr->eth_addr_byte,6);
968     break;
969    
970     case 4:
971     if (!cisco_eeprom_v4_find_field(data,data_len,0xC3,&offset)) {
972     cisco_eeprom_set_region(data,data_len,offset,
973     addr->eth_addr_byte,6);
974     }
975     break;
976    
977     default:
978     fprintf(stderr,"c3600_burn_mac_addr: unable to handle "
979     "EEPROM version %u\n",eeprom_ver);
980     return(-1);
981     }
982    
983     return(0);
984     }
985    
986     /* Set chassis MAC address */
987     int c3600_chassis_set_mac_addr(c3600_t *router,char *mac_addr)
988     {
989     if (parse_mac_addr(&router->mac_addr,mac_addr) == -1) {
990     vm_error(router->vm,"unable to parse MAC address '%s'.\n",mac_addr);
991     return(-1);
992     }
993    
994     /* Set the chassis base MAC address */
995     c3600_burn_mac_addr(router->mb_eeprom_data,sizeof(router->mb_eeprom_data),
996     &router->mac_addr);
997     return(0);
998     }
999    
1000     /* Set the chassis type */
1001     int c3600_chassis_set_type(c3600_t *router,char *chassis_type)
1002     {
1003     struct c3600_chassis_driver *driver;
1004    
1005     if (router->vm->status == VM_STATUS_RUNNING) {
1006     vm_error(router->vm,"unable to change chassis type when online.\n");
1007     return(-1);
1008     }
1009    
1010     if (!(driver = c3600_chassis_get_driver(chassis_type))) {
1011     vm_error(router->vm,"unknown chassis type '%s'.\n",chassis_type);
1012     return(-1);
1013     }
1014    
1015     router->chassis_driver = driver;
1016    
1017     /* Copy the mainboard EEPROM */
1018     memcpy(router->mb_eeprom_data,driver->mb_eeprom,driver->mb_eeprom_len << 1);
1019    
1020     /* Set the chassis base MAC address */
1021     c3600_burn_mac_addr(router->mb_eeprom_data,sizeof(router->mb_eeprom_data),
1022     &router->mac_addr);
1023    
1024     router->mb_eeprom.data = router->mb_eeprom_data;
1025     router->mb_eeprom.data_len = driver->mb_eeprom_len;
1026     return(0);
1027     }
1028    
1029     /* Get the chassis ID */
1030     int c3600_chassis_get_id(c3600_t *router)
1031     {
1032     if (router->chassis_driver)
1033     return(router->chassis_driver->chassis_id);
1034    
1035     return(-1);
1036     }
1037    
1038     /* Show the list of available chassis drivers */
1039     void c3600_chassis_show_drivers(void)
1040     {
1041     int i;
1042    
1043     printf("Available C3600 chassis drivers:\n");
1044    
1045     for(i=0;chassis_drivers[i].chassis_type;i++) {
1046     printf(" * %s %s\n",
1047     chassis_drivers[i].chassis_type,
1048     !chassis_drivers[i].supported ? "(NOT WORKING)" : "");
1049     }
1050    
1051     printf("\n");
1052     }
1053    
1054     /* Create the main PCI bus for a GT64010 based system */
1055     static int c3600_init_gt64010(c3600_t *router)
1056     {
1057     if (!(router->vm->pci_bus[0] = pci_bus_create("PCI bus",0))) {
1058     vm_error(router->vm,"unable to create PCI data.\n");
1059     return(-1);
1060     }
1061    
1062     return(dev_gt64010_init(router->vm,"gt64010",C3600_GT64K_ADDR,0x1000,
1063     C3600_GT64K_IRQ));
1064     }
1065    
1066     /* Create the two main PCI busses for a GT64120 based system */
1067     static int c3600_init_gt64120(c3600_t *router)
1068     {
1069     vm_instance_t *vm = router->vm;
1070    
1071     vm->pci_bus[0] = pci_bus_create("PCI bus #0",0);
1072     vm->pci_bus[1] = pci_bus_create("PCI bus #1",0);
1073    
1074     if (!vm->pci_bus[0] || !vm->pci_bus[1]) {
1075     vm_error(router->vm,"unable to create PCI data.\n");
1076     return(-1);
1077     }
1078    
1079     return(dev_gt64120_init(vm,"gt64120",C3600_GT64K_ADDR,0x1000,
1080     C3600_GT64K_IRQ));
1081     }
1082    
1083     /* Initialize a Cisco 3620 */
1084     static int c3620_init(c3600_t *router)
1085     {
1086     vm_instance_t *vm = router->vm;
1087     int i;
1088    
1089     /* Set the processor type: R4700 */
1090     mips64_set_prid(vm->boot_cpu,MIPS_PRID_R4700);
1091    
1092     /* Initialize the Galileo GT-64010 PCI controller */
1093     if (c3600_init_gt64010(router) == -1)
1094     return(-1);
1095    
1096     /* Initialize PCI map (no PCI bridge for this chassis) */
1097     for(i=0;i<C3600_MAX_NM_BAYS;i++)
1098     router->nm_bay[i].pci_map = vm->pci_bus[0];
1099    
1100     vm->elf_machine_id = C3620_ELF_MACHINE_ID;
1101     return(0);
1102     }
1103    
1104     /* Initialize a Cisco 3640 */
1105     static int c3640_init(c3600_t *router)
1106     {
1107     vm_instance_t *vm = router->vm;
1108     struct nm_bay_info *bay;
1109     int i;
1110    
1111     /* Set the processor type: R4700 */
1112     mips64_set_prid(vm->boot_cpu,MIPS_PRID_R4700);
1113    
1114     /* Initialize the Galileo GT-64010 PCI controller */
1115     if (c3600_init_gt64010(router) == -1)
1116     return(-1);
1117    
1118     /* Create the NM PCI busses */
1119     vm->pci_bus_pool[0] = pci_bus_create("NM Slots 0,2",-1);
1120     vm->pci_bus_pool[1] = pci_bus_create("NM Slots 1,3",-1);
1121    
1122     /* Initialize PCI map and PCI bridges */
1123     for(i=0;i<=3;i++) {
1124     bay = c3600_nm_get_bay_info(3640,i);
1125    
1126     /* Map the NM PCI bus */
1127     router->nm_bay[i].pci_map = vm->pci_bus_pool[i & 1];
1128    
1129     if (bay && (bay->pci_bridge_device != -1))
1130     dev_dec21052_init(vm->pci_bus[0],bay->pci_bridge_device,
1131     router->nm_bay[i].pci_map);
1132     }
1133    
1134     vm->elf_machine_id = C3640_ELF_MACHINE_ID;
1135     return(0);
1136     }
1137    
1138     /* Initialize a Cisco 3660 */
1139     static int c3660_init(c3600_t *router)
1140     {
1141     vm_instance_t *vm = router->vm;
1142     struct nm_bay_info *bay;
1143     char bus_name[128];
1144     int i;
1145    
1146     /* Set the processor type: R5271 */
1147     mips64_set_prid(vm->boot_cpu,MIPS_PRID_R527x);
1148    
1149     /* Initialize the Galileo GT-64120 PCI controller */
1150     if (c3600_init_gt64120(router) == -1)
1151     return(-1);
1152    
1153     /* Create the NM PCI busses */
1154     for(i=1;i<=6;i++) {
1155     snprintf(bus_name,sizeof(bus_name),"NM Slot %d",i);
1156     vm->pci_bus_pool[i] = pci_bus_create(bus_name,-1);
1157     }
1158    
1159     /* Slot 0 is mapped to the first bus of GT64120 */
1160     router->nm_bay[0].pci_map = vm->pci_bus[0];
1161    
1162     /* Initialize PCI map and PCI bridges */
1163     for(i=1;i<C3600_MAX_NM_BAYS;i++) {
1164     bay = c3600_nm_get_bay_info(3660,i);
1165    
1166     /* Map the NM PCI bus */
1167     router->nm_bay[i].pci_map = vm->pci_bus_pool[i];
1168    
1169     /* Slots 1-6 are mapped to the second bus of GT64120 */
1170     if (bay && (bay->pci_bridge_device != -1))
1171     dev_dec21152_init(vm->pci_bus[1],bay->pci_bridge_device,
1172     router->nm_bay[i].pci_map);
1173     }
1174    
1175     /* The motherboard has 2 integrated FastEthernet ports */
1176     c3600_nm_add_binding(router,"Leopard-2FE",0);
1177    
1178     vm->elf_machine_id = C3640_ELF_MACHINE_ID;
1179     return(0);
1180     }
1181    
1182     /* Show C3600 hardware info */
1183     void c3600_show_hardware(c3600_t *router)
1184     {
1185     vm_instance_t *vm = router->vm;
1186    
1187     printf("C3600 instance '%s' (id %d):\n",vm->name,vm->instance_id);
1188    
1189     printf(" VM Status : %d\n",vm->status);
1190     printf(" RAM size : %u Mb\n",vm->ram_size);
1191     printf(" NVRAM size : %u Kb\n",vm->nvram_size);
1192     printf(" Chassis : %s\n",router->chassis_driver->chassis_type);
1193     printf(" IOS image : %s\n\n",vm->ios_image);
1194    
1195     if (vm->debug_level > 0) {
1196     dev_show_list(vm);
1197     pci_dev_show_list(vm->pci_bus[0]);
1198     pci_dev_show_list(vm->pci_bus[1]);
1199     printf("\n");
1200     }
1201     }
1202    
1203     /* Initialize default parameters for a C3600 */
1204     void c3600_init_defaults(c3600_t *router)
1205     {
1206     vm_instance_t *vm = router->vm;
1207     n_eth_addr_t *m;
1208     m_uint16_t pid;
1209    
1210     pid = (m_uint16_t)getpid();
1211    
1212     /* Generate a chassis MAC address based on the instance ID */
1213     m = &router->mac_addr;
1214     m->eth_addr_byte[0] = 0xCC;
1215     m->eth_addr_byte[1] = vm->instance_id & 0xFF;
1216     m->eth_addr_byte[2] = pid >> 8;
1217     m->eth_addr_byte[3] = pid & 0xFF;
1218     m->eth_addr_byte[4] = 0x00;
1219     m->eth_addr_byte[5] = 0x00;
1220    
1221     c3600_init_eeprom_groups(router);
1222     c3600_chassis_set_type(router,C3600_DEFAULT_CHASSIS);
1223    
1224     vm->ram_mmap = C3600_DEFAULT_RAM_MMAP;
1225     vm->ram_size = C3600_DEFAULT_RAM_SIZE;
1226     vm->rom_size = C3600_DEFAULT_ROM_SIZE;
1227     vm->nvram_size = C3600_DEFAULT_NVRAM_SIZE;
1228     vm->conf_reg = C3600_DEFAULT_CONF_REG;
1229     vm->clock_divisor = C3600_DEFAULT_CLOCK_DIV;
1230     vm->nvram_rom_space = C3600_NVRAM_ROM_RES_SIZE;
1231     router->nm_iomem_size = C3600_DEFAULT_IOMEM_SIZE;
1232    
1233     vm->pcmcia_disk_size[0] = C3600_DEFAULT_DISK0_SIZE;
1234     vm->pcmcia_disk_size[1] = C3600_DEFAULT_DISK1_SIZE;
1235     }
1236    
1237     /* Initialize the C3600 Platform */
1238     int c3600_init_platform(c3600_t *router)
1239     {
1240     vm_instance_t *vm = router->vm;
1241     struct c3600_nm_bay *nm_bay;
1242     cpu_mips_t *cpu;
1243     int i;
1244    
1245     /* Copy config register setup into "active" config register */
1246     vm->conf_reg = vm->conf_reg_setup;
1247    
1248     /* Create Console and AUX ports */
1249     vm_init_vtty(vm);
1250    
1251     /* Create a CPU group */
1252     vm->cpu_group = cpu_group_create("System CPU");
1253    
1254     /* Initialize the virtual MIPS processor */
1255     if (!(cpu = cpu_create(vm,0))) {
1256     vm_error(vm,"unable to create CPU!\n");
1257     return(-1);
1258     }
1259    
1260     /* Add this CPU to the system CPU group */
1261     cpu_group_add(vm->cpu_group,cpu);
1262     vm->boot_cpu = cpu;
1263    
1264     /* Mark the Network IO interrupt as high priority */
1265     cpu->irq_idle_preempt[C3600_NETIO_IRQ] = TRUE;
1266     cpu->irq_idle_preempt[C3600_DUART_IRQ] = TRUE;
1267    
1268     /* Copy some parameters from VM to CPU (idle PC, ...) */
1269     cpu->idle_pc = vm->idle_pc;
1270    
1271     if (vm->timer_irq_check_itv)
1272     cpu->timer_irq_check_itv = vm->timer_irq_check_itv;
1273    
1274     /* Get chassis specific driver */
1275     if (!router->chassis_driver) {
1276     vm_error(vm,"no chassis defined.\n");
1277     return(-1);
1278     }
1279    
1280     /* Remote emulator control */
1281     dev_remote_control_init(vm,0x16000000,0x1000);
1282    
1283     /* Bootflash */
1284     dev_bootflash_init(vm,"bootflash",C3600_BOOTFLASH_ADDR,(8 * 1048576));
1285    
1286     /* NVRAM and calendar */
1287     dev_nvram_init(vm,"nvram",
1288     C3600_NVRAM_ADDR,vm->nvram_size*1024,&vm->conf_reg);
1289    
1290     /* Bit-bucket zone */
1291     dev_zero_init(vm,"zero",C3600_BITBUCKET_ADDR,0xc00000);
1292    
1293     /* IO FPGA */
1294     if (dev_c3600_iofpga_init(router,C3600_IOFPGA_ADDR,0x40000) == -1)
1295     return(-1);
1296    
1297     /* PCI IO space */
1298     if (!(vm->pci_io_space = pci_io_data_init(vm,C3600_PCI_IO_ADDR)))
1299     return(-1);
1300    
1301     /* Initialize the chassis */
1302     if (router->chassis_driver->chassis_init(router) == -1)
1303     return(-1);
1304    
1305     /* Initialize RAM */
1306     dev_ram_init(vm,"ram",vm->ram_mmap,0x00000000ULL,vm->ram_size*1048576);
1307    
1308     /* Initialize ROM */
1309     if (!vm->rom_filename) {
1310     /* use embedded ROM */
1311     dev_rom_init(vm,"rom",C3600_ROM_ADDR,vm->rom_size*1048576);
1312     } else {
1313     /* use alternate ROM */
1314     dev_ram_init(vm,"rom",TRUE,C3600_ROM_ADDR,vm->rom_size*1048576);
1315     }
1316    
1317     /* Initialize the NS16552 DUART */
1318     dev_ns16552_init(vm,C3600_DUART_ADDR,0x1000,C3600_DUART_IRQ,
1319     vm->vtty_con,vm->vtty_aux);
1320    
1321     /* Cirrus Logic PD6729 (PCI-to-PCMCIA host adapter) */
1322     dev_clpd6729_init(vm,vm->pci_bus[0],20,vm->pci_io_space,0x4402,0x4403);
1323    
1324     /* Initialize Network Modules */
1325     for(i=0;i<C3600_MAX_NM_BAYS;i++) {
1326     nm_bay = &router->nm_bay[i];
1327    
1328     if (!nm_bay->dev_type)
1329     continue;
1330    
1331     if (c3600_nm_init(router,i) == -1) {
1332     vm_error(vm,"unable to create Network Module \"%s\"\n",
1333     nm_bay->dev_type);
1334     return(-1);
1335     }
1336     }
1337    
1338     /* Enable NVRAM operations to load/store configs */
1339     vm->nvram_extract_config = c3600_nvram_extract_config;
1340     vm->nvram_push_config = c3600_nvram_push_config;
1341    
1342     /* Show device list */
1343     c3600_show_hardware(router);
1344     return(0);
1345     }
1346    
1347     /* Boot the IOS image */
1348     int c3600_boot_ios(c3600_t *router)
1349     {
1350     vm_instance_t *vm = router->vm;
1351    
1352     if (!vm->boot_cpu)
1353     return(-1);
1354    
1355     /* Suspend CPU activity since we will restart directly from ROM */
1356     vm_suspend(vm);
1357    
1358     /* Check that CPU activity is really suspended */
1359     if (cpu_group_sync_state(vm->cpu_group) == -1) {
1360     vm_error(vm,"unable to sync with system CPUs.\n");
1361     return(-1);
1362     }
1363    
1364     /* Reset the boot CPU */
1365     mips64_reset(vm->boot_cpu);
1366    
1367     /* Load IOS image */
1368     if (mips64_load_elf_image(vm->boot_cpu,vm->ios_image,
1369     &vm->ios_entry_point) < 0)
1370     {
1371     vm_error(vm,"failed to load Cisco IOS image '%s'.\n",vm->ios_image);
1372     return(-1);
1373     }
1374    
1375     /* Launch the simulation */
1376     printf("\nC3600 '%s': starting simulation (CPU0 PC=0x%llx), "
1377     "JIT %sabled.\n",
1378     vm->name,vm->boot_cpu->pc,vm->jit_use ? "en":"dis");
1379    
1380     vm_log(vm,"C3600_BOOT",
1381     "starting instance (CPU0 PC=0x%llx,idle_pc=0x%llx,JIT %s)\n",
1382     vm->boot_cpu->pc,vm->boot_cpu->idle_pc,vm->jit_use ? "on":"off");
1383    
1384     /* Start main CPU */
1385     vm->status = VM_STATUS_RUNNING;
1386     cpu_start(vm->boot_cpu);
1387     return(0);
1388     }
1389    
1390     /* Initialize a Cisco 3600 instance */
1391     int c3600_init_instance(c3600_t *router)
1392     {
1393     vm_instance_t *vm = router->vm;
1394     m_uint32_t rom_entry_point;
1395     cpu_mips_t *cpu0;
1396    
1397     if (!vm->ios_image) {
1398     vm_error(vm,"no Cisco IOS image defined.");
1399     return(-1);
1400     }
1401    
1402     /* Initialize the C3600 platform */
1403     if (c3600_init_platform(router) == -1) {
1404     vm_error(vm,"unable to initialize the platform hardware.\n");
1405     return(-1);
1406     }
1407    
1408     /* Load IOS configuration file */
1409     if (vm->ios_config != NULL) {
1410     vm_nvram_push_config(vm,vm->ios_config);
1411     vm->conf_reg &= ~0x40;
1412     }
1413    
1414     /* Load ROM (ELF image or embedded) */
1415     cpu0 = vm->boot_cpu;
1416     rom_entry_point = (m_uint32_t)MIPS_ROM_PC;
1417    
1418     if ((vm->rom_filename != NULL) &&
1419     (mips64_load_elf_image(cpu0,vm->rom_filename,&rom_entry_point) < 0))
1420     {
1421     vm_error(vm,"unable to load alternate ROM '%s', "
1422     "fallback to embedded ROM.\n\n",vm->rom_filename);
1423     vm->rom_filename = NULL;
1424     }
1425    
1426     /* Load symbol file */
1427     if (vm->sym_filename) {
1428     mips64_sym_load_file(cpu0,vm->sym_filename);
1429     cpu0->sym_trace = 1;
1430     }
1431    
1432     return(c3600_boot_ios(router));
1433     }
1434    
1435     /* Stop a Cisco 3600 instance */
1436     int c3600_stop_instance(c3600_t *router)
1437     {
1438     vm_instance_t *vm = router->vm;
1439    
1440     printf("\nC3600 '%s': stopping simulation.\n",vm->name);
1441     vm_log(vm,"C3600_STOP","stopping simulation.\n");
1442    
1443     /* Stop all CPUs */
1444     if (vm->cpu_group != NULL) {
1445     vm_stop(vm);
1446    
1447     if (cpu_group_sync_state(vm->cpu_group) == -1) {
1448     vm_error(vm,"unable to sync with system CPUs.\n");
1449     return(-1);
1450     }
1451     }
1452    
1453     /* Free resources that were used during execution to emulate hardware */
1454     c3600_nm_shutdown_all(router);
1455     vm_hardware_shutdown(vm);
1456     return(0);
1457     }

  ViewVC Help
Powered by ViewVC 1.1.26