/[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

Diff of /trunk/dev_c3600.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

upstream/dynamips-0.2.6-RC1/dev_c3600.c revision 2 by dpavlin, Sat Oct 6 16:03:58 2007 UTC upstream/dynamips-0.2.8-RC1/dev_c3600.c revision 11 by dpavlin, Sat Oct 6 16:33:40 2007 UTC
# Line 12  Line 12 
12  #include <sys/types.h>  #include <sys/types.h>
13  #include <assert.h>  #include <assert.h>
14    
15  #include "mips64.h"  #include "cpu.h"
16  #include "dynamips.h"  #include "dynamips.h"
17  #include "memory.h"  #include "memory.h"
18  #include "device.h"  #include "device.h"
19  #include "pci_io.h"  #include "pci_io.h"
20    #include "dev_gt.h"
21  #include "cisco_eeprom.h"  #include "cisco_eeprom.h"
22    #include "dev_rom.h"
23  #include "dev_c3600.h"  #include "dev_c3600.h"
24    #include "dev_c3600_iofpga.h"
25  #include "dev_c3600_bay.h"  #include "dev_c3600_bay.h"
26  #include "dev_vtty.h"  #include "dev_vtty.h"
27  #include "registry.h"  #include "registry.h"
# Line 28  Line 31 
31  /* ======================================================================== */  /* ======================================================================== */
32    
33  /* Cisco 3620 mainboard EEPROM */  /* Cisco 3620 mainboard EEPROM */
34  static m_uint16_t eeprom_c3620_mainboard[64] = {  static m_uint16_t eeprom_c3620_mainboard_data[64] = {
35     0x0001, 0x0000, 0x0000, 0x0000, 0x0AFF, 0x7318, 0x5011, 0x0020,     0x0001, 0x0000, 0x0000, 0x0000, 0x0AFF, 0x7318, 0x5011, 0x0020,
36     0x0000, 0x0000, 0xA0FF, 0x9904, 0x19FF, 0xFFFF, 0xFFFF, 0x0002,     0x0000, 0x0000, 0xA0FF, 0x9904, 0x19FF, 0xFFFF, 0xFFFF, 0x0002,
37     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
# Line 39  static m_uint16_t eeprom_c3620_mainboard Line 42  static m_uint16_t eeprom_c3620_mainboard
42     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
43  };  };
44    
45    struct cisco_eeprom eeprom_c3620_mainboard = {
46       "C3620 Mainboard",
47       eeprom_c3620_mainboard_data,
48       sizeof(eeprom_c3620_mainboard_data)/2,
49    };
50    
51  /* Cisco 3640 mainboard EEPROM */  /* Cisco 3640 mainboard EEPROM */
52  static m_uint16_t eeprom_c3640_mainboard[64] = {  static m_uint16_t eeprom_c3640_mainboard_data[64] = {
53     0x0001, 0x0000, 0x0000, 0x0000, 0x0AFF, 0x7316, 0x8514, 0x0040,     0x0001, 0x0000, 0x0000, 0x0000, 0x0AFF, 0x7316, 0x8514, 0x0040,
54     0x0000, 0x0000, 0xA1FF, 0x0102, 0x22FF, 0xFFFF, 0xFFFF, 0x0002,     0x0000, 0x0000, 0xA1FF, 0x0102, 0x22FF, 0xFFFF, 0xFFFF, 0x0002,
55     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
# Line 51  static m_uint16_t eeprom_c3640_mainboard Line 60  static m_uint16_t eeprom_c3640_mainboard
60     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
61  };  };
62    
63    struct cisco_eeprom eeprom_c3640_mainboard = {
64       "C3640 Mainboard",
65       eeprom_c3640_mainboard_data,
66       sizeof(eeprom_c3640_mainboard_data)/2,
67    };
68    
69  /* Cisco 3660 backplane EEPROM */  /* Cisco 3660 backplane EEPROM */
70  static m_uint16_t eeprom_c3660_backplane[64] = {  static m_uint16_t eeprom_c3660_backplane_data[64] = {
71     0x04FF, 0x4000, 0xC841, 0x0100, 0xC046, 0x0320, 0x0012, 0x8402,     0x04FF, 0x4000, 0xC841, 0x0100, 0xC046, 0x0320, 0x0012, 0x8402,
72     0x4243, 0x3080, 0x0000, 0x0000, 0x0202, 0xC18B, 0x4841, 0x4430,     0x4243, 0x3080, 0x0000, 0x0000, 0x0202, 0xC18B, 0x4841, 0x4430,
73     0x3434, 0x3431, 0x3135, 0x4A03, 0x0081, 0x0000, 0x0000, 0x0400,     0x3434, 0x3431, 0x3135, 0x4A03, 0x0081, 0x0000, 0x0000, 0x0400,
# Line 63  static m_uint16_t eeprom_c3660_backplane Line 78  static m_uint16_t eeprom_c3660_backplane
78     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
79  };  };
80    
81    struct cisco_eeprom eeprom_c3660_backplane = {
82       "C3660 Backplane",
83       eeprom_c3660_backplane_data,
84       sizeof(eeprom_c3660_backplane_data)/2,
85    };
86    
87  /* ======================================================================== */  /* ======================================================================== */
88  /* Chassis Drivers                                                          */  /* Chassis Drivers                                                          */
89  /* ======================================================================== */  /* ======================================================================== */
# Line 71  static int c3640_init(c3600_t *router); Line 92  static int c3640_init(c3600_t *router);
92  static int c3660_init(c3600_t *router);  static int c3660_init(c3600_t *router);
93    
94  static struct c3600_chassis_driver chassis_drivers[] = {  static struct c3600_chassis_driver chassis_drivers[] = {
95     { "3620"  , 3620, 1, c3620_init,     { "3620"  , 3620, 1, c3620_init, &eeprom_c3620_mainboard },
96       eeprom_c3620_mainboard, sizeof(eeprom_c3620_mainboard)/2 },     { "3640"  , 3640, 1, c3640_init, &eeprom_c3640_mainboard },
97     { "3640"  , 3640, 1, c3640_init,     { "3660"  , 3660, 1, c3660_init, &eeprom_c3660_backplane },
98       eeprom_c3640_mainboard, sizeof(eeprom_c3640_mainboard)/2 },     { NULL    , -1,   0, NULL,       NULL },
    { "3660"  , 3660, 1, c3660_init,  
      eeprom_c3660_backplane, sizeof(eeprom_c3660_backplane)/2 },  
   
    { NULL    , -1, 0, NULL },  
99  };  };
100    
101  /* ======================================================================== */  /* ======================================================================== */
102  /* Network Module Drivers                                                   */  /* Network Module Drivers                                                   */
103  /* ======================================================================== */  /* ======================================================================== */
104  static struct c3600_nm_driver *nm_drivers[] = {  static struct cisco_card_driver *nm_drivers[] = {
105     &dev_c3600_nm_1e_driver,     &dev_c3600_nm_1e_driver,
106     &dev_c3600_nm_4e_driver,     &dev_c3600_nm_4e_driver,
107     &dev_c3600_nm_1fe_tx_driver,     &dev_c3600_nm_1fe_tx_driver,
# Line 98  static struct c3600_nm_driver *nm_driver Line 115  static struct c3600_nm_driver *nm_driver
115  /* Cisco 3600 router instances                                              */  /* Cisco 3600 router instances                                              */
116  /* ======================================================================== */  /* ======================================================================== */
117    
118    /* Initialize default parameters for a C3600 */
119    static void c3600_init_defaults(c3600_t *router);
120    
121  /* Directly extract the configuration from the NVRAM device */  /* Directly extract the configuration from the NVRAM device */
122  ssize_t c3600_nvram_extract_config(vm_instance_t *vm,char **buffer)  static ssize_t c3600_nvram_extract_config(vm_instance_t *vm,u_char **buffer)
123  {    {
124       u_char *base_ptr,*ios_ptr,*cfg_ptr,*end_ptr;
125       m_uint32_t start,nvlen;
126       m_uint16_t magic1,magic2;
127     struct vdevice *nvram_dev;     struct vdevice *nvram_dev;
128     m_uint32_t start,end,clen,nvlen;     off_t nvram_size;
129     m_uint16_t magic1,magic2;     int fd;
130     m_uint64_t addr;  
131       if ((nvram_dev = dev_get_by_name(vm,"nvram")))
132          dev_sync(nvram_dev);
133    
134       fd = vm_mmap_open_file(vm,"nvram",&base_ptr,&nvram_size);
135    
136     if (!(nvram_dev = dev_get_by_name(vm,"nvram")))     if (fd == -1)
137        return(-1);        return(-1);
138    
139     addr = nvram_dev->phys_addr + vm->nvram_rom_space;     ios_ptr = base_ptr + vm->nvram_rom_space;
140     magic1 = physmem_copy_u16_from_vm(vm,addr+0x06);     end_ptr = base_ptr + nvram_size;
141     magic2 = physmem_copy_u16_from_vm(vm,addr+0x08);  
142       if ((ios_ptr + 0x30) >= end_ptr) {
143          vm_error(vm,"NVRAM file too small\n");
144          return(-1);
145       }
146    
147       magic1  = ntohs(*PTR_ADJUST(m_uint16_t *,ios_ptr,0x06));
148       magic2  = ntohs(*PTR_ADJUST(m_uint16_t *,ios_ptr,0x08));
149    
150     if ((magic1 != 0xF0A5) || (magic2 != 0xABCD)) {     if ((magic1 != 0xF0A5) || (magic2 != 0xABCD)) {
151        vm_error(vm,"unable to find IOS magic numbers (0x%x,0x%x)!\n",        vm_error(vm,"unable to find IOS magic numbers (0x%x,0x%x)!\n",
# Line 119  ssize_t c3600_nvram_extract_config(vm_in Line 153  ssize_t c3600_nvram_extract_config(vm_in
153        return(-1);        return(-1);
154     }     }
155    
156     start = physmem_copy_u32_from_vm(vm,addr+0x10) + 1;     start = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x10)) + 1;
157     end   = physmem_copy_u32_from_vm(vm,addr+0x14);     nvlen = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x18));
    nvlen = physmem_copy_u32_from_vm(vm,addr+0x18);  
    clen  = end - start;  
158    
159     if ((clen + 1) != nvlen) {     if (!(*buffer = malloc(nvlen+1))) {
160        vm_error(vm,"invalid configuration size (0x%x)\n",nvlen);        vm_error(vm,"unable to allocate config buffer (%u bytes)\n",nvlen);
161        return(-1);        return(-1);
162     }     }
163    
164     if (!(*buffer = malloc(clen+1))) {     cfg_ptr = ios_ptr + start + 0x08;
165        vm_error(vm,"unable to allocate config buffer (%u bytes)\n",clen);  
166       if ((cfg_ptr + nvlen) > end_ptr) {
167          vm_error(vm,"NVRAM file too small\n");
168        return(-1);        return(-1);
169     }     }
170    
171     physmem_copy_from_vm(vm,*buffer,addr+start+0x08,clen);     memcpy(*buffer,cfg_ptr,nvlen-1);
172     (*buffer)[clen] = 0;     (*buffer)[nvlen-1] = 0;
173     return(clen);     return(nvlen-1);
174  }  }
175    
176  /* Directly push the IOS configuration to the NVRAM device */  /* Directly push the IOS configuration to the NVRAM device */
177  int c3600_nvram_push_config(vm_instance_t *vm,char *buffer,size_t len)  static int c3600_nvram_push_config(vm_instance_t *vm,u_char *buffer,size_t len)
178  {  {
179     struct vdevice *nvram_dev;     u_char *base_ptr,*ios_ptr,*cfg_ptr;
180     m_uint64_t addr,cfg_addr;     m_uint32_t cfg_offset,cklen,tmp;
    m_uint32_t tmp,cfg_offset;  
    m_uint32_t cklen;  
181     m_uint16_t cksum;     m_uint16_t cksum;
182       int fd;
183    
184     if (!(nvram_dev = dev_get_by_name(vm,"nvram")))     fd = vm_mmap_create_file(vm,"nvram",vm->nvram_size*1024,&base_ptr);
185    
186       if (fd == -1)
187        return(-1);        return(-1);
188    
    addr = nvram_dev->phys_addr + vm->nvram_rom_space;  
189     cfg_offset = 0x2c;     cfg_offset = 0x2c;
190     cfg_addr   = addr + cfg_offset;     ios_ptr = base_ptr + vm->nvram_rom_space;
191       cfg_ptr = ios_ptr  + cfg_offset;
192    
193     /* Write IOS tag, uncompressed config... */     /* Write IOS tag, uncompressed config... */
194     physmem_copy_u16_to_vm(vm,addr+0x06,0xF0A5);     *PTR_ADJUST(m_uint16_t *,ios_ptr,0x06) = htons(0xF0A5);
195     physmem_copy_u16_to_vm(vm,addr+0x08,0xABCD);      /* Magic number */     *PTR_ADJUST(m_uint16_t *,ios_ptr,0x08) = htons(0xABCD);
196     physmem_copy_u16_to_vm(vm,addr+0x0a,0x0001);      /* ??? */     *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0a) = htons(0x0001);
197     physmem_copy_u16_to_vm(vm,addr+0x0c,0x0000);      /* Checksum */     *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0c) = htons(0x0000);
198     physmem_copy_u16_to_vm(vm,addr+0x0e,0x0c04);      /* IOS version */     *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0e) = htons(0x0c04);
199    
200     /* Store file contents to NVRAM */     /* Store file contents to NVRAM */
201     physmem_copy_to_vm(vm,buffer,cfg_addr,len);     memcpy(cfg_ptr,buffer,len);
202    
203     /* Write config addresses + size */     /* Write config addresses + size */
204     tmp = cfg_addr - addr - 0x08;     tmp = cfg_offset - 0x08;
205    
206     physmem_copy_u32_to_vm(vm,addr+0x10,tmp);     *PTR_ADJUST(m_uint32_t *,ios_ptr,0x10) = htonl(tmp);
207     physmem_copy_u32_to_vm(vm,addr+0x14,tmp + len);     *PTR_ADJUST(m_uint32_t *,ios_ptr,0x14) = htonl(tmp + len);
208     physmem_copy_u32_to_vm(vm,addr+0x18,len);     *PTR_ADJUST(m_uint32_t *,ios_ptr,0x18) = htonl(len);
209    
210     /* Compute the checksum */     /* Compute the checksum */
211     cklen = nvram_dev->phys_len - (vm->nvram_rom_space + 0x08);     cklen = (vm->nvram_size*1024) - (vm->nvram_rom_space + 0x08);
212     cksum = nvram_cksum(vm,addr+0x08,cklen);     cksum = nvram_cksum((m_uint16_t *)(ios_ptr+0x08),cklen);
213     physmem_copy_u16_to_vm(vm,addr+0x0c,cksum);     *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0c) = htons(cksum);
214    
215       vm_mmap_close_file(fd,base_ptr,vm->nvram_size*1024);
216     return(0);     return(0);
217  }  }
218    
219  /* Create a new router instance */  /* Create a new router instance */
220  c3600_t *c3600_create_instance(char *name,int instance_id)  static int c3600_create_instance(vm_instance_t *vm)
221  {  {
222     c3600_t *router;     c3600_t *router;
223    
224     if (!(router = malloc(sizeof(*router)))) {     if (!(router = malloc(sizeof(*router)))) {
225        fprintf(stderr,"C3600 '%s': Unable to create new instance!\n",name);        fprintf(stderr,"C3600 '%s': Unable to create new instance!\n",vm->name);
226        return NULL;        return(-1);
227     }     }
228    
229     memset(router,0,sizeof(*router));     memset(router,0,sizeof(*router));
230       router->vm = vm;
231     if (!(router->vm = vm_create(name,instance_id,VM_TYPE_C3600))) {     vm->hw_data = router;
       fprintf(stderr,"C3600 '%s': unable to create VM instance!\n",name);  
       goto err_vm;  
    }  
232    
233     c3600_init_defaults(router);     c3600_init_defaults(router);
234     router->vm->hw_data = router;     return(0);
    return router;  
   
  err_vm:  
    free(router);  
    return NULL;  
235  }  }
236    
237  /* Free resources used by a router instance */  /* Free resources used by a router instance */
238  static int c3600_free_instance(void *data,void *arg)  static int c3600_delete_instance(vm_instance_t *vm)
239  {  {
240     vm_instance_t *vm = data;     c3600_t *router = VM_C3600(vm);
    c3600_t *router;  
241     int i;     int i;
242    
243     if (vm->type == VM_TYPE_C3600) {     /* Stop all CPUs */
244        router = VM_C3600(vm);     if (vm->cpu_group != NULL) {
245          vm_stop(vm);
       /* Stop all CPUs */  
       if (vm->cpu_group != NULL) {  
          vm_stop(vm);  
246                
247           if (cpu_group_sync_state(vm->cpu_group) == -1) {        if (cpu_group_sync_state(vm->cpu_group) == -1) {
248              vm_error(vm,"unable to sync with system CPUs.\n");           vm_error(vm,"unable to sync with system CPUs.\n");
249              return(FALSE);           return(FALSE);
          }  
250        }        }
   
       /* Remove NIO bindings */  
       for(i=0;i<C3600_MAX_NM_BAYS;i++)  
          c3600_nm_remove_all_nio_bindings(router,i);  
   
       /* Shutdown all Network Modules */  
       c3600_nm_shutdown_all(router);  
   
       /* Free all resources used by VM */  
       vm_free(vm);  
   
       /* Free the router structure */  
       free(router);  
       return(TRUE);  
251     }     }
252    
253     return(FALSE);     /* Remove NIO bindings */
254  }     for(i=0;i<vm->nr_slots;i++)
255          vm_slot_remove_all_nio_bindings(vm,i);
 /* Delete a router instance */  
 int c3600_delete_instance(char *name)  
 {  
    return(registry_delete_if_unused(name,OBJ_TYPE_VM,  
                                     c3600_free_instance,NULL));  
 }  
   
 /* Delete all router instances */  
 int c3600_delete_all_instances(void)  
 {  
    return(registry_delete_type(OBJ_TYPE_VM,c3600_free_instance,NULL));  
 }  
   
 /* Save configuration of a C3600 instance */  
 void c3600_save_config(c3600_t *router,FILE *fd)  
 {  
    vm_instance_t *vm = router->vm;  
    struct c3600_nio_binding *nb;  
    struct c3600_nm_bay *bay;  
    int i;  
   
    /* General settings */  
    fprintf(fd,"c3600 create %s %u\n",vm->name,vm->instance_id);  
256    
257     fprintf(fd,"c3600 set_chassis %s %s\n",     /* Shutdown all Network Modules */
258             vm->name,router->chassis_driver->chassis_type);     vm_slot_shutdown_all(vm);
259    
260     /* VM configuration */     /* Free mainboard EEPROM */
261     vm_save_config(vm,fd);     cisco_eeprom_free(&router->mb_eeprom);
262    
263     /* Network Module settings */     /* Free all resources used by VM */
264     for(i=0;i<C3600_MAX_NM_BAYS;i++) {     vm_free(vm);
       if (!(bay = c3600_nm_get_info(router,i)))  
          continue;  
   
       if (bay->dev_type) {  
          fprintf(fd,"c3600 add_nm_binding %s %u %s\n",  
                  vm->name,i,bay->dev_type);  
       }  
265    
266        for(nb=bay->nio_list;nb;nb=nb->next) {     /* Free the router structure */
267           fprintf(fd,"c3600 add_nio_binding %s %u %u %s\n",     free(router);
268                   vm->name,i,nb->port_id,nb->nio->name);     return(TRUE);
       }  
    }  
   
    fprintf(fd,"\n");  
269  }  }
270    
271  /* Save configurations of all C3600 instances */  /* Save configuration of a C3600 instance */
272  static void c3600_reg_save_config(registry_entry_t *entry,void *opt,int *err)  static void c3600_save_config(vm_instance_t *vm,FILE *fd)
273  {  {
    vm_instance_t *vm = entry->data;  
274     c3600_t *router = VM_C3600(vm);     c3600_t *router = VM_C3600(vm);
275    
276     if (vm->type == VM_TYPE_C3600)     fprintf(fd,"c3600 set_chassis %s %s\n\n",
277        c3600_save_config(router,(FILE *)opt);             vm->name,router->chassis_driver->chassis_type);
 }  
   
 void c3600_save_config_all(FILE *fd)  
 {  
    registry_foreach_type(OBJ_TYPE_VM,c3600_reg_save_config,fd,NULL);  
 }  
   
 /* Set NM EEPROM definition */  
 int c3600_nm_set_eeprom(c3600_t *router,u_int nm_bay,  
                         const struct c3600_eeprom *eeprom)  
 {  
    if (nm_bay >= C3600_MAX_NM_BAYS) {  
       vm_error(router->vm,"c3600_nm_set_eeprom: invalid NM Bay %u.\n",nm_bay);  
       return(-1);  
    }  
     
    /* 3620/3640 */  
    router->nm_bay[nm_bay].eeprom_data = eeprom->data;  
    router->nm_bay[nm_bay].eeprom_data_len = eeprom->len;  
   
    /* 3660 */  
    router->c3660_nm_eeprom_def[nm_bay].data = eeprom->data;  
    router->c3660_nm_eeprom_def[nm_bay].data_len = eeprom->len;  
    return(0);  
 }  
   
 /* Unset NM EEPROM definition (empty bay) */  
 int c3600_nm_unset_eeprom(c3600_t *router,u_int nm_bay)  
 {  
    if (nm_bay >= C3600_MAX_NM_BAYS) {  
       vm_error(router->vm,"c3600_nm_set_eeprom: invalid NM Bay %u.\n",nm_bay);  
       return(-1);  
    }  
     
    /* 3620/3640 */  
    router->nm_bay[nm_bay].eeprom_data = NULL;  
    router->nm_bay[nm_bay].eeprom_data_len = 0;  
   
    /* 3660 */  
    router->c3660_nm_eeprom_def[nm_bay].data = NULL;  
    router->c3660_nm_eeprom_def[nm_bay].data_len = 0;  
    return(0);  
 }  
   
 /* Check if a bay has a port adapter */  
 int c3600_nm_check_eeprom(c3600_t *router,u_int nm_bay)  
 {  
    if (nm_bay >= C3600_MAX_NM_BAYS)  
       return(FALSE);  
   
    return((router->nm_bay[nm_bay].eeprom_data != NULL) ? TRUE : FALSE);  
 }  
   
 /* Get bay info */  
 struct c3600_nm_bay *c3600_nm_get_info(c3600_t *router,u_int nm_bay)  
 {  
    if (nm_bay >= C3600_MAX_NM_BAYS)  
       return NULL;  
   
    return(&router->nm_bay[nm_bay]);  
 }  
   
 /* Get NM type */  
 char *c3600_nm_get_type(c3600_t *router,u_int nm_bay)  
 {  
    struct c3600_nm_bay *bay;  
   
    bay = c3600_nm_get_info(router,nm_bay);  
    return((bay != NULL) ? bay->dev_type : NULL);  
 }  
   
 /* Get driver info about the specified slot */  
 void *c3600_nm_get_drvinfo(c3600_t *router,u_int nm_bay)  
 {  
    struct c3600_nm_bay *bay;  
   
    bay = c3600_nm_get_info(router,nm_bay);  
    return((bay != NULL) ? bay->drv_info : NULL);  
 }  
   
 /* Set driver info for the specified slot */  
 int c3600_nm_set_drvinfo(c3600_t *router,u_int nm_bay,void *drv_info)  
 {  
    struct c3600_nm_bay *bay;  
   
    if (!(bay = c3600_nm_get_info(router,nm_bay)))  
       return(-1);  
   
    bay->drv_info = drv_info;  
    return(0);  
 }  
   
 /* Get a NM driver */  
 static struct c3600_nm_driver *c3600_nm_get_driver(char *dev_type)  
 {  
    int i;  
   
    for(i=0;nm_drivers[i];i++)  
       if (!strcmp(nm_drivers[i]->dev_type,dev_type))  
          return nm_drivers[i];  
   
    return NULL;  
 }  
   
 /* Add a NM binding */  
 int c3600_nm_add_binding(c3600_t *router,char *dev_type,u_int nm_bay)  
 {    
    struct c3600_nm_driver *nm_driver;  
    struct c3600_nm_bay *bay;  
   
    if (!(bay = c3600_nm_get_info(router,nm_bay)))  
       return(-1);  
   
    /* check that this bay is empty */  
    if (bay->dev_type != NULL) {  
       vm_error(router->vm,"a NM already exists in slot %u.\n",nm_bay);  
       return(-1);  
    }  
   
    /* find the NM driver */  
    if (!(nm_driver = c3600_nm_get_driver(dev_type))) {  
       vm_error(router->vm,"unknown NM type '%s'.\n",dev_type);  
       return(-1);  
    }  
   
    bay->dev_type = nm_driver->dev_type;  
    bay->nm_driver = nm_driver;  
    return(0);    
 }  
   
 /* Remove a NM binding */  
 int c3600_nm_remove_binding(c3600_t *router,u_int nm_bay)  
 {    
    struct c3600_nm_bay *bay;  
   
    if (!(bay = c3600_nm_get_info(router,nm_bay)))  
       return(-1);  
   
    /* stop if this bay is still active */  
    if (bay->drv_info != NULL) {  
       vm_error(router->vm,"slot %u still active.\n",nm_bay);  
       return(-1);  
    }  
   
    /* check that this bay is not empty */  
    if (bay->dev_type == NULL) {  
       vm_error(router->vm,"slot %u is empty.\n",nm_bay);  
       return(-1);  
    }  
     
    /* remove all NIOs bindings */  
    c3600_nm_remove_all_nio_bindings(router,nm_bay);  
   
    bay->dev_type  = NULL;  
    bay->nm_driver = NULL;  
    return(0);  
 }  
   
 /* Find a NIO binding */  
 struct c3600_nio_binding *  
 c3600_nm_find_nio_binding(c3600_t *router,u_int nm_bay,u_int port_id)  
 {    
    struct c3600_nio_binding *nb;  
    struct c3600_nm_bay *bay;  
   
    if (!(bay = c3600_nm_get_info(router,nm_bay)))  
       return NULL;  
   
    for(nb=bay->nio_list;nb;nb=nb->next)  
       if (nb->port_id == port_id)  
          return nb;  
   
    return NULL;  
 }  
   
 /* Add a network IO binding */  
 int c3600_nm_add_nio_binding(c3600_t *router,u_int nm_bay,u_int port_id,  
                              char *nio_name)  
 {  
    struct c3600_nio_binding *nb;  
    struct c3600_nm_bay *bay;  
    netio_desc_t *nio;  
   
    if (!(bay = c3600_nm_get_info(router,nm_bay)))  
       return(-1);  
   
    /* check that a NIO is not already bound to this port */  
    if (c3600_nm_find_nio_binding(router,nm_bay,port_id) != NULL) {  
       vm_error(router->vm,"a NIO already exists for interface %u/%u.\n",  
                nm_bay,port_id);  
       return(-1);  
    }  
   
    /* acquire a reference on the NIO object */  
    if (!(nio = netio_acquire(nio_name))) {  
       vm_error(router->vm,"unable to find NIO '%s'.\n",nio_name);  
       return(-1);  
    }  
   
    /* create a new binding */  
    if (!(nb = malloc(sizeof(*nb)))) {  
       vm_error(router->vm,"unable to create NIO binding "  
                "for interface %u/%u.\n",nm_bay,port_id);  
       netio_release(nio_name);  
       return(-1);  
    }  
   
    memset(nb,0,sizeof(*nb));  
    nb->nio       = nio;  
    nb->port_id   = port_id;  
    nb->next      = bay->nio_list;  
    if (nb->next) nb->next->prev = nb;  
    bay->nio_list = nb;  
    return(0);  
 }  
   
 /* Remove a NIO binding */  
 int c3600_nm_remove_nio_binding(c3600_t *router,u_int nm_bay,u_int port_id)  
 {  
    struct c3600_nio_binding *nb;  
    struct c3600_nm_bay *bay;  
     
    if (!(bay = c3600_nm_get_info(router,nm_bay)))  
       return(-1);  
   
    if (!(nb = c3600_nm_find_nio_binding(router,nm_bay,port_id)))  
       return(-1);   /* no nio binding for this slot/port */  
   
    /* tell the NM driver to stop using this NIO */  
    if (bay->nm_driver)  
       bay->nm_driver->nm_unset_nio(router,nm_bay,port_id);  
   
    /* remove this entry from the double linked list */  
    if (nb->next)  
       nb->next->prev = nb->prev;  
   
    if (nb->prev) {  
       nb->prev->next = nb->next;  
    } else {  
       bay->nio_list = nb->next;  
    }  
   
    /* unreference NIO object */  
    netio_release(nb->nio->name);  
    free(nb);  
    return(0);  
 }  
   
 /* Remove all NIO bindings for the specified NM */  
 int c3600_nm_remove_all_nio_bindings(c3600_t *router,u_int nm_bay)  
 {    
    struct c3600_nio_binding *nb,*next;  
    struct c3600_nm_bay *bay;  
   
    if (!(bay = c3600_nm_get_info(router,nm_bay)))  
       return(-1);  
   
    for(nb=bay->nio_list;nb;nb=next) {  
       next = nb->next;  
   
       /* tell the NM driver to stop using this NIO */  
       if (bay->nm_driver)  
          bay->nm_driver->nm_unset_nio(router,nm_bay,nb->port_id);  
   
       /* unreference NIO object */  
       netio_release(nb->nio->name);  
       free(nb);  
    }  
   
    bay->nio_list = NULL;  
    return(0);  
 }  
   
 /* Enable a Network IO descriptor for a Network Module */  
 int c3600_nm_enable_nio(c3600_t *router,u_int nm_bay,u_int port_id)  
 {  
    struct c3600_nio_binding *nb;  
    struct c3600_nm_bay *bay;  
   
    if (!(bay = c3600_nm_get_info(router,nm_bay)))  
       return(-1);  
   
    /* check that we have an NIO binding for this interface */  
    if (!(nb = c3600_nm_find_nio_binding(router,nm_bay,port_id)))  
       return(-1);  
   
    /* check that the driver is defined and successfully initialized */  
    if (!bay->nm_driver || !bay->drv_info)  
       return(-1);  
   
    return(bay->nm_driver->nm_set_nio(router,nm_bay,port_id,nb->nio));  
 }  
   
 /* Disable Network IO descriptor of a Network Module */  
 int c3600_nm_disable_nio(c3600_t *router,u_int nm_bay,u_int port_id)  
 {  
    struct c3600_nm_bay *bay;  
   
    if (!(bay = c3600_nm_get_info(router,nm_bay)))  
       return(-1);  
   
    /* check that the driver is defined and successfully initialized */  
    if (!bay->nm_driver || !bay->drv_info)  
       return(-1);  
   
    return(bay->nm_driver->nm_unset_nio(router,nm_bay,port_id));  
 }  
   
 /* Enable all NIO of the specified NM */  
 int c3600_nm_enable_all_nio(c3600_t *router,u_int nm_bay)  
 {  
    struct c3600_nio_binding *nb;  
    struct c3600_nm_bay *bay;  
   
    if (!(bay = c3600_nm_get_info(router,nm_bay)))  
       return(-1);  
   
    /* check that the driver is defined and successfully initialized */  
    if (!bay->nm_driver || !bay->drv_info)  
       return(-1);  
   
    for(nb=bay->nio_list;nb;nb=nb->next)  
       bay->nm_driver->nm_set_nio(router,nm_bay,nb->port_id,nb->nio);  
   
    return(0);  
 }  
   
 /* Disable all NIO of the specified NM */  
 int c3600_nm_disable_all_nio(c3600_t *router,u_int nm_bay)  
 {  
    struct c3600_nio_binding *nb;  
    struct c3600_nm_bay *bay;  
   
    if (!(bay = c3600_nm_get_info(router,nm_bay)))  
       return(-1);  
   
    /* check that the driver is defined and successfully initialized */  
    if (!bay->nm_driver || !bay->drv_info)  
       return(-1);  
   
    for(nb=bay->nio_list;nb;nb=nb->next)  
       bay->nm_driver->nm_unset_nio(router,nm_bay,nb->port_id);  
   
    return(0);  
 }  
   
 /* Initialize a Network Module */  
 int c3600_nm_init(c3600_t *router,u_int nm_bay)  
 {    
    struct c3600_nm_bay *bay;  
    size_t len;  
   
    if (!(bay = c3600_nm_get_info(router,nm_bay)))  
       return(-1);  
   
    /* Check that a device type is defined for this bay */  
    if (!bay->dev_type || !bay->nm_driver) {  
       vm_error(router->vm,"trying to init empty slot %u.\n",nm_bay);  
       return(-1);  
    }  
   
    /* Allocate device name */  
    len = strlen(bay->dev_type) + 10;  
    if (!(bay->dev_name = malloc(len))) {  
       vm_error(router->vm,"unable to allocate device name.\n");  
       return(-1);  
    }  
   
    snprintf(bay->dev_name,len,"%s(%u)",bay->dev_type,nm_bay);  
   
    /* Initialize NM driver */  
    if (bay->nm_driver->nm_init(router,bay->dev_name,nm_bay) == 1) {  
       vm_error(router->vm,"unable to initialize NM %u.\n",nm_bay);  
       return(-1);  
    }  
   
    /* Enable all NIO */  
    c3600_nm_enable_all_nio(router,nm_bay);  
    return(0);  
278  }  }
279    
280  /* Shutdown a Network Module */  /* Set EEPROM for the specified slot */
281  int c3600_nm_shutdown(c3600_t *router,u_int nm_bay)  int c3600_set_slot_eeprom(c3600_t *router,u_int slot,
282                              struct cisco_eeprom *eeprom)
283  {  {
284     struct c3600_nm_bay *bay;     if (slot >= C3600_MAX_NM_BAYS)
   
    if (!(bay = c3600_nm_get_info(router,nm_bay)))  
285        return(-1);        return(-1);
286    
287     /* Check that a device type is defined for this bay */       router->c3660_nm_eeprom_group[slot].eeprom[0] = eeprom;
    if (!bay->dev_type || !bay->nm_driver) {  
       vm_error(router->vm,"trying to shut down empty slot %u.\n",nm_bay);  
       return(-1);  
    }  
   
    /* Disable all NIO */  
    c3600_nm_disable_all_nio(router,nm_bay);  
   
    /* Shutdown the NM driver */  
    if (bay->drv_info && (bay->nm_driver->nm_shutdown(router,nm_bay) == -1)) {  
       vm_error(router->vm,"unable to shutdown NM %u.\n",nm_bay);  
       return(-1);  
    }  
   
    free(bay->dev_name);  
    bay->dev_name = NULL;  
    bay->drv_info = NULL;  
    return(0);  
 }  
   
 /* Shutdown all NM of a router */  
 int c3600_nm_shutdown_all(c3600_t *router)  
 {  
    int i;  
   
    for(i=0;i<C3600_MAX_NM_BAYS;i++) {  
       if (!router->nm_bay[i].dev_type)  
          continue;  
   
       c3600_nm_shutdown(router,i);  
    }  
   
288     return(0);     return(0);
289  }  }
290    
291  /* Show info about all NMs */  /* Get slot/port corresponding to specified network IRQ */
292  int c3600_nm_show_all_info(c3600_t *router)  static inline void
293    c3600_net_irq_get_slot_port(u_int irq,u_int *slot,u_int *port)
294  {  {
295     struct c3600_nm_bay *bay;     irq -= C3600_NETIO_IRQ_BASE;
296     int i;     *port = irq & C3600_NETIO_IRQ_PORT_MASK;
297       *slot = irq >> C3600_NETIO_IRQ_PORT_BITS;
    for(i=0;i<C3600_MAX_NM_BAYS;i++) {  
       if (!(bay = c3600_nm_get_info(router,i)) || !bay->nm_driver)  
          continue;  
   
       if (bay->nm_driver->nm_show_info != NULL)  
          bay->nm_driver->nm_show_info(router,i);  
    }  
   
    return(0);  
 }  
   
 /* Maximum number of tokens in a NM description */  
 #define NM_DESC_MAX_TOKENS  8  
   
 /* Create a Network Module (command line) */  
 int c3600_cmd_nm_create(c3600_t *router,char *str)  
 {  
    char *tokens[NM_DESC_MAX_TOKENS];  
    int i,count,res;  
    u_int nm_bay;  
   
    /* A port adapter description is like "1:NM-1FE" */  
    if ((count = m_strsplit(str,':',tokens,NM_DESC_MAX_TOKENS)) != 2) {  
       vm_error(router->vm,"unable to parse NM description '%s'.\n",str);  
       return(-1);  
    }  
   
    /* Parse the NM bay id */  
    nm_bay = atoi(tokens[0]);  
   
    /* Add this new NM to the current NM list */  
    res = c3600_nm_add_binding(router,tokens[1],nm_bay);  
   
    /* The complete array was cleaned by strsplit */  
    for(i=0;i<NM_DESC_MAX_TOKENS;i++)  
       free(tokens[i]);  
   
    return(res);  
 }  
   
 /* Add a Network IO descriptor binding (command line) */  
 int c3600_cmd_add_nio(c3600_t *router,char *str)  
 {  
    char *tokens[NM_DESC_MAX_TOKENS];  
    int i,count,nio_type,res=-1;  
    u_int nm_bay,port_id;  
    netio_desc_t *nio;  
    char nio_name[128];  
   
    /* A port adapter description is like "1:3:tap:tap0" */  
    if ((count = m_strsplit(str,':',tokens,NM_DESC_MAX_TOKENS)) < 3) {  
       vm_error(router->vm,"unable to parse NIO description '%s'.\n",str);  
       return(-1);  
    }  
   
    /* Parse the NM bay */  
    nm_bay = atoi(tokens[0]);  
   
    /* Parse the NM port id */  
    port_id = atoi(tokens[1]);  
   
    /* Autogenerate a NIO name */  
    snprintf(nio_name,sizeof(nio_name),"c3600-i%u/%u/%u",  
             router->vm->instance_id,nm_bay,port_id);  
   
    /* Create the Network IO descriptor */  
    nio = NULL;  
    nio_type = netio_get_type(tokens[2]);  
   
    switch(nio_type) {  
       case NETIO_TYPE_UNIX:  
          if (count != 5) {  
             vm_error(router->vm,  
                      "invalid number of arguments for UNIX NIO '%s'\n",str);  
             goto done;  
          }  
   
          nio = netio_desc_create_unix(nio_name,tokens[3],tokens[4]);  
          break;  
   
       case NETIO_TYPE_VDE:  
          if (count != 5) {  
             vm_error(router->vm,  
                      "invalid number of arguments for VDE NIO '%s'\n",str);  
             goto done;  
          }  
   
          nio = netio_desc_create_vde(nio_name,tokens[3],tokens[4]);  
          break;  
   
       case NETIO_TYPE_TAP:  
          if (count != 4) {  
             vm_error(router->vm,  
                      "invalid number of arguments for TAP NIO '%s'\n",str);  
             goto done;  
          }  
   
          nio = netio_desc_create_tap(nio_name,tokens[3]);  
          break;  
   
       case NETIO_TYPE_UDP:  
          if (count != 6) {  
             vm_error(router->vm,  
                      "invalid number of arguments for UDP NIO '%s'\n",str);  
             goto done;  
          }  
   
          nio = netio_desc_create_udp(nio_name,atoi(tokens[3]),  
                                      tokens[4],atoi(tokens[5]));  
          break;  
   
       case NETIO_TYPE_TCP_CLI:  
          if (count != 5) {  
             vm_error(router->vm,  
                      "invalid number of arguments for TCP CLI NIO '%s'\n",str);  
             goto done;  
          }  
   
          nio = netio_desc_create_tcp_cli(nio_name,tokens[3],tokens[4]);  
          break;  
   
       case NETIO_TYPE_TCP_SER:  
          if (count != 4) {  
             vm_error(router->vm,  
                      "invalid number of arguments for TCP SER NIO '%s'\n",str);  
             goto done;  
          }  
   
          nio = netio_desc_create_tcp_ser(nio_name,tokens[3]);  
          break;  
   
       case NETIO_TYPE_NULL:  
          nio = netio_desc_create_null(nio_name);  
          break;  
   
 #ifdef LINUX_ETH  
       case NETIO_TYPE_LINUX_ETH:  
          if (count != 4) {  
             vm_error(router->vm,  
                      "invalid number of arguments for Linux Eth NIO '%s'\n",  
                      str);  
             goto done;  
          }  
           
          nio = netio_desc_create_lnxeth(nio_name,tokens[3]);  
          break;  
 #endif  
   
 #ifdef GEN_ETH  
       case NETIO_TYPE_GEN_ETH:  
          if (count != 4) {  
             vm_error(router->vm,  
                      "invalid number of arguments for Generic Eth NIO '%s'\n",  
                      str);  
             goto done;  
          }  
           
          nio = netio_desc_create_geneth(nio_name,tokens[3]);  
          break;  
 #endif  
   
       default:  
          vm_error(router->vm,"unknown NETIO type '%s'\n",tokens[2]);  
          goto done;  
    }  
   
    if (!nio) {  
       vm_error(router->vm,"unable to create NETIO "  
               "descriptor for NM slot %u\n",nm_bay);  
       goto done;  
    }  
   
    if (c3600_nm_add_nio_binding(router,nm_bay,port_id,nio_name) == -1) {  
       vm_error(router->vm,"unable to add NETIO binding for slot %u\n",nm_bay);  
       netio_release(nio_name);  
       netio_delete(nio_name);  
       goto done;  
    }  
     
    netio_release(nio_name);  
    res = 0;  
   
  done:  
    /* The complete array was cleaned by strsplit */  
    for(i=0;i<NM_DESC_MAX_TOKENS;i++)  
       free(tokens[i]);  
   
    return(res);  
298  }  }
299    
300  /* Show the list of available NM drivers */  /* Get network IRQ for specified slot/port */
301  void c3600_nm_show_drivers(void)  u_int c3600_net_irq_for_slot_port(u_int slot,u_int port)
302  {  {
303     int i;     u_int irq;
304    
305     printf("Available C3600 Network Module drivers:\n");     irq = (slot << C3600_NETIO_IRQ_PORT_BITS) + port;
306       irq += C3600_NETIO_IRQ_BASE;
307    
308     for(i=0;nm_drivers[i];i++) {     return(irq);
       printf("  * %s %s\n",  
              nm_drivers[i]->dev_type,  
              !nm_drivers[i]->supported ? "(NOT WORKING)" : "");  
    }  
     
    printf("\n");  
309  }  }
310    
311  /* Get a chassis driver */  /* Get a chassis driver */
# Line 950  struct c3600_chassis_driver *c3600_chass Line 321  struct c3600_chassis_driver *c3600_chass
321  }  }
322    
323  /* Set the base MAC address of the chassis */  /* Set the base MAC address of the chassis */
324  static int c3600_burn_mac_addr(m_uint16_t *data,size_t data_len,  static int c3600_burn_mac_addr(c3600_t *router,n_eth_addr_t *addr)
                                n_eth_addr_t *addr)  
325  {  {
326     m_uint8_t eeprom_ver;     m_uint8_t eeprom_ver;
327     size_t offset;     size_t offset;
328    
329     /* Read EEPROM format version */     /* Read EEPROM format version */
330     cisco_eeprom_get_byte(data,data_len,0,&eeprom_ver);     cisco_eeprom_get_byte(&router->mb_eeprom,0,&eeprom_ver);
331    
332     switch(eeprom_ver) {     switch(eeprom_ver) {
333        case 0:        case 0:
334           cisco_eeprom_set_region(data,data_len,2,addr->eth_addr_byte,6);           cisco_eeprom_set_region(&router->mb_eeprom,2,addr->eth_addr_byte,6);
335           break;           break;
336    
337        case 4:        case 4:
338           if (!cisco_eeprom_v4_find_field(data,data_len,0xC3,&offset)) {           if (!cisco_eeprom_v4_find_field(&router->mb_eeprom,0xC3,&offset)) {
339              cisco_eeprom_set_region(data,data_len,offset,              cisco_eeprom_set_region(&router->mb_eeprom,offset,
340                                      addr->eth_addr_byte,6);                                      addr->eth_addr_byte,6);
341           }           }
342           break;           break;
343    
344        default:        default:
345           fprintf(stderr,"c3600_burn_mac_addr: unable to handle "           vm_error(router->vm,"c3600_burn_mac_addr: unable to handle "
346                   "EEPROM version %u\n",eeprom_ver);                    "EEPROM version %u\n",eeprom_ver);
347           return(-1);           return(-1);
348     }     }
349    
# Line 989  int c3600_chassis_set_mac_addr(c3600_t * Line 359  int c3600_chassis_set_mac_addr(c3600_t *
359     }     }
360    
361     /* Set the chassis base MAC address */     /* Set the chassis base MAC address */
362     c3600_burn_mac_addr(router->mb_eeprom_data,sizeof(router->mb_eeprom_data),     c3600_burn_mac_addr(router,&router->mac_addr);
                        &router->mac_addr);  
