/[dynamips]/upstream/dynamips-0.2.6-RC3/dev_c3600.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /upstream/dynamips-0.2.6-RC3/dev_c3600.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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

  ViewVC Help
Powered by ViewVC 1.1.26