[PATCH v2 11/12] KVM: arm/arm64: rework MMIO abort handling to use KVM MMIO bus
Nikolay Nikolaev
n.nikolaev at virtualopensystems.com
Mon Mar 23 14:43:12 PDT 2015
On Mon, Mar 23, 2015 at 5:58 PM, Andre Przywara <andre.przywara at arm.com> wrote:
>
> 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 put the data into
> kvm_run very early and use that encapsulation till the MMIO bus call.
> 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 kvm_run, so we get
> rid of some copying on the way.
> I didn't bother to rename kvm_exit_mmio (to vgic_mmio or something),
I would vote for the renaming.
Otherwise the patch looks much cleaner and straightforward than what
it was before.
Nikolay Nikolaev
> 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 at arm.com>
> Cc: Nikolay Nikolaev <n.nikolaev at virtualopensystems.com>
> ---
> arch/arm/include/asm/kvm_mmio.h | 22 --------------
> arch/arm/kvm/mmio.c | 60 ++++++++++++++++++++++++++-----------
> arch/arm64/include/asm/kvm_mmio.h | 22 --------------
> include/kvm/arm_vgic.h | 3 --
> virt/kvm/arm/vgic.c | 18 +++--------
> virt/kvm/arm/vgic.h | 8 +++++
> 6 files changed, 55 insertions(+), 78 deletions(-)
>
> diff --git a/arch/arm/include/asm/kvm_mmio.h b/arch/arm/include/asm/kvm_mmio.h
> index 3f83db2..d8e90c8 100644
> --- a/arch/arm/include/asm/kvm_mmio.h
> +++ b/arch/arm/include/asm/kvm_mmio.h
> @@ -28,28 +28,6 @@ struct kvm_decode {
> bool sign_extend;
> };
>
> -/*
> - * The in-kernel MMIO emulation code wants to use a copy of run->mmio,
> - * which is an anonymous type. Use our own type instead.
> - */
> -struct kvm_exit_mmio {
> - phys_addr_t phys_addr;
> - u8 data[8];
> - u32 len;
> - bool is_write;
> - void *private;
> -};
> -
> -static inline void kvm_prepare_mmio(struct kvm_run *run,
> - struct kvm_exit_mmio *mmio)
> -{
> - run->mmio.phys_addr = mmio->phys_addr;
> - run->mmio.len = mmio->len;
> - run->mmio.is_write = mmio->is_write;
> - memcpy(run->mmio.data, mmio->data, mmio->len);
> - run->exit_reason = KVM_EXIT_MMIO;
> -}
> -
> int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
> int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
> phys_addr_t fault_ipa);
> diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
> index 5d3bfc0..bb2ab44 100644
> --- a/arch/arm/kvm/mmio.c
> +++ b/arch/arm/kvm/mmio.c
> @@ -122,7 +122,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
> }
>
> static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
> - struct kvm_exit_mmio *mmio)
> + struct kvm_run *run)
> {
> unsigned long rt;
> int len;
> @@ -148,9 +148,9 @@ static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
> sign_extend = kvm_vcpu_dabt_issext(vcpu);
> rt = kvm_vcpu_dabt_get_rd(vcpu);
>
> - mmio->is_write = is_write;
> - mmio->phys_addr = fault_ipa;
> - mmio->len = len;
> + run->mmio.is_write = is_write;
> + run->mmio.phys_addr = fault_ipa;
> + run->mmio.len = len;
> vcpu->arch.mmio_decode.sign_extend = sign_extend;
> vcpu->arch.mmio_decode.rt = rt;
>
> @@ -162,23 +162,49 @@ static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
> return 0;
> }
>
> +/**
> + * handle_kernel_mmio - handle an in-kernel MMIO access
> + * @vcpu: pointer to the vcpu performing the access
> + * @run: pointer to the kvm_run structure
> + *
> + * returns true if the MMIO access has been performed in kernel space,
> + * and false if it needs to be emulated in user space.
> + */
> +static bool handle_kernel_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run)
> +{
> + int ret;
> +
> + if (run->mmio.is_write) {
> + ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr,
> + run->mmio.len, run->mmio.data);
> +
> + } else {
> + ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr,
> + run->mmio.len, run->mmio.data);
> + }
> + if (!ret) {
> + kvm_handle_mmio_return(vcpu, run);
> + return true;
> + }
> +
> + return false;
> +}
> +
> int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
> phys_addr_t fault_ipa)
> {
> - struct kvm_exit_mmio mmio;
> unsigned long data;
> unsigned long rt;
> int ret;
>
> /*
> - * Prepare MMIO operation. First stash it in a private
> - * structure that we can use for in-kernel emulation. If the
> - * kernel can't handle it, copy it into run->mmio and let user
> - * space do its magic.
> + * Prepare MMIO operation. First put the MMIO data into run->mmio.
> + * Then try if some in-kernel emulation feels responsible, otherwise
> + * let user space do its magic.
> */
>
> if (kvm_vcpu_dabt_isvalid(vcpu)) {
> - ret = decode_hsr(vcpu, fault_ipa, &mmio);
> + ret = decode_hsr(vcpu, fault_ipa, run);
> if (ret)
> return ret;
> } else {
> @@ -188,21 +214,21 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
>
> rt = vcpu->arch.mmio_decode.rt;
>
> - if (mmio.is_write) {
> + if (run->mmio.is_write) {
> data = vcpu_data_guest_to_host(vcpu, *vcpu_reg(vcpu, rt),
> - mmio.len);
> + run->mmio.len);
>
> - trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, mmio.len,
> + trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, run->mmio.len,
> fault_ipa, data);
> - mmio_write_buf(mmio.data, mmio.len, data);
> + mmio_write_buf(run->mmio.data, run->mmio.len, data);
> } else {
> - trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, mmio.len,
> + trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, run->mmio.len,
> fault_ipa, 0);
> }
>
> - if (vgic_handle_mmio(vcpu, run, &mmio))
> + if (handle_kernel_mmio(vcpu, run))
> return 1;
>
> - kvm_prepare_mmio(run, &mmio);
> + run->exit_reason = KVM_EXIT_MMIO;
> return 0;
> }
> diff --git a/arch/arm64/include/asm/kvm_mmio.h b/arch/arm64/include/asm/kvm_mmio.h
> index 9f52beb..889c908 100644
> --- a/arch/arm64/include/asm/kvm_mmio.h
> +++ b/arch/arm64/include/asm/kvm_mmio.h
> @@ -31,28 +31,6 @@ struct kvm_decode {
> bool sign_extend;
> };
>
> -/*
> - * The in-kernel MMIO emulation code wants to use a copy of run->mmio,
> - * which is an anonymous type. Use our own type instead.
> - */
> -struct kvm_exit_mmio {
> - phys_addr_t phys_addr;
> - u8 data[8];
> - u32 len;
> - bool is_write;
> - void *private;
> -};
> -
> -static inline void kvm_prepare_mmio(struct kvm_run *run,
> - struct kvm_exit_mmio *mmio)
> -{
> - run->mmio.phys_addr = mmio->phys_addr;
> - run->mmio.len = mmio->len;
> - run->mmio.is_write = mmio->is_write;
> - memcpy(run->mmio.data, mmio->data, mmio->len);
> - run->exit_reason = KVM_EXIT_MMIO;
> -}
> -
> int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
> int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
> phys_addr_t fault_ipa);
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index d6705f4..14853d8 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -314,7 +314,6 @@ struct vgic_cpu {
> struct kvm;
> struct kvm_vcpu;
> struct kvm_run;
> -struct kvm_exit_mmio;
>
> int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
> int kvm_vgic_hyp_init(void);
> @@ -330,8 +329,6 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
> void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
> int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
> int kvm_vgic_vcpu_active_irq(struct kvm_vcpu *vcpu);
> -bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
> - struct kvm_exit_mmio *mmio);
>
> #define irqchip_in_kernel(k) (!!((k)->arch.vgic.in_kernel))
> #define vgic_initialized(k) (!!((k)->arch.vgic.nr_cpus))
> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
> index 9cbb55f4..2598fe8 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -758,7 +758,6 @@ static bool call_range_handler(struct kvm_vcpu *vcpu,
> unsigned long offset,
> const struct vgic_io_range *range)
> {
> - u32 *data32 = (void *)mmio->data;
> struct kvm_exit_mmio mmio32;
> bool ret;
>
> @@ -775,18 +774,12 @@ static bool call_range_handler(struct kvm_vcpu *vcpu,
> mmio32.private = mmio->private;
>
> mmio32.phys_addr = mmio->phys_addr + 4;
> - if (mmio->is_write)
> - *(u32 *)mmio32.data = data32[1];
> + mmio32.data = &((u32 *)mmio->data)[1];
> ret = range->handle_mmio(vcpu, &mmio32, offset + 4);
> - if (!mmio->is_write)
> - data32[1] = *(u32 *)mmio32.data;
>
> mmio32.phys_addr = mmio->phys_addr;
> - if (mmio->is_write)
> - *(u32 *)mmio32.data = data32[0];
> + mmio32.data = &((u32 *)mmio->data)[0];
> ret |= range->handle_mmio(vcpu, &mmio32, offset);
> - if (!mmio->is_write)
> - data32[0] = *(u32 *)mmio32.data;
>
> return ret;
> }
> @@ -873,23 +866,20 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu,
> mmio.phys_addr = addr;
> mmio.len = len;
> mmio.is_write = is_write;
> - if (is_write)
> - memcpy(mmio.data, val, len);
> + mmio.data = val;
> mmio.private = iodev->redist_vcpu;
>
> spin_lock(&dist->lock);
> offset -= range->base;
> if (vgic_validate_access(dist, range, offset)) {
> updated_state = call_range_handler(vcpu, &mmio, offset, range);
> - if (!is_write)
> - memcpy(val, mmio.data, len);
> } else {
> if (!is_write)
> memset(val, 0, len);
> updated_state = false;
> }
> spin_unlock(&dist->lock);
> - kvm_prepare_mmio(run, &mmio);
> + run->exit_reason = KVM_EXIT_MMIO;
> kvm_handle_mmio_return(vcpu, run);
>
> if (updated_state)
> diff --git a/virt/kvm/arm/vgic.h b/virt/kvm/arm/vgic.h
> index 28fa3aa..fc73103 100644
> --- a/virt/kvm/arm/vgic.h
> +++ b/virt/kvm/arm/vgic.h
> @@ -59,6 +59,14 @@ void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq);
> void vgic_unqueue_irqs(struct kvm_vcpu *vcpu);
>
> +struct kvm_exit_mmio {
> + phys_addr_t phys_addr;
> + void *data;
> + u32 len;
> + bool is_write;
> + void *private;
> +};
> +
> void vgic_reg_access(struct kvm_exit_mmio *mmio, u32 *reg,
> phys_addr_t offset, int mode);
> bool handle_mmio_raz_wi(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
> --
> 1.7.9.5
>
More information about the linux-arm-kernel
mailing list