📄 vm.c
字号:
/* * Cisco 7200 (Predator) simulation platform. * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) * * Virtual machine abstraction. * * TODO: IRQ Routing. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <fcntl.h>#include <sys/types.h>#include <assert.h>#include "registry.h"#include "device.h"#include "pci_dev.h"#include "pci_io.h"#include "vm.h"#include "dev_vtty.h"#include ARCH_INC_FILE#define DEBUG_VM 1/* Type of VM file naming (0=use VM name, 1=use instance ID) */int vm_file_naming_type = 0;/* Initialize a VM object */void vm_object_init(vm_obj_t *obj){ memset(obj,0,sizeof(*obj));}/* Add a VM object to an instance */void vm_object_add(vm_instance_t *vm,vm_obj_t *obj){ obj->next = vm->vm_object_list; obj->pprev = &vm->vm_object_list; if (vm->vm_object_list) vm->vm_object_list->pprev = &obj->next; vm->vm_object_list = obj;}/* Remove a VM object from an instance */void vm_object_remove(vm_instance_t *vm,vm_obj_t *obj){ if (obj->next) obj->next->pprev = obj->pprev; *(obj->pprev) = obj->next; obj->shutdown(vm,obj->data);}/* Find an object given its name */vm_obj_t *vm_object_find(vm_instance_t *vm,char *name){ vm_obj_t *obj; for(obj=vm->vm_object_list;obj;obj=obj->next) if (!strcmp(obj->name,name)) return obj; return NULL;}/* Check that a mandatory object is present */int vm_object_check(vm_instance_t *vm,char *name){ return(vm_object_find(vm,name) ? 0 : -1);}/* Shut down all objects of an instance */void vm_object_free_list(vm_instance_t *vm){ vm_obj_t *obj,*next; for(obj=vm->vm_object_list;obj;obj=next) { next = obj->next; if (obj->shutdown != NULL) {#if DEBUG_VM vm_log(vm,"VM_OBJECT","Shutdown of object \"%s\"\n",obj->name);#endif obj->shutdown(vm,obj->data); } } vm->vm_object_list = NULL;}/* Dump the object list of an instance */void vm_object_dump(vm_instance_t *vm){ vm_obj_t *obj; printf("VM \"%s\" (%u) object list:\n",vm->name,vm->instance_id); for(obj=vm->vm_object_list;obj;obj=obj->next) { printf(" - %-15s [data=%p]\n",obj->name,obj->data); } printf("\n");}/* Get VM type */char *vm_get_type(vm_instance_t *vm){ char *machine; switch(vm->type) { case VM_TYPE_C3600: machine = "c3600"; break; case VM_TYPE_C7200: machine = "c7200"; break; case VM_TYPE_C2691: machine = "c2691"; break; case VM_TYPE_C3725: machine = "c3725"; break; case VM_TYPE_C3745: machine = "c3745"; break; default: machine = "unknown"; break; } return machine;}/* Get platform type */char *vm_get_platform_type(vm_instance_t *vm){ char *machine; switch(vm->type) { case VM_TYPE_C3600: machine = "C3600"; break; case VM_TYPE_C7200: machine = "C7200"; break; case VM_TYPE_C2691: machine = "C2691"; break; case VM_TYPE_C3725: machine = "C3725"; break; case VM_TYPE_C3745: machine = "C3745"; break; default: machine = "VM"; break; } return machine;}/* Get MAC address MSB */u_int vm_get_mac_addr_msb(vm_instance_t *vm){ switch(vm->type) { case VM_TYPE_C3600: return(0xCC); case VM_TYPE_C7200: return(0xCA); case VM_TYPE_C2691: return(0xC0); case VM_TYPE_C3725: return(0xC2); case VM_TYPE_C3745: return(0xC4); default: return(0xC6); }}/* Generate a filename for use by the instance */char *vm_build_filename(vm_instance_t *vm,char *name){ char *filename,*machine; machine = vm_get_type(vm); switch(vm_file_naming_type) { case 1: filename = dyn_sprintf("%s_i%u_%s",machine,vm->instance_id,name); break; case 0: default: filename = dyn_sprintf("%s_%s_%s",machine,vm->name,name); break; } assert(filename != NULL); return filename;}/* Erase lock file */void vm_release_lock(vm_instance_t *vm,int erase){ if (vm->lock_fd != NULL) { fclose(vm->lock_fd); vm->lock_fd = NULL; } if (vm->lock_file != NULL) { if (erase) unlink(vm->lock_file); free(vm->lock_file); vm->lock_file = NULL; }}/* Check that an instance lock file doesn't already exist */int vm_get_lock(vm_instance_t *vm){ char pid_str[32]; struct flock lock; vm->lock_file = vm_build_filename(vm,"lock"); if (!(vm->lock_fd = fopen(vm->lock_file,"w"))) { fprintf(stderr,"Unable to create lock file \"%s\".\n",vm->lock_file); return(-1); } memset(&lock,0,sizeof(lock)); lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; if (fcntl(fileno(vm->lock_fd),F_SETLK,&lock) == -1) { if (fcntl(fileno(vm->lock_fd),F_GETLK,&lock) == 0) { snprintf(pid_str,sizeof(pid_str),"%ld",(long)lock.l_pid); } else { strcpy(pid_str,"unknown"); } fprintf(stderr, "\nAn emulator instance (PID %s) is already running with " "identifier %u.\n" "If this is not the case, please erase file \"%s\".\n\n", pid_str,vm->instance_id,vm->lock_file); vm_release_lock(vm,FALSE); return(-1); } /* write the emulator PID */ fprintf(vm->lock_fd,"%ld\n",(u_long)getpid()); return(0);}/* Log a message */void vm_flog(vm_instance_t *vm,char *module,char *format,va_list ap){ if (vm->log_fd) m_flog(vm->log_fd,module,format,ap);}/* Log a message */void vm_log(vm_instance_t *vm,char *module,char *format,...){ va_list ap; va_start(ap,format); vm_flog(vm,module,format,ap); va_end(ap);}/* Close the log file */int vm_close_log(vm_instance_t *vm){ if (vm->log_fd) fclose(vm->log_fd); free(vm->log_file); vm->log_file = NULL; vm->log_fd = NULL; return(0);}/* Create the log file */int vm_create_log(vm_instance_t *vm){ vm_close_log(vm); if (!(vm->log_file = vm_build_filename(vm,"log.txt"))) return(-1); if (!(vm->log_fd = fopen(vm->log_file,"w"))) { fprintf(stderr,"VM %s: unable to create log file '%s'\n", vm->name,vm->log_file); free(vm->log_file); vm->log_file = NULL; return(-1); } return(0);}/* Error message */void vm_error(vm_instance_t *vm,char *format,...){ char buffer[2048]; va_list ap; va_start(ap,format); vsnprintf(buffer,sizeof(buffer),format,ap); va_end(ap); fprintf(stderr,"%s '%s': %s",vm_get_platform_type(vm),vm->name,buffer);}/* Create a new VM instance */vm_instance_t *vm_create(char *name,int instance_id,int machine_type){ vm_instance_t *vm; if (!(vm = malloc(sizeof(*vm)))) { fprintf(stderr,"VM %s: unable to create new instance!\n",name); return NULL; } memset(vm,0,sizeof(*vm)); vm->instance_id = instance_id; vm->type = machine_type; vm->status = VM_STATUS_HALTED; vm->jit_use = JIT_SUPPORT; vm->vtty_con_type = VTTY_TYPE_TERM; vm->vtty_aux_type = VTTY_TYPE_NONE; vm->timer_irq_check_itv = VM_TIMER_IRQ_CHECK_ITV; if (!(vm->name = strdup(name))) { fprintf(stderr,"VM %s: unable to store instance name!\n",name); goto err_name; } /* create lock file */ if (vm_get_lock(vm) == -1) goto err_lock; /* create log file */ if (vm_create_log(vm) == -1) goto err_log; if (registry_add(vm->name,OBJ_TYPE_VM,vm) == -1) { fprintf(stderr,"VM: Unable to store instance '%s' in registry!\n", vm->name); goto err_reg_add; } return vm; err_reg_add: vm_close_log(vm); err_log: free(vm->lock_file); err_lock: free(vm->name); err_name: free(vm); return NULL;}/* * Shutdown hardware resources used by a VM. * The CPU must have been stopped. */int vm_hardware_shutdown(vm_instance_t *vm){ int i; if ((vm->status == VM_STATUS_HALTED) || !vm->cpu_group) { vm_log(vm,"VM","trying to shutdown an inactive VM.\n"); return(-1); } vm_log(vm,"VM","shutdown procedure engaged.\n"); /* Mark the VM as halted */ vm->status = VM_STATUS_HALTED; /* Disable NVRAM operations */ vm->nvram_extract_config = NULL; vm->nvram_push_config = NULL; /* Free the object list */ vm_object_free_list(vm); /* Free resources used by PCI busses */ vm_log(vm,"VM","removing PCI busses.\n"); pci_io_data_remove(vm,vm->pci_io_space); pci_bus_remove(vm->pci_bus[0]); pci_bus_remove(vm->pci_bus[1]); vm->pci_bus[0] = vm->pci_bus[1] = NULL; /* Free the PCI bus pool */ for(i=0;i<VM_PCI_POOL_SIZE;i++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -