/[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 7 - (show annotations)
Sat Oct 6 16:23:47 2007 UTC (11 years, 8 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7-RC1/vm.c
File MIME type: text/plain
File size: 23391 byte(s)
dynamips-0.2.7-RC1

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

  ViewVC Help
Powered by ViewVC 1.1.26