/[dynamips]/upstream/dynamips-0.2.5/dev_c3600.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.5/dev_c3600.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Sat Oct 6 16:01:44 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 40394 byte(s)
import 0.2.5 from upstream

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

  ViewVC Help
Powered by ViewVC 1.1.26