/[dynamips]/upstream/dynamips-0.2.8-RC1/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

Annotation of /upstream/dynamips-0.2.8-RC1/vm.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8 - (hide annotations)
Sat Oct 6 16:24:54 2007 UTC (16 years, 6 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7-RC2/vm.c
File MIME type: text/plain
File size: 23816 byte(s)
dynamips-0.2.7-RC2

1 dpavlin 1 /*
2 dpavlin 7 * Cisco router simulation platform.
3 dpavlin 1 * 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 dpavlin 4 #include <errno.h>
13 dpavlin 1 #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 dpavlin 7 #include "cpu.h"
22     #include "mips64_jit.h"
23 dpavlin 1 #include "vm.h"
24     #include "dev_vtty.h"
25    
26 dpavlin 7 #include MIPS64_ARCH_INC_FILE
27 dpavlin 1
28     #define DEBUG_VM 1
29    
30 dpavlin 7 #define VM_GLOCK() pthread_mutex_lock(&vm_global_lock)
31     #define VM_GUNLOCK() pthread_mutex_unlock(&vm_global_lock)
32    
33 dpavlin 1 /* Type of VM file naming (0=use VM name, 1=use instance ID) */
34     int vm_file_naming_type = 0;
35    
36 dpavlin 7 /* 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 dpavlin 1 /* 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 dpavlin 4
70     obj->shutdown(vm,obj->data);
71 dpavlin 1 }
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 dpavlin 8 /* 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 dpavlin 1 /* 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 dpavlin 4 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 dpavlin 7 case VM_TYPE_C2600:
155     machine = "c2600";
156     break;
157 dpavlin 8 case VM_TYPE_MSFC1:
158     machine = "msfc1";
159     break;
160 dpavlin 7 case VM_TYPE_PPC32_TEST:
161     machine = "ppc32_test";
162     break;
163 dpavlin 1 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 dpavlin 4 break;
183     case VM_TYPE_C2691:
184     machine = "C2691";
185 dpavlin 1 break;
186 dpavlin 4 case VM_TYPE_C3725:
187     machine = "C3725";
188     break;
189     case VM_TYPE_C3745:
190     machine = "C3745";
191     break;
192 dpavlin 7 case VM_TYPE_C2600:
193     machine = "C2600";
194     break;
195 dpavlin 8 case VM_TYPE_MSFC1:
196     machine = "MSFC1";
197     break;
198     case VM_TYPE_PPC32_TEST:
199 dpavlin 7 machine = "PPC32_TEST";
200     break;
201 dpavlin 1 default:
202     machine = "VM";
203     break;
204     }
205    
206     return machine;
207     }
208    
209 dpavlin 4 /* 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 dpavlin 7 case VM_TYPE_C2600:
229     return(0xC8);
230    
231 dpavlin 4 default:
232     return(0xC6);
233     }
234     }
235    
236 dpavlin 1 /* 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 dpavlin 7 if (vm->log_fd) {
326     va_start(ap,format);
327     vm_flog(vm,module,format,ap);
328     va_end(ap);
329     }
330 dpavlin 1 }
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 dpavlin 7 if (vm->log_file_enabled) {
349     vm_close_log(vm);
350 dpavlin 1
351 dpavlin 7 if (!(vm->log_file = vm_build_filename(vm,"log.txt")))
352     return(-1);
353 dpavlin 1
354 dpavlin 7 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 dpavlin 1 }
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 dpavlin 8 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 dpavlin 1
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 dpavlin 7 /* Remove the IRQ routing vectors */
473     vm->set_irq = NULL;
474     vm->clear_irq = NULL;
475    
476 dpavlin 1 /* 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 dpavlin 7 /* Free all chunks */
504     vm_chunk_free_all(vm);
505    
506 dpavlin 1 /* Free various elements */
507 dpavlin 4 free(vm->ghost_ram_filename);
508 dpavlin 1 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 dpavlin 4 /* 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 dpavlin 7 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 dpavlin 4
541     return(dev_ram_init(vm,"ram",vm->ram_mmap,
542     (vm->ghost_status != VM_GHOST_RAM_GENERATE),
543 dpavlin 7 vm->ghost_ram_filename,vm->sparse_mem,paddr,len));
544 dpavlin 4 }
545    
546 dpavlin 1 /* 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 dpavlin 7 for(i=0;i<VM_DEVICE_MAX;i++)
579 dpavlin 1 if (!vm->dev_array[i])
580     break;
581    
582 dpavlin 7 if (i == VM_DEVICE_MAX) {
583 dpavlin 1 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 dpavlin 8 if (!dev || !dev->pprev)
611 dpavlin 1 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 dpavlin 7 for(i=0;i<VM_DEVICE_MAX;i++)
621 dpavlin 1 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 dpavlin 7 cpu_group_set_state(vm->cpu_group,CPU_STATE_SUSPENDED);
666 dpavlin 1 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 dpavlin 7 /* 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 dpavlin 4 /* 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 dpavlin 1 /* 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