#include #include #include #include extern struct vmm_os_hooks *os_hooks; #ifndef NULL #define NULL 0 #endif int dev_mgr_init(struct vmm_dev_mgr *mgr, struct guest_info *vm) { mgr->vm=vm; mgr->dev_list=NULL; mgr->num_devices=0; return 0; } int dev_mgr_deinit(struct vmm_dev_mgr *mgr) { int rc; while (mgr->dev_list) { rc=dev_mgr_detach_device(mgr->vm,mgr->dev_list); if (rc) { // Bad bad bad } } return 0; } int dev_mgr_attach_device(struct guest_info *vm, struct vm_device *device) { struct vmm_dev_mgr *mgr= &(vm->dev_mgr); if (device->io_hooks || device->mem_hooks) { return -1; } device->next = mgr->dev_list; device->prev = 0; if (device->next) { device->next->prev = device; } mgr->dev_list = device; device->vm=vm; return 0; } int dev_mgr_detach_device(struct guest_info *vm, struct vm_device *device) { if (device->prev==0) { vm->dev_mgr.dev_list = device->next; } else { device->prev->next = device->next; } if (device->next) { device->next->prev=device->prev; } // avoid interrupts here device->deinit_device(device); device->vm=NULL; return 0; } #define INSERT_FRONT(listhead,item) \ do { \ if (!(listhead)) { \ (listhead)=(item); \ (item)->prev=NULL; \ (item)->next=NULL; \ } else { \ (item)->prev=NULL; \ (item)->next=(listhead); \ if ((listhead)->next) { \ (listhead)->next->prev=(item); \ } \ (listhead)=(item); \ } \ } while (0) #define DELETE(listhead,item) \ do { \ if ((item)->prev) { \ (item)->prev->next=(item)->next; \ } else { \ (listhead)=(item)->next; \ } \ if ((item)->next) { \ (item)->next->prev=(item)->prev; \ } \ } while (0) int dev_mgr_hook_io(struct guest_info *vm, struct vm_device *device, ushort_t portno, enum access_control control, enum access_type atype) { struct vm_device_io_hook *hook = os_hooks->malloc(sizeof(struct vm_device_io_hook)); if (!hook) { return -1; } int (*read)(ushort_t, void *, uint_t, void *) = NULL; int (*write)(ushort_t, void *, uint_t, void *) = NULL; switch (control) { case DEVICE_EMULATED: switch (atype) { case DEVICE_READ: read = (int (*)(ushort_t, void *,uint_t, void *)) (device->read_io_port); break; case DEVICE_WRITE: write = (int (*)(ushort_t, void *, uint_t, void *)) (device->write_io_port); break; case DEVICE_READWRITE: read = (int (*)(ushort_t, void *, uint_t, void *)) (device->read_io_port); write = (int (*)(ushort_t, void *, uint_t, void *)) (device->write_io_port); break; } break; case DEVICE_PASSTHROUGH: read=write=NULL; break; } hook_io_port(&(vm->io_map), portno, read, write, device); hook->control=control; hook->atype=atype; hook->guest_port = portno; INSERT_FRONT(device->io_hooks,hook); return 0; } int dev_mgr_unhook_io(struct guest_info *vm, struct vm_device *device, ushort_t portno) { struct vm_device_io_hook *hook = device->io_hooks; while (hook) { if (hook->guest_port==portno) { DELETE(device->io_hooks,hook); break; } } if (!hook) { // Very bad - unhooking something that doesn't exist! return -1; } return unhook_io_port(&(vm->io_map), portno); } int dev_mgr_hook_mem(struct guest_info *vm, struct vm_device *device, void *guest_physical_address_start, void *guest_physical_address_end, enum access_control control, enum access_type atype) { struct vm_device_mem_hook *hook = os_hooks->malloc(sizeof(struct vm_device_mem_hook)); if (!hook) { return -1; } int (*read)(ushort_t, void *, uint_t, void *) = NULL; int (*write)(ushort_t, void *, uint_t, void *) = NULL; switch (control) { case DEVICE_EMULATED: switch (atype) { case DEVICE_READ: read = (int (*)(ushort_t, void *, uint_t, void *))(device->read_mapped_memory); break; case DEVICE_WRITE: write = (int (*)(ushort_t, void *, uint_t, void *))(device->write_mapped_memory); break; case DEVICE_READWRITE: read = (int (*)(ushort_t, void *, uint_t, void *))(device->read_mapped_memory); write = (int (*)(ushort_t, void *, uint_t, void *))(device->write_mapped_memory); break; } break; case DEVICE_PASSTHROUGH: read=write=NULL; break; } /* not implemented yet hook_memory(vm->mem_map, guest_physical_address_start, guest_physical_address_end, read, write, device); */ return -1; // remove when hook_memory works hook->control=control; hook->atype=atype; hook->guest_physical_start = guest_physical_address_start; hook->guest_physical_end = guest_physical_address_end; INSERT_FRONT(device->mem_hooks,hook); return 0; } int dev_mgr_unhook_mem(struct guest_info *vm, struct vm_device *device, void *guest_physical_start, void *guest_physical_end) { struct vm_device_mem_hook *hook = device->mem_hooks; while (hook) { if (hook->guest_physical_start==guest_physical_start && hook->guest_physical_end==guest_physical_end) { DELETE(device->mem_hooks,hook); break; } } if (!hook) { // Very bad - unhooking something that doesn't exist! return -1; } /* not implemented yet return unhook_mem_port(vm->mem_map, guest_physical_start, guest_physical_end) ; */ return -1; } int dev_mgr_unhook_device(struct guest_info *vm, struct vm_device *device) { struct vm_device_io_hook *iohook=device->io_hooks; struct vm_device_mem_hook *memhook=device->mem_hooks; while (iohook) { if (dev_mgr_unhook_io(vm,device,iohook->guest_port)) { return -1; } } while (memhook) { if (dev_mgr_unhook_mem(vm,device,memhook->guest_physical_start, memhook->guest_physical_end)) { return -1; } } return 0; }