/[dynamips]/trunk/dev_c3600.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/dev_c3600.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 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: 27192 byte(s)
make working copy

1 /*
2 * Cisco 3600 simulation platform.
3 * Copyright (c) 2006 Christophe Fillot (cf@utc.fr)
4 *
5 * Generic Cisco 3600 routines and definitions (EEPROM,...).
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <sys/types.h>
13 #include <assert.h>
14
15 #include "cpu.h"
16 #include "dynamips.h"
17 #include "memory.h"
18 #include "device.h"
19 #include "pci_io.h"
20 #include "dev_gt.h"
21 #include "cisco_eeprom.h"
22 #include "dev_rom.h"
23 #include "dev_c3600.h"
24 #include "dev_c3600_iofpga.h"
25 #include "dev_c3600_bay.h"
26 #include "dev_vtty.h"
27 #include "registry.h"
28
29 /* ======================================================================== */
30 /* EEPROM definitions */
31 /* ======================================================================== */
32
33 /* Cisco 3620 mainboard EEPROM */
34 static m_uint16_t eeprom_c3620_mainboard_data[64] = {
35 0x0001, 0x0000, 0x0000, 0x0000, 0x0AFF, 0x7318, 0x5011, 0x0020,
36 0x0000, 0x0000, 0xA0FF, 0x9904, 0x19FF, 0xFFFF, 0xFFFF, 0x0002,
37 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
38 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
39 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
40 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
41 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
42 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
43 };
44
45 struct cisco_eeprom eeprom_c3620_mainboard = {
46 "C3620 Mainboard",
47 eeprom_c3620_mainboard_data,
48 sizeof(eeprom_c3620_mainboard_data)/2,
49 };
50
51 /* Cisco 3640 mainboard EEPROM */
52 static m_uint16_t eeprom_c3640_mainboard_data[64] = {
53 0x0001, 0x0000, 0x0000, 0x0000, 0x0AFF, 0x7316, 0x8514, 0x0040,
54 0x0000, 0x0000, 0xA1FF, 0x0102, 0x22FF, 0xFFFF, 0xFFFF, 0x0002,
55 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
56 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
57 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
58 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
59 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
60 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
61 };
62
63 struct cisco_eeprom eeprom_c3640_mainboard = {
64 "C3640 Mainboard",
65 eeprom_c3640_mainboard_data,
66 sizeof(eeprom_c3640_mainboard_data)/2,
67 };
68
69 /* Cisco 3660 backplane EEPROM */
70 static m_uint16_t eeprom_c3660_backplane_data[64] = {
71 0x04FF, 0x4000, 0xC841, 0x0100, 0xC046, 0x0320, 0x0012, 0x8402,
72 0x4243, 0x3080, 0x0000, 0x0000, 0x0202, 0xC18B, 0x4841, 0x4430,
73 0x3434, 0x3431, 0x3135, 0x4A03, 0x0081, 0x0000, 0x0000, 0x0400,
74 0xC28B, 0x4A41, 0x4230, 0x3434, 0x3643, 0x304C, 0x32C3, 0x0600,
75 0x044D, 0x0EC2, 0xD043, 0x0070, 0xC408, 0x0000, 0x0000, 0x0000,
76 0x0000, 0x851C, 0x0A5B, 0x0201, 0x06FF, 0xFFFF, 0xFFFF, 0xFFFF,
77 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
78 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
79 };
80
81 struct cisco_eeprom eeprom_c3660_backplane = {
82 "C3660 Backplane",
83 eeprom_c3660_backplane_data,
84 sizeof(eeprom_c3660_backplane_data)/2,
85 };
86
87 /* ======================================================================== */
88 /* Chassis Drivers */
89 /* ======================================================================== */
90 static int c3620_init(c3600_t *router);
91 static int c3640_init(c3600_t *router);
92 static int c3660_init(c3600_t *router);
93
94 static struct c3600_chassis_driver chassis_drivers[] = {
95 { "3620" , 3620, 1, c3620_init, &eeprom_c3620_mainboard },
96 { "3640" , 3640, 1, c3640_init, &eeprom_c3640_mainboard },
97 { "3660" , 3660, 1, c3660_init, &eeprom_c3660_backplane },
98 { NULL , -1, 0, NULL, NULL },
99 };
100
101 /* ======================================================================== */
102 /* Network Module Drivers */
103 /* ======================================================================== */
104 static struct cisco_card_driver *nm_drivers[] = {
105 &dev_c3600_nm_1e_driver,
106 &dev_c3600_nm_4e_driver,
107 &dev_c3600_nm_1fe_tx_driver,
108 &dev_c3600_nm_4t_driver,
109 &dev_c3600_leopard_2fe_driver,
110 &dev_c3600_nm_16esw_driver,
111 NULL,
112 };
113
114 /* ======================================================================== */
115 /* Cisco 3600 router instances */
116 /* ======================================================================== */
117
118 /* Initialize default parameters for a C3600 */
119 static void c3600_init_defaults(c3600_t *router);
120
121 /* Directly extract the configuration from the NVRAM device */
122 static ssize_t c3600_nvram_extract_config(vm_instance_t *vm,u_char **buffer)
123 {
124 u_char *base_ptr,*ios_ptr,*cfg_ptr,*end_ptr;
125 m_uint32_t start,nvlen;
126 m_uint16_t magic1,magic2;
127 struct vdevice *nvram_dev;
128 off_t nvram_size;
129 int fd;
130
131 if ((nvram_dev = dev_get_by_name(vm,"nvram")))
132 dev_sync(nvram_dev);
133
134 fd = vm_mmap_open_file(vm,"nvram",&base_ptr,&nvram_size);
135
136 if (fd == -1)
137 return(-1);
138
139 ios_ptr = base_ptr + vm->nvram_rom_space;
140 end_ptr = base_ptr + nvram_size;
141
142 if ((ios_ptr + 0x30) >= end_ptr) {
143 vm_error(vm,"NVRAM file too small\n");
144 return(-1);
145 }
146
147 magic1 = ntohs(*PTR_ADJUST(m_uint16_t *,ios_ptr,0x06));
148 magic2 = ntohs(*PTR_ADJUST(m_uint16_t *,ios_ptr,0x08));
149
150 if ((magic1 != 0xF0A5) || (magic2 != 0xABCD)) {
151 vm_error(vm,"unable to find IOS magic numbers (0x%x,0x%x)!\n",
152 magic1,magic2);
153 return(-1);
154 }
155
156 start = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x10)) + 1;
157 nvlen = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x18));
158
159 if (!(*buffer = malloc(nvlen+1))) {
160 vm_error(vm,"unable to allocate config buffer (%u bytes)\n",nvlen);
161 return(-1);
162 }
163
164 cfg_ptr = ios_ptr + start + 0x08;
165
166 if ((cfg_ptr + nvlen) > end_ptr) {
167 vm_error(vm,"NVRAM file too small\n");
168 return(-1);
169 }
170
171 memcpy(*buffer,cfg_ptr,nvlen-1);
172 (*buffer)[nvlen-1] = 0;
173 return(nvlen-1);
174 }
175
176 /* Directly push the IOS configuration to the NVRAM device */
177 static int c3600_nvram_push_config(vm_instance_t *vm,u_char *buffer,size_t len)
178 {
179 u_char *base_ptr,*ios_ptr,*cfg_ptr;
180 m_uint32_t cfg_offset,cklen,tmp;
181 m_uint16_t cksum;
182 int fd;
183
184 fd = vm_mmap_create_file(vm,"nvram",vm->nvram_size*1024,&base_ptr);
185
186 if (fd == -1)
187 return(-1);
188
189 cfg_offset = 0x2c;
190 ios_ptr = base_ptr + vm->nvram_rom_space;
191 cfg_ptr = ios_ptr + cfg_offset;
192
193 /* Write IOS tag, uncompressed config... */
194 *PTR_ADJUST(m_uint16_t *,ios_ptr,0x06) = htons(0xF0A5);
195 *PTR_ADJUST(m_uint16_t *,ios_ptr,0x08) = htons(0xABCD);
196 *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0a) = htons(0x0001);
197 *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0c) = htons(0x0000);
198 *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0e) = htons(0x0c04);
199
200 /* Store file contents to NVRAM */
201 memcpy(cfg_ptr,buffer,len);
202
203 /* Write config addresses + size */
204 tmp = cfg_offset - 0x08;
205
206 *PTR_ADJUST(m_uint32_t *,ios_ptr,0x10) = htonl(tmp);
207 *PTR_ADJUST(m_uint32_t *,ios_ptr,0x14) = htonl(tmp + len);
208 *PTR_ADJUST(m_uint32_t *,ios_ptr,0x18) = htonl(len);
209
210 /* Compute the checksum */
211 cklen = (vm->nvram_size*1024) - (vm->nvram_rom_space + 0x08);
212 cksum = nvram_cksum((m_uint16_t *)(ios_ptr+0x08),cklen);
213 *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0c) = htons(cksum);
214
215 vm_mmap_close_file(fd,base_ptr,vm->nvram_size*1024);
216 return(0);
217 }
218
219 /* Create a new router instance */
220 static int c3600_create_instance(vm_instance_t *vm)
221 {
222 c3600_t *router;
223
224 if (!(router = malloc(sizeof(*router)))) {
225 fprintf(stderr,"C3600 '%s': Unable to create new instance!\n",vm->name);
226 return(-1);
227 }
228
229 memset(router,0,sizeof(*router));
230 router->vm = vm;
231 vm->hw_data = router;
232
233 c3600_init_defaults(router);
234 return(0);
235 }
236
237 /* Free resources used by a router instance */
238 static int c3600_delete_instance(vm_instance_t *vm)
239 {
240 c3600_t *router = VM_C3600(vm);
241 int i;
242
243 /* Stop all CPUs */
244 if (vm->cpu_group != NULL) {
245 vm_stop(vm);
246
247 if (cpu_group_sync_state(vm->cpu_group) == -1) {
248 vm_error(vm,"unable to sync with system CPUs.\n");
249 return(FALSE);
250 }
251 }
252
253 /* Remove NIO bindings */
254 for(i=0;i<vm->nr_slots;i++)
255 vm_slot_remove_all_nio_bindings(vm,i);
256
257 /* Shutdown all Network Modules */
258 vm_slot_shutdown_all(vm);
259
260 /* Free mainboard EEPROM */
261 cisco_eeprom_free(&router->mb_eeprom);
262
263 /* Free all resources used by VM */
264 vm_free(vm);
265
266 /* Free the router structure */
267 free(router);
268 return(TRUE);
269 }
270
271 /* Save configuration of a C3600 instance */
272 static void c3600_save_config(vm_instance_t *vm,FILE *fd)
273 {
274 c3600_t *router = VM_C3600(vm);
275
276 fprintf(fd,"c3600 set_chassis %s %s\n\n",
277 vm->name,router->chassis_driver->chassis_type);
278 }
279
280 /* Set EEPROM for the specified slot */
281 int c3600_set_slot_eeprom(c3600_t *router,u_int slot,
282 struct cisco_eeprom *eeprom)
283 {
284 if (slot >= C3600_MAX_NM_BAYS)
285 return(-1);
286
287 router->c3660_nm_eeprom_group[slot].eeprom[0] = eeprom;
288 return(0);
289 }
290
291 /* Get slot/port corresponding to specified network IRQ */
292 static inline void
293 c3600_net_irq_get_slot_port(u_int irq,u_int *slot,u_int *port)
294 {
295 irq -= C3600_NETIO_IRQ_BASE;
296 *port = irq & C3600_NETIO_IRQ_PORT_MASK;
297 *slot = irq >> C3600_NETIO_IRQ_PORT_BITS;
298 }
299
300 /* Get network IRQ for specified slot/port */
301 u_int c3600_net_irq_for_slot_port(u_int slot,u_int port)
302 {
303 u_int irq;
304
305 irq = (slot << C3600_NETIO_IRQ_PORT_BITS) + port;
306 irq += C3600_NETIO_IRQ_BASE;
307
308 return(irq);
309 }
310
311 /* Get a chassis driver */
312 struct c3600_chassis_driver *c3600_chassis_get_driver(char *chassis_type)
313 {
314 int i;
315
316 for(i=0;chassis_drivers[i].chassis_type;i++)
317 if (!strcmp(chassis_drivers[i].chassis_type,chassis_type))
318 return(&chassis_drivers[i]);
319
320 return NULL;
321 }
322
323 /* Set the base MAC address of the chassis */
324 static int c3600_burn_mac_addr(c3600_t *router,n_eth_addr_t *addr)
325 {
326 m_uint8_t eeprom_ver;
327 size_t offset;
328
329 /* Read EEPROM format version */
330 cisco_eeprom_get_byte(&router->mb_eeprom,0,&eeprom_ver);
331
332 switch(eeprom_ver) {
333 case 0:
334 cisco_eeprom_set_region(&router->mb_eeprom,2,addr->eth_addr_byte,6);
335 break;
336
337 case 4:
338 if (!cisco_eeprom_v4_find_field(&router->mb_eeprom,0xC3,&offset)) {
339 cisco_eeprom_set_region(&router->mb_eeprom,offset,
340 addr->eth_addr_byte,6);
341 }
342 break;
343
344 default:
345 vm_error(router->vm,"c3600_burn_mac_addr: unable to handle "
346 "EEPROM version %u\n",eeprom_ver);
347 return(-1);
348 }
349
350 return(0);
351 }
352
353 /* Set chassis MAC address */
354 int c3600_chassis_set_mac_addr(c3600_t *router,char *mac_addr)
355 {
356 if (parse_mac_addr(&router->mac_addr,mac_addr) == -1) {
357 vm_error(router->vm,"unable to parse MAC address '%s'.\n",mac_addr);
358 return(-1);
359 }
360
361 /* Set the chassis base MAC address */
362 c3600_burn_mac_addr(router,&router->mac_addr);
363 return(0);
364 }
365
366 /* Set the chassis type */
367 int c3600_chassis_set_type(c3600_t *router,char *chassis_type)
368 {
369 struct c3600_chassis_driver *driver;
370
371 if (router->vm->status == VM_STATUS_RUNNING) {
372 vm_error(router->vm,"unable to change chassis type when online.\n");
373 return(-1);
374 }
375
376 if (!(driver = c3600_chassis_get_driver(chassis_type))) {
377 vm_error(router->vm,"unknown chassis type '%s'.\n",chassis_type);
378 return(-1);
379 }
380
381 router->chassis_driver = driver;
382
383 /* Copy the mainboard EEPROM */
384 if (cisco_eeprom_copy(&router->mb_eeprom,driver->eeprom) == -1) {
385 vm_error(router->vm,"unable to set chassis EEPROM '%s'.\n",chassis_type);
386 return(-1);
387 }
388
389 /* Set the chassis base MAC address */
390 c3600_burn_mac_addr(router,&router->mac_addr);
391
392 /* The motherboard has 2 integrated FastEthernet ports on a 3660 */
393 if (driver->chassis_id == 3660) {
394 vm_slot_remove_binding(router->vm,0,0);
395 vm_slot_add_binding(router->vm,"Leopard-2FE",0,0);
396 }
397
398 return(0);
399 }
400
401 /* Get the chassis ID */
402 int c3600_chassis_get_id(c3600_t *router)
403 {
404 if (router->chassis_driver)
405 return(router->chassis_driver->chassis_id);
406
407 return(-1);
408 }
409
410 /* Show the list of available chassis drivers */
411 static void c3600_chassis_show_drivers(void)
412 {
413 int i;
414
415 printf("Available C3600 chassis drivers:\n");
416
417 for(i=0;chassis_drivers[i].chassis_type;i++) {
418 printf(" * %s %s\n",
419 chassis_drivers[i].chassis_type,
420 !chassis_drivers[i].supported ? "(NOT WORKING)" : "");
421 }
422
423 printf("\n");
424 }
425
426 /* Create the main PCI bus for a GT64010 based system */
427 static int c3600_init_gt64010(c3600_t *router)
428 {
429 if (!(router->vm->pci_bus[0] = pci_bus_create("PCI bus",0))) {
430 vm_error(router->vm,"unable to create PCI data.\n");
431 return(-1);
432 }
433
434 return(dev_gt64010_init(router->vm,"gt64010",C3600_GT64K_ADDR,0x1000,
435 C3600_GT64K_IRQ));
436 }
437
438 /* Create the two main PCI busses for a GT64120 based system */
439 static int c3600_init_gt64120(c3600_t *router)
440 {
441 vm_instance_t *vm = router->vm;
442
443 vm->pci_bus[0] = pci_bus_create("PCI bus #0",0);
444 vm->pci_bus[1] = pci_bus_create("PCI bus #1",0);
445
446 if (!vm->pci_bus[0] || !vm->pci_bus[1]) {
447 vm_error(router->vm,"unable to create PCI data.\n");
448 return(-1);
449 }
450
451 return(dev_gt64120_init(vm,"gt64120",C3600_GT64K_ADDR,0x1000,
452 C3600_GT64K_IRQ));
453 }
454
455 /* Initialize a Cisco 3620 */
456 static int c3620_init(c3600_t *router)
457 {
458 vm_instance_t *vm = router->vm;
459 int i;
460
461 /* Set the processor type: R4700 */
462 mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R4700);
463
464 /* Initialize the Galileo GT-64010 PCI controller */
465 if (c3600_init_gt64010(router) == -1)
466 return(-1);
467
468 /* Initialize PCI map (no PCI bridge for this chassis) */
469 for(i=0;i<C3600_MAX_NM_BAYS;i++)
470 vm->slots_pci_bus[i] = vm->pci_bus[0];
471
472 vm->elf_machine_id = C3620_ELF_MACHINE_ID;
473 return(0);
474 }
475
476 /* Initialize a Cisco 3640 */
477 static int c3640_init(c3600_t *router)
478 {
479 vm_instance_t *vm = router->vm;
480 struct nm_bay_info *bay;
481 int i;
482
483 /* Set the processor type: R4700 */
484 mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R4700);
485
486 /* Initialize the Galileo GT-64010 PCI controller */
487 if (c3600_init_gt64010(router) == -1)
488 return(-1);
489
490 /* Create the NM PCI busses */
491 vm->pci_bus_pool[0] = pci_bus_create("NM Slots 0,2",-1);
492 vm->pci_bus_pool[1] = pci_bus_create("NM Slots 1,3",-1);
493
494 /* Initialize PCI map and PCI bridges */
495 for(i=0;i<=3;i++) {
496 bay = c3600_nm_get_bay_info(3640,i);
497
498 /* Map the NM PCI bus */
499 vm->slots_pci_bus[i] = vm->pci_bus_pool[i & 1];
500
501 if (bay && (bay->pci_bridge_device != -1))
502 dev_dec21052_init(vm->pci_bus[0],bay->pci_bridge_device,
503 vm->slots_pci_bus[i]);
504 }
505
506 vm->elf_machine_id = C3640_ELF_MACHINE_ID;
507 return(0);
508 }
509
510 /* Initialize a Cisco 3660 */
511 static int c3660_init(c3600_t *router)
512 {
513 vm_instance_t *vm = router->vm;
514 struct nm_bay_info *bay;
515 char bus_name[128];
516 int i;
517
518 /* Set the processor type: R5271 */
519 mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R527x);
520
521 /* Initialize the Galileo GT-64120 PCI controller */
522 if (c3600_init_gt64120(router) == -1)
523 return(-1);
524
525 /* Create the NM PCI busses */
526 for(i=1;i<=6;i++) {
527 snprintf(bus_name,sizeof(bus_name),"NM Slot %d",i);
528 vm->pci_bus_pool[i] = pci_bus_create(bus_name,-1);
529 }
530
531 /* Slot 0 is mapped to the first bus of GT64120 */
532 vm->slots_pci_bus[0] = vm->pci_bus[0];
533
534 /* Initialize PCI map and PCI bridges */
535 for(i=1;i<C3600_MAX_NM_BAYS;i++) {
536 bay = c3600_nm_get_bay_info(3660,i);
537
538 /* Map the NM PCI bus */
539 vm->slots_pci_bus[i] = vm->pci_bus_pool[i];
540
541 /* Slots 1-6 are mapped to the second bus of GT64120 */
542 if (bay && (bay->pci_bridge_device != -1))
543 dev_dec21152_init(vm->pci_bus[1],bay->pci_bridge_device,
544 vm->slots_pci_bus[i]);
545 }
546
547 vm->elf_machine_id = C3660_ELF_MACHINE_ID;
548 return(0);
549 }
550
551 /* Show C3600 hardware info */
552 void c3600_show_hardware(c3600_t *router)
553 {
554 vm_instance_t *vm = router->vm;
555
556 printf("C3600 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(" Chassis : %s\n",router->chassis_driver->chassis_type);
562 printf(" IOS image : %s\n\n",vm->ios_image);
563
564 if (vm->debug_level > 0) {
565 dev_show_list(vm);
566 pci_dev_show_list(vm->pci_bus[0]);
567 pci_dev_show_list(vm->pci_bus[1]);
568 printf("\n");
569 }
570 }
571
572 /* Initialize default parameters for a C3600 */
573 static void c3600_init_defaults(c3600_t *router)
574 {
575 vm_instance_t *vm = router->vm;
576 n_eth_addr_t *m;
577 m_uint16_t pid;
578
579 /* Set platform slots characteristics */
580 vm->nr_slots = C3600_MAX_NM_BAYS;
581 vm->slots_type = CISCO_CARD_TYPE_NM;
582 vm->slots_drivers = nm_drivers;
583
584 pid = (m_uint16_t)getpid();
585
586 /* Generate a chassis MAC address based on the instance ID */
587 m = &router->mac_addr;
588 m->eth_addr_byte[0] = vm_get_mac_addr_msb(vm);
589 m->eth_addr_byte[1] = vm->instance_id & 0xFF;
590 m->eth_addr_byte[2] = pid >> 8;
591 m->eth_addr_byte[3] = pid & 0xFF;
592 m->eth_addr_byte[4] = 0x00;
593 m->eth_addr_byte[5] = 0x00;
594
595 c3600_init_eeprom_groups(router);
596 c3600_chassis_set_type(router,C3600_DEFAULT_CHASSIS);
597
598 vm->ram_mmap = C3600_DEFAULT_RAM_MMAP;
599 vm->ram_size = C3600_DEFAULT_RAM_SIZE;
600 vm->rom_size = C3600_DEFAULT_ROM_SIZE;
601 vm->nvram_size = C3600_DEFAULT_NVRAM_SIZE;
602 vm->conf_reg_setup = C3600_DEFAULT_CONF_REG;
603 vm->clock_divisor = C3600_DEFAULT_CLOCK_DIV;
604 vm->nvram_rom_space = C3600_NVRAM_ROM_RES_SIZE;
605 vm->nm_iomem_size = C3600_DEFAULT_IOMEM_SIZE;
606
607 vm->pcmcia_disk_size[0] = C3600_DEFAULT_DISK0_SIZE;
608 vm->pcmcia_disk_size[1] = C3600_DEFAULT_DISK1_SIZE;
609 }
610
611 /* Initialize the C3600 Platform */
612 static int c3600_init_platform(c3600_t *router)
613 {
614 vm_instance_t *vm = router->vm;
615 cpu_mips_t *cpu;
616 cpu_gen_t *gen;
617 vm_obj_t *obj;
618
619 /* Copy config register setup into "active" config register */
620 vm->conf_reg = vm->conf_reg_setup;
621
622 /* Create Console and AUX ports */
623 vm_init_vtty(vm);
624
625 /* Create a CPU group */
626 vm->cpu_group = cpu_group_create("System CPU");
627
628 /* Initialize the virtual MIPS processor */
629 if (!(gen = cpu_create(vm,CPU_TYPE_MIPS64,0))) {
630 vm_error(vm,"unable to create CPU!\n");
631 return(-1);
632 }
633
634 cpu = CPU_MIPS64(gen);
635
636 /* Add this CPU to the system CPU group */
637 cpu_group_add(vm->cpu_group,gen);
638 vm->boot_cpu = gen;
639
640 /* Initialize the IRQ routing vectors */
641 vm->set_irq = mips64_vm_set_irq;
642 vm->clear_irq = mips64_vm_clear_irq;
643
644 /* Mark the Network IO interrupt as high priority */
645 cpu->irq_idle_preempt[C3600_NETIO_IRQ] = TRUE;
646 cpu->irq_idle_preempt[C3600_GT64K_IRQ] = TRUE;
647 cpu->irq_idle_preempt[C3600_DUART_IRQ] = TRUE;
648
649 /* Copy some parameters from VM to CPU (idle PC, ...) */
650 cpu->idle_pc = vm->idle_pc;
651
652 if (vm->timer_irq_check_itv)
653 cpu->timer_irq_check_itv = vm->timer_irq_check_itv;
654
655 /* Get chassis specific driver */
656 if (!router->chassis_driver) {
657 vm_error(vm,"no chassis defined.\n");
658 return(-1);
659 }
660
661 /* Remote emulator control */
662 dev_remote_control_init(vm,0x16000000,0x1000);
663
664 /* Bootflash (8 Mb) */
665 dev_bootflash_init(vm,"bootflash","c3600-bootflash-8mb",
666 C3600_BOOTFLASH_ADDR);
667
668 /* NVRAM and calendar */
669 dev_nvram_init(vm,"nvram",
670 C3600_NVRAM_ADDR,vm->nvram_size*1024,&vm->conf_reg);
671
672 /* Bit-bucket zone */
673 dev_zero_init(vm,"zero",C3600_BITBUCKET_ADDR,0xc00000);
674
675 /* IO FPGA */
676 if (dev_c3600_iofpga_init(router,C3600_IOFPGA_ADDR,0x40000) == -1)
677 return(-1);
678
679 if (!(obj = vm_object_find(router->vm,"io_fpga")))
680 return(-1);
681
682 router->iofpga_data = obj->data;
683
684 /* PCI IO space */
685 if (!(vm->pci_io_space = pci_io_data_init(vm,C3600_PCI_IO_ADDR)))
686 return(-1);
687
688 /* Initialize the chassis */
689 if (router->chassis_driver->chassis_init(router) == -1)
690 return(-1);
691
692 /* Initialize RAM */
693 vm_ram_init(vm,0x00000000ULL);
694
695 /* Initialize ROM */
696 if (!vm->rom_filename) {
697 /* use embedded ROM */
698 dev_rom_init(vm,"rom",C3600_ROM_ADDR,vm->rom_size*1048576,
699 mips64_microcode,mips64_microcode_len);
700 } else {
701 /* use alternate ROM */
702 dev_ram_init(vm,"rom",TRUE,TRUE,NULL,FALSE,
703 C3600_ROM_ADDR,vm->rom_size*1048576);
704 }
705
706 /* Initialize the NS16552 DUART */
707 dev_ns16552_init(vm,C3600_DUART_ADDR,0x1000,3,C3600_DUART_IRQ,
708 vm->vtty_con,vm->vtty_aux);
709
710 /* Cirrus Logic PD6729 (PCI-to-PCMCIA host adapter) */
711 dev_clpd6729_init(vm,vm->pci_bus[0],20,vm->pci_io_space,0x4402,0x4403);
712
713 /* Initialize Network Modules */
714 if (vm_slot_init_all(vm) == -1)
715 return(-1);
716
717 /* Show device list */
718 c3600_show_hardware(router);
719 return(0);
720 }
721
722 /* Boot the IOS image */
723 static int c3600_boot_ios(c3600_t *router)
724 {
725 vm_instance_t *vm = router->vm;
726 cpu_mips_t *cpu;
727
728 if (!vm->boot_cpu)
729 return(-1);
730
731 /* Suspend CPU activity since we will restart directly from ROM */
732 vm_suspend(vm);
733
734 /* Check that CPU activity is really suspended */
735 if (cpu_group_sync_state(vm->cpu_group) == -1) {
736 vm_error(vm,"unable to sync with system CPUs.\n");
737 return(-1);
738 }
739
740 /* Reset the boot CPU */
741 cpu = CPU_MIPS64(vm->boot_cpu);
742 mips64_reset(cpu);
743
744 /* Load IOS image */
745 if (mips64_load_elf_image(cpu,vm->ios_image,
746 (vm->ghost_status == VM_GHOST_RAM_USE),
747 &vm->ios_entry_point) < 0)
748 {
749 vm_error(vm,"failed to load Cisco IOS image '%s'.\n",vm->ios_image);
750 return(-1);
751 }
752
753 /* Launch the simulation */
754 printf("\nC3600 '%s': starting simulation (CPU0 PC=0x%llx), "
755 "JIT %sabled.\n",
756 vm->name,cpu->pc,vm->jit_use ? "en":"dis");
757
758 vm_log(vm,"C3600_BOOT",
759 "starting instance (CPU0 PC=0x%llx,idle_pc=0x%llx,JIT %s)\n",
760 cpu->pc,cpu->idle_pc,vm->jit_use ? "on":"off");
761
762 /* Start main CPU */
763 if (vm->ghost_status != VM_GHOST_RAM_GENERATE) {
764 vm->status = VM_STATUS_RUNNING;
765 cpu_start(vm->boot_cpu);
766 } else {
767 vm->status = VM_STATUS_SHUTDOWN;
768 }
769 return(0);
770 }
771
772 /* Set an IRQ */
773 static void c3600_set_irq(vm_instance_t *vm,u_int irq)
774 {
775 c3600_t *router = VM_C3600(vm);
776 cpu_mips_t *cpu0 = CPU_MIPS64(vm->boot_cpu);
777 u_int slot,port;
778
779 switch(irq) {
780 case 0 ... 7:
781 mips64_set_irq(cpu0,irq);
782
783 if (cpu0->irq_idle_preempt[irq])
784 cpu_idle_break_wait(cpu0->gen);
785 break;
786
787 case C3600_NETIO_IRQ_BASE ... C3600_NETIO_IRQ_END:
788 c3600_net_irq_get_slot_port(irq,&slot,&port);
789 dev_c3600_iofpga_net_set_irq(router->iofpga_data,slot,port);
790 break;
791 }
792 }
793
794 /* Clear an IRQ */
795 static void c3600_clear_irq(vm_instance_t *vm,u_int irq)
796 {
797 c3600_t *router = VM_C3600(vm);
798 cpu_mips_t *cpu0 = CPU_MIPS64(vm->boot_cpu);
799 u_int slot,port;
800
801 switch(irq) {
802 case 0 ... 7:
803 mips64_clear_irq(cpu0,irq);
804 break;
805
806 case C3600_NETIO_IRQ_BASE ... C3600_NETIO_IRQ_END:
807 c3600_net_irq_get_slot_port(irq,&slot,&port);
808 dev_c3600_iofpga_net_clear_irq(router->iofpga_data,slot,port);
809 break;
810 }
811 }
812
813 /* Initialize a Cisco 3600 instance */
814 static int c3600_init_instance(vm_instance_t *vm)
815 {
816 c3600_t *router = VM_C3600(vm);
817 m_uint32_t rom_entry_point;
818 cpu_mips_t *cpu0;
819
820 if (!vm->ios_image) {
821 vm_error(vm,"no Cisco IOS image defined.");
822 return(-1);
823 }
824
825 /* Initialize the C3600 platform */
826 if (c3600_init_platform(router) == -1) {
827 vm_error(vm,"unable to initialize the platform hardware.\n");
828 return(-1);
829 }
830
831 /* IRQ routing */
832 vm->set_irq = c3600_set_irq;
833 vm->clear_irq = c3600_clear_irq;
834
835 /* Load IOS configuration file */
836 if (vm->ios_config != NULL) {
837 vm_nvram_push_config(vm,vm->ios_config);
838 vm->conf_reg &= ~0x40;
839 }
840
841 /* Load ROM (ELF image or embedded) */
842 cpu0 = CPU_MIPS64(vm->boot_cpu);
843 rom_entry_point = (m_uint32_t)MIPS_ROM_PC;
844
845 if ((vm->rom_filename != NULL) &&
846 (mips64_load_elf_image(cpu0,vm->rom_filename,0,&rom_entry_point) < 0))
847 {
848 vm_error(vm,"unable to load alternate ROM '%s', "
849 "fallback to embedded ROM.\n\n",vm->rom_filename);
850 vm->rom_filename = NULL;
851 }
852
853 /* Load symbol file */
854 if (vm->sym_filename) {
855 mips64_sym_load_file(cpu0,vm->sym_filename);
856 cpu0->sym_trace = 1;
857 }
858
859 return(c3600_boot_ios(router));
860 }
861
862 /* Stop a Cisco 3600 instance */
863 static int c3600_stop_instance(vm_instance_t *vm)
864 {
865 printf("\nC3600 '%s': stopping simulation.\n",vm->name);
866 vm_log(vm,"C3600_STOP","stopping simulation.\n");
867
868 /* Stop all CPUs */
869 if (vm->cpu_group != NULL) {
870 vm_stop(vm);
871
872 if (cpu_group_sync_state(vm->cpu_group) == -1) {
873 vm_error(vm,"unable to sync with system CPUs.\n");
874 return(-1);
875 }
876 }
877
878 /* Free resources that were used during execution to emulate hardware */
879 vm_slot_shutdown_all(vm);
880 vm_hardware_shutdown(vm);
881 return(0);
882 }
883
884 /* Get MAC address MSB */
885 static u_int c3600_get_mac_addr_msb(void)
886 {
887 return(0xCC);
888 }
889
890 /* Parse specific options for the Cisco 3600 platform */
891 static int c3600_cli_parse_options(vm_instance_t *vm,int option)
892 {
893 c3600_t *router = VM_C3600(vm);
894
895 switch(option) {
896 /* IO memory reserved for NMs (in percents!) */
897 case OPT_IOMEM_SIZE:
898 vm->nm_iomem_size = 0x8000 | atoi(optarg);
899 break;
900
901 /* Chassis type */
902 case 't':
903 c3600_chassis_set_type(router,optarg);
904 break;
905
906 /* Unknown option */
907 default:
908 return(-1);
909 }
910
911 return(0);
912 }
913
914 /* Show specific CLI options */
915 static void c3600_cli_show_options(vm_instance_t *vm)
916 {
917 printf(" -t <chassis_type> : Select Chassis type (default: \"%s\")\n"
918 " --iomem-size <val> : IO memory (in percents, default: %u)\n"
919 " -p <nm_desc> : Define a Network Module\n"
920 " -s <nm_nio> : Bind a Network IO interface to a "
921 "Network Module\n",
922 C3600_DEFAULT_CHASSIS,vm->nm_iomem_size);
923 }
924
925 /* Platform definition */
926 static vm_platform_t c3600_platform = {
927 "c3600", "C3600", "3600",
928 c3600_create_instance,
929 c3600_delete_instance,
930 c3600_init_instance,
931 c3600_stop_instance,
932 c3600_nvram_extract_config,
933 c3600_nvram_push_config,
934 c3600_get_mac_addr_msb,
935 c3600_save_config,
936 c3600_cli_parse_options,
937 c3600_cli_show_options,
938 c3600_chassis_show_drivers,
939 };
940
941 /* Register the c3600 platform */
942 int c3600_platform_register(void)
943 {
944 if (vm_platform_register(&c3600_platform) == -1)
945 return(-1);
946
947 return(hypervisor_c3600_init(&c3600_platform));
948 }

  ViewVC Help
Powered by ViewVC 1.1.26