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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (hide annotations)
Sat Oct 6 16:05:34 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 40212 byte(s)
dynamips-0.2.6-RC2

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

  ViewVC Help
Powered by ViewVC 1.1.26