363     return(0);     return(0);
364  }  }
365    
# Line 1012  int c3600_chassis_set_type(c3600_t *rout Line 381  int c3600_chassis_set_type(c3600_t *rout
381     router->chassis_driver = driver;     router->chassis_driver = driver;
382    
383     /* Copy the mainboard EEPROM */     /* Copy the mainboard EEPROM */
384     memcpy(router->mb_eeprom_data,driver->mb_eeprom,driver->mb_eeprom_len << 1);     if (cisco_eeprom_copy(&router->mb_eeprom,driver->eeprom) == -1) {
385          vm_error(router->vm,"unable to set chassis EEPROM '%s'.\n",chassis_type);
386          return(-1);
387       }
388    
389     /* Set the chassis base MAC address */     /* Set the chassis base MAC address */
390     c3600_burn_mac_addr(router->mb_eeprom_data,sizeof(router->mb_eeprom_data),     c3600_burn_mac_addr(router,&router->mac_addr);
391                         &router->mac_addr);  
392       /* The motherboard has 2 integrated FastEthernet ports on a 3660 */
393       if (driver->chassis_id == 3660) {
394          vm_slot_remove_binding(router->vm,0,0);
395          vm_slot_add_binding(router->vm,"Leopard-2FE",0,0);
396       }
397    
    router->mb_eeprom.data = router->mb_eeprom_data;  
    router->mb_eeprom.data_len = driver->mb_eeprom_len;  
