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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6 - (show annotations)
Sat Oct 6 16:09:07 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.6-RC5/dev_c3725.c
File MIME type: text/plain
File size: 35419 byte(s)
dynamips-0.2.6-RC5

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

  ViewVC Help
Powered by ViewVC 1.1.26