/[dynamips]/upstream/dynamips-0.2.6-RC3/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.6-RC3/dev_c3600.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (show annotations)
Sat Oct 6 16:05:34 2007 UTC (13 years ago) by dpavlin
Original Path: upstream/dynamips-0.2.6-RC2/dev_c3600.c
File MIME type: text/plain
File size: 40212 byte(s)
dynamips-0.2.6-RC2

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

  ViewVC Help
Powered by ViewVC 1.1.26