[Android-virt] [PATCH 03/15] ARM: KVM: Initial VGIC MMIO support code

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, May 14, 2012 at 9:05 AM, Marc Zyngier <marc.zyngier at arm.com> wrote:
> Wire the initial in-kernel MMIO support code for the VGIC, used
> for the distributor emulation.
>
> Signed-off-by: Marc Zyngier <marc.zyngier at arm.com>
> ---
> ?arch/arm/include/asm/kvm_vgic.h | ? ?4 +-
> ?arch/arm/kvm/Makefile ? ? ? ? ? | ? ?1 +
> ?arch/arm/kvm/vgic.c ? ? ? ? ? ? | ?130 +++++++++++++++++++++++++++++++++++++++
> ?3 files changed, 134 insertions(+), 1 deletions(-)
> ?create mode 100644 arch/arm/kvm/vgic.c
>
> diff --git a/arch/arm/include/asm/kvm_vgic.h b/arch/arm/include/asm/kvm_vgic.h
> index 222812e..34f5cc0 100644
> --- a/arch/arm/include/asm/kvm_vgic.h
> +++ b/arch/arm/include/asm/kvm_vgic.h
> @@ -11,7 +11,9 @@ struct kvm;
> ?struct kvm_vcpu;
> ?struct kvm_run;
>
> -#ifndef CONFIG_KVM_ARM_VGIC
> +#ifdef CONFIG_KVM_ARM_VGIC
> +int vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run);
> +#else
> ?static inline int kvm_vgic_hyp_init(void)
> ?{
> ? ? ? ?return 0;
> diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
> index e69a8e1..d21c7b7 100644
> --- a/arch/arm/kvm/Makefile
> +++ b/arch/arm/kvm/Makefile
> @@ -15,3 +15,4 @@ kvm-arm-y += $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o)
> ?kvm-arm-y += arm.o guest.o mmu.o emulate.o
>
> ?obj-$(CONFIG_KVM) += kvm-arm.o
> +obj-$(CONFIG_KVM_ARM_VGIC) += vgic.o
> diff --git a/arch/arm/kvm/vgic.c b/arch/arm/kvm/vgic.c
> new file mode 100644
> index 0000000..f7856a9
> --- /dev/null
> +++ b/arch/arm/kvm/vgic.c
> @@ -0,0 +1,130 @@
> +/*
> + * Copyright (C) 2012 ARM Ltd.
> + * Author: Marc Zyngier <marc.zyngier at arm.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + */
> +
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +
> +#define ACCESS_READ_VALUE ? ? ?(1 << 0)
> +#define ACCESS_READ_RAZ ? ? ? ? ? ? ? ?(0 << 0)
> +#define ACCESS_READ_MASK(x) ? ?((x) & (1 << 0))
> +#define ACCESS_WRITE_IGNORED ? (0 << 1)
> +#define ACCESS_WRITE_SETBIT ? ?(1 << 1)
> +#define ACCESS_WRITE_CLEARBIT ?(2 << 1)
> +#define ACCESS_WRITE_VALUE ? ? (3 << 1)
> +#define ACCESS_WRITE_MASK(x) ? ((x) & (3 << 1))
> +
> +static void mmio_do_copy(struct kvm_run *run, u32 *reg, u32 offset, int mode)
> +{
> + ? ? ? int u32off = offset & 3;
> + ? ? ? int shift = u32off * 8;
> + ? ? ? u32 mask;
> + ? ? ? u32 regval;
> +
> + ? ? ? /*
> + ? ? ? ?* We do silly things on cross-register accesses, so pretend
> + ? ? ? ?* they do not exist. Will have to be handled though...
> + ? ? ? ?*/
> + ? ? ? if (WARN_ON((u32off + run->mmio.len) > 4))
> + ? ? ? ? ? ? ? run->mmio.len = 4 - u32off;
> +
> + ? ? ? mask = ((u32)-1) >> (u32off * 8);
> + ? ? ? if (reg)
> + ? ? ? ? ? ? ? regval = *reg;
> + ? ? ? else {
> + ? ? ? ? ? ? ? BUG_ON(mode != (ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED));
> + ? ? ? ? ? ? ? regval = 0;
> + ? ? ? }
> +
> + ? ? ? if (run->mmio.is_write) {
> + ? ? ? ? ? ? ? u32 data = (*((u32 *)run->mmio.data) & mask) << shift;

I guess this is dangerous as user space can play with run->mmio.data
and read anything they want here

> + ? ? ? ? ? ? ? switch (ACCESS_WRITE_MASK(mode)) {
> + ? ? ? ? ? ? ? case ACCESS_WRITE_IGNORED:
> + ? ? ? ? ? ? ? ? ? ? ? return;
> +
> + ? ? ? ? ? ? ? case ACCESS_WRITE_SETBIT:
> + ? ? ? ? ? ? ? ? ? ? ? regval |= data;
> + ? ? ? ? ? ? ? ? ? ? ? break;
> +
> + ? ? ? ? ? ? ? case ACCESS_WRITE_CLEARBIT:
> + ? ? ? ? ? ? ? ? ? ? ? regval &= ~data;
> + ? ? ? ? ? ? ? ? ? ? ? break;
> +
> + ? ? ? ? ? ? ? case ACCESS_WRITE_VALUE:
> + ? ? ? ? ? ? ? ? ? ? ? regval = (regval & ~(mask << shift)) | data;
> + ? ? ? ? ? ? ? ? ? ? ? break;
> + ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? *reg = regval;
> + ? ? ? } else {
> + ? ? ? ? ? ? ? switch (ACCESS_READ_MASK(mode)) {
> + ? ? ? ? ? ? ? case ACCESS_READ_RAZ:
> + ? ? ? ? ? ? ? ? ? ? ? regval = 0;
> + ? ? ? ? ? ? ? ? ? ? ? /* fall through */
> +
> + ? ? ? ? ? ? ? case ACCESS_READ_VALUE:
> + ? ? ? ? ? ? ? ? ? ? ? *((u32 *)run->mmio.data) = (regval >> shift) & mask;

same as above, but potentially worse

> + ? ? ? ? ? ? ? }
> + ? ? ? }
> +}
> +
> +/* All this should really be generic code... FIXME!!! */
> +struct mmio_range {
> + ? ? ? unsigned long base;
> + ? ? ? unsigned long len;
> + ? ? ? void (*handle_mmio)(struct kvm_vcpu *vcpu, struct kvm_run *run,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? u32 offset);
> +};
> +
> +static const struct mmio_range vgic_ranges[] = {
> + ? ? ? {}
> +};
> +
> +static const
> +struct mmio_range *find_matching_range(const struct mmio_range *ranges,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?struct kvm_run *run)
> +{
> + ? ? ? const struct mmio_range *r = ranges;
> + ? ? ? while (r->len) {
> + ? ? ? ? ? ? ? if (run->mmio.phys_addr >= r->base &&
> + ? ? ? ? ? ? ? ? ? (run->mmio.phys_addr + run->mmio.len) <= (r->base + r->len))
> + ? ? ? ? ? ? ? ? ? ? ? return r;
> + ? ? ? ? ? ? ? r++;
> + ? ? ? }
> +
> + ? ? ? return NULL;
> +}
> +
> +int vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run)
> +{

I'm guessing we probably don't want to do all this off of the kvm_run
struct given that user space maps it, but rather have a separate copy
of the struct mmio or something different all together.

> + ? ? ? const struct mmio_range *range;
> +
> + ? ? ? if (!irqchip_in_kernel(vcpu->kvm))
> + ? ? ? ? ? ? ? return KVM_EXIT_MMIO;
> +
> + ? ? ? range = find_matching_range(vgic_ranges, run);
> + ? ? ? if (!range || !range->handle_mmio)
> + ? ? ? ? ? ? ? return KVM_EXIT_MMIO;
> +
> + ? ? ? pr_debug("emulating %d %08llx %d\n", run->mmio.is_write,
> + ? ? ? ? ? ? ? ?run->mmio.phys_addr, run->mmio.len);
> + ? ? ? range->handle_mmio(vcpu, run, run->mmio.phys_addr - range->base);
> + ? ? ? kvm_handle_mmio_return(vcpu, run);
> +
> + ? ? ? return KVM_EXIT_UNKNOWN;
> +}
> --
> 1.7.7.1
>
>
>
> _______________________________________________
> Android-virt mailing list
> Android-virt at lists.cs.columbia.edu
> https://lists.cs.columbia.edu/cucslists/listinfo/android-virt



[Index of Archives]     [Linux KVM]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux