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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (hide annotations)
Sat Oct 6 16:03:58 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 40329 byte(s)
import dynamips-0.2.6-RC1

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

  ViewVC Help
Powered by ViewVC 1.1.26