/[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 12 - (show annotations)
Sat Oct 6 16:45:40 2007 UTC (11 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 26687 byte(s)
make working copy

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 xm_model;
51 int supported;
52 };
53
54 struct c2600_mb_id c2600_mainboard_id[] = {
55 { "2610" , "CISCO2600-MB-1E" , 0x0091, FALSE, TRUE },
56 { "2611" , "CISCO2600-MB-2E" , 0x0092, FALSE, TRUE },
57 { "2620" , "CISCO2600-MB-1FE" , 0x0094, FALSE, TRUE },
58 { "2621" , "CISCO2600-MB-2FE" , 0x00a2, FALSE, TRUE },
59 { "2610XM" , "CISCO2600-MB-1FE" , 0x036a, TRUE, TRUE },
60 { "2611XM" , "CISCO2600-MB-2FE" , 0x036b, TRUE, FALSE },
61 { "2620XM" , "CISCO2600-MB-1FE" , 0x036c, TRUE, TRUE },
62 { "2621XM" , "CISCO2600-MB-2FE" , 0x036d, TRUE, FALSE },
63 { "2650XM" , "CISCO2600-MB-1FE" , 0x036e, TRUE, TRUE },
64 { "2651XM" , "CISCO2600-MB-2FE" , 0x036f, TRUE, FALSE },
65 { NULL , NULL , 0x0000, FALSE, FALSE },
66 };
67
68 /* ======================================================================== */
69 /* Network Module Drivers */
70 /* ======================================================================== */
71 static struct cisco_card_driver *nm_drivers[] = {
72 &dev_c2600_mb1e_eth_driver,
73 &dev_c2600_mb2e_eth_driver,
74 &dev_c2600_mb1fe_eth_driver,
75 &dev_c2600_mb2fe_eth_driver,
76
77 &dev_c2600_nm_1e_driver,
78 &dev_c2600_nm_4e_driver,
79 &dev_c2600_nm_1fe_tx_driver,
80 &dev_c2600_nm_16esw_driver,
81
82 &dev_c2600_nm_nam_driver,
83 &dev_c2600_nm_cids_driver,
84
85 NULL,
86 };
87
88 /* ======================================================================== */
89 /* Cisco 2600 router instances */
90 /* ======================================================================== */
91
92 /* Initialize default parameters for a C2600 */
93 static void c2600_init_defaults(c2600_t *router);
94
95 /* Read a byte from the NVRAM */
96 static inline m_uint8_t nvram_read_byte(u_char *base,u_int offset)
97 {
98 m_uint8_t *ptr;
99
100 ptr = (m_uint8_t *)base + (offset << 2);
101 return(*ptr);
102 }
103
104 /* Write a byte to the NVRAM */
105 static inline void nvram_write_byte(u_char *base,u_int offset,m_uint8_t val)
106 {
107 m_uint8_t *ptr;
108
109 ptr = (m_uint8_t *)base + (offset << 2);
110 *ptr = val;
111 }
112
113 /* Read a 16-bit value from NVRAM */
114 static m_uint16_t nvram_read16(u_char *base,u_int offset)
115 {
116 m_uint16_t val;
117 val = nvram_read_byte(base,offset) << 8;
118 val |= nvram_read_byte(base,offset+1);
119 return(val);
120 }
121
122 /* Write a 16-bit value to NVRAM */
123 static void nvram_write16(u_char *base,u_int offset,m_uint16_t val)
124 {
125 nvram_write_byte(base,offset,val >> 8);
126 nvram_write_byte(base,offset+1,val & 0xFF);
127 }
128
129 /* Read a 32-bit value from NVRAM */
130 static m_uint32_t nvram_read32(u_char *base,u_int offset)
131 {
132 m_uint32_t val;
133 val = nvram_read_byte(base,offset) << 24;
134 val |= nvram_read_byte(base,offset+1) << 16;
135 val |= nvram_read_byte(base,offset+2) << 8;
136 val |= nvram_read_byte(base,offset+3);
137 return(val);
138 }
139
140 /* Write a 32-bit value to NVRAM */
141 static void nvram_write32(u_char *base,u_int offset,m_uint32_t val)
142 {
143 nvram_write_byte(base,offset,val >> 24);
144 nvram_write_byte(base,offset+1,val >> 16);
145 nvram_write_byte(base,offset+2,val >> 8);
146 nvram_write_byte(base,offset+3,val & 0xFF);
147 }
148
149 /* Read a buffer from NVRAM */
150 static void nvram_memcpy_from(u_char *base,u_int offset,u_char *data,u_int len)
151 {
152 u_int i;
153
154 for(i=0;i<len;i++) {
155 *data = nvram_read_byte(base,offset+i);
156 data++;
157 }
158 }
159
160 /* Write a buffer from NVRAM */
161 static void nvram_memcpy_to(u_char *base,u_int offset,u_char *data,u_int len)
162 {
163 u_int i;
164
165 for(i=0;i<len;i++) {
166 nvram_write_byte(base,offset+i,*data);
167 data++;
168 }
169 }
170
171 /* Directly extract the configuration from the NVRAM device */
172 ssize_t c2600_nvram_extract_config(vm_instance_t *vm,u_char **buffer)
173 {
174 u_char *base_ptr;
175 u_int ios_ptr,cfg_ptr,end_ptr;
176 m_uint32_t start,nvlen;
177 m_uint16_t magic1,magic2;
178 struct vdevice *nvram_dev;
179 off_t nvram_size;
180 int fd;
181
182 if ((nvram_dev = dev_get_by_name(vm,"nvram")))
183 dev_sync(nvram_dev);
184
185 fd = vm_mmap_open_file(vm,"nvram",&base_ptr,&nvram_size);
186
187 if (fd == -1)
188 return(-1);
189
190 ios_ptr = vm->nvram_rom_space;
191 end_ptr = nvram_size;
192
193 if ((ios_ptr + 0x30) >= end_ptr) {
194 vm_error(vm,"NVRAM file too small\n");
195 return(-1);
196 }
197
198 magic1 = nvram_read16(base_ptr,ios_ptr+0x06);
199 magic2 = nvram_read16(base_ptr,ios_ptr+0x08);
200
201 if ((magic1 != 0xF0A5) || (magic2 != 0xABCD)) {
202 vm_error(vm,"unable to find IOS magic numbers (0x%x,0x%x)!\n",
203 magic1,magic2);
204 return(-1);
205 }
206
207 start = nvram_read32(base_ptr,ios_ptr+0x10) + 1;
208 nvlen = nvram_read32(base_ptr,ios_ptr+0x18);
209
210 printf("START = 0x%8.8x, LEN = 0x%8.8x\n",start,nvlen);
211 printf("END = 0x%8.8x\n",nvram_read32(base_ptr,ios_ptr+0x14));
212
213 if (!(*buffer = malloc(nvlen+1))) {
214 vm_error(vm,"unable to allocate config buffer (%u bytes)\n",nvlen);
215 return(-1);
216 }
217
218 cfg_ptr = ios_ptr + start + 0x08;
219
220 if ((cfg_ptr + nvlen) > end_ptr) {
221 vm_error(vm,"NVRAM file too small\n");
222 return(-1);
223 }
224
225 nvram_memcpy_from(base_ptr,cfg_ptr,*buffer,nvlen-1);
226 (*buffer)[nvlen-1] = 0;
227 return(nvlen-1);
228 }
229
230 /* Compute NVRAM checksum */
231 static m_uint16_t c2600_nvram_cksum(u_char *base_ptr,u_int offset,size_t count)
232 {
233 m_uint32_t sum = 0;
234
235 while(count > 1) {
236 sum = sum + nvram_read16(base_ptr,offset);
237 offset += 2;
238 count -= sizeof(m_uint16_t);
239 }
240
241 if (count > 0)
242 sum = sum + ((nvram_read16(base_ptr,offset) & 0xFF) << 8);
243
244 while(sum>>16)
245 sum = (sum & 0xffff) + (sum >> 16);
246
247 return(~sum);
248 }
249
250 /* Directly push the IOS configuration to the NVRAM device */
251 int c2600_nvram_push_config(vm_instance_t *vm,u_char *buffer,size_t len)
252 {
253 m_uint32_t cfg_offset,cklen,tmp,ios_ptr,cfg_ptr;
254 m_uint16_t cksum;
255 u_char *base_ptr;
256 int fd;
257
258 fd = vm_mmap_create_file(vm,"nvram",vm->nvram_size*4096,&base_ptr);
259
260 if (fd == -1)
261 return(-1);
262
263 cfg_offset = 0x2c;
264 ios_ptr = vm->nvram_rom_space;
265 cfg_ptr = ios_ptr + cfg_offset;
266
267 /* Write IOS tag, uncompressed config... */
268 nvram_write16(base_ptr,ios_ptr+0x06,0xF0A5);
269 nvram_write16(base_ptr,ios_ptr+0x08,0xABCD);
270 nvram_write16(base_ptr,ios_ptr+0x0a,0x0001);
271 nvram_write16(base_ptr,ios_ptr+0x0c,0x0000);
272 nvram_write16(base_ptr,ios_ptr+0x0e,0x0c04);
273
274 /* Store file contents to NVRAM */
275 nvram_memcpy_to(base_ptr,cfg_ptr,buffer,len);
276
277 /* Write config addresses + size */
278 tmp = cfg_offset - 0x08;
279
280 nvram_write32(base_ptr,ios_ptr+0x10,tmp);
281 nvram_write32(base_ptr,ios_ptr+0x14,tmp + len);
282 nvram_write32(base_ptr,ios_ptr+0x18,len);
283
284 /* Compute the checksum */
285 cklen = (vm->nvram_size*1024) - (vm->nvram_rom_space + 0x08);
286 cksum = c2600_nvram_cksum(base_ptr,ios_ptr+0x08,cklen);
287 nvram_write16(base_ptr,ios_ptr+0x0c,cksum);
288
289 vm_mmap_close_file(fd,base_ptr,vm->nvram_size*4096);
290 return(0);
291 }
292
293 /* Check for empty config */
294 int c2600_nvram_check_empty_config(vm_instance_t *vm)
295 {
296 struct vdevice *dev;
297 m_uint64_t addr;
298 m_uint32_t len;
299
300 if (!(dev = dev_get_by_name(vm,"nvram")))
301 return(-1);
302
303 addr = dev->phys_addr + (vm->nvram_rom_space << 2);
304 len = dev->phys_len - (vm->nvram_rom_space << 2);
305
306 while(len > 0) {
307 if (physmem_copy_u32_from_vm(vm,addr) != 0)
308 return(0);
309
310 addr += sizeof(m_uint32_t);
311 len -= sizeof(m_uint32_t);
312 }
313
314 /* Empty NVRAM */
315 vm->conf_reg |= 0x0040;
316 printf("NVRAM is empty, setting config register to 0x%x\n",vm->conf_reg);
317 return(0);
318 }
319
320 /* Create a new router instance */
321 static int c2600_create_instance(vm_instance_t *vm)
322 {
323 c2600_t *router;
324
325 if (!(router = malloc(sizeof(*router)))) {
326 fprintf(stderr,"C2600 '%s': Unable to create new instance!\n",vm->name);
327 return(-1);
328 }
329
330 memset(router,0,sizeof(*router));
331 router->vm = vm;
332 vm->hw_data = router;
333
334 c2600_init_defaults(router);
335 return(0);
336 }
337
338 /* Free resources used by a router instance */
339 static int c2600_delete_instance(vm_instance_t *vm)
340 {
341 c2600_t *router = VM_C2600(vm);
342 int i;
343
344 /* Stop all CPUs */
345 if (vm->cpu_group != NULL) {
346 vm_stop(vm);
347
348 if (cpu_group_sync_state(vm->cpu_group) == -1) {
349 vm_error(vm,"unable to sync with system CPUs.\n");
350 return(FALSE);
351 }
352 }
353
354 /* Remove NIO bindings */
355 for(i=0;i<vm->nr_slots;i++)
356 vm_slot_remove_all_nio_bindings(vm,i);
357
358 /* Shutdown all Network Modules */
359 vm_slot_shutdown_all(vm);
360
361 /* Free mainboard EEPROM */
362 cisco_eeprom_free(&router->mb_eeprom);
363
364 /* Free all resources used by VM */
365 vm_free(vm);
366
367 /* Free the router structure */
368 free(router);
369 return(TRUE);
370 }
371
372 /* Save configuration of a C2600 instance */
373 void c2600_save_config(vm_instance_t *vm,FILE *fd)
374 {
375 c2600_t *router = VM_C2600(vm);
376
377 fprintf(fd,"c2600 set_chassis %s %s\n\n",vm->name,router->mainboard_type);
378 }
379
380 /* Get WIC device address for the specified onboard port */
381 int c2600_get_onboard_wic_addr(u_int slot,m_uint64_t *phys_addr)
382 {
383 if (slot >= C2600_MAX_WIC_BAYS)
384 return(-1);
385
386 *phys_addr = C2600_WIC_ADDR + (slot * C2600_WIC_SIZE);
387 return(0);
388 }
389
390 /* Set EEPROM for the specified slot */
391 int c2600_set_slot_eeprom(c2600_t *router,u_int slot,
392 struct cisco_eeprom *eeprom)
393 {
394 switch(slot) {
395 case 1:
396 router->nm_eeprom_group.eeprom[0] = eeprom;
397 return(0);
398 default:
399 return(-1);
400 }
401 }
402
403 /* Get slot/port corresponding to specified network IRQ */
404 static inline void
405 c2600_net_irq_get_slot_port(u_int irq,u_int *slot,u_int *port)
406 {
407 irq -= C2600_NETIO_IRQ_BASE;
408 *port = irq & C2600_NETIO_IRQ_PORT_MASK;
409 *slot = irq >> C2600_NETIO_IRQ_PORT_BITS;
410 }
411
412 /* Get network IRQ for specified slot/port */
413 u_int c2600_net_irq_for_slot_port(u_int slot,u_int port)
414 {
415 u_int irq;
416
417 irq = (slot << C2600_NETIO_IRQ_PORT_BITS) + port;
418 irq += C2600_NETIO_IRQ_BASE;
419
420 return(irq);
421 }
422
423 /* Find Cisco 2600 Mainboard info */
424 static struct c2600_mb_id *c2600_get_mb_info(char *mainboard_type)
425 {
426 int i;
427
428 for(i=0;c2600_mainboard_id[i].name;i++)
429 if (!strcmp(c2600_mainboard_id[i].name,mainboard_type))
430 return(&c2600_mainboard_id[i]);
431
432 return NULL;
433 }
434
435 /* Show all available mainboards */
436 void c2600_mainboard_show_drivers(void)
437 {
438 int i;
439
440 printf("Available C2600 chassis drivers:\n");
441
442 for(i=0;c2600_mainboard_id[i].name;i++)
443 printf(" * %s %s\n",
444 c2600_mainboard_id[i].name,
445 !c2600_mainboard_id[i].supported ? "(NOT WORKING)" : "");
446
447 printf("\n");
448 }
449
450 /* Show the list of available NM drivers */
451 void c2600_nm_show_drivers(void)
452 {
453 int i;
454
455 printf("Available C2600 Network Module drivers:\n");
456
457 for(i=0;nm_drivers[i];i++) {
458 printf(" * %s %s\n",
459 nm_drivers[i]->dev_type,
460 !nm_drivers[i]->supported ? "(NOT WORKING)" : "");
461 }
462
463 printf("\n");
464 }
465
466 /* Set the base MAC address of the chassis */
467 static int c2600_burn_mac_addr(c2600_t *router,n_eth_addr_t *addr)
468 {
469 int i;
470
471 for(i=0;i<3;i++) {
472 router->vm->chassis_cookie[i+1] = addr->eth_addr_byte[i*2] << 8;
473 router->vm->chassis_cookie[i+1] |= addr->eth_addr_byte[(i*2)+1];
474 }
475
476 return(0);
477 }
478
479 /* Set mainboard type */
480 int c2600_mainboard_set_type(c2600_t *router,char *mainboard_type)
481 {
482 struct c2600_mb_id *mb_info;
483
484 if (router->vm->status == VM_STATUS_RUNNING) {
485 vm_error(router->vm,"unable to change mainboard type when online.\n");
486 return(-1);
487 }
488
489 if (!(mb_info = c2600_get_mb_info(mainboard_type))) {
490 vm_error(router->vm,"unknown mainboard '%s'\n",mainboard_type);
491 return(-1);
492 }
493
494 router->mainboard_type = mainboard_type;
495 router->xm_model = mb_info->xm_model;
496
497 /* Set the cookie */
498 memcpy(router->vm->chassis_cookie,
499 eeprom_c2600_mb_data,sizeof(eeprom_c2600_mb_data));
500
501 router->vm->chassis_cookie[6] = mb_info->id;
502
503 /* Set the chassis base MAC address */
504 c2600_burn_mac_addr(router,&router->mac_addr);
505
506 /* Set the mainboard driver */
507 if (vm_slot_active(router->vm,0,0))
508 vm_slot_remove_binding(router->vm,0,0);
509
510 vm_slot_add_binding(router->vm,mb_info->mb_driver,0,0);
511 return(0);
512 }
513
514 /* Set chassis MAC address */
515 int c2600_chassis_set_mac_addr(c2600_t *router,char *mac_addr)
516 {
517 if (parse_mac_addr(&router->mac_addr,mac_addr) == -1) {
518 vm_error(router->vm,"unable to parse MAC address '%s'.\n",mac_addr);
519 return(-1);
520 }
521
522 /* Set the chassis base MAC address */
523 c2600_burn_mac_addr(router,&router->mac_addr);
524 return(0);
525 }
526
527 /* Initialize a Cisco 2600 */
528 static int c2600_init(c2600_t *router)
529 {
530 vm_instance_t *vm = router->vm;
531
532 /* Create the PCI bus */
533 if (!(vm->pci_bus[0] = pci_bus_create("PCI0",0))) {
534 vm_error(vm,"unable to create PCI data.\n");
535 return(-1);
536 }
537
538 /* Create the PCI controller */
539 if (dev_c2600_pci_init(vm,"c2600_pci",C2600_PCICTRL_ADDR,0x10000,
540 vm->pci_bus[0]) == -1)
541 return(-1);
542
543 /* Bind PCI bus to slots 0 and 1 */
544 vm->slots_pci_bus[0] = vm->pci_bus[0];
545 vm->slots_pci_bus[1] = vm->pci_bus[0];
546
547 vm->elf_machine_id = C2600_ELF_MACHINE_ID;
548 return(0);
549 }
550
551 /* Show C2600 hardware info */
552 void c2600_show_hardware(c2600_t *router)
553 {
554 vm_instance_t *vm = router->vm;
555
556 printf("C2600 instance '%s' (id %d):\n",vm->name,vm->instance_id);
557
558 printf(" VM Status : %d\n",vm->status);
559 printf(" RAM size : %u Mb\n",vm->ram_size);
560 printf(" NVRAM size : %u Kb\n",vm->nvram_size);
561 printf(" IOS image : %s\n\n",vm->ios_image);
562
563 if (vm->debug_level > 0) {
564 dev_show_list(vm);
565 pci_dev_show_list(vm->pci_bus[0]);
566 pci_dev_show_list(vm->pci_bus[1]);
567 printf("\n");
568 }
569 }
570
571 /* Initialize default parameters for a C2600 */
572 static void c2600_init_defaults(c2600_t *router)
573 {
574 vm_instance_t *vm = router->vm;
575 n_eth_addr_t *m;
576 m_uint16_t pid;
577
578 /* Set platform slots characteristics */
579 vm->nr_slots = C2600_MAX_NM_BAYS;
580 vm->slots_type = CISCO_CARD_TYPE_NM;
581 vm->slots_drivers = nm_drivers;
582
583 pid = (m_uint16_t)getpid();
584
585 /* Generate a chassis MAC address based on the instance ID */
586 m = &router->mac_addr;
587 m->eth_addr_byte[0] = vm_get_mac_addr_msb(vm);
588 m->eth_addr_byte[1] = vm->instance_id & 0xFF;
589 m->eth_addr_byte[2] = pid >> 8;
590 m->eth_addr_byte[3] = pid & 0xFF;
591 m->eth_addr_byte[4] = 0x00;
592 m->eth_addr_byte[5] = 0x00;
593
594 c2600_init_eeprom_groups(router);
595 c2600_mainboard_set_type(router,C2600_DEFAULT_MAINBOARD);
596 c2600_burn_mac_addr(router,&router->mac_addr);
597
598 vm->ram_mmap = C2600_DEFAULT_RAM_MMAP;
599 vm->ram_size = C2600_DEFAULT_RAM_SIZE;
600 vm->rom_size = C2600_DEFAULT_ROM_SIZE;
601 vm->nvram_size = C2600_DEFAULT_NVRAM_SIZE;
602 vm->conf_reg_setup = C2600_DEFAULT_CONF_REG;
603 vm->clock_divisor = C2600_DEFAULT_CLOCK_DIV;
604 vm->nvram_rom_space = C2600_NVRAM_ROM_RES_SIZE;
605 vm->nm_iomem_size = C2600_DEFAULT_IOMEM_SIZE;
606
607 vm->pcmcia_disk_size[0] = C2600_DEFAULT_DISK0_SIZE;
608 vm->pcmcia_disk_size[1] = C2600_DEFAULT_DISK1_SIZE;
609 }
610
611 /* Set an IRQ */
612 static void c2600_set_irq(vm_instance_t *vm,u_int irq)
613 {
614 c2600_t *router = VM_C2600(vm);
615 cpu_ppc_t *cpu = CPU_PPC32(vm->boot_cpu);
616 u_int slot,port;
617
618 switch(irq) {
619 case C2600_VTIMER_IRQ:
620 mpc860_set_pending_irq(router->mpc_data,30);
621 break;
622 case C2600_DUART_IRQ:
623 mpc860_set_pending_irq(router->mpc_data,29);
624 break;
625 case C2600_NETIO_IRQ:
626 mpc860_set_pending_irq(router->mpc_data,25);
627 break;
628 case C2600_PA_MGMT_IRQ:
629 mpc860_set_pending_irq(router->mpc_data,27);
630 break;
631
632 case C2600_NETIO_IRQ_BASE ... C2600_NETIO_IRQ_END:
633 c2600_net_irq_get_slot_port(irq,&slot,&port);
634 dev_c2600_iofpga_net_set_irq(router->iofpga_data,slot,port);
635 break;
636
637 /* IRQ test */
638 case 255:
639 mpc860_set_pending_irq(router->mpc_data,24);
640 break;
641 }
642
643 if (vm->irq_idle_preempt[irq])
644 cpu_idle_break_wait(cpu->gen);
645 }
646
647 /* Clear an IRQ */
648 static void c2600_clear_irq(vm_instance_t *vm,u_int irq)
649 {
650 c2600_t *router = VM_C2600(vm);
651 u_int slot,port;
652
653 switch(irq) {
654 case C2600_VTIMER_IRQ:
655 mpc860_clear_pending_irq(router->mpc_data,30);
656 break;
657 case C2600_DUART_IRQ:
658 mpc860_clear_pending_irq(router->mpc_data,29);
659 break;
660 case C2600_NETIO_IRQ:
661 mpc860_clear_pending_irq(router->mpc_data,25);
662 break;
663 case C2600_PA_MGMT_IRQ:
664 mpc860_clear_pending_irq(router->mpc_data,27);
665 break;
666
667 case C2600_NETIO_IRQ_BASE ... C2600_NETIO_IRQ_END:
668 c2600_net_irq_get_slot_port(irq,&slot,&port);
669 dev_c2600_iofpga_net_clear_irq(router->iofpga_data,slot,port);
670 break;
671
672 /* IRQ test */
673 case 255:
674 mpc860_clear_pending_irq(router->mpc_data,24);
675 break;
676 }
677 }
678
679 /* Initialize the C2600 Platform */
680 static int c2600_init_platform(c2600_t *router)
681 {
682 vm_instance_t *vm = router->vm;
683 vm_obj_t *obj;
684 cpu_ppc_t *cpu;
685 cpu_gen_t *gen;
686
687 /* Copy config register setup into "active" config register */
688 vm->conf_reg = vm->conf_reg_setup;
689
690 /* Create Console and AUX ports */
691 vm_init_vtty(vm);
692
693 /* Create a CPU group */
694 vm->cpu_group = cpu_group_create("System CPU");
695
696 /* Initialize the virtual PowerPC processor */
697 if (!(gen = cpu_create(vm,CPU_TYPE_PPC32,0))) {
698 vm_error(vm,"unable to create CPU!\n");
699 return(-1);
700 }
701
702 cpu = CPU_PPC32(gen);
703
704 /* Add this CPU to the system CPU group */
705 cpu_group_add(vm->cpu_group,gen);
706 vm->boot_cpu = gen;
707
708 /* Set processor ID */
709 ppc32_set_pvr(cpu,0x00500202);
710
711 /* Mark the Network IO interrupt as high priority */
712 vm->irq_idle_preempt[C2600_NETIO_IRQ] = TRUE;
713 vm->irq_idle_preempt[C2600_DUART_IRQ] = TRUE;
714
715 /* Copy some parameters from VM to CPU (idle PC, ...) */
716 cpu->idle_pc = vm->idle_pc;
717
718 if (vm->timer_irq_check_itv)
719 cpu->timer_irq_check_itv = vm->timer_irq_check_itv;
720
721 /* Remote emulator control */
722 dev_remote_control_init(vm,0xf6000000,0x1000);
723
724 /* MPC860 */
725 cpu->mpc860_immr = C2600_MPC860_ADDR;
726
727 if (dev_mpc860_init(vm,"MPC860",C2600_MPC860_ADDR,0x10000) == -1)
728 return(-1);
729
730 if (!(obj = vm_object_find(router->vm,"MPC860")))
731 return(-1);
732
733 router->mpc_data = obj->data;
734
735 /* IO FPGA */
736 if (dev_c2600_iofpga_init(router,C2600_IOFPGA_ADDR,0x10000) == -1)
737 return(-1);
738
739 if (!(obj = vm_object_find(router->vm,"io_fpga")))
740 return(-1);
741
742 router->iofpga_data = obj->data;
743
744 /* Initialize the chassis */
745 if (c2600_init(router) == -1)
746 return(-1);
747
748 /* Initialize RAM */
749 vm_ram_init(vm,0x00000000ULL);
750
751 /* Initialize ROM */
752 if (!vm->rom_filename) {
753 /* use embedded ROM */
754 dev_rom_init(vm,"rom",C2600_ROM_ADDR,512*1024,
755 ppc32_microcode,ppc32_microcode_len);
756 } else {
757 /* use alternate ROM */
758 dev_ram_init(vm,"rom",TRUE,TRUE,NULL,FALSE,C2600_ROM_ADDR,512*1024);
759 }
760
761 /* RAM aliasing */
762 dev_create_ram_alias(vm,"ram_alias","ram",0x80000000,vm->ram_size*1048576);
763
764 /* NVRAM */
765 dev_ram_init(vm,"nvram",TRUE,FALSE,NULL,FALSE,
766 C2600_NVRAM_ADDR,vm->nvram_size*4096);
767 c2600_nvram_check_empty_config(vm);
768
769 /* Bootflash */
770 dev_bootflash_init(vm,"flash0","c2600-bootflash-8mb",
771 C2600_FLASH_ADDR);
772 dev_bootflash_init(vm,"flash1","c2600-bootflash-8mb",
773 C2600_FLASH_ADDR+0x800000);
774
775 /* Initialize the NS16552 DUART */
776 dev_ns16552_init(vm,C2600_DUART_ADDR,0x1000,0,C2600_DUART_IRQ,
777 vm->vtty_con,vm->vtty_aux);
778
779 /* Initialize Network Modules */
780 if (vm_slot_init_all(vm) == -1)
781 return(-1);
782
783 /* Show device list */
784 c2600_show_hardware(router);
785 return(0);
786 }
787
788 static struct ppc32_bat_prog bat_array[] = {
789 { PPC32_IBAT_IDX, 0, 0xfff0001e, 0xfff00001 },
790 { PPC32_IBAT_IDX, 1, 0x00001ffe, 0x00000001 },
791 { PPC32_IBAT_IDX, 2, 0x00000000, 0xee3e0072 },
792 { PPC32_IBAT_IDX, 3, 0x80001ffe, 0x00000001 },
793
794 { PPC32_DBAT_IDX, 0, 0x80001ffe, 0x00000042 },
795 { PPC32_DBAT_IDX, 1, 0x00001ffe, 0x0000002a },
796 { PPC32_DBAT_IDX, 2, 0x40007ffe, 0x4000002a },
797 { PPC32_DBAT_IDX, 3, 0xf0001ffe, 0xf000002a },
798 { -1, -1, 0, 0 },
799 };
800
801 /* Boot the IOS image */
802 int c2600_boot_ios(c2600_t *router)
803 {
804 vm_instance_t *vm = router->vm;
805 cpu_ppc_t *cpu;
806
807 if (!vm->boot_cpu)
808 return(-1);
809
810 /* Suspend CPU activity since we will restart directly from ROM */
811 vm_suspend(vm);
812
813 /* Check that CPU activity is really suspended */
814 if (cpu_group_sync_state(vm->cpu_group) == -1) {
815 vm_error(vm,"unable to sync with system CPUs.\n");
816 return(-1);
817 }
818
819 /* Reset the boot CPU */
820 cpu = CPU_PPC32(vm->boot_cpu);
821 ppc32_reset(cpu);
822
823 /* Adjust stack pointer */
824 cpu->gpr[1] |= 0x80000000;
825
826 /* Load BAT registers */
827 printf("Loading BAT registers\n");
828 ppc32_load_bat_array(cpu,bat_array);
829 cpu->msr |= PPC32_MSR_IR|PPC32_MSR_DR;
830
831 /* IRQ routing */
832 vm->set_irq = c2600_set_irq;
833 vm->clear_irq = c2600_clear_irq;
834
835 /* Load IOS image */
836 if (ppc32_load_elf_image(cpu,vm->ios_image,
837 (vm->ghost_status == VM_GHOST_RAM_USE),
838 &vm->ios_entry_point) < 0)
839 {
840 vm_error(vm,"failed to load Cisco IOS image '%s'.\n",vm->ios_image);
841 return(-1);
842 }
843
844 /* Launch the simulation */
845 printf("\nC2600 '%s': starting simulation (CPU0 IA=0x%8.8x), "
846 "JIT %sabled.\n",
847 vm->name,cpu->ia,vm->jit_use ? "en":"dis");
848
849 vm_log(vm,"C2600_BOOT",
850 "starting instance (CPU0 PC=0x%8.8x,idle_pc=0x%8.8x,JIT %s)\n",
851 cpu->ia,cpu->idle_pc,vm->jit_use ? "on":"off");
852
853 /* Start main CPU */
854 if (vm->ghost_status != VM_GHOST_RAM_GENERATE) {
855 vm->status = VM_STATUS_RUNNING;
856 cpu_start(vm->boot_cpu);
857 } else {
858 vm->status = VM_STATUS_SHUTDOWN;
859 }
860 return(0);
861 }
862
863 /* Initialize a Cisco 2600 instance */
864 static int c2600_init_instance(vm_instance_t *vm)
865 {
866 c2600_t *router = VM_C2600(vm);
867 m_uint32_t rom_entry_point;
868 cpu_ppc_t *cpu0;
869
870 if (!vm->ios_image) {
871 vm_error(vm,"no Cisco IOS image defined.");
872 return(-1);
873 }
874
875 /* Initialize the C2600 platform */
876 if (c2600_init_platform(router) == -1) {
877 vm_error(vm,"unable to initialize the platform hardware.\n");
878 return(-1);
879 }
880
881 /* Load IOS configuration file */
882 if (vm->ios_config != NULL) {
883 vm_nvram_push_config(vm,vm->ios_config);
884 vm->conf_reg &= ~0x40;
885 }
886
887 /* Load ROM (ELF image or embedded) */
888 cpu0 = CPU_PPC32(vm->boot_cpu);
889 rom_entry_point = (m_uint32_t)PPC32_ROM_START;
890
891 if ((vm->rom_filename != NULL) &&
892 (ppc32_load_elf_image(cpu0,vm->rom_filename,0,&rom_entry_point) < 0))
893 {
894 vm_error(vm,"unable to load alternate ROM '%s', "
895 "fallback to embedded ROM.\n\n",vm->rom_filename);
896 vm->rom_filename = NULL;
897 }
898
899 return(c2600_boot_ios(router));
900 }
901
902 /* Stop a Cisco 2600 instance */
903 int c2600_stop_instance(vm_instance_t *vm)
904 {
905 printf("\nC2600 '%s': stopping simulation.\n",vm->name);
906 vm_log(vm,"C2600_STOP","stopping simulation.\n");
907
908 /* Stop all CPUs */
909 if (vm->cpu_group != NULL) {
910 vm_stop(vm);
911
912 if (cpu_group_sync_state(vm->cpu_group) == -1) {
913 vm_error(vm,"unable to sync with system CPUs.\n");
914 return(-1);
915 }
916 }
917
918 /* Free resources that were used during execution to emulate hardware */
919 vm_slot_shutdown_all(vm);
920 vm_hardware_shutdown(vm);
921 return(0);
922 }
923
924 /* Get MAC address MSB */
925 static u_int c2600_get_mac_addr_msb(void)
926 {
927 return(0xC8);
928 }
929
930 /* Parse specific options for the Cisco 2600 platform */
931 static int c2600_cli_parse_options(vm_instance_t *vm,int option)
932 {
933 c2600_t *router = VM_C2600(vm);
934
935 switch(option) {
936 /* IO memory reserved for NMs (in percents!) */
937 case OPT_IOMEM_SIZE:
938 vm->nm_iomem_size = 0x8000 | atoi(optarg);
939 break;
940
941 /* Mainboard type */
942 case 't':
943 c2600_mainboard_set_type(router,optarg);
944 break;
945
946 /* Unknown option */
947 default:
948 return(-1);
949 }
950
951 return(0);
952 }
953
954 /* Show specific CLI options */
955 static void c2600_cli_show_options(vm_instance_t *vm)
956 {
957 printf(" --iomem-size <val> : IO memory (in percents, default: %u)\n"
958 " -p <nm_desc> : Define a Network Module\n"
959 " -s <nm_nio> : Bind a Network IO interface to a "
960 "Network Module\n",
961 vm->nm_iomem_size);
962 }
963
964 /* Platform definition */
965 static vm_platform_t c2600_platform = {
966 "c2600", "C2600", "2600",
967 c2600_create_instance,
968 c2600_delete_instance,
969 c2600_init_instance,
970 c2600_stop_instance,
971 c2600_nvram_extract_config,
972 c2600_nvram_push_config,
973 c2600_get_mac_addr_msb,
974 c2600_save_config,
975 c2600_cli_parse_options,
976 c2600_cli_show_options,
977 c2600_mainboard_show_drivers,
978 };
979
980 /* Register the c2600 platform */
981 int c2600_platform_register(void)
982 {
983 if (vm_platform_register(&c2600_platform) == -1)
984 return(-1);
985
986 return(hypervisor_c2600_init(&c2600_platform));
987 }

  ViewVC Help
Powered by ViewVC 1.1.26