/[dynamips]/upstream/dynamips-0.2.7-RC2/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 /upstream/dynamips-0.2.7-RC2/dev_c2600.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
File MIME type: text/plain
File size: 41872 byte(s)
dynamips-0.2.7-RC2

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

  ViewVC Help
Powered by ViewVC 1.1.26