kvm tools: arm: align guest memory buffer to maximum page size

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@arm.com>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
Will Deacon
2013-01-07 18:43:45 +00:00
parent 1e0c135a3b
commit 9eb3dbcbc8
2 changed files with 28 additions and 6 deletions
+10
View File
@@ -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;
+18 -6
View File
@@ -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))