X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fdevices%2Flnx_virtio_symmod.c;h=993dcb6727a95b8052926327fec7efb728cc1551;hb=8a3dbb70c29175bad79764a0b2f3961b98138bb2;hp=d6df7a73406981bb68fa7f2ace6acb597cde579d;hpb=63fc27a4eedc44a349cf8fde14e4c1b2401b4100;p=palacios.git diff --git a/palacios/src/devices/lnx_virtio_symmod.c b/palacios/src/devices/lnx_virtio_symmod.c index d6df7a7..993dcb6 100644 --- a/palacios/src/devices/lnx_virtio_symmod.c +++ b/palacios/src/devices/lnx_virtio_symmod.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -30,6 +31,8 @@ #define NUM_QUEUES 2 struct sym_config { + uint32_t avail_mods; + uint32_t loaded_mods; } __attribute__((packed)); @@ -41,7 +44,9 @@ struct virtio_sym_state { struct vm_device * pci_bus; struct pci_device * pci_dev; - + struct v3_vm_info * vm; + struct v3_symmod_state * symmod_state; + #define NOTIFY_QUEUE 0 #define LOADER_QUEUE 1 @@ -56,10 +61,41 @@ struct virtio_sym_state { +struct symmod_cmd { +#define CMD_INV 0 +#define CMD_LOAD 1 +#define CMD_LIST 2 + uint32_t cmd; + uint32_t num_cmds; +} __attribute__((packed)); + + // structure of the symmod notifier ring structures struct symmod_hdr { uint32_t num_bytes; char name[32]; + union { + uint32_t flags; + struct { +#define V3_SYMMOD_INV (0x00) +#define V3_SYMMOD_LNX (0x01) +#define V3_SYMMOD_MOD (0x02) +#define V3_SYMMOD_SEC (0x03) + uint8_t type; + +#define V3_SYMMOD_ARCH_INV (0x00) +#define V3_SYMMOD_ARCH_i386 (0x01) +#define V3_SYMMOD_ARCH_x86_64 (0x02) + uint8_t arch; + +#define V3_SYMMOD_ACT_INV (0x00) +#define V3_SYMMOD_ACT_ADVERTISE (0x01) +#define V3_SYMMOD_ACT_LOAD (0x02) + uint8_t action; + + uint8_t rsvd; + } __attribute__((packed)); + } __attribute__((packed)); } __attribute__((packed)); @@ -76,7 +112,8 @@ static int virtio_reset(struct virtio_sym_state * virtio) { virtio->queue[1].queue_size = QUEUE_SIZE; - memset(&(virtio->sym_cfg), 0, sizeof(struct sym_config)); + virtio->sym_cfg.avail_mods = virtio->symmod_state->num_avail_capsules; + virtio->sym_cfg.loaded_mods = virtio->symmod_state->num_loaded_capsules; return 0; } @@ -103,68 +140,85 @@ static int handle_xfer_kick(struct guest_info * core, struct virtio_sym_state * PrintDebug("SYMMOD: VIRTIO SYMMOD Kick on loader queue\n"); - while (q->cur_avail_idx < q->avail->index) { - struct vring_desc * hdr_desc = NULL; - struct vring_desc * buf_desc = NULL; - struct vring_desc * status_desc = NULL; + while (q->cur_avail_idx != q->avail->index) { + struct vring_desc * cmd_desc = NULL; + struct symmod_cmd * cmd = NULL; uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % QUEUE_SIZE]; uint16_t desc_cnt = get_desc_count(q, desc_idx); - struct symmod_hdr * hdr = NULL; - int i; - uint32_t xfer_len = 0; + struct vring_desc * status_desc = NULL; uint8_t status = 0; uint8_t * status_ptr = NULL; - struct v3_sym_module * module = NULL; - uint32_t offset = 0; - - - PrintDebug("Descriptor Count=%d, index=%d\n", desc_cnt, q->cur_avail_idx % QUEUE_SIZE); + int i; + uint32_t xfer_len = 0; - if (desc_cnt < 3) { - PrintError("Symmod loads must include at least 3 descriptors (cnt=%d)\n", desc_cnt); - return -1; - } + cmd_desc = &(q->desc[desc_idx]); - hdr_desc = &(q->desc[desc_idx]); - - if (guest_pa_to_host_va(core, hdr_desc->addr_gpa, (addr_t *)&hdr) == -1) { + if (v3_gpa_to_hva(core, cmd_desc->addr_gpa, (addr_t *)&cmd) == -1) { PrintError("Could not translate SYMMOD header address\n"); return -1; } + + desc_idx = cmd_desc->next; + + if (cmd->cmd == CMD_LOAD) { + struct vring_desc * name_desc = NULL; + struct vring_desc * buf_desc = NULL; + char * name = NULL; + struct v3_sym_capsule * capsule = NULL; + uint32_t offset = 0; + - desc_idx = hdr_desc->next; + PrintDebug("Descriptor Count=%d, index=%d\n", desc_cnt, q->cur_avail_idx % QUEUE_SIZE); + + if (desc_cnt < 3) { + PrintError("Symmod loads must include at least 3 descriptors (cnt=%d)\n", desc_cnt); + return -1; + } + + name_desc = &(q->desc[desc_idx]); - module = v3_get_sym_module(core->vm_info, hdr->name); + if (v3_gpa_to_hva(core, name_desc->addr_gpa, (addr_t *)&name) == -1) { + PrintError("Could not translate SYMMOD header address\n"); + return -1; + } - for (i = 0; i < desc_cnt - 2; i++) { - uint8_t tmp_status = 0; - uint8_t * buf = NULL; + desc_idx = name_desc->next; - buf_desc = &(q->desc[desc_idx]); + capsule = v3_get_sym_capsule(core->vm_info, name); - if (guest_pa_to_host_va(core, buf_desc->addr_gpa, (addr_t *)&(buf)) == -1) { - PrintError("Could not translate buffer address\n"); - return -1; - } + for (i = 0; i < desc_cnt - 3; i++) { + uint8_t tmp_status = 0; + uint8_t * buf = NULL; - memcpy(buf, module->start_addr + offset, buf_desc->length); - PrintDebug("Copying module to virtio buffers: SRC=%p, DST=%p, len=%d\n", - (void *)(module->start_addr + offset), (void *)buf, buf_desc->length); + buf_desc = &(q->desc[desc_idx]); - if (tmp_status != 0) { - PrintError("Error loading module segment\n"); - status = tmp_status; - } + if (v3_gpa_to_hva(core, buf_desc->addr_gpa, (addr_t *)&(buf)) == -1) { + PrintError("Could not translate buffer address\n"); + return -1; + } + + memcpy(buf, capsule->start_addr + offset, buf_desc->length); + PrintDebug("Copying module to virtio buffers: SRC=%p, DST=%p, len=%d\n", + (void *)(capsule->start_addr + offset), (void *)buf, buf_desc->length); + + if (tmp_status != 0) { + PrintError("Error loading module segment\n"); + status = tmp_status; + } - offset += buf_desc->length; - xfer_len += buf_desc->length; - desc_idx = buf_desc->next; + offset += buf_desc->length; + xfer_len += buf_desc->length; + desc_idx = buf_desc->next; + } + } else { + PrintError("Invalid SYMMOD Loader command\n"); + return -1; } status_desc = &(q->desc[desc_idx]); - if (guest_pa_to_host_va(core, status_desc->addr_gpa, (addr_t *)&status_ptr) == -1) { + if (v3_gpa_to_hva(core, status_desc->addr_gpa, (addr_t *)&status_ptr) == -1) { PrintError("SYMMOD Error could not translate status address\n"); return -1; } @@ -178,6 +232,7 @@ static int handle_xfer_kick(struct guest_info * core, struct virtio_sym_state * q->used->index++; q->cur_avail_idx++; + } @@ -192,6 +247,75 @@ static int handle_xfer_kick(struct guest_info * core, struct virtio_sym_state * } + + +static int handle_notification_kick(struct guest_info * core, struct virtio_sym_state * sym_state) { + // struct virtio_queue * q = sym_state->cur_queue; + struct virtio_queue * q = &(sym_state->queue[NOTIFY_QUEUE]); + struct hashtable_iter * capsule_iter = NULL; + + PrintDebug("SYMMOD: VIRTIO SYMMOD Kick on notification queue\n"); + + capsule_iter = v3_create_htable_iter(sym_state->symmod_state->capsule_table); + + do { + uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % q->queue_size]; + struct vring_desc * hdr_desc = NULL; + struct symmod_hdr * hdr = NULL; + struct v3_sym_capsule * capsule = NULL; + + + capsule = (struct v3_sym_capsule *)v3_htable_get_iter_value(capsule_iter); + + + PrintDebug("SYMMOD: Advertising Capsule %s\n", capsule->name); + + if (capsule->type != V3_SYMMOD_LNX) { + continue; + } + + + + if (q->cur_avail_idx == q->avail->index) { + PrintError("Notification Queue Too SMALL\n"); + return -1; + } + + hdr_desc = &(q->desc[desc_idx]); + + if (v3_gpa_to_hva(core, hdr_desc->addr_gpa, (addr_t *)&hdr) == -1) { + PrintError("Could not translate SYMMOD header address\n"); + return -1; + } + + memset(hdr, 0, sizeof(struct symmod_hdr)); + + + memcpy(hdr->name, capsule->name, strlen(capsule->name)); + hdr->num_bytes = capsule->size; + hdr->flags = capsule->flags; + hdr->action = V3_SYMMOD_ACT_ADVERTISE; + + q->used->ring[q->used->index % QUEUE_SIZE].id = q->avail->ring[q->cur_avail_idx % QUEUE_SIZE]; + q->used->ring[q->used->index % QUEUE_SIZE].length = sizeof(struct symmod_hdr) ; // set to total inbound xfer length + + q->used->index++; + q->cur_avail_idx++; + + } while (v3_htable_iter_advance(capsule_iter)); + + + if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) { + PrintDebug("Raising IRQ %d\n", sym_state->pci_dev->config_header.intr_line); + v3_pci_raise_irq(sym_state->pci_bus, 0, sym_state->pci_dev); + sym_state->virtio_cfg.pci_isr = 1; + } + + + return 0; +} + + static int virtio_io_write(struct guest_info * core, uint16_t port, void * src, uint_t length, void * private_data) { struct virtio_sym_state * sym_state = (struct virtio_sym_state *)private_data; int port_idx = port % sym_state->io_range_size; @@ -228,19 +352,19 @@ static int virtio_io_write(struct guest_info * core, uint16_t port, void * src, // round up to next page boundary. sym_state->cur_queue->ring_used_addr = (sym_state->cur_queue->ring_used_addr + 0xfff) & ~0xfff; - if (guest_pa_to_host_va(core, sym_state->cur_queue->ring_desc_addr, (addr_t *)&(sym_state->cur_queue->desc)) == -1) { + if (v3_gpa_to_hva(core, sym_state->cur_queue->ring_desc_addr, (addr_t *)&(sym_state->cur_queue->desc)) == -1) { PrintError("Could not translate ring descriptor address\n"); return -1; } - if (guest_pa_to_host_va(core, sym_state->cur_queue->ring_avail_addr, (addr_t *)&(sym_state->cur_queue->avail)) == -1) { + if (v3_gpa_to_hva(core, sym_state->cur_queue->ring_avail_addr, (addr_t *)&(sym_state->cur_queue->avail)) == -1) { PrintError("Could not translate ring available address\n"); return -1; } - if (guest_pa_to_host_va(core, sym_state->cur_queue->ring_used_addr, (addr_t *)&(sym_state->cur_queue->used)) == -1) { + if (v3_gpa_to_hva(core, sym_state->cur_queue->ring_used_addr, (addr_t *)&(sym_state->cur_queue->used)) == -1) { PrintError("Could not translate ring used address\n"); return -1; } @@ -272,12 +396,17 @@ static int virtio_io_write(struct guest_info * core, uint16_t port, void * src, break; case VRING_Q_NOTIFY_PORT: { uint16_t queue_idx = *(uint16_t *)src; - + PrintDebug("SYMMOD: Handling Kick\n"); - + if (queue_idx == 0) { + if (handle_notification_kick(core, sym_state) == -1) { + PrintError("Could not handle Notification Kick\n"); + return -1; + } + sym_state->notifier_active = 1; - + } else if (queue_idx == 1) { if (handle_xfer_kick(core, sym_state) == -1) { PrintError("Could not handle Symbiotic Notification\n"); @@ -287,7 +416,7 @@ static int virtio_io_write(struct guest_info * core, uint16_t port, void * src, PrintError("Kick on invalid queue (%d)\n", queue_idx); return -1; } - + break; } case VIRTIO_STATUS_PORT: @@ -372,6 +501,8 @@ static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, u uint8_t * cfg_ptr = (uint8_t *)&(sym_state->sym_cfg); memcpy(dst, cfg_ptr + cfg_offset, length); + + V3_Print("Reading SymConfig at idx %d (val=%x)\n", cfg_offset, *(uint32_t *)cfg_ptr); } else { PrintError("Read of Unhandled Virtio Read\n"); @@ -387,17 +518,18 @@ static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, u -static int virtio_load_module(struct v3_vm_info * vm, char * name, int mod_size, void * priv_data) { +static int virtio_load_capsule(struct v3_vm_info * vm, struct v3_sym_capsule * mod, void * priv_data) { struct virtio_sym_state * virtio = (struct virtio_sym_state *)priv_data; // struct virtio_queue * q = virtio->cur_queue; struct virtio_queue * q = &(virtio->queue[NOTIFY_QUEUE]); - if (strlen(name) >= 32) { - PrintError("Module name is too long... (%d bytes) limit is 32\n", (uint32_t)strlen(name)); + + if (strlen(mod->name) >= 32) { + PrintError("Capsule name is too long... (%d bytes) limit is 32\n", (uint32_t)strlen(mod->name)); return -1; } - PrintDebug("SYMMOD: VIRTIO SYMMOD Loader: Loading Module (size=%d)\n", mod_size); + PrintDebug("SYMMOD: VIRTIO SYMMOD Loader: Loading Capsule (size=%d)\n", mod->size); //queue is not set yet if (q->ring_avail_addr == 0) { @@ -415,10 +547,12 @@ static int virtio_load_module(struct v3_vm_info * vm, char * name, int mod_size, notifier_desc = &(q->desc[notifier_idx]); - PrintDebug("SYMMOD: Notifier Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", notifier_desc, - (void *)(notifier_desc->addr_gpa), notifier_desc->length, notifier_desc->flags, notifier_desc->next); + PrintDebug("SYMMOD: Notifier Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", + notifier_desc, (void *)(addr_t)(notifier_desc->addr_gpa), + notifier_desc->length, notifier_desc->flags, + notifier_desc->next); - if (guest_pa_to_host_va(&(vm->cores[0]), notifier_desc->addr_gpa, (addr_t *)&(notifier)) == -1) { + if (v3_gpa_to_hva(&(vm->cores[0]), notifier_desc->addr_gpa, (addr_t *)&(notifier)) == -1) { PrintError("Could not translate receive buffer address\n"); return -1; } @@ -426,11 +560,13 @@ static int virtio_load_module(struct v3_vm_info * vm, char * name, int mod_size, // clear the notifier memset(notifier, 0, sizeof(struct symmod_hdr)); - // set the module name - memcpy(notifier->name, name, strlen(name)); + // set the capsule name + memcpy(notifier->name, mod->name, strlen(mod->name)); - // set module length - notifier->num_bytes = mod_size; + // set capsule length + notifier->num_bytes = mod->size; + notifier->flags = mod->flags; + notifier->action = V3_SYMMOD_ACT_LOAD; q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size]; @@ -452,27 +588,31 @@ static int virtio_load_module(struct v3_vm_info * vm, char * name, int mod_size, } +static int virtio_free(struct virtio_sym_state * virtio_state) { + // unregister from PCI + + V3_Free(virtio_state); + return 0; +} static struct v3_device_ops dev_ops = { - .free = NULL, - .reset = NULL, - .start = NULL, - .stop = NULL, + .free = (int (*)(void *))virtio_free, }; static struct v3_symmod_loader_ops loader_ops = { - .load_module = virtio_load_module, + .load_capsule = virtio_load_capsule, }; static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus")); struct virtio_sym_state * virtio_state = NULL; + struct v3_symmod_state * symmod_state = &(vm->sym_vm_state.symmod_state); struct pci_device * pci_dev = NULL; - char * name = v3_cfg_val(cfg, "name"); + char * dev_id = v3_cfg_val(cfg, "ID"); PrintDebug("SYMMOD: Initializing VIRTIO Symbiotic Module device\n"); @@ -484,10 +624,17 @@ static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { virtio_state = (struct virtio_sym_state *)V3_Malloc(sizeof(struct virtio_sym_state)); memset(virtio_state, 0, sizeof(struct virtio_sym_state)); - struct vm_device * dev = v3_allocate_device(name, &dev_ops, virtio_state); + virtio_state->vm = vm; + virtio_state->symmod_state = symmod_state; - if (v3_attach_device(vm, dev) == -1) { - PrintError("Could not attach device %s\n", name); + + + + struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, virtio_state); + + if (dev == NULL) { + PrintError("Could not attach device %s\n", dev_id); + V3_Free(virtio_state); return -1; } @@ -534,6 +681,7 @@ static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { if (!pci_dev) { PrintError("Could not register PCI Device\n"); + v3_remove_device(dev); return -1; } @@ -556,6 +704,9 @@ static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { virtio_state->pci_dev = pci_dev; virtio_state->pci_bus = pci_bus; } + + + V3_Print("SYMMOD: %d available sym modules\n", virtio_state->sym_cfg.avail_mods); virtio_reset(virtio_state);