return container_of(dev, struct vgic_io_device, dev);
 }
 
-static bool check_region(const struct vgic_register_region *region,
+static bool check_region(const struct kvm *kvm,
+                        const struct vgic_register_region *region,
                         gpa_t addr, int len)
 {
-       if ((region->access_flags & VGIC_ACCESS_8bit) && len == 1)
-               return true;
-       if ((region->access_flags & VGIC_ACCESS_32bit) &&
-           len == sizeof(u32) && !(addr & 3))
-               return true;
-       if ((region->access_flags & VGIC_ACCESS_64bit) &&
-           len == sizeof(u64) && !(addr & 7))
-               return true;
+       int flags, nr_irqs = kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+
+       switch (len) {
+       case sizeof(u8):
+               flags = VGIC_ACCESS_8bit;
+               break;
+       case sizeof(u32):
+               flags = VGIC_ACCESS_32bit;
+               break;
+       case sizeof(u64):
+               flags = VGIC_ACCESS_64bit;
+               break;
+       default:
+               return false;
+       }
+
+       if ((region->access_flags & flags) && IS_ALIGNED(addr, len)) {
+               if (!region->bits_per_irq)
+                       return true;
+
+               /* Do we access a non-allocated IRQ? */
+               return VGIC_ADDR_TO_INTID(addr, region->bits_per_irq) < nr_irqs;
+       }
 
        return false;
 }
 
        region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
                                       addr - iodev->base_addr);
-       if (!region || !check_region(region, addr, len)) {
+       if (!region || !check_region(vcpu->kvm, region, addr, len)) {
                memset(val, 0, len);
                return 0;
        }
 
        region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
                                       addr - iodev->base_addr);
-       if (!region)
-               return 0;
-
-       if (!check_region(region, addr, len))
+       if (!region || !check_region(vcpu->kvm, region, addr, len))
                return 0;
 
        switch (iodev->iodev_type) {
 
 #define VGIC_ADDR_IRQ_MASK(bits) (((bits) * 1024 / 8) - 1)
 
 /*
- * (addr & mask) gives us the byte offset for the INT ID, so we want to
- * divide this with 'bytes per irq' to get the INT ID, which is given
- * by '(bits) / 8'.  But we do this with fixed-point-arithmetic and
- * take advantage of the fact that division by a fraction equals
- * multiplication with the inverted fraction, and scale up both the
- * numerator and denominator with 8 to support at most 64 bits per IRQ:
+ * (addr & mask) gives us the _byte_ offset for the INT ID.
+ * We multiply this by 8 the get the _bit_ offset, then divide this by
+ * the number of bits to learn the actual INT ID.
+ * But instead of a division (which requires a "long long div" implementation),
+ * we shift by the binary logarithm of <bits>.
+ * This assumes that <bits> is a power of two.
  */
 #define VGIC_ADDR_TO_INTID(addr, bits)  (((addr) & VGIC_ADDR_IRQ_MASK(bits)) * \
-                                       64 / (bits) / 8)
+                                       8 >> ilog2(bits))
 
 /*
  * Some VGIC registers store per-IRQ information, with a different number