398     return(0);     return(0);
399  }  }
400    
# Line 1033  int c3600_chassis_get_id(c3600_t *router Line 408  int c3600_chassis_get_id(c3600_t *router
408  }  }
409    
410  /* Show the list of available chassis drivers */  /* Show the list of available chassis drivers */
411  void c3600_chassis_show_drivers(void)  static void c3600_chassis_show_drivers(void)
412  {  {
413     int i;     int i;
414    
# Line 1084  static int c3620_init(c3600_t *router) Line 459  static int c3620_init(c3600_t *router)
459     int i;     int i;
460    
461     /* Set the processor type: R4700 */     /* Set the processor type: R4700 */
462     mips64_set_prid(vm->boot_cpu,MIPS_PRID_R4700);     mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R4700);
463    
464     /* Initialize the Galileo GT-64010 PCI controller */     /* Initialize the Galileo GT-64010 PCI controller */
465     if (c3600_init_gt64010(router) == -1)     if (c3600_init_gt64010(router) == -1)
# Line 1092  static int c3620_init(c3600_t *router) Line 467  static int c3620_init(c3600_t *router)
467    
468     /* Initialize PCI map (no PCI bridge for this chassis) */     /* Initialize PCI map (no PCI bridge for this chassis) */
469     for(i=0;i<C3600_MAX_NM_BAYS;i++)     for(i=0;i<C3600_MAX_NM_BAYS;i++)
470        router->nm_bay[i].pci_map = vm->pci_bus[0];        vm->slots_pci_bus[i] = vm->pci_bus[0];
471    
472     vm->elf_machine_id = C3620_ELF_MACHINE_ID;     vm->elf_machine_id = C3620_ELF_MACHINE_ID;
473     return(0);     return(0);
# Line 1106  static int c3640_init(c3600_t *router) Line 481  static int c3640_init(c3600_t *router)
481     int i;     int i;
482    
483     /* Set the processor type: R4700 */     /* Set the processor type: R4700 */
484     mips64_set_prid(vm->boot_cpu,MIPS_PRID_R4700);     mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R4700);
485    
486     /* Initialize the Galileo GT-64010 PCI controller */     /* Initialize the Galileo GT-64010 PCI controller */
487     if (c3600_init_gt64010(router) == -1)     if (c3600_init_gt64010(router) == -1)
# Line 1121  static int c3640_init(c3600_t *router) Line 496  static int c3640_init(c3600_t *router)
496        bay = c3600_nm_get_bay_info(3640,i);        bay = c3600_nm_get_bay_info(3640,i);
497    
498        /* Map the NM PCI bus */        /* Map the NM PCI bus */
499        router->nm_bay[i].pci_map = vm->pci_bus_pool[i & 1];        vm->slots_pci_bus[i] = vm->pci_bus_pool[i & 1];
500    
501        if (bay && (bay->pci_bridge_device != -1))        if (bay && (bay->pci_bridge_device != -1))
502           dev_dec21052_init(vm->pci_bus[0],bay->pci_bridge_device,           dev_dec21052_init(vm->pci_bus[0],bay->pci_bridge_device,
503                             router->nm_bay[i].pci_map);                             vm->slots_pci_bus[i]);
504     }     }
505    
506     vm->elf_machine_id = C3640_ELF_MACHINE_ID;     vm->elf_machine_id = C3640_ELF_MACHINE_ID;
# Line 1141  static int c3660_init(c3600_t *router) Line 516  static int c3660_init(c3600_t *router)
516     int i;     int i;
517    
518     /* Set the processor type: R5271 */     /* Set the processor type: R5271 */
519     mips64_set_prid(vm->boot_cpu,MIPS_PRID_R527x);     mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R527x);
520    
521     /* Initialize the Galileo GT-64120 PCI controller */     /* Initialize the Galileo GT-64120 PCI controller */
522     if (c3600_init_gt64120(router) == -1)     if (c3600_init_gt64120(router) == -1)
# Line 1154  static int c3660_init(c3600_t *router) Line 529  static int c3660_init(c3600_t *router)
529     }     }
530    
531     /* Slot 0 is mapped to the first bus of GT64120 */     /* Slot 0 is mapped to the first bus of GT64120 */
532     router->nm_bay[0].pci_map = vm->pci_bus[0];     vm->slots_pci_bus[0] = vm->pci_bus[0];
533    
534     /* Initialize PCI map and PCI bridges */     /* Initialize PCI map and PCI bridges */
535     for(i=1;i<C3600_MAX_NM_BAYS;i++) {     for(i=1;i<C3600_MAX_NM_BAYS;i++) {
536        bay = c3600_nm_get_bay_info(3660,i);        bay = c3600_nm_get_bay_info(3660,i);
537    
538        /* Map the NM PCI bus */        /* Map the NM PCI bus */
539        router->nm_bay[i].pci_map = vm->pci_bus_pool[i];        vm->slots_pci_bus[i] = vm->pci_bus_pool[i];
540    
541        /* Slots 1-6 are mapped to the second bus of GT64120 */        /* Slots 1-6 are mapped to the second bus of GT64120 */
542        if (bay && (bay->pci_bridge_device != -1))        if (bay && (bay->pci_bridge_device != -1))
543           dev_dec21152_init(vm->pci_bus[1],bay->pci_bridge_device,           dev_dec21152_init(vm->pci_bus[1],bay->pci_bridge_device,
544                             router->nm_bay[i].pci_map);                             vm->slots_pci_bus[i]);
545     }     }
546    
547     /* The motherboard has 2 integrated FastEthernet ports */     vm->elf_machine_id = C3660_ELF_MACHINE_ID;
    c3600_nm_add_binding(router,"Leopard-2FE",0);  
   
    vm->elf_machine_id = C3640_ELF_MACHINE_ID;  
