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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5 - (show annotations)
Sat Oct 6 16:08:03 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.6-RC4/dev_c3745.c
File MIME type: text/plain
File size: 37281 byte(s)
dynamips-0.2.6-RC4

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

  ViewVC Help
Powered by ViewVC 1.1.26