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

KVM: arm/arm64: rework MMIO abort handling to use KVM MMIO bus

Currently we have struct kvm_exit_mmio for encapsulating MMIO abort
data to be passed on from syndrome decoding all the way down to the
VGIC register handlers. Now as we switch the MMIO handling to be
routed through the KVM MMIO bus, it does not make sense anymore to
use that structure already from the beginning. So we keep the data in
local variables until we put them into the kvm_io_bus framework.
Then we fill kvm_exit_mmio in the VGIC only, making it a VGIC private
structure. On that way we replace the data buffer in that structure
with a pointer pointing to a single location in a local variable, so
we get rid of some copying on the way.
With all of the virtual GIC emulation code now being registered with
the kvm_io_bus, we can remove all of the old MMIO handling code and
its dispatching functionality.

I didn't bother to rename kvm_exit_mmio (to vgic_mmio or something),
because that touches a lot of code lines without any good reason.

This is based on an original patch by Nikolay.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Cc: Nikolay Nikolaev <n.nikolaev@virtualopensystems.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

authored by

Andre Przywara and committed by
Marc Zyngier
950324ab fb8f61ab

+56 -222
-22
arch/arm/include/asm/kvm_mmio.h
··· 28 28 bool sign_extend; 29 29 }; 30 30 31 - /* 32 - * The in-kernel MMIO emulation code wants to use a copy of run->mmio, 33 - * which is an anonymous type. Use our own type instead. 34 - */ 35 - struct kvm_exit_mmio { 36 - phys_addr_t phys_addr; 37 - u8 data[8]; 38 - u32 len; 39 - bool is_write; 40 - void *private; 41 - }; 42 - 43 - static inline void kvm_prepare_mmio(struct kvm_run *run, 44 - struct kvm_exit_mmio *mmio) 45 - { 46 - run->mmio.phys_addr = mmio->phys_addr; 47 - run->mmio.len = mmio->len; 48 - run->mmio.is_write = mmio->is_write; 49 - memcpy(run->mmio.data, mmio->data, mmio->len); 50 - run->exit_reason = KVM_EXIT_MMIO; 51 - } 52 - 53 31 int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run); 54 32 int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, 55 33 phys_addr_t fault_ipa);
+38 -28
arch/arm/kvm/mmio.c
··· 121 121 return 0; 122 122 } 123 123 124 - static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, 125 - struct kvm_exit_mmio *mmio) 124 + static int decode_hsr(struct kvm_vcpu *vcpu, bool *is_write, int *len) 126 125 { 127 126 unsigned long rt; 128 - int len; 129 - bool is_write, sign_extend; 127 + int access_size; 128 + bool sign_extend; 130 129 131 130 if (kvm_vcpu_dabt_isextabt(vcpu)) { 132 131 /* cache operation on I/O addr, tell guest unsupported */ ··· 139 140 return 1; 140 141 } 141 142 142 - len = kvm_vcpu_dabt_get_as(vcpu); 143 - if (unlikely(len < 0)) 144 - return len; 143 + access_size = kvm_vcpu_dabt_get_as(vcpu); 144 + if (unlikely(access_size < 0)) 145 + return access_size; 145 146 146 - is_write = kvm_vcpu_dabt_iswrite(vcpu); 147 + *is_write = kvm_vcpu_dabt_iswrite(vcpu); 147 148 sign_extend = kvm_vcpu_dabt_issext(vcpu); 148 149 rt = kvm_vcpu_dabt_get_rd(vcpu); 149 150 150 - mmio->is_write = is_write; 151 - mmio->phys_addr = fault_ipa; 152 - mmio->len = len; 151 + *len = access_size; 153 152 vcpu->arch.mmio_decode.sign_extend = sign_extend; 154 153 vcpu->arch.mmio_decode.rt = rt; 155 154 ··· 162 165 int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, 163 166 phys_addr_t fault_ipa) 164 167 { 165 - struct kvm_exit_mmio mmio; 166 168 unsigned long data; 167 169 unsigned long rt; 168 170 int ret; 171 + bool is_write; 172 + int len; 173 + u8 data_buf[8]; 169 174 170 175 /* 171 - * Prepare MMIO operation. First stash it in a private 172 - * structure that we can use for in-kernel emulation. If the 173 - * kernel can't handle it, copy it into run->mmio and let user 174 - * space do its magic. 176 + * Prepare MMIO operation. First decode the syndrome data we get 177 + * from the CPU. Then try if some in-kernel emulation feels 178 + * responsible, otherwise let user space do its magic. 175 179 */ 176 - 177 180 if (kvm_vcpu_dabt_isvalid(vcpu)) { 178 - ret = decode_hsr(vcpu, fault_ipa, &mmio); 181 + ret = decode_hsr(vcpu, &is_write, &len); 179 182 if (ret) 180 183 return ret; 181 184 } else { ··· 185 188 186 189 rt = vcpu->arch.mmio_decode.rt; 187 190 188 - if (mmio.is_write) { 189 - data = vcpu_data_guest_to_host(vcpu, *vcpu_reg(vcpu, rt), 190 - mmio.len); 191 + if (is_write) { 192 + data = vcpu_data_guest_to_host(vcpu, *vcpu_reg(vcpu, rt), len); 191 193 192 - trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, mmio.len, 193 - fault_ipa, data); 194 - mmio_write_buf(mmio.data, mmio.len, data); 194 + trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data); 195 + mmio_write_buf(data_buf, len, data); 196 + 197 + ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len, 198 + data_buf); 195 199 } else { 196 - trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, mmio.len, 200 + trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, len, 197 201 fault_ipa, 0); 202 + 203 + ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, fault_ipa, len, 204 + data_buf); 198 205 } 199 206 200 - if (vgic_handle_mmio(vcpu, run, &mmio)) 201 - return 1; 207 + /* Now prepare kvm_run for the potential return to userland. */ 208 + run->mmio.is_write = is_write; 209 + run->mmio.phys_addr = fault_ipa; 210 + run->mmio.len = len; 211 + memcpy(run->mmio.data, data_buf, len); 202 212 203 - kvm_prepare_mmio(run, &mmio); 213 + if (!ret) { 214 + /* We handled the access successfully in the kernel. */ 215 + kvm_handle_mmio_return(vcpu, run); 216 + return 1; 217 + } 218 + 219 + run->exit_reason = KVM_EXIT_MMIO; 204 220 return 0; 205 221 }
-22
arch/arm64/include/asm/kvm_mmio.h
··· 31 31 bool sign_extend; 32 32 }; 33 33 34 - /* 35 - * The in-kernel MMIO emulation code wants to use a copy of run->mmio, 36 - * which is an anonymous type. Use our own type instead. 37 - */ 38 - struct kvm_exit_mmio { 39 - phys_addr_t phys_addr; 40 - u8 data[8]; 41 - u32 len; 42 - bool is_write; 43 - void *private; 44 - }; 45 - 46 - static inline void kvm_prepare_mmio(struct kvm_run *run, 47 - struct kvm_exit_mmio *mmio) 48 - { 49 - run->mmio.phys_addr = mmio->phys_addr; 50 - run->mmio.len = mmio->len; 51 - run->mmio.is_write = mmio->is_write; 52 - memcpy(run->mmio.data, mmio->data, mmio->len); 53 - run->exit_reason = KVM_EXIT_MMIO; 54 - } 55 - 56 34 int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run); 57 35 int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, 58 36 phys_addr_t fault_ipa);
-6
include/kvm/arm_vgic.h
··· 140 140 }; 141 141 142 142 struct vgic_vm_ops { 143 - bool (*handle_mmio)(struct kvm_vcpu *, struct kvm_run *, 144 - struct kvm_exit_mmio *); 145 143 bool (*queue_sgi)(struct kvm_vcpu *, int irq); 146 144 void (*add_sgi_source)(struct kvm_vcpu *, int irq, int source); 147 145 int (*init_model)(struct kvm *); ··· 311 313 312 314 struct kvm; 313 315 struct kvm_vcpu; 314 - struct kvm_run; 315 - struct kvm_exit_mmio; 316 316 317 317 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write); 318 318 int kvm_vgic_hyp_init(void); ··· 326 330 void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg); 327 331 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu); 328 332 int kvm_vgic_vcpu_active_irq(struct kvm_vcpu *vcpu); 329 - bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, 330 - struct kvm_exit_mmio *mmio); 331 333 332 334 #define irqchip_in_kernel(k) (!!((k)->arch.vgic.in_kernel)) 333 335 #define vgic_initialized(k) (!!((k)->arch.vgic.nr_cpus))
+2 -19
virt/kvm/arm/vgic-v2-emul.c
··· 404 404 {} 405 405 }; 406 406 407 - static bool vgic_v2_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, 408 - struct kvm_exit_mmio *mmio) 409 - { 410 - unsigned long base = vcpu->kvm->arch.vgic.vgic_dist_base; 411 - 412 - if (!is_in_range(mmio->phys_addr, mmio->len, base, 413 - KVM_VGIC_V2_DIST_SIZE)) 414 - return false; 415 - 416 - /* GICv2 does not support accesses wider than 32 bits */ 417 - if (mmio->len > 4) { 418 - kvm_inject_dabt(vcpu, mmio->phys_addr); 419 - return true; 420 - } 421 - 422 - return vgic_handle_mmio_range(vcpu, run, mmio, vgic_dist_ranges, base); 423 - } 424 - 425 407 static void vgic_dispatch_sgi(struct kvm_vcpu *vcpu, u32 reg) 426 408 { 427 409 struct kvm *kvm = vcpu->kvm; ··· 562 580 { 563 581 struct vgic_dist *dist = &kvm->arch.vgic; 564 582 565 - dist->vm_ops.handle_mmio = vgic_v2_handle_mmio; 566 583 dist->vm_ops.queue_sgi = vgic_v2_queue_sgi; 567 584 dist->vm_ops.add_sgi_source = vgic_v2_add_sgi_source; 568 585 dist->vm_ops.init_model = vgic_v2_init_model; ··· 671 690 struct kvm_vcpu *vcpu, *tmp_vcpu; 672 691 struct vgic_dist *vgic; 673 692 struct kvm_exit_mmio mmio; 693 + u32 data; 674 694 675 695 offset = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK; 676 696 cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >> ··· 693 711 694 712 mmio.len = 4; 695 713 mmio.is_write = is_write; 714 + mmio.data = &data; 696 715 if (is_write) 697 716 mmio_data_write(&mmio, ~0, *reg); 698 717 switch (attr->group) {
-35
virt/kvm/arm/vgic-v3-emul.c
··· 708 708 {}, 709 709 }; 710 710 711 - /* 712 - * This function splits accesses between the distributor and the two 713 - * redistributor parts (private/SPI). As each redistributor is accessible 714 - * from any CPU, we have to determine the affected VCPU by taking the faulting 715 - * address into account. We then pass this VCPU to the handler function via 716 - * the private parameter. 717 - */ 718 - #define SGI_BASE_OFFSET SZ_64K 719 - static bool vgic_v3_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, 720 - struct kvm_exit_mmio *mmio) 721 - { 722 - struct vgic_dist *dist = &vcpu->kvm->arch.vgic; 723 - unsigned long dbase = dist->vgic_dist_base; 724 - unsigned long rdbase = dist->vgic_redist_base; 725 - int nrcpus = atomic_read(&vcpu->kvm->online_vcpus); 726 - int vcpu_id; 727 - 728 - if (is_in_range(mmio->phys_addr, mmio->len, dbase, GIC_V3_DIST_SIZE)) { 729 - return vgic_handle_mmio_range(vcpu, run, mmio, 730 - vgic_v3_dist_ranges, dbase); 731 - } 732 - 733 - if (!is_in_range(mmio->phys_addr, mmio->len, rdbase, 734 - GIC_V3_REDIST_SIZE * nrcpus)) 735 - return false; 736 - 737 - vcpu_id = (mmio->phys_addr - rdbase) / GIC_V3_REDIST_SIZE; 738 - rdbase += (vcpu_id * GIC_V3_REDIST_SIZE); 739 - mmio->private = kvm_get_vcpu(vcpu->kvm, vcpu_id); 740 - 741 - return vgic_handle_mmio_range(vcpu, run, mmio, vgic_redist_ranges, 742 - rdbase); 743 - } 744 - 745 711 static bool vgic_v3_queue_sgi(struct kvm_vcpu *vcpu, int irq) 746 712 { 747 713 if (vgic_queue_irq(vcpu, 0, irq)) { ··· 827 861 { 828 862 struct vgic_dist *dist = &kvm->arch.vgic; 829 863 830 - dist->vm_ops.handle_mmio = vgic_v3_handle_mmio; 831 864 dist->vm_ops.queue_sgi = vgic_v3_queue_sgi; 832 865 dist->vm_ops.add_sgi_source = vgic_v3_add_sgi_source; 833 866 dist->vm_ops.init_model = vgic_v3_init_model;
+8 -85
virt/kvm/arm/vgic.c
··· 758 758 unsigned long offset, 759 759 const struct vgic_io_range *range) 760 760 { 761 - u32 *data32 = (void *)mmio->data; 762 761 struct kvm_exit_mmio mmio32; 763 762 bool ret; 764 763 ··· 774 775 mmio32.private = mmio->private; 775 776 776 777 mmio32.phys_addr = mmio->phys_addr + 4; 777 - if (mmio->is_write) 778 - *(u32 *)mmio32.data = data32[1]; 778 + mmio32.data = &((u32 *)mmio->data)[1]; 779 779 ret = range->handle_mmio(vcpu, &mmio32, offset + 4); 780 - if (!mmio->is_write) 781 - data32[1] = *(u32 *)mmio32.data; 782 780 783 781 mmio32.phys_addr = mmio->phys_addr; 784 - if (mmio->is_write) 785 - *(u32 *)mmio32.data = data32[0]; 782 + mmio32.data = &((u32 *)mmio->data)[0]; 786 783 ret |= range->handle_mmio(vcpu, &mmio32, offset); 787 - if (!mmio->is_write) 788 - data32[0] = *(u32 *)mmio32.data; 789 784 790 785 return ret; 791 - } 792 - 793 - /** 794 - * vgic_handle_mmio_range - handle an in-kernel MMIO access 795 - * @vcpu: pointer to the vcpu performing the access 796 - * @run: pointer to the kvm_run structure 797 - * @mmio: pointer to the data describing the access 798 - * @ranges: array of MMIO ranges in a given region 799 - * @mmio_base: base address of that region 800 - * 801 - * returns true if the MMIO access could be performed 802 - */ 803 - bool vgic_handle_mmio_range(struct kvm_vcpu *vcpu, struct kvm_run *run, 804 - struct kvm_exit_mmio *mmio, 805 - const struct vgic_io_range *ranges, 806 - unsigned long mmio_base) 807 - { 808 - const struct vgic_io_range *range; 809 - struct vgic_dist *dist = &vcpu->kvm->arch.vgic; 810 - bool updated_state; 811 - unsigned long offset; 812 - 813 - offset = mmio->phys_addr - mmio_base; 814 - range = vgic_find_range(ranges, mmio->len, offset); 815 - if (unlikely(!range || !range->handle_mmio)) { 816 - pr_warn("Unhandled access %d %08llx %d\n", 817 - mmio->is_write, mmio->phys_addr, mmio->len); 818 - return false; 819 - } 820 - 821 - spin_lock(&vcpu->kvm->arch.vgic.lock); 822 - offset -= range->base; 823 - if (vgic_validate_access(dist, range, offset)) { 824 - updated_state = call_range_handler(vcpu, mmio, offset, range); 825 - } else { 826 - if (!mmio->is_write) 827 - memset(mmio->data, 0, mmio->len); 828 - updated_state = false; 829 - } 830 - spin_unlock(&vcpu->kvm->arch.vgic.lock); 831 - kvm_prepare_mmio(run, mmio); 832 - kvm_handle_mmio_return(vcpu, run); 833 - 834 - if (updated_state) 835 - vgic_kick_vcpus(vcpu->kvm); 836 - 837 - return true; 838 786 } 839 787 840 788 /** ··· 819 873 mmio.phys_addr = addr; 820 874 mmio.len = len; 821 875 mmio.is_write = is_write; 822 - if (is_write) 823 - memcpy(mmio.data, val, len); 876 + mmio.data = val; 824 877 mmio.private = iodev->redist_vcpu; 825 878 826 879 spin_lock(&dist->lock); 827 880 offset -= range->base; 828 881 if (vgic_validate_access(dist, range, offset)) { 829 882 updated_state = call_range_handler(vcpu, &mmio, offset, range); 830 - if (!is_write) 831 - memcpy(val, mmio.data, len); 832 883 } else { 833 884 if (!is_write) 834 885 memset(val, 0, len); 835 886 updated_state = false; 836 887 } 837 888 spin_unlock(&dist->lock); 838 - kvm_prepare_mmio(run, &mmio); 889 + run->mmio.is_write = is_write; 890 + run->mmio.len = len; 891 + run->mmio.phys_addr = addr; 892 + memcpy(run->mmio.data, val, len); 893 + 839 894 kvm_handle_mmio_return(vcpu, run); 840 895 841 896 if (updated_state) 842 897 vgic_kick_vcpus(vcpu->kvm); 843 898 844 899 return 0; 845 - } 846 - 847 - /** 848 - * vgic_handle_mmio - handle an in-kernel MMIO access for the GIC emulation 849 - * @vcpu: pointer to the vcpu performing the access 850 - * @run: pointer to the kvm_run structure 851 - * @mmio: pointer to the data describing the access 852 - * 853 - * returns true if the MMIO access has been performed in kernel space, 854 - * and false if it needs to be emulated in user space. 855 - * Calls the actual handling routine for the selected VGIC model. 856 - */ 857 - bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, 858 - struct kvm_exit_mmio *mmio) 859 - { 860 - if (!irqchip_in_kernel(vcpu->kvm)) 861 - return false; 862 - 863 - /* 864 - * This will currently call either vgic_v2_handle_mmio() or 865 - * vgic_v3_handle_mmio(), which in turn will call 866 - * vgic_handle_mmio_range() defined above. 867 - */ 868 - return vcpu->kvm->arch.vgic.vm_ops.handle_mmio(vcpu, run, mmio); 869 900 } 870 901 871 902 static int vgic_handle_mmio_read(struct kvm_vcpu *vcpu,
+8 -5
virt/kvm/arm/vgic.h
··· 59 59 bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq); 60 60 void vgic_unqueue_irqs(struct kvm_vcpu *vcpu); 61 61 62 + struct kvm_exit_mmio { 63 + phys_addr_t phys_addr; 64 + void *data; 65 + u32 len; 66 + bool is_write; 67 + void *private; 68 + }; 69 + 62 70 void vgic_reg_access(struct kvm_exit_mmio *mmio, u32 *reg, 63 71 phys_addr_t offset, int mode); 64 72 bool handle_mmio_raz_wi(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, ··· 106 98 const 107 99 struct vgic_io_range *vgic_find_range(const struct vgic_io_range *ranges, 108 100 int len, gpa_t offset); 109 - 110 - bool vgic_handle_mmio_range(struct kvm_vcpu *vcpu, struct kvm_run *run, 111 - struct kvm_exit_mmio *mmio, 112 - const struct vgic_io_range *ranges, 113 - unsigned long mmio_base); 114 101 115 102 bool vgic_handle_enable_reg(struct kvm *kvm, struct kvm_exit_mmio *mmio, 116 103 phys_addr_t offset, int vcpu_id, int access);