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

Annotation of /trunk/dev_c3600.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8 - (hide annotations)
Sat Oct 6 16:24:54 2007 UTC (16 years, 6 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7-RC2/dev_c3600.c
File MIME type: text/plain
File size: 42997 byte(s)
dynamips-0.2.7-RC2

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

  ViewVC Help
Powered by ViewVC 1.1.26