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

Parent Directory Parent Directory | Revision Log Revision Log


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

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

  ViewVC Help
Powered by ViewVC 1.1.26