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

Contents of /upstream/dynamips-0.2.7-RC2/dev_c3745.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8 - (show annotations)
Sat Oct 6 16:24:54 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 39268 byte(s)
dynamips-0.2.7-RC2

1 /*
2 * Cisco 3745 simulation platform.
3 * Copyright (c) 2006 Christophe Fillot (cf@utc.fr)
4 *
5 * Generic Cisco 3745 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 "pci_io.h"
21 #include "dev_gt.h"
22 #include "cisco_eeprom.h"
23 #include "dev_rom.h"
24 #include "dev_c3745.h"
25 #include "dev_c3745_iofpga.h"
26 #include "dev_vtty.h"
27 #include "registry.h"
28
29 /* ======================================================================== */
30 /* EEPROM definitions */
31 /* ======================================================================== */
32
33 /* Cisco 3745 motherboard EEPROM */
34 static m_uint16_t eeprom_c3745_motherboard_data[] = {
35 0x04FF, 0xC18B, 0x5858, 0x5858, 0x5858, 0x5858, 0x5858, 0x5809,
36 0x6940, 0x02F7, 0xC046, 0x0320, 0x003E, 0x3E03, 0x4241, 0x3085,
37 0x1C12, 0x4004, 0x80FF, 0xFFFF, 0xFFC4, 0x08FF, 0xFFFF, 0xFFFF,
38 0xFFFF, 0xFF81, 0x0000, 0x0000, 0x0400, 0x0300, 0xC508, 0xFFFF,
39 0xFFFF, 0xFFFF, 0xFFFF, 0x4102, 0x0002, 0x04C2, 0x8B58, 0x5858,
40 0x5858, 0x5858, 0x5858, 0x5858, 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_c3745_motherboard = {
46 "C3745 Motherboard",
47 eeprom_c3745_motherboard_data,
48 sizeof(eeprom_c3745_motherboard_data)/2,
49 };
50
51 /* Cisco 3745 I/O board EEPROM */
52 static m_uint16_t eeprom_c3745_ioboard_data[] = {
53 0x04FF, 0x4002, 0xF841, 0x0200, 0xC046, 0x0320, 0x0038, 0x7E01,
54 0x4242, 0x3080, 0x0000, 0x0000, 0x0203, 0xC18B, 0x5858, 0x5858,
55 0x5858, 0x5858, 0x5858, 0x5803, 0x0081, 0x0000, 0x0000, 0x0400,
56 0xC809, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFC2, 0x8B58, 0x5858,
57 0x5858, 0x5858, 0x5858, 0x5858, 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_c3745_ioboard = {
64 "C3745 I/O board",
65 eeprom_c3745_ioboard_data,
66 sizeof(eeprom_c3745_ioboard_data)/2,
67 };
68
69 /* Cisco 3745 midplane EEPROM */
70 static m_uint16_t eeprom_c3745_midplane_data[] = {
71 0x04FF, 0x4003, 0x3E41, 0x0200, 0xC046, 0x0320, 0x0030, 0x0101,
72 0x4241, 0x3080, 0x0000, 0x0000, 0x0205, 0xC18B, 0x5858, 0x5858,
73 0x5858, 0x5858, 0x5858, 0x5803, 0x0081, 0x0000, 0x0000, 0x0400,
74 0xC809, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFC3, 0x0600, 0x0DED,
75 0xCD7D, 0x8043, 0x0050, 0xC28B, 0x5858, 0x5858, 0x5858, 0x5858,
76 0x5858, 0x58FF, 0xFFFF, 0xFFFF, 0xFFFF, 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_c3745_midplane = {
82 "C3745 Midplane",
83 eeprom_c3745_midplane_data,
84 sizeof(eeprom_c3745_midplane_data)/2,
85 };
86
87
88 /* ======================================================================== */
89 /* Network Module Drivers */
90 /* ======================================================================== */
91 static struct c3745_nm_driver *nm_drivers[] = {
92 &dev_c3745_nm_1fe_tx_driver,
93 &dev_c3745_nm_16esw_driver,
94 &dev_c3745_gt96100_fe_driver,
95 &dev_c3745_nm_4t_driver,
96 NULL,
97 };
98
99 /* ======================================================================== */
100 /* Cisco 3745 router instances */
101 /* ======================================================================== */
102
103 /* Directly extract the configuration from the NVRAM device */
104 ssize_t c3745_nvram_extract_config(vm_instance_t *vm,char **buffer)
105 {
106 u_char *base_ptr,*ios_ptr,*cfg_ptr,*end_ptr;
107 m_uint32_t start,nvlen;
108 m_uint16_t magic1,magic2;
109 struct vdevice *nvram_dev;
110 off_t nvram_size;
111 int fd;
112
113 if ((nvram_dev = dev_get_by_name(vm,"rom")))
114 dev_sync(nvram_dev);
115
116 fd = vm_mmap_open_file(vm,"rom",&base_ptr,&nvram_size);
117
118 if (fd == -1)
119 return(-1);
120
121 ios_ptr = base_ptr + C3745_NVRAM_OFFSET;
122 end_ptr = base_ptr + nvram_size;
123
124 if ((ios_ptr + 0x30) >= end_ptr) {
125 vm_error(vm,"NVRAM file too small\n");
126 return(-1);
127 }
128
129 magic1 = ntohs(*PTR_ADJUST(m_uint16_t *,ios_ptr,0x06));
130 magic2 = ntohs(*PTR_ADJUST(m_uint16_t *,ios_ptr,0x08));
131
132 if ((magic1 != 0xF0A5) || (magic2 != 0xABCD)) {
133 vm_error(vm,"unable to find IOS magic numbers (0x%x,0x%x)!\n",
134 magic1,magic2);
135 return(-1);
136 }
137
138 start = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x10)) + 1;
139 nvlen = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x18));
140
141 if (!(*buffer = malloc(nvlen+1))) {
142 vm_error(vm,"unable to allocate config buffer (%u bytes)\n",nvlen);
143 return(-1);
144 }
145
146 cfg_ptr = ios_ptr + start + 0x08;
147
148 if ((cfg_ptr + nvlen) > end_ptr) {
149 vm_error(vm,"NVRAM file too small\n");
150 return(-1);
151 }
152
153 memcpy(*buffer,cfg_ptr,nvlen-1);
154 (*buffer)[nvlen-1] = 0;
155 return(nvlen-1);
156 }
157
158 static int c3745_nvram_push_config_part(vm_instance_t *vm,
159 char *buffer,size_t len,
160 u_char *ios_ptr)
161 {
162 m_uint32_t cfg_offset,cklen,tmp;
163 m_uint16_t cksum;
164 u_char *cfg_ptr;
165
166 cfg_offset = 0x2c;
167 cfg_ptr = ios_ptr + cfg_offset;
168
169 /* Write IOS tag, uncompressed config... */
170 *PTR_ADJUST(m_uint16_t *,ios_ptr,0x06) = htons(0xF0A5);
171 *PTR_ADJUST(m_uint16_t *,ios_ptr,0x08) = htons(0xABCD);
172 *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0a) = htons(0x0001);
173 *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0c) = htons(0x0000);
174 *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0e) = htons(0x0c04);
175
176 /* Store file contents to NVRAM */
177 memcpy(cfg_ptr,buffer,len);
178
179 /* Write config addresses + size */
180 tmp = cfg_offset - 0x08;
181
182 *PTR_ADJUST(m_uint32_t *,ios_ptr,0x10) = htonl(tmp);
183 *PTR_ADJUST(m_uint32_t *,ios_ptr,0x14) = htonl(tmp + len);
184 *PTR_ADJUST(m_uint32_t *,ios_ptr,0x18) = htonl(len);
185
186 /* Compute the checksum */
187 cklen = C3745_NVRAM_SIZE - 0x08;
188 cksum = nvram_cksum((m_uint16_t *)(ios_ptr+0x08),cklen);
189 *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0c) = htons(cksum);
190 return(0);
191 }
192
193 /* Directly push the IOS configuration to the NVRAM device */
194 int c3745_nvram_push_config(vm_instance_t *vm,char *buffer,size_t len)
195 {
196 u_char *base_ptr,*ios_ptr;
197 int fd;
198
199 fd = vm_mmap_create_file(vm,"rom",vm->rom_size*1048576,&base_ptr);
200
201 if (fd == -1)
202 return(-1);
203
204 ios_ptr = base_ptr + C3745_NVRAM_OFFSET;
205
206 /* Normal config */
207 c3745_nvram_push_config_part(vm,buffer,len,ios_ptr);
208
209 /* Backup config */
210 c3745_nvram_push_config_part(vm,buffer,len,ios_ptr + C3745_NVRAM_SIZE);
211
212 vm_mmap_close_file(fd,base_ptr,vm->rom_size*1048576);
213 return(0);
214 }
215
216 /* Check for empty config */
217 int c3745_nvram_check_empty_config(vm_instance_t *vm)
218 {
219 struct vdevice *rom_dev;
220 m_uint64_t addr;
221 size_t len;
222
223 if (!(rom_dev = dev_get_by_name(vm,"rom")))
224 return(-1);
225
226 addr = rom_dev->phys_addr + C3745_NVRAM_OFFSET;
227 len = C3745_NVRAM_SIZE;
228
229 while(len > 0) {
230 if (physmem_copy_u32_from_vm(vm,addr) != 0)
231 return(0);
232
233 addr += sizeof(m_uint32_t);
234 len -= sizeof(m_uint32_t);
235 }
236
237 /* Empty NVRAM */
238 vm->conf_reg |= 0x0040;
239 printf("NVRAM is empty, setting config register to 0x%x\n",vm->conf_reg);
240 return(0);
241 }
242
243 /* Create a new router instance */
244 c3745_t *c3745_create_instance(char *name,int instance_id)
245 {
246 c3745_t *router;
247
248 if (!(router = malloc(sizeof(*router)))) {
249 fprintf(stderr,"C3745 '%s': Unable to create new instance!\n",name);
250 return NULL;
251 }
252
253 memset(router,0,sizeof(*router));
254
255 if (!(router->vm = vm_create(name,instance_id,VM_TYPE_C3745))) {
256 fprintf(stderr,"C3745 '%s': unable to create VM instance!\n",name);
257 goto err_vm;
258 }
259
260 c3745_init_defaults(router);
261 router->vm->hw_data = router;
262 return router;
263
264 err_vm:
265 free(router);
266 return NULL;
267 }
268
269 /* Free resources used by a router instance */
270 static int c3745_free_instance(void *data,void *arg)
271 {
272 vm_instance_t *vm = data;
273 c3745_t *router;
274 int i;
275
276 if (vm->type == VM_TYPE_C3745) {
277 router = VM_C3745(vm);
278
279 /* Stop all CPUs */
280 if (vm->cpu_group != NULL) {
281 vm_stop(vm);
282
283 if (cpu_group_sync_state(vm->cpu_group) == -1) {
284 vm_error(vm,"unable to sync with system CPUs.\n");
285 return(FALSE);
286 }
287 }
288
289 /* Remove NIO bindings */
290 for(i=0;i<C3745_MAX_NM_BAYS;i++)
291 c3745_nm_remove_all_nio_bindings(router,i);
292
293 /* Shutdown all Network Modules */
294 c3745_nm_shutdown_all(router);
295
296 /* Free mainboard EEPROM */
297 for(i=0;i<3;i++)
298 cisco_eeprom_free(&router->sys_eeprom[i]);
299
300 /* Free all resources used by VM */
301 vm_free(vm);
302
303 /* Free the router structure */
304 free(router);
305 return(TRUE);
306 }
307
308 return(FALSE);
309 }
310
311 /* Delete a router instance */
312 int c3745_delete_instance(char *name)
313 {
314 return(registry_delete_if_unused(name,OBJ_TYPE_VM,
315 c3745_free_instance,NULL));
316 }
317
318 /* Delete all router instances */
319 int c3745_delete_all_instances(void)
320 {
321 return(registry_delete_type(OBJ_TYPE_VM,c3745_free_instance,NULL));
322 }
323
324 /* Save configuration of a C3745 instance */
325 void c3745_save_config(c3745_t *router,FILE *fd)
326 {
327 vm_instance_t *vm = router->vm;
328 struct c3745_nio_binding *nb;
329 struct c3745_nm_bay *bay;
330 int i;
331
332 /* General settings */
333 fprintf(fd,"c3745 create %s %u\n",vm->name,vm->instance_id);
334
335 /* VM configuration */
336 vm_save_config(vm,fd);
337
338 /* Network Module settings */
339 for(i=0;i<C3745_MAX_NM_BAYS;i++) {
340 if (!(bay = c3745_nm_get_info(router,i)))
341 continue;
342
343 if (bay->dev_type) {
344 fprintf(fd,"c3745 add_nm_binding %s %u %s\n",
345 vm->name,i,bay->dev_type);
346 }
347
348 for(nb=bay->nio_list;nb;nb=nb->next) {
349 fprintf(fd,"c3745 add_nio_binding %s %u %u %s\n",
350 vm->name,i,nb->port_id,nb->nio->name);
351 }
352 }
353
354 fprintf(fd,"\n");
355 }
356
357 /* Save configurations of all C3745 instances */
358 static void c3745_reg_save_config(registry_entry_t *entry,void *opt,int *err)
359 {
360 vm_instance_t *vm = entry->data;
361 c3745_t *router = VM_C3745(vm);
362
363 if (vm->type == VM_TYPE_C3745)
364 c3745_save_config(router,(FILE *)opt);
365 }
366
367 void c3745_save_config_all(FILE *fd)
368 {
369 registry_foreach_type(OBJ_TYPE_VM,c3745_reg_save_config,fd,NULL);
370 }
371
372 /* Get slot/port corresponding to specified network IRQ */
373 static inline void
374 c3745_net_irq_get_slot_port(u_int irq,u_int *slot,u_int *port)
375 {
376 irq -= C3745_NETIO_IRQ_BASE;
377 *port = irq & C3745_NETIO_IRQ_PORT_MASK;
378 *slot = irq >> C3745_NETIO_IRQ_PORT_BITS;
379 }
380
381 /* Get network IRQ for specified slot/port */
382 u_int c3745_net_irq_for_slot_port(u_int slot,u_int port)
383 {
384 u_int irq;
385
386 irq = (slot << C3745_NETIO_IRQ_PORT_BITS) + port;
387 irq += C3745_NETIO_IRQ_BASE;
388
389 return(irq);
390 }
391
392 /* Set NM EEPROM definition */
393 int c3745_nm_set_eeprom(c3745_t *router,u_int nm_bay,
394 const struct cisco_eeprom *eeprom)
395 {
396 if (!nm_bay || (nm_bay >= C3745_MAX_NM_BAYS)) {
397 vm_error(router->vm,"c3745_nm_set_eeprom: invalid NM Bay %u.\n",nm_bay);
398 return(-1);
399 }
400
401 if (cisco_eeprom_copy(&router->nm_bay[nm_bay].eeprom,eeprom) == -1) {
402 vm_error(router->vm,"c3745_nm_set_eeprom: no memory.\n");
403 return(-1);
404 }
405
406 return(0);
407 }
408
409 /* Unset NM EEPROM definition (empty bay) */
410 int c3745_nm_unset_eeprom(c3745_t *router,u_int nm_bay)
411 {
412 if (!nm_bay || (nm_bay >= C3745_MAX_NM_BAYS)) {
413 vm_error(router->vm,"c3745_nm_set_eeprom: invalid NM Bay %u.\n",nm_bay);
414 return(-1);
415 }
416
417 cisco_eeprom_free(&router->nm_bay[nm_bay].eeprom);
418 return(0);
419 }
420
421 /* Check if a bay has a port adapter */
422 int c3745_nm_check_eeprom(c3745_t *router,u_int nm_bay)
423 {
424 if (!nm_bay || (nm_bay >= C3745_MAX_NM_BAYS))
425 return(FALSE);
426
427 return(cisco_eeprom_valid(&router->nm_bay[nm_bay].eeprom));
428 }
429
430 /* Get bay info */
431 struct c3745_nm_bay *c3745_nm_get_info(c3745_t *router,u_int nm_bay)
432 {
433 if (nm_bay >= C3745_MAX_NM_BAYS)
434 return NULL;
435
436 return(&router->nm_bay[nm_bay]);
437 }
438
439 /* Get NM type */
440 char *c3745_nm_get_type(c3745_t *router,u_int nm_bay)
441 {
442 struct c3745_nm_bay *bay;
443
444 bay = c3745_nm_get_info(router,nm_bay);
445 return((bay != NULL) ? bay->dev_type : NULL);
446 }
447
448 /* Get driver info about the specified slot */
449 void *c3745_nm_get_drvinfo(c3745_t *router,u_int nm_bay)
450 {
451 struct c3745_nm_bay *bay;
452
453 bay = c3745_nm_get_info(router,nm_bay);
454 return((bay != NULL) ? bay->drv_info : NULL);
455 }
456
457 /* Set driver info for the specified slot */
458 int c3745_nm_set_drvinfo(c3745_t *router,u_int nm_bay,void *drv_info)
459 {
460 struct c3745_nm_bay *bay;
461
462 if (!(bay = c3745_nm_get_info(router,nm_bay)))
463 return(-1);
464
465 bay->drv_info = drv_info;
466 return(0);
467 }
468
469 /* Get a NM driver */
470 static struct c3745_nm_driver *c3745_nm_get_driver(char *dev_type)
471 {
472 int i;
473
474 for(i=0;nm_drivers[i];i++)
475 if (!strcmp(nm_drivers[i]->dev_type,dev_type))
476 return nm_drivers[i];
477
478 return NULL;
479 }
480
481 /* Add a NM binding */
482 int c3745_nm_add_binding(c3745_t *router,char *dev_type,u_int nm_bay)
483 {
484 struct c3745_nm_driver *nm_driver;
485 struct c3745_nm_bay *bay;
486
487 if (!(bay = c3745_nm_get_info(router,nm_bay)))
488 return(-1);
489
490 /* check that this bay is empty */
491 if (bay->dev_type != NULL) {
492 vm_error(router->vm,"a NM already exists in slot %u.\n",nm_bay);
493 return(-1);
494 }
495
496 /* find the NM driver */
497 if (!(nm_driver = c3745_nm_get_driver(dev_type))) {
498 vm_error(router->vm,"unknown NM type '%s'.\n",dev_type);
499 return(-1);
500 }
501
502 bay->dev_type = nm_driver->dev_type;
503 bay->nm_driver = nm_driver;
504 return(0);
505 }
506
507 /* Remove a NM binding */
508 int c3745_nm_remove_binding(c3745_t *router,u_int nm_bay)
509 {
510 struct c3745_nm_bay *bay;
511
512 if (!(bay = c3745_nm_get_info(router,nm_bay)))
513 return(-1);
514
515 /* stop if this bay is still active */
516 if (bay->drv_info != NULL) {
517 vm_error(router->vm,"slot %u still active.\n",nm_bay);
518 return(-1);
519 }
520
521 /* check that this bay is not empty */
522 if (bay->dev_type == NULL) {
523 vm_error(router->vm,"slot %u is empty.\n",nm_bay);
524 return(-1);
525 }
526
527 /* remove all NIOs bindings */
528 c3745_nm_remove_all_nio_bindings(router,nm_bay);
529
530 bay->dev_type = NULL;
531 bay->nm_driver = NULL;
532 return(0);
533 }
534
535 /* Find a NIO binding */
536 struct c3745_nio_binding *
537 c3745_nm_find_nio_binding(c3745_t *router,u_int nm_bay,u_int port_id)
538 {
539 struct c3745_nio_binding *nb;
540 struct c3745_nm_bay *bay;
541
542 if (!(bay = c3745_nm_get_info(router,nm_bay)))
543 return NULL;
544
545 for(nb=bay->nio_list;nb;nb=nb->next)
546 if (nb->port_id == port_id)
547 return nb;
548
549 return NULL;
550 }
551
552 /* Add a network IO binding */
553 int c3745_nm_add_nio_binding(c3745_t *router,u_int nm_bay,u_int port_id,
554 char *nio_name)
555 {
556 struct c3745_nio_binding *nb;
557 struct c3745_nm_bay *bay;
558 netio_desc_t *nio;
559
560 if (!(bay = c3745_nm_get_info(router,nm_bay)))
561 return(-1);
562
563 /* check that a NIO is not already bound to this port */
564 if (c3745_nm_find_nio_binding(router,nm_bay,port_id) != NULL) {
565 vm_error(router->vm,"a NIO already exists for interface %u/%u.\n",
566 nm_bay,port_id);
567 return(-1);
568 }
569
570 /* acquire a reference on the NIO object */
571 if (!(nio = netio_acquire(nio_name))) {
572 vm_error(router->vm,"unable to find NIO '%s'.\n",nio_name);
573 return(-1);
574 }
575
576 /* create a new binding */
577 if (!(nb = malloc(sizeof(*nb)))) {
578 vm_error(router->vm,"unable to create NIO binding "
579 "for interface %u/%u.\n",nm_bay,port_id);
580 netio_release(nio_name);
581 return(-1);
582 }
583
584 memset(nb,0,sizeof(*nb));
585 nb->nio = nio;
586 nb->port_id = port_id;
587 nb->next = bay->nio_list;
588 if (nb->next) nb->next->prev = nb;
589 bay->nio_list = nb;
590 return(0);
591 }
592
593 /* Remove a NIO binding */
594 int c3745_nm_remove_nio_binding(c3745_t *router,u_int nm_bay,u_int port_id)
595 {
596 struct c3745_nio_binding *nb;
597 struct c3745_nm_bay *bay;
598
599 if (!(bay = c3745_nm_get_info(router,nm_bay)))
600 return(-1);
601
602 if (!(nb = c3745_nm_find_nio_binding(router,nm_bay,port_id)))
603 return(-1); /* no nio binding for this slot/port */
604
605 /* tell the NM driver to stop using this NIO */
606 if (bay->nm_driver)
607 bay->nm_driver->nm_unset_nio(router,nm_bay,port_id);
608
609 /* remove this entry from the double linked list */
610 if (nb->next)
611 nb->next->prev = nb->prev;
612
613 if (nb->prev) {
614 nb->prev->next = nb->next;
615 } else {
616 bay->nio_list = nb->next;
617 }
618
619 /* unreference NIO object */
620 netio_release(nb->nio->name);
621 free(nb);
622 return(0);
623 }
624
625 /* Remove all NIO bindings for the specified NM */
626 int c3745_nm_remove_all_nio_bindings(c3745_t *router,u_int nm_bay)
627 {
628 struct c3745_nio_binding *nb,*next;
629 struct c3745_nm_bay *bay;
630
631 if (!(bay = c3745_nm_get_info(router,nm_bay)))
632 return(-1);
633
634 for(nb=bay->nio_list;nb;nb=next) {
635 next = nb->next;
636
637 /* tell the NM driver to stop using this NIO */
638 if (bay->nm_driver)
639 bay->nm_driver->nm_unset_nio(router,nm_bay,nb->port_id);
640
641 /* unreference NIO object */
642 netio_release(nb->nio->name);
643 free(nb);
644 }
645
646 bay->nio_list = NULL;
647 return(0);
648 }
649
650 /* Enable a Network IO descriptor for a Network Module */
651 int c3745_nm_enable_nio(c3745_t *router,u_int nm_bay,u_int port_id)
652 {
653 struct c3745_nio_binding *nb;
654 struct c3745_nm_bay *bay;
655
656 if (!(bay = c3745_nm_get_info(router,nm_bay)))
657 return(-1);
658
659 /* check that we have an NIO binding for this interface */
660 if (!(nb = c3745_nm_find_nio_binding(router,nm_bay,port_id)))
661 return(-1);
662
663 /* check that the driver is defined and successfully initialized */
664 if (!bay->nm_driver || !bay->drv_info)
665 return(-1);
666
667 return(bay->nm_driver->nm_set_nio(router,nm_bay,port_id,nb->nio));
668 }
669
670 /* Disable Network IO descriptor of a Network Module */
671 int c3745_nm_disable_nio(c3745_t *router,u_int nm_bay,u_int port_id)
672 {
673 struct c3745_nm_bay *bay;
674
675 if (!(bay = c3745_nm_get_info(router,nm_bay)))
676 return(-1);
677
678 /* check that the driver is defined and successfully initialized */
679 if (!bay->nm_driver || !bay->drv_info)
680 return(-1);
681
682 return(bay->nm_driver->nm_unset_nio(router,nm_bay,port_id));
683 }
684
685 /* Enable all NIO of the specified NM */
686 int c3745_nm_enable_all_nio(c3745_t *router,u_int nm_bay)
687 {
688 struct c3745_nio_binding *nb;
689 struct c3745_nm_bay *bay;
690
691 if (!(bay = c3745_nm_get_info(router,nm_bay)))
692 return(-1);
693
694 /* check that the driver is defined and successfully initialized */
695 if (!bay->nm_driver || !bay->drv_info)
696 return(-1);
697
698 for(nb=bay->nio_list;nb;nb=nb->next)
699 bay->nm_driver->nm_set_nio(router,nm_bay,nb->port_id,nb->nio);
700
701 return(0);
702 }
703
704 /* Disable all NIO of the specified NM */
705 int c3745_nm_disable_all_nio(c3745_t *router,u_int nm_bay)
706 {
707 struct c3745_nio_binding *nb;
708 struct c3745_nm_bay *bay;
709
710 if (!(bay = c3745_nm_get_info(router,nm_bay)))
711 return(-1);
712
713 /* check that the driver is defined and successfully initialized */
714 if (!bay->nm_driver || !bay->drv_info)
715 return(-1);
716
717 for(nb=bay->nio_list;nb;nb=nb->next)
718 bay->nm_driver->nm_unset_nio(router,nm_bay,nb->port_id);
719
720 return(0);
721 }
722
723 /* Initialize a Network Module */
724 int c3745_nm_init(c3745_t *router,u_int nm_bay)
725 {
726 struct c3745_nm_bay *bay;
727 size_t len;
728
729 if (!(bay = c3745_nm_get_info(router,nm_bay)))
730 return(-1);
731
732 /* Check that a device type is defined for this bay */
733 if (!bay->dev_type || !bay->nm_driver) {
734 vm_error(router->vm,"trying to init empty slot %u.\n",nm_bay);
735 return(-1);
736 }
737
738 /* Allocate device name */
739 len = strlen(bay->dev_type) + 10;
740 if (!(bay->dev_name = malloc(len))) {
741 vm_error(router->vm,"unable to allocate device name.\n");
742 return(-1);
743 }
744
745 snprintf(bay->dev_name,len,"%s(%u)",bay->dev_type,nm_bay);
746
747 /* Initialize NM driver */
748 if (bay->nm_driver->nm_init(router,bay->dev_name,nm_bay) == -1) {
749 vm_error(router->vm,"unable to initialize NM %u.\n",nm_bay);
750 return(-1);
751 }
752
753 /* Enable all NIO */
754 c3745_nm_enable_all_nio(router,nm_bay);
755 return(0);
756 }
757
758 /* Shutdown a Network Module */
759 int c3745_nm_shutdown(c3745_t *router,u_int nm_bay)
760 {
761 struct c3745_nm_bay *bay;
762
763 if (!(bay = c3745_nm_get_info(router,nm_bay)))
764 return(-1);
765
766 /* Check that a device type is defined for this bay */
767 if (!bay->dev_type || !bay->nm_driver) {
768 vm_error(router->vm,"trying to shut down empty slot %u.\n",nm_bay);
769 return(-1);
770 }
771
772 /* Disable all NIO */
773 c3745_nm_disable_all_nio(router,nm_bay);
774
775 /* Shutdown the NM driver */
776 if (bay->drv_info && (bay->nm_driver->nm_shutdown(router,nm_bay) == -1)) {
777 vm_error(router->vm,"unable to shutdown NM %u.\n",nm_bay);
778 return(-1);
779 }
780
781 free(bay->dev_name);
782 bay->dev_name = NULL;
783 bay->drv_info = NULL;
784 return(0);
785 }
786
787 /* Shutdown all NM of a router */
788 int c3745_nm_shutdown_all(c3745_t *router)
789 {
790 int i;
791
792 for(i=0;i<C3745_MAX_NM_BAYS;i++) {
793 if (!router->nm_bay[i].dev_type)
794 continue;
795
796 c3745_nm_shutdown(router,i);
797 }
798
799 return(0);
800 }
801
802 /* Show info about all NMs */
803 int c3745_nm_show_all_info(c3745_t *router)
804 {
805 struct c3745_nm_bay *bay;
806 int i;
807
808 for(i=0;i<C3745_MAX_NM_BAYS;i++) {
809 if (!(bay = c3745_nm_get_info(router,i)) || !bay->nm_driver)
810 continue;
811
812 if (bay->nm_driver->nm_show_info != NULL)
813 bay->nm_driver->nm_show_info(router,i);
814 }
815
816 return(0);
817 }
818
819 /* Maximum number of tokens in a NM description */
820 #define NM_DESC_MAX_TOKENS 8
821
822 /* Create a Network Module (command line) */
823 int c3745_cmd_nm_create(c3745_t *router,char *str)
824 {
825 char *tokens[NM_DESC_MAX_TOKENS];
826 int i,count,res;
827 u_int nm_bay;
828
829 /* A port adapter description is like "1:NM-1FE" */
830 if ((count = m_strsplit(str,':',tokens,NM_DESC_MAX_TOKENS)) != 2) {
831 vm_error(router->vm,"unable to parse NM description '%s'.\n",str);
832 return(-1);
833 }
834
835 /* Parse the NM bay id */
836 nm_bay = atoi(tokens[0]);
837
838 /* Add this new NM to the current NM list */
839 res = c3745_nm_add_binding(router,tokens[1],nm_bay);
840
841 /* The complete array was cleaned by strsplit */
842 for(i=0;i<NM_DESC_MAX_TOKENS;i++)
843 free(tokens[i]);
844
845 return(res);
846 }
847
848 /* Add a Network IO descriptor binding (command line) */
849 int c3745_cmd_add_nio(c3745_t *router,char *str)
850 {
851 char *tokens[NM_DESC_MAX_TOKENS];
852 int i,count,nio_type,res=-1;
853 u_int nm_bay,port_id;
854 netio_desc_t *nio;
855 char nio_name[128];
856
857 /* A port adapter description is like "1:3:tap:tap0" */
858 if ((count = m_strsplit(str,':',tokens,NM_DESC_MAX_TOKENS)) < 3) {
859 vm_error(router->vm,"unable to parse NIO description '%s'.\n",str);
860 return(-1);
861 }
862
863 /* Parse the NM bay */
864 nm_bay = atoi(tokens[0]);
865
866 /* Parse the NM port id */
867 port_id = atoi(tokens[1]);
868
869 /* Autogenerate a NIO name */
870 snprintf(nio_name,sizeof(nio_name),"c3745-i%u/%u/%u",
871 router->vm->instance_id,nm_bay,port_id);
872
873 /* Create the Network IO descriptor */
874 nio = NULL;
875 nio_type = netio_get_type(tokens[2]);
876
877 switch(nio_type) {
878 case NETIO_TYPE_UNIX:
879 if (count != 5) {
880 vm_error(router->vm,
881 "invalid number of arguments for UNIX NIO '%s'\n",str);
882 goto done;
883 }
884
885 nio = netio_desc_create_unix(nio_name,tokens[3],tokens[4]);
886 break;
887
888 case NETIO_TYPE_VDE:
889 if (count != 5) {
890 vm_error(router->vm,
891 "invalid number of arguments for VDE NIO '%s'\n",str);
892 goto done;
893 }
894
895 nio = netio_desc_create_vde(nio_name,tokens[3],tokens[4]);
896 break;
897
898 case NETIO_TYPE_TAP:
899 if (count != 4) {
900 vm_error(router->vm,
901 "invalid number of arguments for TAP NIO '%s'\n",str);
902 goto done;
903 }
904
905 nio = netio_desc_create_tap(nio_name,tokens[3]);
906 break;
907
908 case NETIO_TYPE_UDP:
909 if (count != 6) {
910 vm_error(router->vm,
911 "invalid number of arguments for UDP NIO '%s'\n",str);
912 goto done;
913 }
914
915 nio = netio_desc_create_udp(nio_name,atoi(tokens[3]),
916 tokens[4],atoi(tokens[5]));
917 break;
918
919 case NETIO_TYPE_TCP_CLI:
920 if (count != 5) {
921 vm_error(router->vm,
922 "invalid number of arguments for TCP CLI NIO '%s'\n",str);
923 goto done;
924 }
925
926 nio = netio_desc_create_tcp_cli(nio_name,tokens[3],tokens[4]);
927 break;
928
929 case NETIO_TYPE_TCP_SER:
930 if (count != 4) {
931 vm_error(router->vm,
932 "invalid number of arguments for TCP SER NIO '%s'\n",str);
933 goto done;
934 }
935
936 nio = netio_desc_create_tcp_ser(nio_name,tokens[3]);
937 break;
938
939 case NETIO_TYPE_NULL:
940 nio = netio_desc_create_null(nio_name);
941 break;
942
943 #ifdef LINUX_ETH
944 case NETIO_TYPE_LINUX_ETH:
945 if (count != 4) {
946 vm_error(router->vm,
947 "invalid number of arguments for Linux Eth NIO '%s'\n",
948 str);
949 goto done;
950 }
951
952 nio = netio_desc_create_lnxeth(nio_name,tokens[3]);
953 break;
954 #endif
955
956 #ifdef GEN_ETH
957 case NETIO_TYPE_GEN_ETH:
958 if (count != 4) {
959 vm_error(router->vm,
960 "invalid number of arguments for Generic Eth NIO '%s'\n",
961 str);
962 goto done;
963 }
964
965 nio = netio_desc_create_geneth(nio_name,tokens[3]);
966 break;
967 #endif
968
969 default:
970 vm_error(router->vm,"unknown NETIO type '%s'\n",tokens[2]);
971 goto done;
972 }
973
974 if (!nio) {
975 vm_error(router->vm,"unable to create NETIO "
976 "descriptor for NM slot %u\n",nm_bay);
977 goto done;
978 }
979
980 if (c3745_nm_add_nio_binding(router,nm_bay,port_id,nio_name) == -1) {
981 vm_error(router->vm,"unable to add NETIO binding for slot %u\n",nm_bay);
982 netio_release(nio_name);
983 netio_delete(nio_name);
984 goto done;
985 }
986
987 netio_release(nio_name);
988 res = 0;
989
990 done:
991 /* The complete array was cleaned by strsplit */
992 for(i=0;i<NM_DESC_MAX_TOKENS;i++)
993 free(tokens[i]);
994
995 return(res);
996 }
997
998 /* Show the list of available NM drivers */
999 void c3745_nm_show_drivers(void)
1000 {
1001 int i;
1002
1003 printf("Available C3745 Network Module drivers:\n");
1004
1005 for(i=0;nm_drivers[i];i++) {
1006 printf(" * %s %s\n",
1007 nm_drivers[i]->dev_type,
1008 !nm_drivers[i]->supported ? "(NOT WORKING)" : "");
1009 }
1010
1011 printf("\n");
1012 }
1013
1014 /* Set the base MAC address of the chassis */
1015 static int c3745_burn_mac_addr(c3745_t *router,n_eth_addr_t *addr)
1016 {
1017 m_uint8_t eeprom_ver;
1018 size_t offset;
1019
1020 /* Read EEPROM format version */
1021 cisco_eeprom_get_byte(&router->sys_eeprom[2],0,&eeprom_ver);
1022
1023 switch(eeprom_ver) {
1024 case 0:
1025 cisco_eeprom_set_region(&router->sys_eeprom[2],2,
1026 addr->eth_addr_byte,6);
1027 break;
1028
1029 case 4:
1030 if (!cisco_eeprom_v4_find_field(&router->sys_eeprom[2],
1031 0xC3,&offset)) {
1032 cisco_eeprom_set_region(&router->sys_eeprom[2],offset,
1033 addr->eth_addr_byte,6);
1034 }
1035 break;
1036
1037 default:
1038 vm_error(router->vm,"c3745_burn_mac_addr: unable to handle "
1039 "EEPROM version %u\n",eeprom_ver);
1040 return(-1);
1041 }
1042
1043 return(0);
1044 }
1045
1046 /* Set chassis MAC address */
1047 int c3745_chassis_set_mac_addr(c3745_t *router,char *mac_addr)
1048 {
1049 if (parse_mac_addr(&router->mac_addr,mac_addr) == -1) {
1050 vm_error(router->vm,"unable to parse MAC address '%s'.\n",mac_addr);
1051 return(-1);
1052 }
1053
1054 /* Set the chassis base MAC address */
1055 c3745_burn_mac_addr(router,&router->mac_addr);
1056 return(0);
1057 }
1058
1059 /* Create the two main PCI busses for a GT64120 based system */
1060 static int c3745_init_gt96100(c3745_t *router)
1061 {
1062 vm_instance_t *vm = router->vm;
1063
1064 vm->pci_bus[0] = pci_bus_create("PCI bus #0",0);
1065 vm->pci_bus[1] = pci_bus_create("PCI bus #1",0);
1066
1067 if (!vm->pci_bus[0] || !vm->pci_bus[1]) {
1068 vm_error(router->vm,"unable to create PCI data.\n");
1069 return(-1);
1070 }
1071
1072 return(dev_gt96100_init(vm,"gt96100",C3745_GT96K_ADDR,0x200000,
1073 C3745_GT96K_IRQ,c3745_net_irq_for_slot_port(0,0)));
1074 }
1075
1076 /* Initialize a Cisco 3745 */
1077 static int c3745_init(c3745_t *router)
1078 {
1079 vm_instance_t *vm = router->vm;
1080 char bus_name[128];
1081 int i;
1082
1083 /* Set the processor type: R7000 */
1084 mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R7000);
1085
1086 /* Initialize the Galileo GT-96100 PCI controller */
1087 if (c3745_init_gt96100(router) == -1)
1088 return(-1);
1089
1090 /* Create the NM PCI busses for slots 1-4 */
1091 for(i=1;i<=4;i++) {
1092 snprintf(bus_name,sizeof(bus_name),"NM Slot %d",i);
1093 vm->pci_bus_pool[i] = pci_bus_create(bus_name,-1);
1094
1095 /* Map the NM PCI bus */
1096 router->nm_bay[i].pci_map = vm->pci_bus_pool[i];
1097
1098 /* Create the PCI bridge */
1099 dev_ti2050b_init(vm->pci_bus[1],i,router->nm_bay[i].pci_map);
1100 }
1101
1102 vm->elf_machine_id = C3745_ELF_MACHINE_ID;
1103 return(0);
1104 }
1105
1106 /* Show C3745 hardware info */
1107 void c3745_show_hardware(c3745_t *router)
1108 {
1109 vm_instance_t *vm = router->vm;
1110
1111 printf("C3745 instance '%s' (id %d):\n",vm->name,vm->instance_id);
1112
1113 printf(" VM Status : %d\n",vm->status);
1114 printf(" RAM size : %u Mb\n",vm->ram_size);
1115 printf(" NVRAM size : %u Kb\n",vm->nvram_size);
1116 printf(" IOS image : %s\n\n",vm->ios_image);
1117
1118 if (vm->debug_level > 0) {
1119 dev_show_list(vm);
1120 pci_dev_show_list(vm->pci_bus[0]);
1121 pci_dev_show_list(vm->pci_bus[1]);
1122 printf("\n");
1123 }
1124 }
1125
1126 /* Initialize default parameters for a C3745 */
1127 void c3745_init_defaults(c3745_t *router)
1128 {
1129 vm_instance_t *vm = router->vm;
1130 n_eth_addr_t *m;
1131 m_uint16_t pid;
1132
1133 pid = (m_uint16_t)getpid();
1134
1135 /* Generate a chassis MAC address based on the instance ID */
1136 m = &router->mac_addr;
1137 m->eth_addr_byte[0] = vm_get_mac_addr_msb(vm);
1138 m->eth_addr_byte[1] = vm->instance_id & 0xFF;
1139 m->eth_addr_byte[2] = pid >> 8;
1140 m->eth_addr_byte[3] = pid & 0xFF;
1141 m->eth_addr_byte[4] = 0x00;
1142 m->eth_addr_byte[5] = 0x00;
1143
1144 c3745_init_eeprom_groups(router);
1145 cisco_eeprom_copy(&router->sys_eeprom[0],&eeprom_c3745_motherboard);
1146 cisco_eeprom_copy(&router->sys_eeprom[1],&eeprom_c3745_ioboard);
1147 cisco_eeprom_copy(&router->sys_eeprom[2],&eeprom_c3745_midplane);
1148
1149 c3745_burn_mac_addr(router,&router->mac_addr);
1150
1151 vm->ram_mmap = C3745_DEFAULT_RAM_MMAP;
1152 vm->ram_size = C3745_DEFAULT_RAM_SIZE;
1153 vm->rom_size = C3745_DEFAULT_ROM_SIZE;
1154 vm->nvram_size = C3745_DEFAULT_NVRAM_SIZE;
1155 vm->conf_reg_setup = C3745_DEFAULT_CONF_REG;
1156 vm->clock_divisor = C3745_DEFAULT_CLOCK_DIV;
1157 vm->nvram_rom_space = C3745_NVRAM_ROM_RES_SIZE;
1158 router->nm_iomem_size = C3745_DEFAULT_IOMEM_SIZE;
1159
1160 vm->pcmcia_disk_size[0] = C3745_DEFAULT_DISK0_SIZE;
1161 vm->pcmcia_disk_size[1] = C3745_DEFAULT_DISK1_SIZE;
1162
1163 /* Enable NVRAM operations to load/store configs */
1164 vm->nvram_extract_config = c3745_nvram_extract_config;
1165 vm->nvram_push_config = c3745_nvram_push_config;
1166 }
1167
1168 /* Initialize the C3745 Platform */
1169 int c3745_init_platform(c3745_t *router)
1170 {
1171 vm_instance_t *vm = router->vm;
1172 struct c3745_nm_bay *nm_bay;
1173 cpu_mips_t *cpu;
1174 cpu_gen_t *gen;
1175 vm_obj_t *obj;
1176 int i;
1177
1178 /* Copy config register setup into "active" config register */
1179 vm->conf_reg = vm->conf_reg_setup;
1180
1181 /* Create Console and AUX ports */
1182 vm_init_vtty(vm);
1183
1184 /* Create a CPU group */
1185 vm->cpu_group = cpu_group_create("System CPU");
1186
1187 /* Initialize the virtual MIPS processor */
1188 if (!(gen = cpu_create(vm,CPU_TYPE_MIPS64,0))) {
1189 vm_error(vm,"unable to create CPU!\n");
1190 return(-1);
1191 }
1192
1193 cpu = CPU_MIPS64(gen);
1194
1195 /* Add this CPU to the system CPU group */
1196 cpu_group_add(vm->cpu_group,gen);
1197 vm->boot_cpu = gen;
1198
1199 /* Initialize the IRQ routing vectors */
1200 vm->set_irq = mips64_vm_set_irq;
1201 vm->clear_irq = mips64_vm_clear_irq;
1202
1203 /* Mark the Network IO interrupt as high priority */
1204 cpu->irq_idle_preempt[C3745_NETIO_IRQ] = TRUE;
1205 cpu->irq_idle_preempt[C3745_GT96K_IRQ] = TRUE;
1206 cpu->irq_idle_preempt[C3745_DUART_IRQ] = TRUE;
1207
1208 /* Copy some parameters from VM to CPU (idle PC, ...) */
1209 cpu->idle_pc = vm->idle_pc;
1210
1211 if (vm->timer_irq_check_itv)
1212 cpu->timer_irq_check_itv = vm->timer_irq_check_itv;
1213
1214 /* Remote emulator control */
1215 dev_remote_control_init(vm,0x16000000,0x1000);
1216
1217 /* Specific Storage Area (SSA) */
1218 dev_ram_init(vm,"ssa",TRUE,FALSE,NULL,FALSE,0x16001000ULL,0x7000);
1219
1220 /* IO FPGA */
1221 if (dev_c3745_iofpga_init(router,C3745_IOFPGA_ADDR,0x200000) == -1)
1222 return(-1);
1223
1224 if (!(obj = vm_object_find(router->vm,"io_fpga")))
1225 return(-1);
1226
1227 router->iofpga_data = obj->data;
1228
1229 #if 0
1230 /* PCI IO space */
1231 if (!(vm->pci_io_space = pci_io_data_init(vm,C3745_PCI_IO_ADDR)))
1232 return(-1);
1233 #endif
1234
1235 /* Initialize the chassis */
1236 if (c3745_init(router) == -1)
1237 return(-1);
1238
1239 /* Initialize RAM */
1240 vm_ram_init(vm,0x00000000ULL);
1241
1242 /* Initialize ROM (as a Flash) */
1243 if (!(obj = dev_flash_init(vm,"rom",C3745_ROM_ADDR,vm->rom_size*1048576)))
1244 return(-1);
1245
1246 dev_flash_copy_data(obj,0,mips64_microcode,mips64_microcode_len);
1247 c3745_nvram_check_empty_config(vm);
1248
1249 /* Initialize the NS16552 DUART */
1250 dev_ns16552_init(vm,C3745_DUART_ADDR,0x1000,3,C3745_DUART_IRQ,
1251 vm->vtty_con,vm->vtty_aux);
1252
1253 /* PCMCIA Slot 0 */
1254 dev_pcmcia_disk_init(vm,"slot0",C3745_SLOT0_ADDR,0x200000,
1255 vm->pcmcia_disk_size[0],1);
1256
1257 /* PCMCIA Slot 1 */
1258 dev_pcmcia_disk_init(vm,"slot1",C3745_SLOT1_ADDR,0x200000,
1259 vm->pcmcia_disk_size[1],1);
1260
1261 /* The GT96100 system controller has 2 integrated FastEthernet ports */
1262 c3745_nm_add_binding(router,"GT96100-FE",0);
1263
1264 /* Initialize Network Modules */
1265 for(i=0;i<C3745_MAX_NM_BAYS;i++) {
1266 nm_bay = &router->nm_bay[i];
1267
1268 if (!nm_bay->dev_type)
1269 continue;
1270
1271 if (c3745_nm_init(router,i) == -1) {
1272 vm_error(vm,"unable to create Network Module \"%s\"\n",
1273 nm_bay->dev_type);
1274 return(-1);
1275 }
1276 }
1277
1278 /* Show device list */
1279 c3745_show_hardware(router);
1280 return(0);
1281 }
1282
1283 /* Boot the IOS image */
1284 int c3745_boot_ios(c3745_t *router)
1285 {
1286 vm_instance_t *vm = router->vm;
1287 cpu_mips_t *cpu;
1288
1289 if (!vm->boot_cpu)
1290 return(-1);
1291
1292 /* Suspend CPU activity since we will restart directly from ROM */
1293 vm_suspend(vm);
1294
1295 /* Check that CPU activity is really suspended */
1296 if (cpu_group_sync_state(vm->cpu_group) == -1) {
1297 vm_error(vm,"unable to sync with system CPUs.\n");
1298 return(-1);
1299 }
1300
1301 /* Reset the boot CPU */
1302 cpu = CPU_MIPS64(vm->boot_cpu);
1303 mips64_reset(cpu);
1304
1305 /* Load IOS image */
1306 if (mips64_load_elf_image(cpu,vm->ios_image,
1307 (vm->ghost_status == VM_GHOST_RAM_USE),
1308 &vm->ios_entry_point) < 0)
1309 {
1310 vm_error(vm,"failed to load Cisco IOS image '%s'.\n",vm->ios_image);
1311 return(-1);
1312 }
1313
1314 /* Launch the simulation */
1315 printf("\nC3745 '%s': starting simulation (CPU0 PC=0x%llx), "
1316 "JIT %sabled.\n",
1317 vm->name,cpu->pc,vm->jit_use ? "en":"dis");
1318
1319 vm_log(vm,"C3745_BOOT",
1320 "starting instance (CPU0 PC=0x%llx,idle_pc=0x%llx,JIT %s)\n",
1321 cpu->pc,cpu->idle_pc,vm->jit_use ? "on":"off");
1322
1323 /* Start main CPU */
1324 if (vm->ghost_status != VM_GHOST_RAM_GENERATE) {
1325 vm->status = VM_STATUS_RUNNING;
1326 cpu_start(vm->boot_cpu);
1327 } else {
1328 vm->status = VM_STATUS_SHUTDOWN;
1329 }
1330 return(0);
1331 }
1332
1333 /* Set an IRQ */
1334 static void c3745_set_irq(vm_instance_t *vm,u_int irq)
1335 {
1336 c3745_t *router = VM_C3745(vm);
1337 cpu_mips_t *cpu0 = CPU_MIPS64(vm->boot_cpu);
1338 u_int slot,port;
1339
1340 switch(irq) {
1341 case 0 ... 7:
1342 mips64_set_irq(cpu0,irq);
1343
1344 if (cpu0->irq_idle_preempt[irq])
1345 cpu_idle_break_wait(cpu0->gen);
1346 break;
1347
1348 case C3745_NETIO_IRQ_BASE ... C3745_NETIO_IRQ_END:
1349 c3745_net_irq_get_slot_port(irq,&slot,&port);
1350 dev_c3745_iofpga_net_set_irq(router->iofpga_data,slot,port);
1351 break;
1352 }
1353 }
1354
1355 /* Clear an IRQ */
1356 static void c3745_clear_irq(vm_instance_t *vm,u_int irq)
1357 {
1358 c3745_t *router = VM_C3745(vm);
1359 cpu_mips_t *cpu0 = CPU_MIPS64(vm->boot_cpu);
1360 u_int slot,port;
1361
1362 switch(irq) {
1363 case 0 ... 7:
1364 mips64_clear_irq(cpu0,irq);
1365 break;
1366
1367 case C3745_NETIO_IRQ_BASE ... C3745_NETIO_IRQ_END:
1368 c3745_net_irq_get_slot_port(irq,&slot,&port);
1369 dev_c3745_iofpga_net_clear_irq(router->iofpga_data,slot,port);
1370 break;
1371 }
1372 }
1373
1374 /* Initialize a Cisco 3745 instance */
1375 int c3745_init_instance(c3745_t *router)
1376 {
1377 vm_instance_t *vm = router->vm;
1378 m_uint32_t rom_entry_point;
1379 cpu_mips_t *cpu0;
1380
1381 if (!vm->ios_image) {
1382 vm_error(vm,"no Cisco IOS image defined.");
1383 return(-1);
1384 }
1385
1386 /* Initialize the C3745 platform */
1387 if (c3745_init_platform(router) == -1) {
1388 vm_error(vm,"unable to initialize the platform hardware.\n");
1389 return(-1);
1390 }
1391
1392 /* IRQ routing */
1393 vm->set_irq = c3745_set_irq;
1394 vm->clear_irq = c3745_clear_irq;
1395
1396 /* Load IOS configuration file */
1397 if (vm->ios_config != NULL) {
1398 vm_nvram_push_config(vm,vm->ios_config);
1399 vm->conf_reg &= ~0x40;
1400 }
1401
1402 /* Load ROM (ELF image or embedded) */
1403 cpu0 = CPU_MIPS64(vm->boot_cpu);
1404 rom_entry_point = (m_uint32_t)MIPS_ROM_PC;
1405
1406 if ((vm->rom_filename != NULL) &&
1407 (mips64_load_elf_image(cpu0,vm->rom_filename,0,&rom_entry_point) < 0))
1408 {
1409 vm_error(vm,"unable to load alternate ROM '%s', "
1410 "fallback to embedded ROM.\n\n",vm->rom_filename);
1411 vm->rom_filename = NULL;
1412 }
1413
1414 /* Load symbol file */
1415 if (vm->sym_filename) {
1416 mips64_sym_load_file(cpu0,vm->sym_filename);
1417 cpu0->sym_trace = 1;
1418 }
1419
1420 return(c3745_boot_ios(router));
1421 }
1422
1423 /* Stop a Cisco 3745 instance */
1424 int c3745_stop_instance(c3745_t *router)
1425 {
1426 vm_instance_t *vm = router->vm;
1427
1428 printf("\nC3745 '%s': stopping simulation.\n",vm->name);
1429 vm_log(vm,"C3745_STOP","stopping simulation.\n");
1430
1431 /* Stop all CPUs */
1432 if (vm->cpu_group != NULL) {
1433 vm_stop(vm);
1434
1435 if (cpu_group_sync_state(vm->cpu_group) == -1) {
1436 vm_error(vm,"unable to sync with system CPUs.\n");
1437 return(-1);
1438 }
1439 }
1440
1441 /* Free resources that were used during execution to emulate hardware */
1442 c3745_nm_shutdown_all(router);
1443 vm_hardware_shutdown(vm);
1444 return(0);
1445 }

  ViewVC Help
Powered by ViewVC 1.1.26