If we're running a guest with a larger page size than the host,
interesting things start to happen when communicating via a virtio-mmio
device because the idea of buffer alignment between the guest and the
host will be off by the misalignment of the guest memory buffer allocated
by the host. This causes things like the index field of vring.used to
be accessed at different addresses on the guest and the host, leading
to deadlock.

Fix this problem by allocating guest memory aligned to the maximum
possible page size for the architecture (64K).

Signed-off-by: Will Deacon <will.dea...@arm.com>
---
 tools/kvm/arm/include/arm-common/kvm-arch.h | 10 ++++++++++
 tools/kvm/arm/kvm.c                         | 24 ++++++++++++++++++------
 2 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/tools/kvm/arm/include/arm-common/kvm-arch.h 
b/tools/kvm/arm/include/arm-common/kvm-arch.h
index 46ee7e2..7860e17 100644
--- a/tools/kvm/arm/include/arm-common/kvm-arch.h
+++ b/tools/kvm/arm/include/arm-common/kvm-arch.h
@@ -37,6 +37,16 @@ static inline bool arm_addr_in_pci_mmio_region(u64 phys_addr)
 }
 
 struct kvm_arch {
+       /*
+        * We may have to align the guest memory for virtio, so keep the
+        * original pointers here for munmap.
+        */
+       void    *ram_alloc_start;
+       u64     ram_alloc_size;
+
+       /*
+        * Guest addresses for memory layout.
+        */
        u64     memory_guest_start;
        u64     kern_guest_start;
        u64     initrd_guest_start;
diff --git a/tools/kvm/arm/kvm.c b/tools/kvm/arm/kvm.c
index 9eff927..1bcfce3 100644
--- a/tools/kvm/arm/kvm.c
+++ b/tools/kvm/arm/kvm.c
@@ -7,6 +7,7 @@
 
 #include <linux/kernel.h>
 #include <linux/kvm.h>
+#include <linux/sizes.h>
 
 struct kvm_ext kvm_req_ext[] = {
        { DEFINE_KVM_EXT(KVM_CAP_IRQCHIP) },
@@ -41,7 +42,7 @@ void kvm__init_ram(struct kvm *kvm)
 
 void kvm__arch_delete_ram(struct kvm *kvm)
 {
-       munmap(kvm->ram_start, kvm->ram_size);
+       munmap(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size);
 }
 
 void kvm__arch_periodic_poll(struct kvm *kvm)
@@ -56,13 +57,24 @@ void kvm__arch_set_cmdline(char *cmdline, bool video)
 
 void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size)
 {
-       /* Allocate guest memory. */
+       /*
+        * Allocate guest memory. We must align out buffer to 64K to
+        * correlate with the maximum guest page size for virtio-mmio.
+        */
        kvm->ram_size = min(ram_size, (u64)ARM_MAX_MEMORY(kvm));
-       kvm->ram_start = mmap_anon_or_hugetlbfs(kvm, hugetlbfs_path, 
kvm->ram_size);
-       if (kvm->ram_start == MAP_FAILED)
+       kvm->arch.ram_alloc_size = kvm->ram_size + SZ_64K;
+       kvm->arch.ram_alloc_start = mmap_anon_or_hugetlbfs(kvm, hugetlbfs_path,
+                                               kvm->arch.ram_alloc_size);
+
+       if (kvm->arch.ram_alloc_start == MAP_FAILED)
                die("Failed to map %lld bytes for guest memory (%d)",
-                   kvm->ram_size, errno);
-       madvise(kvm->ram_start, kvm->ram_size, MADV_MERGEABLE);
+                   kvm->arch.ram_alloc_size, errno);
+
+       kvm->ram_start = (void *)ALIGN((unsigned long)kvm->arch.ram_alloc_start,
+                                       SZ_64K);
+
+       madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size,
+               MADV_MERGEABLE);
 
        /* Initialise the virtual GIC. */
        if (gic__init_irqchip(kvm))
-- 
1.8.0

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to