static void kvm_arm_its_reset(DeviceState *dev) { GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); KVMARMITSClass *c = KVM_ARM_ITS_GET_CLASS(s); int i; c->parent_reset(dev); if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_ITS_CTRL_RESET)) { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_ITS_CTRL_RESET, NULL, true, &error_abort); return; } error_report("ITS KVM: full reset is not supported by the host kernel"); if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_CTLR)) { return; } kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_CTLR, &s->ctlr, true, &error_abort); kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_CBASER, &s->cbaser, true, &error_abort); for (i = 0; i < 8; i++) { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_BASER + i * 8, &s->baser[i], true, &error_abort); } }
/** * kvm_arm_its_post_load - Restore both the ITS registers and tables */ static void kvm_arm_its_post_load(GICv3ITSState *s) { int i; kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_IIDR, &s->iidr, true, &error_abort); /* * must be written before GITS_CREADR since GITS_CBASER write * access resets GITS_CREADR. */ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_CBASER, &s->cbaser, true, &error_abort); kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_CREADR, &s->creadr, true, &error_abort); kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_CWRITER, &s->cwriter, true, &error_abort); for (i = 0; i < 8; i++) { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_BASER + i * 8, &s->baser[i], true, &error_abort); } kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_ITS_RESTORE_TABLES, NULL, true, &error_abort); kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_CTLR, &s->ctlr, true, &error_abort); }
static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) { GICv3State *s = KVM_ARM_GICV3(dev); KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s); Error *local_err = NULL; DPRINTF("kvm_arm_gicv3_realize\n"); kgc->parent_realize(dev, &local_err); if (local_err) { error_propagate(errp, local_err); return; } if (s->security_extn) { error_setg(errp, "the in-kernel VGICv3 does not implement the " "security extensions"); return; } gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL); /* Try to create the device via the device control API */ s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V3, false); if (s->dev_fd < 0) { error_setg_errno(errp, -s->dev_fd, "error creating in-kernel VGIC"); return; } kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, &s->num_irq, true); /* Tell the kernel to complete VGIC initialization now */ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); kvm_arm_register_device(&s->iomem_dist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd); kvm_arm_register_device(&s->iomem_redist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_REDIST, s->dev_fd); }
/** * kvm_arm_its_pre_save - handles the saving of ITS registers. * ITS tables are flushed into guest RAM separately and earlier, * through the VM change state handler, since at the moment pre_save() * is called, the guest RAM has already been saved. */ static void kvm_arm_its_pre_save(GICv3ITSState *s) { int i; for (i = 0; i < 8; i++) { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_BASER + i * 8, &s->baser[i], false, &error_abort); } kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_CTLR, &s->ctlr, false, &error_abort); kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_CBASER, &s->cbaser, false, &error_abort); kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_CREADR, &s->creadr, false, &error_abort); kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_CWRITER, &s->cwriter, false, &error_abort); kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_IIDR, &s->iidr, false, &error_abort); }
/** * vm_change_state_handler - VM change state callback aiming at flushing * ITS tables into guest RAM * * The tables get flushed to guest RAM whenever the VM gets stopped. */ static void vm_change_state_handler(void *opaque, int running, RunState state) { GICv3ITSState *s = (GICv3ITSState *)opaque; Error *err = NULL; if (running) { return; } kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_ITS_SAVE_TABLES, NULL, true, &err); if (err) { error_report_err(err); } }
static void kvm_arm_its_realize(DeviceState *dev, Error **errp) { GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); Error *local_err = NULL; s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_ITS, false); if (s->dev_fd < 0) { error_setg_errno(errp, -s->dev_fd, "error creating in-kernel ITS"); return; } /* explicit init of the ITS */ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true, &error_abort); /* register the base address */ kvm_arm_register_device(&s->iomem_its_cntrl, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_ITS_ADDR_TYPE, s->dev_fd); gicv3_its_init_mmio(s, NULL); if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_CTLR)) { error_setg(&s->migration_blocker, "This operating system kernel " "does not support vITS migration"); migrate_add_blocker(s->migration_blocker, &local_err); if (local_err) { error_propagate(errp, local_err); error_free(s->migration_blocker); return; } } else { qemu_add_vm_change_state_handler(vm_change_state_handler, s); } kvm_msi_use_devid = true; kvm_gsi_direct_mapping = false; kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); }
static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) { GICv3State *s = KVM_ARM_GICV3(dev); KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s); Error *local_err = NULL; int i; DPRINTF("kvm_arm_gicv3_realize\n"); kgc->parent_realize(dev, &local_err); if (local_err) { error_propagate(errp, local_err); return; } if (s->security_extn) { error_setg(errp, "the in-kernel VGICv3 does not implement the " "security extensions"); return; } gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL); /* Block migration of a KVM GICv3 device: the API for saving and restoring * the state in the kernel is not yet finalised in the kernel or * implemented in QEMU. */ error_setg(&s->migration_blocker, "vGICv3 migration is not implemented"); migrate_add_blocker(s->migration_blocker, &local_err); if (local_err) { error_propagate(errp, local_err); error_free(s->migration_blocker); return; } /* Try to create the device via the device control API */ s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V3, false); if (s->dev_fd < 0) { error_setg_errno(errp, -s->dev_fd, "error creating in-kernel VGIC"); return; } kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, &s->num_irq, true); /* Tell the kernel to complete VGIC initialization now */ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); kvm_arm_register_device(&s->iomem_dist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd); kvm_arm_register_device(&s->iomem_redist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_REDIST, s->dev_fd); if (kvm_has_gsi_routing()) { /* set up irq routing */ kvm_init_irq_routing(kvm_state); for (i = 0; i < s->num_irq - GIC_INTERNAL; ++i) { kvm_irqchip_add_irq_route(kvm_state, i, 0, i); } kvm_gsi_routing_allowed = true; kvm_irqchip_commit_routes(kvm_state); } }
static void kvm_gicd_access(GICState *s, int offset, int cpu, uint32_t *val, bool write) { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, KVM_VGIC_ATTR(offset, cpu), val, write); }