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.deacon@xxxxxxx> --- 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html