Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.14-rc1 162 lines 4.4 kB view raw
1/* 2 * Copyright (C) 2012-2015 - ARM Ltd 3 * Author: Marc Zyngier <marc.zyngier@arm.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18#include <linux/compiler.h> 19#include <linux/irqchip/arm-gic.h> 20#include <linux/kvm_host.h> 21 22#include <asm/kvm_emulate.h> 23#include <asm/kvm_hyp.h> 24 25static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base) 26{ 27 struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2; 28 int nr_lr = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr; 29 u32 elrsr0, elrsr1; 30 31 elrsr0 = readl_relaxed(base + GICH_ELRSR0); 32 if (unlikely(nr_lr > 32)) 33 elrsr1 = readl_relaxed(base + GICH_ELRSR1); 34 else 35 elrsr1 = 0; 36 37#ifdef CONFIG_CPU_BIG_ENDIAN 38 cpu_if->vgic_elrsr = ((u64)elrsr0 << 32) | elrsr1; 39#else 40 cpu_if->vgic_elrsr = ((u64)elrsr1 << 32) | elrsr0; 41#endif 42} 43 44static void __hyp_text save_lrs(struct kvm_vcpu *vcpu, void __iomem *base) 45{ 46 struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2; 47 int i; 48 u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs; 49 50 for (i = 0; i < used_lrs; i++) { 51 if (cpu_if->vgic_elrsr & (1UL << i)) 52 cpu_if->vgic_lr[i] &= ~GICH_LR_STATE; 53 else 54 cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4)); 55 56 writel_relaxed(0, base + GICH_LR0 + (i * 4)); 57 } 58} 59 60/* vcpu is already in the HYP VA space */ 61void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu) 62{ 63 struct kvm *kvm = kern_hyp_va(vcpu->kvm); 64 struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2; 65 struct vgic_dist *vgic = &kvm->arch.vgic; 66 void __iomem *base = kern_hyp_va(vgic->vctrl_base); 67 u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs; 68 69 if (!base) 70 return; 71 72 if (used_lrs) { 73 cpu_if->vgic_apr = readl_relaxed(base + GICH_APR); 74 75 save_elrsr(vcpu, base); 76 save_lrs(vcpu, base); 77 78 writel_relaxed(0, base + GICH_HCR); 79 } else { 80 cpu_if->vgic_elrsr = ~0UL; 81 cpu_if->vgic_apr = 0; 82 } 83} 84 85/* vcpu is already in the HYP VA space */ 86void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu) 87{ 88 struct kvm *kvm = kern_hyp_va(vcpu->kvm); 89 struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2; 90 struct vgic_dist *vgic = &kvm->arch.vgic; 91 void __iomem *base = kern_hyp_va(vgic->vctrl_base); 92 int i; 93 u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs; 94 95 if (!base) 96 return; 97 98 if (used_lrs) { 99 writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR); 100 writel_relaxed(cpu_if->vgic_apr, base + GICH_APR); 101 for (i = 0; i < used_lrs; i++) { 102 writel_relaxed(cpu_if->vgic_lr[i], 103 base + GICH_LR0 + (i * 4)); 104 } 105 } 106} 107 108#ifdef CONFIG_ARM64 109/* 110 * __vgic_v2_perform_cpuif_access -- perform a GICV access on behalf of the 111 * guest. 112 * 113 * @vcpu: the offending vcpu 114 * 115 * Returns: 116 * 1: GICV access successfully performed 117 * 0: Not a GICV access 118 * -1: Illegal GICV access 119 */ 120int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu) 121{ 122 struct kvm *kvm = kern_hyp_va(vcpu->kvm); 123 struct vgic_dist *vgic = &kvm->arch.vgic; 124 phys_addr_t fault_ipa; 125 void __iomem *addr; 126 int rd; 127 128 /* Build the full address */ 129 fault_ipa = kvm_vcpu_get_fault_ipa(vcpu); 130 fault_ipa |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0); 131 132 /* If not for GICV, move on */ 133 if (fault_ipa < vgic->vgic_cpu_base || 134 fault_ipa >= (vgic->vgic_cpu_base + KVM_VGIC_V2_CPU_SIZE)) 135 return 0; 136 137 /* Reject anything but a 32bit access */ 138 if (kvm_vcpu_dabt_get_as(vcpu) != sizeof(u32)) 139 return -1; 140 141 /* Not aligned? Don't bother */ 142 if (fault_ipa & 3) 143 return -1; 144 145 rd = kvm_vcpu_dabt_get_rd(vcpu); 146 addr = kern_hyp_va((kern_hyp_va(&kvm_vgic_global_state))->vcpu_base_va); 147 addr += fault_ipa - vgic->vgic_cpu_base; 148 149 if (kvm_vcpu_dabt_iswrite(vcpu)) { 150 u32 data = vcpu_data_guest_to_host(vcpu, 151 vcpu_get_reg(vcpu, rd), 152 sizeof(u32)); 153 writel_relaxed(data, addr); 154 } else { 155 u32 data = readl_relaxed(addr); 156 vcpu_set_reg(vcpu, rd, vcpu_data_host_to_guest(vcpu, data, 157 sizeof(u32))); 158 } 159 160 return 1; 161} 162#endif