Add support for ARMv8 CPUs to kvmtool
cover Add support for ARMv8 CPUs to kvmtool
Hello again,
These two patches add support for ARMv8 processors running an AArch64 instance of kvm to kvmtool. Both AArch32 and AArch64 guests are supported and, in the case of the latter, the guest page size may be either 64k or 4k.
This depends on the ARM updates series I just posted:
https://lists.cs.columbia.edu/pipermail/kvmarm/2013-January/004505.html
Feedback welcome,
Will
Will Deacon (2):
kvm tools: add support for ARMv8 processors
kvm tools: arm: align guest memory buffer to maximum page size
tools/kvm/Makefile | 14 +-
tools/kvm/arm/aarch32/include/kvm/kvm-arch.h | 20 +--
.../kvm/arm/aarch32/include/kvm/kvm-config-arch.h | 8 ++
tools/kvm/arm/aarch64/cortex-a57.c | 95 ++++++++++++
tools/kvm/arm/aarch64/include/kvm/barrier.h | 8 ++
tools/kvm/arm/aarch64/include/kvm/kvm-arch.h | 17 +++
.../kvm/arm/aarch64/include/kvm/kvm-config-arch.h | 10 ++
tools/kvm/arm/aarch64/include/kvm/kvm-cpu-arch.h | 13 ++
tools/kvm/arm/aarch64/kvm-cpu.c | 160 +++++++++++++++++++++
tools/kvm/arm/fdt.c | 2 +-
tools/kvm/arm/include/arm-common/kvm-arch.h | 32 ++++-
.../include/{kvm => arm-common}/kvm-config-arch.h | 8 +-
tools/kvm/arm/kvm.c | 26 +++-
13 files changed, 381 insertions(+), 32 deletions(-)
create mode 100644 tools/kvm/arm/aarch32/include/kvm/kvm-config-arch.h
create mode 100644 tools/kvm/arm/aarch64/cortex-a57.c
create mode 100644 tools/kvm/arm/aarch64/include/kvm/barrier.h
create mode 100644 tools/kvm/arm/aarch64/include/kvm/kvm-arch.h
create mode 100644 tools/kvm/arm/aarch64/include/kvm/kvm-config-arch.h
create mode 100644 tools/kvm/arm/aarch64/include/kvm/kvm-cpu-arch.h
create mode 100644 tools/kvm/arm/aarch64/kvm-cpu.c
rename tools/kvm/arm/include/{kvm => arm-common}/kvm-config-arch.h (61%)Signature · 1 line
1.8.0
PATCH 1/2 kvm tools: add support for ARMv8 processors
This patch adds support for ARMv8 processors (more specifically, Cortex-A57) to kvmtool. Both AArch64 and AArch32 guests are supported, so the existing AArch32 code is slightly restructured to allow for re-use of much of the current code.
The implementation closely follows the ARMv7 code and reuses much of the work written there.
---
tools/kvm/Makefile | 14 +-
tools/kvm/arm/aarch32/include/kvm/kvm-arch.h | 20 +--
.../kvm/arm/aarch32/include/kvm/kvm-config-arch.h | 8 ++
tools/kvm/arm/aarch64/cortex-a57.c | 95 ++++++++++++
tools/kvm/arm/aarch64/include/kvm/barrier.h | 8 ++
tools/kvm/arm/aarch64/include/kvm/kvm-arch.h | 17 +++
.../kvm/arm/aarch64/include/kvm/kvm-config-arch.h | 10 ++
tools/kvm/arm/aarch64/include/kvm/kvm-cpu-arch.h | 13 ++
tools/kvm/arm/aarch64/kvm-cpu.c | 160 +++++++++++++++++++++
tools/kvm/arm/fdt.c | 2 +-
tools/kvm/arm/include/arm-common/kvm-arch.h | 22 ++-
.../include/{kvm => arm-common}/kvm-config-arch.h | 8 +-
tools/kvm/arm/kvm.c | 2 +-
13 files changed, 353 insertions(+), 26 deletions(-)
create mode 100644 tools/kvm/arm/aarch32/include/kvm/kvm-config-arch.h
create mode 100644 tools/kvm/arm/aarch64/cortex-a57.c
create mode 100644 tools/kvm/arm/aarch64/include/kvm/barrier.h
create mode 100644 tools/kvm/arm/aarch64/include/kvm/kvm-arch.h
create mode 100644 tools/kvm/arm/aarch64/include/kvm/kvm-config-arch.h
create mode 100644 tools/kvm/arm/aarch64/include/kvm/kvm-cpu-arch.h
create mode 100644 tools/kvm/arm/aarch64/kvm-cpu.c
rename tools/kvm/arm/include/{kvm => arm-common}/kvm-config-arch.h (61%)tools/kvm/Makefile +13 -1
@@ -103,7 +103,7 @@ OBJS += virtio/mmio.o # Translate uname -m into ARCH string ARCH ?= $(shell uname -m | sed -e s/i.86/i386/ -e s/ppc.*/powerpc/ \ - -e s/armv7.*/arm/) + -e s/armv7.*/arm/ -e s/aarch64.*/arm64/) ifeq ($(ARCH),i386) ARCH := x86
@@ -174,6 +174,18 @@ ifeq ($(ARCH), arm) OTHEROBJS += $(LIBFDT_OBJS) endif +# ARM64 +ifeq ($(ARCH), arm64) + DEFINES += -DCONFIG_ARM64 + OBJS += $(OBJS_ARM_COMMON) + OBJS += arm/aarch64/cortex-a57.o + OBJS += arm/aarch64/kvm-cpu.o + ARCH_INCLUDE := $(HDRS_ARM_COMMON) + ARCH_INCLUDE += -Iarm/aarch64/include + CFLAGS += -I../../scripts/dtc/libfdt + OTHEROBJS += $(LIBFDT_OBJS) +endif + ### ifeq (,$(ARCH_INCLUDE))
tools/kvm/arm/aarch32/include/kvm/kvm-arch.h +2 -18
@@ -1,28 +1,12 @@#ifndef KVM__KVM_ARCH_H #define KVM__KVM_ARCH_H -#include <linux/const.h> - -#define ARM_LOMAP_MMIO_AREA _AC(0x00000000, UL) -#define ARM_LOMAP_AXI_AREA _AC(0x40000000, UL) -#define ARM_LOMAP_MEMORY_AREA _AC(0x80000000, UL) -#define ARM_LOMAP_MAX_MEMORY _AC(0x7fffffff, UL) -#define ARM_GIC_DIST_SIZE 0x1000 -#define ARM_GIC_DIST_BASE (ARM_LOMAP_AXI_AREA - ARM_GIC_DIST_SIZE)#define ARM_GIC_CPUI_SIZE 0x2000 -#define ARM_GIC_CPUI_BASE (ARM_GIC_DIST_BASE - ARM_GIC_CPUI_SIZE) - -#define ARM_KERN_OFFSET 0x8000 - -#define ARM_VIRTIO_MMIO_SIZE (ARM_GIC_DIST_BASE - ARM_LOMAP_MMIO_AREA) -#define ARM_PCI_MMIO_SIZE (ARM_LOMAP_MEMORY_AREA - ARM_LOMAP_AXI_AREA) -#define ARM_MEMORY_AREA ARM_LOMAP_MEMORY_AREA -#define ARM_MAX_MEMORY ARM_LOMAP_MAX_MEMORY +#define ARM_KERN_OFFSET (...) 0x8000 -#define KVM_PCI_MMIO_AREA ARM_LOMAP_AXI_AREA -#define KVM_VIRTIO_MMIO_AREA ARM_LOMAP_MMIO_AREA +#define ARM_MAX_MEMORY (...) ARM_LOMAP_MAX_MEMORY#include "arm-common/kvm-arch.h"
tools/kvm/arm/aarch32/include/kvm/kvm-config-arch.h new file +8 -0
@@ -0,0 +1,8 @@ +#ifndef KVM__KVM_CONFIG_ARCH_H +#define KVM__KVM_CONFIG_ARCH_H + +#define ARM_OPT_ARCH_RUN (...) + +#include "arm-common/kvm-config-arch.h" + +#endif /* KVM__KVM_CONFIG_ARCH_H */
tools/kvm/arm/aarch64/cortex-a57.c new file +95 -0
95 lines not on this page · raw message
tools/kvm/arm/aarch64/include/kvm/barrier.h new file +8 -0
@@ -0,0 +1,8 @@ +#ifndef KVM__KVM_BARRIER_H +#define KVM__KVM_BARRIER_H + +#define mb () asm volatile ("dmb ish" : : : "memory") +#define rmb () asm volatile ("dmb ishld" : : : "memory") +#define wmb () asm volatile ("dmb ishst" : : : "memory") + +#endif /* KVM__KVM_BARRIER_H */
tools/kvm/arm/aarch64/include/kvm/kvm-arch.h new file +17 -0
@@ -0,0 +1,17 @@ +#ifndef KVM__KVM_ARCH_H +#define KVM__KVM_ARCH_H + +#define ARM_GIC_DIST_SIZE 0x10000 +#define ARM_GIC_CPUI_SIZE 0x10000 + +#define ARM_KERN_OFFSET (kvm) ((kvm)->cfg.arch.aarch32_guest ? \ + 0x8000 : \ + 0x80000) + +#define ARM_MAX_MEMORY (kvm) ((kvm)->cfg.arch.aarch32_guest ? \ + ARM_LOMAP_MAX_MEMORY : \ + ARM_HIMAP_MAX_MEMORY) + +#include "arm-common/kvm-arch.h" + +#endif /* KVM__KVM_ARCH_H */
tools/kvm/arm/aarch64/include/kvm/kvm-config-arch.h new file +10 -0
@@ -0,0 +1,10 @@ +#ifndef KVM__KVM_CONFIG_ARCH_H +#define KVM__KVM_CONFIG_ARCH_H + +#define ARM_OPT_ARCH_RUN (cfg) \ + OPT_BOOLEAN('\0', "aarch32", &(cfg)->aarch32_guest, \ + "Run AArch32 guest"), + +#include "arm-common/kvm-config-arch.h" + +#endif /* KVM__KVM_CONFIG_ARCH_H */
tools/kvm/arm/aarch64/include/kvm/kvm-cpu-arch.h new file +13 -0
@@ -0,0 +1,13 @@ +#ifndef KVM__KVM_CPU_ARCH_H +#define KVM__KVM_CPU_ARCH_H + +#include "kvm/kvm.h" + +#include "arm-common/kvm-cpu-arch.h" + +#define ARM_VCPU_FEATURE_FLAGS (kvm, cpuid) { \ + [0] = ((!!(cpuid) << KVM_ARM_VCPU_POWER_OFF) | \ + (!!(kvm)->cfg.arch.aarch32_guest << KVM_ARM_VCPU_EL1_32BIT)) \ +} + +#endif /* KVM__KVM_CPU_ARCH_H */
tools/kvm/arm/aarch64/kvm-cpu.c new file +160 -0
160 lines not on this page · raw message
tools/kvm/arm/fdt.c +1 -1
@@ -178,7 +178,7 @@ int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd,*/ limit = kvm->ram_start +min (kvm->ram_size, (u64 )SZ_256M ) -1 ; - pos = kvm->ram_start +ARM_KERN_OFFSET ; + pos = kvm->ram_start +ARM_KERN_OFFSET (kvm); kvm->arch.kern_guest_start =host_to_guest_flat (kvm, pos);if (read_image (fd_kernel, &pos, limit) == -ENOMEM )die ("kernel image too big to contain in guest memory." );
tools/kvm/arm/include/arm-common/kvm-arch.h +20 -2
@@ -1,11 +1,29 @@#ifndef ARM_COMMON__KVM_ARCH_H #define ARM_COMMON__KVM_ARCH_H -#define VIRTIO_DEFAULT_TRANS VIRTIO_MMIO -#include <stdbool.h> +#include <linux/const.h> #include <linux/types.h> +#define ARM_MMIO_AREA _AC(0x0000000000000000, UL) +#define ARM_AXI_AREA _AC(0x0000000040000000, UL) +#define ARM_MEMORY_AREA _AC(0x0000000080000000, UL) + +#define ARM_LOMAP_MAX_MEMORY ((1ULL << 32) - ARM_MEMORY_AREA) +#define ARM_HIMAP_MAX_MEMORY ((1ULL << 40) - ARM_MEMORY_AREA) + +#define ARM_GIC_DIST_BASE (ARM_AXI_AREA - ARM_GIC_DIST_SIZE) +#define ARM_GIC_CPUI_BASE (ARM_GIC_DIST_BASE - ARM_GIC_CPUI_SIZE) +#define ARM_GIC_SIZE (ARM_GIC_DIST_SIZE + ARM_GIC_CPUI_SIZE) + +#define ARM_VIRTIO_MMIO_SIZE (ARM_AXI_AREA - ARM_GIC_SIZE) +#define ARM_PCI_MMIO_SIZE (ARM_MEMORY_AREA - ARM_AXI_AREA) + +#define KVM_PCI_MMIO_AREA ARM_AXI_AREA +#define KVM_VIRTIO_MMIO_AREA ARM_MMIO_AREA + +#define VIRTIO_DEFAULT_TRANS VIRTIO_MMIO +static inline bool arm_addr_in_virtio_mmio_region (u64 phys_addr) {u64 limit =KVM_VIRTIO_MMIO_AREA +ARM_VIRTIO_MMIO_SIZE ;
tools/kvm/arm/include/arm-common/kvm-config-arch.h renamed from tools/kvm/arm/include/kvm/kvm-config-arch.h +5 -3
@@ -1,15 +1,17 @@ -#ifndef KVM__KVM_CONFIG_ARCH_H -#define KVM__KVM_CONFIG_ARCH_H +#ifndef ARM_COMMON__KVM_CONFIG_ARCH_H +#define ARM_COMMON__KVM_CONFIG_ARCH_H #include "kvm/parse-options.h" struct kvm_config_arch {const char *dump_dtb_filename; +bool aarch32_guest; };#define OPT_ARCH_RUN (pfx, cfg) \ pfx, \ + ARM_OPT_ARCH_RUN(cfg) \ OPT_STRING('\0', "dump-dtb", &(cfg)->dump_dtb_filename, \ ".dtb file", "Dump generated .dtb to specified file"), -#endif /* KVM__KVM_CONFIG_ARCH_H */ +#endif /* ARM_COMMON__KVM_CONFIG_ARCH_H */
tools/kvm/arm/kvm.c +1 -1
@@ -57,7 +57,7 @@ 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. */ - kvm->ram_size =min (ram_size, (u64 )ARM_MAX_MEMORY ); + 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 ) die("Failed to map %lld bytes for guest memory (%d)",
Signature · 1 line
1.8.0
PATCH 2/2 kvm tools: arm: align guest memory buffer to maximum page size
In reply to Will DeaconIf 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).
--- tools/kvm/arm/include/arm-common/kvm-arch.h | 10 ++++++++++ tools/kvm/arm/kvm.c | 24 ++++++++++++++++++------ 2 files changed, 28 insertions(+), 6 deletions(-)
tools/kvm/arm/include/arm-common/kvm-arch.h +10 -0
@@ -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;
tools/kvm/arm/kvm.c +18 -6
@@ -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))
Signature · 1 line
1.8.0
Hi Will,
Quoted 11 lines · Will Deacon
Hello again,
These two patches add support for ARMv8 processors running an AArch64 instance of kvm to kvmtool. Both AArch32 and AArch64 guests are supported and, in the case of the latter, the guest page size may be either 64k or 4k.
This depends on the ARM updates series I just posted:
https://lists.cs.columbia.edu/pipermail/kvmarm/2013-January/004505.html
Feedback welcome,
So will ARMv7 continue to work after this patch even without the ARM updates? If so, I'm happy to merge the patch before the updates hit v3.9.
Pekka
Quoted 1 line · Pekka Enberg
Hi Will,
Hello,
Quoted 7 lines · Will Deacon
Quoted 6 lines
These two patches add support for ARMv8 processors running an AArch64 instance of kvm to kvmtool. Both AArch32 and AArch64 guests are supported and, in the case of the latter, the guest page size may be either 64k or 4k.
This depends on the ARM updates series I just posted:
Quoted 7 lines
Quoted 3 lines
https://lists.cs.columbia.edu/pipermail/kvmarm/2013-January/004505.html
Feedback welcome,
So will ARMv7 continue to work after this patch even without the ARM updates? If so, I'm happy to merge the patch before the updates hit v3.9.
I think we're getting our wires crossed a bit here, so I'll try to explain my madness:
- Mainline ARM kernels cannot be booted by kvmtool yet, you currently have to use my virt/mach branch from
git://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git
I hope to upstream this for 3.9 (it has gone through the necessary review on the ARM kernel list).
- As part of the review mentioned above, some kvmtool changes were required to support SMP with the latest virt/mach. You just merged these in my ARM updates series.
- The ARMv8 kvmtool code builds on top of the series you just merged and won't apply without it. Applying it won't have any adverse effects on ARMv7 (AArch32). In fact, the two series sit together on my kvmtool/arm branch from
git://git.kernel.org/pub/scm/linux/kernel/git/will/kvmtool.git
but I posted them separately to avoid holding up the ARM updates.
Does that answer you question or have I made things worse?!
Cheers,
Will
Quoted 20 lines · Will Deacon
I think we're getting our wires crossed a bit here, so I'll try to explain my madness:
- Mainline ARM kernels cannot be booted by kvmtool yet, you currently have to use my
virt/machbranch from
git://git.kernel.org/pub/scm/linux/kernel/git/will/linux.gitI hope to upstream this for 3.9 (it has gone through the necessary review on the ARM kernel list).
- As part of the review mentioned above, some kvmtool changes were required to support SMP with the latest
virt/mach. You just merged these in my ARM updates series.- The ARMv8 kvmtool code builds on top of the series you just merged and won't apply without it. Applying it won't have any adverse effects on ARMv7 (AArch32). In fact, the two series sit together on my kvmtool/arm branch from
Quoted 5 lines
git://git.kernel.org/pub/scm/linux/kernel/git/will/kvmtool.gitbut I posted them separately to avoid holding up the ARM updates.
Does that answer you question or have I made things worse?!
Yes, it answers my question. I'll go ahead and apply the ARMv8 patches.