Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a07d3b07 authored by Marc Zyngier's avatar Marc Zyngier Committed by Christoffer Dall
Browse files

arm64: KVM: vgic-v2: Enable GICV access from HYP if access from guest is unsafe



So far, we've been disabling KVM on systems where the GICV region couldn't
be safely given to a guest. Now that we're able to handle this access
safely by emulating it in HYP, we can enable this feature when we detect
an unsafe configuration.

Reviewed-by: default avatarChristoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
Signed-off-by: default avatarChristoffer Dall <christoffer.dall@linaro.org>
parent bf8feb39
Loading
Loading
Loading
Loading
+42 −27
Original line number Diff line number Diff line
@@ -278,6 +278,7 @@ int vgic_v2_map_resources(struct kvm *kvm)
		goto out;
	}

	if (!static_branch_unlikely(&vgic_v2_cpuif_trap)) {
		ret = kvm_phys_addr_ioremap(kvm, dist->vgic_cpu_base,
					    kvm_vgic_global_state.vcpu_base,
					    KVM_VGIC_V2_CPU_SIZE, true);
@@ -285,6 +286,7 @@ int vgic_v2_map_resources(struct kvm *kvm)
			kvm_err("Unable to remap VGIC CPU to VCPU\n");
			goto out;
		}
	}

	dist->ready = true;

@@ -312,45 +314,51 @@ int vgic_v2_probe(const struct gic_kvm_info *info)
		return -ENXIO;
	}

	if (!PAGE_ALIGNED(info->vcpu.start)) {
		kvm_err("GICV physical address 0x%llx not page aligned\n",
			(unsigned long long)info->vcpu.start);
		return -ENXIO;
	if (!PAGE_ALIGNED(info->vcpu.start) ||
	    !PAGE_ALIGNED(resource_size(&info->vcpu))) {
		kvm_info("GICV region size/alignment is unsafe, using trapping (reduced performance)\n");
		kvm_vgic_global_state.vcpu_base_va = ioremap(info->vcpu.start,
							     resource_size(&info->vcpu));
		if (!kvm_vgic_global_state.vcpu_base_va) {
			kvm_err("Cannot ioremap GICV\n");
			return -ENOMEM;
		}

	if (!PAGE_ALIGNED(resource_size(&info->vcpu))) {
		kvm_err("GICV size 0x%llx not a multiple of page size 0x%lx\n",
			(unsigned long long)resource_size(&info->vcpu),
			PAGE_SIZE);
		return -ENXIO;
		ret = create_hyp_io_mappings(kvm_vgic_global_state.vcpu_base_va,
					     kvm_vgic_global_state.vcpu_base_va + resource_size(&info->vcpu),
					     info->vcpu.start);
		if (ret) {
			kvm_err("Cannot map GICV into hyp\n");
			goto out;
		}

		static_branch_enable(&vgic_v2_cpuif_trap);
	}

	kvm_vgic_global_state.vctrl_base = ioremap(info->vctrl.start,
						   resource_size(&info->vctrl));
	if (!kvm_vgic_global_state.vctrl_base) {
		kvm_err("Cannot ioremap GICH\n");
		return -ENOMEM;
		ret = -ENOMEM;
		goto out;
	}

	vtr = readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VTR);
	kvm_vgic_global_state.nr_lr = (vtr & 0x3f) + 1;

	ret = kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
	if (ret) {
		kvm_err("Cannot register GICv2 KVM device\n");
		iounmap(kvm_vgic_global_state.vctrl_base);
		return ret;
	}

	ret = create_hyp_io_mappings(kvm_vgic_global_state.vctrl_base,
				     kvm_vgic_global_state.vctrl_base +
					 resource_size(&info->vctrl),
				     info->vctrl.start);
	if (ret) {
		kvm_err("Cannot map VCTRL into hyp\n");
		kvm_unregister_device_ops(KVM_DEV_TYPE_ARM_VGIC_V2);
		iounmap(kvm_vgic_global_state.vctrl_base);
		return ret;
		goto out;
	}

	ret = kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
	if (ret) {
		kvm_err("Cannot register GICv2 KVM device\n");
		goto out;
	}

	kvm_vgic_global_state.can_emulate_gicv2 = true;
@@ -361,4 +369,11 @@ int vgic_v2_probe(const struct gic_kvm_info *info)
	kvm_info("vgic-v2@%llx\n", info->vctrl.start);

	return 0;
out:
	if (kvm_vgic_global_state.vctrl_base)
		iounmap(kvm_vgic_global_state.vctrl_base);
	if (kvm_vgic_global_state.vcpu_base_va)
		iounmap(kvm_vgic_global_state.vcpu_base_va);

	return ret;
}