vgic-v2-cpuif-proxy.c 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2012-2015 - ARM Ltd
  4. * Author: Marc Zyngier <[email protected]>
  5. */
  6. #include <hyp/adjust_pc.h>
  7. #include <linux/compiler.h>
  8. #include <linux/irqchip/arm-gic.h>
  9. #include <linux/kvm_host.h>
  10. #include <linux/swab.h>
  11. #include <asm/kvm_emulate.h>
  12. #include <asm/kvm_hyp.h>
  13. #include <asm/kvm_mmu.h>
  14. static bool __is_be(struct kvm_vcpu *vcpu)
  15. {
  16. if (vcpu_mode_is_32bit(vcpu))
  17. return !!(read_sysreg_el2(SYS_SPSR) & PSR_AA32_E_BIT);
  18. return !!(read_sysreg(SCTLR_EL1) & SCTLR_ELx_EE);
  19. }
  20. /*
  21. * __vgic_v2_perform_cpuif_access -- perform a GICV access on behalf of the
  22. * guest.
  23. *
  24. * @vcpu: the offending vcpu
  25. *
  26. * Returns:
  27. * 1: GICV access successfully performed
  28. * 0: Not a GICV access
  29. * -1: Illegal GICV access successfully performed
  30. */
  31. int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
  32. {
  33. struct kvm *kvm = kern_hyp_va(vcpu->kvm);
  34. struct vgic_dist *vgic = &kvm->arch.vgic;
  35. phys_addr_t fault_ipa;
  36. void __iomem *addr;
  37. int rd;
  38. /* Build the full address */
  39. fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
  40. fault_ipa |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0);
  41. /* If not for GICV, move on */
  42. if (fault_ipa < vgic->vgic_cpu_base ||
  43. fault_ipa >= (vgic->vgic_cpu_base + KVM_VGIC_V2_CPU_SIZE))
  44. return 0;
  45. /* Reject anything but a 32bit access */
  46. if (kvm_vcpu_dabt_get_as(vcpu) != sizeof(u32)) {
  47. __kvm_skip_instr(vcpu);
  48. return -1;
  49. }
  50. /* Not aligned? Don't bother */
  51. if (fault_ipa & 3) {
  52. __kvm_skip_instr(vcpu);
  53. return -1;
  54. }
  55. rd = kvm_vcpu_dabt_get_rd(vcpu);
  56. addr = kvm_vgic_global_state.vcpu_hyp_va;
  57. addr += fault_ipa - vgic->vgic_cpu_base;
  58. if (kvm_vcpu_dabt_iswrite(vcpu)) {
  59. u32 data = vcpu_get_reg(vcpu, rd);
  60. if (__is_be(vcpu)) {
  61. /* guest pre-swabbed data, undo this for writel() */
  62. data = __kvm_swab32(data);
  63. }
  64. writel_relaxed(data, addr);
  65. } else {
  66. u32 data = readl_relaxed(addr);
  67. if (__is_be(vcpu)) {
  68. /* guest expects swabbed data */
  69. data = __kvm_swab32(data);
  70. }
  71. vcpu_set_reg(vcpu, rd, data);
  72. }
  73. __kvm_skip_instr(vcpu);
  74. return 1;
  75. }