/[dynamips]/upstream/dynamips-0.2.6-RC5/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-RC5/dev_c3600.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
File MIME type: text/plain
File size: 40891 byte(s)
dynamips-0.2.6-RC5

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

  ViewVC Help
Powered by ViewVC 1.1.26