]> git.baikalelectronics.ru Git - kernel.git/commitdiff
KVM: arm/arm64: Keep GICv2 HYP VAs in kvm_vgic_global_state
authorMarc Zyngier <marc.zyngier@arm.com>
Mon, 4 Dec 2017 16:43:23 +0000 (16:43 +0000)
committerMarc Zyngier <marc.zyngier@arm.com>
Mon, 19 Mar 2018 13:04:06 +0000 (13:04 +0000)
As we're about to change the way we map devices at HYP, we need
to move away from kern_hyp_va on an IO address.

One way of achieving this is to store the VAs in kvm_vgic_global_state,
and use that directly from the HYP code. This requires a small change
to create_hyp_io_mappings so that it can also return a HYP VA.

We take this opportunity to nuke the vctrl_base field in the emulated
distributor, as it is not used anymore.

Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
arch/arm/include/asm/kvm_mmu.h
arch/arm64/include/asm/kvm_mmu.h
arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c
include/kvm/arm_vgic.h
virt/kvm/arm/mmu.c
virt/kvm/arm/vgic/vgic-init.c
virt/kvm/arm/vgic/vgic-v2.c

index bf17ad83d2f0976057b857a610380cc85dfc7e70..4c5c8a386baf703eb5c9a26de19467b33ae81b36 100644 (file)
@@ -51,7 +51,8 @@
 
 int create_hyp_mappings(void *from, void *to, pgprot_t prot);
 int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
-                          void __iomem **kaddr);
+                          void __iomem **kaddr,
+                          void __iomem **haddr);
 void free_hyp_pgds(void);
 
 void stage2_unmap_vm(struct kvm *kvm);
index 8d5f9934d8197331d7da81b780f3f7e9913e8f19..3836641dd6f065ffb9921e5fba1e67fc386370e4 100644 (file)
@@ -141,7 +141,8 @@ static inline unsigned long __kern_hyp_va(unsigned long v)
 
 int create_hyp_mappings(void *from, void *to, pgprot_t prot);
 int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
-                          void __iomem **kaddr);
+                          void __iomem **kaddr,
+                          void __iomem **haddr);
 void free_hyp_pgds(void);
 
 void stage2_unmap_vm(struct kvm *kvm);
index 10eb2e96b3e6b2a6b09877d45d59ca9001d9e746..86801b6055d6dc714a1bb98640caee9985965092 100644 (file)
@@ -60,7 +60,7 @@ int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
                return -1;
 
        rd = kvm_vcpu_dabt_get_rd(vcpu);
