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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9 - (show annotations)
Sat Oct 6 16:26:06 2007 UTC (11 years, 11 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7-RC3/vm.c
File MIME type: text/plain
File size: 23816 byte(s)
dynamips-0.2.7-RC3

1 /*
2 * Cisco router simulation platform.
3 * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
4 *
5 * Virtual machine abstraction.
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <sys/types.h>
15 #include <assert.h>
16
17 #include "registry.h"
18 #include "device.h"
19 #include "pci_dev.h"
20 #include "pci_io.h"
21 #include "cpu.h"
22 #include "mips64_jit.h"
23 #include "vm.h"
24 #include "dev_vtty.h"
25
26 #include MIPS64_ARCH_INC_FILE
27
28 #define DEBUG_VM 1
29
30 #define VM_GLOCK() pthread_mutex_lock(&vm_global_lock)
31 #define VM_GUNLOCK() pthread_mutex_unlock(&vm_global_lock)
32
33 /* Type of VM file naming (0=use VM name, 1=use instance ID) */
34 int vm_file_naming_type = 0;
35
36 /* Pool of ghost images */
37 static vm_ghost_image_t *vm_ghost_pool = NULL;
38
39 /* Global lock for VM manipulation */
40 static pthread_mutex_t vm_global_lock = PTHREAD_MUTEX_INITIALIZER;
41
42 /* Free all chunks used by a VM */
43 static void vm_chunk_free_all(vm_instance_t *vm);
44
45 /* Initialize a VM object */
46 void vm_object_init(vm_obj_t *obj)
47 {
48 memset(obj,0,sizeof(*obj));
49 }
50
51 /* Add a VM object to an instance */
52 void vm_object_add(vm_instance_t *vm,vm_obj_t *obj)
53 {
54 obj->next = vm->vm_object_list;
55 obj->pprev = &vm->vm_object_list;
56
57 if (vm->vm_object_list)
58 vm->vm_object_list->pprev = &obj->next;
59
60 vm->vm_object_list = obj;
61 }
62
63 /* Remove a VM object from an instance */
64 void vm_object_remove(vm_instance_t *vm,vm_obj_t *obj)
65 {
66 if (obj->next)
67 obj->next->pprev = obj->pprev;
68 *(obj->pprev) = obj->next;
69
70 obj->shutdown(vm,obj->data);
71 }
72
73 /* Find an object given its name */
74 vm_obj_t *vm_object_find(vm_instance_t *vm,char *name)
75 {
76 vm_obj_t *obj;
77
78 for(obj=vm->vm_object_list;obj;obj=obj->next)
79 if (!strcmp(obj->name,name))
80 return obj;
81
82 return NULL;
83 }
84
85 /* Check that a mandatory object is present */
86 int vm_object_check(vm_instance_t *vm,char *name)
87 {
88 return(vm_object_find(vm,name) ? 0 : -1);
89 }
90
91 /* Shut down all objects of an instance */
92 void vm_object_free_list(vm_instance_t *vm)
93 {
94 vm_obj_t *obj,*next;
95
96 for(obj=vm->vm_object_list;obj;obj=next) {
97 next = obj->next;
98
99 if (obj->shutdown != NULL) {
100 #if DEBUG_VM
101 vm_log(vm,"VM_OBJECT","Shutdown of object \"%s\"\n",obj->name);
102 #endif
103 obj->shutdown(vm,obj->data);
104 }
105 }
106
107 vm->vm_object_list = NULL;
108 }
109
110 /* Rebuild the object list pointers */
111 static void vm_object_rebuild_list(vm_instance_t *vm)
112 {
113 vm_obj_t **obj;
114
115 for(obj=&vm->vm_object_list;*obj;obj=&(*obj)->next)
116 (*obj)->pprev = obj;
117 }
118
119 /* Dump the object list of an instance */
120 void vm_object_dump(vm_instance_t *vm)
121 {
122 vm_obj_t *obj;
123
124 printf("VM \"%s\" (%u) object list:\n",vm->name,vm->instance_id);
125
126 for(obj=vm->vm_object_list;obj;obj=obj->next) {
127 printf(" - %-15s [data=%p]\n",obj->name,obj->data);
128 }
129
130 printf("\n");
131 }
132
133 /* Get VM type */
134 char *vm_get_type(vm_instance_t *vm)
135 {
136 char *machine;
137
138 switch(vm->type) {
139 case VM_TYPE_C3600:
140 machine = "c3600";
141 break;
142 case VM_TYPE_C7200:
143 machine = "c7200";
144 break;
145 case VM_TYPE_C2691:
146 machine = "c2691";
147 break;
148 case VM_TYPE_C3725:
149 machine = "c3725";
150 break;
151 case VM_TYPE_C3745:
152 machine = "c3745";
153 break;
154 case VM_TYPE_C2600:
155 machine = "c2600";
156 break;
157 case VM_TYPE_MSFC1:
158 machine = "msfc1";
159 break;
160 case VM_TYPE_PPC32_TEST:
161 machine = "ppc32_test";
162 break;
163 default:
164 machine = "unknown";
165 break;
166 }
167
168 return machine;
169 }
170
171 /* Get platform type */
172 char *vm_get_platform_type(vm_instance_t *vm)
173 {
174 char *machine;
175
176 switch(vm->type) {
177 case VM_TYPE_C3600:
178 machine = "C3600";
179 break;
180 case VM_TYPE_C7200:
181 machine = "C7200";
182 break;
183 case VM_TYPE_C2691:
184 machine = "C2691";
185 break;
186 case VM_TYPE_C3725:
187 machine = "C3725";
188 break;
189 case VM_TYPE_C3745:
190 machine = "C3745";
191 break;
192 case VM_TYPE_C2600:
193 machine = "C2600";
194 break;
195 case VM_TYPE_MSFC1:
196 machine = "MSFC1";
197 break;
198 case VM_TYPE_PPC32_TEST:
199 machine = "PPC32_TEST";
200 break;
201 default:
202 machine = "VM";
203 break;
204 }
205
206 return machine;
207 }
208
209 /* Get MAC address MSB */
210 u_int vm_get_mac_addr_msb(vm_instance_t *vm)
211 {
212 switch(vm->type) {
213 case VM_TYPE_C3600:
214 return(0xCC);
215
216 case VM_TYPE_C7200:
217 return(0xCA);
218
219 case VM_TYPE_C2691:
220 return(0xC0);
221
222 case VM_TYPE_C3725:
223 return(0xC2);
224
225 case VM_TYPE_C3745:
226 return(0xC4);
227
228 case VM_TYPE_C2600:
229 return(0xC8);
230
231 default:
232 return(0xC6);
233 }
234 }
235
236 /* Generate a filename for use by the instance */
237 char *vm_build_filename(vm_instance_t *vm,char *name)
238 {
239 char *filename,*machine;
240
241 machine = vm_get_type(vm);
242
243 switch(vm_file_naming_type) {
244 case 1:
245 filename = dyn_sprintf("%s_i%u_%s",machine,vm->instance_id,name);
246 break;
247 case 0:
248 default:
249 filename = dyn_sprintf("%s_%s_%s",machine,vm->name,name);
250 break;
251 }
252
253 assert(filename != NULL);
254 return filename;
255 }
256
257 /* Erase lock file */
258 void vm_release_lock(vm_instance_t *vm,int erase)
259 {
260 if (vm->lock_fd != NULL) {
261 fclose(vm->lock_fd);
262 vm->lock_fd = NULL;
263 }
264
265 if (vm->lock_file != NULL) {
266 if (erase)
267 unlink(vm->lock_file);
268 free(vm->lock_file);
269 vm->lock_file = NULL;
270 }
271 }
272
273 /* Check that an instance lock file doesn't already exist */
274 int vm_get_lock(vm_instance_t *vm)
275 {
276 char pid_str[32];
277 struct flock lock;
278
279 vm->lock_file = vm_build_filename(vm,"lock");
280
281 if (!(vm->lock_fd = fopen(vm->lock_file,"w"))) {
282 fprintf(stderr,"Unable to create lock file \"%s\".\n",vm->lock_file);
283 return(-1);
284 }
285
286 memset(&lock,0,sizeof(lock));
287 lock.l_type = F_WRLCK;
288 lock.l_whence = SEEK_SET;
289 lock.l_start = 0;
290 lock.l_len = 0;
291
292 if (fcntl(fileno(vm->lock_fd),F_SETLK,&lock) == -1) {
293 if (fcntl(fileno(vm->lock_fd),F_GETLK,&lock) == 0) {
294 snprintf(pid_str,sizeof(pid_str),"%ld",(long)lock.l_pid);
295 } else {
296 strcpy(pid_str,"unknown");
297 }
298
299 fprintf(stderr,
300 "\nAn emulator instance (PID %s) is already running with "
301 "identifier %u.\n"
302 "If this is not the case, please erase file \"%s\".\n\n",
303 pid_str,vm->instance_id,vm->lock_file);
304 vm_release_lock(vm,FALSE);
305 return(-1);
306 }
307
308 /* write the emulator PID */
309 fprintf(vm->lock_fd,"%ld\n",(u_long)getpid());
310 return(0);
311 }
312
313 /* Log a message */
314 void vm_flog(vm_instance_t *vm,char *module,char *format,va_list ap)
315 {
316 if (vm->log_fd)
317 m_flog(vm->log_fd,module,format,ap);
318 }
319
320 /* Log a message */
321 void vm_log(vm_instance_t *vm,char *module,char *format,...)
322 {
323 va_list ap;
324
325 if (vm->log_fd) {
326 va_start(ap,format);
327 vm_flog(vm,module,format,ap);
328 va_end(ap);
329 }
330 }
331
332 /* Close the log file */
333 int vm_close_log(vm_instance_t *vm)
334 {
335 if (vm->log_fd)
336 fclose(vm->log_fd);
337
338 free(vm->log_file);
339
340 vm->log_file = NULL;
341 vm->log_fd = NULL;
342 return(0);
343 }
344
345 /* Create the log file */
346 int vm_create_log(vm_instance_t *vm)
347 {
348 if (vm->log_file_enabled) {
349 vm_close_log(vm);
350
351 if (!(vm->log_file = vm_build_filename(vm,"log.txt")))
352 return(-1);
353
354 if (!(vm->log_fd = fopen(vm->log_file,"w"))) {
355 fprintf(stderr,"VM %s: unable to create log file '%s'\n",
356 vm->name,vm->log_file);
357 free(vm->log_file);
358 vm->log_file = NULL;
359 return(-1);
360 }
361 }
362
363 return(0);
364 }
365
366 /* Error message */
367 void vm_error(vm_instance_t *vm,char *format,...)
368 {
369 char buffer[2048];
370 va_list ap;
371
372 va_start(ap,format);
373 vsnprintf(buffer,sizeof(buffer),format,ap);
374 va_end(ap);
375
376 fprintf(stderr,"%s '%s': %s",vm_get_platform_type(vm),vm->name,buffer);
377 }
378
379 /* Create a new VM instance */
380 vm_instance_t *vm_create(char *name,int instance_id,int machine_type)
381 {
382 vm_instance_t *vm;
383
384 if (!(vm = malloc(sizeof(*vm)))) {
385 fprintf(stderr,"VM %s: unable to create new instance!\n",name);
386 return NULL;
387 }
388
389 memset(vm,0,sizeof(*vm));
390 vm->instance_id = instance_id;
391 vm->type = machine_type;
392 vm->status = VM_STATUS_HALTED;
393 vm->jit_use = JIT_SUPPORT;
394 vm->exec_blk_direct_jump = TRUE;
395 vm->vtty_con_type = VTTY_TYPE_TERM;
396 vm->vtty_aux_type = VTTY_TYPE_NONE;
397 vm->timer_irq_check_itv = VM_TIMER_IRQ_CHECK_ITV;
398 vm->log_file_enabled = TRUE;
399
400 if (!(vm->name = strdup(name))) {
401 fprintf(stderr,"VM %s: unable to store instance name!\n",name);
402 goto err_name;
403 }
404
405 /* create lock file */
406 if (vm_get_lock(vm) == -1)
407 goto err_lock;
408
409 /* create log file */
410 if (vm_create_log(vm) == -1)
411 goto err_log;
412
413 if (registry_add(vm->name,OBJ_TYPE_VM,vm) == -1) {
414 fprintf(stderr,"VM: Unable to store instance '%s' in registry!\n",
415 vm->name);
416 goto err_reg_add;
417 }
418
419 return vm;
420
421 err_reg_add:
422 vm_close_log(vm);
423 err_log:
424 free(vm->lock_file);
425 err_lock:
426 free(vm->name);
427 err_name:
428 free(vm);
429 return NULL;
430 }
431
432 /*
433 * Shutdown hardware resources used by a VM.
434 * The CPU must have been stopped.
435 */
436 int vm_hardware_shutdown(vm_instance_t *vm)
437 {
438 int i;
439
440 if ((vm->status == VM_STATUS_HALTED) || !vm->cpu_group) {
441 vm_log(vm,"VM","trying to shutdown an inactive VM.\n");
442 return(-1);
443 }
444
445 vm_log(vm,"VM","shutdown procedure engaged.\n");
446
447 /* Mark the VM as halted */
448 vm->status = VM_STATUS_HALTED;
449
450 /* Disable NVRAM operations */
451 vm->nvram_extract_config = NULL;
452 vm->nvram_push_config = NULL;
453
454 /* Free the object list */
455 vm_object_free_list(vm);
456
457 /* Free resources used by PCI busses */
458 vm_log(vm,"VM","removing PCI busses.\n");
459 pci_io_data_remove(vm,vm->pci_io_space);
460 pci_bus_remove(vm->pci_bus[0]);
461 pci_bus_remove(vm->pci_bus[1]);
462 vm->pci_bus[0] = vm->pci_bus[1] = NULL;
463
464 /* Free the PCI bus pool */
465 for(i=0;i<VM_PCI_POOL_SIZE;i++) {
466 if (vm->pci_bus_pool[i] != NULL) {
467 pci_bus_remove(vm->pci_bus_pool[i]);
468 vm->pci_bus_pool[i] = NULL;
469 }
470 }
471
472 /* Remove the IRQ routing vectors */
473 vm->set_irq = NULL;
474 vm->clear_irq = NULL;
475
476 /* Delete the VTTY for Console and AUX ports */
477 vm_log(vm,"VM","deleting VTTY.\n");
478 vm_delete_vtty(vm);
479
480 /* Delete system CPU group */
481 vm_log(vm,"VM","deleting system CPUs.\n");
482 cpu_group_delete(vm->cpu_group);
483 vm->cpu_group = NULL;
484 vm->boot_cpu = NULL;
485
486 vm_log(vm,"VM","shutdown procedure completed.\n");
487 return(0);
488 }
489
490 /* Free resources used by a VM */
491 void vm_free(vm_instance_t *vm)
492 {
493 if (vm != NULL) {
494 /* Free hardware resources */
495 vm_hardware_shutdown(vm);
496
497 /* Close log file */
498 vm_close_log(vm);
499
500 /* Remove the lock file */
501 vm_release_lock(vm,TRUE);
502
503 /* Free all chunks */
504 vm_chunk_free_all(vm);
505
506 /* Free various elements */
507 free(vm->ghost_ram_filename);
508 free(vm->sym_filename);
509 free(vm->ios_image);
510 free(vm->ios_config);
511 free(vm->rom_filename);
512 free(vm->name);
513 free(vm);
514 }
515 }
516
517 /* Get an instance given a name */
518 vm_instance_t *vm_acquire(char *name)
519 {
520 return(registry_find(name,OBJ_TYPE_VM));
521 }
522
523 /* Release a VM (decrement reference count) */
524 int vm_release(vm_instance_t *vm)
525 {
526 return(registry_unref(vm->name,OBJ_TYPE_VM));
527 }
528
529 /* Initialize RAM */
530 int vm_ram_init(vm_instance_t *vm,m_uint64_t paddr)
531 {
532 m_uint32_t len;
533
534 len = vm->ram_size * 1048576;
535
536 if (vm->ghost_status == VM_GHOST_RAM_USE) {
537 return(dev_ram_ghost_init(vm,"ram",vm->sparse_mem,vm->ghost_ram_filename,
538 paddr,len));
539 }
540
541 return(dev_ram_init(vm,"ram",vm->ram_mmap,
542 (vm->ghost_status != VM_GHOST_RAM_GENERATE),
543 vm->ghost_ram_filename,vm->sparse_mem,paddr,len));
544 }
545
546 /* Initialize VTTY */
547 int vm_init_vtty(vm_instance_t *vm)
548 {
549 /* Create Console and AUX ports */
550 vm->vtty_con = vtty_create(vm,"Console port",
551 vm->vtty_con_type,vm->vtty_con_tcp_port,
552 &vm->vtty_con_serial_option);
553
554 vm->vtty_aux = vtty_create(vm,"AUX port",
555 vm->vtty_aux_type,vm->vtty_aux_tcp_port,
556 &vm->vtty_aux_serial_option);
557 return(0);
558 }
559
560 /* Delete VTTY */
561 void vm_delete_vtty(vm_instance_t *vm)
562 {
563 vtty_delete(vm->vtty_con);
564 vtty_delete(vm->vtty_aux);
565 vm->vtty_con = vm->vtty_aux = NULL;
566 }
567
568 /* Bind a device to a virtual machine */
569 int vm_bind_device(vm_instance_t *vm,struct vdevice *dev)
570 {
571 struct vdevice **cur;
572 u_int i;
573
574 /*
575 * Add this device to the device array. The index in the device array
576 * is used by the MTS subsystem.
577 */
578 for(i=0;i<VM_DEVICE_MAX;i++)
579 if (!vm->dev_array[i])
580 break;
581
582 if (i == VM_DEVICE_MAX) {
583 fprintf(stderr,"VM%u: vm_bind_device: device table full.\n",
584 vm->instance_id);
585 return(-1);
586 }
587
588 vm->dev_array[i] = dev;
589 dev->id = i;
590
591 /*
592 * Add it to the linked-list (devices are ordered by physical addresses).
593 */
594 for(cur=&vm->dev_list;*cur;cur=&(*cur)->next)
595 if ((*cur)->phys_addr > dev->phys_addr)
596 break;
597
598 dev->next = *cur;
599 if (*cur) (*cur)->pprev = &dev->next;
600 dev->pprev = cur;
601 *cur = dev;
602 return(0);
603 }
604
605 /* Unbind a device from a virtual machine */
606 int vm_unbind_device(vm_instance_t *vm,struct vdevice *dev)
607 {
608 u_int i;
609
610 if (!dev || !dev->pprev)
611 return(-1);
612
613 /* Remove the device from the linked list */
614 if (dev->next)
615 dev->next->pprev = dev->pprev;
616
617 *(dev->pprev) = dev->next;
618
619 /* Remove the device from the device array */
620 for(i=0;i<VM_DEVICE_MAX;i++)
621 if (vm->dev_array[i] == dev) {
622 vm->dev_array[i] = NULL;
623 break;
624 }
625
626 /* Clear device list info */
627 dev->next = NULL;
628 dev->pprev = NULL;
629 return(0);
630 }
631
632 /* Map a device at the specified physical address */
633 int vm_map_device(vm_instance_t *vm,struct vdevice *dev,m_uint64_t base_addr)
634 {
635 #if 0
636 /* Suspend VM activity */
637 vm_suspend(vm);
638
639 if (cpu_group_sync_state(vm->cpu_group) == -1) {
640 fprintf(stderr,"VM%u: unable to sync with system CPUs.\n",
641 vm->instance_id);
642 return(-1);
643 }
644 #endif
645
646 /* Unbind the device if it was already active */
647 vm_unbind_device(vm,dev);
648
649 /* Map the device at the new base address and rebuild MTS */
650 dev->phys_addr = base_addr;
651 vm_bind_device(vm,dev);
652 cpu_group_rebuild_mts(vm->cpu_group);
653
654 #if 0
655 vm_resume(vm);
656 #endif
657 return(0);
658 }
659
660 /* Suspend a VM instance */
661 int vm_suspend(vm_instance_t *vm)
662 {
663 if (vm->status == VM_STATUS_RUNNING) {
664 cpu_group_save_state(vm->cpu_group);
665 cpu_group_set_state(vm->cpu_group,CPU_STATE_SUSPENDED);
666 vm->status = VM_STATUS_SUSPENDED;
667 }
668 return(0);
669 }
670
671 /* Resume a VM instance */
672 int vm_resume(vm_instance_t *vm)
673 {
674 if (vm->status == VM_STATUS_SUSPENDED) {
675 cpu_group_restore_state(vm->cpu_group);
676 vm->status = VM_STATUS_RUNNING;
677 }
678 return(0);
679 }
680
681 /* Stop an instance */
682 int vm_stop(vm_instance_t *vm)
683 {
684 cpu_group_stop_all_cpu(vm->cpu_group);
685 vm->status = VM_STATUS_SHUTDOWN;
686 return(0);
687 }
688
689 /* Monitor an instance periodically */
690 void vm_monitor(vm_instance_t *vm)
691 {
692 while(vm->status != VM_STATUS_SHUTDOWN)
693 usleep(200000);
694 }
695
696 /* Create a new chunk */
697 static vm_chunk_t *vm_chunk_create(vm_instance_t *vm)
698 {
699 vm_chunk_t *chunk;
700 size_t area_len;
701
702 if (!(chunk = malloc(sizeof(*chunk))))
703 return NULL;
704
705 area_len = VM_CHUNK_AREA_SIZE * VM_PAGE_SIZE;
706
707 if (!(chunk->area = m_memalign(VM_PAGE_SIZE,area_len))) {
708 free(chunk);
709 return NULL;
710 }
711
712 chunk->page_alloc = 0;
713 chunk->page_total = VM_CHUNK_AREA_SIZE;
714
715 chunk->next = vm->chunks;
716 vm->chunks = chunk;
717 return chunk;
718 }
719
720 /* Free a chunk */
721 static void vm_chunk_free(vm_chunk_t *chunk)
722 {
723 free(chunk->area);
724 free(chunk);
725 }
726
727 /* Free all chunks used by a VM */
728 static void vm_chunk_free_all(vm_instance_t *vm)
729 {
730 vm_chunk_t *chunk,*next;
731
732 for(chunk=vm->chunks;chunk;chunk=next) {
733 next = chunk->next;
734 vm_chunk_free(chunk);
735 }
736
737 vm->chunks = NULL;
738 }
739
740 /* Allocate an host page */
741 void *vm_alloc_host_page(vm_instance_t *vm)
742 {
743 vm_chunk_t *chunk = vm->chunks;
744 void *ptr;
745
746 if (!chunk || (chunk->page_alloc == chunk->page_total)) {
747 chunk = vm_chunk_create(vm);
748 if (!chunk) return NULL;
749 }
750
751 ptr = chunk->area + (chunk->page_alloc * VM_PAGE_SIZE);
752 chunk->page_alloc++;
753 return(ptr);
754 }
755
756 /* Free resources used by a ghost image */
757 static void vm_ghost_image_free(vm_ghost_image_t *img)
758 {
759 if (img) {
760 if (img->fd != -1) {
761 close(img->fd);
762
763 if (img->area_ptr != NULL)
764 munmap(img->area_ptr,img->file_size);
765 }
766
767 free(img->filename);
768 free(img);
769 }
770 }
771
772 /* Find a specified ghost image in the pool */
773 static vm_ghost_image_t *vm_ghost_image_find(char *filename)
774 {
775 vm_ghost_image_t *img;
776
777 for(img=vm_ghost_pool;img;img=img->next)
778 if (!strcmp(img->filename,filename))
779 return img;
780
781 return NULL;
782 }
783
784 /* Load a new ghost image */
785 static vm_ghost_image_t *vm_ghost_image_load(char *filename)
786 {
787 vm_ghost_image_t *img;
788
789 if (!(img = calloc(1,sizeof(*img))))
790 return NULL;
791
792 img->fd = -1;
793
794 if (!(img->filename = strdup(filename))) {
795 vm_ghost_image_free(img);
796 return NULL;
797 }
798
799 img->fd = memzone_open_file(img->filename,&img->area_ptr,&img->file_size);
800
801 if (img->fd == -1) {
802 vm_ghost_image_free(img);
803 return NULL;
804 }
805
806 m_log("GHOST","loaded ghost image %s (fd=%d) at addr=%p (size=0x%llx)\n",
807 img->filename,img->fd,img->area_ptr,(long long)img->file_size);
808
809 return img;
810 }
811
812 /* Get a ghost image */
813 int vm_ghost_image_get(char *filename,u_char **ptr,int *fd)
814 {
815 vm_ghost_image_t *img;
816
817 VM_GLOCK();
818
819 /* Do we already have this image in the pool ? */
820 if ((img = vm_ghost_image_find(filename)) != NULL) {
821 img->ref_count++;
822 *ptr = img->area_ptr;
823 *fd = img->fd;
824 VM_GUNLOCK();
825 return(0);
826 }
827
828 /* Load the ghost file and add it into the pool */
829 if (!(img = vm_ghost_image_load(filename))) {
830 VM_GUNLOCK();
831 fprintf(stderr,"Unable to load ghost image %s\n",filename);
832 return(-1);
833 }
834
835 img->ref_count = 1;
836 *ptr = img->area_ptr;
837 *fd = img->fd;
838
839 img->next = vm_ghost_pool;
840 vm_ghost_pool = img;
841 VM_GUNLOCK();
842 return(0);
843 }
844
845 /* Release a ghost image */
846 int vm_ghost_image_release(int fd)
847 {
848 vm_ghost_image_t **img,*next;
849
850 VM_GLOCK();
851
852 for(img=&vm_ghost_pool;*img;img=&(*img)->next) {
853 if ((*img)->fd == fd) {
854 assert((*img)->ref_count > 0);
855
856 (*img)->ref_count--;
857
858 if ((*img)->ref_count == 0) {
859 m_log("GHOST","unloaded ghost image %s (fd=%d) at "
860 "addr=%p (size=0x%llx)\n",
861 (*img)->filename,(*img)->fd,(*img)->area_ptr,
862 (long long)(*img)->file_size);
863
864 next = (*img)->next;
865 vm_ghost_image_free(*img);
866 *img = next;
867 }
868
869 VM_GUNLOCK();
870 return(0);
871 }
872 }
873
874 VM_GUNLOCK();
875 return(-1);
876 }
877
878 /* Open a VM file and map it in memory */
879 int vm_mmap_open_file(vm_instance_t *vm,char *name,
880 u_char **ptr,off_t *fsize)
881 {
882 char *filename;
883 int fd;
884
885 if (!(filename = vm_build_filename(vm,name))) {
886 fprintf(stderr,"vm_mmap_open_file: unable to create filename (%s)\n",
887 name);
888 return(-1);
889 }
890
891 if ((fd = memzone_open_file(filename,ptr,fsize)) == -1)
892 fprintf(stderr,"vm_mmap_open_file: unable to open file '%s' (%s)\n",
893 filename,strerror(errno));
894
895 free(filename);
896 return(fd);
897 }
898
899 /* Open/Create a VM file and map it in memory */
900 int vm_mmap_create_file(vm_instance_t *vm,char *name,size_t len,u_char **ptr)
901 {
902 char *filename;
903 int fd;
904
905 if (!(filename = vm_build_filename(vm,name))) {
906 fprintf(stderr,"vm_mmap_create_file: unable to create filename (%s)\n",
907 name);
908 return(-1);
909 }
910
911 if ((fd = memzone_create_file(filename,len,ptr)) == -1)
912 fprintf(stderr,"vm_mmap_create_file: unable to open file '%s' (%s)\n",
913 filename,strerror(errno));
914
915 free(filename);
916 return(fd);
917 }
918
919 /* Close a memory mapped file */
920 int vm_mmap_close_file(int fd,u_char *ptr,size_t len)
921 {
922 if (ptr != NULL)
923 munmap(ptr,len);
924
925 if (fd != -1)
926 close(fd);
927
928 return(0);
929 }
930
931 /* Save the Cisco IOS configuration from NVRAM */
932 int vm_ios_save_config(vm_instance_t *vm)
933 {
934 char *output;
935 int res;
936
937 if (!(output = vm_build_filename(vm,"ios_cfg.txt")))
938 return(-1);
939
940 res = vm_nvram_extract_config(vm,output);
941 free(output);
942 return(res);
943 }
944
945 /* Set Cisco IOS image to use */
946 int vm_ios_set_image(vm_instance_t *vm,char *ios_image)
947 {
948 char *str;
949
950 if (!(str = strdup(ios_image)))
951 return(-1);
952
953 if (vm->ios_image != NULL) {
954 free(vm->ios_image);
955 vm->ios_image = NULL;
956 }
957
958 vm->ios_image = str;
959 return(0);
960 }
961
962 /* Unset a Cisco IOS configuration file */
963 void vm_ios_unset_config(vm_instance_t *vm)
964 {
965 if (vm->ios_config != NULL) {
966 free(vm->ios_config);
967 vm->ios_config = NULL;
968 }
969 }
970
971 /* Set Cisco IOS configuration file to use */
972 int vm_ios_set_config(vm_instance_t *vm,char *ios_config)
973 {
974 char *str;
975
976 if (!(str = strdup(ios_config)))
977 return(-1);
978
979 vm_ios_unset_config(vm);
980 vm->ios_config = str;
981 return(0);
982 }
983
984 /* Extract IOS configuration from NVRAM and write it to a file */
985 int vm_nvram_extract_config(vm_instance_t *vm,char *filename)
986 {
987 char *cfg_buffer;
988 ssize_t cfg_len;
989 FILE *fd;
990
991 if (!vm->nvram_extract_config)
992 return(-1);
993
994 /* Extract the IOS configuration */
995 if (((cfg_len = vm->nvram_extract_config(vm,&cfg_buffer)) < 0) ||
996 (cfg_buffer == NULL))
997 return(-1);
998
999 /* Write configuration to the specified filename */
1000 if (!(fd = fopen(filename,"w"))) {
1001 vm_error(vm,"unable to create file '%s'\n",filename);
1002 free(cfg_buffer);
1003 return(-1);
1004 }
1005
1006 fwrite(cfg_buffer,cfg_len,1,fd);
1007
1008 fclose(fd);
1009 free(cfg_buffer);
1010 return(0);
1011 }
1012
1013 /* Read an IOS configuraton from a file and push it to NVRAM */
1014 int vm_nvram_push_config(vm_instance_t *vm,char *filename)
1015 {
1016 char *cfg_buffer;
1017 ssize_t len;
1018 int res;
1019
1020 if (!vm->nvram_push_config)
1021 return(-1);
1022
1023 /* Read configuration */
1024 if (((len = m_read_file(filename,&cfg_buffer)) <= 0) || !cfg_buffer)
1025 return(-1);
1026
1027 /* Push it! */
1028 res = vm->nvram_push_config(vm,cfg_buffer,len);
1029 free(cfg_buffer);
1030 return(res);
1031 }
1032
1033 /* Save general VM configuration into the specified file */
1034 void vm_save_config(vm_instance_t *vm,FILE *fd)
1035 {
1036 if (vm->ios_image)
1037 fprintf(fd,"vm set_ios %s %s\n",vm->name,vm->ios_image);
1038
1039 fprintf(fd,"vm set_ram %s %u\n",vm->name,vm->ram_size);
1040 fprintf(fd,"vm set_nvram %s %u\n",vm->name,vm->nvram_size);
1041 fprintf(fd,"vm set_ram_mmap %s %u\n",vm->name,vm->ram_mmap);
1042 fprintf(fd,"vm set_clock_divisor %s %u\n",vm->name,vm->clock_divisor);
1043 fprintf(fd,"vm set_conf_reg %s 0x%4.4x\n",vm->name,vm->conf_reg_setup);
1044
1045 if (vm->vtty_con_type == VTTY_TYPE_TCP)
1046 fprintf(fd,"vm set_con_tcp_port %s %d\n",vm->name,vm->vtty_con_tcp_port);
1047
1048 if (vm->vtty_aux_type == VTTY_TYPE_TCP)
1049 fprintf(fd,"vm set_aux_tcp_port %s %d\n",vm->name,vm->vtty_aux_tcp_port);
1050 }

  ViewVC Help
Powered by ViewVC 1.1.26