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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (show annotations)
Sat Oct 6 16:29:14 2007 UTC (16 years, 6 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7/dev_c2600.c
File MIME type: text/plain
File size: 41872 byte(s)
dynamips-0.2.7

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

  ViewVC Help
Powered by ViewVC 1.1.26