-       addr  = kern_hyp_va(hyp_symbol_addr(kvm_vgic_global_state)->vcpu_base_va);
+       addr  = hyp_symbol_addr(kvm_vgic_global_state)->vcpu_hyp_va;
        addr += fault_ipa - vgic->vgic_cpu_base;
 
        if (kvm_vcpu_dabt_iswrite(vcpu)) {
index ac98ae46bfb7353b53d6eb82dd1f1e3093427ac2..87d2ad0a4292e3785ff8af94d2dcbc7f72388821 100644 (file)
@@ -57,11 +57,15 @@ struct vgic_global {
        /* Physical address of vgic virtual cpu interface */
        phys_addr_t             vcpu_base;
 
-       /* GICV mapping */
+       /* GICV mapping, kernel VA */
        void __iomem            *vcpu_base_va;
+       /* GICV mapping, HYP VA */
+       void __iomem            *vcpu_hyp_va;
 
-       /* virtual control interface mapping */
+       /* virtual control interface mapping, kernel VA */
        void __iomem            *vctrl_base;
+       /* virtual control interface mapping, HYP VA */
+       void __iomem            *vctrl_hyp;
 
        /* Number of implemented list registers */
        int                     nr_lr;
@@ -209,10 +213,6 @@ struct vgic_dist {
 
        int                     nr_spis;
 
-       /* TODO: Consider moving to global state */
-       /* Virtual control interface mapping */
-       void __iomem            *vctrl_base;
-
        /* base addresses in guest physical address space: */
        gpa_t                   vgic_dist_base;         /* distributor */
        union {
index 2bc32bdf932acf3baca7392a0018d9db472eac09..52b0ee31ebee0d77a2f07775af9dd08783d02659 100644 (file)
@@ -713,28 +713,38 @@ int create_hyp_mappings(void *from, void *to, pgprot_t prot)
  * @phys_addr: The physical start address which gets mapped
  * @size:      Size of the region being mapped
  * @kaddr:     Kernel VA for this mapping
- *
- * The resulting HYP VA is the same as the kernel VA, modulo
- * HYP_PAGE_OFFSET.
+ * @haddr:     HYP VA for this mapping
  */
 int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
-                          void __iomem **kaddr)
+                          void __iomem **kaddr,
+                          void __iomem **haddr)
 {
        unsigned long start, end;
+       int ret;
 
        *kaddr = ioremap(phys_addr, size);
        if (!*kaddr)
                return -ENOMEM;
 
        if (is_kernel_in_hyp_mode()) {
+               *haddr = *kaddr;
                return 0;
        }
 
 
        start = kern_hyp_va((unsigned long)*kaddr);
        end = kern_hyp_va((unsigned long)*kaddr + size);
-       return __create_hyp_mappings(hyp_pgd, PTRS_PER_PGD, start, end,
+       ret = __create_hyp_mappings(hyp_pgd, PTRS_PER_PGD, start, end,
                                     __phys_to_pfn(phys_addr), PAGE_HYP_DEVICE);
+
+       if (ret) {
+               iounmap(*kaddr);
+               *kaddr = NULL;
+               return ret;
+       }
+
+       *haddr = (void __iomem *)start;
+       return 0;
 }
 
 /**
index 3e8209a075858aa87a21b36a9940aa5e12eaa620..68378fe17a0e7e5b0be896863b94913bceb901c9 100644 (file)
@@ -166,12 +166,6 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
        kvm->arch.vgic.in_kernel = true;
        kvm->arch.vgic.vgic_model = type;
 
-       /*
-        * kvm_vgic_global_state.vctrl_base is set on vgic probe (kvm_arch_init)
-        * it is stored in distributor struct for asm save/restore purpose
-        */
-       kvm->arch.vgic.vctrl_base = kvm_vgic_global_state.vctrl_base;
-
        kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
        kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
        kvm->arch.vgic.vgic_redist_base = VGIC_ADDR_UNDEF;
index 66532f2f0e40de00717b5aa52a3d2c5cbb52cc58..96e144f9d93d2226cdc441fb0acc516f02644d69 100644 (file)
@@ -363,7 +363,8 @@ int vgic_v2_probe(const struct gic_kvm_info *info)
 
                ret = create_hyp_io_mappings(info->vcpu.start,
                                             resource_size(&info->vcpu),
-                                            &kvm_vgic_global_state.vcpu_base_va);
+                                            &kvm_vgic_global_state.vcpu_base_va,
+                                            &kvm_vgic_global_state.vcpu_hyp_va);
                if (ret) {
                        kvm_err("Cannot map GICV into hyp\n");
                        goto out;
@@ -374,7 +375,8 @@ int vgic_v2_probe(const struct gic_kvm_info *info)
 
        ret = create_hyp_io_mappings(info->vctrl.start,
                                     resource_size(&info->vctrl),
-                                    &kvm_vgic_global_state.vctrl_base);
+                                    &kvm_vgic_global_state.vctrl_base,
+                                    &kvm_vgic_global_state.vctrl_hyp);
        if (ret) {
                kvm_err("Cannot map VCTRL into hyp\n");
                goto out;
@@ -429,9 +431,7 @@ static void save_lrs(struct kvm_vcpu *vcpu, void __iomem *base)
 
 void vgic_v2_save_state(struct kvm_vcpu *vcpu)
 {
-       struct kvm *kvm = vcpu->kvm;
-       struct vgic_dist *vgic = &kvm->arch.vgic;
-       void __iomem *base = vgic->vctrl_base;
+       void __iomem *base = kvm_vgic_global_state.vctrl_base;
        u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 
        if (!base)
@@ -445,10 +445,8 @@ void vgic_v2_save_state(struct kvm_vcpu *vcpu)
 
 void vgic_v2_restore_state(struct kvm_vcpu *vcpu)
 {
-       struct kvm *kvm = vcpu->kvm;
-       struct vgic_dist *vgic = &kvm->arch.vgic;
        struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
-       void __iomem *base = vgic->vctrl_base;
+       void __iomem *base = kvm_vgic_global_state.vctrl_base;
        u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
        int i;
 
@@ -467,17 +465,17 @@ void vgic_v2_restore_state(struct kvm_vcpu *vcpu)
 void vgic_v2_load(struct kvm_vcpu *vcpu)
 {
        struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
-       struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
 
-       writel_relaxed(cpu_if->vgic_vmcr, vgic->vctrl_base + GICH_VMCR);
-       writel_relaxed(cpu_if->vgic_apr, vgic->vctrl_base + GICH_APR);
+       writel_relaxed(cpu_if->vgic_vmcr,
+                      kvm_vgic_global_state.vctrl_base + GICH_VMCR);
+       writel_relaxed(cpu_if->vgic_apr,
+                      kvm_vgic_global_state.vctrl_base + GICH_APR);
 }
 
 void vgic_v2_put(struct kvm_vcpu *vcpu)
 {
        struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
-       struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
 
-       cpu_if->vgic_vmcr = readl_relaxed(vgic->vctrl_base + GICH_VMCR);
-       cpu_if->vgic_apr = readl_relaxed(vgic->vctrl_base + GICH_APR);
+       cpu_if->vgic_vmcr = readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VMCR);
+       cpu_if->vgic_apr = readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_APR);
 }