|
@@ -565,7 +565,7 @@ unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
|
|
|
*
|
|
|
* Return 0 on success, -ERRNO otherwise.
|
|
|
*/
|
|
|
-static int vgic_register_redist_iodev(struct kvm_vcpu *vcpu)
|
|
|
+int vgic_register_redist_iodev(struct kvm_vcpu *vcpu)
|
|
|
{
|
|
|
struct kvm *kvm = vcpu->kvm;
|
|
|
struct vgic_dist *vgic = &kvm->arch.vgic;
|
|
@@ -574,6 +574,18 @@ static int vgic_register_redist_iodev(struct kvm_vcpu *vcpu)
|
|
|
gpa_t rd_base, sgi_base;
|
|
|
int ret;
|
|
|
|
|
|
+ /*
|
|
|
+ * We may be creating VCPUs before having set the base address for the
|
|
|
+ * redistributor region, in which case we will come back to this
|
|
|
+ * function for all VCPUs when the base address is set. Just return
|
|
|
+ * without doing any work for now.
|
|
|
+ */
|
|
|
+ if (IS_VGIC_ADDR_UNDEF(vgic->vgic_redist_base))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (!vgic_v3_check_base(kvm))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
rd_base = vgic->vgic_redist_base + kvm_vcpu_get_idx(vcpu) * SZ_64K * 2;
|
|
|
sgi_base = rd_base + SZ_64K;
|
|
|
|
|
@@ -619,7 +631,7 @@ static void vgic_unregister_redist_iodev(struct kvm_vcpu *vcpu)
|
|
|
kvm_io_bus_unregister_dev(vcpu->kvm, KVM_MMIO_BUS, &sgi_dev->dev);
|
|
|
}
|
|
|
|
|
|
-int vgic_register_redist_iodevs(struct kvm *kvm)
|
|
|
+static int vgic_register_all_redist_iodevs(struct kvm *kvm)
|
|
|
{
|
|
|
struct kvm_vcpu *vcpu;
|
|
|
int c, ret = 0;
|
|
@@ -641,6 +653,33 @@ int vgic_register_redist_iodevs(struct kvm *kvm)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+int vgic_v3_set_redist_base(struct kvm *kvm, u64 addr)
|
|
|
+{
|
|
|
+ struct vgic_dist *vgic = &kvm->arch.vgic;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ /* vgic_check_ioaddr makes sure we don't do this twice */
|
|
|
+ ret = vgic_check_ioaddr(kvm, &vgic->vgic_redist_base, addr, SZ_64K);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ vgic->vgic_redist_base = addr;
|
|
|
+ if (!vgic_v3_check_base(kvm)) {
|
|
|
+ vgic->vgic_redist_base = VGIC_ADDR_UNDEF;
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Register iodevs for each existing VCPU. Adding more VCPUs
|
|
|
+ * afterwards will register the iodevs when needed.
|
|
|
+ */
|
|
|
+ ret = vgic_register_all_redist_iodevs(kvm);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
|
|
|
{
|
|
|
const struct vgic_register_region *region;
|