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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (hide annotations)
Sat Oct 6 16:06:49 2007 UTC (14 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 35419 byte(s)
dynamips-0.2.6-RC3

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

  ViewVC Help
Powered by ViewVC 1.1.26