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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (hide annotations)
Sat Oct 6 16:23:47 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7-RC1/dev_c2600.c
File MIME type: text/plain
File size: 40778 byte(s)
dynamips-0.2.7-RC1

1 dpavlin 7 /*
2     * Cisco router simulation platform.
3     * Copyright (c) 2006 Christophe Fillot (cf@utc.fr)
4     *
5     * Generic Cisco 2600 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 "cpu.h"
16     #include "vm.h"
17     #include "dynamips.h"
18     #include "memory.h"
19     #include "device.h"
20     #include "ppc32_mem.h"
21     #include "pci_io.h"
22     #include "cisco_eeprom.h"
23     #include "dev_mpc860.h"
24     #include "dev_rom.h"
25     #include "dev_c2600.h"
26     #include "dev_vtty.h"
27     #include "registry.h"
28    
29     /* ======================================================================== */
30     /* EEPROM definitions */
31     /* ======================================================================== */
32    
33     /* Cisco 2600 mainboard EEPROM */
34     static m_uint16_t eeprom_c2600_mb_data[] = {
35     0x0101, 0x0404, 0x0000, 0x0000, 0x4320, 0x00FF, 0x0091, 0x0020,
36     0x0000, 0x0000, 0x0000, 0x0000, 0x3030, 0x3000, 0x0030, 0x3030,
37     0x3002, 0x0200, 0x0000, 0x0000, 0x00FF, 0xFFFF, 0x5006, 0x490B,
38     0x1709, 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     struct c2600_mb_id {
46     char *name;
47     char *mb_driver;
48     m_uint16_t id;
49     int supported;
50     };
51    
52     struct c2600_mb_id c2600_mainboard_id[] = {
53     { "2610" , "CISCO2600-MB-1E" , 0x0091, TRUE },
54     { "2611" , "CISCO2600-MB-2E" , 0x0092, TRUE },
55     { "2620" , "CISCO2600-MB-1FE" , 0x0094, TRUE },
56     { "2621" , "CISCO2600-MB-2FE" , 0x00a2, TRUE },
57     { "2610XM" , "CISCO2600-MB-1FE" , 0x036a, TRUE },
58     { "2611XM" , "CISCO2600-MB-2FE" , 0x036b, FALSE },
59     { "2620XM" , "CISCO2600-MB-1FE" , 0x036c, TRUE },
60     { "2621XM" , "CISCO2600-MB-2FE" , 0x036d, FALSE },
61     { "2650XM" , "CISCO2600-MB-1FE" , 0x036e, TRUE },
62     { "2651XM" , "CISCO2600-MB-2FE" , 0x036f, FALSE },
63     { NULL , NULL , 0x0000, 0 },
64     };
65    
66     /* ======================================================================== */
67     /* Network Module Drivers */
68     /* ======================================================================== */
69     static struct c2600_nm_driver *nm_drivers[] = {
70     &dev_c2600_mb1e_eth_driver,
71     &dev_c2600_mb2e_eth_driver,
72     &dev_c2600_mb1fe_eth_driver,
73     &dev_c2600_mb2fe_eth_driver,
74    
75     &dev_c2600_nm_1e_driver,
76     &dev_c2600_nm_4e_driver,
77     &dev_c2600_nm_1fe_tx_driver,
78     &dev_c2600_nm_16esw_driver,
79     NULL,
80     };
81    
82     /* ======================================================================== */
83     /* Cisco 2600 router instances */
84     /* ======================================================================== */
85    
86     /* Read a byte from the NVRAM */
87     static inline m_uint8_t nvram_read_byte(u_char *base,u_int offset)
88     {
89     m_uint8_t *ptr;
90    
91     ptr = (m_uint8_t *)base + (offset << 2);
92     return(*ptr);
93     }
94    
95     /* Write a byte to the NVRAM */
96     static inline void nvram_write_byte(u_char *base,u_int offset,m_uint8_t val)
97     {
98     m_uint8_t *ptr;
99    
100     ptr = (m_uint8_t *)base + (offset << 2);
101     *ptr = val;
102     }
103    
104     /* Read a 16-bit value from NVRAM */
105     static m_uint16_t nvram_read16(u_char *base,u_int offset)
106     {
107     m_uint16_t val;
108     val = nvram_read_byte(base,offset) << 8;
109     val |= nvram_read_byte(base,offset+1);
110     return(val);
111     }
112    
113     /* Write a 16-bit value to NVRAM */
114     static void nvram_write16(u_char *base,u_int offset,m_uint16_t val)
115     {
116     nvram_write_byte(base,offset,val >> 8);
117     nvram_write_byte(base,offset+1,val & 0xFF);
118     }
119    
120     /* Read a 32-bit value from NVRAM */
121     static m_uint32_t nvram_read32(u_char *base,u_int offset)
122     {
123     m_uint32_t val;
124     val = nvram_read_byte(base,offset) << 24;
125     val |= nvram_read_byte(base,offset+1) << 16;
126     val |= nvram_read_byte(base,offset+2) << 8;
127     val |= nvram_read_byte(base,offset+3);
128     return(val);
129     }
130    
131     /* Write a 32-bit value to NVRAM */
132     static void nvram_write32(u_char *base,u_int offset,m_uint32_t val)
133     {
134     nvram_write_byte(base,offset,val >> 24);
135     nvram_write_byte(base,offset+1,val >> 16);
136     nvram_write_byte(base,offset+2,val >> 8);
137     nvram_write_byte(base,offset+3,val & 0xFF);
138     }
139    
140     /* Read a buffer from NVRAM */
141     static void nvram_memcpy_from(u_char *base,u_int offset,u_char *data,u_int len)
142     {
143     u_int i;
144    
145     for(i=0;i<len;i++) {
146     *data = nvram_read_byte(base,offset+i);
147     data++;
148     }
149     }
150    
151     /* Write a buffer from NVRAM */
152     static void nvram_memcpy_to(u_char *base,u_int offset,u_char *data,u_int len)
153     {
154     u_int i;
155    
156     for(i=0;i<len;i++) {
157     nvram_write_byte(base,offset+i,*data);
158     data++;
159     }
160     }
161    
162     /* Directly extract the configuration from the NVRAM device */
163     ssize_t c2600_nvram_extract_config(vm_instance_t *vm,char **buffer)
164     {
165     u_char *base_ptr;
166     u_int ios_ptr,cfg_ptr,end_ptr;
167     m_uint32_t start,nvlen;
168     m_uint16_t magic1,magic2;
169     struct vdevice *nvram_dev;
170     off_t nvram_size;
171     int fd;
172    
173     if ((nvram_dev = dev_get_by_name(vm,"nvram")))
174     dev_sync(nvram_dev);
175    
176     fd = vm_mmap_open_file(vm,"nvram",&base_ptr,&nvram_size);
177    
178     if (fd == -1)
179     return(-1);
180    
181     ios_ptr = vm->nvram_rom_space;
182     end_ptr = nvram_size;
183    
184     if ((ios_ptr + 0x30) >= end_ptr) {
185     vm_error(vm,"NVRAM file too small\n");
186     return(-1);
187     }
188    
189     magic1 = nvram_read16(base_ptr,ios_ptr+0x06);
190     magic2 = nvram_read16(base_ptr,ios_ptr+0x08);
191    
192     if ((magic1 != 0xF0A5) || (magic2 != 0xABCD)) {
193     vm_error(vm,"unable to find IOS magic numbers (0x%x,0x%x)!\n",
194     magic1,magic2);
195     return(-1);
196     }
197    
198     start = nvram_read32(base_ptr,ios_ptr+0x10) + 1;
199     nvlen = nvram_read32(base_ptr,ios_ptr+0x18);
200    
201     printf("START = 0x%8.8x, LEN = 0x%8.8x\n",start,nvlen);
202     printf("END = 0x%8.8x\n",nvram_read32(base_ptr,ios_ptr+0x14));
203    
204     if (!(*buffer = malloc(nvlen+1))) {
205     vm_error(vm,"unable to allocate config buffer (%u bytes)\n",nvlen);
206     return(-1);
207     }
208    
209     cfg_ptr = ios_ptr + start + 0x08;
210    
211     if ((cfg_ptr + nvlen) > end_ptr) {
212     vm_error(vm,"NVRAM file too small\n");
213     return(-1);
214     }
215    
216     nvram_memcpy_from(base_ptr,cfg_ptr,*buffer,nvlen-1);
217     (*buffer)[nvlen-1] = 0;
218     return(nvlen-1);
219     }
220    
221     /* Compute NVRAM checksum */
222     static m_uint16_t c2600_nvram_cksum(u_char *base_ptr,u_int offset,size_t count)
223     {
224     m_uint32_t sum = 0;
225    
226     while(count > 1) {
227     sum = sum + nvram_read16(base_ptr,offset);
228     offset += 2;
229     count -= sizeof(m_uint16_t);
230     }
231    
232     if (count > 0)
233     sum = sum + ((nvram_read16(base_ptr,offset) & 0xFF) << 8);
234    
235     while(sum>>16)
236     sum = (sum & 0xffff) + (sum >> 16);
237    
238     return(~sum);
239     }
240    
241     /* Directly push the IOS configuration to the NVRAM device */
242     int c2600_nvram_push_config(vm_instance_t *vm,char *buffer,size_t len)
243     {
244     m_uint32_t cfg_offset,cklen,tmp,ios_ptr,cfg_ptr;
245     m_uint16_t cksum;
246     u_char *base_ptr;
247     int fd;
248    
249     fd = vm_mmap_create_file(vm,"nvram",vm->nvram_size*4096,&base_ptr);
250    
251     if (fd == -1)
252     return(-1);
253    
254     cfg_offset = 0x2c;
255     ios_ptr = vm->nvram_rom_space;
256     cfg_ptr = ios_ptr + cfg_offset;
257    
258     /* Write IOS tag, uncompressed config... */
259     nvram_write16(base_ptr,ios_ptr+0x06,0xF0A5);
260     nvram_write16(base_ptr,ios_ptr+0x08,0xABCD);
261     nvram_write16(base_ptr,ios_ptr+0x0a,0x0001);
262     nvram_write16(base_ptr,ios_ptr+0x0c,0x0000);
263     nvram_write16(base_ptr,ios_ptr+0x0e,0x0c04);
264    
265     /* Store file contents to NVRAM */
266     nvram_memcpy_to(base_ptr,cfg_ptr,buffer,len);
267    
268     /* Write config addresses + size */
269     tmp = cfg_offset - 0x08;
270    
271     nvram_write32(base_ptr,ios_ptr+0x10,tmp);
272     nvram_write32(base_ptr,ios_ptr+0x14,tmp + len);
273     nvram_write32(base_ptr,ios_ptr+0x18,len);
274    
275     /* Compute the checksum */
276     cklen = (vm->nvram_size*1024) - (vm->nvram_rom_space + 0x08);
277     cksum = c2600_nvram_cksum(base_ptr,ios_ptr+0x08,cklen);
278     nvram_write16(base_ptr,ios_ptr+0x0c,cksum);
279    
280     vm_mmap_close_file(fd,base_ptr,vm->nvram_size*4096);
281     return(0);
282     }
283    
284     /* Check for empty config */
285     int c2600_nvram_check_empty_config(vm_instance_t *vm)
286     {
287     struct vdevice *dev;
288     m_uint64_t addr;
289     m_uint32_t len;
290    
291     if (!(dev = dev_get_by_name(vm,"nvram")))
292     return(-1);
293    
294     addr = dev->phys_addr + (vm->nvram_rom_space << 2);
295     len = dev->phys_len - (vm->nvram_rom_space << 2);
296    
297     while(len > 0) {
298     if (physmem_copy_u32_from_vm(vm,addr) != 0)
299     return(0);
300    
301     addr += sizeof(m_uint32_t);
302     len -= sizeof(m_uint32_t);
303     }
304    
305     /* Empty NVRAM */
306     vm->conf_reg |= 0x0040;
307     printf("NVRAM is empty, setting config register to 0x%x\n",vm->conf_reg);
308     return(0);
309     }
310    
311     /* Create a new router instance */
312     c2600_t *c2600_create_instance(char *name,int instance_id)
313     {
314     c2600_t *router;
315    
316     if (!(router = malloc(sizeof(*router)))) {
317     fprintf(stderr,"C2600 '%s': Unable to create new instance!\n",name);
318     return NULL;
319     }
320    
321     memset(router,0,sizeof(*router));
322    
323     if (!(router->vm = vm_create(name,instance_id,VM_TYPE_C2600))) {
324     fprintf(stderr,"C2600 '%s': unable to create VM instance!\n",name);
325     goto err_vm;
326     }
327    
328     c2600_init_defaults(router);
329     router->vm->hw_data = router;
330     return router;
331    
332     err_vm:
333     free(router);
334     return NULL;
335     }
336    
337     /* Free resources used by a router instance */
338     static int c2600_free_instance(void *data,void *arg)
339     {
340     vm_instance_t *vm = data;
341     c2600_t *router;
342     int i;
343    
344     if (vm->type == VM_TYPE_C2600) {
345     router = VM_C2600(vm);
346    
347     /* Stop all CPUs */
348     if (vm->cpu_group != NULL) {
349     vm_stop(vm);
350    
351     if (cpu_group_sync_state(vm->cpu_group) == -1) {
352     vm_error(vm,"unable to sync with system CPUs.\n");
353     return(FALSE);
354     }
355     }
356    
357     /* Remove NIO bindings */
358     for(i=0;i<C2600_MAX_NM_BAYS;i++)
359     c2600_nm_remove_all_nio_bindings(router,i);
360    
361     /* Shutdown all Network Modules */
362     c2600_nm_shutdown_all(router);
363    
364     /* Free mainboard EEPROM */
365     cisco_eeprom_free(&router->mb_eeprom);
366    
367     /* Free all resources used by VM */
368     vm_free(vm);
369    
370     /* Free the router structure */
371     free(router);
372     return(TRUE);
373     }
374    
375     return(FALSE);
376     }
377    
378     /* Delete a router instance */
379     int c2600_delete_instance(char *name)
380     {
381     return(registry_delete_if_unused(name,OBJ_TYPE_VM,
382     c2600_free_instance,NULL));
383     }
384    
385     /* Delete all router instances */
386     int c2600_delete_all_instances(void)
387     {
388     return(registry_delete_type(OBJ_TYPE_VM,c2600_free_instance,NULL));
389     }
390    
391     /* Save configuration of a C2600 instance */
392     void c2600_save_config(c2600_t *router,FILE *fd)
393     {
394     vm_instance_t *vm = router->vm;
395     struct c2600_nio_binding *nb;
396     struct c2600_nm_bay *bay;
397     int i;
398    
399     /* General settings */
400     fprintf(fd,"c2600 create %s %u\n",vm->name,vm->instance_id);
401     fprintf(fd,"c2600 set_chassis %s %s\n",vm->name,router->mainboard_type);
402    
403     /* VM configuration */
404     vm_save_config(vm,fd);
405    
406     /* Network Module settings */
407     for(i=0;i<C2600_MAX_NM_BAYS;i++) {
408     if (!(bay = c2600_nm_get_info(router,i)))
409     continue;
410    
411     if (bay->dev_type) {
412     fprintf(fd,"c2600 add_nm_binding %s %u %s\n",
413     vm->name,i,bay->dev_type);
414     }
415    
416     for(nb=bay->nio_list;nb;nb=nb->next) {
417     fprintf(fd,"c2600 add_nio_binding %s %u %u %s\n",
418     vm->name,i,nb->port_id,nb->nio->name);
419     }
420     }
421    
422     fprintf(fd,"\n");
423     }
424    
425     /* Save configurations of all C2600 instances */
426     static void c2600_reg_save_config(registry_entry_t *entry,void *opt,int *err)
427     {
428     vm_instance_t *vm = entry->data;
429     c2600_t *router = VM_C2600(vm);
430    
431     if (vm->type == VM_TYPE_C2600)
432     c2600_save_config(router,(FILE *)opt);
433     }
434    
435     void c2600_save_config_all(FILE *fd)
436     {
437     registry_foreach_type(OBJ_TYPE_VM,c2600_reg_save_config,fd,NULL);
438     }
439    
440     /* Find Cisco 2600 Mainboard info */
441     static struct c2600_mb_id *c2600_get_mb_info(char *mainboard_type)
442     {
443     int i;
444    
445     for(i=0;c2600_mainboard_id[i].name;i++)
446     if (!strcmp(c2600_mainboard_id[i].name,mainboard_type))
447     return(&c2600_mainboard_id[i]);
448    
449     return NULL;
450     }
451    
452     /* Show all available mainboards */
453     void c2600_mainboard_show_drivers(void)
454     {
455     int i;
456    
457     printf("Available C2600 chassis drivers:\n");
458    
459     for(i=0;c2600_mainboard_id[i].name;i++)
460     printf(" * %s %s\n",
461     c2600_mainboard_id[i].name,
462     !c2600_mainboard_id[i].supported ? "(NOT WORKING)" : "");
463    
464     printf("\n");
465     }
466    
467     /* Set NM EEPROM definition */
468     int c2600_nm_set_eeprom(c2600_t *router,u_int nm_bay,
469     const struct cisco_eeprom *eeprom)
470     {
471     if (nm_bay == 0)
472     return(0);
473    
474     if (nm_bay != 1) {
475     vm_error(router->vm,"c2600_nm_set_eeprom: invalid NM Bay %u.\n",nm_bay);
476     return(-1);
477     }
478    
479     if (cisco_eeprom_copy(&router->nm_bay[nm_bay].eeprom,eeprom) == -1) {
480     vm_error(router->vm,"c2600_nm_set_eeprom: no memory.\n");
481     return(-1);
482     }
483    
484     return(0);
485     }
486    
487     /* Unset NM EEPROM definition (empty bay) */
488     int c2600_nm_unset_eeprom(c2600_t *router,u_int nm_bay)
489     {
490     if (nm_bay == 0)
491     return(0);
492    
493     if (nm_bay != 1) {
494     vm_error(router->vm,"c2600_nm_set_eeprom: invalid NM Bay %u.\n",nm_bay);
495     return(-1);
496     }
497    
498     cisco_eeprom_free(&router->nm_bay[nm_bay].eeprom);
499     return(0);
500     }
501    
502     /* Check if a bay has a port adapter */
503     int c2600_nm_check_eeprom(c2600_t *router,u_int nm_bay)
504     {
505     if (nm_bay != 1)
506     return(FALSE);
507    
508     return(cisco_eeprom_valid(&router->nm_bay[nm_bay].eeprom));
509     }
510    
511     /* Get bay info */
512     struct c2600_nm_bay *c2600_nm_get_info(c2600_t *router,u_int nm_bay)
513     {
514     if (nm_bay >= C2600_MAX_NM_BAYS)
515     return NULL;
516    
517     return(&router->nm_bay[nm_bay]);
518     }
519    
520     /* Get NM type */
521     char *c2600_nm_get_type(c2600_t *router,u_int nm_bay)
522     {
523     struct c2600_nm_bay *bay;
524    
525     bay = c2600_nm_get_info(router,nm_bay);
526     return((bay != NULL) ? bay->dev_type : NULL);
527     }
528    
529     /* Get driver info about the specified slot */
530     void *c2600_nm_get_drvinfo(c2600_t *router,u_int nm_bay)
531     {
532     struct c2600_nm_bay *bay;
533    
534     bay = c2600_nm_get_info(router,nm_bay);
535     return((bay != NULL) ? bay->drv_info : NULL);
536     }
537    
538     /* Set driver info for the specified slot */
539     int c2600_nm_set_drvinfo(c2600_t *router,u_int nm_bay,void *drv_info)
540     {
541     struct c2600_nm_bay *bay;
542    
543     if (!(bay = c2600_nm_get_info(router,nm_bay)))
544     return(-1);
545    
546     bay->drv_info = drv_info;
547     return(0);
548     }
549    
550     /* Get a NM driver */
551     static struct c2600_nm_driver *c2600_nm_get_driver(char *dev_type)
552     {
553     int i;
554    
555     for(i=0;nm_drivers[i];i++)
556     if (!strcmp(nm_drivers[i]->dev_type,dev_type))
557     return nm_drivers[i];
558    
559     return NULL;
560     }
561    
562     /* Add a NM binding */
563     int c2600_nm_add_binding(c2600_t *router,char *dev_type,u_int nm_bay)
564     {
565     struct c2600_nm_driver *nm_driver;
566     struct c2600_nm_bay *bay;
567    
568     if (!(bay = c2600_nm_get_info(router,nm_bay)))
569     return(-1);
570    
571     /* check that this bay is empty */
572     if (bay->dev_type != NULL) {
573     vm_error(router->vm,"a NM already exists in slot %u.\n",nm_bay);
574     return(-1);
575     }
576    
577     /* find the NM driver */
578     if (!(nm_driver = c2600_nm_get_driver(dev_type))) {
579     vm_error(router->vm,"unknown NM type '%s'.\n",dev_type);
580     return(-1);
581     }
582    
583     bay->dev_type = nm_driver->dev_type;
584     bay->nm_driver = nm_driver;
585     return(0);
586     }
587    
588     /* Remove a NM binding */
589     int c2600_nm_remove_binding(c2600_t *router,u_int nm_bay)
590     {
591     struct c2600_nm_bay *bay;
592    
593     if (!(bay = c2600_nm_get_info(router,nm_bay)))
594     return(-1);
595    
596     /* stop if this bay is still active */
597     if (bay->drv_info != NULL) {
598     vm_error(router->vm,"slot %u still active.\n",nm_bay);
599     return(-1);
600     }
601    
602     /* check that this bay is not empty */
603     if (bay->dev_type == NULL) {
604     vm_error(router->vm,"slot %u is empty.\n",nm_bay);
605     return(-1);
606     }
607    
608     /* remove all NIOs bindings */
609     c2600_nm_remove_all_nio_bindings(router,nm_bay);
610    
611     bay->dev_type = NULL;
612     bay->nm_driver = NULL;
613     return(0);
614     }
615    
616     /* Find a NIO binding */
617     struct c2600_nio_binding *
618     c2600_nm_find_nio_binding(c2600_t *router,u_int nm_bay,u_int port_id)
619     {
620     struct c2600_nio_binding *nb;
621     struct c2600_nm_bay *bay;
622    
623     if (!(bay = c2600_nm_get_info(router,nm_bay)))
624     return NULL;
625    
626     for(nb=bay->nio_list;nb;nb=nb->next)
627     if (nb->port_id == port_id)
628     return nb;
629    
630     return NULL;
631     }
632    
633     /* Add a network IO binding */
634     int c2600_nm_add_nio_binding(c2600_t *router,u_int nm_bay,u_int port_id,
635     char *nio_name)
636     {
637     struct c2600_nio_binding *nb;
638     struct c2600_nm_bay *bay;
639     netio_desc_t *nio;
640    
641     if (!(bay = c2600_nm_get_info(router,nm_bay)))
642     return(-1);
643    
644     /* check that a NIO is not already bound to this port */
645     if (c2600_nm_find_nio_binding(router,nm_bay,port_id) != NULL) {
646     vm_error(router->vm,"a NIO already exists for interface %u/%u.\n",
647     nm_bay,port_id);
648     return(-1);
649     }
650    
651     /* acquire a reference on the NIO object */
652     if (!(nio = netio_acquire(nio_name))) {
653     vm_error(router->vm,"unable to find NIO '%s'.\n",nio_name);
654     return(-1);
655     }
656    
657     /* create a new binding */
658     if (!(nb = malloc(sizeof(*nb)))) {
659     vm_error(router->vm,"unable to create NIO binding "
660     "for interface %u/%u.\n",nm_bay,port_id);
661     netio_release(nio_name);
662     return(-1);
663     }
664    
665     memset(nb,0,sizeof(*nb));
666     nb->nio = nio;
667     nb->port_id = port_id;
668     nb->next = bay->nio_list;
669     if (nb->next) nb->next->prev = nb;
670     bay->nio_list = nb;
671     return(0);
672     }
673    
674     /* Remove a NIO binding */
675     int c2600_nm_remove_nio_binding(c2600_t *router,u_int nm_bay,u_int port_id)
676     {
677     struct c2600_nio_binding *nb;
678     struct c2600_nm_bay *bay;
679    
680     if (!(bay = c2600_nm_get_info(router,nm_bay)))
681     return(-1);
682    
683     if (!(nb = c2600_nm_find_nio_binding(router,nm_bay,port_id)))
684     return(-1); /* no nio binding for this slot/port */
685    
686     /* tell the NM driver to stop using this NIO */
687     if (bay->nm_driver)
688     bay->nm_driver->nm_unset_nio(router,nm_bay,port_id);
689    
690     /* remove this entry from the double linked list */
691     if (nb->next)
692     nb->next->prev = nb->prev;
693    
694     if (nb->prev) {
695     nb->prev->next = nb->next;
696     } else {
697     bay->nio_list = nb->next;
698     }
699    
700     /* unreference NIO object */
701     netio_release(nb->nio->name);
702     free(nb);
703     return(0);
704     }
705    
706     /* Remove all NIO bindings for the specified NM */
707     int c2600_nm_remove_all_nio_bindings(c2600_t *router,u_int nm_bay)
708     {
709     struct c2600_nio_binding *nb,*next;
710     struct c2600_nm_bay *bay;
711    
712     if (!(bay = c2600_nm_get_info(router,nm_bay)))
713     return(-1);
714    
715     for(nb=bay->nio_list;nb;nb=next) {
716     next = nb->next;
717    
718     /* tell the NM driver to stop using this NIO */
719     if (bay->nm_driver)
720     bay->nm_driver->nm_unset_nio(router,nm_bay,nb->port_id);
721    
722     /* unreference NIO object */
723     netio_release(nb->nio->name);
724     free(nb);
725     }
726    
727     bay->nio_list = NULL;
728     return(0);
729     }
730    
731     /* Enable a Network IO descriptor for a Network Module */
732     int c2600_nm_enable_nio(c2600_t *router,u_int nm_bay,u_int port_id)
733     {
734     struct c2600_nio_binding *nb;
735     struct c2600_nm_bay *bay;
736    
737     if (!(bay = c2600_nm_get_info(router,nm_bay)))
738     return(-1);
739    
740     /* check that we have an NIO binding for this interface */
741     if (!(nb = c2600_nm_find_nio_binding(router,nm_bay,port_id)))
742     return(-1);
743    
744     /* check that the driver is defined and successfully initialized */
745     if (!bay->nm_driver || !bay->drv_info)
746     return(-1);
747    
748     return(bay->nm_driver->nm_set_nio(router,nm_bay,port_id,nb->nio));
749     }
750    
751     /* Disable Network IO descriptor of a Network Module */
752     int c2600_nm_disable_nio(c2600_t *router,u_int nm_bay,u_int port_id)
753     {
754     struct c2600_nm_bay *bay;
755    
756     if (!(bay = c2600_nm_get_info(router,nm_bay)))
757     return(-1);
758    
759     /* check that the driver is defined and successfully initialized */
760     if (!bay->nm_driver || !bay->drv_info)
761     return(-1);
762    
763     return(bay->nm_driver->nm_unset_nio(router,nm_bay,port_id));
764     }
765    
766     /* Enable all NIO of the specified NM */
767     int c2600_nm_enable_all_nio(c2600_t *router,u_int nm_bay)
768     {
769     struct c2600_nio_binding *nb;
770     struct c2600_nm_bay *bay;
771    
772     if (!(bay = c2600_nm_get_info(router,nm_bay)))
773     return(-1);
774    
775     /* check that the driver is defined and successfully initialized */
776     if (!bay->nm_driver || !bay->drv_info)
777     return(-1);
778    
779     for(nb=bay->nio_list;nb;nb=nb->next)
780     bay->nm_driver->nm_set_nio(router,nm_bay,nb->port_id,nb->nio);
781    
782     return(0);
783     }
784    
785     /* Disable all NIO of the specified NM */
786     int c2600_nm_disable_all_nio(c2600_t *router,u_int nm_bay)
787     {
788     struct c2600_nio_binding *nb;
789     struct c2600_nm_bay *bay;
790    
791     if (!(bay = c2600_nm_get_info(router,nm_bay)))
792     return(-1);
793    
794     /* check that the driver is defined and successfully initialized */
795     if (!bay->nm_driver || !bay->drv_info)
796     return(-1);
797    
798     for(nb=bay->nio_list;nb;nb=nb->next)
799     bay->nm_driver->nm_unset_nio(router,nm_bay,nb->port_id);
800    
801     return(0);
802     }
803    
804     /* Initialize a Network Module */
805     int c2600_nm_init(c2600_t *router,u_int nm_bay)
806     {
807     struct c2600_nm_bay *bay;
808     size_t len;
809    
810     if (!(bay = c2600_nm_get_info(router,nm_bay)))
811     return(-1);
812    
813     /* Check that a device type is defined for this bay */
814     if (!bay->dev_type || !bay->nm_driver) {
815     vm_error(router->vm,"trying to init empty slot %u.\n",nm_bay);
816     return(-1);
817     }
818    
819     /* Allocate device name */
820     len = strlen(bay->dev_type) + 10;
821     if (!(bay->dev_name = malloc(len))) {
822     vm_error(router->vm,"unable to allocate device name.\n");
823     return(-1);
824     }
825    
826     snprintf(bay->dev_name,len,"%s(%u)",bay->dev_type,nm_bay);
827    
828     /* Initialize NM driver */
829     if (bay->nm_driver->nm_init(router,bay->dev_name,nm_bay) == 1) {
830     vm_error(router->vm,"unable to initialize NM %u.\n",nm_bay);
831     return(-1);
832     }
833    
834     /* Enable all NIO */
835     c2600_nm_enable_all_nio(router,nm_bay);
836     return(0);
837     }
838    
839     /* Shutdown a Network Module */
840     int c2600_nm_shutdown(c2600_t *router,u_int nm_bay)
841     {
842     struct c2600_nm_bay *bay;
843    
844     if (!(bay = c2600_nm_get_info(router,nm_bay)))
845     return(-1);
846    
847     /* Check that a device type is defined for this bay */
848     if (!bay->dev_type || !bay->nm_driver) {
849     vm_error(router->vm,"trying to shut down empty slot %u.\n",nm_bay);
850     return(-1);
851     }
852    
853     /* Disable all NIO */
854     c2600_nm_disable_all_nio(router,nm_bay);
855    
856     /* Shutdown the NM driver */
857     if (bay->drv_info && (bay->nm_driver->nm_shutdown(router,nm_bay) == -1)) {
858     vm_error(router->vm,"unable to shutdown NM %u.\n",nm_bay);
859     return(-1);
860     }
861    
862     free(bay->dev_name);
863     bay->dev_name = NULL;
864     bay->drv_info = NULL;
865     return(0);
866     }
867    
868     /* Shutdown all NM of a router */
869     int c2600_nm_shutdown_all(c2600_t *router)
870     {
871     int i;
872    
873     for(i=0;i<C2600_MAX_NM_BAYS;i++) {
874     if (!router->nm_bay[i].dev_type)
875     continue;
876    
877     c2600_nm_shutdown(router,i);
878     }
879    
880     return(0);
881     }
882    
883     /* Show info about all NMs */
884     int c2600_nm_show_all_info(c2600_t *router)
885     {
886     struct c2600_nm_bay *bay;
887     int i;
888    
889     for(i=0;i<C2600_MAX_NM_BAYS;i++) {
890     if (!(bay = c2600_nm_get_info(router,i)) || !bay->nm_driver)
891     continue;
892    
893     if (bay->nm_driver->nm_show_info != NULL)
894     bay->nm_driver->nm_show_info(router,i);
895     }
896    
897     return(0);
898     }
899    
900     /* Maximum number of tokens in a NM description */
901     #define NM_DESC_MAX_TOKENS 8
902    
903     /* Create a Network Module (command line) */
904     int c2600_cmd_nm_create(c2600_t *router,char *str)
905     {
906     char *tokens[NM_DESC_MAX_TOKENS];
907     int i,count,res;
908     u_int nm_bay;
909    
910     /* A port adapter description is like "1:NM-1FE" */
911     if ((count = m_strsplit(str,':',tokens,NM_DESC_MAX_TOKENS)) != 2) {
912     vm_error(router->vm,"unable to parse NM description '%s'.\n",str);
913     return(-1);
914     }
915    
916     /* Parse the NM bay id */
917     nm_bay = atoi(tokens[0]);
918    
919     /* Add this new NM to the current NM list */
920     res = c2600_nm_add_binding(router,tokens[1],nm_bay);
921    
922     /* The complete array was cleaned by strsplit */
923     for(i=0;i<NM_DESC_MAX_TOKENS;i++)
924     free(tokens[i]);
925    
926     return(res);
927     }
928    
929     /* Add a Network IO descriptor binding (command line) */
930     int c2600_cmd_add_nio(c2600_t *router,char *str)
931     {
932     char *tokens[NM_DESC_MAX_TOKENS];
933     int i,count,nio_type,res=-1;
934     u_int nm_bay,port_id;
935     netio_desc_t *nio;
936     char nio_name[128];
937    
938     /* A port adapter description is like "1:3:tap:tap0" */
939     if ((count = m_strsplit(str,':',tokens,NM_DESC_MAX_TOKENS)) < 3) {
940     vm_error(router->vm,"unable to parse NIO description '%s'.\n",str);
941     return(-1);
942     }
943    
944     /* Parse the NM bay */
945     nm_bay = atoi(tokens[0]);
946    
947     /* Parse the NM port id */
948     port_id = atoi(tokens[1]);
949    
950     /* Autogenerate a NIO name */
951     snprintf(nio_name,sizeof(nio_name),"c2600-i%u/%u/%u",
952     router->vm->instance_id,nm_bay,port_id);
953    
954     /* Create the Network IO descriptor */
955     nio = NULL;
956     nio_type = netio_get_type(tokens[2]);
957    
958     switch(nio_type) {
959     case NETIO_TYPE_UNIX:
960     if (count != 5) {
961     vm_error(router->vm,
962     "invalid number of arguments for UNIX NIO '%s'\n",str);
963     goto done;
964     }
965    
966     nio = netio_desc_create_unix(nio_name,tokens[3],tokens[4]);
967     break;
968    
969     case NETIO_TYPE_VDE:
970     if (count != 5) {
971     vm_error(router->vm,
972     "invalid number of arguments for VDE NIO '%s'\n",str);
973     goto done;
974     }
975    
976     nio = netio_desc_create_vde(nio_name,tokens[3],tokens[4]);
977     break;
978    
979     case NETIO_TYPE_TAP:
980     if (count != 4) {
981     vm_error(router->vm,
982     "invalid number of arguments for TAP NIO '%s'\n",str);
983     goto done;
984     }
985    
986     nio = netio_desc_create_tap(nio_name,tokens[3]);
987     break;
988    
989     case NETIO_TYPE_UDP:
990     if (count != 6) {
991     vm_error(router->vm,
992     "invalid number of arguments for UDP NIO '%s'\n",str);
993     goto done;
994     }
995    
996     nio = netio_desc_create_udp(nio_name,atoi(tokens[3]),
997     tokens[4],atoi(tokens[5]));
998     break;
999    
1000     case NETIO_TYPE_TCP_CLI:
1001     if (count != 5) {
1002     vm_error(router->vm,
1003     "invalid number of arguments for TCP CLI NIO '%s'\n",str);
1004     goto done;
1005     }
1006    
1007     nio = netio_desc_create_tcp_cli(nio_name,tokens[3],tokens[4]);
1008     break;
1009    
1010     case NETIO_TYPE_TCP_SER:
1011     if (count != 4) {
1012     vm_error(router->vm,
1013     "invalid number of arguments for TCP SER NIO '%s'\n",str);
1014     goto done;
1015     }
1016    
1017     nio = netio_desc_create_tcp_ser(nio_name,tokens[3]);
1018     break;
1019    
1020     case NETIO_TYPE_NULL:
1021     nio = netio_desc_create_null(nio_name);
1022     break;
1023    
1024     #ifdef LINUX_ETH
1025     case NETIO_TYPE_LINUX_ETH:
1026     if (count != 4) {
1027     vm_error(router->vm,
1028     "invalid number of arguments for Linux Eth NIO '%s'\n",
1029     str);
1030     goto done;
1031     }
1032    
1033     nio = netio_desc_create_lnxeth(nio_name,tokens[3]);
1034     break;
1035     #endif
1036    
1037     #ifdef GEN_ETH
1038     case NETIO_TYPE_GEN_ETH:
1039     if (count != 4) {
1040     vm_error(router->vm,
1041     "invalid number of arguments for Generic Eth NIO '%s'\n",
1042     str);
1043     goto done;
1044     }
1045    
1046     nio = netio_desc_create_geneth(nio_name,tokens[3]);
1047     break;
1048     #endif
1049    
1050     default:
1051     vm_error(router->vm,"unknown NETIO type '%s'\n",tokens[2]);
1052     goto done;
1053     }
1054    
1055     if (!nio) {
1056     vm_error(router->vm,"unable to create NETIO "
1057     "descriptor for NM slot %u\n",nm_bay);
1058     goto done;
1059     }
1060    
1061     if (c2600_nm_add_nio_binding(router,nm_bay,port_id,nio_name) == -1) {
1062     vm_error(router->vm,"unable to add NETIO binding for slot %u\n",nm_bay);
1063     netio_release(nio_name);
1064     netio_delete(nio_name);
1065     goto done;
1066     }
1067    
1068     netio_release(nio_name);
1069     res = 0;
1070    
1071     done:
1072     /* The complete array was cleaned by strsplit */
1073     for(i=0;i<NM_DESC_MAX_TOKENS;i++)
1074     free(tokens[i]);
1075    
1076     return(res);
1077     }
1078    
1079     /* Show the list of available NM drivers */
1080     void c2600_nm_show_drivers(void)
1081     {
1082     int i;
1083    
1084     printf("Available C2600 Network Module drivers:\n");
1085    
1086     for(i=0;nm_drivers[i];i++) {
1087     printf(" * %s %s\n",
1088     nm_drivers[i]->dev_type,
1089     !nm_drivers[i]->supported ? "(NOT WORKING)" : "");
1090     }
1091    
1092     printf("\n");
1093     }
1094    
1095     /* Set the base MAC address of the chassis */
1096     static int c2600_burn_mac_addr(c2600_t *router,n_eth_addr_t *addr)
1097     {
1098     int i;
1099    
1100     for(i=0;i<3;i++) {
1101     router->vm->chassis_cookie[i+1] = addr->eth_addr_byte[i*2] << 8;
1102     router->vm->chassis_cookie[i+1] |= addr->eth_addr_byte[(i*2)+1];
1103     }
1104    
1105     return(0);
1106     }
1107    
1108     /* Set mainboard type */
1109     int c2600_mainboard_set_type(c2600_t *router,char *mainboard_type)
1110     {
1111     struct c2600_mb_id *mb_info;
1112    
1113     if (router->vm->status == VM_STATUS_RUNNING) {
1114     vm_error(router->vm,"unable to change mainboard type when online.\n");
1115     return(-1);
1116     }
1117    
1118     if (!(mb_info = c2600_get_mb_info(mainboard_type))) {
1119     vm_error(router->vm,"unknown mainboard '%s'\n",mainboard_type);
1120     return(-1);
1121     }
1122    
1123     router->mainboard_type = mainboard_type;
1124    
1125     /* Set the cookie */
1126     memcpy(router->vm->chassis_cookie,
1127     eeprom_c2600_mb_data,sizeof(eeprom_c2600_mb_data));
1128    
1129     router->vm->chassis_cookie[6] = mb_info->id;
1130    
1131     /* Set the chassis base MAC address */
1132     c2600_burn_mac_addr(router,&router->mac_addr);
1133     return(0);
1134     }
1135    
1136     /* Set chassis MAC address */
1137     int c2600_chassis_set_mac_addr(c2600_t *router,char *mac_addr)
1138     {
1139     if (parse_mac_addr(&router->mac_addr,mac_addr) == -1) {
1140     vm_error(router->vm,"unable to parse MAC address '%s'.\n",mac_addr);
1141     return(-1);
1142     }
1143    
1144     /* Set the chassis base MAC address */
1145     c2600_burn_mac_addr(router,&router->mac_addr);
1146     return(0);
1147     }
1148    
1149     /* Initialize a Cisco 2600 */
1150     static int c2600_init(c2600_t *router)
1151     {
1152     vm_instance_t *vm = router->vm;
1153    
1154     /* Create the PCI bus */
1155     if (!(vm->pci_bus[0] = pci_bus_create("PCI0",0))) {
1156     vm_error(vm,"unable to create PCI data.\n");
1157     return(-1);
1158     }
1159    
1160     /* Create the PCI controller */
1161     if (dev_c2600_pci_init(vm,"c2600_pci",C2600_PCICTRL_ADDR,0x1000,
1162     vm->pci_bus[0]) == -1)
1163     return(-1);
1164    
1165     /* Bind PCI bus to slots 0 and 1 */
1166     router->nm_bay[0].pci_map = vm->pci_bus[0];
1167     router->nm_bay[1].pci_map = vm->pci_bus[0];
1168    
1169     vm->elf_machine_id = C2600_ELF_MACHINE_ID;
1170     return(0);
1171     }
1172    
1173     /* Show C2600 hardware info */
1174     void c2600_show_hardware(c2600_t *router)
1175     {
1176     vm_instance_t *vm = router->vm;
1177    
1178     printf("C2600 instance '%s' (id %d):\n",vm->name,vm->instance_id);
1179    
1180     printf(" VM Status : %d\n",vm->status);
1181     printf(" RAM size : %u Mb\n",vm->ram_size);
1182     printf(" NVRAM size : %u Kb\n",vm->nvram_size);
1183     printf(" IOS image : %s\n\n",vm->ios_image);
1184    
1185     if (vm->debug_level > 0) {
1186     dev_show_list(vm);
1187     pci_dev_show_list(vm->pci_bus[0]);
1188     pci_dev_show_list(vm->pci_bus[1]);
1189     printf("\n");
1190     }
1191     }
1192    
1193     /* Initialize default parameters for a C2600 */
1194     void c2600_init_defaults(c2600_t *router)
1195     {
1196     vm_instance_t *vm = router->vm;
1197     n_eth_addr_t *m;
1198     m_uint16_t pid;
1199    
1200     pid = (m_uint16_t)getpid();
1201    
1202     /* Generate a chassis MAC address based on the instance ID */
1203     m = &router->mac_addr;
1204     m->eth_addr_byte[0] = vm_get_mac_addr_msb(vm);
1205     m->eth_addr_byte[1] = vm->instance_id & 0xFF;
1206     m->eth_addr_byte[2] = pid >> 8;
1207     m->eth_addr_byte[3] = pid & 0xFF;
1208     m->eth_addr_byte[4] = 0x00;
1209     m->eth_addr_byte[5] = 0x00;
1210    
1211     c2600_init_eeprom_groups(router);
1212     c2600_mainboard_set_type(router,C2600_DEFAULT_MAINBOARD);
1213     c2600_burn_mac_addr(router,&router->mac_addr);
1214    
1215     vm->ram_mmap = C2600_DEFAULT_RAM_MMAP;
1216     vm->ram_size = C2600_DEFAULT_RAM_SIZE;
1217     vm->rom_size = C2600_DEFAULT_ROM_SIZE;
1218     vm->nvram_size = C2600_DEFAULT_NVRAM_SIZE;
1219     vm->conf_reg_setup = C2600_DEFAULT_CONF_REG;
1220     vm->clock_divisor = C2600_DEFAULT_CLOCK_DIV;
1221     vm->nvram_rom_space = C2600_NVRAM_ROM_RES_SIZE;
1222     router->nm_iomem_size = C2600_DEFAULT_IOMEM_SIZE;
1223    
1224     vm->pcmcia_disk_size[0] = C2600_DEFAULT_DISK0_SIZE;
1225     vm->pcmcia_disk_size[1] = C2600_DEFAULT_DISK1_SIZE;
1226    
1227     /* Enable NVRAM operations to load/store configs */
1228     vm->nvram_extract_config = c2600_nvram_extract_config;
1229     vm->nvram_push_config = c2600_nvram_push_config;
1230     }
1231    
1232     /* Set an IRQ */
1233     static void c2600_set_irq(vm_instance_t *vm,u_int irq)
1234     {
1235     c2600_t *router = VM_C2600(vm);
1236     cpu_ppc_t *cpu = CPU_PPC32(vm->boot_cpu);
1237    
1238     switch(irq) {
1239     case C2600_VTIMER_IRQ:
1240     mpc860_set_pending_irq(router->mpc_data,30);
1241     break;
1242     case C2600_DUART_IRQ:
1243     mpc860_set_pending_irq(router->mpc_data,29);
1244     break;
1245     case C2600_NETIO_IRQ:
1246     mpc860_set_pending_irq(router->mpc_data,25);
1247     break;
1248     case C2600_PA_MGMT_IRQ:
1249     mpc860_set_pending_irq(router->mpc_data,27);
1250     break;
1251    
1252     /* IRQ test */
1253     case 255:
1254     mpc860_set_pending_irq(router->mpc_data,24);
1255     break;
1256     }
1257    
1258     if (cpu->irq_idle_preempt[irq])
1259     cpu_idle_break_wait(cpu->gen);
1260     }
1261    
1262     /* Clear an IRQ */
1263     static void c2600_clear_irq(vm_instance_t *vm,u_int irq)
1264     {
1265     c2600_t *router = VM_C2600(vm);
1266    
1267     switch(irq) {
1268     case C2600_VTIMER_IRQ:
1269     mpc860_clear_pending_irq(router->mpc_data,30);
1270     break;
1271     case C2600_DUART_IRQ:
1272     mpc860_clear_pending_irq(router->mpc_data,29);
1273     break;
1274     case C2600_NETIO_IRQ:
1275     mpc860_clear_pending_irq(router->mpc_data,25);
1276     break;
1277     case C2600_PA_MGMT_IRQ:
1278     mpc860_clear_pending_irq(router->mpc_data,27);
1279     break;
1280    
1281     /* IRQ test */
1282     case 255:
1283     mpc860_clear_pending_irq(router->mpc_data,24);
1284     break;
1285     }
1286     }
1287    
1288     /* Initialize the C2600 Platform */
1289     int c2600_init_platform(c2600_t *router)
1290     {
1291     vm_instance_t *vm = router->vm;
1292     struct c2600_mb_id *mb_info;
1293     struct c2600_nm_bay *nm_bay;
1294     vm_obj_t *obj;
1295     cpu_ppc_t *cpu;
1296     cpu_gen_t *gen;
1297     int i;
1298    
1299     /* Copy config register setup into "active" config register */
1300     vm->conf_reg = vm->conf_reg_setup;
1301    
1302     /* Create Console and AUX ports */
1303     vm_init_vtty(vm);
1304    
1305     /* Create a CPU group */
1306     vm->cpu_group = cpu_group_create("System CPU");
1307    
1308     /* Initialize the virtual PowerPC processor */
1309     if (!(gen = cpu_create(vm,CPU_TYPE_PPC32,0))) {
1310     vm_error(vm,"unable to create CPU!\n");
1311     return(-1);
1312     }
1313    
1314     cpu = CPU_PPC32(gen);
1315    
1316     /* Add this CPU to the system CPU group */
1317     cpu_group_add(vm->cpu_group,gen);
1318     vm->boot_cpu = gen;
1319    
1320     /* Set processor ID */
1321     ppc32_set_pvr(cpu,0x00500202);
1322    
1323     /* Mark the Network IO interrupt as high priority */
1324     cpu->irq_idle_preempt[C2600_NETIO_IRQ] = TRUE;
1325     cpu->irq_idle_preempt[C2600_DUART_IRQ] = TRUE;
1326    
1327     /* Copy some parameters from VM to CPU (idle PC, ...) */
1328     cpu->idle_pc = vm->idle_pc;
1329    
1330     if (vm->timer_irq_check_itv)
1331     cpu->timer_irq_check_itv = vm->timer_irq_check_itv;
1332    
1333     /* Remote emulator control */
1334     dev_remote_control_init(vm,0xf6000000,0x1000);
1335    
1336     /* MPC860 */
1337     if (dev_mpc860_init(vm,"MPC860",C2600_MPC860_ADDR,0x10000) == -1)
1338     return(-1);
1339    
1340     if (!(obj = vm_object_find(router->vm,"MPC860")))
1341     return(-1);
1342    
1343     router->mpc_data = obj->data;
1344    
1345     /* IO FPGA */
1346     if (dev_c2600_iofpga_init(router,C2600_IOFPGA_ADDR,0x10000) == -1)
1347     return(-1);
1348    
1349     /* Initialize the chassis */
1350     if (c2600_init(router) == -1)
1351     return(-1);
1352    
1353     /* Initialize RAM */
1354     vm_ram_init(vm,0x00000000ULL);
1355    
1356     /* Initialize ROM */
1357     if (!vm->rom_filename) {
1358     /* use embedded ROM */
1359     dev_rom_init(vm,"rom",C2600_ROM_ADDR,512*1024,
1360     ppc32_microcode,ppc32_microcode_len);
1361     } else {
1362     /* use alternate ROM */
1363     dev_ram_init(vm,"rom",TRUE,TRUE,NULL,FALSE,C2600_ROM_ADDR,512*1024);
1364     }
1365    
1366     /* RAM aliasing */
1367     dev_create_ram_alias(vm,"ram_alias","ram",0x80000000,vm->ram_size*1048576);
1368    
1369     /* NVRAM */
1370     dev_ram_init(vm,"nvram",TRUE,FALSE,NULL,FALSE,
1371     C2600_NVRAM_ADDR,vm->nvram_size*4096);
1372     c2600_nvram_check_empty_config(vm);
1373    
1374     /* Bootflash */
1375     dev_bootflash_init(vm,"flash0",C2600_FLASH_ADDR,8*1048576);
1376     dev_bootflash_init(vm,"flash1",C2600_FLASH_ADDR+0x800000,8*1048576);
1377    
1378     /* Initialize the NS16552 DUART */
1379     dev_ns16552_init(vm,C2600_DUART_ADDR,0x1000,0,C2600_DUART_IRQ,
1380     vm->vtty_con,vm->vtty_aux);
1381    
1382     /* Initialize the mainboard ports */
1383     if ((mb_info = c2600_get_mb_info(router->mainboard_type)) != NULL)
1384     c2600_nm_add_binding(router,mb_info->mb_driver,0);
1385    
1386     /* Initialize Network Modules */
1387     for(i=0;i<C2600_MAX_NM_BAYS;i++) {
1388     nm_bay = &router->nm_bay[i];
1389    
1390     if (!nm_bay->dev_type)
1391     continue;
1392    
1393     if (c2600_nm_init(router,i) == -1) {
1394     vm_error(vm,"unable to create Network Module \"%s\"\n",
1395     nm_bay->dev_type);
1396     return(-1);
1397     }
1398     }
1399    
1400     /* Show device list */
1401     c2600_show_hardware(router);
1402     return(0);
1403     }
1404    
1405     static struct ppc32_bat_prog bat_array[] = {
1406     { PPC32_IBAT_IDX, 0, 0xfff0001e, 0xfff00001 },
1407     { PPC32_IBAT_IDX, 1, 0x00001ffe, 0x00000001 },
1408     { PPC32_IBAT_IDX, 2, 0x00000000, 0xee3e0072 },
1409     { PPC32_IBAT_IDX, 3, 0x80001ffe, 0x80000001 },
1410    
1411     { PPC32_DBAT_IDX, 0, 0x80001ffe, 0x80000042 },
1412     { PPC32_DBAT_IDX, 1, 0x00001ffe, 0x0000002a },
1413     { PPC32_DBAT_IDX, 2, 0x40007ffe, 0x4000002a },
1414     { PPC32_DBAT_IDX, 3, 0xfc0007fe, 0xfc00002a },
1415     { -1, -1, 0, 0 },
1416     };
1417    
1418     /* Boot the IOS image */
1419     int c2600_boot_ios(c2600_t *router)
1420     {
1421     vm_instance_t *vm = router->vm;
1422     cpu_ppc_t *cpu;
1423    
1424     if (!vm->boot_cpu)
1425     return(-1);
1426    
1427     /* Suspend CPU activity since we will restart directly from ROM */
1428     vm_suspend(vm);
1429    
1430     /* Check that CPU activity is really suspended */
1431     if (cpu_group_sync_state(vm->cpu_group) == -1) {
1432     vm_error(vm,"unable to sync with system CPUs.\n");
1433     return(-1);
1434     }
1435    
1436     /* Reset the boot CPU */
1437     cpu = CPU_PPC32(vm->boot_cpu);
1438     ppc32_reset(cpu);
1439    
1440     /* Adjust stack pointer */
1441     cpu->gpr[1] |= 0x80000000;
1442    
1443     /* Load BAT registers */
1444     printf("Loading BAT registers\n");
1445     ppc32_load_bat_array(CPU_PPC32(vm->boot_cpu),bat_array);
1446    
1447     /* IRQ routing */
1448     vm->set_irq = c2600_set_irq;
1449     vm->clear_irq = c2600_clear_irq;
1450    
1451     /* Load IOS image */
1452     if (ppc32_load_elf_image(cpu,vm->ios_image,
1453     (vm->ghost_status == VM_GHOST_RAM_USE),
1454     &vm->ios_entry_point) < 0)
1455     {
1456     vm_error(vm,"failed to load Cisco IOS image '%s'.\n",vm->ios_image);
1457     return(-1);
1458     }
1459    
1460     /* Launch the simulation */
1461     printf("\nC2600 '%s': starting simulation (CPU0 IA=0x%8.8x), "
1462     "JIT %sabled.\n",
1463     vm->name,cpu->ia,vm->jit_use ? "en":"dis");
1464    
1465     vm_log(vm,"C2600_BOOT",
1466     "starting instance (CPU0 PC=0x%8.8x,idle_pc=0x%8.8x,JIT %s)\n",
1467     cpu->ia,cpu->idle_pc,vm->jit_use ? "on":"off");
1468    
1469     /* Start main CPU */
1470     if (vm->ghost_status != VM_GHOST_RAM_GENERATE) {
1471     vm->status = VM_STATUS_RUNNING;
1472     cpu_start(vm->boot_cpu);
1473     } else {
1474     vm->status = VM_STATUS_SHUTDOWN;
1475     }
1476     return(0);
1477     }
1478    
1479     /* Initialize a Cisco 2600 instance */
1480     int c2600_init_instance(c2600_t *router)
1481     {
1482     vm_instance_t *vm = router->vm;
1483     m_uint32_t rom_entry_point;
1484     cpu_ppc_t *cpu0;
1485    
1486     if (!vm->ios_image) {
1487     vm_error(vm,"no Cisco IOS image defined.");
1488     return(-1);
1489     }
1490    
1491     /* Initialize the C2600 platform */
1492     if (c2600_init_platform(router) == -1) {
1493     vm_error(vm,"unable to initialize the platform hardware.\n");
1494     return(-1);
1495     }
1496    
1497     /* Load IOS configuration file */
1498     if (vm->ios_config != NULL) {
1499     vm_nvram_push_config(vm,vm->ios_config);
1500     vm->conf_reg &= ~0x40;
1501     }
1502    
1503     /* Load ROM (ELF image or embedded) */
1504     cpu0 = CPU_PPC32(vm->boot_cpu);
1505     rom_entry_point = (m_uint32_t)PPC32_ROM_START;
1506    
1507     if ((vm->rom_filename != NULL) &&
1508     (ppc32_load_elf_image(cpu0,vm->rom_filename,0,&rom_entry_point) < 0))
1509     {
1510     vm_error(vm,"unable to load alternate ROM '%s', "
1511     "fallback to embedded ROM.\n\n",vm->rom_filename);
1512     vm->rom_filename = NULL;
1513     }
1514    
1515     return(c2600_boot_ios(router));
1516     }
1517    
1518     /* Stop a Cisco 2600 instance */
1519     int c2600_stop_instance(c2600_t *router)
1520     {
1521     vm_instance_t *vm = router->vm;
1522    
1523     printf("\nC2600 '%s': stopping simulation.\n",vm->name);
1524     vm_log(vm,"C2600_STOP","stopping simulation.\n");
1525    
1526     /* Stop all CPUs */
1527     if (vm->cpu_group != NULL) {
1528     vm_stop(vm);
1529    
1530     if (cpu_group_sync_state(vm->cpu_group) == -1) {
1531     vm_error(vm,"unable to sync with system CPUs.\n");
1532     return(-1);
1533     }
1534     }
1535    
1536     /* Free resources that were used during execution to emulate hardware */
1537     c2600_nm_shutdown_all(router);
1538     vm_hardware_shutdown(vm);
1539     return(0);
1540     }

  ViewVC Help
Powered by ViewVC 1.1.26