/[dynamips]/upstream/dynamips-0.2.7-RC1/dev_c2691.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

Contents of /upstream/dynamips-0.2.7-RC1/dev_c2691.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (show annotations)
Sat Oct 6 16:23:47 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 35263 byte(s)
dynamips-0.2.7-RC1

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

  ViewVC Help
Powered by ViewVC 1.1.26