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

Parent Directory Parent Directory | Revision Log Revision Log


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

1 /*
2 * Cisco 3725 simulation platform.
3 * Copyright (c) 2006 Christophe Fillot (cf@utc.fr)
4 *
5 * Generic Cisco 3725 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_c3725.h"
25 #include "dev_vtty.h"
26 #include "registry.h"
27
28 /* ======================================================================== */
29 /* EEPROM definitions */
30 /* ======================================================================== */
31
32 /* Cisco 3725 mainboard EEPROM */
33 static m_uint16_t eeprom_c3725_mainboard_data[] = {
34 0x04FF, 0xC18B, 0x5858, 0x5858, 0x5858, 0x5858, 0x5858, 0x5809,
35 0x6140, 0x0259, 0xC046, 0x0320, 0x003F, 0x1302, 0x4244, 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, 0x1319, 0x5C6F,
39 0x7043, 0x0030, 0xC508, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x4100,
40 0x0101, 0x02FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
41 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
42 };
43
44 struct cisco_eeprom eeprom_c3725_mainboard = {
45 "C3725 Backplane",
46 eeprom_c3725_mainboard_data,
47 sizeof(eeprom_c3725_mainboard_data)/2,
48 };
49
50 /* ======================================================================== */
51 /* Network Module Drivers */
52 /* ======================================================================== */
53 static struct c3725_nm_driver *nm_drivers[] = {
54 &dev_c3725_nm_1fe_tx_driver,
55 &dev_c3725_nm_16esw_driver,
56 &dev_c3725_gt96100_fe_driver,
57 &dev_c3725_nm_4t_driver,
58 NULL,
59 };
60
61 /* ======================================================================== */
62 /* Cisco 3725 router instances */
63 /* ======================================================================== */
64
65 /* Directly extract the configuration from the NVRAM device */
66 ssize_t c3725_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 + C3725_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 c3725_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 = C3725_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 c3725_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 + C3725_NVRAM_OFFSET;
167
168 /* Normal config */
169 c3725_nvram_push_config_part(vm,buffer,len,ios_ptr);
170
171 /* Backup config */
172 c3725_nvram_push_config_part(vm,buffer,len,ios_ptr + C3725_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 c3725_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 + C3725_NVRAM_OFFSET;
189 len = C3725_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 c3725_t *c3725_create_instance(char *name,int instance_id)
207 {
208 c3725_t *router;
209
210 if (!(router = malloc(sizeof(*router)))) {
211 fprintf(stderr,"C3725 '%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_C3725))) {
218 fprintf(stderr,"C3725 '%s': unable to create VM instance!\n",name);
219 goto err_vm;
220 }
221
222 c3725_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 c3725_free_instance(void *data,void *arg)
233 {
234 vm_instance_t *vm = data;
235 c3725_t *router;
236 int i;
237
238 if (vm->type == VM_TYPE_C3725) {
239 router = VM_C3725(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<C3725_MAX_NM_BAYS;i++)
253 c3725_nm_remove_all_nio_bindings(router,i);
254
255 /* Shutdown all Network Modules */
256 c3725_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 c3725_delete_instance(char *name)
274 {
275 return(registry_delete_if_unused(name,OBJ_TYPE_VM,
276 c3725_free_instance,NULL));
277 }
278
279 /* Delete all router instances */
280 int c3725_delete_all_instances(void)
281 {
282 return(registry_delete_type(OBJ_TYPE_VM,c3725_free_instance,NULL));
283 }
284
285 /* Save configuration of a C3725 instance */
286 void c3725_save_config(c3725_t *router,FILE *fd)
287 {
288 vm_instance_t *vm = router->vm;
289 struct c3725_nio_binding *nb;
290 struct c3725_nm_bay *bay;
291 int i;
292
293 /* General settings */
294 fprintf(fd,"c3725 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<C3725_MAX_NM_BAYS;i++) {
301 if (!(bay = c3725_nm_get_info(router,i)))
302 continue;
303
304 if (bay->dev_type) {
305 fprintf(fd,"c3725 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,"c3725 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 C3725 instances */
319 static void c3725_reg_save_config(registry_entry_t *entry,void *opt,int *err)
320 {
321 vm_instance_t *vm = entry->data;
322 c3725_t *router = VM_C3725(vm);
323
324 if (vm->type == VM_TYPE_C3725)
325 c3725_save_config(router,(FILE *)opt);
326 }
327
328 void c3725_save_config_all(FILE *fd)
329 {
330 registry_foreach_type(OBJ_TYPE_VM,c3725_reg_save_config,fd,NULL);
331 }
332
333 /* Get PCI device for the specified NM bay */
334 int c3725_nm_get_pci_device(u_int nm_bay)
335 {
336 switch(nm_bay) {
337 case 1:
338 return(0x06);
339 case 2:
340 return(0x0A);
341 default:
342 return(-1);
343 }
344 }
345
346 /* Set NM EEPROM definition */
347 int c3725_nm_set_eeprom(c3725_t *router,u_int nm_bay,
348 const struct cisco_eeprom *eeprom)
349 {
350 if (!nm_bay || (nm_bay >= C3725_MAX_NM_BAYS)) {
351 vm_error(router->vm,"c3725_nm_set_eeprom: invalid NM Bay %u.\n",nm_bay);
352 return(-1);
353 }
354
355 if (cisco_eeprom_copy(&router->nm_bay[nm_bay].eeprom,eeprom) == -1) {
356 vm_error(router->vm,"c3725_nm_set_eeprom: no memory.\n");
357 return(-1);
358 }
359
360 return(0);
361 }
362
363 /* Unset NM EEPROM definition (empty bay) */
364 int c3725_nm_unset_eeprom(c3725_t *router,u_int nm_bay)
365 {
366 if (!nm_bay || (nm_bay >= C3725_MAX_NM_BAYS)) {
367 vm_error(router->vm,"c3725_nm_set_eeprom: invalid NM Bay %u.\n",nm_bay);
368 return(-1);
369 }
370
371 cisco_eeprom_free(&router->nm_bay[nm_bay].eeprom);
372 return(0);
373 }
374
375 /* Check if a bay has a port adapter */
376 int c3725_nm_check_eeprom(c3725_t *router,u_int nm_bay)
377 {
378 if (!nm_bay || (nm_bay >= C3725_MAX_NM_BAYS))
379 return(FALSE);
380
381 return(cisco_eeprom_valid(&router->nm_bay[nm_bay].eeprom));
382 }
383
384 /* Get bay info */
385 struct c3725_nm_bay *c3725_nm_get_info(c3725_t *router,u_int nm_bay)
386 {
387 if (nm_bay >= C3725_MAX_NM_BAYS)
388 return NULL;
389
390 return(&router->nm_bay[nm_bay]);
391 }
392
393 /* Get NM type */
394 char *c3725_nm_get_type(c3725_t *router,u_int nm_bay)
395 {
396 struct c3725_nm_bay *bay;
397
398 bay = c3725_nm_get_info(router,nm_bay);
399 return((bay != NULL) ? bay->dev_type : NULL);
400 }
401
402 /* Get driver info about the specified slot */
403 void *c3725_nm_get_drvinfo(c3725_t *router,u_int nm_bay)
404 {
405 struct c3725_nm_bay *bay;
406
407 bay = c3725_nm_get_info(router,nm_bay);
408 return((bay != NULL) ? bay->drv_info : NULL);
409 }
410
411 /* Set driver info for the specified slot */
412 int c3725_nm_set_drvinfo(c3725_t *router,u_int nm_bay,void *drv_info)
413 {
414 struct c3725_nm_bay *bay;
415
416 if (!(bay = c3725_nm_get_info(router,nm_bay)))
417 return(-1);
418
419 bay->drv_info = drv_info;
420 return(0);
421 }
422
423 /* Get a NM driver */
424 static struct c3725_nm_driver *c3725_nm_get_driver(char *dev_type)
425 {
426 int i;
427
428 for(i=0;nm_drivers[i];i++)
429 if (!strcmp(nm_drivers[i]->dev_type,dev_type))
430 return nm_drivers[i];
431
432 return NULL;
433 }
434
435 /* Add a NM binding */
436 int c3725_nm_add_binding(c3725_t *router,char *dev_type,u_int nm_bay)
437 {
438 struct c3725_nm_driver *nm_driver;
439 struct c3725_nm_bay *bay;
440
441 if (!(bay = c3725_nm_get_info(router,nm_bay)))
442 return(-1);
443
444 /* check that this bay is empty */
445 if (bay->dev_type != NULL) {
446 vm_error(router->vm,"a NM already exists in slot %u.\n",nm_bay);
447 return(-1);
448 }
449
450 /* find the NM driver */
451 if (!(nm_driver = c3725_nm_get_driver(dev_type))) {
452 vm_error(router->vm,"unknown NM type '%s'.\n",dev_type);
453 return(-1);
454 }
455
456 bay->dev_type = nm_driver->dev_type;
457 bay->nm_driver = nm_driver;
458 return(0);
459 }
460
461 /* Remove a NM binding */
462 int c3725_nm_remove_binding(c3725_t *router,u_int nm_bay)
463 {
464 struct c3725_nm_bay *bay;
465
466 if (!(bay = c3725_nm_get_info(router,nm_bay)))
467 return(-1);
468
469 /* stop if this bay is still active */
470 if (bay->drv_info != NULL) {
471 vm_error(router->vm,"slot %u still active.\n",nm_bay);
472 return(-1);
473 }
474
475 /* check that this bay is not empty */
476 if (bay->dev_type == NULL) {
477 vm_error(router->vm,"slot %u is empty.\n",nm_bay);
478 return(-1);
479 }
480
481 /* remove all NIOs bindings */
482 c3725_nm_remove_all_nio_bindings(router,nm_bay);
483
484 bay->dev_type = NULL;
485 bay->nm_driver = NULL;
486 return(0);
487 }
488
489 /* Find a NIO binding */
490 struct c3725_nio_binding *
491 c3725_nm_find_nio_binding(c3725_t *router,u_int nm_bay,u_int port_id)
492 {
493 struct c3725_nio_binding *nb;
494 struct c3725_nm_bay *bay;
495
496 if (!(bay = c3725_nm_get_info(router,nm_bay)))
497 return NULL;
498
499 for(nb=bay->nio_list;nb;nb=nb->next)
500 if (nb->port_id == port_id)
501 return nb;
502
503 return NULL;
504 }
505
506 /* Add a network IO binding */
507 int c3725_nm_add_nio_binding(c3725_t *router,u_int nm_bay,u_int port_id,
508 char *nio_name)
509 {
510 struct c3725_nio_binding *nb;
511 struct c3725_nm_bay *bay;
512 netio_desc_t *nio;
513
514 if (!(bay = c3725_nm_get_info(router,nm_bay)))
515 return(-1);
516
517 /* check that a NIO is not already bound to this port */
518 if (c3725_nm_find_nio_binding(router,nm_bay,port_id) != NULL) {
519 vm_error(router->vm,"a NIO already exists for interface %u/%u.\n",
520 nm_bay,port_id);
521 return(-1);
522 }
523
524 /* acquire a reference on the NIO object */
525 if (!(nio = netio_acquire(nio_name))) {
526 vm_error(router->vm,"unable to find NIO '%s'.\n",nio_name);
527 return(-1);
528 }
529
530 /* create a new binding */
531 if (!(nb = malloc(sizeof(*nb)))) {
532 vm_error(router->vm,"unable to create NIO binding "
533 "for interface %u/%u.\n",nm_bay,port_id);
534 netio_release(nio_name);
535 return(-1);
536 }
537
538 memset(nb,0,sizeof(*nb));
539 nb->nio = nio;
540 nb->port_id = port_id;
541 nb->next = bay->nio_list;
542 if (nb->next) nb->next->prev = nb;
543 bay->nio_list = nb;
544 return(0);
545 }
546
547 /* Remove a NIO binding */
548 int c3725_nm_remove_nio_binding(c3725_t *router,u_int nm_bay,u_int port_id)
549 {
550 struct c3725_nio_binding *nb;
551 struct c3725_nm_bay *bay;
552
553 if (!(bay = c3725_nm_get_info(router,nm_bay)))
554 return(-1);
555
556 if (!(nb = c3725_nm_find_nio_binding(router,nm_bay,port_id)))
557 return(-1); /* no nio binding for this slot/port */
558
559 /* tell the NM driver to stop using this NIO */
560 if (bay->nm_driver)
561 bay->nm_driver->nm_unset_nio(router,nm_bay,port_id);
562
563 /* remove this entry from the double linked list */
564 if (nb->next)
565 nb->next->prev = nb->prev;
566
567 if (nb->prev) {
568 nb->prev->next = nb->next;
569 } else {
570 bay->nio_list = nb->next;
571 }
572
573 /* unreference NIO object */
574 netio_release(nb->nio->name);
575 free(nb);
576 return(0);
577 }
578
579 /* Remove all NIO bindings for the specified NM */
580 int c3725_nm_remove_all_nio_bindings(c3725_t *router,u_int nm_bay)
581 {
582 struct c3725_nio_binding *nb,*next;
583 struct c3725_nm_bay *bay;
584
585 if (!(bay = c3725_nm_get_info(router,nm_bay)))
586 return(-1);
587
588 for(nb=bay->nio_list;nb;nb=next) {
589 next = nb->next;
590
591 /* tell the NM driver to stop using this NIO */
592 if (bay->nm_driver)
593 bay->nm_driver->nm_unset_nio(router,nm_bay,nb->port_id);
594
595 /* unreference NIO object */
596 netio_release(nb->nio->name);
597 free(nb);
598 }
599
600 bay->nio_list = NULL;
601 return(0);
602 }
603
604 /* Enable a Network IO descriptor for a Network Module */
605 int c3725_nm_enable_nio(c3725_t *router,u_int nm_bay,u_int port_id)
606 {
607 struct c3725_nio_binding *nb;
608 struct c3725_nm_bay *bay;
609
610 if (!(bay = c3725_nm_get_info(router,nm_bay)))
611 return(-1);
612
613 /* check that we have an NIO binding for this interface */
614 if (!(nb = c3725_nm_find_nio_binding(router,nm_bay,port_id)))
615 return(-1);
616
617 /* check that the driver is defined and successfully initialized */
618 if (!bay->nm_driver || !bay->drv_info)
619 return(-1);
620
621 return(bay->nm_driver->nm_set_nio(router,nm_bay,port_id,nb->nio));
622 }
623
624 /* Disable Network IO descriptor of a Network Module */
625 int c3725_nm_disable_nio(c3725_t *router,u_int nm_bay,u_int port_id)
626 {
627 struct c3725_nm_bay *bay;
628
629 if (!(bay = c3725_nm_get_info(router,nm_bay)))
630 return(-1);
631
632 /* check that the driver is defined and successfully initialized */
633 if (!bay->nm_driver || !bay->drv_info)
634 return(-1);
635
636 return(bay->nm_driver->nm_unset_nio(router,nm_bay,port_id));
637 }
638
639 /* Enable all NIO of the specified NM */
640 int c3725_nm_enable_all_nio(c3725_t *router,u_int nm_bay)
641 {
642 struct c3725_nio_binding *nb;
643 struct c3725_nm_bay *bay;
644
645 if (!(bay = c3725_nm_get_info(router,nm_bay)))
646 return(-1);
647
648 /* check that the driver is defined and successfully initialized */
649 if (!bay->nm_driver || !bay->drv_info)
650 return(-1);
651
652 for(nb=bay->nio_list;nb;nb=nb->next)
653 bay->nm_driver->nm_set_nio(router,nm_bay,nb->port_id,nb->nio);
654
655 return(0);
656 }
657
658 /* Disable all NIO of the specified NM */
659 int c3725_nm_disable_all_nio(c3725_t *router,u_int nm_bay)
660 {
661 struct c3725_nio_binding *nb;
662 struct c3725_nm_bay *bay;
663
664 if (!(bay = c3725_nm_get_info(router,nm_bay)))
665 return(-1);
666
667 /* check that the driver is defined and successfully initialized */
668 if (!bay->nm_driver || !bay->drv_info)
669 return(-1);
670
671 for(nb=bay->nio_list;nb;nb=nb->next)
672 bay->nm_driver->nm_unset_nio(router,nm_bay,nb->port_id);
673
674 return(0);
675 }
676
677 /* Initialize a Network Module */
678 int c3725_nm_init(c3725_t *router,u_int nm_bay)
679 {
680 struct c3725_nm_bay *bay;
681 size_t len;
682
683 if (!(bay = c3725_nm_get_info(router,nm_bay)))
684 return(-1);
685
686 /* Check that a device type is defined for this bay */
687 if (!bay->dev_type || !bay->nm_driver) {
688 vm_error(router->vm,"trying to init empty slot %u.\n",nm_bay);
689 return(-1);
690 }
691
692 /* Allocate device name */
693 len = strlen(bay->dev_type) + 10;
694 if (!(bay->dev_name = malloc(len))) {
695 vm_error(router->vm,"unable to allocate device name.\n");
696 return(-1);
697 }
698
699 snprintf(bay->dev_name,len,"%s(%u)",bay->dev_type,nm_bay);
700
701 /* Initialize NM driver */
702 if (bay->nm_driver->nm_init(router,bay->dev_name,nm_bay) == 1) {
703 vm_error(router->vm,"unable to initialize NM %u.\n",nm_bay);
704 return(-1);
705 }
706
707 /* Enable all NIO */
708 c3725_nm_enable_all_nio(router,nm_bay);
709 return(0);
710 }
711
712 /* Shutdown a Network Module */
713 int c3725_nm_shutdown(c3725_t *router,u_int nm_bay)
714 {
715 struct c3725_nm_bay *bay;
716
717 if (!(bay = c3725_nm_get_info(router,nm_bay)))
718 return(-1);
719
720 /* Check that a device type is defined for this bay */
721 if (!bay->dev_type || !bay->nm_driver) {
722 vm_error(router->vm,"trying to shut down empty slot %u.\n",nm_bay);
723 return(-1);
724 }
725
726 /* Disable all NIO */
727 c3725_nm_disable_all_nio(router,nm_bay);
728
729 /* Shutdown the NM driver */
730 if (bay->drv_info && (bay->nm_driver->nm_shutdown(router,nm_bay) == -1)) {
731 vm_error(router->vm,"unable to shutdown NM %u.\n",nm_bay);
732 return(-1);
733 }
734
735 free(bay->dev_name);
736 bay->dev_name = NULL;
737 bay->drv_info = NULL;
738 return(0);
739 }
740
741 /* Shutdown all NM of a router */
742 int c3725_nm_shutdown_all(c3725_t *router)
743 {
744 int i;
745
746 for(i=0;i<C3725_MAX_NM_BAYS;i++) {
747 if (!router->nm_bay[i].dev_type)
748 continue;
749
750 c3725_nm_shutdown(router,i);
751 }
752
753 return(0);
754 }
755
756 /* Show info about all NMs */
757 int c3725_nm_show_all_info(c3725_t *router)
758 {
759 struct c3725_nm_bay *bay;
760 int i;
761
762 for(i=0;i<C3725_MAX_NM_BAYS;i++) {
763 if (!(bay = c3725_nm_get_info(router,i)) || !bay->nm_driver)
764 continue;
765
766 if (bay->nm_driver->nm_show_info != NULL)
767 bay->nm_driver->nm_show_info(router,i);
768 }
769
770 return(0);
771 }
772
773 /* Maximum number of tokens in a NM description */
774 #define NM_DESC_MAX_TOKENS 8
775
776 /* Create a Network Module (command line) */
777 int c3725_cmd_nm_create(c3725_t *router,char *str)
778 {
779 char *tokens[NM_DESC_MAX_TOKENS];
780 int i,count,res;
781 u_int nm_bay;
782
783 /* A port adapter description is like "1:NM-1FE" */
784 if ((count = m_strsplit(str,':',tokens,NM_DESC_MAX_TOKENS)) != 2) {
785 vm_error(router->vm,"unable to parse NM description '%s'.\n",str);
786 return(-1);
787 }
788
789 /* Parse the NM bay id */
790 nm_bay = atoi(tokens[0]);
791
792 /* Add this new NM to the current NM list */
793 res = c3725_nm_add_binding(router,tokens[1],nm_bay);
794
795 /* The complete array was cleaned by strsplit */
796 for(i=0;i<NM_DESC_MAX_TOKENS;i++)
797 free(tokens[i]);
798
799 return(res);
800 }
801
802 /* Add a Network IO descriptor binding (command line) */
803 int c3725_cmd_add_nio(c3725_t *router,char *str)
804 {
805 char *tokens[NM_DESC_MAX_TOKENS];
806 int i,count,nio_type,res=-1;
807 u_int nm_bay,port_id;
808 netio_desc_t *nio;
809 char nio_name[128];
810
811 /* A port adapter description is like "1:3:tap:tap0" */
812 if ((count = m_strsplit(str,':',tokens,NM_DESC_MAX_TOKENS)) < 3) {
813 vm_error(router->vm,"unable to parse NIO description '%s'.\n",str);
814 return(-1);
815 }
816
817 /* Parse the NM bay */
818 nm_bay = atoi(tokens[0]);
819
820 /* Parse the NM port id */
821 port_id = atoi(tokens[1]);
822
823 /* Autogenerate a NIO name */
824 snprintf(nio_name,sizeof(nio_name),"c3725-i%u/%u/%u",
825 router->vm->instance_id,nm_bay,port_id);
826
827 /* Create the Network IO descriptor */
828 nio = NULL;
829 nio_type = netio_get_type(tokens[2]);
830
831 switch(nio_type) {
832 case NETIO_TYPE_UNIX:
833 if (count != 5) {
834 vm_error(router->vm,
835 "invalid number of arguments for UNIX NIO '%s'\n",str);
836 goto done;
837 }
838
839 nio = netio_desc_create_unix(nio_name,tokens[3],tokens[4]);
840 break;
841
842 case NETIO_TYPE_VDE:
843 if (count != 5) {
844 vm_error(router->vm,
845 "invalid number of arguments for VDE NIO '%s'\n",str);
846 goto done;
847 }
848
849 nio = netio_desc_create_vde(nio_name,tokens[3],tokens[4]);
850 break;
851
852 case NETIO_TYPE_TAP:
853 if (count != 4) {
854 vm_error(router->vm,
855 "invalid number of arguments for TAP NIO '%s'\n",str);
856 goto done;
857 }
858
859 nio = netio_desc_create_tap(nio_name,tokens[3]);
860 break;
861
862 case NETIO_TYPE_UDP:
863 if (count != 6) {
864 vm_error(router->vm,
865 "invalid number of arguments for UDP NIO '%s'\n",str);
866 goto done;
867 }
868
869 nio = netio_desc_create_udp(nio_name,atoi(tokens[3]),
870 tokens[4],atoi(tokens[5]));
871 break;
872
873 case NETIO_TYPE_TCP_CLI:
874 if (count != 5) {
875 vm_error(router->vm,
876 "invalid number of arguments for TCP CLI NIO '%s'\n",str);
877 goto done;
878 }
879
880 nio = netio_desc_create_tcp_cli(nio_name,tokens[3],tokens[4]);
881 break;
882
883 case NETIO_TYPE_TCP_SER:
884 if (count != 4) {
885 vm_error(router->vm,
886 "invalid number of arguments for TCP SER NIO '%s'\n",str);
887 goto done;
888 }
889
890 nio = netio_desc_create_tcp_ser(nio_name,tokens[3]);
891 break;
892
893 case NETIO_TYPE_NULL:
894 nio = netio_desc_create_null(nio_name);
895 break;
896
897 #ifdef LINUX_ETH
898 case NETIO_TYPE_LINUX_ETH:
899 if (count != 4) {
900 vm_error(router->vm,
901 "invalid number of arguments for Linux Eth NIO '%s'\n",
902 str);
903 goto done;
904 }
905
906 nio = netio_desc_create_lnxeth(nio_name,tokens[3]);
907 break;
908 #endif
909
910 #ifdef GEN_ETH
911 case NETIO_TYPE_GEN_ETH:
912 if (count != 4) {
913 vm_error(router->vm,
914 "invalid number of arguments for Generic Eth NIO '%s'\n",
915 str);
916 goto done;
917 }
918
919 nio = netio_desc_create_geneth(nio_name,tokens[3]);
920 break;
921 #endif
922
923 default:
924 vm_error(router->vm,"unknown NETIO type '%s'\n",tokens[2]);
925 goto done;
926 }
927
928 if (!nio) {
929 vm_error(router->vm,"unable to create NETIO "
930 "descriptor for NM slot %u\n",nm_bay);
931 goto done;
932 }
933
934 if (c3725_nm_add_nio_binding(router,nm_bay,port_id,nio_name) == -1) {
935 vm_error(router->vm,"unable to add NETIO binding for slot %u\n",nm_bay);
936 netio_release(nio_name);
937 netio_delete(nio_name);
938 goto done;
939 }
940
941 netio_release(nio_name);
942 res = 0;
943
944 done:
945 /* The complete array was cleaned by strsplit */
946 for(i=0;i<NM_DESC_MAX_TOKENS;i++)
947 free(tokens[i]);
948
949 return(res);
950 }
951
952 /* Show the list of available NM drivers */
953 void c3725_nm_show_drivers(void)
954 {
955 int i;
956
957 printf("Available C3725 Network Module drivers:\n");
958
959 for(i=0;nm_drivers[i];i++) {
960 printf(" * %s %s\n",
961 nm_drivers[i]->dev_type,
962 !nm_drivers[i]->supported ? "(NOT WORKING)" : "");
963 }
964
965 printf("\n");
966 }
967
968 /* Set the base MAC address of the chassis */
969 static int c3725_burn_mac_addr(c3725_t *router,n_eth_addr_t *addr)
970 {
971 m_uint8_t eeprom_ver;
972 size_t offset;
973
974 /* Read EEPROM format version */
975 cisco_eeprom_get_byte(&router->mb_eeprom,0,&eeprom_ver);
976
977 switch(eeprom_ver) {
978 case 0:
979 cisco_eeprom_set_region(&router->mb_eeprom,2,addr->eth_addr_byte,6);
980 break;
981
982 case 4:
983 if (!cisco_eeprom_v4_find_field(&router->mb_eeprom,0xC3,&offset)) {
984 cisco_eeprom_set_region(&router->mb_eeprom,offset,
985 addr->eth_addr_byte,6);
986 }
987 break;
988
989 default:
990 vm_error(router->vm,"c3725_burn_mac_addr: unable to handle "
991 "EEPROM version %u\n",eeprom_ver);
992 return(-1);
993 }
994
995 return(0);
996 }
997
998 /* Set chassis MAC address */
999 int c3725_chassis_set_mac_addr(c3725_t *router,char *mac_addr)
1000 {
1001 if (parse_mac_addr(&router->mac_addr,mac_addr) == -1) {
1002 vm_error(router->vm,"unable to parse MAC address '%s'.\n",mac_addr);
1003 return(-1);
1004 }
1005
1006 /* Set the chassis base MAC address */
1007 c3725_burn_mac_addr(router,&router->mac_addr);
1008 return(0);
1009 }
1010
1011 /* Create the two main PCI busses for a GT64120 based system */
1012 static int c3725_init_gt96100(c3725_t *router)
1013 {
1014 vm_instance_t *vm = router->vm;
1015
1016 vm->pci_bus[0] = pci_bus_create("PCI bus #0",0);
1017 vm->pci_bus[1] = pci_bus_create("PCI bus #1",0);
1018
1019 if (!vm->pci_bus[0] || !vm->pci_bus[1]) {
1020 vm_error(router->vm,"unable to create PCI data.\n");
1021 return(-1);
1022 }
1023
1024 return(dev_gt96100_init(vm,"gt96100",C3725_GT96K_ADDR,0x200000,
1025 C3725_GT96K_IRQ,C3725_NETIO_IRQ));
1026 }
1027
1028 /* Initialize a Cisco 3725 */
1029 static int c3725_init(c3725_t *router)
1030 {
1031 vm_instance_t *vm = router->vm;
1032
1033 /* Set the processor type: R7000 */
1034 mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R7000);
1035
1036 /* Initialize the Galileo GT-96100 PCI controller */
1037 if (c3725_init_gt96100(router) == -1)
1038 return(-1);
1039
1040 /* Initialize PCI map (NM slot 1 & 2) */
1041 router->nm_bay[1].pci_map = vm->pci_bus[1];
1042 router->nm_bay[2].pci_map = vm->pci_bus[1];
1043
1044 vm->elf_machine_id = C3725_ELF_MACHINE_ID;
1045 return(0);
1046 }
1047
1048 /* Show C3725 hardware info */
1049 void c3725_show_hardware(c3725_t *router)
1050 {
1051 vm_instance_t *vm = router->vm;
1052
1053 printf("C3725 instance '%s' (id %d):\n",vm->name,vm->instance_id);
1054
1055 printf(" VM Status : %d\n",vm->status);
1056 printf(" RAM size : %u Mb\n",vm->ram_size);
1057 printf(" NVRAM size : %u Kb\n",vm->nvram_size);
1058 printf(" IOS image : %s\n\n",vm->ios_image);
1059
1060 if (vm->debug_level > 0) {
1061 dev_show_list(vm);
1062 pci_dev_show_list(vm->pci_bus[0]);
1063 pci_dev_show_list(vm->pci_bus[1]);
1064 printf("\n");
1065 }
1066 }
1067
1068 /* Initialize default parameters for a C3725 */
1069 void c3725_init_defaults(c3725_t *router)
1070 {
1071 vm_instance_t *vm = router->vm;
1072 n_eth_addr_t *m;
1073 m_uint16_t pid;
1074
1075 pid = (m_uint16_t)getpid();
1076
1077 /* Generate a chassis MAC address based on the instance ID */
1078 m = &router->mac_addr;
1079 m->eth_addr_byte[0] = vm_get_mac_addr_msb(vm);
1080 m->eth_addr_byte[1] = vm->instance_id & 0xFF;
1081 m->eth_addr_byte[2] = pid >> 8;
1082 m->eth_addr_byte[3] = pid & 0xFF;
1083 m->eth_addr_byte[4] = 0x00;
1084 m->eth_addr_byte[5] = 0x00;
1085
1086 c3725_init_eeprom_groups(router);
1087 cisco_eeprom_copy(&router->mb_eeprom,&eeprom_c3725_mainboard);
1088 c3725_burn_mac_addr(router,&router->mac_addr);
1089
1090 vm->ram_mmap = C3725_DEFAULT_RAM_MMAP;
1091 vm->ram_size = C3725_DEFAULT_RAM_SIZE;
1092 vm->rom_size = C3725_DEFAULT_ROM_SIZE;
1093 vm->nvram_size = C3725_DEFAULT_NVRAM_SIZE;
1094 vm->conf_reg_setup = C3725_DEFAULT_CONF_REG;
1095 vm->clock_divisor = C3725_DEFAULT_CLOCK_DIV;
1096 vm->nvram_rom_space = C3725_NVRAM_ROM_RES_SIZE;
1097 router->nm_iomem_size = C3725_DEFAULT_IOMEM_SIZE;
1098
1099 vm->pcmcia_disk_size[0] = C3725_DEFAULT_DISK0_SIZE;
1100 vm->pcmcia_disk_size[1] = C3725_DEFAULT_DISK1_SIZE;
1101
1102 /* Enable NVRAM operations to load/store configs */
1103 vm->nvram_extract_config = c3725_nvram_extract_config;
1104 vm->nvram_push_config = c3725_nvram_push_config;
1105 }
1106
1107 /* Initialize the C3725 Platform */
1108 int c3725_init_platform(c3725_t *router)
1109 {
1110 vm_instance_t *vm = router->vm;
1111 struct c3725_nm_bay *nm_bay;
1112 cpu_mips_t *cpu;
1113 cpu_gen_t *gen;
1114 vm_obj_t *obj;
1115 int i;
1116
1117 /* Copy config register setup into "active" config register */
1118 vm->conf_reg = vm->conf_reg_setup;
1119
1120 /* Create Console and AUX ports */
1121 vm_init_vtty(vm);
1122
1123 /* Create a CPU group */
1124 vm->cpu_group = cpu_group_create("System CPU");
1125
1126 /* Initialize the virtual MIPS processor */
1127 if (!(gen = cpu_create(vm,CPU_TYPE_MIPS64,0))) {
1128 vm_error(vm,"unable to create CPU!\n");
1129 return(-1);
1130 }
1131
1132 cpu = CPU_MIPS64(gen);
1133
1134 /* Add this CPU to the system CPU group */
1135 cpu_group_add(vm->cpu_group,gen);
1136 vm->boot_cpu = gen;
1137
1138 /* Initialize the IRQ routing vectors */
1139 vm->set_irq = mips64_vm_set_irq;
1140 vm->clear_irq = mips64_vm_clear_irq;
1141
1142 /* Mark the Network IO interrupt as high priority */
1143 cpu->irq_idle_preempt[C3725_NETIO_IRQ] = TRUE;
1144 cpu->irq_idle_preempt[C3725_GT96K_IRQ] = TRUE;
1145 cpu->irq_idle_preempt[C3725_DUART_IRQ] = TRUE;
1146
1147 /* Copy some parameters from VM to CPU (idle PC, ...) */
1148 cpu->idle_pc = vm->idle_pc;
1149
1150 if (vm->timer_irq_check_itv)
1151 cpu->timer_irq_check_itv = vm->timer_irq_check_itv;
1152
1153 /* Remote emulator control */
1154 dev_remote_control_init(vm,0x16000000,0x1000);
1155
1156 /* Specific Storage Area (SSA) */
1157 dev_ram_init(vm,"ssa",TRUE,FALSE,NULL,FALSE,0x16001000ULL,0x7000);
1158
1159 /* IO FPGA */
1160 if (dev_c3725_iofpga_init(router,C3725_IOFPGA_ADDR,0x40000) == -1)
1161 return(-1);
1162
1163 #if 0
1164 /* PCI IO space */
1165 if (!(vm->pci_io_space = pci_io_data_init(vm,C3725_PCI_IO_ADDR)))
1166 return(-1);
1167 #endif
1168
1169 /* Initialize the chassis */
1170 if (c3725_init(router) == -1)
1171 return(-1);
1172
1173 /* Initialize RAM */
1174 vm_ram_init(vm,0x00000000ULL);
1175
1176 /* Initialize ROM (as a Flash) */
1177 if (!(obj = dev_flash_init(vm,"rom",C3725_ROM_ADDR,vm->rom_size*1048576)))
1178 return(-1);
1179
1180 dev_flash_copy_data(obj,0,mips64_microcode,mips64_microcode_len);
1181 c3725_nvram_check_empty_config(vm);
1182
1183 /* Initialize the NS16552 DUART */
1184 dev_ns16552_init(vm,C3725_DUART_ADDR,0x1000,3,C3725_DUART_IRQ,
1185 vm->vtty_con,vm->vtty_aux);
1186
1187 /* PCMCIA Slot 0 */
1188 dev_pcmcia_disk_init(vm,"slot0",C3725_SLOT0_ADDR,0x200000,
1189 vm->pcmcia_disk_size[0],1);
1190
1191 /* PCMCIA Slot 1 */
1192 dev_pcmcia_disk_init(vm,"slot1",C3725_SLOT1_ADDR,0x200000,
1193 vm->pcmcia_disk_size[1],1);
1194
1195 /* The GT96100 system controller has 2 integrated FastEthernet ports */
1196 c3725_nm_add_binding(router,"GT96100-FE",0);
1197
1198 /* Initialize Network Modules */
1199 for(i=0;i<C3725_MAX_NM_BAYS;i++) {
1200 nm_bay = &router->nm_bay[i];
1201
1202 if (!nm_bay->dev_type)
1203 continue;
1204
1205 if (c3725_nm_init(router,i) == -1) {
1206 vm_error(vm,"unable to create Network Module \"%s\"\n",
1207 nm_bay->dev_type);
1208 return(-1);
1209 }
1210 }
1211
1212 /* Show device list */
1213 c3725_show_hardware(router);
1214 return(0);
1215 }
1216
1217 /* Boot the IOS image */
1218 int c3725_boot_ios(c3725_t *router)
1219 {
1220 vm_instance_t *vm = router->vm;
1221 cpu_mips_t *cpu;
1222
1223 if (!vm->boot_cpu)
1224 return(-1);
1225
1226 /* Suspend CPU activity since we will restart directly from ROM */
1227 vm_suspend(vm);
1228
1229 /* Check that CPU activity is really suspended */
1230 if (cpu_group_sync_state(vm->cpu_group) == -1) {
1231 vm_error(vm,"unable to sync with system CPUs.\n");
1232 return(-1);
1233 }
1234
1235 /* Reset the boot CPU */
1236 cpu = CPU_MIPS64(vm->boot_cpu);
1237 mips64_reset(cpu);
1238
1239 /* Load IOS image */
1240 if (mips64_load_elf_image(cpu,vm->ios_image,
1241 (vm->ghost_status == VM_GHOST_RAM_USE),
1242 &vm->ios_entry_point) < 0)
1243 {
1244 vm_error(vm,"failed to load Cisco IOS image '%s'.\n",vm->ios_image);
1245 return(-1);
1246 }
1247
1248 /* Launch the simulation */
1249 printf("\nC3725 '%s': starting simulation (CPU0 PC=0x%llx), "
1250 "JIT %sabled.\n",
1251 vm->name,cpu->pc,vm->jit_use ? "en":"dis");
1252
1253 vm_log(vm,"C3725_BOOT",
1254 "starting instance (CPU0 PC=0x%llx,idle_pc=0x%llx,JIT %s)\n",
1255 cpu->pc,cpu->idle_pc,vm->jit_use ? "on":"off");
1256
1257 /* Start main CPU */
1258 if (vm->ghost_status != VM_GHOST_RAM_GENERATE) {
1259 vm->status = VM_STATUS_RUNNING;
1260 cpu_start(vm->boot_cpu);
1261 } else {
1262 vm->status = VM_STATUS_SHUTDOWN;
1263 }
1264 return(0);
1265 }
1266
1267 /* Initialize a Cisco 3725 instance */
1268 int c3725_init_instance(c3725_t *router)
1269 {
1270 vm_instance_t *vm = router->vm;
1271 m_uint32_t rom_entry_point;
1272 cpu_mips_t *cpu0;
1273
1274 if (!vm->ios_image) {
1275 vm_error(vm,"no Cisco IOS image defined.");
1276 return(-1);
1277 }
1278
1279 /* Initialize the C3725 platform */
1280 if (c3725_init_platform(router) == -1) {
1281 vm_error(vm,"unable to initialize the platform hardware.\n");
1282 return(-1);
1283 }
1284
1285 /* Load IOS configuration file */
1286 if (vm->ios_config != NULL) {
1287 vm_nvram_push_config(vm,vm->ios_config);
1288 vm->conf_reg &= ~0x40;
1289 }
1290
1291 /* Load ROM (ELF image or embedded) */
1292 cpu0 = CPU_MIPS64(vm->boot_cpu);
1293 rom_entry_point = (m_uint32_t)MIPS_ROM_PC;
1294
1295 if ((vm->rom_filename != NULL) &&
1296 (mips64_load_elf_image(cpu0,vm->rom_filename,0,&rom_entry_point) < 0))
1297 {
1298 vm_error(vm,"unable to load alternate ROM '%s', "
1299 "fallback to embedded ROM.\n\n",vm->rom_filename);
1300 vm->rom_filename = NULL;
1301 }
1302
1303 /* Load symbol file */
1304 if (vm->sym_filename) {
1305 mips64_sym_load_file(cpu0,vm->sym_filename);
1306 cpu0->sym_trace = 1;
1307 }
1308
1309 return(c3725_boot_ios(router));
1310 }
1311
1312 /* Stop a Cisco 3725 instance */
1313 int c3725_stop_instance(c3725_t *router)
1314 {
1315 vm_instance_t *vm = router->vm;
1316
1317 printf("\nC3725 '%s': stopping simulation.\n",vm->name);
1318 vm_log(vm,"C3725_STOP","stopping simulation.\n");
1319
1320 /* Stop all CPUs */
1321 if (vm->cpu_group != NULL) {
1322 vm_stop(vm);
1323
1324 if (cpu_group_sync_state(vm->cpu_group) == -1) {
1325 vm_error(vm,"unable to sync with system CPUs.\n");
1326 return(-1);
1327 }
1328 }
1329
1330 /* Free resources that were used during execution to emulate hardware */
1331 c3725_nm_shutdown_all(router);
1332 vm_hardware_shutdown(vm);
1333 return(0);
1334 }

  ViewVC Help
Powered by ViewVC 1.1.26