/[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

Annotation of /trunk/vm.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (hide annotations)
Sat Oct 6 16:45:40 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 25703 byte(s)
make working copy

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

  ViewVC Help
Powered by ViewVC 1.1.26