/[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 10 - (show annotations)
Sat Oct 6 16:29:14 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7/dev_c3600.c
File MIME type: text/plain
File size: 42997 byte(s)
dynamips-0.2.7

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 c3600_nm_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 /* Directly extract the configuration from the NVRAM device */
119 ssize_t c3600_nvram_extract_config(vm_instance_t *vm,char **buffer)
120 {
121 u_char *base_ptr,*ios_ptr,*cfg_ptr,*end_ptr;
122 m_uint32_t start,nvlen;
123 m_uint16_t magic1,magic2;
124 struct vdevice *nvram_dev;
125 off_t nvram_size;
126 int fd;
127
128 if ((nvram_dev = dev_get_by_name(vm,"nvram")))
129 dev_sync(nvram_dev);
130
131 fd = vm_mmap_open_file(vm,"nvram",&base_ptr,&nvram_size);
132
133 if (fd == -1)
134 return(-1);
135
136 ios_ptr = base_ptr + vm->nvram_rom_space;
137 end_ptr = base_ptr + nvram_size;
138
139 if ((ios_ptr + 0x30) >= end_ptr) {
140 vm_error(vm,"NVRAM file too small\n");
141 return(-1);
142 }
143
144 magic1 = ntohs(*PTR_ADJUST(m_uint16_t *,ios_ptr,0x06));
145 magic2 = ntohs(*PTR_ADJUST(m_uint16_t *,ios_ptr,0x08));
146
147 if ((magic1 != 0xF0A5) || (magic2 != 0xABCD)) {
148 vm_error(vm,"unable to find IOS magic numbers (0x%x,0x%x)!\n",
149 magic1,magic2);
150 return(-1);
151 }
152
153 start = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x10)) + 1;
154 nvlen = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x18));
155
156 if (!(*buffer = malloc(nvlen+1))) {
157 vm_error(vm,"unable to allocate config buffer (%u bytes)\n",nvlen);
158 return(-1);
159 }
160
161 cfg_ptr = ios_ptr + start + 0x08;
162
163 if ((cfg_ptr + nvlen) > end_ptr) {
164 vm_error(vm,"NVRAM file too small\n");
165 return(-1);
166 }
167
168 memcpy(*buffer,cfg_ptr,nvlen-1);
169 (*buffer)[nvlen-1] = 0;
170 return(nvlen-1);
171 }
172
173 /* Directly push the IOS configuration to the NVRAM device */
174 int c3600_nvram_push_config(vm_instance_t *vm,char *buffer,size_t len)
175 {
176 u_char *base_ptr,*ios_ptr,*cfg_ptr;
177 m_uint32_t cfg_offset,cklen,tmp;
178 m_uint16_t cksum;
179 int fd;
180
181 fd = vm_mmap_create_file(vm,"nvram",vm->nvram_size*1024,&base_ptr);
182
183 if (fd == -1)
184 return(-1);
185
186 cfg_offset = 0x2c;
187 ios_ptr = base_ptr + vm->nvram_rom_space;
188 cfg_ptr = ios_ptr + cfg_offset;
189
190 /* Write IOS tag, uncompressed config... */
191 *PTR_ADJUST(m_uint16_t *,ios_ptr,0x06) = htons(0xF0A5);
192 *PTR_ADJUST(m_uint16_t *,ios_ptr,0x08) = htons(0xABCD);
193 *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0a) = htons(0x0001);
194 *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0c) = htons(0x0000);
195 *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0e) = htons(0x0c04);
196
197 /* Store file contents to NVRAM */
198 memcpy(cfg_ptr,buffer,len);
199
200 /* Write config addresses + size */
201 tmp = cfg_offset - 0x08;
202
203 *PTR_ADJUST(m_uint32_t *,ios_ptr,0x10) = htonl(tmp);
204 *PTR_ADJUST(m_uint32_t *,ios_ptr,0x14) = htonl(tmp + len);
205 *PTR_ADJUST(m_uint32_t *,ios_ptr,0x18) = htonl(len);
206
207 /* Compute the checksum */
208 cklen = (vm->nvram_size*1024) - (vm->nvram_rom_space + 0x08);
209 cksum = nvram_cksum((m_uint16_t *)(ios_ptr+0x08),cklen);
210 *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0c) = htons(cksum);
211
212 vm_mmap_close_file(fd,base_ptr,vm->nvram_size*1024);
213 return(0);
214 }
215
216 /* Create a new router instance */
217 c3600_t *c3600_create_instance(char *name,int instance_id)
218 {
219 c3600_t *router;
220
221 if (!(router = malloc(sizeof(*router)))) {
222 fprintf(stderr,"C3600 '%s': Unable to create new instance!\n",name);
223 return NULL;
224 }
225
226 memset(router,0,sizeof(*router));
227
228 if (!(router->vm = vm_create(name,instance_id,VM_TYPE_C3600))) {
229 fprintf(stderr,"C3600 '%s': unable to create VM instance!\n",name);
230 goto err_vm;
231 }
232
233 c3600_init_defaults(router);
234 router->vm->hw_data = router;
235 return router;
236
237 err_vm:
238 free(router);
239 return NULL;
240 }
241
242 /* Free resources used by a router instance */
243 static int c3600_free_instance(void *data,void *arg)
244 {
245 vm_instance_t *vm = data;
246 c3600_t *router;
247 int i;
248
249 if (vm->type == VM_TYPE_C3600) {
250 router = VM_C3600(vm);
251
252 /* Stop all CPUs */
253 if (vm->cpu_group != NULL) {
254 vm_stop(vm);
255
256 if (cpu_group_sync_state(vm->cpu_group) == -1) {
257 vm_error(vm,"unable to sync with system CPUs.\n");
258 return(FALSE);
259 }
260 }
261
262 /* Remove NIO bindings */
263 for(i=0;i<C3600_MAX_NM_BAYS;i++)
264 c3600_nm_remove_all_nio_bindings(router,i);
265
266 /* Shutdown all Network Modules */
267 c3600_nm_shutdown_all(router);
268
269 /* Free mainboard EEPROM */
270 cisco_eeprom_free(&router->mb_eeprom);
271
272 /* Free all resources used by VM */
273 vm_free(vm);
274
275 /* Free the router structure */
276 free(router);
277 return(TRUE);
278 }
279
280 return(FALSE);
281 }
282
283 /* Delete a router instance */
284 int c3600_delete_instance(char *name)
285 {
286 return(registry_delete_if_unused(name,OBJ_TYPE_VM,
287 c3600_free_instance,NULL));
288 }
289
290 /* Delete all router instances */
291 int c3600_delete_all_instances(void)
292 {
293 return(registry_delete_type(OBJ_TYPE_VM,c3600_free_instance,NULL));
294 }
295
296 /* Save configuration of a C3600 instance */
297 void c3600_save_config(c3600_t *router,FILE *fd)
298 {
299 vm_instance_t *vm = router->vm;
300 struct c3600_nio_binding *nb;
301 struct c3600_nm_bay *bay;
302 int i;
303
304 /* General settings */
305 fprintf(fd,"c3600 create %s %u\n",vm->name,vm->instance_id);
306
307 fprintf(fd,"c3600 set_chassis %s %s\n",
308 vm->name,router->chassis_driver->chassis_type);
309
310 /* VM configuration */
311 vm_save_config(vm,fd);
312
313 /* Network Module settings */
314 for(i=0;i<C3600_MAX_NM_BAYS;i++) {
315 if (!(bay = c3600_nm_get_info(router,i)))
316 continue;
317
318 if (bay->dev_type) {
319 fprintf(fd,"c3600 add_nm_binding %s %u %s\n",
320 vm->name,i,bay->dev_type);
321 }
322
323 for(nb=bay->nio_list;nb;nb=nb->next) {
324 fprintf(fd,"c3600 add_nio_binding %s %u %u %s\n",
325 vm->name,i,nb->port_id,nb->nio->name);
326 }
327 }
328
329 fprintf(fd,"\n");
330 }
331
332 /* Save configurations of all C3600 instances */
333 static void c3600_reg_save_config(registry_entry_t *entry,void *opt,int *err)
334 {
335 vm_instance_t *vm = entry->data;
336 c3600_t *router = VM_C3600(vm);
337
338 if (vm->type == VM_TYPE_C3600)
339 c3600_save_config(router,(FILE *)opt);
340 }
341
342 void c3600_save_config_all(FILE *fd)
343 {
344 registry_foreach_type(OBJ_TYPE_VM,c3600_reg_save_config,fd,NULL);
345 }
346
347 /* Get slot/port corresponding to specified network IRQ */
348 static inline void
349 c3600_net_irq_get_slot_port(u_int irq,u_int *slot,u_int *port)
350 {
351 irq -= C3600_NETIO_IRQ_BASE;
352 *port = irq & C3600_NETIO_IRQ_PORT_MASK;
353 *slot = irq >> C3600_NETIO_IRQ_PORT_BITS;
354 }
355
356 /* Get network IRQ for specified slot/port */
357 u_int c3600_net_irq_for_slot_port(u_int slot,u_int port)
358 {
359 u_int irq;
360
361 irq = (slot << C3600_NETIO_IRQ_PORT_BITS) + port;
362 irq += C3600_NETIO_IRQ_BASE;
363
364 return(irq);
365 }
366
367 /* Set NM EEPROM definition */
368 int c3600_nm_set_eeprom(c3600_t *router,u_int nm_bay,
369 const struct cisco_eeprom *eeprom)
370 {
371 if (nm_bay >= C3600_MAX_NM_BAYS) {
372 vm_error(router->vm,"c3600_nm_set_eeprom: invalid NM Bay %u.\n",nm_bay);
373 return(-1);
374 }
375
376 if (cisco_eeprom_copy(&router->nm_bay[nm_bay].eeprom,eeprom) == -1) {
377 vm_error(router->vm,"c3600_nm_set_eeprom: no memory.\n");
378 return(-1);
379 }
380
381 return(0);
382 }
383
384 /* Unset NM EEPROM definition (empty bay) */
385 int c3600_nm_unset_eeprom(c3600_t *router,u_int nm_bay)
386 {
387 if (nm_bay >= C3600_MAX_NM_BAYS) {
388 vm_error(router->vm,"c3600_nm_set_eeprom: invalid NM Bay %u.\n",nm_bay);
389 return(-1);
390 }
391
392 cisco_eeprom_free(&router->nm_bay[nm_bay].eeprom);
393 return(0);
394 }
395
396 /* Check if a bay has a port adapter */
397 int c3600_nm_check_eeprom(c3600_t *router,u_int nm_bay)
398 {
399 if (nm_bay >= C3600_MAX_NM_BAYS)
400 return(FALSE);
401
402 return(cisco_eeprom_valid(&router->nm_bay[nm_bay].eeprom));
403 }
404
405 /* Get bay info */
406 struct c3600_nm_bay *c3600_nm_get_info(c3600_t *router,u_int nm_bay)
407 {
408 if (nm_bay >= C3600_MAX_NM_BAYS)
409 return NULL;
410
411 return(&router->nm_bay[nm_bay]);
412 }
413
414 /* Get NM type */
415 char *c3600_nm_get_type(c3600_t *router,u_int nm_bay)
416 {
417 struct c3600_nm_bay *bay;
418
419 bay = c3600_nm_get_info(router,nm_bay);
420 return((bay != NULL) ? bay->dev_type : NULL);
421 }
422
423 /* Get driver info about the specified slot */
424 void *c3600_nm_get_drvinfo(c3600_t *router,u_int nm_bay)
425 {
426 struct c3600_nm_bay *bay;
427
428 bay = c3600_nm_get_info(router,nm_bay);
429 return((bay != NULL) ? bay->drv_info : NULL);
430 }
431
432 /* Set driver info for the specified slot */
433 int c3600_nm_set_drvinfo(c3600_t *router,u_int nm_bay,void *drv_info)
434 {
435 struct c3600_nm_bay *bay;
436
437 if (!(bay = c3600_nm_get_info(router,nm_bay)))
438 return(-1);
439
440 bay->drv_info = drv_info;
441 return(0);
442 }
443
444 /* Get a NM driver */
445 static struct c3600_nm_driver *c3600_nm_get_driver(char *dev_type)
446 {
447 int i;
448
449 for(i=0;nm_drivers[i];i++)
450 if (!strcmp(nm_drivers[i]->dev_type,dev_type))
451 return nm_drivers[i];
452
453 return NULL;
454 }
455
456 /* Add a NM binding */
457 int c3600_nm_add_binding(c3600_t *router,char *dev_type,u_int nm_bay)
458 {
459 struct c3600_nm_driver *nm_driver;
460 struct c3600_nm_bay *bay;
461
462 if (!(bay = c3600_nm_get_info(router,nm_bay)))
463 return(-1);
464
465 /* check that this bay is empty */
466 if (bay->dev_type != NULL) {
467 vm_error(router->vm,"a NM already exists in slot %u.\n",nm_bay);
468 return(-1);
469 }
470
471 /* find the NM driver */
472 if (!(nm_driver = c3600_nm_get_driver(dev_type))) {
473 vm_error(router->vm,"unknown NM type '%s'.\n",dev_type);
474 return(-1);
475 }
476
477 bay->dev_type = nm_driver->dev_type;
478 bay->nm_driver = nm_driver;
479 return(0);
480 }
481
482 /* Remove a NM binding */
483 int c3600_nm_remove_binding(c3600_t *router,u_int nm_bay)
484 {
485 struct c3600_nm_bay *bay;
486
487 if (!(bay = c3600_nm_get_info(router,nm_bay)))
488 return(-1);
489
490 /* stop if this bay is still active */
491 if (bay->drv_info != NULL) {
492 vm_error(router->vm,"slot %u still active.\n",nm_bay);
493 return(-1);
494 }
495
496 /* check that this bay is not empty */
497 if (bay->dev_type == NULL) {
498 vm_error(router->vm,"slot %u is empty.\n",nm_bay);
499 return(-1);
500 }
501
502 /* remove all NIOs bindings */
503 c3600_nm_remove_all_nio_bindings(router,nm_bay);
504
505 bay->dev_type = NULL;
506 bay->nm_driver = NULL;
507 return(0);
508 }
509
510 /* Find a NIO binding */
511 struct c3600_nio_binding *
512 c3600_nm_find_nio_binding(c3600_t *router,u_int nm_bay,u_int port_id)
513 {
514 struct c3600_nio_binding *nb;
515 struct c3600_nm_bay *bay;
516
517 if (!(bay = c3600_nm_get_info(router,nm_bay)))
518 return NULL;
519
520 for(nb=bay->nio_list;nb;nb=nb->next)
521 if (nb->port_id == port_id)
522 return nb;
523
524 return NULL;
525 }
526
527 /* Add a network IO binding */
528 int c3600_nm_add_nio_binding(c3600_t *router,u_int nm_bay,u_int port_id,
529 char *nio_name)
530 {
531 struct c3600_nio_binding *nb;
532 struct c3600_nm_bay *bay;
533 netio_desc_t *nio;
534
535 if (!(bay = c3600_nm_get_info(router,nm_bay)))
536 return(-1);
537
538 /* check that a NIO is not already bound to this port */
539 if (c3600_nm_find_nio_binding(router,nm_bay,port_id) != NULL) {
540 vm_error(router->vm,"a NIO already exists for interface %u/%u.\n",
541 nm_bay,port_id);
542 return(-1);
543 }
544
545 /* acquire a reference on the NIO object */
546 if (!(nio = netio_acquire(nio_name))) {
547 vm_error(router->vm,"unable to find NIO '%s'.\n",nio_name);
548 return(-1);
549 }
550
551 /* create a new binding */
552 if (!(nb = malloc(sizeof(*nb)))) {
553 vm_error(router->vm,"unable to create NIO binding "
554 "for interface %u/%u.\n",nm_bay,port_id);
555 netio_release(nio_name);
556 return(-1);
557 }
558
559 memset(nb,0,sizeof(*nb));
560 nb->nio = nio;
561 nb->port_id = port_id;
562 nb->next = bay->nio_list;
563 if (nb->next) nb->next->prev = nb;
564 bay->nio_list = nb;
565 return(0);
566 }
567
568 /* Remove a NIO binding */
569 int c3600_nm_remove_nio_binding(c3600_t *router,u_int nm_bay,u_int port_id)
570 {
571 struct c3600_nio_binding *nb;
572 struct c3600_nm_bay *bay;
573
574 if (!(bay = c3600_nm_get_info(router,nm_bay)))
575 return(-1);
576
577 if (!(nb = c3600_nm_find_nio_binding(router,nm_bay,port_id)))
578 return(-1); /* no nio binding for this slot/port */
579
580 /* tell the NM driver to stop using this NIO */
581 if (bay->nm_driver)
582 bay->nm_driver->nm_unset_nio(router,nm_bay,port_id);
583
584 /* remove this entry from the double linked list */
585 if (nb->next)
586 nb->next->prev = nb->prev;
587
588 if (nb->prev) {
589 nb->prev->next = nb->next;
590 } else {
591 bay->nio_list = nb->next;
592 }
593
594 /* unreference NIO object */
595 netio_release(nb->nio->name);
596 free(nb);
597 return(0);
598 }
599
600 /* Remove all NIO bindings for the specified NM */
601 int c3600_nm_remove_all_nio_bindings(c3600_t *router,u_int nm_bay)
602 {
603 struct c3600_nio_binding *nb,*next;
604 struct c3600_nm_bay *bay;
605
606 if (!(bay = c3600_nm_get_info(router,nm_bay)))
607 return(-1);
608
609 for(nb=bay->nio_list;nb;nb=next) {
610 next = nb->next;
611
612 /* tell the NM driver to stop using this NIO */
613 if (bay->nm_driver)
614 bay->nm_driver->nm_unset_nio(router,nm_bay,nb->port_id);
615
616 /* unreference NIO object */
617 netio_release(nb->nio->name);
618 free(nb);
619 }
620
621 bay->nio_list = NULL;
622 return(0);
623 }
624
625 /* Enable a Network IO descriptor for a Network Module */
626 int c3600_nm_enable_nio(c3600_t *router,u_int nm_bay,u_int port_id)
627 {
628 struct c3600_nio_binding *nb;
629 struct c3600_nm_bay *bay;
630
631 if (!(bay = c3600_nm_get_info(router,nm_bay)))
632 return(-1);
633
634 /* check that we have an NIO binding for this interface */
635 if (!(nb = c3600_nm_find_nio_binding(router,nm_bay,port_id)))
636 return(-1);
637
638 /* check that the driver is defined and successfully initialized */
639 if (!bay->nm_driver || !bay->drv_info)
640 return(-1);
641
642 return(bay->nm_driver->nm_set_nio(router,nm_bay,port_id,nb->nio));
643 }
644
645 /* Disable Network IO descriptor of a Network Module */
646 int c3600_nm_disable_nio(c3600_t *router,u_int nm_bay,u_int port_id)
647 {
648 struct c3600_nm_bay *bay;
649
650 if (!(bay = c3600_nm_get_info(router,nm_bay)))
651 return(-1);
652
653 /* check that the driver is defined and successfully initialized */
654 if (!bay->nm_driver || !bay->drv_info)
655 return(-1);
656
657 return(bay->nm_driver->nm_unset_nio(router,nm_bay,port_id));
658 }
659
660 /* Enable all NIO of the specified NM */
661 int c3600_nm_enable_all_nio(c3600_t *router,u_int nm_bay)
662 {
663 struct c3600_nio_binding *nb;
664 struct c3600_nm_bay *bay;
665
666 if (!(bay = c3600_nm_get_info(router,nm_bay)))
667 return(-1);
668
669 /* check that the driver is defined and successfully initialized */
670 if (!bay->nm_driver || !bay->drv_info)
671 return(-1);
672
673 for(nb=bay->nio_list;nb;nb=nb->next)
674 bay->nm_driver->nm_set_nio(router,nm_bay,nb->port_id,nb->nio);
675
676 return(0);
677 }
678
679 /* Disable all NIO of the specified NM */
680 int c3600_nm_disable_all_nio(c3600_t *router,u_int nm_bay)
681 {
682 struct c3600_nio_binding *nb;
683 struct c3600_nm_bay *bay;
684
685 if (!(bay = c3600_nm_get_info(router,nm_bay)))
686 return(-1);
687
688 /* check that the driver is defined and successfully initialized */
689 if (!bay->nm_driver || !bay->drv_info)
690 return(-1);
691
692 for(nb=bay->nio_list;nb;nb=nb->next)
693 bay->nm_driver->nm_unset_nio(router,nm_bay,nb->port_id);
694
695 return(0);
696 }
697
698 /* Initialize a Network Module */
699 int c3600_nm_init(c3600_t *router,u_int nm_bay)
700 {
701 struct c3600_nm_bay *bay;
702 size_t len;
703
704 if (!(bay = c3600_nm_get_info(router,nm_bay)))
705 return(-1);
706
707 /* Check that a device type is defined for this bay */
708 if (!bay->dev_type || !bay->nm_driver) {
709 vm_error(router->vm,"trying to init empty slot %u.\n",nm_bay);
710 return(-1);
711 }
712
713 /* Allocate device name */
714 len = strlen(bay->dev_type) + 10;
715 if (!(bay->dev_name = malloc(len))) {
716 vm_error(router->vm,"unable to allocate device name.\n");
717 return(-1);
718 }
719
720 snprintf(bay->dev_name,len,"%s(%u)",bay->dev_type,nm_bay);
721
722 /* Initialize NM driver */
723 if (bay->nm_driver->nm_init(router,bay->dev_name,nm_bay) == -1) {
724 vm_error(router->vm,"unable to initialize NM %u.\n",nm_bay);
725 return(-1);
726 }
727
728 /* Enable all NIO */
729 c3600_nm_enable_all_nio(router,nm_bay);
730 return(0);
731 }
732
733 /* Shutdown a Network Module */
734 int c3600_nm_shutdown(c3600_t *router,u_int nm_bay)
735 {
736 struct c3600_nm_bay *bay;
737
738 if (!(bay = c3600_nm_get_info(router,nm_bay)))
739 return(-1);
740
741 /* Check that a device type is defined for this bay */
742 if (!bay->dev_type || !bay->nm_driver) {
743 vm_error(router->vm,"trying to shut down empty slot %u.\n",nm_bay);
744 return(-1);
745 }
746
747 /* Disable all NIO */
748 c3600_nm_disable_all_nio(router,nm_bay);
749
750 /* Shutdown the NM driver */
751 if (bay->drv_info && (bay->nm_driver->nm_shutdown(router,nm_bay) == -1)) {
752 vm_error(router->vm,"unable to shutdown NM %u.\n",nm_bay);
753 return(-1);
754 }
755
756 free(bay->dev_name);
757 bay->dev_name = NULL;
758 bay->drv_info = NULL;
759 return(0);
760 }
761
762 /* Shutdown all NM of a router */
763 int c3600_nm_shutdown_all(c3600_t *router)
764 {
765 int i;
766
767 for(i=0;i<C3600_MAX_NM_BAYS;i++) {
768 if (!router->nm_bay[i].dev_type)
769 continue;
770
771 c3600_nm_shutdown(router,i);
772 }
773
774 return(0);
775 }
776
777 /* Show info about all NMs */
778 int c3600_nm_show_all_info(c3600_t *router)
779 {
780 struct c3600_nm_bay *bay;
781 int i;
782
783 for(i=0;i<C3600_MAX_NM_BAYS;i++) {
784 if (!(bay = c3600_nm_get_info(router,i)) || !bay->nm_driver)
785 continue;
786
787 if (bay->nm_driver->nm_show_info != NULL)
788 bay->nm_driver->nm_show_info(router,i);
789 }
790
791 return(0);
792 }
793
794 /* Maximum number of tokens in a NM description */
795 #define NM_DESC_MAX_TOKENS 8
796
797 /* Create a Network Module (command line) */
798 int c3600_cmd_nm_create(c3600_t *router,char *str)
799 {
800 char *tokens[NM_DESC_MAX_TOKENS];
801 int i,count,res;
802 u_int nm_bay;
803
804 /* A port adapter description is like "1:NM-1FE" */
805 if ((count = m_strsplit(str,':',tokens,NM_DESC_MAX_TOKENS)) != 2) {
806 vm_error(router->vm,"unable to parse NM description '%s'.\n",str);
807 return(-1);
808 }
809
810 /* Parse the NM bay id */
811 nm_bay = atoi(tokens[0]);
812
813 /* Add this new NM to the current NM list */
814 res = c3600_nm_add_binding(router,tokens[1],nm_bay);
815
816 /* The complete array was cleaned by strsplit */
817 for(i=0;i<NM_DESC_MAX_TOKENS;i++)
818 free(tokens[i]);
819
820 return(res);
821 }
822
823 /* Add a Network IO descriptor binding (command line) */
824 int c3600_cmd_add_nio(c3600_t *router,char *str)
825 {
826 char *tokens[NM_DESC_MAX_TOKENS];
827 int i,count,nio_type,res=-1;
828 u_int nm_bay,port_id;
829 netio_desc_t *nio;
830 char nio_name[128];
831
832 /* A port adapter description is like "1:3:tap:tap0" */
833 if ((count = m_strsplit(str,':',tokens,NM_DESC_MAX_TOKENS)) < 3) {
834 vm_error(router->vm,"unable to parse NIO description '%s'.\n",str);
835 return(-1);
836 }
837
838 /* Parse the NM bay */
839 nm_bay = atoi(tokens[0]);
840
841 /* Parse the NM port id */
842 port_id = atoi(tokens[1]);
843
844 /* Autogenerate a NIO name */
845 snprintf(nio_name,sizeof(nio_name),"c3600-i%u/%u/%u",
846 router->vm->instance_id,nm_bay,port_id);
847
848 /* Create the Network IO descriptor */
849 nio = NULL;
850 nio_type = netio_get_type(tokens[2]);
851
852 switch(nio_type) {
853 case NETIO_TYPE_UNIX:
854 if (count != 5) {
855 vm_error(router->vm,
856 "invalid number of arguments for UNIX NIO '%s'\n",str);
857 goto done;
858 }
859
860 nio = netio_desc_create_unix(nio_name,tokens[3],tokens[4]);
861 break;
862
863 case NETIO_TYPE_VDE:
864 if (count != 5) {
865 vm_error(router->vm,
866 "invalid number of arguments for VDE NIO '%s'\n",str);
867 goto done;
868 }
869
870 nio = netio_desc_create_vde(nio_name,tokens[3],tokens[4]);
871 break;
872
873 case NETIO_TYPE_TAP:
874 if (count != 4) {
875 vm_error(router->vm,
876 "invalid number of arguments for TAP NIO '%s'\n",str);
877 goto done;
878 }
879
880 nio = netio_desc_create_tap(nio_name,tokens[3]);
881 break;
882
883 case NETIO_TYPE_UDP:
884 if (count != 6) {
885 vm_error(router->vm,
886 "invalid number of arguments for UDP NIO '%s'\n",str);
887 goto done;
888 }
889
890 nio = netio_desc_create_udp(nio_name,atoi(tokens[3]),
891 tokens[4],atoi(tokens[5]));
892 break;
893
894 case NETIO_TYPE_TCP_CLI:
895 if (count != 5) {
896 vm_error(router->vm,
897 "invalid number of arguments for TCP CLI NIO '%s'\n",str);
898 goto done;
899 }
900
901 nio = netio_desc_create_tcp_cli(nio_name,tokens[3],tokens[4]);
902 break;
903
904 case NETIO_TYPE_TCP_SER:
905 if (count != 4) {
906 vm_error(router->vm,
907 "invalid number of arguments for TCP SER NIO '%s'\n",str);
908 goto done;
909 }
910
911 nio = netio_desc_create_tcp_ser(nio_name,tokens[3]);
912 break;
913
914 case NETIO_TYPE_NULL:
915 nio = netio_desc_create_null(nio_name);
916 break;
917
918 #ifdef LINUX_ETH
919 case NETIO_TYPE_LINUX_ETH:
920 if (count != 4) {
921 vm_error(router->vm,
922 "invalid number of arguments for Linux Eth NIO '%s'\n",
923 str);
924 goto done;
925 }
926
927 nio = netio_desc_create_lnxeth(nio_name,tokens[3]);
928 break;
929 #endif
930
931 #ifdef GEN_ETH
932 case NETIO_TYPE_GEN_ETH:
933 if (count != 4) {
934 vm_error(router->vm,
935 "invalid number of arguments for Generic Eth NIO '%s'\n",
936 str);
937 goto done;
938 }
939
940 nio = netio_desc_create_geneth(nio_name,tokens[3]);
941 break;
942 #endif
943
944 default:
945 vm_error(router->vm,"unknown NETIO type '%s'\n",tokens[2]);
946 goto done;
947 }
948
949 if (!nio) {
950 vm_error(router->vm,"unable to create NETIO "
951 "descriptor for NM slot %u\n",nm_bay);
952 goto done;
953 }
954
955 if (c3600_nm_add_nio_binding(router,nm_bay,port_id,nio_name) == -1) {
956 vm_error(router->vm,"unable to add NETIO binding for slot %u\n",nm_bay);
957 netio_release(nio_name);
958 netio_delete(nio_name);
959 goto done;
960 }
961
962 netio_release(nio_name);
963 res = 0;
964
965 done:
966 /* The complete array was cleaned by strsplit */
967 for(i=0;i<NM_DESC_MAX_TOKENS;i++)
968 free(tokens[i]);
969
970 return(res);
971 }
972
973 /* Show the list of available NM drivers */
974 void c3600_nm_show_drivers(void)
975 {
976 int i;
977
978 printf("Available C3600 Network Module drivers:\n");
979
980 for(i=0;nm_drivers[i];i++) {
981 printf(" * %s %s\n",
982 nm_drivers[i]->dev_type,
983 !nm_drivers[i]->supported ? "(NOT WORKING)" : "");
984 }
985
986 printf("\n");
987 }
988
989 /* Get a chassis driver */
990 struct c3600_chassis_driver *c3600_chassis_get_driver(char *chassis_type)
991 {
992 int i;
993
994 for(i=0;chassis_drivers[i].chassis_type;i++)
995 if (!strcmp(chassis_drivers[i].chassis_type,chassis_type))
996 return(&chassis_drivers[i]);
997
998 return NULL;
999 }
1000
1001 /* Set the base MAC address of the chassis */
1002 static int c3600_burn_mac_addr(c3600_t *router,n_eth_addr_t *addr)
1003 {
1004 m_uint8_t eeprom_ver;
1005 size_t offset;
1006
1007 /* Read EEPROM format version */
1008 cisco_eeprom_get_byte(&router->mb_eeprom,0,&eeprom_ver);
1009
1010 switch(eeprom_ver) {
1011 case 0:
1012 cisco_eeprom_set_region(&router->mb_eeprom,2,addr->eth_addr_byte,6);
1013 break;
1014
1015 case 4:
1016 if (!cisco_eeprom_v4_find_field(&router->mb_eeprom,0xC3,&offset)) {
1017 cisco_eeprom_set_region(&router->mb_eeprom,offset,
1018 addr->eth_addr_byte,6);
1019 }
1020 break;
1021
1022 default:
1023 vm_error(router->vm,"c3600_burn_mac_addr: unable to handle "
1024 "EEPROM version %u\n",eeprom_ver);
1025 return(-1);
1026 }
1027
1028 return(0);
1029 }
1030
1031 /* Set chassis MAC address */
1032 int c3600_chassis_set_mac_addr(c3600_t *router,char *mac_addr)
1033 {
1034 if (parse_mac_addr(&router->mac_addr,mac_addr) == -1) {
1035 vm_error(router->vm,"unable to parse MAC address '%s'.\n",mac_addr);
1036 return(-1);
1037 }
1038
1039 /* Set the chassis base MAC address */
1040 c3600_burn_mac_addr(router,&router->mac_addr);
1041 return(0);
1042 }
1043
1044 /* Set the chassis type */
1045 int c3600_chassis_set_type(c3600_t *router,char *chassis_type)
1046 {
1047 struct c3600_chassis_driver *driver;
1048
1049 if (router->vm->status == VM_STATUS_RUNNING) {
1050 vm_error(router->vm,"unable to change chassis type when online.\n");
1051 return(-1);
1052 }
1053
1054 if (!(driver = c3600_chassis_get_driver(chassis_type))) {
1055 vm_error(router->vm,"unknown chassis type '%s'.\n",chassis_type);
1056 return(-1);
1057 }
1058
1059 router->chassis_driver = driver;
1060
1061 /* Copy the mainboard EEPROM */
1062 if (cisco_eeprom_copy(&router->mb_eeprom,driver->eeprom) == -1) {
1063 vm_error(router->vm,"unable to set chassis EEPROM '%s'.\n",chassis_type);
1064 return(-1);
1065 }
1066
1067 /* Set the chassis base MAC address */
1068 c3600_burn_mac_addr(router,&router->mac_addr);
1069 return(0);
1070 }
1071
1072 /* Get the chassis ID */
1073 int c3600_chassis_get_id(c3600_t *router)
1074 {
1075 if (router->chassis_driver)
1076 return(router->chassis_driver->chassis_id);
1077
1078 return(-1);
1079 }
1080
1081 /* Show the list of available chassis drivers */
1082 void c3600_chassis_show_drivers(void)
1083 {
1084 int i;
1085
1086 printf("Available C3600 chassis drivers:\n");
1087
1088 for(i=0;chassis_drivers[i].chassis_type;i++) {
1089 printf(" * %s %s\n",
1090 chassis_drivers[i].chassis_type,
1091 !chassis_drivers[i].supported ? "(NOT WORKING)" : "");
1092 }
1093
1094 printf("\n");
1095 }
1096
1097 /* Create the main PCI bus for a GT64010 based system */
1098 static int c3600_init_gt64010(c3600_t *router)
1099 {
1100 if (!(router->vm->pci_bus[0] = pci_bus_create("PCI bus",0))) {
1101 vm_error(router->vm,"unable to create PCI data.\n");
1102 return(-1);
1103 }
1104
1105 return(dev_gt64010_init(router->vm,"gt64010",C3600_GT64K_ADDR,0x1000,
1106 C3600_GT64K_IRQ));
1107 }
1108
1109 /* Create the two main PCI busses for a GT64120 based system */
1110 static int c3600_init_gt64120(c3600_t *router)
1111 {
1112 vm_instance_t *vm = router->vm;
1113
1114 vm->pci_bus[0] = pci_bus_create("PCI bus #0",0);
1115 vm->pci_bus[1] = pci_bus_create("PCI bus #1",0);
1116
1117 if (!vm->pci_bus[0] || !vm->pci_bus[1]) {
1118 vm_error(router->vm,"unable to create PCI data.\n");
1119 return(-1);
1120 }
1121
1122 return(dev_gt64120_init(vm,"gt64120",C3600_GT64K_ADDR,0x1000,
1123 C3600_GT64K_IRQ));
1124 }
1125
1126 /* Initialize a Cisco 3620 */
1127 static int c3620_init(c3600_t *router)
1128 {
1129 vm_instance_t *vm = router->vm;
1130 int i;
1131
1132 /* Set the processor type: R4700 */
1133 mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R4700);
1134
1135 /* Initialize the Galileo GT-64010 PCI controller */
1136 if (c3600_init_gt64010(router) == -1)
1137 return(-1);
1138
1139 /* Initialize PCI map (no PCI bridge for this chassis) */
1140 for(i=0;i<C3600_MAX_NM_BAYS;i++)
1141 router->nm_bay[i].pci_map = vm->pci_bus[0];
1142
1143 vm->elf_machine_id = C3620_ELF_MACHINE_ID;
1144 return(0);
1145 }
1146
1147 /* Initialize a Cisco 3640 */
1148 static int c3640_init(c3600_t *router)
1149 {
1150 vm_instance_t *vm = router->vm;
1151 struct nm_bay_info *bay;
1152 int i;
1153
1154 /* Set the processor type: R4700 */
1155 mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R4700);
1156
1157 /* Initialize the Galileo GT-64010 PCI controller */
1158 if (c3600_init_gt64010(router) == -1)
1159 return(-1);
1160
1161 /* Create the NM PCI busses */
1162 vm->pci_bus_pool[0] = pci_bus_create("NM Slots 0,2",-1);
1163 vm->pci_bus_pool[1] = pci_bus_create("NM Slots 1,3",-1);
1164
1165 /* Initialize PCI map and PCI bridges */
1166 for(i=0;i<=3;i++) {
1167 bay = c3600_nm_get_bay_info(3640,i);
1168
1169 /* Map the NM PCI bus */
1170 router->nm_bay[i].pci_map = vm->pci_bus_pool[i & 1];
1171
1172 if (bay && (bay->pci_bridge_device != -1))
1173 dev_dec21052_init(vm->pci_bus[0],bay->pci_bridge_device,
1174 router->nm_bay[i].pci_map);
1175 }
1176
1177 vm->elf_machine_id = C3640_ELF_MACHINE_ID;
1178 return(0);
1179 }
1180
1181 /* Initialize a Cisco 3660 */
1182 static int c3660_init(c3600_t *router)
1183 {
1184 vm_instance_t *vm = router->vm;
1185 struct nm_bay_info *bay;
1186 char bus_name[128];
1187 int i;
1188
1189 /* Set the processor type: R5271 */
1190 mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R527x);
1191
1192 /* Initialize the Galileo GT-64120 PCI controller */
1193 if (c3600_init_gt64120(router) == -1)
1194 return(-1);
1195
1196 /* Create the NM PCI busses */
1197 for(i=1;i<=6;i++) {
1198 snprintf(bus_name,sizeof(bus_name),"NM Slot %d",i);
1199 vm->pci_bus_pool[i] = pci_bus_create(bus_name,-1);
1200 }
1201
1202 /* Slot 0 is mapped to the first bus of GT64120 */
1203 router->nm_bay[0].pci_map = vm->pci_bus[0];
1204
1205 /* Initialize PCI map and PCI bridges */
1206 for(i=1;i<C3600_MAX_NM_BAYS;i++) {
1207 bay = c3600_nm_get_bay_info(3660,i);
1208
1209 /* Map the NM PCI bus */
1210 router->nm_bay[i].pci_map = vm->pci_bus_pool[i];
1211
1212 /* Slots 1-6 are mapped to the second bus of GT64120 */
1213 if (bay && (bay->pci_bridge_device != -1))
1214 dev_dec21152_init(vm->pci_bus[1],bay->pci_bridge_device,
1215 router->nm_bay[i].pci_map);
1216 }
1217
1218 /* The motherboard has 2 integrated FastEthernet ports */
1219 c3600_nm_add_binding(router,"Leopard-2FE",0);
1220
1221 vm->elf_machine_id = C3640_ELF_MACHINE_ID;
1222 return(0);
1223 }
1224
1225 /* Show C3600 hardware info */
1226 void c3600_show_hardware(c3600_t *router)
1227 {
1228 vm_instance_t *vm = router->vm;
1229
1230 printf("C3600 instance '%s' (id %d):\n",vm->name,vm->instance_id);
1231
1232 printf(" VM Status : %d\n",vm->status);
1233 printf(" RAM size : %u Mb\n",vm->ram_size);
1234 printf(" NVRAM size : %u Kb\n",vm->nvram_size);
1235 printf(" Chassis : %s\n",router->chassis_driver->chassis_type);
1236 printf(" IOS image : %s\n\n",vm->ios_image);
1237
1238 if (vm->debug_level > 0) {
1239 dev_show_list(vm);
1240 pci_dev_show_list(vm->pci_bus[0]);
1241 pci_dev_show_list(vm->pci_bus[1]);
1242 printf("\n");
1243 }
1244 }
1245
1246 /* Initialize default parameters for a C3600 */
1247 void c3600_init_defaults(c3600_t *router)
1248 {
1249 vm_instance_t *vm = router->vm;
1250 n_eth_addr_t *m;
1251 m_uint16_t pid;
1252
1253 pid = (m_uint16_t)getpid();
1254
1255 /* Generate a chassis MAC address based on the instance ID */
1256 m = &router->mac_addr;
1257 m->eth_addr_byte[0] = vm_get_mac_addr_msb(vm);
1258 m->eth_addr_byte[1] = vm->instance_id & 0xFF;
1259 m->eth_addr_byte[2] = pid >> 8;
1260 m->eth_addr_byte[3] = pid & 0xFF;
1261 m->eth_addr_byte[4] = 0x00;
1262 m->eth_addr_byte[5] = 0x00;
1263
1264 c3600_init_eeprom_groups(router);
1265 c3600_chassis_set_type(router,C3600_DEFAULT_CHASSIS);
1266
1267 vm->ram_mmap = C3600_DEFAULT_RAM_MMAP;
1268 vm->ram_size = C3600_DEFAULT_RAM_SIZE;
1269 vm->rom_size = C3600_DEFAULT_ROM_SIZE;
1270 vm->nvram_size = C3600_DEFAULT_NVRAM_SIZE;
1271 vm->conf_reg_setup = C3600_DEFAULT_CONF_REG;
1272 vm->clock_divisor = C3600_DEFAULT_CLOCK_DIV;
1273 vm->nvram_rom_space = C3600_NVRAM_ROM_RES_SIZE;
1274 router->nm_iomem_size = C3600_DEFAULT_IOMEM_SIZE;
1275
1276 vm->pcmcia_disk_size[0] = C3600_DEFAULT_DISK0_SIZE;
1277 vm->pcmcia_disk_size[1] = C3600_DEFAULT_DISK1_SIZE;
1278
1279 /* Enable NVRAM operations to load/store configs */
1280 vm->nvram_extract_config = c3600_nvram_extract_config;
1281 vm->nvram_push_config = c3600_nvram_push_config;
1282 }
1283
1284 /* Initialize the C3600 Platform */
1285 int c3600_init_platform(c3600_t *router)
1286 {
1287 vm_instance_t *vm = router->vm;
1288 struct c3600_nm_bay *nm_bay;
1289 cpu_mips_t *cpu;
1290 cpu_gen_t *gen;
1291 vm_obj_t *obj;
1292 int i;
1293
1294 /* Copy config register setup into "active" config register */
1295 vm->conf_reg = vm->conf_reg_setup;
1296
1297 /* Create Console and AUX ports */
1298 vm_init_vtty(vm);
1299
1300 /* Create a CPU group */
1301 vm->cpu_group = cpu_group_create("System CPU");
1302
1303 /* Initialize the virtual MIPS processor */
1304 if (!(gen = cpu_create(vm,CPU_TYPE_MIPS64,0))) {
1305 vm_error(vm,"unable to create CPU!\n");
1306 return(-1);
1307 }
1308
1309 cpu = CPU_MIPS64(gen);
1310
1311 /* Add this CPU to the system CPU group */
1312 cpu_group_add(vm->cpu_group,gen);
1313 vm->boot_cpu = gen;
1314
1315 /* Initialize the IRQ routing vectors */
1316 vm->set_irq = mips64_vm_set_irq;
1317 vm->clear_irq = mips64_vm_clear_irq;
1318
1319 /* Mark the Network IO interrupt as high priority */
1320 cpu->irq_idle_preempt[C3600_NETIO_IRQ] = TRUE;
1321 cpu->irq_idle_preempt[C3600_GT64K_IRQ] = TRUE;
1322 cpu->irq_idle_preempt[C3600_DUART_IRQ] = TRUE;
1323
1324 /* Copy some parameters from VM to CPU (idle PC, ...) */
1325 cpu->idle_pc = vm->idle_pc;
1326
1327 if (vm->timer_irq_check_itv)
1328 cpu->timer_irq_check_itv = vm->timer_irq_check_itv;
1329
1330 /* Get chassis specific driver */
1331 if (!router->chassis_driver) {
1332 vm_error(vm,"no chassis defined.\n");
1333 return(-1);
1334 }
1335
1336 /* Remote emulator control */
1337 dev_remote_control_init(vm,0x16000000,0x1000);
1338
1339 /* Bootflash */
1340 dev_bootflash_init(vm,"bootflash",C3600_BOOTFLASH_ADDR,(8 * 1048576));
1341
1342 /* NVRAM and calendar */
1343 dev_nvram_init(vm,"nvram",
1344 C3600_NVRAM_ADDR,vm->nvram_size*1024,&vm->conf_reg);
1345
1346 /* Bit-bucket zone */
1347 dev_zero_init(vm,"zero",C3600_BITBUCKET_ADDR,0xc00000);
1348
1349 /* IO FPGA */
1350 if (dev_c3600_iofpga_init(router,C3600_IOFPGA_ADDR,0x40000) == -1)
1351 return(-1);
1352
1353 if (!(obj = vm_object_find(router->vm,"io_fpga")))
1354 return(-1);
1355
1356 router->iofpga_data = obj->data;
1357
1358 /* PCI IO space */
1359 if (!(vm->pci_io_space = pci_io_data_init(vm,C3600_PCI_IO_ADDR)))
1360 return(-1);
1361
1362 /* Initialize the chassis */
1363 if (router->chassis_driver->chassis_init(router) == -1)
1364 return(-1);
1365
1366 /* Initialize RAM */
1367 vm_ram_init(vm,0x00000000ULL);
1368
1369 /* Initialize ROM */
1370 if (!vm->rom_filename) {
1371 /* use embedded ROM */
1372 dev_rom_init(vm,"rom",C3600_ROM_ADDR,vm->rom_size*1048576,
1373 mips64_microcode,mips64_microcode_len);
1374 } else {
1375 /* use alternate ROM */
1376 dev_ram_init(vm,"rom",TRUE,TRUE,NULL,FALSE,
1377 C3600_ROM_ADDR,vm->rom_size*1048576);
1378 }
1379
1380 /* Initialize the NS16552 DUART */
1381 dev_ns16552_init(vm,C3600_DUART_ADDR,0x1000,3,C3600_DUART_IRQ,
1382 vm->vtty_con,vm->vtty_aux);
1383
1384 /* Cirrus Logic PD6729 (PCI-to-PCMCIA host adapter) */
1385 dev_clpd6729_init(vm,vm->pci_bus[0],20,vm->pci_io_space,0x4402,0x4403);
1386
1387 /* Initialize Network Modules */
1388 for(i=0;i<C3600_MAX_NM_BAYS;i++) {
1389 nm_bay = &router->nm_bay[i];
1390
1391 if (!nm_bay->dev_type)
1392 continue;
1393
1394 if (c3600_nm_init(router,i) == -1) {
1395 vm_error(vm,"unable to create Network Module \"%s\"\n",
1396 nm_bay->dev_type);
1397 return(-1);
1398 }
1399 }
1400
1401 /* Show device list */
1402 c3600_show_hardware(router);
1403 return(0);
1404 }
1405
1406 /* Boot the IOS image */
1407 int c3600_boot_ios(c3600_t *router)
1408 {
1409 vm_instance_t *vm = router->vm;
1410 cpu_mips_t *cpu;
1411
1412 if (!vm->boot_cpu)
1413 return(-1);
1414
1415 /* Suspend CPU activity since we will restart directly from ROM */
1416 vm_suspend(vm);
1417
1418 /* Check that CPU activity is really suspended */
1419 if (cpu_group_sync_state(vm->cpu_group) == -1) {
1420 vm_error(vm,"unable to sync with system CPUs.\n");
1421 return(-1);
1422 }
1423
1424 /* Reset the boot CPU */
1425 cpu = CPU_MIPS64(vm->boot_cpu);
1426 mips64_reset(cpu);
1427
1428 /* Load IOS image */
1429 if (mips64_load_elf_image(cpu,vm->ios_image,
1430 (vm->ghost_status == VM_GHOST_RAM_USE),
1431 &vm->ios_entry_point) < 0)
1432 {
1433 vm_error(vm,"failed to load Cisco IOS image '%s'.\n",vm->ios_image);
1434 return(-1);
1435 }
1436
1437 /* Launch the simulation */
1438 printf("\nC3600 '%s': starting simulation (CPU0 PC=0x%llx), "
1439 "JIT %sabled.\n",
1440 vm->name,cpu->pc,vm->jit_use ? "en":"dis");
1441
1442 vm_log(vm,"C3600_BOOT",
1443 "starting instance (CPU0 PC=0x%llx,idle_pc=0x%llx,JIT %s)\n",
1444 cpu->pc,cpu->idle_pc,vm->jit_use ? "on":"off");
1445
1446 /* Start main CPU */
1447 if (vm->ghost_status != VM_GHOST_RAM_GENERATE) {
1448 vm->status = VM_STATUS_RUNNING;
1449 cpu_start(vm->boot_cpu);
1450 } else {
1451 vm->status = VM_STATUS_SHUTDOWN;
1452 }
1453 return(0);
1454 }
1455
1456 /* Set an IRQ */
1457 static void c3600_set_irq(vm_instance_t *vm,u_int irq)
1458 {
1459 c3600_t *router = VM_C3600(vm);
1460 cpu_mips_t *cpu0 = CPU_MIPS64(vm->boot_cpu);
1461 u_int slot,port;
1462
1463 switch(irq) {
1464 case 0 ... 7:
1465 mips64_set_irq(cpu0,irq);
1466
1467 if (cpu0->irq_idle_preempt[irq])
1468 cpu_idle_break_wait(cpu0->gen);
1469 break;
1470
1471 case C3600_NETIO_IRQ_BASE ... C3600_NETIO_IRQ_END:
1472 c3600_net_irq_get_slot_port(irq,&slot,&port);
1473 dev_c3600_iofpga_net_set_irq(router->iofpga_data,slot,port);
1474 break;
1475 }
1476 }
1477
1478 /* Clear an IRQ */
1479 static void c3600_clear_irq(vm_instance_t *vm,u_int irq)
1480 {
1481 c3600_t *router = VM_C3600(vm);
1482 cpu_mips_t *cpu0 = CPU_MIPS64(vm->boot_cpu);
1483 u_int slot,port;
1484
1485 switch(irq) {
1486 case 0 ... 7:
1487 mips64_clear_irq(cpu0,irq);
1488 break;
1489
1490 case C3600_NETIO_IRQ_BASE ... C3600_NETIO_IRQ_END:
1491 c3600_net_irq_get_slot_port(irq,&slot,&port);
1492 dev_c3600_iofpga_net_clear_irq(router->iofpga_data,slot,port);
1493 break;
1494 }
1495 }
1496
1497 /* Initialize a Cisco 3600 instance */
1498 int c3600_init_instance(c3600_t *router)
1499 {
1500 vm_instance_t *vm = router->vm;
1501 m_uint32_t rom_entry_point;
1502 cpu_mips_t *cpu0;
1503
1504 if (!vm->ios_image) {
1505 vm_error(vm,"no Cisco IOS image defined.");
1506 return(-1);
1507 }
1508
1509 /* Initialize the C3600 platform */
1510 if (c3600_init_platform(router) == -1) {
1511 vm_error(vm,"unable to initialize the platform hardware.\n");
1512 return(-1);
1513 }
1514
1515 /* IRQ routing */
1516 vm->set_irq = c3600_set_irq;
1517 vm->clear_irq = c3600_clear_irq;
1518
1519 /* Load IOS configuration file */
1520 if (vm->ios_config != NULL) {
1521 vm_nvram_push_config(vm,vm->ios_config);
1522 vm->conf_reg &= ~0x40;
1523 }
1524
1525 /* Load ROM (ELF image or embedded) */
1526 cpu0 = CPU_MIPS64(vm->boot_cpu);
1527 rom_entry_point = (m_uint32_t)MIPS_ROM_PC;
1528
1529 if ((vm->rom_filename != NULL) &&
1530 (mips64_load_elf_image(cpu0,vm->rom_filename,0,&rom_entry_point) < 0))
1531 {
1532 vm_error(vm,"unable to load alternate ROM '%s', "
1533 "fallback to embedded ROM.\n\n",vm->rom_filename);
1534 vm->rom_filename = NULL;
1535 }
1536
1537 /* Load symbol file */
1538 if (vm->sym_filename) {
1539 mips64_sym_load_file(cpu0,vm->sym_filename);
1540 cpu0->sym_trace = 1;
1541 }
1542
1543 return(c3600_boot_ios(router));
1544 }
1545
1546 /* Stop a Cisco 3600 instance */
1547 int c3600_stop_instance(c3600_t *router)
1548 {
1549 vm_instance_t *vm = router->vm;
1550
1551 printf("\nC3600 '%s': stopping simulation.\n",vm->name);
1552 vm_log(vm,"C3600_STOP","stopping simulation.\n");
1553
1554 /* Stop all CPUs */
1555 if (vm->cpu_group != NULL) {
1556 vm_stop(vm);
1557
1558 if (cpu_group_sync_state(vm->cpu_group) == -1) {
1559 vm_error(vm,"unable to sync with system CPUs.\n");
1560 return(-1);
1561 }
1562 }
1563
1564 /* Free resources that were used during execution to emulate hardware */
1565 c3600_nm_shutdown_all(router);
1566 vm_hardware_shutdown(vm);
1567 return(0);
1568 }

  ViewVC Help
Powered by ViewVC 1.1.26