static void pl011_set_irq(struct pl011_state *s, u32 level, u32 enabled) { if (level & enabled) { vmm_devemu_emulate_irq(s->guest, s->irq, 1); } else { vmm_devemu_emulate_irq(s->guest, s->irq, 0); } }
/* Update interrupts. */ static void pl190_update(struct pl190_emulator_state *s) { u32 status; struct vmm_vcpu *vcpu = vmm_manager_guest_vcpu(s->guest, 0); if (!vcpu) { return; } status = pl190_irq_status(s); if (s->is_child_pic) { vmm_devemu_emulate_irq(s->guest, s->parent_irq, status); } else { if (status & s->prio_mask[s->priority]) { vmm_vcpu_irq_assert(vcpu, s->parent_irq, 0x0); } else { vmm_vcpu_irq_deassert(vcpu, s->parent_irq); } if ((s->level | s->soft_level) & s->fiq_select) { vmm_vcpu_irq_assert(vcpu, s->parent_irq + 1, 0x0); } else { vmm_vcpu_irq_deassert(vcpu, s->parent_irq + 1); } } }
int virtio_pci_config_read(struct virtio_pci_dev *m, u32 offset, void *dst, u32 dst_len) { int rc = VMM_OK; switch (offset) { case VMM_VIRTIO_PCI_HOST_FEATURES: *(u32 *)dst = m->dev.emu->get_host_features(&m->dev); break; case VMM_VIRTIO_PCI_QUEUE_PFN: *(u32 *)dst = m->dev.emu->get_pfn_vq(&m->dev, m->config.queue_sel); break; case VMM_VIRTIO_PCI_QUEUE_NUM: *(u32 *)dst = m->dev.emu->get_size_vq(&m->dev, m->config.queue_sel); break; case VMM_VIRTIO_PCI_STATUS: *(u32 *)dst = m->config.status; break; case VMM_VIRTIO_PCI_ISR: /* reading from the ISR also clears it. */ *(u32 *)dst = m->config.interrupt_state; m->config.interrupt_state = 0; vmm_devemu_emulate_irq(m->guest, m->irq, 0); break; default: vmm_printf("%s: guest=%s offset=0x%x\n", __func__, m->guest->name, offset); rc = VMM_EINVALID; break; } return rc; }
/* Update interrupts. */ static void pl190_emulator_update(struct pl190_emulator_state *s) { u32 irqset, fiqset, status; struct vmm_vcpu *vcpu = vmm_manager_guest_vcpu(s->guest, 0); if (!vcpu) { return; } status = pl190_emulator_irq_status(s); if (s->is_child_pic) { vmm_devemu_emulate_irq(s->guest, s->parent_irq, status); } else { irqset = ((status & s->prio_mask[s->priority]) != 0); if (irqset) { vmm_vcpu_irq_assert(vcpu, CPU_EXTERNAL_IRQ, 0x0); } else { vmm_vcpu_irq_deassert(vcpu, CPU_EXTERNAL_IRQ); } fiqset = (((s->level | s->soft_level) & s->fiq_select) != 0); if (fiqset) { vmm_vcpu_irq_assert(vcpu, CPU_EXTERNAL_FIQ, 0x0); } else { vmm_vcpu_irq_deassert(vcpu, CPU_EXTERNAL_FIQ); } } }
static int virtio_mmio_reset(struct vmm_emudev *edev) { struct virtio_mmio_dev *m = edev->priv; m->config.interrupt_state = 0x0; vmm_devemu_emulate_irq(m->guest, m->irq, 0); return virtio_reset(&m->dev); }
static int virtio_mmio_notify(struct virtio_device *dev, u32 vq) { struct virtio_mmio_dev *m = dev->tra_data; m->config.interrupt_state |= VIRTIO_MMIO_INT_VRING; vmm_devemu_emulate_irq(m->guest, m->irq, 1); return VMM_OK; }
static int virtio_pci_bar_reset(struct vmm_emudev *edev) { struct virtio_pci_dev *m = edev->priv; m->config.queue_sel = 0x0; m->config.interrupt_state = 0x0; m->config.status = 0x0; vmm_devemu_emulate_irq(m->guest, m->irq, 0); return vmm_virtio_reset(&m->dev); }
static int virtio_mmio_config_write(struct virtio_mmio_dev *m, physical_addr_t offset, void *src, u32 src_len) { int rc = VMM_OK; u32 val = vmm_cpu_to_le32(*(u32 *)(src)); switch (offset) { case VIRTIO_MMIO_HOST_FEATURES_SEL: case VIRTIO_MMIO_GUEST_FEATURES_SEL: case VIRTIO_MMIO_QUEUE_SEL: case VIRTIO_MMIO_STATUS: *(u32 *)(((void *)&m->config) + offset) = val; break; case VIRTIO_MMIO_GUEST_FEATURES: if (m->config.guest_features_sel == 0) { m->dev.emu->set_guest_features(&m->dev, val); } break; case VIRTIO_MMIO_GUEST_PAGE_SIZE: m->config.guest_page_size = val; break; case VIRTIO_MMIO_QUEUE_NUM: m->config.queue_num = val; m->dev.emu->set_size_vq(&m->dev, m->config.queue_sel, m->config.queue_num); break; case VIRTIO_MMIO_QUEUE_ALIGN: m->config.queue_align = val; break; case VIRTIO_MMIO_QUEUE_PFN: m->dev.emu->init_vq(&m->dev, m->config.queue_sel, m->config.guest_page_size, m->config.queue_align, val); break; case VIRTIO_MMIO_QUEUE_NOTIFY: m->dev.emu->notify_vq(&m->dev, val); break; case VIRTIO_MMIO_INTERRUPT_ACK: m->config.interrupt_state &= ~val; vmm_devemu_emulate_irq(m->guest, m->irq, 0); break; default: break; }; return rc; }
/* Call update function with lock held */ static void pl061_update(struct pl061_state *s) { int line; u8 changed, mask, out; /* Outputs float high. */ /* FIXME: This is board dependent. */ out = (s->data & s->dir) | ~s->dir; changed = s->old_data ^ out; if (!changed) return; s->old_data = out; for (line = 0; line < 8; line++) { mask = 1 << line; if (changed & mask) { vmm_devemu_emulate_irq(s->guest, s->out_irq[line], (out & mask) != 0); } } /* FIXME: Implement input interrupts. */ }
static void pl031_update(struct pl031_state *s) { vmm_devemu_emulate_irq(s->guest, s->irq, s->is & s->im); }
static int virtio_mmio_config_write(struct virtio_mmio_dev *m, u32 offset, void *src, u32 src_len) { int rc = VMM_OK; u32 val = *(u32 *)(src); switch (offset) { case VMM_VIRTIO_MMIO_HOST_FEATURES_SEL: m->config.host_features_sel = val; break; case VMM_VIRTIO_MMIO_GUEST_FEATURES_SEL: m->config.guest_features_sel = val; break; case VMM_VIRTIO_MMIO_GUEST_FEATURES: if (m->config.guest_features_sel == 0) { m->dev.emu->set_guest_features(&m->dev, val); } break; case VMM_VIRTIO_MMIO_GUEST_PAGE_SIZE: m->config.guest_page_size = val; break; case VMM_VIRTIO_MMIO_QUEUE_SEL: m->config.queue_sel = val; break; case VMM_VIRTIO_MMIO_QUEUE_NUM: m->config.queue_num = val; m->dev.emu->set_size_vq(&m->dev, m->config.queue_sel, m->config.queue_num); break; case VMM_VIRTIO_MMIO_QUEUE_ALIGN: m->config.queue_align = val; break; case VMM_VIRTIO_MMIO_QUEUE_PFN: m->dev.emu->init_vq(&m->dev, m->config.queue_sel, m->config.guest_page_size, m->config.queue_align, val); break; case VMM_VIRTIO_MMIO_QUEUE_NOTIFY: m->dev.emu->notify_vq(&m->dev, val); break; case VMM_VIRTIO_MMIO_INTERRUPT_ACK: m->config.interrupt_state &= ~val; vmm_devemu_emulate_irq(m->guest, m->irq, 0); break; case VMM_VIRTIO_MMIO_STATUS: if (val != m->config.status) { m->dev.emu->status_changed(&m->dev, val); } m->config.status = val; break; default: vmm_printf("%s: guest=%s offset=0x%x\n", __func__, m->guest->name, offset); rc = VMM_EINVALID; break; }; return rc; }