/[dynamips]/upstream/dynamips-0.2.7-RC1/dev_c2600.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.7-RC1/dev_c2600.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
File MIME type: text/plain
File size: 40778 byte(s)
dynamips-0.2.7-RC1

1 /*
2 * Cisco router simulation platform.
3 * Copyright (c) 2006 Christophe Fillot (cf@utc.fr)
4 *
5 * Generic Cisco 2600 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 "vm.h"
17 #include "dynamips.h"
18 #include "memory.h"
19 #include "device.h"
20 #include "ppc32_mem.h"
21 #include "pci_io.h"
22 #include "cisco_eeprom.h"
23 #include "dev_mpc860.h"
24 #include "dev_rom.h"
25 #include "dev_c2600.h"
26 #include "dev_vtty.h"
27 #include "registry.h"
28
29 /* ======================================================================== */
30 /* EEPROM definitions */
31 /* ======================================================================== */
32
33 /* Cisco 2600 mainboard EEPROM */
34 static m_uint16_t eeprom_c2600_mb_data[] = {
35 0x0101, 0x0404, 0x0000, 0x0000, 0x4320, 0x00FF, 0x0091, 0x0020,
36 0x0000, 0x0000, 0x0000, 0x0000, 0x3030, 0x3000, 0x0030, 0x3030,
37 0x3002, 0x0200, 0x0000, 0x0000, 0x00FF, 0xFFFF, 0x5006, 0x490B,
38 0x1709, 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 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
43 };
44
45 struct c2600_mb_id {
46 char *name;
47 char *mb_driver;
48 m_uint16_t id;
49 int supported;
50 };
51
52 struct c2600_mb_id c2600_mainboard_id[] = {
53 { "2610" , "CISCO2600-MB-1E" , 0x0091, TRUE },
54 { "2611" , "CISCO2600-MB-2E" , 0x0092, TRUE },
55 { "2620" , "CISCO2600-MB-1FE" , 0x0094, TRUE },
56 { "2621" , "CISCO2600-MB-2FE" , 0x00a2, TRUE },
57 { "2610XM" , "CISCO2600-MB-1FE" , 0x036a, TRUE },
58 { "2611XM" , "CISCO2600-MB-2FE" , 0x036b, FALSE },
59 { "2620XM" , "CISCO2600-MB-1FE" , 0x036c, TRUE },
60 { "2621XM" , "CISCO2600-MB-2FE" , 0x036d, FALSE },
61 { "2650XM" , "CISCO2600-MB-1FE" , 0x036e, TRUE },
62 { "2651XM" , "CISCO2600-MB-2FE" , 0x036f, FALSE },
63 { NULL , NULL , 0x0000, 0 },
64 };
65
66 /* ======================================================================== */
67 /* Network Module Drivers */
68 /* ======================================================================== */
69 static struct c2600_nm_driver *nm_drivers[] = {
70 &dev_c2600_mb1e_eth_driver,
71 &dev_c2600_mb2e_eth_driver,
72 &dev_c2600_mb1fe_eth_driver,
73 &dev_c2600_mb2fe_eth_driver,
74
75 &dev_c2600_nm_1e_driver,
76 &dev_c2600_nm_4e_driver,
77 &dev_c2600_nm_1fe_tx_driver,
78 &dev_c2600_nm_16esw_driver,
79 NULL,
80 };
81
82 /* ======================================================================== */
83 /* Cisco 2600 router instances */
84 /* ======================================================================== */
85
86 /* Read a byte from the NVRAM */
87 static inline m_uint8_t nvram_read_byte(u_char *base,u_int offset)
88 {
89 m_uint8_t *ptr;
90
91 ptr = (m_uint8_t *)base + (offset << 2);
92 return(*ptr);
93 }
94
95 /* Write a byte to the NVRAM */
96 static inline void nvram_write_byte(u_char *base,u_int offset,m_uint8_t val)
97 {
98 m_uint8_t *ptr;
99
100 ptr = (m_uint8_t *)base + (offset << 2);
101 *ptr = val;
102 }
103
104 /* Read a 16-bit value from NVRAM */
105 static m_uint16_t nvram_read16(u_char *base,u_int offset)
106 {
107 m_uint16_t val;
108 val = nvram_read_byte(base,offset) << 8;
109 val |= nvram_read_byte(base,offset+1);
110 return(val);
111 }
112
113 /* Write a 16-bit value to NVRAM */
114 static void nvram_write16(u_char *base,u_int offset,m_uint16_t val)
115 {
116 nvram_write_byte(base,offset,val >> 8);
117 nvram_write_byte(base,offset+1,val & 0xFF);
118 }
119
120 /* Read a 32-bit value from NVRAM */
121 static m_uint32_t nvram_read32(u_char *base,u_int offset)
122 {
123 m_uint32_t val;
124 val = nvram_read_byte(base,offset) << 24;
125 val |= nvram_read_byte(base,offset+1) << 16;
126 val |= nvram_read_byte(base,offset+2) << 8;
127 val |= nvram_read_byte(base,offset+3);
128 return(val);
129 }
130
131 /* Write a 32-bit value to NVRAM */
132 static void nvram_write32(u_char *base,u_int offset,m_uint32_t val)
133 {
134 nvram_write_byte(base,offset,val >> 24);
135 nvram_write_byte(base,offset+1,val >> 16);
136 nvram_write_byte(base,offset+2,val >> 8);
137 nvram_write_byte(base,offset+3,val & 0xFF);
138 }
139
140 /* Read a buffer from NVRAM */
141 static void nvram_memcpy_from(u_char *base,u_int offset,u_char *data,u_int len)
142 {
143 u_int i;
144
145 for(i=0;i<len;i++) {
146 *data = nvram_read_byte(base,offset+i);
147 data++;
148 }
149 }
150
151 /* Write a buffer from NVRAM */
152 static void nvram_memcpy_to(u_char *base,u_int offset,u_char *data,u_int len)
153 {
154 u_int i;
155
156 for(i=0;i<len;i++) {
157 nvram_write_byte(base,offset+i,*data);
158 data++;
159 }
160 }
161
162 /* Directly extract the configuration from the NVRAM device */
163 ssize_t c2600_nvram_extract_config(vm_instance_t *vm,char **buffer)
164 {
165 u_char *base_ptr;
166 u_int ios_ptr,cfg_ptr,end_ptr;
167 m_uint32_t start,nvlen;
168 m_uint16_t magic1,magic2;
169 struct vdevice *nvram_dev;
170 off_t nvram_size;
171 int fd;
172
173 if ((nvram_dev = dev_get_by_name(vm,"nvram")))
174 dev_sync(nvram_dev);
175
176 fd = vm_mmap_open_file(vm,"nvram",&base_ptr,&nvram_size);
177
178 if (fd == -1)
179 return(-1);
180
181 ios_ptr = vm->nvram_rom_space;
182 end_ptr = nvram_size;
183
184 if ((ios_ptr + 0x30) >= end_ptr) {
185 vm_error(vm,"NVRAM file too small\n");
186 return(-1);
187 }
188
189 magic1 = nvram_read16(base_ptr,ios_ptr+0x06);
190 magic2 = nvram_read16(base_ptr,ios_ptr+0x08);
191
192 if ((magic1 != 0xF0A5) || (magic2 != 0xABCD)) {
193 vm_error(vm,"unable to find IOS magic numbers (0x%x,0x%x)!\n",
194 magic1,magic2);
195 return(-1);
196 }
197
198 start = nvram_read32(base_ptr,ios_ptr+0x10) + 1;
199 nvlen = nvram_read32(base_ptr,ios_ptr+0x18);
200
201 printf("START = 0x%8.8x, LEN = 0x%8.8x\n",start,nvlen);
202 printf("END = 0x%8.8x\n",nvram_read32(base_ptr,ios_ptr+0x14));
203
204 if (!(*buffer = malloc(nvlen+1))) {
205 vm_error(vm,"unable to allocate config buffer (%u bytes)\n",nvlen);
206 return(-1);
207 }
208
209 cfg_ptr = ios_ptr + start + 0x08;
210
211 if ((cfg_ptr + nvlen) > end_ptr) {
212 vm_error(vm,"NVRAM file too small\n");
213 return(-1);
214 }
215
216 nvram_memcpy_from(base_ptr,cfg_ptr,*buffer,nvlen-1);
217 (*buffer)[nvlen-1] = 0;
218 return(nvlen-1);
219 }
220
221 /* Compute NVRAM checksum */
222 static m_uint16_t c2600_nvram_cksum(u_char *base_ptr,u_int offset,size_t count)
223 {
224 m_uint32_t sum = 0;
225
226 while(count > 1) {
227 sum = sum + nvram_read16(base_ptr,offset);
228 offset += 2;
229 count -= sizeof(m_uint16_t);
230 }
231
232 if (count > 0)
233 sum = sum + ((nvram_read16(base_ptr,offset) & 0xFF) << 8);
234
235 while(sum>>16)
236 sum = (sum & 0xffff) + (sum >> 16);
237
238 return(~sum);
239 }
240
241 /* Directly push the IOS configuration to the NVRAM device */
242 int c2600_nvram_push_config(vm_instance_t *vm,char *buffer,size_t len)
243 {
244 m_uint32_t cfg_offset,cklen,tmp,ios_ptr,cfg_ptr;
245 m_uint16_t cksum;
246 u_char *base_ptr;
247 int fd;
248
249 fd = vm_mmap_create_file(vm,"nvram",vm->nvram_size*4096,&base_ptr);
250
251 if (fd == -1)
252 return(-1);
253
254 cfg_offset = 0x2c;
255 ios_ptr = vm->nvram_rom_space;
256 cfg_ptr = ios_ptr + cfg_offset;
257
258 /* Write IOS tag, uncompressed config... */
259 nvram_write16(base_ptr,ios_ptr+0x06,0xF0A5);
260 nvram_write16(base_ptr,ios_ptr+0x08,0xABCD);
261 nvram_write16(base_ptr,ios_ptr+0x0a,0x0001);
262 nvram_write16(base_ptr,ios_ptr+0x0c,0x0000);
263 nvram_write16(base_ptr,ios_ptr+0x0e,0x0c04);
264
265 /* Store file contents to NVRAM */
266 nvram_memcpy_to(base_ptr,cfg_ptr,buffer,len);
267
268 /* Write config addresses + size */
269 tmp = cfg_offset - 0x08;
270
271 nvram_write32(base_ptr,ios_ptr+0x10,tmp);
272 nvram_write32(base_ptr,ios_ptr+0x14,tmp + len);
273 nvram_write32(base_ptr,ios_ptr+0x18,len);
274
275 /* Compute the checksum */
276 cklen = (vm->nvram_size*1024) - (vm->nvram_rom_space + 0x08);
277 cksum = c2600_nvram_cksum(base_ptr,ios_ptr+0x08,cklen);
278 nvram_write16(base_ptr,ios_ptr+0x0c,cksum);
279
280 vm_mmap_close_file(fd,base_ptr,vm->nvram_size*4096);
281 return(0);
282 }
283
284 /* Check for empty config */
285 int c2600_nvram_check_empty_config(vm_instance_t *vm)
286 {
287 struct vdevice *dev;
288 m_uint64_t addr;
289 m_uint32_t len;
290
291 if (!(dev = dev_get_by_name(vm,"nvram")))
292 return(-1);
293
294 addr = dev->phys_addr + (vm->nvram_rom_space << 2);
295 len = dev->phys_len - (vm->nvram_rom_space << 2);
296
297 while(len > 0) {
298 if (physmem_copy_u32_from_vm(vm,addr) != 0)
299 return(0);
300
301 addr += sizeof(m_uint32_t);
302 len -= sizeof(m_uint32_t);
303 }
304
305 /* Empty NVRAM */
306 vm->conf_reg |= 0x0040;
307 printf("NVRAM is empty, setting config register to 0x%x\n",vm->conf_reg);
308 return(0);
309 }
310
311 /* Create a new router instance */
312 c2600_t *c2600_create_instance(char *name,int instance_id)
313 {
314 c2600_t *router;
315
316 if (!(router = malloc(sizeof(*router)))) {
317 fprintf(stderr,"C2600 '%s': Unable to create new instance!\n",name);
318 return NULL;
319 }
320
321 memset(router,0,sizeof(*router));
322
323 if (!(router->vm = vm_create(name,instance_id,VM_TYPE_C2600))) {
324 fprintf(stderr,"C2600 '%s': unable to create VM instance!\n",name);
325 goto err_vm;
326 }
327
328 c2600_init_defaults(router);
329 router->vm->hw_data = router;
330 return router;
331
332 err_vm:
333 free(router);
334 return NULL;
335 }
336
337 /* Free resources used by a router instance */
338 static int c2600_free_instance(void *data,void *arg)
339 {
340 vm_instance_t *vm = data;
341 c2600_t *router;
342 int i;
343
344 if (vm->type == VM_TYPE_C2600) {
345 router = VM_C2600(vm);
346
347 /* Stop all CPUs */
348 if (vm->cpu_group != NULL) {
349 vm_stop(vm);
350
351 if (cpu_group_sync_state(vm->cpu_group) == -1) {
352 vm_error(vm,"unable to sync with system CPUs.\n");
353 return(FALSE);
354 }
355 }
356
357 /* Remove NIO bindings */
358 for(i=0;i<C2600_MAX_NM_BAYS;i++)
359 c2600_nm_remove_all_nio_bindings(router,i);
360
361 /* Shutdown all Network Modules */
362 c2600_nm_shutdown_all(router);
363
364 /* Free mainboard EEPROM */
365 cisco_eeprom_free(&router->mb_eeprom);
366
367 /* Free all resources used by VM */
368 vm_free(vm);
369
370 /* Free the router structure */
371 free(router);
372 return(TRUE);
373 }
374
375 return(FALSE);
376 }
377
378 /* Delete a router instance */
379 int c2600_delete_instance(char *name)
380 {
381 return(registry_delete_if_unused(name,OBJ_TYPE_VM,
382 c2600_free_instance,NULL));
383 }
384
385 /* Delete all router instances */
386 int c2600_delete_all_instances(void)
387 {
388 return(registry_delete_type(OBJ_TYPE_VM,c2600_free_instance,NULL));
389 }
390
391 /* Save configuration of a C2600 instance */
392 void c2600_save_config(c2600_t *router,FILE *fd)
393 {
394 vm_instance_t *vm = router->vm;
395 struct c2600_nio_binding *nb;
396 struct c2600_nm_bay *bay;
397 int i;
398
399 /* General settings */
400 fprintf(fd,"c2600 create %s %u\n",vm->name,vm->instance_id);
401 fprintf(fd,"c2600 set_chassis %s %s\n",vm->name,router->mainboard_type);
402
403 /* VM configuration */
404 vm_save_config(vm,fd);
405
406 /* Network Module settings */
407 for(i=0;i<C2600_MAX_NM_BAYS;i++) {
408 if (!(bay = c2600_nm_get_info(router,i)))
409 continue;
410
411 if (bay->dev_type) {
412 fprintf(fd,"c2600 add_nm_binding %s %u %s\n",
413 vm->name,i,bay->dev_type);
414 }
415
416 for(nb=bay->nio_list;nb;nb=nb->next) {
417 fprintf(fd,"c2600 add_nio_binding %s %u %u %s\n",
418 vm->name,i,nb->port_id,nb->nio->name);
419 }
420 }
421
422 fprintf(fd,"\n");
423 }
424
425 /* Save configurations of all C2600 instances */
426 static void c2600_reg_save_config(registry_entry_t *entry,void *opt,int *err)
427 {
428 vm_instance_t *vm = entry->data;
429 c2600_t *router = VM_C2600(vm);
430
431 if (vm->type == VM_TYPE_C2600)
432 c2600_save_config(router,(FILE *)opt);
433 }
434
435 void c2600_save_config_all(FILE *fd)
436 {
437 registry_foreach_type(OBJ_TYPE_VM,c2600_reg_save_config,fd,NULL);
438 }
439
440 /* Find Cisco 2600 Mainboard info */
441 static struct c2600_mb_id *c2600_get_mb_info(char *mainboard_type)
442 {
443 int i;
444
445 for(i=0;c2600_mainboard_id[i].name;i++)
446 if (!strcmp(c2600_mainboard_id[i].name,mainboard_type))
447 return(&c2600_mainboard_id[i]);
448
449 return NULL;
450 }
451
452 /* Show all available mainboards */
453 void c2600_mainboard_show_drivers(void)
454 {
455 int i;
456
457 printf("Available C2600 chassis drivers:\n");
458
459 for(i=0;c2600_mainboard_id[i].name;i++)
460 printf(" * %s %s\n",
461 c2600_mainboard_id[i].name,
462 !c2600_mainboard_id[i].supported ? "(NOT WORKING)" : "");
463
464 printf("\n");
465 }
466
467 /* Set NM EEPROM definition */
468 int c2600_nm_set_eeprom(c2600_t *router,u_int nm_bay,
469 const struct cisco_eeprom *eeprom)
470 {
471 if (nm_bay == 0)
472 return(0);
473
474 if (nm_bay != 1) {
475 vm_error(router->vm,"c2600_nm_set_eeprom: invalid NM Bay %u.\n",nm_bay);
476 return(-1);
477 }
478
479 if (cisco_eeprom_copy(&router->nm_bay[nm_bay].eeprom,eeprom) == -1) {
480 vm_error(router->vm,"c2600_nm_set_eeprom: no memory.\n");
481 return(-1);
482 }
483
484 return(0);
485 }
486
487 /* Unset NM EEPROM definition (empty bay) */
488 int c2600_nm_unset_eeprom(c2600_t *router,u_int nm_bay)
489 {
490 if (nm_bay == 0)
491 return(0);
492
493 if (nm_bay != 1) {
494 vm_error(router->vm,"c2600_nm_set_eeprom: invalid NM Bay %u.\n",nm_bay);
495 return(-1);
496 }
497
498 cisco_eeprom_free(&router->nm_bay[nm_bay].eeprom);
499 return(0);
500 }
501
502 /* Check if a bay has a port adapter */
503 int c2600_nm_check_eeprom(c2600_t *router,u_int nm_bay)
504 {
505 if (nm_bay != 1)
506 return(FALSE);
507
508 return(cisco_eeprom_valid(&router->nm_bay[nm_bay].eeprom));
509 }
510
511 /* Get bay info */
512 struct c2600_nm_bay *c2600_nm_get_info(c2600_t *router,u_int nm_bay)
513 {
514 if (nm_bay >= C2600_MAX_NM_BAYS)
515 return NULL;
516
517 return(&router->nm_bay[nm_bay]);
518 }
519
520 /* Get NM type */
521 char *c2600_nm_get_type(c2600_t *router,u_int nm_bay)
522 {
523 struct c2600_nm_bay *bay;
524
525 bay = c2600_nm_get_info(router,nm_bay);
526 return((bay != NULL) ? bay->dev_type : NULL);
527 }
528
529 /* Get driver info about the specified slot */
530 void *c2600_nm_get_drvinfo(c2600_t *router,u_int nm_bay)
531 {
532 struct c2600_nm_bay *bay;
533
534 bay = c2600_nm_get_info(router,nm_bay);
535 return((bay != NULL) ? bay->drv_info : NULL);
536 }
537
538 /* Set driver info for the specified slot */
539 int c2600_nm_set_drvinfo(c2600_t *router,u_int nm_bay,void *drv_info)
540 {
541 struct c2600_nm_bay *bay;
542
543 if (!(bay = c2600_nm_get_info(router,nm_bay)))
544 return(-1);
545
546 bay->drv_info = drv_info;
547 return(0);
548 }
549
550 /* Get a NM driver */
551 static struct c2600_nm_driver *c2600_nm_get_driver(char *dev_type)
552 {
553 int i;
554
555 for(i=0;nm_drivers[i];i++)
556 if (!strcmp(nm_drivers[i]->dev_type,dev_type))
557 return nm_drivers[i];
558
559 return NULL;
560 }
561
562 /* Add a NM binding */
563 int c2600_nm_add_binding(c2600_t *router,char *dev_type,u_int nm_bay)
564 {
565 struct c2600_nm_driver *nm_driver;
566 struct c2600_nm_bay *bay;
567
568 if (!(bay = c2600_nm_get_info(router,nm_bay)))
569 return(-1);
570
571 /* check that this bay is empty */
572 if (bay->dev_type != NULL) {
573 vm_error(router->vm,"a NM already exists in slot %u.\n",nm_bay);
574 return(-1);
575 }
576
577 /* find the NM driver */
578 if (!(nm_driver = c2600_nm_get_driver(dev_type))) {
579 vm_error(router->vm,"unknown NM type '%s'.\n",dev_type);
580 return(-1);
581 }
582
583 bay->dev_type = nm_driver->dev_type;
584 bay->nm_driver = nm_driver;
585 return(0);
586 }
587
588 /* Remove a NM binding */
589 int c2600_nm_remove_binding(c2600_t *router,u_int nm_bay)
590 {
591 struct c2600_nm_bay *bay;
592
593 if (!(bay = c2600_nm_get_info(router,nm_bay)))
594 return(-1);
595
596 /* stop if this bay is still active */
597 if (bay->drv_info != NULL) {
598 vm_error(router->vm,"slot %u still active.\n",nm_bay);
599 return(-1);
600 }
601
602 /* check that this bay is not empty */
603 if (bay->dev_type == NULL) {
604 vm_error(router->vm,"slot %u is empty.\n",nm_bay);
605 return(-1);
606 }
607
608 /* remove all NIOs bindings */
609 c2600_nm_remove_all_nio_bindings(router,nm_bay);
610
611 bay->dev_type = NULL;
612 bay->nm_driver = NULL;
613 return(0);
614 }
615
616 /* Find a NIO binding */
617 struct c2600_nio_binding *
618 c2600_nm_find_nio_binding(c2600_t *router,u_int nm_bay,u_int port_id)
619 {
620 struct c2600_nio_binding *nb;
621 struct c2600_nm_bay *bay;
622
623 if (!(bay = c2600_nm_get_info(router,nm_bay)))
624 return NULL;
625
626 for(nb=bay->nio_list;nb;nb=nb->next)
627 if (nb->port_id == port_id)
628 return nb;
629
630 return NULL;
631 }
632
633 /* Add a network IO binding */
634 int c2600_nm_add_nio_binding(c2600_t *router,u_int nm_bay,u_int port_id,
635 char *nio_name)
636 {
637 struct c2600_nio_binding *nb;
638 struct c2600_nm_bay *bay;
639 netio_desc_t *nio;
640
641 if (!(bay = c2600_nm_get_info(router,nm_bay)))
642 return(-1);
643
644 /* check that a NIO is not already bound to this port */
645 if (c2600_nm_find_nio_binding(router,nm_bay,port_id) != NULL) {
646 vm_error(router->vm,"a NIO already exists for interface %u/%u.\n",
647 nm_bay,port_id);
648 return(-1);
649 }
650
651 /* acquire a reference on the NIO object */
652 if (!(nio = netio_acquire(nio_name))) {
653 vm_error(router->vm,"unable to find NIO '%s'.\n",nio_name);
654 return(-1);
655 }
656
657 /* create a new binding */
658 if (!(nb = malloc(sizeof(*nb)))) {
659 vm_error(router->vm,"unable to create NIO binding "
660 "for interface %u/%u.\n",nm_bay,port_id);
661 netio_release(nio_name);
662 return(-1);
663 }
664
665 memset(nb,0,sizeof(*nb));
666 nb->nio = nio;
667 nb->port_id = port_id;
668 nb->next = bay->nio_list;
669 if (nb->next) nb->next->prev = nb;
670 bay->nio_list = nb;
671 return(0);
672 }
673
674 /* Remove a NIO binding */
675 int c2600_nm_remove_nio_binding(c2600_t *router,u_int nm_bay,u_int port_id)
676 {
677 struct c2600_nio_binding *nb;
678 struct c2600_nm_bay *bay;
679
680 if (!(bay = c2600_nm_get_info(router,nm_bay)))
681 return(-1);
682
683 if (!(nb = c2600_nm_find_nio_binding(router,nm_bay,port_id)))
684 return(-1); /* no nio binding for this slot/port */
685
686 /* tell the NM driver to stop using this NIO */
687 if (bay->nm_driver)
688 bay->nm_driver->nm_unset_nio(router,nm_bay,port_id);
689
690 /* remove this entry from the double linked list */
691 if (nb->next)
692 nb->next->prev = nb->prev;
693
694 if (nb->prev) {
695 nb->prev->next = nb->next;
696 } else {
697 bay->nio_list = nb->next;
698 }
699
700 /* unreference NIO object */
701 netio_release(nb->nio->name);
702 free(nb);
703 return(0);
704 }
705
706 /* Remove all NIO bindings for the specified NM */
707 int c2600_nm_remove_all_nio_bindings(c2600_t *router,u_int nm_bay)
708 {
709 struct c2600_nio_binding *nb,*next;
710 struct c2600_nm_bay *bay;
711
712 if (!(bay = c2600_nm_get_info(router,nm_bay)))
713 return(-1);
714
715 for(nb=bay->nio_list;nb;nb=next) {
716 next = nb->next;
717
718 /* tell the NM driver to stop using this NIO */
719 if (bay->nm_driver)
720 bay->nm_driver->nm_unset_nio(router,nm_bay,nb->port_id);
721
722 /* unreference NIO object */
723 netio_release(nb->nio->name);
724 free(nb);
725 }
726
727 bay->nio_list = NULL;
728 return(0);
729 }
730
731 /* Enable a Network IO descriptor for a Network Module */
732 int c2600_nm_enable_nio(c2600_t *router,u_int nm_bay,u_int port_id)
733 {
734 struct c2600_nio_binding *nb;
735 struct c2600_nm_bay *bay;
736
737 if (!(bay = c2600_nm_get_info(router,nm_bay)))
738 return(-1);
739
740 /* check that we have an NIO binding for this interface */
741 if (!(nb = c2600_nm_find_nio_binding(router,nm_bay,port_id)))
742 return(-1);
743
744 /* check that the driver is defined and successfully initialized */
745 if (!bay->nm_driver || !bay->drv_info)
746 return(-1);
747
748 return(bay->nm_driver->nm_set_nio(router,nm_bay,port_id,nb->nio));
749 }
750
751 /* Disable Network IO descriptor of a Network Module */
752 int c2600_nm_disable_nio(c2600_t *router,u_int nm_bay,u_int port_id)
753 {
754 struct c2600_nm_bay *bay;
755
756 if (!(bay = c2600_nm_get_info(router,nm_bay)))
757 return(-1);
758
759 /* check that the driver is defined and successfully initialized */
760 if (!bay->nm_driver || !bay->drv_info)
761 return(-1);
762
763 return(bay->nm_driver->nm_unset_nio(router,nm_bay,port_id));
764 }
765
766 /* Enable all NIO of the specified NM */
767 int c2600_nm_enable_all_nio(c2600_t *router,u_int nm_bay)
768 {
769 struct c2600_nio_binding *nb;
770 struct c2600_nm_bay *bay;
771
772 if (!(bay = c2600_nm_get_info(router,nm_bay)))
773 return(-1);
774
775 /* check that the driver is defined and successfully initialized */
776 if (!bay->nm_driver || !bay->drv_info)
777 return(-1);
778
779 for(nb=bay->nio_list;nb;nb=nb->next)
780 bay->nm_driver->nm_set_nio(router,nm_bay,nb->port_id,nb->nio);
781
782 return(0);
783 }
784
785 /* Disable all NIO of the specified NM */
786 int c2600_nm_disable_all_nio(c2600_t *router,u_int nm_bay)
787 {
788 struct c2600_nio_binding *nb;
789 struct c2600_nm_bay *bay;
790
791 if (!(bay = c2600_nm_get_info(router,nm_bay)))
792 return(-1);
793
794 /* check that the driver is defined and successfully initialized */
795 if (!bay->nm_driver || !bay->drv_info)
796 return(-1);
797
798 for(nb=bay->nio_list;nb;nb=nb->next)
799 bay->nm_driver->nm_unset_nio(router,nm_bay,nb->port_id);
800
801 return(0);
802 }
803
804 /* Initialize a Network Module */
805 int c2600_nm_init(c2600_t *router,u_int nm_bay)
806 {
807 struct c2600_nm_bay *bay;
808 size_t len;
809
810 if (!(bay = c2600_nm_get_info(router,nm_bay)))
811 return(-1);
812
813 /* Check that a device type is defined for this bay */
814 if (!bay->dev_type || !bay->nm_driver) {
815 vm_error(router->vm,"trying to init empty slot %u.\n",nm_bay);
816 return(-1);
817 }
818
819 /* Allocate device name */
820 len = strlen(bay->dev_type) + 10;
821 if (!(bay->dev_name = malloc(len))) {
822 vm_error(router->vm,"unable to allocate device name.\n");
823 return(-1);
824 }
825
826 snprintf(bay->dev_name,len,"%s(%u)",bay->dev_type,nm_bay);
827
828 /* Initialize NM driver */
829 if (bay->nm_driver->nm_init(router,bay->dev_name,nm_bay) == 1) {
830 vm_error(router->vm,"unable to initialize NM %u.\n",nm_bay);
831 return(-1);
832 }
833
834 /* Enable all NIO */
835 c2600_nm_enable_all_nio(router,nm_bay);
836 return(0);
837 }
838
839 /* Shutdown a Network Module */
840 int c2600_nm_shutdown(c2600_t *router,u_int nm_bay)
841 {
842 struct c2600_nm_bay *bay;
843
844 if (!(bay = c2600_nm_get_info(router,nm_bay)))
845 return(-1);
846
847 /* Check that a device type is defined for this bay */
848 if (!bay->dev_type || !bay->nm_driver) {
849 vm_error(router->vm,"trying to shut down empty slot %u.\n",nm_bay);
850 return(-1);
851 }
852
853 /* Disable all NIO */
854 c2600_nm_disable_all_nio(router,nm_bay);
855
856 /* Shutdown the NM driver */
857 if (bay->drv_info && (bay->nm_driver->nm_shutdown(router,nm_bay) == -1)) {
858 vm_error(router->vm,"unable to shutdown NM %u.\n",nm_bay);
859 return(-1);
860 }
861
862 free(bay->dev_name);
863 bay->dev_name = NULL;
864 bay->drv_info = NULL;
865 return(0);
866 }
867
868 /* Shutdown all NM of a router */
869 int c2600_nm_shutdown_all(c2600_t *router)
870 {
871 int i;
872
873 for(i=0;i<C2600_MAX_NM_BAYS;i++) {
874 if (!router->nm_bay[i].dev_type)
875 continue;
876
877 c2600_nm_shutdown(router,i);
878 }
879
880 return(0);
881 }
882
883 /* Show info about all NMs */
884 int c2600_nm_show_all_info(c2600_t *router)
885 {
886 struct c2600_nm_bay *bay;
887 int i;
888
889 for(i=0;i<C2600_MAX_NM_BAYS;i++) {
890 if (!(bay = c2600_nm_get_info(router,i)) || !bay->nm_driver)
891 continue;
892
893 if (bay->nm_driver->nm_show_info != NULL)
894 bay->nm_driver->nm_show_info(router,i);
895 }
896
897 return(0);
898 }
899
900 /* Maximum number of tokens in a NM description */
901 #define NM_DESC_MAX_TOKENS 8
902
903 /* Create a Network Module (command line) */
904 int c2600_cmd_nm_create(c2600_t *router,char *str)
905 {
906 char *tokens[NM_DESC_MAX_TOKENS];
907 int i,count,res;
908 u_int nm_bay;
909
910 /* A port adapter description is like "1:NM-1FE" */
911 if ((count = m_strsplit(str,':',tokens,NM_DESC_MAX_TOKENS)) != 2) {
912 vm_error(router->vm,"unable to parse NM description '%s'.\n",str);
913 return(-1);
914 }
915
916 /* Parse the NM bay id */
917 nm_bay = atoi(tokens[0]);
918
919 /* Add this new NM to the current NM list */
920 res = c2600_nm_add_binding(router,tokens[1],nm_bay);
921
922 /* The complete array was cleaned by strsplit */
923 for(i=0;i<NM_DESC_MAX_TOKENS;i++)
924 free(tokens[i]);
925
926 return(res);
927 }
928
929 /* Add a Network IO descriptor binding (command line) */
930 int c2600_cmd_add_nio(c2600_t *router,char *str)
931 {
932 char *tokens[NM_DESC_MAX_TOKENS];
933 int i,count,nio_type,res=-1;
934 u_int nm_bay,port_id;
935 netio_desc_t *nio;
936 char nio_name[128];
937
938 /* A port adapter description is like "1:3:tap:tap0" */
939 if ((count = m_strsplit(str,':',tokens,NM_DESC_MAX_TOKENS)) < 3) {
940 vm_error(router->vm,"unable to parse NIO description '%s'.\n",str);
941 return(-1);
942 }
943
944 /* Parse the NM bay */
945 nm_bay = atoi(tokens[0]);
946
947 /* Parse the NM port id */
948 port_id = atoi(tokens[1]);
949
950 /* Autogenerate a NIO name */
951 snprintf(nio_name,sizeof(nio_name),"c2600-i%u/%u/%u",
952 router->vm->instance_id,nm_bay,port_id);
953
954 /* Create the Network IO descriptor */
955 nio = NULL;
956 nio_type = netio_get_type(tokens[2]);
957
958 switch(nio_type) {
959 case NETIO_TYPE_UNIX:
960 if (count != 5) {
961 vm_error(router->vm,
962 "invalid number of arguments for UNIX NIO '%s'\n",str);
963 goto done;
964 }
965
966 nio = netio_desc_create_unix(nio_name,tokens[3],tokens[4]);
967 break;
968
969 case NETIO_TYPE_VDE:
970 if (count != 5) {
971 vm_error(router->vm,
972 "invalid number of arguments for VDE NIO '%s'\n",str);
973 goto done;
974 }
975
976 nio = netio_desc_create_vde(nio_name,tokens[3],tokens[4]);
977 break;
978
979 case NETIO_TYPE_TAP:
980 if (count != 4) {
981 vm_error(router->vm,
982 "invalid number of arguments for TAP NIO '%s'\n",str);
983 goto done;
984 }
985
986 nio = netio_desc_create_tap(nio_name,tokens[3]);
987 break;
988
989 case NETIO_TYPE_UDP:
990 if (count != 6) {
991 vm_error(router->vm,
992 "invalid number of arguments for UDP NIO '%s'\n",str);
993 goto done;
994 }
995
996 nio = netio_desc_create_udp(nio_name,atoi(tokens[3]),
997 tokens[4],atoi(tokens[5]));
998 break;
999
1000 case NETIO_TYPE_TCP_CLI:
1001 if (count != 5) {
1002 vm_error(router->vm,
1003 "invalid number of arguments for TCP CLI NIO '%s'\n",str);
1004 goto done;
1005 }
1006
1007 nio = netio_desc_create_tcp_cli(nio_name,tokens[3],tokens[4]);
1008 break;
1009
1010 case NETIO_TYPE_TCP_SER:
1011 if (count != 4) {
1012 vm_error(router->vm,
1013 "invalid number of arguments for TCP SER NIO '%s'\n",str);
1014 goto done;
1015 }
1016
1017 nio = netio_desc_create_tcp_ser(nio_name,tokens[3]);
1018 break;
1019
1020 case NETIO_TYPE_NULL:
1021 nio = netio_desc_create_null(nio_name);
1022 break;
1023
1024 #ifdef LINUX_ETH
1025 case NETIO_TYPE_LINUX_ETH:
1026 if (count != 4) {
1027 vm_error(router->vm,
1028 "invalid number of arguments for Linux Eth NIO '%s'\n",
1029 str);
1030 goto done;
1031 }
1032
1033 nio = netio_desc_create_lnxeth(nio_name,tokens[3]);
1034 break;
1035 #endif
1036
1037 #ifdef GEN_ETH
1038 case NETIO_TYPE_GEN_ETH:
1039 if (count != 4) {
1040 vm_error(router->vm,
1041 "invalid number of arguments for Generic Eth NIO '%s'\n",
1042 str);
1043 goto done;
1044 }
1045
1046 nio = netio_desc_create_geneth(nio_name,tokens[3]);
1047 break;
1048 #endif
1049
1050 default:
1051 vm_error(router->vm,"unknown NETIO type '%s'\n",tokens[2]);
1052 goto done;
1053 }
1054
1055 if (!nio) {
1056 vm_error(router->vm,"unable to create NETIO "
1057 "descriptor for NM slot %u\n",nm_bay);
1058 goto done;
1059 }
1060
1061 if (c2600_nm_add_nio_binding(router,nm_bay,port_id,nio_name) == -1) {
1062 vm_error(router->vm,"unable to add NETIO binding for slot %u\n",nm_bay);
1063 netio_release(nio_name);
1064 netio_delete(nio_name);
1065 goto done;
1066 }
1067
1068 netio_release(nio_name);
1069 res = 0;
1070
1071 done:
1072 /* The complete array was cleaned by strsplit */
1073 for(i=0;i<NM_DESC_MAX_TOKENS;i++)
1074 free(tokens[i]);
1075
1076 return(res);
1077 }
1078
1079 /* Show the list of available NM drivers */
1080 void c2600_nm_show_drivers(void)
1081 {
1082 int i;
1083
1084 printf("Available C2600 Network Module drivers:\n");
1085
1086 for(i=0;nm_drivers[i];i++) {
1087 printf(" * %s %s\n",
1088 nm_drivers[i]->dev_type,
1089 !nm_drivers[i]->supported ? "(NOT WORKING)" : "");
1090 }
1091
1092 printf("\n");
1093 }
1094
1095 /* Set the base MAC address of the chassis */
1096 static int c2600_burn_mac_addr(c2600_t *router,n_eth_addr_t *addr)
1097 {
1098 int i;
1099
1100 for(i=0;i<3;i++) {
1101 router->vm->chassis_cookie[i+1] = addr->eth_addr_byte[i*2] << 8;
1102 router->vm->chassis_cookie[i+1] |= addr->eth_addr_byte[(i*2)+1];
1103 }
1104
1105 return(0);
1106 }
1107
1108 /* Set mainboard type */
1109 int c2600_mainboard_set_type(c2600_t *router,char *mainboard_type)
1110 {
1111 struct c2600_mb_id *mb_info;
1112
1113 if (router->vm->status == VM_STATUS_RUNNING) {
1114 vm_error(router->vm,"unable to change mainboard type when online.\n");
1115 return(-1);
1116 }
1117
1118 if (!(mb_info = c2600_get_mb_info(mainboard_type))) {
1119 vm_error(router->vm,"unknown mainboard '%s'\n",mainboard_type);
1120 return(-1);
1121 }
1122
1123 router->mainboard_type = mainboard_type;
1124
1125 /* Set the cookie */
1126 memcpy(router->vm->chassis_cookie,
1127 eeprom_c2600_mb_data,sizeof(eeprom_c2600_mb_data));
1128
1129 router->vm->chassis_cookie[6] = mb_info->id;
1130
1131 /* Set the chassis base MAC address */
1132 c2600_burn_mac_addr(router,&router->mac_addr);
1133 return(0);
1134 }
1135
1136 /* Set chassis MAC address */
1137 int c2600_chassis_set_mac_addr(c2600_t *router,char *mac_addr)
1138 {
1139 if (parse_mac_addr(&router->mac_addr,mac_addr) == -1) {
1140 vm_error(router->vm,"unable to parse MAC address '%s'.\n",mac_addr);
1141 return(-1);
1142 }
1143
1144 /* Set the chassis base MAC address */
1145 c2600_burn_mac_addr(router,&router->mac_addr);
1146 return(0);
1147 }
1148
1149 /* Initialize a Cisco 2600 */
1150 static int c2600_init(c2600_t *router)
1151 {
1152 vm_instance_t *vm = router->vm;
1153
1154 /* Create the PCI bus */
1155 if (!(vm->pci_bus[0] = pci_bus_create("PCI0",0))) {
1156 vm_error(vm,"unable to create PCI data.\n");
1157 return(-1);
1158 }
1159
1160 /* Create the PCI controller */
1161 if (dev_c2600_pci_init(vm,"c2600_pci",C2600_PCICTRL_ADDR,0x1000,
1162 vm->pci_bus[0]) == -1)
1163 return(-1);
1164
1165 /* Bind PCI bus to slots 0 and 1 */
1166 router->nm_bay[0].pci_map = vm->pci_bus[0];
1167 router->nm_bay[1].pci_map = vm->pci_bus[0];
1168
1169 vm->elf_machine_id = C2600_ELF_MACHINE_ID;
1170 return(0);
1171 }
1172
1173 /* Show C2600 hardware info */
1174 void c2600_show_hardware(c2600_t *router)
1175 {
1176 vm_instance_t *vm = router->vm;
1177
1178 printf("C2600 instance '%s' (id %d):\n",vm->name,vm->instance_id);
1179
1180 printf(" VM Status : %d\n",vm->status);
1181 printf(" RAM size : %u Mb\n",vm->ram_size);
1182 printf(" NVRAM size : %u Kb\n",vm->nvram_size);
1183 printf(" IOS image : %s\n\n",vm->ios_image);
1184
1185 if (vm->debug_level > 0) {
1186 dev_show_list(vm);
1187 pci_dev_show_list(vm->pci_bus[0]);
1188 pci_dev_show_list(vm->pci_bus[1]);
1189 printf("\n");
1190 }
1191 }
1192
1193 /* Initialize default parameters for a C2600 */
1194 void c2600_init_defaults(c2600_t *router)
1195 {
1196 vm_instance_t *vm = router->vm;
1197 n_eth_addr_t *m;
1198 m_uint16_t pid;
1199
1200 pid = (m_uint16_t)getpid();
1201
1202 /* Generate a chassis MAC address based on the instance ID */
1203 m = &router->mac_addr;
1204 m->eth_addr_byte[0] = vm_get_mac_addr_msb(vm);
1205 m->eth_addr_byte[1] = vm->instance_id & 0xFF;
1206 m->eth_addr_byte[2] = pid >> 8;
1207 m->eth_addr_byte[3] = pid & 0xFF;
1208 m->eth_addr_byte[4] = 0x00;
1209 m->eth_addr_byte[5] = 0x00;
1210
1211 c2600_init_eeprom_groups(router);
1212 c2600_mainboard_set_type(router,C2600_DEFAULT_MAINBOARD);
1213 c2600_burn_mac_addr(router,&router->mac_addr);
1214
1215 vm->ram_mmap = C2600_DEFAULT_RAM_MMAP;
1216 vm->ram_size = C2600_DEFAULT_RAM_SIZE;
1217 vm->rom_size = C2600_DEFAULT_ROM_SIZE;
1218 vm->nvram_size = C2600_DEFAULT_NVRAM_SIZE;
1219 vm->conf_reg_setup = C2600_DEFAULT_CONF_REG;
1220 vm->clock_divisor = C2600_DEFAULT_CLOCK_DIV;
1221 vm->nvram_rom_space = C2600_NVRAM_ROM_RES_SIZE;
1222 router->nm_iomem_size = C2600_DEFAULT_IOMEM_SIZE;
1223
1224 vm->pcmcia_disk_size[0] = C2600_DEFAULT_DISK0_SIZE;
1225 vm->pcmcia_disk_size[1] = C2600_DEFAULT_DISK1_SIZE;
1226
1227 /* Enable NVRAM operations to load/store configs */
1228 vm->nvram_extract_config = c2600_nvram_extract_config;
1229 vm->nvram_push_config = c2600_nvram_push_config;
1230 }
1231
1232 /* Set an IRQ */
1233 static void c2600_set_irq(vm_instance_t *vm,u_int irq)
1234 {
1235 c2600_t *router = VM_C2600(vm);
1236 cpu_ppc_t *cpu = CPU_PPC32(vm->boot_cpu);
1237
1238 switch(irq) {
1239 case C2600_VTIMER_IRQ:
1240 mpc860_set_pending_irq(router->mpc_data,30);
1241 break;
1242 case C2600_DUART_IRQ:
1243 mpc860_set_pending_irq(router->mpc_data,29);
1244 break;
1245 case C2600_NETIO_IRQ:
1246 mpc860_set_pending_irq(router->mpc_data,25);
1247 break;
1248 case C2600_PA_MGMT_IRQ:
1249 mpc860_set_pending_irq(router->mpc_data,27);
1250 break;
1251
1252 /* IRQ test */
1253 case 255:
1254 mpc860_set_pending_irq(router->mpc_data,24);
1255 break;
1256 }
1257
1258 if (cpu->irq_idle_preempt[irq])
1259 cpu_idle_break_wait(cpu->gen);
1260 }
1261
1262 /* Clear an IRQ */
1263 static void c2600_clear_irq(vm_instance_t *vm,u_int irq)
1264 {
1265 c2600_t *router = VM_C2600(vm);
1266
1267 switch(irq) {
1268 case C2600_VTIMER_IRQ:
1269 mpc860_clear_pending_irq(router->mpc_data,30);
1270 break;
1271 case C2600_DUART_IRQ:
1272 mpc860_clear_pending_irq(router->mpc_data,29);
1273 break;
1274 case C2600_NETIO_IRQ:
1275 mpc860_clear_pending_irq(router->mpc_data,25);
1276 break;
1277 case C2600_PA_MGMT_IRQ:
1278 mpc860_clear_pending_irq(router->mpc_data,27);
1279 break;
1280
1281 /* IRQ test */
1282 case 255:
1283 mpc860_clear_pending_irq(router->mpc_data,24);
1284 break;
1285 }
1286 }
1287
1288 /* Initialize the C2600 Platform */
1289 int c2600_init_platform(c2600_t *router)
1290 {
1291 vm_instance_t *vm = router->vm;
1292 struct c2600_mb_id *mb_info;
1293 struct c2600_nm_bay *nm_bay;
1294 vm_obj_t *obj;
1295 cpu_ppc_t *cpu;
1296 cpu_gen_t *gen;
1297 int i;
1298
1299 /* Copy config register setup into "active" config register */
1300 vm->conf_reg = vm->conf_reg_setup;
1301
1302 /* Create Console and AUX ports */
1303 vm_init_vtty(vm);
1304
1305 /* Create a CPU group */
1306 vm->cpu_group = cpu_group_create("System CPU");
1307
1308 /* Initialize the virtual PowerPC processor */
1309 if (!(gen = cpu_create(vm,CPU_TYPE_PPC32,0))) {
1310 vm_error(vm,"unable to create CPU!\n");
1311 return(-1);
1312 }
1313
1314 cpu = CPU_PPC32(gen);
1315
1316 /* Add this CPU to the system CPU group */
1317 cpu_group_add(vm->cpu_group,gen);
1318 vm->boot_cpu = gen;
1319
1320 /* Set processor ID */
1321 ppc32_set_pvr(cpu,0x00500202);
1322
1323 /* Mark the Network IO interrupt as high priority */
1324 cpu->irq_idle_preempt[C2600_NETIO_IRQ] = TRUE;
1325 cpu->irq_idle_preempt[C2600_DUART_IRQ] = TRUE;
1326
1327 /* Copy some parameters from VM to CPU (idle PC, ...) */
1328 cpu->idle_pc = vm->idle_pc;
1329
1330 if (vm->timer_irq_check_itv)
1331 cpu->timer_irq_check_itv = vm->timer_irq_check_itv;
1332
1333 /* Remote emulator control */
1334 dev_remote_control_init(vm,0xf6000000,0x1000);
1335
1336 /* MPC860 */
1337 if (dev_mpc860_init(vm,"MPC860",C2600_MPC860_ADDR,0x10000) == -1)
1338 return(-1);
1339
1340 if (!(obj = vm_object_find(router->vm,"MPC860")))
1341 return(-1);
1342
1343 router->mpc_data = obj->data;
1344
1345 /* IO FPGA */
1346 if (dev_c2600_iofpga_init(router,C2600_IOFPGA_ADDR,0x10000) == -1)
1347 return(-1);
1348
1349 /* Initialize the chassis */
1350 if (c2600_init(router) == -1)
1351 return(-1);
1352
1353 /* Initialize RAM */
1354 vm_ram_init(vm,0x00000000ULL);
1355
1356 /* Initialize ROM */
1357 if (!vm->rom_filename) {
1358 /* use embedded ROM */
1359 dev_rom_init(vm,"rom",C2600_ROM_ADDR,512*1024,
1360 ppc32_microcode,ppc32_microcode_len);
1361 } else {
1362 /* use alternate ROM */
1363 dev_ram_init(vm,"rom",TRUE,TRUE,NULL,FALSE,C2600_ROM_ADDR,512*1024);
1364 }
1365
1366 /* RAM aliasing */
1367 dev_create_ram_alias(vm,"ram_alias","ram",0x80000000,vm->ram_size*1048576);
1368
1369 /* NVRAM */
1370 dev_ram_init(vm,"nvram",TRUE,FALSE,NULL,FALSE,
1371 C2600_NVRAM_ADDR,vm->nvram_size*4096);
1372 c2600_nvram_check_empty_config(vm);
1373
1374 /* Bootflash */
1375 dev_bootflash_init(vm,"flash0",C2600_FLASH_ADDR,8*1048576);
1376 dev_bootflash_init(vm,"flash1",C2600_FLASH_ADDR+0x800000,8*1048576);
1377
1378 /* Initialize the NS16552 DUART */
1379 dev_ns16552_init(vm,C2600_DUART_ADDR,0x1000,0,C2600_DUART_IRQ,
1380 vm->vtty_con,vm->vtty_aux);
1381
1382 /* Initialize the mainboard ports */
1383 if ((mb_info = c2600_get_mb_info(router->mainboard_type)) != NULL)
1384 c2600_nm_add_binding(router,mb_info->mb_driver,0);
1385
1386 /* Initialize Network Modules */
1387 for(i=0;i<C2600_MAX_NM_BAYS;i++) {
1388 nm_bay = &router->nm_bay[i];
1389
1390 if (!nm_bay->dev_type)
1391 continue;
1392
1393 if (c2600_nm_init(router,i) == -1) {
1394 vm_error(vm,"unable to create Network Module \"%s\"\n",
1395 nm_bay->dev_type);
1396 return(-1);
1397 }
1398 }
1399
1400 /* Show device list */
1401 c2600_show_hardware(router);
1402 return(0);
1403 }
1404
1405 static struct ppc32_bat_prog bat_array[] = {
1406 { PPC32_IBAT_IDX, 0, 0xfff0001e, 0xfff00001 },
1407 { PPC32_IBAT_IDX, 1, 0x00001ffe, 0x00000001 },
1408 { PPC32_IBAT_IDX, 2, 0x00000000, 0xee3e0072 },
1409 { PPC32_IBAT_IDX, 3, 0x80001ffe, 0x80000001 },
1410
1411 { PPC32_DBAT_IDX, 0, 0x80001ffe, 0x80000042 },
1412 { PPC32_DBAT_IDX, 1, 0x00001ffe, 0x0000002a },
1413 { PPC32_DBAT_IDX, 2, 0x40007ffe, 0x4000002a },
1414 { PPC32_DBAT_IDX, 3, 0xfc0007fe, 0xfc00002a },
1415 { -1, -1, 0, 0 },
1416 };
1417
1418 /* Boot the IOS image */
1419 int c2600_boot_ios(c2600_t *router)
1420 {
1421 vm_instance_t *vm = router->vm;
1422 cpu_ppc_t *cpu;
1423
1424 if (!vm->boot_cpu)
1425 return(-1);
1426
1427 /* Suspend CPU activity since we will restart directly from ROM */
1428 vm_suspend(vm);
1429
1430 /* Check that CPU activity is really suspended */
1431 if (cpu_group_sync_state(vm->cpu_group) == -1) {
1432 vm_error(vm,"unable to sync with system CPUs.\n");
1433 return(-1);
1434 }
1435
1436 /* Reset the boot CPU */
1437 cpu = CPU_PPC32(vm->boot_cpu);
1438 ppc32_reset(cpu);
1439
1440 /* Adjust stack pointer */
1441 cpu->gpr[1] |= 0x80000000;
1442
1443 /* Load BAT registers */
1444 printf("Loading BAT registers\n");
1445 ppc32_load_bat_array(CPU_PPC32(vm->boot_cpu),bat_array);
1446
1447 /* IRQ routing */
1448 vm->set_irq = c2600_set_irq;
1449 vm->clear_irq = c2600_clear_irq;
1450
1451 /* Load IOS image */
1452 if (ppc32_load_elf_image(cpu,vm->ios_image,
1453 (vm->ghost_status == VM_GHOST_RAM_USE),
1454 &vm->ios_entry_point) < 0)
1455 {
1456 vm_error(vm,"failed to load Cisco IOS image '%s'.\n",vm->ios_image);
1457 return(-1);
1458 }
1459
1460 /* Launch the simulation */
1461 printf("\nC2600 '%s': starting simulation (CPU0 IA=0x%8.8x), "
1462 "JIT %sabled.\n",
1463 vm->name,cpu->ia,vm->jit_use ? "en":"dis");
1464
1465 vm_log(vm,"C2600_BOOT",
1466 "starting instance (CPU0 PC=0x%8.8x,idle_pc=0x%8.8x,JIT %s)\n",
1467 cpu->ia,cpu->idle_pc,vm->jit_use ? "on":"off");
1468
1469 /* Start main CPU */
1470 if (vm->ghost_status != VM_GHOST_RAM_GENERATE) {
1471 vm->status = VM_STATUS_RUNNING;
1472 cpu_start(vm->boot_cpu);
1473 } else {
1474 vm->status = VM_STATUS_SHUTDOWN;
1475 }
1476 return(0);
1477 }
1478
1479 /* Initialize a Cisco 2600 instance */
1480 int c2600_init_instance(c2600_t *router)
1481 {
1482 vm_instance_t *vm = router->vm;
1483 m_uint32_t rom_entry_point;
1484 cpu_ppc_t *cpu0;
1485
1486 if (!vm->ios_image) {
1487 vm_error(vm,"no Cisco IOS image defined.");
1488 return(-1);
1489 }
1490
1491 /* Initialize the C2600 platform */
1492 if (c2600_init_platform(router) == -1) {
1493 vm_error(vm,"unable to initialize the platform hardware.\n");
1494 return(-1);
1495 }
1496
1497 /* Load IOS configuration file */
1498 if (vm->ios_config != NULL) {
1499 vm_nvram_push_config(vm,vm->ios_config);
1500 vm->conf_reg &= ~0x40;
1501 }
1502
1503 /* Load ROM (ELF image or embedded) */
1504 cpu0 = CPU_PPC32(vm->boot_cpu);
1505 rom_entry_point = (m_uint32_t)PPC32_ROM_START;
1506
1507 if ((vm->rom_filename != NULL) &&
1508 (ppc32_load_elf_image(cpu0,vm->rom_filename,0,&rom_entry_point) < 0))
1509 {
1510 vm_error(vm,"unable to load alternate ROM '%s', "
1511 "fallback to embedded ROM.\n\n",vm->rom_filename);
1512 vm->rom_filename = NULL;
1513 }
1514
1515 return(c2600_boot_ios(router));
1516 }
1517
1518 /* Stop a Cisco 2600 instance */
1519 int c2600_stop_instance(c2600_t *router)
1520 {
1521 vm_instance_t *vm = router->vm;
1522
1523 printf("\nC2600 '%s': stopping simulation.\n",vm->name);
1524 vm_log(vm,"C2600_STOP","stopping simulation.\n");
1525
1526 /* Stop all CPUs */
1527 if (vm->cpu_group != NULL) {
1528 vm_stop(vm);
1529
1530 if (cpu_group_sync_state(vm->cpu_group) == -1) {
1531 vm_error(vm,"unable to sync with system CPUs.\n");
1532 return(-1);
1533 }
1534 }
1535
1536 /* Free resources that were used during execution to emulate hardware */
1537 c2600_nm_shutdown_all(router);
1538 vm_hardware_shutdown(vm);
1539 return(0);
1540 }

  ViewVC Help
Powered by ViewVC 1.1.26