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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26