548     return(0);     return(0);
549  }  }
550    
# Line 1198  void c3600_show_hardware(c3600_t *router Line 570  void c3600_show_hardware(c3600_t *router
570  }  }
571    
572  /* Initialize default parameters for a C3600 */  /* Initialize default parameters for a C3600 */
573  void c3600_init_defaults(c3600_t *router)  static void c3600_init_defaults(c3600_t *router)
574  {    {  
575     vm_instance_t *vm = router->vm;       vm_instance_t *vm = router->vm;  
576     n_eth_addr_t *m;     n_eth_addr_t *m;
577     m_uint16_t pid;     m_uint16_t pid;
578    
579       /* Set platform slots characteristics */
580       vm->nr_slots   = C3600_MAX_NM_BAYS;
581       vm->slots_type = CISCO_CARD_TYPE_NM;
582       vm->slots_drivers = nm_drivers;
583    
584     pid = (m_uint16_t)getpid();     pid = (m_uint16_t)getpid();
585    
586     /* Generate a chassis MAC address based on the instance ID */     /* Generate a chassis MAC address based on the instance ID */
587     m = &router->mac_addr;     m = &router->mac_addr;
588     m->eth_addr_byte[0] = 0xCC;     m->eth_addr_byte[0] = vm_get_mac_addr_msb(vm);
589     m->eth_addr_byte[1] = vm->instance_id & 0xFF;     m->eth_addr_byte[1] = vm->instance_id & 0xFF;
590     m->eth_addr_byte[2] = pid >> 8;     m->eth_addr_byte[2] = pid >> 8;
591     m->eth_addr_byte[3] = pid & 0xFF;     m->eth_addr_byte[3] = pid & 0xFF;
# Line 1222  void c3600_init_defaults(c3600_t *router Line 599  void c3600_init_defaults(c3600_t *router
599     vm->ram_size          = C3600_DEFAULT_RAM_SIZE;     vm->ram_size          = C3600_DEFAULT_RAM_SIZE;
600     vm->rom_size          = C3600_DEFAULT_ROM_SIZE;     vm->rom_size          = C3600_DEFAULT_ROM_SIZE;
601     vm->nvram_size        = C3600_DEFAULT_NVRAM_SIZE;     vm->nvram_size        = C3600_DEFAULT_NVRAM_SIZE;
602     vm->conf_reg          = C3600_DEFAULT_CONF_REG;     vm->conf_reg_setup    = C3600_DEFAULT_CONF_REG;
603     vm->clock_divisor     = C3600_DEFAULT_CLOCK_DIV;     vm->clock_divisor     = C3600_DEFAULT_CLOCK_DIV;
604     vm->nvram_rom_space   = C3600_NVRAM_ROM_RES_SIZE;     vm->nvram_rom_space   = C3600_NVRAM_ROM_RES_SIZE;
605     router->nm_iomem_size = C3600_DEFAULT_IOMEM_SIZE;     vm->nm_iomem_size     = C3600_DEFAULT_IOMEM_SIZE;
606    
607     vm->pcmcia_disk_size[0] = C3600_DEFAULT_DISK0_SIZE;     vm->pcmcia_disk_size[0] = C3600_DEFAULT_DISK0_SIZE;
608     vm->pcmcia_disk_size[1] = C3600_DEFAULT_DISK1_SIZE;     vm->pcmcia_disk_size[1] = C3600_DEFAULT_DISK1_SIZE;
609  }  }
610    
611  /* Initialize the C3600 Platform */  /* Initialize the C3600 Platform */
612  int c3600_init_platform(c3600_t *router)  static int c3600_init_platform(c3600_t *router)
613  {  {
614     vm_instance_t *vm = router->vm;     vm_instance_t *vm = router->vm;
    struct c3600_nm_bay *nm_bay;  
615     cpu_mips_t *cpu;     cpu_mips_t *cpu;
616     int i;     cpu_gen_t *gen;
617       vm_obj_t *obj;
618    
619     /* Copy config register setup into "active" config register */     /* Copy config register setup into "active" config register */
620     vm->conf_reg = vm->conf_reg_setup;     vm->conf_reg = vm->conf_reg_setup;
# Line 1249  int c3600_init_platform(c3600_t *router) Line 626  int c3600_init_platform(c3600_t *router)
626     vm->cpu_group = cpu_group_create("System CPU");     vm->cpu_group = cpu_group_create("System CPU");
627    
628     /* Initialize the virtual MIPS processor */     /* Initialize the virtual MIPS processor */
629     if (!(cpu = cpu_create(vm,0))) {     if (!(gen = cpu_create(vm,CPU_TYPE_MIPS64,0))) {
630        vm_error(vm,"unable to create CPU!\n");        vm_error(vm,"unable to create CPU!\n");
631        return(-1);        return(-1);
632     }     }
633    
634       cpu = CPU_MIPS64(gen);
635    
636     /* Add this CPU to the system CPU group */     /* Add this CPU to the system CPU group */
637     cpu_group_add(vm->cpu_group,cpu);     cpu_group_add(vm->cpu_group,gen);
638     vm->boot_cpu = cpu;     vm->boot_cpu = gen;
639    
640       /* Initialize the IRQ routing vectors */
641       vm->set_irq = mips64_vm_set_irq;
642       vm->clear_irq = mips64_vm_clear_irq;
643    
644     /* Mark the Network IO interrupt as high priority */     /* Mark the Network IO interrupt as high priority */
645     cpu->irq_idle_preempt[C3600_NETIO_IRQ] = TRUE;     cpu->irq_idle_preempt[C3600_NETIO_IRQ] = TRUE;
646       cpu->irq_idle_preempt[C3600_GT64K_IRQ] = TRUE;
647     cpu->irq_idle_preempt[C3600_DUART_IRQ] = TRUE;     cpu->irq_idle_preempt[C3600_DUART_IRQ] = TRUE;
648    
649     /* Copy some parameters from VM to CPU (idle PC, ...) */     /* Copy some parameters from VM to CPU (idle PC, ...) */
# Line 1277  int c3600_init_platform(c3600_t *router) Line 661  int c3600_init_platform(c3600_t *router)
661     /* Remote emulator control */     /* Remote emulator control */
662     dev_remote_control_init(vm,0x16000000,0x1000);     dev_remote_control_init(vm,0x16000000,0x1000);
663    
664     /* Bootflash */     /* Bootflash (8 Mb) */
665     dev_bootflash_init(vm,"bootflash",C3600_BOOTFLASH_ADDR,(8 * 1048576));     dev_bootflash_init(vm,"bootflash","c3600-bootflash-8mb",
666                          C3600_BOOTFLASH_ADDR);
667    
668     /* NVRAM and calendar */     /* NVRAM and calendar */
669     dev_nvram_init(vm,"nvram",     dev_nvram_init(vm,"nvram",
# Line 1291  int c3600_init_platform(c3600_t *router) Line 676  int c3600_init_platform(c3600_t *router)
676     if (dev_c3600_iofpga_init(router,C3600_IOFPGA_ADDR,0x40000) == -1)     if (dev_c3600_iofpga_init(router,C3600_IOFPGA_ADDR,0x40000) == -1)
677        return(-1);        return(-1);
678    
679       if (!(obj = vm_object_find(router->vm,"io_fpga")))
680          return(-1);
681    
682       router->iofpga_data = obj->data;
683    
684     /* PCI IO space */     /* PCI IO space */
685     if (!(vm->pci_io_space = pci_io_data_init(vm,C3600_PCI_IO_ADDR)))     if (!(vm->pci_io_space = pci_io_data_init(vm,C3600_PCI_IO_ADDR)))
686        return(-1);        return(-1);
# Line 1300  int c3600_init_platform(c3600_t *router) Line 690  int c3600_init_platform(c3600_t *router)
690        return(-1);        return(-1);
691    
692     /* Initialize RAM */     /* Initialize RAM */
693     dev_ram_init(vm,"ram",vm->ram_mmap,0x00000000ULL,vm->ram_size*1048576);     vm_ram_init(vm,0x00000000ULL);
694    
695     /* Initialize ROM */     /* Initialize ROM */
696     if (!vm->rom_filename) {     if (!vm->rom_filename) {
697        /* use embedded ROM */        /* use embedded ROM */
698        dev_rom_init(vm,"rom",C3600_ROM_ADDR,vm->rom_size*1048576);        dev_rom_init(vm,"rom",C3600_ROM_ADDR,vm->rom_size*1048576,
699                       mips64_microcode,mips64_microcode_len);
700     } else {     } else {
701        /* use alternate ROM */        /* use alternate ROM */
702        dev_ram_init(vm,"rom",TRUE,C3600_ROM_ADDR,vm->rom_size*1048576);        dev_ram_init(vm,"rom",TRUE,TRUE,NULL,FALSE,
703                       C3600_ROM_ADDR,vm->rom_size*1048576);
704     }     }
705    
706     /* Initialize the NS16552 DUART */     /* Initialize the NS16552 DUART */
# Line 1319  int c3600_init_platform(c3600_t *router) Line 711  int c3600_init_platform(c3600_t *router)
711     dev_clpd6729_init(vm,vm->pci_bus[0],20,vm->pci_io_space,0x4402,0x4403);     dev_clpd6729_init(vm,vm->pci_bus[0],20,vm->pci_io_space,0x4402,0x4403);
712    
713     /* Initialize Network Modules */     /* Initialize Network Modules */
714     for(i=0;i<C3600_MAX_NM_BAYS;i++) {     if (vm_slot_init_all(vm) == -1)
715        nm_bay = &router->nm_bay[i];        return(-1);
   
       if (!nm_bay->dev_type)  
          continue;  
   
       if (c3600_nm_init(router,i) == -1) {  
          vm_error(vm,"unable to create Network Module \"%s\"\n",  
                   nm_bay->dev_type);  
          return(-1);  
       }  
    }  
   
    /* Enable NVRAM operations to load/store configs */  
    vm->nvram_extract_config = c3600_nvram_extract_config;  
    vm->nvram_push_config = c3600_nvram_push_config;  
716    
717     /* Show device list */     /* Show device list */
718     c3600_show_hardware(router);     c3600_show_hardware(router);
# Line 1342  int c3600_init_platform(c3600_t *router) Line 720  int c3600_init_platform(c3600_t *router)
720  }  }
721    
722  /* Boot the IOS image */  /* Boot the IOS image */
723  int c3600_boot_ios(c3600_t *router)  static int c3600_boot_ios(c3600_t *router)
724  {    {  
725     vm_instance_t *vm = router->vm;     vm_instance_t *vm = router->vm;
726       cpu_mips_t *cpu;
727    
728     if (!vm->boot_cpu)     if (!vm->boot_cpu)
729        return(-1);        return(-1);
# Line 1359  int c3600_boot_ios(c3600_t *router) Line 738  int c3600_boot_ios(c3600_t *router)
738     }     }
739    
740     /* Reset the boot CPU */     /* Reset the boot CPU */
741     mips64_reset(vm->boot_cpu);     cpu = CPU_MIPS64(vm->boot_cpu);
742       mips64_reset(cpu);
743    
744     /* Load IOS image */     /* Load IOS image */
745     if (mips64_load_elf_image(vm->boot_cpu,vm->ios_image,     if (mips64_load_elf_image(cpu,vm->ios_image,
746                                 (vm->ghost_status == VM_GHOST_RAM_USE),
747                               &vm->ios_entry_point) < 0)                               &vm->ios_entry_point) < 0)
748     {     {
749        vm_error(vm,"failed to load Cisco IOS image '%s'.\n",vm->ios_image);        vm_error(vm,"failed to load Cisco IOS image '%s'.\n",vm->ios_image);
# Line 1372  int c3600_boot_ios(c3600_t *router) Line 753  int c3600_boot_ios(c3600_t *router)
753     /* Launch the simulation */     /* Launch the simulation */
754     printf("\nC3600 '%s': starting simulation (CPU0 PC=0x%llx), "     printf("\nC3600 '%s': starting simulation (CPU0 PC=0x%llx), "
755            "JIT %sabled.\n",            "JIT %sabled.\n",
756            vm->name,vm->boot_cpu->pc,vm->jit_use ? "en":"dis");            vm->name,cpu->pc,vm->jit_use ? "en":"dis");
757    
758     vm_log(vm,"C3600_BOOT",     vm_log(vm,"C3600_BOOT",
759            "starting instance (CPU0 PC=0x%llx,idle_pc=0x%llx,JIT %s)\n",            "starting instance (CPU0 PC=0x%llx,idle_pc=0x%llx,JIT %s)\n",
760            vm->boot_cpu->pc,vm->boot_cpu->idle_pc,vm->jit_use ? "on":"off");            cpu->pc,cpu->idle_pc,vm->jit_use ? "on":"off");
761    
762     /* Start main CPU */     /* Start main CPU */
763     vm->status = VM_STATUS_RUNNING;     if (vm->ghost_status != VM_GHOST_RAM_GENERATE) {
764     cpu_start(vm->boot_cpu);        vm->status = VM_STATUS_RUNNING;
765          cpu_start(vm->boot_cpu);
766       } else {
767          vm->status = VM_STATUS_SHUTDOWN;
768       }
769     return(0);     return(0);
770  }  }
771    
772    /* Set an IRQ */
773    static void c3600_set_irq(vm_instance_t *vm,u_int irq)
774    {
775       c3600_t *router = VM_C3600(vm);
776       cpu_mips_t *cpu0 = CPU_MIPS64(vm->boot_cpu);
777       u_int slot,port;
778    
779       switch(irq) {
780          case 0 ... 7:
781             mips64_set_irq(cpu0,irq);
782    
783             if (cpu0->irq_idle_preempt[irq])
784                cpu_idle_break_wait(cpu0->gen);
785             break;
786    
787          case C3600_NETIO_IRQ_BASE ... C3600_NETIO_IRQ_END:
788             c3600_net_irq_get_slot_port(irq,&slot,&port);
789             dev_c3600_iofpga_net_set_irq(router->iofpga_data,slot,port);
790             break;
791       }
792    }
793    
794    /* Clear an IRQ */
795    static void c3600_clear_irq(vm_instance_t *vm,u_int irq)
796    {
797       c3600_t *router = VM_C3600(vm);
798       cpu_mips_t *cpu0 = CPU_MIPS64(vm->boot_cpu);
799       u_int slot,port;
800    
801       switch(irq) {
802          case 0 ... 7:
803             mips64_clear_irq(cpu0,irq);
804             break;
805    
806          case C3600_NETIO_IRQ_BASE ... C3600_NETIO_IRQ_END:
807             c3600_net_irq_get_slot_port(irq,&slot,&port);
808             dev_c3600_iofpga_net_clear_irq(router->iofpga_data,slot,port);
809             break;
810       }
811    }
812    
813  /* Initialize a Cisco 3600 instance */  /* Initialize a Cisco 3600 instance */
814  int c3600_init_instance(c3600_t *router)  static int c3600_init_instance(vm_instance_t *vm)
815  {    {  
816     vm_instance_t *vm = router->vm;     c3600_t *router = VM_C3600(vm);
817     m_uint32_t rom_entry_point;     m_uint32_t rom_entry_point;
818     cpu_mips_t *cpu0;     cpu_mips_t *cpu0;
819    
# Line 1402  int c3600_init_instance(c3600_t *router) Line 828  int c3600_init_instance(c3600_t *router)
828        return(-1);        return(-1);
829     }     }
830    
831       /* IRQ routing */
832       vm->set_irq = c3600_set_irq;
833       vm->clear_irq = c3600_clear_irq;
834    
835     /* Load IOS configuration file */     /* Load IOS configuration file */
836     if (vm->ios_config != NULL) {     if (vm->ios_config != NULL) {
837        vm_nvram_push_config(vm,vm->ios_config);        vm_nvram_push_config(vm,vm->ios_config);
# Line 1409  int c3600_init_instance(c3600_t *router) Line 839  int c3600_init_instance(c3600_t *router)
839     }     }
840    
841     /* Load ROM (ELF image or embedded) */     /* Load ROM (ELF image or embedded) */
842     cpu0 = vm->boot_cpu;     cpu0 = CPU_MIPS64(vm->boot_cpu);
843     rom_entry_point = (m_uint32_t)MIPS_ROM_PC;     rom_entry_point = (m_uint32_t)MIPS_ROM_PC;
844    
845     if ((vm->rom_filename != NULL) &&     if ((vm->rom_filename != NULL) &&
846         (mips64_load_elf_image(cpu0,vm->rom_filename,&rom_entry_point) < 0))         (mips64_load_elf_image(cpu0,vm->rom_filename,0,&rom_entry_point) < 0))
847     {     {
848        vm_error(vm,"unable to load alternate ROM '%s', "        vm_error(vm,"unable to load alternate ROM '%s', "
849                 "fallback to embedded ROM.\n\n",vm->rom_filename);                 "fallback to embedded ROM.\n\n",vm->rom_filename);
# Line 1430  int c3600_init_instance(c3600_t *router) Line 860  int c3600_init_instance(c3600_t *router)
860  }  }
861    
862  /* Stop a Cisco 3600 instance */  /* Stop a Cisco 3600 instance */
863  int c3600_stop_instance(c3600_t *router)  static int c3600_stop_instance(vm_instance_t *vm)
864  {  {
    vm_instance_t *vm = router->vm;  
   
865     printf("\nC3600 '%s': stopping simulation.\n",vm->name);     printf("\nC3600 '%s': stopping simulation.\n",vm->name);
866     vm_log(vm,"C3600_STOP","stopping simulation.\n");     vm_log(vm,"C3600_STOP","stopping simulation.\n");
867    
# Line 1448  int c3600_stop_instance(c3600_t *router) Line 876  int c3600_stop_instance(c3600_t *router)
876     }     }
877    
878     /* Free resources that were used during execution to emulate hardware */     /* Free resources that were used during execution to emulate hardware */
879     c3600_nm_shutdown_all(router);     vm_slot_shutdown_all(vm);
880     vm_hardware_shutdown(vm);     vm_hardware_shutdown(vm);
881     return(0);     return(0);
882  }  }
883    
884    /* Get MAC address MSB */
885    static u_int c3600_get_mac_addr_msb(void)
886    {
887       return(0xCC);
888    }
889    
890    /* Parse specific options for the Cisco 3600 platform */
891    static int c3600_cli_parse_options(vm_instance_t *vm,int option)
892    {
893       c3600_t *router = VM_C3600(vm);
894    
895       switch(option) {
896          /* IO memory reserved for NMs (in percents!) */
897          case OPT_IOMEM_SIZE:
898             vm->nm_iomem_size = 0x8000 | atoi(optarg);
899             break;
900    
901          /* Chassis type */
902          case 't':
903             c3600_chassis_set_type(router,optarg);
904             break;
905    
906          /* Unknown option */
907          default:
908             return(-1);
909       }
910    
911       return(0);
912    }
913    
914    /* Show specific CLI options */
915    static void c3600_cli_show_options(vm_instance_t *vm)
916    {
917       printf("  -t <chassis_type>  : Select Chassis type (default: \"%s\")\n"
918              "  --iomem-size <val> : IO memory (in percents, default: %u)\n"
919              "  -p <nm_desc>       : Define a Network Module\n"
920              "  -s <nm_nio>        : Bind a Network IO interface to a "
921              "Network Module\n",
922              C3600_DEFAULT_CHASSIS,vm->nm_iomem_size);
923    }
924    
925    /* Platform definition */
926    static vm_platform_t c3600_platform = {
927       "c3600", "C3600", "3600",
928       c3600_create_instance,
929       c3600_delete_instance,
930       c3600_init_instance,
931       c3600_stop_instance,
932       c3600_nvram_extract_config,
933       c3600_nvram_push_config,
934       c3600_get_mac_addr_msb,
935       c3600_save_config,
936       c3600_cli_parse_options,
937       c3600_cli_show_options,
938       c3600_chassis_show_drivers,
939    };
940    
941    /* Register the c3600 platform */
942    int c3600_platform_register(void)
943    {
944       if (vm_platform_register(&c3600_platform) == -1)
945          return(-1);
946    
947       return(hypervisor_c3600_init(&c3600_platform));
948    }

Legend:
Removed from v.2  
changed lines
  Added in v.11

  ViewVC Help
Powered by ViewVC 1.1.26