/[dynamips]/trunk/dev_c3745.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_c3745.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (hide annotations)
Sat Oct 6 16:29:14 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7/dev_c3745.c
File MIME type: text/plain
File size: 39268 byte(s)
dynamips-0.2.7

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

  ViewVC Help
Powered by ViewVC 1.1.26