On 03.04.2013, at 03:57, Scott Wood wrote: > Hook the MPIC code up to the KVM interfaces, add locking, etc. > > TODO: irqfd support, split up into multiple patches, KVM_IRQ_LINE > support > > Signed-off-by: Scott Wood <scottwood@xxxxxxxxxxxxx> > --- > v3: mpic_put -> kvmppc_mpic_put > > [...] > +void kvmppc_mpic_set_epr(struct kvm_vcpu *vcpu); > + > int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu, > struct kvm_config_tlb *cfg); > int kvm_vcpu_ioctl_dirty_tlb(struct kvm_vcpu *vcpu, > diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig > index 63c67ec..a87139b 100644 > --- a/arch/powerpc/kvm/Kconfig > +++ b/arch/powerpc/kvm/Kconfig > @@ -151,6 +151,11 @@ config KVM_E500MC > > If unsure, say N. > > +config KVM_MPIC > + bool "KVM in-kernel MPIC emulation" > + depends on KVM This should probably depend on FSL KVM for now, until someone adds support for other MPIC revisions. > + > + > source drivers/vhost/Kconfig > > endif # VIRTUALIZATION > diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile > index b772ede..4a2277a 100644 > --- a/arch/powerpc/kvm/Makefile > +++ b/arch/powerpc/kvm/Makefile > @@ -103,6 +103,8 @@ kvm-book3s_32-objs := \ > book3s_32_mmu.o > kvm-objs-$(CONFIG_KVM_BOOK3S_32) := $(kvm-book3s_32-objs) > > +kvm-objs-$(CONFIG_KVM_MPIC) += mpic.o > + > kvm-objs := $(kvm-objs-m) $(kvm-objs-y) > > obj-$(CONFIG_KVM_440) += kvm.o > [...] > struct irq_dest { > + struct kvm_vcpu *vcpu; > + > int32_t ctpr; /* CPU current task priority */ > struct irq_queue raised; > struct irq_queue servicing; > - qemu_irq *irqs; > > /* Count of IRQ sources asserting on non-INT outputs */ > - uint32_t outputs_active[OPENPIC_OUTPUT_NB]; > + uint32_t outputs_active[NUM_OUTPUTS]; > }; > > +struct openpic; Isn't this superfluous? > + > struct openpic { > + struct kvm *kvm; > + struct kvm_io_device mmio; > + struct list_head mmio_regions; > + atomic_t users; > + bool mmio_mapped; > + > + gpa_t reg_base; > + spinlock_t lock; > + > /* Behavior control */ > struct fsl_mpic_info *fsl; > uint32_t model; > @@ -208,6 +231,47 @@ struct openpic { > uint32_t irq_msi; > }; > > [...] > -static uint64_t openpic_gbl_read(void *opaque, gpa_t addr, unsigned len) > +static int openpic_gbl_read(void *opaque, gpa_t addr, u32 *ptr) > { > struct openpic *opp = opaque; > - uint32_t retval; > + u32 retval; > > - pr_debug("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); > + pr_debug("%s: addr %#llx\n", __func__, addr); > retval = 0xFFFFFFFF; > if (addr & 0xF) > - return retval; > + goto out; > > switch (addr) { > case 0x1000: /* FRR */ > retval = opp->frr; > + retval |= (opp->nb_cpus - 1) << FRR_NCPU_SHIFT; > break; > case 0x1020: /* GCR */ > retval = opp->gcr; > @@ -731,8 +771,8 @@ static uint64_t openpic_gbl_read(void *opaque, gpa_t addr, unsigned len) > case 0x90: > case 0xA0: > case 0xB0: > - retval = > - openpic_cpu_read_internal(opp, addr, get_current_cpu()); > + retval = openpic_cpu_read_internal(opp, addr, > + &retval, get_current_cpu()); This looks bogus. You're passing &retval and overwrite it with the return value right after the function returns? > break; > case 0x10A0: /* IPI_IVPR */ > case 0x10B0: > @@ -750,28 +790,28 @@ static uint64_t openpic_gbl_read(void *opaque, gpa_t addr, unsigned len) > default: > break; > } > - pr_debug("%s: => 0x%08x\n", __func__, retval); > > - return retval; > +out: > + pr_debug("%s: => 0x%08x\n", __func__, retval); > + *ptr = retval; > + return 0; > } > [...] > > +static int kvm_mpic_read(struct kvm_io_device *this, gpa_t addr, > + int len, void *ptr) > +{ > + struct openpic *opp = container_of(this, struct openpic, mmio); > + int ret; > + > + /* > + * Technically only 32-bit accesses are allowed, but be nice to > + * people dumping registers a byte at a time -- it works in real > + * hardware (reads only, not writes). Do 16-bit accesses work in real hardware? > + */ > + if (len == 4) { > + if (addr & 3) { > + pr_debug("%s: bad alignment %llx/%d\n", > + __func__, addr, len); > + return -EINVAL; > + } if (addr & (len - 1)) Then the read_internal call can be shared between the different access sizes, no? > + > + spin_lock_irq(&opp->lock); > + ret = kvm_mpic_read_internal(opp, addr - opp->reg_base, ptr); > + spin_unlock_irq(&opp->lock); > + > + pr_debug("%s: addr %llx ret %d len 4 val %x\n", > + __func__, addr, ret, *(const u32 *)ptr); > + } else if (len == 1) { > + union { > + u32 val; > + u8 bytes[4]; > + } u; > + > + spin_lock_irq(&opp->lock); > + ret = kvm_mpic_read_internal(opp, addr - opp->reg_base, &u.val); > + spin_unlock_irq(&opp->lock); > + > + *(u8 *)ptr = u.bytes[addr & 3]; > + > + pr_debug("%s: addr %llx ret %d len 1 val %x\n", > + __func__, addr, ret, *(const u8 *)ptr); > + } else { > + pr_debug("%s: bad length %d\n", __func__, len); > + return -EINVAL; > + } > + > + return ret; > +} > + [...] > > +static int mpic_set_attr(struct openpic *opp, struct kvm_device_attr *attr) > +{ > + u32 attr32; > + > + switch (attr->group) { > + case KVM_DEV_MPIC_GRP_MISC: > + switch (attr->attr) { > + case KVM_DEV_MPIC_BASE_ADDR: > + return set_base_addr(opp, attr); > + } > + > + break; > + > + case KVM_DEV_MPIC_GRP_REGISTER: > + if (copy_from_user(&attr32, (u32 __user *)(long)attr->addr, > + sizeof(u32))) get_user? > + return -EFAULT; > + > + return access_reg(opp, attr->attr, &attr32, ATTR_SET); > + > + case KVM_DEV_MPIC_GRP_IRQ_ACTIVE: > + if (attr->attr > MAX_SRC) > + return -EINVAL; > + > + if (copy_from_user(&attr32, (u32 __user *)(long)attr->addr, > + sizeof(u32))) same here > + return -EFAULT; > + > + if (attr32 != 0 && attr32 != 1) > + return -EINVAL; > + > + spin_lock_irq(&opp->lock); > + openpic_set_irq(opp, attr->attr, attr32); > + spin_unlock_irq(&opp->lock); > + return 0; > + } > + > + return -ENXIO; > +} > + > +static int mpic_get_attr(struct openpic *opp, struct kvm_device_attr *attr) > +{ > + u64 attr64; > + u32 attr32; > + int ret; > + > + switch (attr->group) { > + case KVM_DEV_MPIC_GRP_MISC: > + switch (attr->attr) { > + case KVM_DEV_MPIC_BASE_ADDR: > + mutex_lock(&opp->kvm->slots_lock); > + attr64 = opp->reg_base; > + mutex_unlock(&opp->kvm->slots_lock); > + > + if (copy_to_user((u64 __user *)(long)attr->addr, > + &attr64, sizeof(u64))) u64 is tricky with put_user on 32bit hosts, so here copy_to_user makes sense > + return -EFAULT; > + > + return 0; > + } > + > + break; > + > + case KVM_DEV_MPIC_GRP_REGISTER: > + ret = access_reg(opp, attr->attr, &attr32, ATTR_GET); > + if (ret) > + return ret; > + > + if (copy_to_user((u32 __user *)(long)attr->addr, &attr32, > + sizeof(u32))) put_user > + return -EFAULT; > + > + return 0; > + > + case KVM_DEV_MPIC_GRP_IRQ_ACTIVE: > + if (attr->attr > MAX_SRC) > + return -EINVAL; > + > + attr32 = opp->src[attr->attr].pending; Isn't this missing a lock? > + > + if (copy_to_user((u32 __user *)(long)attr->addr, &attr32, > + sizeof(u32))) > + return -EFAULT; > + > + return 0; > + } > + > + return -ENXIO; > +} Alex -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html