vgic-v2-cpuif-proxy.c 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  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. #include <linux/compiler.h>
  18. #include <linux/irqchip/arm-gic.h>
  19. #include <linux/kvm_host.h>
  20. #include <linux/swab.h>
  21. #include <asm/kvm_emulate.h>
  22. #include <asm/kvm_hyp.h>
  23. #include <asm/kvm_mmu.h>
  24. static bool __hyp_text __is_be(struct kvm_vcpu *vcpu)
  25. {
  26. if (vcpu_mode_is_32bit(vcpu))
  27. return !!(read_sysreg_el2(spsr) & PSR_AA32_E_BIT);
  28. return !!(read_sysreg(SCTLR_EL1) & SCTLR_ELx_EE);
  29. }
  30. /*
  31. * __vgic_v2_perform_cpuif_access -- perform a GICV access on behalf of the
  32. * guest.
  33. *
  34. * @vcpu: the offending vcpu
  35. *
  36. * Returns:
  37. * 1: GICV access successfully performed
  38. * 0: Not a GICV access
  39. * -1: Illegal GICV access
  40. */
  41. int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
  42. {
  43. struct kvm *kvm = kern_hyp_va(vcpu->kvm);
  44. struct vgic_dist *vgic = &kvm->arch.vgic;
  45. phys_addr_t fault_ipa;
  46. void __iomem *addr;
  47. int rd;
  48. /* Build the full address */
  49. fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
  50. fault_ipa |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0);
  51. /* If not for GICV, move on */
  52. if (fault_ipa < vgic->vgic_cpu_base ||
  53. fault_ipa >= (vgic->vgic_cpu_base + KVM_VGIC_V2_CPU_SIZE))
  54. return 0;
  55. /* Reject anything but a 32bit access */
  56. if (kvm_vcpu_dabt_get_as(vcpu) != sizeof(u32))
  57. return -1;
  58. /* Not aligned? Don't bother */
  59. if (fault_ipa & 3)
  60. return -1;
  61. rd = kvm_vcpu_dabt_get_rd(vcpu);
  62. addr = hyp_symbol_addr(kvm_vgic_global_state)->vcpu_hyp_va;
  63. addr += fault_ipa - vgic->vgic_cpu_base;
  64. if (kvm_vcpu_dabt_iswrite(vcpu)) {
  65. u32 data = vcpu_get_reg(vcpu, rd);
  66. if (__is_be(vcpu)) {
  67. /* guest pre-swabbed data, undo this for writel() */
  68. data = swab32(data);
  69. }
  70. writel_relaxed(data, addr);
  71. } else {
  72. u32 data = readl_relaxed(addr);
  73. if (__is_be(vcpu)) {
  74. /* guest expects swabbed data */
  75. data = swab32(data);
  76. }
  77. vcpu_set_reg(vcpu, rd, data);
  78. }
  79. return 1;
  80. }