public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/8] kvm tools: add support for ARMv7 processors
@ 2012-11-22 15:58 Will Deacon
  2012-11-22 15:58 ` [PATCH v2 1/8] rbtree: include linux/compiler.h for definition of __always_inline Will Deacon
                   ` (8 more replies)
  0 siblings, 9 replies; 15+ messages in thread
From: Will Deacon @ 2012-11-22 15:58 UTC (permalink / raw)
  To: kvm
  Cc: penberg, marc.zyngier, c.dall, matt, peter.maydell, michael,
	levinsasha928, kvmarm, Will Deacon

Hello,

This is version two of the patches I originally posted here:

  http://www.spinics.net/lists/kvm/msg82447.html

Changes since version one include:

	- MAX_MEMORY no longer needlessly page-aligned for ARM
	- Use xread instead of read for reading the kernel image
	- Limit virtual CPUs to 8 due to hardware limitations of the GIC
	- Use hugetlbfs_path instead of NULL
	- Improved member type consistency between kvm_mem_bank and
	  kvm_userspace_memory_region
	- New tree-based device registration which moves device number
	  allocation out of the arch-dependent IRQ registration code
	- Included dependency from mainline kernel to use rbtrees without
	  including linux/compiler.h
	- SMP secondary boot now initialises the GIC CPU interface (this
	  worked by fluke previously due to a bug in kvm)
	- Added a dummy set_size_vq function to the balloon driver,
	  which I accidentally missed in the original patch (now merged)
	- Fixed header guard consistency
	- Dropped the RFC tag
	- Rebased onto latest kvmtool code

As usual, all comments welcome.

Cheers,

Will


Will Deacon (8):
  rbtree: include linux/compiler.h for definition of __always_inline
  kvm tools: don't bother including linux/compiler.h
  kvm tools: balloon: add dummy set_size_vq implementation
  kvm tools: add generic device registration mechanism
  kvm tools: keep track of registered memory banks in struct kvm
  kvm tools: teach guest_flat_to_host about memory banks starting above
    0
  kvm tools: provide a mechanism for translating host to guest
    addresses
  kvm tools: add support for ARMv7 processors

 include/linux/rbtree_augmented.h             |   1 +
 tools/kvm/Makefile                           |  23 ++-
 tools/kvm/arm/aarch32/cortex-a15.c           |  98 ++++++++++
 tools/kvm/arm/aarch32/include/kvm/barrier.h  |  10 +
 tools/kvm/arm/aarch32/include/kvm/kvm-arch.h |  30 +++
 tools/kvm/arm/aarch32/kvm-cpu.c              | 111 +++++++++++
 tools/kvm/arm/aarch32/smp-pen.S              |  30 +++
 tools/kvm/arm/fdt.c                          | 266 +++++++++++++++++++++++++++
 tools/kvm/arm/gic.c                          |  92 +++++++++
 tools/kvm/arm/include/arm-common/gic.h       |  34 ++++
 tools/kvm/arm/include/arm-common/kvm-arch.h  |  34 ++++
 tools/kvm/arm/include/kvm/kvm-cpu-arch.h     |  47 +++++
 tools/kvm/arm/ioport.c                       |   5 +
 tools/kvm/arm/irq.c                          |  17 ++
 tools/kvm/arm/kvm-cpu.c                      | 107 +++++++++++
 tools/kvm/arm/kvm.c                          |  69 +++++++
 tools/kvm/arm/smp.c                          |  21 +++
 tools/kvm/devices.c                          |  86 +++++++++
 tools/kvm/hw/pci-shmem.c                     |  12 +-
 tools/kvm/hw/vesa.c                          |  12 +-
 tools/kvm/include/kvm/devices.h              |  27 +++
 tools/kvm/include/kvm/irq.h                  |   2 +-
 tools/kvm/include/kvm/kvm.h                  |  16 +-
 tools/kvm/include/kvm/pci.h                  |   2 -
 tools/kvm/include/kvm/virtio-mmio.h          |   1 +
 tools/kvm/include/kvm/virtio-pci.h           |   2 +
 tools/kvm/include/linux/stddef.h             |   6 -
 tools/kvm/kvm.c                              |  56 +++++-
 tools/kvm/pci.c                              |  39 ++--
 tools/kvm/powerpc/irq.c                      |  10 +-
 tools/kvm/powerpc/spapr_pci.c                |   2 +-
 tools/kvm/virtio/balloon.c                   |   7 +
 tools/kvm/virtio/mmio.c                      |  11 +-
 tools/kvm/virtio/pci.c                       |  11 +-
 tools/kvm/x86/include/kvm/kvm-arch.h         |   9 -
 tools/kvm/x86/irq.c                          |   4 +-
 tools/kvm/x86/kvm.c                          |   7 +
 37 files changed, 1242 insertions(+), 75 deletions(-)
 create mode 100644 tools/kvm/arm/aarch32/cortex-a15.c
 create mode 100644 tools/kvm/arm/aarch32/include/kvm/barrier.h
 create mode 100644 tools/kvm/arm/aarch32/include/kvm/kvm-arch.h
 create mode 100644 tools/kvm/arm/aarch32/kvm-cpu.c
 create mode 100644 tools/kvm/arm/aarch32/smp-pen.S
 create mode 100644 tools/kvm/arm/fdt.c
 create mode 100644 tools/kvm/arm/gic.c
 create mode 100644 tools/kvm/arm/include/arm-common/gic.h
 create mode 100644 tools/kvm/arm/include/arm-common/kvm-arch.h
 create mode 100644 tools/kvm/arm/include/kvm/kvm-cpu-arch.h
 create mode 100644 tools/kvm/arm/ioport.c
 create mode 100644 tools/kvm/arm/irq.c
 create mode 100644 tools/kvm/arm/kvm-cpu.c
 create mode 100644 tools/kvm/arm/kvm.c
 create mode 100644 tools/kvm/arm/smp.c
 create mode 100644 tools/kvm/devices.c
 create mode 100644 tools/kvm/include/kvm/devices.h

-- 
1.8.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 1/8] rbtree: include linux/compiler.h for definition of __always_inline
  2012-11-22 15:58 [PATCH v2 0/8] kvm tools: add support for ARMv7 processors Will Deacon
@ 2012-11-22 15:58 ` Will Deacon
  2012-11-22 18:44   ` Sasha Levin
  2012-11-22 15:58 ` [PATCH v2 2/8] kvm tools: don't bother including linux/compiler.h Will Deacon
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 15+ messages in thread
From: Will Deacon @ 2012-11-22 15:58 UTC (permalink / raw)
  To: kvm
  Cc: penberg, marc.zyngier, c.dall, matt, peter.maydell, michael,
	levinsasha928, kvmarm, Will Deacon, Ingo Molnar, Andrew Morton,
	Linus Torvalds

Commit 29fc7c5a4f516d388fb6e1f6d24bfb04b8093e54 upstream.

rb_erase_augmented() is a static function annotated with
__always_inline.  This causes a compile failure when attempting to use
the rbtree implementation as a library (e.g.  kvm tool):

  rbtree_augmented.h:125:24: error: expected `=', `,', `;', `asm' or `__attribute__' before `void'

Include linux/compiler.h in rbtree_augmented.h so that the __always_inline
macro is resolved correctly.

Signed-off-by: Will Deacon <will.deacon@arm.com>
Cc: Pekka Enberg <penberg@kernel.org>
Reviewed-by: Michel Lespinasse <walken@google.com>
Cc: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
 include/linux/rbtree_augmented.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/rbtree_augmented.h b/include/linux/rbtree_augmented.h
index 214caa3..2ac60c9 100644
--- a/include/linux/rbtree_augmented.h
+++ b/include/linux/rbtree_augmented.h
@@ -24,6 +24,7 @@
 #ifndef _LINUX_RBTREE_AUGMENTED_H
 #define _LINUX_RBTREE_AUGMENTED_H
 
+#include <linux/compiler.h>
 #include <linux/rbtree.h>
 
 /*
-- 
1.8.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 2/8] kvm tools: don't bother including linux/compiler.h
  2012-11-22 15:58 [PATCH v2 0/8] kvm tools: add support for ARMv7 processors Will Deacon
  2012-11-22 15:58 ` [PATCH v2 1/8] rbtree: include linux/compiler.h for definition of __always_inline Will Deacon
@ 2012-11-22 15:58 ` Will Deacon
  2012-11-22 15:58 ` [PATCH v2 3/8] kvm tools: balloon: add dummy set_size_vq implementation Will Deacon
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Will Deacon @ 2012-11-22 15:58 UTC (permalink / raw)
  To: kvm
  Cc: penberg, marc.zyngier, c.dall, matt, peter.maydell, michael,
	levinsasha928, kvmarm, Will Deacon

linux/compiler.h will never give us a definition for __compiler_offsetof
because __KERNEL__ isn't defined, so just use the simple definition that
we have already.

This patch removes the redundant code.

Signed-off-by: Will Deacon <will.deacon@arm.com>
---
 tools/kvm/include/linux/stddef.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/tools/kvm/include/linux/stddef.h b/tools/kvm/include/linux/stddef.h
index 60ea512..39da808 100644
--- a/tools/kvm/include/linux/stddef.h
+++ b/tools/kvm/include/linux/stddef.h
@@ -1,16 +1,10 @@
 #ifndef _LINUX_STDDEF_H
 #define _LINUX_STDDEF_H
 
-#include <linux/compiler.h>
-
 #undef NULL
 #define NULL ((void *)0)
 
 #undef offsetof
-#ifdef __compiler_offsetof
-#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
-#else
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-#endif
 
 #endif
-- 
1.8.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 3/8] kvm tools: balloon: add dummy set_size_vq implementation
  2012-11-22 15:58 [PATCH v2 0/8] kvm tools: add support for ARMv7 processors Will Deacon
  2012-11-22 15:58 ` [PATCH v2 1/8] rbtree: include linux/compiler.h for definition of __always_inline Will Deacon
  2012-11-22 15:58 ` [PATCH v2 2/8] kvm tools: don't bother including linux/compiler.h Will Deacon
@ 2012-11-22 15:58 ` Will Deacon
  2012-11-22 15:58 ` [PATCH v2 4/8] kvm tools: add generic device registration mechanism Will Deacon
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Will Deacon @ 2012-11-22 15:58 UTC (permalink / raw)
  To: kvm
  Cc: penberg, marc.zyngier, c.dall, matt, peter.maydell, michael,
	levinsasha928, kvmarm, Will Deacon

Commit 5e980d372620 ("kvm tools: virtio: add dummy set_size_vq
implementations") added dummy set_size_vq implementations for a number
of devices now that they can use virtio MMIO as their transport.

Unfortunately, it missed the balloon driver, so this patch adds the same
implementation there.

Signed-off-by: Will Deacon <will.deacon@arm.com>
---
 tools/kvm/virtio/balloon.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/tools/kvm/virtio/balloon.c b/tools/kvm/virtio/balloon.c
index 3965b24..9edce87 100644
--- a/tools/kvm/virtio/balloon.c
+++ b/tools/kvm/virtio/balloon.c
@@ -232,6 +232,12 @@ static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
 	return VIRTIO_BLN_QUEUE_SIZE;
 }
 
+static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size)
+{
+	/* FIXME: dynamic */
+	return size;
+}
+
 struct virtio_ops bln_dev_virtio_ops = (struct virtio_ops) {
 	.get_config		= get_config,
 	.get_host_features	= get_host_features,
@@ -240,6 +246,7 @@ struct virtio_ops bln_dev_virtio_ops = (struct virtio_ops) {
 	.notify_vq		= notify_vq,
 	.get_pfn_vq		= get_pfn_vq,
 	.get_size_vq		= get_size_vq,
+	.set_size_vq            = set_size_vq,
 };
 
 int virtio_bln__init(struct kvm *kvm)
-- 
1.8.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 4/8] kvm tools: add generic device registration mechanism
  2012-11-22 15:58 [PATCH v2 0/8] kvm tools: add support for ARMv7 processors Will Deacon
                   ` (2 preceding siblings ...)
  2012-11-22 15:58 ` [PATCH v2 3/8] kvm tools: balloon: add dummy set_size_vq implementation Will Deacon
@ 2012-11-22 15:58 ` Will Deacon
  2012-11-22 15:58 ` [PATCH v2 5/8] kvm tools: keep track of registered memory banks in struct kvm Will Deacon
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Will Deacon @ 2012-11-22 15:58 UTC (permalink / raw)
  To: kvm
  Cc: penberg, marc.zyngier, c.dall, matt, peter.maydell, michael,
	levinsasha928, kvmarm, Will Deacon

PCI devices are currently registered into the pci_devices array via the
pci__register function, which can then be indexed later by architecture
code to construct device tree nodes. For MMIO devices, there is no such
utility.

Rather than invent a similar mechanism for MMIO, this patch creates a
global device registration mechanism, which allows the device type to be
specified when registered or indexing a device. Current users of the pci
registration code are migrated to the new infrastructure and virtio MMIO
devices are registered at init time.

As part of the device registration, allocation of the device number is
moved out of irq__register_device and performed when adding the device
header to the relevant bus tree, allowing us to maintain separate device
numberspaces for each bus.

Signed-off-by: Will Deacon <will.deacon@arm.com>
---
 tools/kvm/Makefile                  |  1 +
 tools/kvm/devices.c                 | 86 +++++++++++++++++++++++++++++++++++++
 tools/kvm/hw/pci-shmem.c            | 12 ++++--
 tools/kvm/hw/vesa.c                 | 12 ++++--
 tools/kvm/include/kvm/devices.h     | 27 ++++++++++++
 tools/kvm/include/kvm/irq.h         |  2 +-
 tools/kvm/include/kvm/pci.h         |  2 -
 tools/kvm/include/kvm/virtio-mmio.h |  1 +
 tools/kvm/include/kvm/virtio-pci.h  |  2 +
 tools/kvm/pci.c                     | 39 ++++++-----------
 tools/kvm/powerpc/irq.c             | 10 +----
 tools/kvm/powerpc/spapr_pci.c       |  2 +-
 tools/kvm/virtio/mmio.c             | 11 ++++-
 tools/kvm/virtio/pci.c              | 11 +++--
 tools/kvm/x86/irq.c                 |  4 +-
 15 files changed, 169 insertions(+), 53 deletions(-)
 create mode 100644 tools/kvm/devices.c
 create mode 100644 tools/kvm/include/kvm/devices.h

diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile
index de11060..3f25a14 100644
--- a/tools/kvm/Makefile
+++ b/tools/kvm/Makefile
@@ -50,6 +50,7 @@ OBJS	+= builtin-run.o
 OBJS	+= builtin-setup.o
 OBJS	+= builtin-stop.o
 OBJS	+= builtin-version.o
+OBJS	+= devices.o
 OBJS	+= disk/core.o
 OBJS	+= framebuffer.o
 OBJS	+= guest_compat.o
diff --git a/tools/kvm/devices.c b/tools/kvm/devices.c
new file mode 100644
index 0000000..9f1941d
--- /dev/null
+++ b/tools/kvm/devices.c
@@ -0,0 +1,86 @@
+#include "kvm/devices.h"
+#include "kvm/kvm.h"
+
+#include <linux/err.h>
+#include <linux/rbtree.h>
+
+struct device_bus {
+	struct rb_root	root;
+	int		dev_num;
+};
+
+static struct device_bus device_trees[DEVICE_BUS_MAX] = {
+	[0 ... (DEVICE_BUS_MAX - 1)] = { RB_ROOT, 0 },
+};
+
+int device__register(struct device_header *dev)
+{
+	struct device_bus *bus;
+	struct rb_node **node, *parent = NULL;
+
+	if (dev->bus_type >= DEVICE_BUS_MAX) {
+		pr_warning("Ignoring device registration on unknown bus %d\n",
+			   dev->bus_type);
+		return -EINVAL;
+	}
+
+	bus = &device_trees[dev->bus_type];
+	dev->dev_num = bus->dev_num++;
+
+	node = &bus->root.rb_node;
+	while (*node) {
+		int num = rb_entry(*node, struct device_header, node)->dev_num;
+		int result = dev->dev_num - num;
+
+		if (result < 0)
+			node = &((*node)->rb_left);
+		else if (result > 0)
+			node = &((*node)->rb_right);
+		else
+			return -EEXIST;
+	}
+
+	rb_link_node(&dev->node, parent, node);
+	rb_insert_color(&dev->node, &bus->root);
+	return 0;
+}
+
+struct device_header *device__find_dev(enum device_bus_type bus_type, u8 dev_num)
+{
+	struct rb_node *node;
+
+	if (bus_type >= DEVICE_BUS_MAX)
+		return ERR_PTR(-EINVAL);
+
+	node = device_trees[bus_type].root.rb_node;
+	while (node) {
+		struct device_header *dev = rb_entry(node, struct device_header,
+						     node);
+		if (dev_num < dev->dev_num) {
+			node = node->rb_left;
+		} else if (dev_num > dev->dev_num) {
+			node = node->rb_right;
+		} else {
+			return dev;
+		}
+	}
+
+	return NULL;
+}
+
+struct device_header *device__first_dev(enum device_bus_type bus_type)
+{
+	struct rb_node *node;
+
+	if (bus_type >= DEVICE_BUS_MAX)
+		return NULL;
+
+	node = rb_first(&device_trees[bus_type].root);
+	return node ? rb_entry(node, struct device_header, node) : NULL;
+}
+
+struct device_header *device__next_dev(struct device_header *dev)
+{
+	struct rb_node *node = rb_next(&dev->node);
+	return node ? rb_entry(node, struct device_header, node) : NULL;
+}
diff --git a/tools/kvm/hw/pci-shmem.c b/tools/kvm/hw/pci-shmem.c
index 4161335..00e5d93 100644
--- a/tools/kvm/hw/pci-shmem.c
+++ b/tools/kvm/hw/pci-shmem.c
@@ -1,3 +1,4 @@
+#include "kvm/devices.h"
 #include "kvm/pci-shmem.h"
 #include "kvm/virtio-pci-dev.h"
 #include "kvm/irq.h"
@@ -30,6 +31,11 @@ static struct pci_device_header pci_shmem_pci_device = {
 	.msix.pba_offset = cpu_to_le32(0x1001),		/* Use BAR 1 */
 };
 
+static struct device_header pci_shmem_device = {
+	.bus_type	= DEVICE_BUS_PCI,
+	.data		= &pci_shmem_pci_device,
+};
+
 /* registers for the Inter-VM shared memory device */
 enum ivshmem_registers {
 	INTRMASK = 0,
@@ -346,7 +352,7 @@ int shmem_parser(const struct option *opt, const char *arg, int unset)
 
 int pci_shmem__init(struct kvm *kvm)
 {
-	u8 dev, line, pin;
+	u8 line, pin;
 	char *mem;
 	int r;
 
@@ -354,7 +360,7 @@ int pci_shmem__init(struct kvm *kvm)
 		return 0;
 
 	/* Register good old INTx */
-	r = irq__register_device(PCI_DEVICE_ID_PCI_SHMEM, &dev, &pin, &line);
+	r = irq__register_device(PCI_DEVICE_ID_PCI_SHMEM, &pin, &line);
 	if (r < 0)
 		return r;
 
@@ -384,7 +390,7 @@ int pci_shmem__init(struct kvm *kvm)
 	pci_shmem_pci_device.bar[2] = cpu_to_le32(shmem_region->phys_addr | PCI_BASE_ADDRESS_SPACE_MEMORY);
 	pci_shmem_pci_device.bar_size[2] = shmem_region->size;
 
-	pci__register(&pci_shmem_pci_device, dev);
+	device__register(&pci_shmem_device);
 
 	/* Open shared memory and plug it into the guest */
 	mem = setup_shmem(shmem_region->handle, shmem_region->size,
diff --git a/tools/kvm/hw/vesa.c b/tools/kvm/hw/vesa.c
index a211491..33a675f 100644
--- a/tools/kvm/hw/vesa.c
+++ b/tools/kvm/hw/vesa.c
@@ -1,5 +1,6 @@
 #include "kvm/vesa.h"
 
+#include "kvm/devices.h"
 #include "kvm/virtio-pci-dev.h"
 #include "kvm/framebuffer.h"
 #include "kvm/kvm-cpu.h"
@@ -44,19 +45,24 @@ static struct pci_device_header vesa_pci_device = {
 	.bar_size[1]		= VESA_MEM_SIZE,
 };
 
+static struct device_header vesa_device = {
+	.bus_type	= DEVICE_BUS_PCI,
+	.data		= &vesa_pci_device,
+};
+
 static struct framebuffer vesafb;
 
 struct framebuffer *vesa__init(struct kvm *kvm)
 {
 	u16 vesa_base_addr;
-	u8 dev, line, pin;
+	u8 line, pin;
 	char *mem;
 	int r;
 
 	if (!kvm->cfg.vnc && !kvm->cfg.sdl)
 		return NULL;
 
-	r = irq__register_device(PCI_DEVICE_ID_VESA, &dev, &pin, &line);
+	r = irq__register_device(PCI_DEVICE_ID_VESA, &pin, &line);
 	if (r < 0)
 		return ERR_PTR(r);
 
@@ -68,7 +74,7 @@ struct framebuffer *vesa__init(struct kvm *kvm)
 	vesa_pci_device.irq_line	= line;
 	vesa_base_addr			= (u16)r;
 	vesa_pci_device.bar[0]		= cpu_to_le32(vesa_base_addr | PCI_BASE_ADDRESS_SPACE_IO);
-	pci__register(&vesa_pci_device, dev);
+	device__register(&vesa_device);
 
 	mem = mmap(NULL, VESA_MEM_SIZE, PROT_RW, MAP_ANON_NORESERVE, -1, 0);
 	if (mem == MAP_FAILED)
diff --git a/tools/kvm/include/kvm/devices.h b/tools/kvm/include/kvm/devices.h
new file mode 100644
index 0000000..c5de3de
--- /dev/null
+++ b/tools/kvm/include/kvm/devices.h
@@ -0,0 +1,27 @@
+#ifndef KVM__DEVICES_H
+#define KVM__DEVICES_H
+
+#include <linux/rbtree.h>
+#include <linux/types.h>
+
+enum device_bus_type {
+	DEVICE_BUS_PCI,
+	DEVICE_BUS_MMIO,
+	DEVICE_BUS_MAX,
+};
+
+struct device_header {
+	enum device_bus_type	bus_type;
+	void			*data;
+	int			dev_num;
+	struct rb_node		node;
+};
+
+int device__register(struct device_header *dev);
+struct device_header *device__find_dev(enum device_bus_type bus_type,
+				       u8 dev_num);
+
+struct device_header *device__first_dev(enum device_bus_type bus_type);
+struct device_header *device__next_dev(struct device_header *dev);
+
+#endif /* KVM__DEVICES_H */
diff --git a/tools/kvm/include/kvm/irq.h b/tools/kvm/include/kvm/irq.h
index 43fecaf..5c1274b 100644
--- a/tools/kvm/include/kvm/irq.h
+++ b/tools/kvm/include/kvm/irq.h
@@ -22,7 +22,7 @@ struct pci_dev {
 	struct list_head	lines;
 };
 
-int irq__register_device(u32 dev, u8 *num, u8 *pin, u8 *line);
+int irq__register_device(u32 dev, u8 *pin, u8 *line);
 
 struct rb_node *irq__get_pci_tree(void);
 
diff --git a/tools/kvm/include/kvm/pci.h b/tools/kvm/include/kvm/pci.h
index 26639b5..3da3811 100644
--- a/tools/kvm/include/kvm/pci.h
+++ b/tools/kvm/include/kvm/pci.h
@@ -9,7 +9,6 @@
 #include "kvm/kvm.h"
 #include "kvm/msi.h"
 
-#define PCI_MAX_DEVICES		256
 /*
  * PCI Configuration Mechanism #1 I/O ports. See Section 3.7.4.1.
  * ("Configuration Mechanism #1") of the PCI Local Bus Specification 2.1 for
@@ -86,7 +85,6 @@ struct pci_device_header {
 
 int pci__init(struct kvm *kvm);
 int pci__exit(struct kvm *kvm);
-int pci__register(struct pci_device_header *dev, u8 dev_num);
 struct pci_device_header *pci__find_dev(u8 dev_num);
 u32 pci_get_io_space_block(u32 size);
 void pci__config_wr(struct kvm *kvm, union pci_config_address addr, void *data, int size);
diff --git a/tools/kvm/include/kvm/virtio-mmio.h b/tools/kvm/include/kvm/virtio-mmio.h
index e0ede3c..983c8fc 100644
--- a/tools/kvm/include/kvm/virtio-mmio.h
+++ b/tools/kvm/include/kvm/virtio-mmio.h
@@ -47,6 +47,7 @@ struct virtio_mmio {
 	struct kvm		*kvm;
 	u8			irq;
 	struct virtio_mmio_hdr	hdr;
+	struct device_header	dev_hdr;
 	struct virtio_mmio_ioevent_param ioeventfds[VIRTIO_MMIO_MAX_VQ];
 };
 
diff --git a/tools/kvm/include/kvm/virtio-pci.h b/tools/kvm/include/kvm/virtio-pci.h
index 44130e0c..6d9a558 100644
--- a/tools/kvm/include/kvm/virtio-pci.h
+++ b/tools/kvm/include/kvm/virtio-pci.h
@@ -1,6 +1,7 @@
 #ifndef KVM__VIRTIO_PCI_H
 #define KVM__VIRTIO_PCI_H
 
+#include "kvm/devices.h"
 #include "kvm/pci.h"
 
 #include <linux/types.h>
@@ -19,6 +20,7 @@ struct virtio_pci_ioevent_param {
 
 struct virtio_pci {
 	struct pci_device_header pci_hdr;
+	struct device_header	dev_hdr;
 	void			*dev;
 
 	u16			base_addr;
diff --git a/tools/kvm/pci.c b/tools/kvm/pci.c
index c77d3cc..8d3732d 100644
--- a/tools/kvm/pci.c
+++ b/tools/kvm/pci.c
@@ -1,3 +1,4 @@
+#include "kvm/devices.h"
 #include "kvm/pci.h"
 #include "kvm/ioport.h"
 #include "kvm/util.h"
@@ -8,8 +9,6 @@
 
 #define PCI_BAR_OFFSET(b)		(offsetof(struct pci_device_header, bar[b]))
 
-static struct pci_device_header		*pci_devices[PCI_MAX_DEVICES];
-
 static union pci_config_address		pci_config_address;
 
 /* This is within our PCI gap - in an unused area.
@@ -63,20 +62,13 @@ static struct ioport_operations pci_config_address_ops = {
 
 static bool pci_device_exists(u8 bus_number, u8 device_number, u8 function_number)
 {
-	struct pci_device_header *dev;
-
 	if (pci_config_address.bus_number != bus_number)
 		return false;
 
 	if (pci_config_address.function_number != function_number)
 		return false;
 
-	if (device_number >= PCI_MAX_DEVICES)
-		return false;
-
-	dev = pci_devices[device_number];
-
-	return dev != NULL;
+	return !IS_ERR_OR_NULL(device__find_dev(DEVICE_BUS_PCI, device_number));
 }
 
 static bool pci_config_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
@@ -121,12 +113,13 @@ void pci__config_wr(struct kvm *kvm, union pci_config_address addr, void *data,
 
 		offset = addr.w & 0xff;
 		if (offset < sizeof(struct pci_device_header)) {
-			void *p = pci_devices[dev_num];
+			void *p = device__find_dev(DEVICE_BUS_PCI, dev_num)->data;
+			struct pci_device_header *hdr = p;
 			u8 bar = (offset - PCI_BAR_OFFSET(0)) / (sizeof(u32));
 			u32 sz = PCI_IO_SIZE;
 
-			if (bar < 6 && pci_devices[dev_num]->bar_size[bar])
-				sz = pci_devices[dev_num]->bar_size[bar];
+			if (bar < 6 && hdr->bar_size[bar])
+				sz = hdr->bar_size[bar];
 
 			/*
 			 * If the kernel masks the BAR it would expect to find the
@@ -158,7 +151,7 @@ void pci__config_rd(struct kvm *kvm, union pci_config_address addr, void *data,
 
 		offset = addr.w & 0xff;
 		if (offset < sizeof(struct pci_device_header)) {
-			void *p = pci_devices[dev_num];
+			void *p = device__find_dev(DEVICE_BUS_PCI, dev_num)->data;
 
 			memcpy(data, p + offset, size);
 		} else {
@@ -169,22 +162,14 @@ void pci__config_rd(struct kvm *kvm, union pci_config_address addr, void *data,
 	}
 }
 
-int pci__register(struct pci_device_header *dev, u8 dev_num)
-{
-	if (dev_num >= PCI_MAX_DEVICES)
-		return -ENOSPC;
-
-	pci_devices[dev_num] = dev;
-
-	return 0;
-}
-
 struct pci_device_header *pci__find_dev(u8 dev_num)
 {
-	if (dev_num >= PCI_MAX_DEVICES)
-		return ERR_PTR(-EOVERFLOW);
+	struct device_header *hdr = device__find_dev(DEVICE_BUS_PCI, dev_num);
+
+	if (IS_ERR_OR_NULL(hdr))
+		return NULL;
 
-	return pci_devices[dev_num];
+	return hdr->data;
 }
 
 int pci__init(struct kvm *kvm)
diff --git a/tools/kvm/powerpc/irq.c b/tools/kvm/powerpc/irq.c
index e89fa3b..ae9da50 100644
--- a/tools/kvm/powerpc/irq.c
+++ b/tools/kvm/powerpc/irq.c
@@ -8,6 +8,7 @@
  * by the Free Software Foundation.
  */
 
+#include "kvm/devices.h"
 #include "kvm/irq.h"
 #include "kvm/kvm.h"
 #include "kvm/util.h"
@@ -31,15 +32,8 @@
  * generic & cope with multiple PPC platform types.
  */
 
-static int pci_devs = 0;
-
-int irq__register_device(u32 dev, u8 *num, u8 *pin, u8 *line)
+int irq__register_device(u32 dev, u8 *pin, u8 *line)
 {
-	if (pci_devs >= PCI_MAX_DEVICES)
-		die("Hit PCI device limit!\n");
-
-	*num = pci_devs++;
-
 	*pin = 1;
 	/*
 	 * Have I said how nasty I find this?  Line should be dontcare... PHB
diff --git a/tools/kvm/powerpc/spapr_pci.c b/tools/kvm/powerpc/spapr_pci.c
index 9f0ce7a..5f4016c 100644
--- a/tools/kvm/powerpc/spapr_pci.c
+++ b/tools/kvm/powerpc/spapr_pci.c
@@ -302,7 +302,7 @@ int spapr_populate_pci_devices(struct kvm *kvm,
 	/* Populate PCI devices and allocate IRQs */
 	devices = 0;
 
-	for (devid = 0; devid < PCI_MAX_DEVICES; devid++) {
+	for (devid = 0; devid < KVM_MAX_DEVICES; devid++) {
 		uint32_t *irqmap = interrupt_map[devices];
 		struct pci_device_header *hdr = pci__find_dev(devid);
 
diff --git a/tools/kvm/virtio/mmio.c b/tools/kvm/virtio/mmio.c
index fe42e95..f94c54f 100644
--- a/tools/kvm/virtio/mmio.c
+++ b/tools/kvm/virtio/mmio.c
@@ -1,3 +1,4 @@
+#include "kvm/devices.h"
 #include "kvm/virtio-mmio.h"
 #include "kvm/ioeventfd.h"
 #include "kvm/ioport.h"
@@ -218,7 +219,7 @@ int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
 		     int device_id, int subsys_id, int class)
 {
 	struct virtio_mmio *vmmio = vdev->virtio;
-	u8 device, pin, line;
+	u8 pin, line;
 
 	vmmio->addr	= virtio_mmio_get_io_space_block(VIRTIO_MMIO_IO_SIZE);
 	vmmio->kvm	= kvm;
@@ -235,9 +236,15 @@ int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
 		.queue_num_max	= 256,
 	};
 
-	if (irq__register_device(subsys_id, &device, &pin, &line) < 0)
+	if (irq__register_device(subsys_id, &pin, &line) < 0)
 		return -1;
 	vmmio->irq = line;
+	vmmio->dev_hdr = (struct device_header) {
+		.bus_type	= DEVICE_BUS_MMIO,
+		.data		= vmmio,
+	};
+
+	device__register(&vmmio->dev_hdr);
 
 	/*
 	 * Instantiate guest virtio-mmio devices using kernel command line
diff --git a/tools/kvm/virtio/pci.c b/tools/kvm/virtio/pci.c
index adc8efc..3d3e599 100644
--- a/tools/kvm/virtio/pci.c
+++ b/tools/kvm/virtio/pci.c
@@ -306,7 +306,7 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
 		     int device_id, int subsys_id, int class)
 {
 	struct virtio_pci *vpci = vdev->virtio;
-	u8 pin, line, ndev;
+	u8 pin, line;
 	int r;
 
 	vpci->dev = dev;
@@ -343,6 +343,11 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
 		.bar_size[3]		= PCI_IO_SIZE,
 	};
 
+	vpci->dev_hdr = (struct device_header) {
+		.bus_type		= DEVICE_BUS_PCI,
+		.data			= &vpci->pci_hdr,
+	};
+
 	vpci->pci_hdr.msix.cap = PCI_CAP_ID_MSIX;
 	vpci->pci_hdr.msix.next = 0;
 	/*
@@ -366,7 +371,7 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
 	vpci->pci_hdr.msix.pba_offset = cpu_to_le32(1 | PCI_IO_SIZE); /* Use BAR 3 */
 	vpci->config_vector = 0;
 
-	r = irq__register_device(subsys_id, &ndev, &pin, &line);
+	r = irq__register_device(subsys_id, &pin, &line);
 	if (r < 0)
 		goto free_mmio;
 
@@ -375,7 +380,7 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
 
 	vpci->pci_hdr.irq_pin	= pin;
 	vpci->pci_hdr.irq_line	= line;
-	r = pci__register(&vpci->pci_hdr, ndev);
+	r = device__register(&vpci->dev_hdr);
 	if (r < 0)
 		goto free_ioport;
 
diff --git a/tools/kvm/x86/irq.c b/tools/kvm/x86/irq.c
index 8dc90bf..7447c6b 100644
--- a/tools/kvm/x86/irq.c
+++ b/tools/kvm/x86/irq.c
@@ -17,7 +17,6 @@
 #define IRQCHIP_IOAPIC			2
 
 static u8		next_line	= 5;
-static u8		next_dev	= 1;
 static struct rb_root	pci_tree	= RB_ROOT;
 
 /* First 24 GSIs are routed between IRQCHIPs and IOAPICs */
@@ -86,7 +85,7 @@ static int insert(struct rb_root *root, struct pci_dev *data)
 	return 0;
 }
 
-int irq__register_device(u32 dev, u8 *num, u8 *pin, u8 *line)
+int irq__register_device(u32 dev, u8 *pin, u8 *line)
 {
 	struct pci_dev *node;
 	int r;
@@ -128,7 +127,6 @@ int irq__register_device(u32 dev, u8 *num, u8 *pin, u8 *line)
 		new->line	= next_line++;
 		*line		= new->line;
 		*pin		= node->pin;
-		*num		= next_dev++;
 
 		list_add(&new->node, &node->lines);
 
-- 
1.8.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 5/8] kvm tools: keep track of registered memory banks in struct kvm
  2012-11-22 15:58 [PATCH v2 0/8] kvm tools: add support for ARMv7 processors Will Deacon
                   ` (3 preceding siblings ...)
  2012-11-22 15:58 ` [PATCH v2 4/8] kvm tools: add generic device registration mechanism Will Deacon
@ 2012-11-22 15:58 ` Will Deacon
  2012-11-22 15:58 ` [PATCH v2 6/8] kvm tools: teach guest_flat_to_host about memory banks starting above 0 Will Deacon
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Will Deacon @ 2012-11-22 15:58 UTC (permalink / raw)
  To: kvm
  Cc: penberg, marc.zyngier, c.dall, matt, peter.maydell, michael,
	levinsasha928, kvmarm, Will Deacon

When registering memory banks for a guest, it is useful to keep the
range information around for translating between guest and host address
spaces.

This patch adds a list of kvm_mem_bank structures to struct kvm, which
is updated when a new bank is registered.

Signed-off-by: Will Deacon <will.deacon@arm.com>
---
 tools/kvm/include/kvm/kvm.h |  8 ++++++++
 tools/kvm/kvm.c             | 23 ++++++++++++++++++++++-
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/tools/kvm/include/kvm/kvm.h b/tools/kvm/include/kvm/kvm.h
index cf959ea..9b4a9a4 100644
--- a/tools/kvm/include/kvm/kvm.h
+++ b/tools/kvm/include/kvm/kvm.h
@@ -35,6 +35,13 @@ struct kvm_ext {
 	int code;
 };
 
+struct kvm_mem_bank {
+	struct list_head	list;
+	u64			guest_phys_addr;
+	void			*host_addr;
+	u64			size;
+};
+
 struct kvm {
 	struct kvm_arch		arch;
 	struct kvm_config	cfg;
@@ -49,6 +56,7 @@ struct kvm {
 	u64			ram_size;
 	void			*ram_start;
 	u64			ram_pagesize;
+	struct list_head	mem_banks;
 
 	bool			nmi_disabled;
 
diff --git a/tools/kvm/kvm.c b/tools/kvm/kvm.c
index b283171..1a10ec0 100644
--- a/tools/kvm/kvm.c
+++ b/tools/kvm/kvm.c
@@ -6,7 +6,9 @@
 #include "kvm/kvm-cpu.h"
 #include "kvm/kvm-ipc.h"
 
+#include <linux/kernel.h>
 #include <linux/kvm.h>
+#include <linux/list.h>
 #include <linux/err.h>
 
 #include <sys/un.h>
@@ -133,9 +135,16 @@ struct kvm *kvm__new(void)
 
 int kvm__exit(struct kvm *kvm)
 {
+	struct kvm_mem_bank *bank, *tmp;
+
 	kvm__arch_delete_ram(kvm);
-	free(kvm);
 
+	list_for_each_entry_safe(bank, tmp, &kvm->mem_banks, list) {
+		list_del(&bank->list);
+		free(bank);
+	}
+
+	free(kvm);
 	return 0;
 }
 core_exit(kvm__exit);
@@ -148,8 +157,18 @@ core_exit(kvm__exit);
 int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr)
 {
 	struct kvm_userspace_memory_region mem;
+	struct kvm_mem_bank *bank;
 	int ret;
 
+	bank = malloc(sizeof(*bank));
+	if (!bank)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&bank->list);
+	bank->guest_phys_addr		= guest_phys;
+	bank->host_addr			= userspace_addr;
+	bank->size			= size;
+
 	mem = (struct kvm_userspace_memory_region) {
 		.slot			= kvm->mem_slots++,
 		.guest_phys_addr	= guest_phys,
@@ -161,6 +180,7 @@ int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace
 	if (ret < 0)
 		return -errno;
 
+	list_add(&bank->list, &kvm->mem_banks);
 	return 0;
 }
 
@@ -245,6 +265,7 @@ int kvm__init(struct kvm *kvm)
 
 	kvm__arch_init(kvm, kvm->cfg.hugetlbfs_path, kvm->cfg.ram_size);
 
+	INIT_LIST_HEAD(&kvm->mem_banks);
 	kvm__init_ram(kvm);
 
 	if (!kvm->cfg.firmware_filename) {
-- 
1.8.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 6/8] kvm tools: teach guest_flat_to_host about memory banks starting above 0
  2012-11-22 15:58 [PATCH v2 0/8] kvm tools: add support for ARMv7 processors Will Deacon
                   ` (4 preceding siblings ...)
  2012-11-22 15:58 ` [PATCH v2 5/8] kvm tools: keep track of registered memory banks in struct kvm Will Deacon
@ 2012-11-22 15:58 ` Will Deacon
  2012-11-22 15:58 ` [PATCH v2 7/8] kvm tools: provide a mechanism for translating host to guest addresses Will Deacon
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Will Deacon @ 2012-11-22 15:58 UTC (permalink / raw)
  To: kvm
  Cc: penberg, marc.zyngier, c.dall, matt, peter.maydell, michael,
	levinsasha928, kvmarm, Will Deacon

Running a guest with multiple banks of memory based above 0 causes the
guest_flat_to_host address conversion to fail, as it is assumed that
guest memory addresses are offset linearly from 0.

This patch changes the translation function so that the kvm_mem_bank
structures registered by kvm__register_mem are used to translate guest
addresses, rather than use an offset from the start of host memory.

Signed-off-by: Will Deacon <will.deacon@arm.com>
---
 tools/kvm/include/kvm/kvm.h          |  7 ++-----
 tools/kvm/kvm.c                      | 17 +++++++++++++++++
 tools/kvm/x86/include/kvm/kvm-arch.h |  9 ---------
 tools/kvm/x86/kvm.c                  |  7 +++++++
 4 files changed, 26 insertions(+), 14 deletions(-)

diff --git a/tools/kvm/include/kvm/kvm.h b/tools/kvm/include/kvm/kvm.h
index 9b4a9a4..5fb2fb2 100644
--- a/tools/kvm/include/kvm/kvm.h
+++ b/tools/kvm/include/kvm/kvm.h
@@ -105,6 +105,8 @@ int kvm__arch_free_firmware(struct kvm *kvm);
 bool kvm__arch_cpu_supports_vm(void);
 void kvm__arch_periodic_poll(struct kvm *kvm);
 
+void *guest_flat_to_host(struct kvm *kvm, u64 offset);
+
 int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline);
 bool load_bzimage(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline, u16 vidmode);
 
@@ -120,11 +122,6 @@ static inline bool host_ptr_in_ram(struct kvm *kvm, void *p)
 	return kvm->ram_start <= p && p < (kvm->ram_start + kvm->ram_size);
 }
 
-static inline void *guest_flat_to_host(struct kvm *kvm, unsigned long offset)
-{
-	return kvm->ram_start + offset;
-}
-
 bool kvm__supports_extension(struct kvm *kvm, unsigned int extension);
 
 static inline void kvm__set_thread_name(const char *name)
diff --git a/tools/kvm/kvm.c b/tools/kvm/kvm.c
index 1a10ec0..a7e2628 100644
--- a/tools/kvm/kvm.c
+++ b/tools/kvm/kvm.c
@@ -184,6 +184,23 @@ int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace
 	return 0;
 }
 
+void *guest_flat_to_host(struct kvm *kvm, u64 offset)
+{
+	struct kvm_mem_bank *bank;
+
+	list_for_each_entry(bank, &kvm->mem_banks, list) {
+		u64 bank_start = bank->guest_phys_addr;
+		u64 bank_end = bank_start + bank->size;
+
+		if (offset >= bank_start && offset < bank_end)
+			return bank->host_addr + (offset - bank_start);
+	}
+
+	pr_warning("unable to translate guest address 0x%llx to host",
+			(unsigned long long)offset);
+	return NULL;
+}
+
 int kvm__recommended_cpus(struct kvm *kvm)
 {
 	int ret;
diff --git a/tools/kvm/x86/include/kvm/kvm-arch.h b/tools/kvm/x86/include/kvm/kvm-arch.h
index 2aaedcc..1e0949e 100644
--- a/tools/kvm/x86/include/kvm/kvm-arch.h
+++ b/tools/kvm/x86/include/kvm/kvm-arch.h
@@ -33,13 +33,4 @@ struct kvm_arch {
 	struct interrupt_table	interrupt_table;
 };
 
-static inline void *guest_flat_to_host(struct kvm *kvm, unsigned long offset); /* In kvm.h */
-
-static inline void *guest_real_to_host(struct kvm *kvm, u16 selector, u16 offset)
-{
-	unsigned long flat = segment_to_flat(selector, offset);
-
-	return guest_flat_to_host(kvm, flat);
-}
-
 #endif /* KVM__KVM_ARCH_H */
diff --git a/tools/kvm/x86/kvm.c b/tools/kvm/x86/kvm.c
index ecada45..9971ffd 100644
--- a/tools/kvm/x86/kvm.c
+++ b/tools/kvm/x86/kvm.c
@@ -199,6 +199,13 @@ void kvm__irq_trigger(struct kvm *kvm, int irq)
 #define BOOT_PROTOCOL_REQUIRED	0x206
 #define LOAD_HIGH		0x01
 
+static inline void *guest_real_to_host(struct kvm *kvm, u16 selector, u16 offset)
+{
+	unsigned long flat = segment_to_flat(selector, offset);
+
+	return guest_flat_to_host(kvm, flat);
+}
+
 int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline)
 {
 	void *p;
-- 
1.8.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 7/8] kvm tools: provide a mechanism for translating host to guest addresses
  2012-11-22 15:58 [PATCH v2 0/8] kvm tools: add support for ARMv7 processors Will Deacon
                   ` (5 preceding siblings ...)
  2012-11-22 15:58 ` [PATCH v2 6/8] kvm tools: teach guest_flat_to_host about memory banks starting above 0 Will Deacon
@ 2012-11-22 15:58 ` Will Deacon
  2012-11-22 15:58 ` [PATCH v2 8/8] kvm tools: add support for ARMv7 processors Will Deacon
  2012-11-23 11:22 ` [PATCH v2 0/8] " Pekka Enberg
  8 siblings, 0 replies; 15+ messages in thread
From: Will Deacon @ 2012-11-22 15:58 UTC (permalink / raw)
  To: kvm
  Cc: penberg, marc.zyngier, c.dall, matt, peter.maydell, michael,
	levinsasha928, kvmarm, Will Deacon

When generating a device tree for a guest, it is useful to have a helper
for converting host addresses to guest addresses in order to populate
the device nodes correctly.

This patch adds such a helper, following a similar implementation to the
reverse translation function that already exists.

Signed-off-by: Will Deacon <will.deacon@arm.com>
---
 tools/kvm/include/kvm/kvm.h |  1 +
 tools/kvm/kvm.c             | 16 ++++++++++++++++
 2 files changed, 17 insertions(+)

diff --git a/tools/kvm/include/kvm/kvm.h b/tools/kvm/include/kvm/kvm.h
index 5fb2fb2..b54ac03 100644
--- a/tools/kvm/include/kvm/kvm.h
+++ b/tools/kvm/include/kvm/kvm.h
@@ -106,6 +106,7 @@ bool kvm__arch_cpu_supports_vm(void);
 void kvm__arch_periodic_poll(struct kvm *kvm);
 
 void *guest_flat_to_host(struct kvm *kvm, u64 offset);
+u64 host_to_guest_flat(struct kvm *kvm, void *ptr);
 
 int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline);
 bool load_bzimage(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline, u16 vidmode);
diff --git a/tools/kvm/kvm.c b/tools/kvm/kvm.c
index a7e2628..af19e37 100644
--- a/tools/kvm/kvm.c
+++ b/tools/kvm/kvm.c
@@ -201,6 +201,22 @@ void *guest_flat_to_host(struct kvm *kvm, u64 offset)
 	return NULL;
 }
 
+u64 host_to_guest_flat(struct kvm *kvm, void *ptr)
+{
+	struct kvm_mem_bank *bank;
+
+	list_for_each_entry(bank, &kvm->mem_banks, list) {
+		void *bank_start = bank->host_addr;
+		void *bank_end = bank_start + bank->size;
+
+		if (ptr >= bank_start && ptr < bank_end)
+			return bank->guest_phys_addr + (ptr - bank_start);
+	}
+
+	pr_warning("unable to translate host address %p to guest", ptr);
+	return 0;
+}
+
 int kvm__recommended_cpus(struct kvm *kvm)
 {
 	int ret;
-- 
1.8.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 8/8] kvm tools: add support for ARMv7 processors
  2012-11-22 15:58 [PATCH v2 0/8] kvm tools: add support for ARMv7 processors Will Deacon
                   ` (6 preceding siblings ...)
  2012-11-22 15:58 ` [PATCH v2 7/8] kvm tools: provide a mechanism for translating host to guest addresses Will Deacon
@ 2012-11-22 15:58 ` Will Deacon
  2012-11-22 16:13   ` Peter Maydell
  2012-11-23 11:22 ` [PATCH v2 0/8] " Pekka Enberg
  8 siblings, 1 reply; 15+ messages in thread
From: Will Deacon @ 2012-11-22 15:58 UTC (permalink / raw)
  To: kvm
  Cc: penberg, marc.zyngier, c.dall, matt, peter.maydell, michael,
	levinsasha928, kvmarm, Will Deacon

This patch adds initial support for ARMv7 processors (more specifically,
Cortex-A15) to kvmtool.

Everything is driven by FDT, including dynamic generation of virtio nodes
for MMIO devices (PCI is not used due to lack of a suitable host-bridge).

The virtual timers and virtual interrupt controller (VGIC) are provided
by the kernel and require very little in terms of userspace code.

Signed-off-by: Will Deacon <will.deacon@arm.com>
---
 tools/kvm/Makefile                           |  22 ++-
 tools/kvm/arm/aarch32/cortex-a15.c           |  98 ++++++++++
 tools/kvm/arm/aarch32/include/kvm/barrier.h  |  10 +
 tools/kvm/arm/aarch32/include/kvm/kvm-arch.h |  30 +++
 tools/kvm/arm/aarch32/kvm-cpu.c              | 111 +++++++++++
 tools/kvm/arm/aarch32/smp-pen.S              |  30 +++
 tools/kvm/arm/fdt.c                          | 266 +++++++++++++++++++++++++++
 tools/kvm/arm/gic.c                          |  92 +++++++++
 tools/kvm/arm/include/arm-common/gic.h       |  34 ++++
 tools/kvm/arm/include/arm-common/kvm-arch.h  |  34 ++++
 tools/kvm/arm/include/kvm/kvm-cpu-arch.h     |  47 +++++
 tools/kvm/arm/ioport.c                       |   5 +
 tools/kvm/arm/irq.c                          |  17 ++
 tools/kvm/arm/kvm-cpu.c                      | 107 +++++++++++
 tools/kvm/arm/kvm.c                          |  69 +++++++
 tools/kvm/arm/smp.c                          |  21 +++
 16 files changed, 992 insertions(+), 1 deletion(-)
 create mode 100644 tools/kvm/arm/aarch32/cortex-a15.c
 create mode 100644 tools/kvm/arm/aarch32/include/kvm/barrier.h
 create mode 100644 tools/kvm/arm/aarch32/include/kvm/kvm-arch.h
 create mode 100644 tools/kvm/arm/aarch32/kvm-cpu.c
 create mode 100644 tools/kvm/arm/aarch32/smp-pen.S
 create mode 100644 tools/kvm/arm/fdt.c
 create mode 100644 tools/kvm/arm/gic.c
 create mode 100644 tools/kvm/arm/include/arm-common/gic.h
 create mode 100644 tools/kvm/arm/include/arm-common/kvm-arch.h
 create mode 100644 tools/kvm/arm/include/kvm/kvm-cpu-arch.h
 create mode 100644 tools/kvm/arm/ioport.c
 create mode 100644 tools/kvm/arm/irq.c
 create mode 100644 tools/kvm/arm/kvm-cpu.c
 create mode 100644 tools/kvm/arm/kvm.c
 create mode 100644 tools/kvm/arm/smp.c

diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile
index 3f25a14..a83dd10 100644
--- a/tools/kvm/Makefile
+++ b/tools/kvm/Makefile
@@ -102,7 +102,8 @@ OBJS	+= builtin-sandbox.o
 OBJS	+= virtio/mmio.o
 
 # Translate uname -m into ARCH string
-ARCH ?= $(shell uname -m | sed -e s/i.86/i386/ -e s/ppc.*/powerpc/)
+ARCH ?= $(shell uname -m | sed -e s/i.86/i386/ -e s/ppc.*/powerpc/ \
+	  -e s/armv7.*/arm/)
 
 ifeq ($(ARCH),i386)
 	ARCH         := x86
@@ -157,6 +158,25 @@ ifeq ($(ARCH), powerpc)
 	CFLAGS 	+= -m64
 endif
 
+# ARM
+OBJS_ARM_COMMON		:= arm/fdt.o arm/gic.o arm/ioport.o arm/irq.o \
+			   arm/kvm.o arm/kvm-cpu.o arm/smp.o
+HDRS_ARM_COMMON		:= arm/include
+ifeq ($(ARCH), arm)
+	DEFINES		+= -DCONFIG_ARM
+	OBJS		+= $(OBJS_ARM_COMMON)
+	OBJS		+= arm/aarch32/cortex-a15.o
+	OBJS		+= arm/aarch32/kvm-cpu.o
+	OBJS       	+= arm/aarch32/smp-pen.o
+	ARCH_INCLUDE	:= $(HDRS_ARM_COMMON)
+	ARCH_INCLUDE	+= -Iarm/aarch32/include
+	ASFLAGS		+= -D__ASSEMBLY__
+	ASFLAGS		+= -I$(ARCH_INCLUDE)
+	CFLAGS		+= -march=armv7-a
+	CFLAGS		+= -I../../scripts/dtc/libfdt
+	OTHEROBJS	+= $(LIBFDT_OBJS)
+endif
+
 ###
 
 ifeq (,$(ARCH_INCLUDE))
diff --git a/tools/kvm/arm/aarch32/cortex-a15.c b/tools/kvm/arm/aarch32/cortex-a15.c
new file mode 100644
index 0000000..eac0bb9
--- /dev/null
+++ b/tools/kvm/arm/aarch32/cortex-a15.c
@@ -0,0 +1,98 @@
+#include "kvm/fdt.h"
+#include "kvm/kvm.h"
+#include "kvm/kvm-cpu.h"
+#include "kvm/util.h"
+
+#include "arm-common/gic.h"
+
+#include <linux/byteorder.h>
+#include <linux/types.h>
+
+#define CPU_NAME_MAX_LEN 8
+static void generate_cpu_nodes(void *fdt, struct kvm *kvm)
+{
+	int cpu;
+
+	_FDT(fdt_begin_node(fdt, "cpus"));
+	_FDT(fdt_property_cell(fdt, "#address-cells", 0x1));
+	_FDT(fdt_property_cell(fdt, "#size-cells", 0x0));
+
+	for (cpu = 0; cpu < kvm->nrcpus; ++cpu) {
+		char cpu_name[CPU_NAME_MAX_LEN];
+
+		if (kvm->cpus[cpu]->cpu_type != KVM_ARM_TARGET_CORTEX_A15) {
+			pr_warning("Ignoring unknown type for CPU %d\n", cpu);
+			continue;
+		}
+
+		snprintf(cpu_name, CPU_NAME_MAX_LEN, "cpu@%d", cpu);
+
+		_FDT(fdt_begin_node(fdt, cpu_name));
+		_FDT(fdt_property_string(fdt, "device_type", "cpu"));
+		_FDT(fdt_property_string(fdt, "compatible", "arm,cortex-a15"));
+
+		if (kvm->nrcpus > 1) {
+			_FDT(fdt_property_string(fdt, "enable-method",
+						 "spin-table"));
+			_FDT(fdt_property_cell(fdt, "cpu-release-addr",
+					       kvm->arch.smp_jump_guest_start));
+		}
+
+		_FDT(fdt_property_cell(fdt, "reg", cpu));
+		_FDT(fdt_end_node(fdt));
+	}
+
+	_FDT(fdt_end_node(fdt));
+}
+
+static void generate_timer_nodes(void *fdt, struct kvm *kvm)
+{
+	u32 cpu_mask = (((1 << kvm->nrcpus) - 1) << GIC_FDT_IRQ_PPI_CPU_SHIFT) \
+		       & GIC_FDT_IRQ_PPI_CPU_MASK;
+	u32 irq_prop[] = {
+		cpu_to_fdt32(GIC_FDT_IRQ_TYPE_PPI),
+		cpu_to_fdt32(13),
+		cpu_to_fdt32(cpu_mask | GIC_FDT_IRQ_FLAGS_EDGE_LO_HI),
+
+		cpu_to_fdt32(GIC_FDT_IRQ_TYPE_PPI),
+		cpu_to_fdt32(14),
+		cpu_to_fdt32(cpu_mask | GIC_FDT_IRQ_FLAGS_EDGE_LO_HI),
+
+		cpu_to_fdt32(GIC_FDT_IRQ_TYPE_PPI),
+		cpu_to_fdt32(11),
+		cpu_to_fdt32(cpu_mask | GIC_FDT_IRQ_FLAGS_EDGE_LO_HI),
+
+		cpu_to_fdt32(GIC_FDT_IRQ_TYPE_PPI),
+		cpu_to_fdt32(10),
+		cpu_to_fdt32(cpu_mask | GIC_FDT_IRQ_FLAGS_EDGE_LO_HI),
+	};
+
+	_FDT(fdt_begin_node(fdt, "timer"));
+	_FDT(fdt_property_string(fdt, "compatible", "arm,armv7-timer"));
+	_FDT(fdt_property(fdt, "interrupts", irq_prop, sizeof(irq_prop)));
+	_FDT(fdt_end_node(fdt));
+}
+
+static void generate_fdt_nodes(void *fdt, struct kvm *kvm, u32 gic_phandle)
+{
+	generate_cpu_nodes(fdt, kvm);
+	gic__generate_fdt_nodes(fdt, gic_phandle);
+	generate_timer_nodes(fdt, kvm);
+}
+
+static int cortex_a15__vcpu_init(struct kvm_cpu *vcpu)
+{
+	vcpu->generate_fdt_nodes = generate_fdt_nodes;
+	return 0;
+}
+
+static struct kvm_arm_target target_cortex_a15 = {
+	.id	= KVM_ARM_TARGET_CORTEX_A15,
+	.init	= cortex_a15__vcpu_init,
+};
+
+static int cortex_a15__core_init(struct kvm *kvm)
+{
+	return kvm_cpu__register_kvm_arm_target(&target_cortex_a15);
+}
+core_init(cortex_a15__core_init);
diff --git a/tools/kvm/arm/aarch32/include/kvm/barrier.h b/tools/kvm/arm/aarch32/include/kvm/barrier.h
new file mode 100644
index 0000000..94913a9
--- /dev/null
+++ b/tools/kvm/arm/aarch32/include/kvm/barrier.h
@@ -0,0 +1,10 @@
+#ifndef KVM__KVM_BARRIER_H
+#define KVM__KVM_BARRIER_H
+
+#define dmb()	asm volatile ("dmb" : : : "memory")
+
+#define mb()	dmb()
+#define rmb()	dmb()
+#define wmb()	dmb()
+
+#endif /* KVM__KVM_BARRIER_H */
diff --git a/tools/kvm/arm/aarch32/include/kvm/kvm-arch.h b/tools/kvm/arm/aarch32/include/kvm/kvm-arch.h
new file mode 100644
index 0000000..f236895
--- /dev/null
+++ b/tools/kvm/arm/aarch32/include/kvm/kvm-arch.h
@@ -0,0 +1,30 @@
+#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_SMP_PEN_SIZE	PAGE_SIZE
+#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 KVM_PCI_MMIO_AREA	ARM_LOMAP_AXI_AREA
+#define KVM_VIRTIO_MMIO_AREA	ARM_LOMAP_MMIO_AREA
+
+#include "arm-common/kvm-arch.h"
+
+#endif /* KVM__KVM_ARCH_H */
diff --git a/tools/kvm/arm/aarch32/kvm-cpu.c b/tools/kvm/arm/aarch32/kvm-cpu.c
new file mode 100644
index 0000000..f00a2f1
--- /dev/null
+++ b/tools/kvm/arm/aarch32/kvm-cpu.c
@@ -0,0 +1,111 @@
+#include "kvm/kvm-cpu.h"
+#include "kvm/kvm.h"
+
+#include <asm/ptrace.h>
+
+#define ARM_CORE_REG(x)	(KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_CORE | \
+			 KVM_REG_ARM_CORE_REG(x))
+
+void kvm_cpu__reset_vcpu(struct kvm_cpu *vcpu)
+{
+	struct kvm *kvm	= vcpu->kvm;
+	struct kvm_one_reg reg;
+	u32 data;
+
+	/* Who said future-proofing was a good idea? */
+	reg.addr = (u64)(unsigned long)&data;
+
+	/* cpsr = IRQs/FIQs masked */
+	data	= PSR_I_BIT | PSR_F_BIT | SVC_MODE;
+	reg.id	= ARM_CORE_REG(usr_regs.ARM_cpsr);
+	if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &reg) < 0)
+		die_perror("KVM_SET_ONE_REG failed (cpsr)");
+
+	if (vcpu->cpu_id == 0) {
+		/* r0 = 0 */
+		data	= 0;
+		reg.id	= ARM_CORE_REG(usr_regs.ARM_r0);
+		if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &reg) < 0)
+			die_perror("KVM_SET_ONE_REG failed (r0)");
+
+		/* r1 = machine type (-1) */
+		data	= -1;
+		reg.id	= ARM_CORE_REG(usr_regs.ARM_r1);
+		if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &reg) < 0)
+			die_perror("KVM_SET_ONE_REG failed (r1)");
+
+		/* r2 = physical address of the device tree blob */
+		data	= kvm->arch.dtb_guest_start;
+		reg.id	= ARM_CORE_REG(usr_regs.ARM_r2);
+		if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &reg) < 0)
+			die_perror("KVM_SET_ONE_REG failed (r2)");
+
+		/* pc = start of kernel image */
+		data	= kvm->arch.kern_guest_start;
+		reg.id	= ARM_CORE_REG(usr_regs.ARM_pc);
+		if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &reg) < 0)
+			die_perror("KVM_SET_ONE_REG failed (pc)");
+
+	} else {
+		/* Simply enter the pen */
+		data	= kvm->arch.smp_pen_guest_start;
+		reg.id	= ARM_CORE_REG(usr_regs.ARM_pc);
+		if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &reg) < 0)
+			die_perror("KVM_SET_ONE_REG failed (SMP pc)");
+	}
+}
+
+void kvm_cpu__show_code(struct kvm_cpu *vcpu)
+{
+	struct kvm_one_reg reg;
+	u32 data;
+
+	reg.addr = (u64)(unsigned long)&data;
+
+	printf("*pc:\n");
+	reg.id = ARM_CORE_REG(usr_regs.ARM_pc);
+	if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg) < 0)
+		die("KVM_GET_ONE_REG failed (show_code @ PC)");
+
+	kvm__dump_mem(vcpu->kvm, data, 32);
+	printf("\n");
+
+	printf("*lr (svc):\n");
+	reg.id = ARM_CORE_REG(svc_regs[1]);
+	if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg) < 0)
+		die("KVM_GET_ONE_REG failed (show_code @ LR_svc)");
+	data &= ~0x1;
+
+	kvm__dump_mem(vcpu->kvm, data, 32);
+	printf("\n");
+}
+
+void kvm_cpu__show_registers(struct kvm_cpu *vcpu)
+{
+	struct kvm_one_reg reg;
+	u32 data;
+	int debug_fd = kvm_cpu__get_debug_fd();
+
+	reg.addr	= (u64)(unsigned long)&data;
+	dprintf(debug_fd, "\n Registers:\n");
+
+	reg.id		= ARM_CORE_REG(usr_regs.ARM_pc);
+	if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg) < 0)
+		die("KVM_GET_ONE_REG failed (pc)");
+	dprintf(debug_fd, " PC:    0x%x\n", data);
+
+	reg.id		= ARM_CORE_REG(usr_regs.ARM_cpsr);
+	if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg) < 0)
+		die("KVM_GET_ONE_REG failed (cpsr)");
+	dprintf(debug_fd, " CPSR:  0x%x\n", data);
+
+	reg.id		= ARM_CORE_REG(svc_regs[0]);
+	if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg) < 0)
+		die("KVM_GET_ONE_REG failed (SP_svc)");
+	dprintf(debug_fd, " SP_svc:  0x%x\n", data);
+
+	reg.id		= ARM_CORE_REG(svc_regs[1]);
+	if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg) < 0)
+		die("KVM_GET_ONE_REG failed (LR_svc)");
+	dprintf(debug_fd, " LR_svc:  0x%x\n", data);
+}
diff --git a/tools/kvm/arm/aarch32/smp-pen.S b/tools/kvm/arm/aarch32/smp-pen.S
new file mode 100644
index 0000000..57c6f8d
--- /dev/null
+++ b/tools/kvm/arm/aarch32/smp-pen.S
@@ -0,0 +1,30 @@
+#include "kvm/kvm-arch.h"
+
+#include "arm-common/gic.h"
+
+	.arm
+
+	.globl	smp_pen_start
+	.globl	smp_jump_addr
+	.globl	smp_pen_end
+
+	.align
+smp_pen_start:
+	@ Ensure that the CPU interface is enabled for the wfi wakeup
+	ldr	r0, =ARM_GIC_CPUI_BASE
+	mov	r1, #GIC_CPUI_CTLR_EN
+	str	r1, [r0]
+
+	@ Now wait for the primary to poke us
+	adr	r0, smp_jump_addr
+	dsb
+	wfi
+	ldr	r1, [r0]
+	mov	pc, r1
+
+	.ltorg
+
+	.align
+smp_jump_addr:
+	.long	0xdeadc0de
+smp_pen_end:
diff --git a/tools/kvm/arm/fdt.c b/tools/kvm/arm/fdt.c
new file mode 100644
index 0000000..d9d33dd
--- /dev/null
+++ b/tools/kvm/arm/fdt.c
@@ -0,0 +1,266 @@
+#include "kvm/devices.h"
+#include "kvm/fdt.h"
+#include "kvm/kvm.h"
+#include "kvm/kvm-cpu.h"
+#include "kvm/virtio-mmio.h"
+
+#include "arm-common/gic.h"
+
+#include <stdbool.h>
+
+#include <asm/setup.h>
+#include <linux/byteorder.h>
+#include <linux/kernel.h>
+#include <linux/sizes.h>
+
+#define DEBUG			0
+#define DEBUG_FDT_DUMP_FILE	"/tmp/kvmtool.dtb"
+
+static char kern_cmdline[COMMAND_LINE_SIZE];
+
+bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename)
+{
+	return false;
+}
+
+int kvm__arch_setup_firmware(struct kvm *kvm)
+{
+	return 0;
+}
+
+#if DEBUG
+static void dump_fdt(void *fdt)
+{
+	int count, fd;
+
+	fd = open(DEBUG_FDT_DUMP_FILE, O_CREAT | O_TRUNC | O_RDWR, 0666);
+	if (fd < 0)
+		die("Failed to write dtb to %s", DEBUG_FDT_DUMP_FILE);
+
+	count = write(fd, fdt, FDT_MAX_SIZE);
+	if (count < 0)
+		die_perror("Failed to dump dtb");
+
+	pr_info("Wrote %d bytes to dtb %s\n", count, DEBUG_FDT_DUMP_FILE);
+	close(fd);
+}
+#else
+static void dump_fdt(void *fdt) { }
+#endif
+
+#define DEVICE_NAME_MAX_LEN 32
+static void generate_virtio_mmio_node(void *fdt, struct virtio_mmio *vmmio)
+{
+	char dev_name[DEVICE_NAME_MAX_LEN];
+	u64 addr = vmmio->addr;
+	u64 reg_prop[] = {
+		cpu_to_fdt64(addr),
+		cpu_to_fdt64(VIRTIO_MMIO_IO_SIZE)
+	};
+	u32 irq_prop[] = {
+		cpu_to_fdt32(GIC_FDT_IRQ_TYPE_SPI),
+		cpu_to_fdt32(vmmio->irq - GIC_SPI_IRQ_BASE),
+		cpu_to_fdt32(GIC_FDT_IRQ_FLAGS_EDGE_LO_HI),
+	};
+
+	snprintf(dev_name, DEVICE_NAME_MAX_LEN, "virtio@%llx", addr);
+
+	_FDT(fdt_begin_node(fdt, dev_name));
+	_FDT(fdt_property_string(fdt, "compatible", "virtio,mmio"));
+	_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
+	_FDT(fdt_property(fdt, "interrupts", irq_prop, sizeof(irq_prop)));
+	_FDT(fdt_end_node(fdt));
+}
+
+static int setup_fdt(struct kvm *kvm)
+{
+	struct device_header *dev_hdr;
+	u8 staging_fdt[FDT_MAX_SIZE];
+	u32 gic_phandle		= fdt__alloc_phandle();
+	u64 mem_reg_prop[]	= {
+		cpu_to_fdt64(kvm->arch.memory_guest_start),
+		cpu_to_fdt64(kvm->ram_size),
+	};
+	void *fdt		= staging_fdt;
+	void *fdt_dest		= guest_flat_to_host(kvm,
+						     kvm->arch.dtb_guest_start);
+	void (*generate_cpu_nodes)(void *, struct kvm *, u32)
+				= kvm->cpus[0]->generate_fdt_nodes;
+
+	/* Create new tree without a reserve map */
+	_FDT(fdt_create(fdt, FDT_MAX_SIZE));
+	if (kvm->nrcpus > 1)
+		_FDT(fdt_add_reservemap_entry(fdt,
+					      kvm->arch.smp_pen_guest_start,
+					      ARM_SMP_PEN_SIZE));
+	_FDT(fdt_finish_reservemap(fdt));
+
+	/* Header */
+	_FDT(fdt_begin_node(fdt, ""));
+	_FDT(fdt_property_cell(fdt, "interrupt-parent", gic_phandle));
+	_FDT(fdt_property_string(fdt, "compatible", "linux,dummy-virt"));
+	_FDT(fdt_property_cell(fdt, "#address-cells", 0x2));
+	_FDT(fdt_property_cell(fdt, "#size-cells", 0x2));
+
+	/* /chosen */
+	_FDT(fdt_begin_node(fdt, "chosen"));
+	_FDT(fdt_property_string(fdt, "bootargs", kern_cmdline));
+
+	/* Initrd */
+	if (kvm->arch.initrd_size != 0) {
+		u32 ird_st_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start);
+		u32 ird_end_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start +
+					       kvm->arch.initrd_size);
+
+		_FDT(fdt_property(fdt, "linux,initrd-start",
+				   &ird_st_prop, sizeof(ird_st_prop)));
+		_FDT(fdt_property(fdt, "linux,initrd-end",
+				   &ird_end_prop, sizeof(ird_end_prop)));
+	}
+	_FDT(fdt_end_node(fdt));
+
+	/* Memory */
+	_FDT(fdt_begin_node(fdt, "memory"));
+	_FDT(fdt_property_string(fdt, "device_type", "memory"));
+	_FDT(fdt_property(fdt, "reg", mem_reg_prop, sizeof(mem_reg_prop)));
+	_FDT(fdt_end_node(fdt));
+
+	/* CPU and peripherals (interrupt controller, timers, etc) */
+	if (generate_cpu_nodes)
+		generate_cpu_nodes(fdt, kvm, gic_phandle);
+
+	/* Virtio MMIO devices */
+	dev_hdr = device__first_dev(DEVICE_BUS_MMIO);
+	while (dev_hdr) {
+		generate_virtio_mmio_node(fdt, dev_hdr->data);
+		dev_hdr = device__next_dev(dev_hdr);
+	}
+
+	/* Finalise. */
+	_FDT(fdt_end_node(fdt));
+	_FDT(fdt_finish(fdt));
+
+	_FDT(fdt_open_into(fdt, fdt_dest, FDT_MAX_SIZE));
+	_FDT(fdt_pack(fdt_dest));
+
+	dump_fdt(fdt_dest);
+	return 0;
+}
+firmware_init(setup_fdt);
+
+static int read_image(int fd, void **pos, void *limit)
+{
+	int count;
+
+	while (((count = xread(fd, *pos, SZ_64K)) > 0) && *pos <= limit)
+		*pos += count;
+
+	if (pos < 0)
+		die_perror("xread");
+
+	return *pos < limit ? 0 : -ENOMEM;
+}
+
+#define FDT_ALIGN	SZ_2M
+#define INITRD_ALIGN	4
+#define SMP_PEN_ALIGN	PAGE_SIZE
+int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd,
+		     const char *kernel_cmdline)
+{
+	void *pos, *kernel_end, *limit;
+	unsigned long guest_addr;
+
+	if (lseek(fd_kernel, 0, SEEK_SET) < 0)
+		die_perror("lseek");
+
+	/*
+	 * Linux requires the initrd, pen and dtb to be mapped inside
+	 * lowmem, so we can't just place them at the top of memory.
+	 */
+	limit = kvm->ram_start + min(kvm->ram_size, (u64)SZ_256M) - 1;
+
+	pos = kvm->ram_start + ARM_KERN_OFFSET;
+	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.");
+
+	kernel_end = pos;
+	pr_info("Loaded kernel to 0x%llx (%llu bytes)",
+		kvm->arch.kern_guest_start,
+		host_to_guest_flat(kvm, pos) - kvm->arch.kern_guest_start);
+
+	/*
+	 * Now load backwards from the end of memory so the kernel
+	 * decompressor has plenty of space to work with. First up is
+	 * the SMP pen if we have more than one virtual CPU...
+	 */
+	pos = limit;
+	if (kvm->cfg.nrcpus > 1) {
+		pos -= (ARM_SMP_PEN_SIZE + SMP_PEN_ALIGN);
+		guest_addr = ALIGN(host_to_guest_flat(kvm, pos), SMP_PEN_ALIGN);
+		pos = guest_flat_to_host(kvm, guest_addr);
+		if (pos < kernel_end)
+			die("SMP pen overlaps with kernel image.");
+
+		kvm->arch.smp_pen_guest_start = guest_addr;
+		pr_info("Placing SMP pen at 0x%llx - 0x%llx",
+			kvm->arch.smp_pen_guest_start,
+			host_to_guest_flat(kvm, limit));
+		limit = pos;
+	}
+
+	/* ...now the device tree blob... */
+	pos -= (FDT_MAX_SIZE + FDT_ALIGN);
+	guest_addr = ALIGN(host_to_guest_flat(kvm, pos), FDT_ALIGN);
+	pos = guest_flat_to_host(kvm, guest_addr);
+	if (pos < kernel_end)
+		die("fdt overlaps with kernel image.");
+
+	kvm->arch.dtb_guest_start = guest_addr;
+	pr_info("Placing fdt at 0x%llx - 0x%llx",
+		kvm->arch.dtb_guest_start,
+		host_to_guest_flat(kvm, limit));
+	limit = pos;
+
+	/* ... and finally the initrd, if we have one. */
+	if (fd_initrd != -1) {
+		struct stat sb;
+		unsigned long initrd_start;
+
+		if (lseek(fd_initrd, 0, SEEK_SET) < 0)
+			die_perror("lseek");
+
+		if (fstat(fd_initrd, &sb))
+			die_perror("fstat");
+
+		pos -= (sb.st_size + INITRD_ALIGN);
+		guest_addr = ALIGN(host_to_guest_flat(kvm, pos), INITRD_ALIGN);
+		pos = guest_flat_to_host(kvm, guest_addr);
+		if (pos < kernel_end)
+			die("initrd overlaps with kernel image.");
+
+		initrd_start = guest_addr;
+		if (read_image(fd_initrd, &pos, limit) == -ENOMEM)
+			die("initrd too big to contain in guest memory.");
+
+		kvm->arch.initrd_guest_start = initrd_start;
+		kvm->arch.initrd_size = host_to_guest_flat(kvm, pos) - initrd_start;
+		pr_info("Loaded initrd to 0x%llx (%llu bytes)",
+			kvm->arch.initrd_guest_start,
+			kvm->arch.initrd_size);
+	} else {
+		kvm->arch.initrd_size = 0;
+	}
+
+	strncpy(kern_cmdline, kernel_cmdline, COMMAND_LINE_SIZE);
+	kern_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
+
+	return true;
+}
+
+bool load_bzimage(struct kvm *kvm, int fd_kernel,
+		  int fd_initrd, const char *kernel_cmdline, u16 vidmode)
+{
+	/* To b or not to b? That is the zImage. */
+	return false;
+}
diff --git a/tools/kvm/arm/gic.c b/tools/kvm/arm/gic.c
new file mode 100644
index 0000000..3f42c3a
--- /dev/null
+++ b/tools/kvm/arm/gic.c
@@ -0,0 +1,92 @@
+#include "kvm/fdt.h"
+#include "kvm/kvm.h"
+#include "kvm/virtio.h"
+
+#include "arm-common/gic.h"
+
+#include <linux/byteorder.h>
+#include <linux/kvm.h>
+
+static int irq_ids;
+
+int gic__alloc_irqnum(void)
+{
+	int irq = GIC_SPI_IRQ_BASE + irq_ids++;
+
+	if (irq > GIC_MAX_IRQ)
+		die("GIC IRQ limit %d reached!", GIC_MAX_IRQ);
+
+	return irq;
+}
+
+int gic__init_irqchip(struct kvm *kvm)
+{
+	int err;
+	struct kvm_device_address gic_addr[] = {
+		[0] = {
+			.id = (KVM_ARM_DEVICE_VGIC_V2 << KVM_DEVICE_ID_SHIFT) |\
+			       KVM_VGIC_V2_ADDR_TYPE_DIST,
+			.addr = ARM_GIC_DIST_BASE,
+		},
+		[1] = {
+			.id = (KVM_ARM_DEVICE_VGIC_V2 << KVM_DEVICE_ID_SHIFT) |\
+			       KVM_VGIC_V2_ADDR_TYPE_CPU,
+			.addr = ARM_GIC_CPUI_BASE,
+		}
+	};
+
+	if (kvm->nrcpus > GIC_MAX_CPUS) {
+		pr_warning("%d CPUS greater than maximum of %d -- truncating\n",
+				kvm->nrcpus, GIC_MAX_CPUS);
+		kvm->nrcpus = GIC_MAX_CPUS;
+	}
+
+	err = ioctl(kvm->vm_fd, KVM_CREATE_IRQCHIP);
+	if (err)
+		return err;
+
+	err = ioctl(kvm->vm_fd, KVM_SET_DEVICE_ADDRESS, &gic_addr[0]);
+	if (err)
+		return err;
+
+	err = ioctl(kvm->vm_fd, KVM_SET_DEVICE_ADDRESS, &gic_addr[1]);
+	return err;
+}
+
+void gic__generate_fdt_nodes(void *fdt, u32 phandle)
+{
+	u64 reg_prop[] = {
+		cpu_to_fdt64(ARM_GIC_DIST_BASE), cpu_to_fdt64(ARM_GIC_DIST_SIZE),
+		cpu_to_fdt64(ARM_GIC_CPUI_BASE), cpu_to_fdt64(ARM_GIC_CPUI_SIZE),
+	};
+
+	_FDT(fdt_begin_node(fdt, "intc"));
+	_FDT(fdt_property_string(fdt, "compatible", "arm,cortex-a15-gic"));
+	_FDT(fdt_property_cell(fdt, "#interrupt-cells", GIC_FDT_IRQ_NUM_CELLS));
+	_FDT(fdt_property(fdt, "interrupt-controller", NULL, 0));
+	_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
+	_FDT(fdt_property_cell(fdt, "phandle", phandle));
+	_FDT(fdt_end_node(fdt));
+}
+
+#define KVM_IRQCHIP_IRQ(x) (KVM_ARM_IRQ_TYPE_SPI << KVM_ARM_IRQ_TYPE_SHIFT) |\
+			   ((x) & KVM_ARM_IRQ_NUM_MASK)
+
+void kvm__irq_line(struct kvm *kvm, int irq, int level)
+{
+	struct kvm_irq_level irq_level = {
+		.irq	= KVM_IRQCHIP_IRQ(irq),
+		.level	= !!level,
+	};
+
+	if (irq < GIC_SPI_IRQ_BASE || irq > GIC_MAX_IRQ)
+		pr_warning("Ignoring invalid GIC IRQ %d", irq);
+	else if (ioctl(kvm->vm_fd, KVM_IRQ_LINE, &irq_level) < 0)
+		pr_warning("Could not KVM_IRQ_LINE for irq %d", irq);
+}
+
+void kvm__irq_trigger(struct kvm *kvm, int irq)
+{
+	kvm__irq_line(kvm, irq, VIRTIO_IRQ_HIGH);
+	kvm__irq_line(kvm, irq, VIRTIO_IRQ_LOW);
+}
diff --git a/tools/kvm/arm/include/arm-common/gic.h b/tools/kvm/arm/include/arm-common/gic.h
new file mode 100644
index 0000000..d534174
--- /dev/null
+++ b/tools/kvm/arm/include/arm-common/gic.h
@@ -0,0 +1,34 @@
+#ifndef ARM_COMMON__GIC_H
+#define ARM_COMMON__GIC_H
+
+#define GIC_SGI_IRQ_BASE		0
+#define GIC_PPI_IRQ_BASE		16
+#define GIC_SPI_IRQ_BASE		32
+
+#define GIC_FDT_IRQ_NUM_CELLS		3
+
+#define GIC_FDT_IRQ_TYPE_SPI		0
+#define GIC_FDT_IRQ_TYPE_PPI		1
+
+#define GIC_FDT_IRQ_FLAGS_EDGE_LO_HI	1
+#define GIC_FDT_IRQ_FLAGS_EDGE_HI_LO	2
+#define GIC_FDT_IRQ_FLAGS_LEVEL_HI	4
+#define GIC_FDT_IRQ_FLAGS_LEVEL_LO	8
+
+#define GIC_FDT_IRQ_PPI_CPU_SHIFT	8
+#define GIC_FDT_IRQ_PPI_CPU_MASK	(0xff << GIC_FDT_IRQ_PPI_CPU_SHIFT)
+
+#define GIC_CPUI_CTLR_EN		(1 << 0)
+
+#define GIC_MAX_CPUS			8
+#define GIC_MAX_IRQ			255
+
+#ifndef __ASSEMBLY__
+struct kvm;
+
+int gic__alloc_irqnum(void);
+int gic__init_irqchip(struct kvm *kvm);
+void gic__generate_fdt_nodes(void *fdt, u32 phandle);
+
+#endif /* __ASSEMBLY__ */
+#endif /* ARM_COMMON__GIC_H */
diff --git a/tools/kvm/arm/include/arm-common/kvm-arch.h b/tools/kvm/arm/include/arm-common/kvm-arch.h
new file mode 100644
index 0000000..c910f07
--- /dev/null
+++ b/tools/kvm/arm/include/arm-common/kvm-arch.h
@@ -0,0 +1,34 @@
+#ifndef ARM_COMMON__KVM_ARCH_H
+#define ARM_COMMON__KVM_ARCH_H
+
+#define VIRTIO_DEFAULT_TRANS	VIRTIO_MMIO
+
+#ifndef __ASSEMBLY__
+
+#include <stdbool.h>
+#include <linux/types.h>
+
+static inline bool arm_addr_in_virtio_mmio_region(u64 phys_addr)
+{
+	u64 limit = KVM_VIRTIO_MMIO_AREA + ARM_VIRTIO_MMIO_SIZE;
+	return phys_addr >= KVM_VIRTIO_MMIO_AREA && phys_addr < limit;
+}
+
+static inline bool arm_addr_in_pci_mmio_region(u64 phys_addr)
+{
+	u64 limit = KVM_PCI_MMIO_AREA + ARM_PCI_MMIO_SIZE;
+	return phys_addr >= KVM_PCI_MMIO_AREA && phys_addr < limit;
+}
+
+struct kvm_arch {
+	u64	memory_guest_start;
+	u64	kern_guest_start;
+	u64	initrd_guest_start;
+	u64	initrd_size;
+	u64	dtb_guest_start;
+	u64	smp_pen_guest_start;
+	u64	smp_jump_guest_start;
+};
+
+#endif /* __ASSEMBLY__ */
+#endif /* ARM_COMMON__KVM_ARCH_H */
diff --git a/tools/kvm/arm/include/kvm/kvm-cpu-arch.h b/tools/kvm/arm/include/kvm/kvm-cpu-arch.h
new file mode 100644
index 0000000..d4618e9
--- /dev/null
+++ b/tools/kvm/arm/include/kvm/kvm-cpu-arch.h
@@ -0,0 +1,47 @@
+#ifndef ARM_COMMON__KVM_CPU_ARCH_H
+#define ARM_COMMON__KVM_CPU_ARCH_H
+
+#include <linux/kvm.h>
+#include <pthread.h>
+#include <stdbool.h>
+
+struct kvm;
+
+struct kvm_cpu {
+	pthread_t	thread;
+
+	unsigned long	cpu_id;
+	unsigned long	cpu_type;
+
+	struct kvm	*kvm;
+	int		vcpu_fd;
+	struct kvm_run	*kvm_run;
+
+	u8		is_running;
+	u8		paused;
+	u8		needs_nmi;
+
+	struct kvm_coalesced_mmio_ring	*ring;
+
+	void		(*generate_fdt_nodes)(void *fdt, struct kvm* kvm,
+					      u32 gic_phandle);
+};
+
+struct kvm_arm_target {
+	u32	id;
+	int	(*init)(struct kvm_cpu *vcpu);
+};
+
+int kvm_cpu__register_kvm_arm_target(struct kvm_arm_target *target);
+
+static inline bool kvm_cpu__emulate_io(struct kvm *kvm, u16 port, void *data,
+				       int direction, int size, u32 count)
+{
+	return false;
+}
+
+bool kvm_cpu__emulate_mmio(struct kvm *kvm, u64 phys_addr, u8 *data, u32 len,
+			   u8 is_write);
+
+#endif /* ARM_COMMON__KVM_CPU_ARCH_H */
+
diff --git a/tools/kvm/arm/ioport.c b/tools/kvm/arm/ioport.c
new file mode 100644
index 0000000..3c03fa0
--- /dev/null
+++ b/tools/kvm/arm/ioport.c
@@ -0,0 +1,5 @@
+#include "kvm/ioport.h"
+
+void ioport__setup_arch(struct kvm *kvm)
+{
+}
diff --git a/tools/kvm/arm/irq.c b/tools/kvm/arm/irq.c
new file mode 100644
index 0000000..e173e04
--- /dev/null
+++ b/tools/kvm/arm/irq.c
@@ -0,0 +1,17 @@
+#include "kvm/irq.h"
+#include "kvm/kvm.h"
+#include "kvm/util.h"
+
+#include "arm-common/gic.h"
+
+int irq__register_device(u32 dev, u8 *pin, u8 *line)
+{
+	*line = gic__alloc_irqnum();
+	return 0;
+}
+
+int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg)
+{
+	die(__FUNCTION__);
+	return 0;
+}
diff --git a/tools/kvm/arm/kvm-cpu.c b/tools/kvm/arm/kvm-cpu.c
new file mode 100644
index 0000000..3b08e55
--- /dev/null
+++ b/tools/kvm/arm/kvm-cpu.c
@@ -0,0 +1,107 @@
+#include "kvm/kvm.h"
+#include "kvm/kvm-cpu.h"
+
+static int debug_fd;
+
+void kvm_cpu__set_debug_fd(int fd)
+{
+	debug_fd = fd;
+}
+
+int kvm_cpu__get_debug_fd(void)
+{
+	return debug_fd;
+}
+
+static struct kvm_arm_target *kvm_arm_targets[KVM_ARM_NUM_TARGETS];
+int kvm_cpu__register_kvm_arm_target(struct kvm_arm_target *target)
+{
+	unsigned int i = 0;
+
+	for (i = 0; i < ARRAY_SIZE(kvm_arm_targets); ++i) {
+		if (!kvm_arm_targets[i]) {
+			kvm_arm_targets[i] = target;
+			return 0;
+		}
+	}
+
+	return -ENOSPC;
+}
+
+struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id)
+{
+	struct kvm_cpu *vcpu;
+	int coalesced_offset, mmap_size, err = -1;
+	unsigned int i;
+	struct kvm_vcpu_init vcpu_init = { };
+
+	vcpu = calloc(1, sizeof(struct kvm_cpu));
+	if (!vcpu)
+		return NULL;
+
+	vcpu->vcpu_fd = ioctl(kvm->vm_fd, KVM_CREATE_VCPU, cpu_id);
+	if (vcpu->vcpu_fd < 0)
+		die_perror("KVM_CREATE_VCPU ioctl");
+
+	mmap_size = ioctl(kvm->sys_fd, KVM_GET_VCPU_MMAP_SIZE, 0);
+	if (mmap_size < 0)
+		die_perror("KVM_GET_VCPU_MMAP_SIZE ioctl");
+
+	vcpu->kvm_run = mmap(NULL, mmap_size, PROT_RW, MAP_SHARED,
+			     vcpu->vcpu_fd, 0);
+	if (vcpu->kvm_run == MAP_FAILED)
+		die("unable to mmap vcpu fd");
+
+	/* Find an appropriate target CPU type. */
+	for (i = 0; i < ARRAY_SIZE(kvm_arm_targets); ++i) {
+		vcpu_init.target = kvm_arm_targets[i]->id;
+		err = ioctl(vcpu->vcpu_fd, KVM_ARM_VCPU_INIT, &vcpu_init);
+		if (!err)
+			break;
+	}
+
+	if (err || kvm_arm_targets[i]->init(vcpu))
+		die("Unable to initialise ARM vcpu");
+
+	coalesced_offset = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION,
+				 KVM_CAP_COALESCED_MMIO);
+	if (coalesced_offset)
+		vcpu->ring = (void *)vcpu->kvm_run +
+			     (coalesced_offset * PAGE_SIZE);
+
+	/* Populate the vcpu structure. */
+	vcpu->kvm		= kvm;
+	vcpu->cpu_id		= cpu_id;
+	vcpu->cpu_type		= vcpu_init.target;
+	vcpu->is_running	= true;
+	return vcpu;
+}
+
+void kvm_cpu__arch_nmi(struct kvm_cpu *cpu)
+{
+}
+
+void kvm_cpu__delete(struct kvm_cpu *vcpu)
+{
+	free(vcpu);
+}
+
+bool kvm_cpu__handle_exit(struct kvm_cpu *vcpu)
+{
+	return false;
+}
+
+bool kvm_cpu__emulate_mmio(struct kvm *kvm, u64 phys_addr, u8 *data, u32 len,
+			   u8 is_write)
+{
+	if (arm_addr_in_virtio_mmio_region(phys_addr))
+		return kvm__emulate_mmio(kvm, phys_addr, data, len, is_write);
+	else if (arm_addr_in_pci_mmio_region(phys_addr))
+		die("PCI emulation not supported on ARM!");
+
+	return false;
+}
+
+void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
+{
+}
diff --git a/tools/kvm/arm/kvm.c b/tools/kvm/arm/kvm.c
new file mode 100644
index 0000000..bfce685
--- /dev/null
+++ b/tools/kvm/arm/kvm.c
@@ -0,0 +1,69 @@
+#include "kvm/kvm.h"
+#include "kvm/term.h"
+#include "kvm/util.h"
+#include "kvm/virtio-console.h"
+
+#include "arm-common/gic.h"
+
+#include <linux/kernel.h>
+#include <linux/kvm.h>
+
+struct kvm_ext kvm_req_ext[] = {
+	{ DEFINE_KVM_EXT(KVM_CAP_IRQCHIP) },
+	{ DEFINE_KVM_EXT(KVM_CAP_ONE_REG) },
+	{ 0, 0 },
+};
+
+bool kvm__arch_cpu_supports_vm(void)
+{
+	/* The KVM capability check is enough. */
+	return true;
+}
+
+void kvm__init_ram(struct kvm *kvm)
+{
+	int err;
+	u64 phys_start, phys_size;
+	void *host_mem;
+
+	phys_start	= ARM_MEMORY_AREA;
+	phys_size	= kvm->ram_size;
+	host_mem	= kvm->ram_start;
+
+	err = kvm__register_mem(kvm, phys_start, phys_size, host_mem);
+	if (err)
+		die("Failed to register %lld bytes of memory at physical "
+		    "address 0x%llx [err %d]", phys_size, phys_start, err);
+
+	kvm->arch.memory_guest_start = phys_start;
+}
+
+void kvm__arch_delete_ram(struct kvm *kvm)
+{
+	munmap(kvm->ram_start, kvm->ram_size);
+}
+
+void kvm__arch_periodic_poll(struct kvm *kvm)
+{
+	if (term_readable(0))
+		virtio_console__inject_interrupt(kvm);
+}
+
+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_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)",
+		    kvm->ram_size, errno);
+	madvise(kvm->ram_start, kvm->ram_size, MADV_MERGEABLE);
+
+	/* Initialise the virtual GIC. */
+	if (gic__init_irqchip(kvm))
+		die("Failed to initialise virtual GIC");
+}
diff --git a/tools/kvm/arm/smp.c b/tools/kvm/arm/smp.c
new file mode 100644
index 0000000..3a659bc
--- /dev/null
+++ b/tools/kvm/arm/smp.c
@@ -0,0 +1,21 @@
+#include "kvm/kvm.h"
+
+extern u8 smp_pen_start, smp_pen_end, smp_jump_addr;
+
+static int smp_pen_init(struct kvm *kvm)
+{
+	unsigned long pen_size, pen_start, jump_offset;
+
+	if (!(kvm->nrcpus > 1))
+		return 0;
+
+	pen_size = &smp_pen_end - &smp_pen_start;
+	pen_start = kvm->arch.smp_pen_guest_start;
+	jump_offset = &smp_jump_addr - &smp_pen_start;
+
+	kvm->arch.smp_jump_guest_start = pen_start + jump_offset;
+	memcpy(guest_flat_to_host(kvm, pen_start), &smp_pen_start, pen_size);
+
+	return 0;
+}
+base_init(smp_pen_init);
-- 
1.8.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 8/8] kvm tools: add support for ARMv7 processors
  2012-11-22 15:58 ` [PATCH v2 8/8] kvm tools: add support for ARMv7 processors Will Deacon
@ 2012-11-22 16:13   ` Peter Maydell
  2012-11-22 16:22     ` Will Deacon
  0 siblings, 1 reply; 15+ messages in thread
From: Peter Maydell @ 2012-11-22 16:13 UTC (permalink / raw)
  To: Will Deacon
  Cc: kvm, penberg, marc.zyngier, c.dall, matt, michael, levinsasha928,
	kvmarm

On 22 November 2012 15:58, Will Deacon <will.deacon@arm.com> wrote:
> +++ b/tools/kvm/arm/aarch32/smp-pen.S
> @@ -0,0 +1,30 @@
> +#include "kvm/kvm-arch.h"
> +
> +#include "arm-common/gic.h"
> +
> +       .arm
> +
> +       .globl  smp_pen_start
> +       .globl  smp_jump_addr
> +       .globl  smp_pen_end
> +
> +       .align
> +smp_pen_start:
> +       @ Ensure that the CPU interface is enabled for the wfi wakeup
> +       ldr     r0, =ARM_GIC_CPUI_BASE
> +       mov     r1, #GIC_CPUI_CTLR_EN
> +       str     r1, [r0]
> +
> +       @ Now wait for the primary to poke us
> +       adr     r0, smp_jump_addr
> +       dsb
> +       wfi
> +       ldr     r1, [r0]
> +       mov     pc, r1
> +
> +       .ltorg
> +
> +       .align
> +smp_jump_addr:
> +       .long   0xdeadc0de
> +smp_pen_end:

You've left the gate ajar on your pen -- this won't cope with
spurious WFI wakeups (the architecture allows WFI to return
at any time, down to the trivial case of "implemented as NOP").
Needs a 'branch back to WFI if not yet poked' (or you could
make the initial value stored at smp_jump_addr be the address
of the wfi :-))

-- PMM

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 8/8] kvm tools: add support for ARMv7 processors
  2012-11-22 16:13   ` Peter Maydell
@ 2012-11-22 16:22     ` Will Deacon
  0 siblings, 0 replies; 15+ messages in thread
From: Will Deacon @ 2012-11-22 16:22 UTC (permalink / raw)
  To: Peter Maydell
  Cc: kvm@vger.kernel.org, penberg@kernel.org, Marc Zyngier,
	c.dall@virtualopensystems.com, matt@ozlabs.org,
	michael@ellerman.id.au, levinsasha928@gmail.com,
	kvmarm@lists.cs.columbia.edu

Hi Peter,

On Thu, Nov 22, 2012 at 04:13:17PM +0000, Peter Maydell wrote:
> On 22 November 2012 15:58, Will Deacon <will.deacon@arm.com> wrote:
> > +++ b/tools/kvm/arm/aarch32/smp-pen.S
> > @@ -0,0 +1,30 @@
> > +#include "kvm/kvm-arch.h"
> > +
> > +#include "arm-common/gic.h"
> > +
> > +       .arm
> > +
> > +       .globl  smp_pen_start
> > +       .globl  smp_jump_addr
> > +       .globl  smp_pen_end
> > +
> > +       .align
> > +smp_pen_start:
> > +       @ Ensure that the CPU interface is enabled for the wfi wakeup
> > +       ldr     r0, =ARM_GIC_CPUI_BASE
> > +       mov     r1, #GIC_CPUI_CTLR_EN
> > +       str     r1, [r0]
> > +
> > +       @ Now wait for the primary to poke us
> > +       adr     r0, smp_jump_addr
> > +       dsb
> > +       wfi
> > +       ldr     r1, [r0]
> > +       mov     pc, r1
> > +
> > +       .ltorg
> > +
> > +       .align
> > +smp_jump_addr:
> > +       .long   0xdeadc0de
> > +smp_pen_end:
> 
> You've left the gate ajar on your pen -- this won't cope with
> spurious WFI wakeups (the architecture allows WFI to return
> at any time, down to the trivial case of "implemented as NOP").
> Needs a 'branch back to WFI if not yet poked' (or you could
> make the initial value stored at smp_jump_addr be the address
> of the wfi :-))

Thanks for pointing this out, somehow I missed it despite updating the ARMv8
code. Will fix for v3.

Will

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/8] rbtree: include linux/compiler.h for definition of __always_inline
  2012-11-22 15:58 ` [PATCH v2 1/8] rbtree: include linux/compiler.h for definition of __always_inline Will Deacon
@ 2012-11-22 18:44   ` Sasha Levin
  2012-11-23 14:36     ` Will Deacon
  0 siblings, 1 reply; 15+ messages in thread
From: Sasha Levin @ 2012-11-22 18:44 UTC (permalink / raw)
  To: Will Deacon
  Cc: kvm, penberg, marc.zyngier, c.dall, matt, peter.maydell, michael,
	kvmarm, Ingo Molnar, Andrew Morton, Linus Torvalds

On 11/22/2012 10:58 AM, Will Deacon wrote:
> Commit 29fc7c5a4f516d388fb6e1f6d24bfb04b8093e54 upstream.
> 
> rb_erase_augmented() is a static function annotated with
> __always_inline.  This causes a compile failure when attempting to use
> the rbtree implementation as a library (e.g.  kvm tool):
> 
>   rbtree_augmented.h:125:24: error: expected `=', `,', `;', `asm' or `__attribute__' before `void'

On a side note, our rbtree-interval is broken at the moment due to kernel side
changing the implementation and (IMO) breaking augmented rbtrees, followed
by several patches in our own code that tried to fix the breakage but haven't
identified the problem correctly - leading to more subtle breakage.

If you see things broken with mmio, that might be the reason.

I have a fix for that which goes to both kernel and our code, but I'm
waiting to verify that the kernel side is indeed broken.


Thanks,
Sasha

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 0/8] kvm tools: add support for ARMv7 processors
  2012-11-22 15:58 [PATCH v2 0/8] kvm tools: add support for ARMv7 processors Will Deacon
                   ` (7 preceding siblings ...)
  2012-11-22 15:58 ` [PATCH v2 8/8] kvm tools: add support for ARMv7 processors Will Deacon
@ 2012-11-23 11:22 ` Pekka Enberg
  2012-11-23 14:38   ` Will Deacon
  8 siblings, 1 reply; 15+ messages in thread
From: Pekka Enberg @ 2012-11-23 11:22 UTC (permalink / raw)
  To: Will Deacon
  Cc: kvm, marc.zyngier, c.dall, matt, peter.maydell, michael,
	levinsasha928, kvmarm

On Thu, 22 Nov 2012, Will Deacon wrote:
> Hello,
> 
> This is version two of the patches I originally posted here:
> 
>   http://www.spinics.net/lists/kvm/msg82447.html
> 
> Changes since version one include:
> 
> 	- MAX_MEMORY no longer needlessly page-aligned for ARM
> 	- Use xread instead of read for reading the kernel image
> 	- Limit virtual CPUs to 8 due to hardware limitations of the GIC
> 	- Use hugetlbfs_path instead of NULL
> 	- Improved member type consistency between kvm_mem_bank and
> 	  kvm_userspace_memory_region
> 	- New tree-based device registration which moves device number
> 	  allocation out of the arch-dependent IRQ registration code
> 	- Included dependency from mainline kernel to use rbtrees without
> 	  including linux/compiler.h
> 	- SMP secondary boot now initialises the GIC CPU interface (this
> 	  worked by fluke previously due to a bug in kvm)
> 	- Added a dummy set_size_vq function to the balloon driver,
> 	  which I accidentally missed in the original patch (now merged)
> 	- Fixed header guard consistency
> 	- Dropped the RFC tag
> 	- Rebased onto latest kvmtool code
> 
> As usual, all comments welcome.

I applied patches 1-7. I'll wait for a new revision of the final 
patch. Thanks, Will!

			Pekka

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/8] rbtree: include linux/compiler.h for definition of __always_inline
  2012-11-22 18:44   ` Sasha Levin
@ 2012-11-23 14:36     ` Will Deacon
  0 siblings, 0 replies; 15+ messages in thread
From: Will Deacon @ 2012-11-23 14:36 UTC (permalink / raw)
  To: Sasha Levin
  Cc: kvm@vger.kernel.org, penberg@kernel.org, Marc Zyngier,
	c.dall@virtualopensystems.com, matt@ozlabs.org,
	peter.maydell@linaro.org, michael@ellerman.id.au,
	kvmarm@lists.cs.columbia.edu, Ingo Molnar, Andrew Morton,
	Linus Torvalds

Hi Sasha,

On Thu, Nov 22, 2012 at 06:44:34PM +0000, Sasha Levin wrote:
> On 11/22/2012 10:58 AM, Will Deacon wrote:
> > Commit 29fc7c5a4f516d388fb6e1f6d24bfb04b8093e54 upstream.
> > 
> > rb_erase_augmented() is a static function annotated with
> > __always_inline.  This causes a compile failure when attempting to use
> > the rbtree implementation as a library (e.g.  kvm tool):
> > 
> >   rbtree_augmented.h:125:24: error: expected `=', `,', `;', `asm' or `__attribute__' before `void'
> 
> On a side note, our rbtree-interval is broken at the moment due to kernel side
> changing the implementation and (IMO) breaking augmented rbtrees, followed
> by several patches in our own code that tried to fix the breakage but haven't
> identified the problem correctly - leading to more subtle breakage.
> 
> If you see things broken with mmio, that might be the reason.

Interesting... the only problems I've seen with MMIO so far have all been
related to highmem and I've been sending patches for those (should all make
it for 3.8).

What specifically do you see when things go wrong?

Will

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 0/8] kvm tools: add support for ARMv7 processors
  2012-11-23 11:22 ` [PATCH v2 0/8] " Pekka Enberg
@ 2012-11-23 14:38   ` Will Deacon
  0 siblings, 0 replies; 15+ messages in thread
From: Will Deacon @ 2012-11-23 14:38 UTC (permalink / raw)
  To: Pekka Enberg
  Cc: kvm@vger.kernel.org, Marc Zyngier, c.dall@virtualopensystems.com,
	matt@ozlabs.org, peter.maydell@linaro.org, michael@ellerman.id.au,
	levinsasha928@gmail.com, kvmarm@lists.cs.columbia.edu

On Fri, Nov 23, 2012 at 11:22:24AM +0000, Pekka Enberg wrote:
> On Thu, 22 Nov 2012, Will Deacon wrote:
> > This is version two of the patches I originally posted here:
> > 
> >   http://www.spinics.net/lists/kvm/msg82447.html

[...]

> I applied patches 1-7. I'll wait for a new revision of the final 
> patch. Thanks, Will!

Great, thanks Pekka! I'll send a v3 of that last patch now...

Will

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2012-11-23 14:39 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-11-22 15:58 [PATCH v2 0/8] kvm tools: add support for ARMv7 processors Will Deacon
2012-11-22 15:58 ` [PATCH v2 1/8] rbtree: include linux/compiler.h for definition of __always_inline Will Deacon
2012-11-22 18:44   ` Sasha Levin
2012-11-23 14:36     ` Will Deacon
2012-11-22 15:58 ` [PATCH v2 2/8] kvm tools: don't bother including linux/compiler.h Will Deacon
2012-11-22 15:58 ` [PATCH v2 3/8] kvm tools: balloon: add dummy set_size_vq implementation Will Deacon
2012-11-22 15:58 ` [PATCH v2 4/8] kvm tools: add generic device registration mechanism Will Deacon
2012-11-22 15:58 ` [PATCH v2 5/8] kvm tools: keep track of registered memory banks in struct kvm Will Deacon
2012-11-22 15:58 ` [PATCH v2 6/8] kvm tools: teach guest_flat_to_host about memory banks starting above 0 Will Deacon
2012-11-22 15:58 ` [PATCH v2 7/8] kvm tools: provide a mechanism for translating host to guest addresses Will Deacon
2012-11-22 15:58 ` [PATCH v2 8/8] kvm tools: add support for ARMv7 processors Will Deacon
2012-11-22 16:13   ` Peter Maydell
2012-11-22 16:22     ` Will Deacon
2012-11-23 11:22 ` [PATCH v2 0/8] " Pekka Enberg
2012-11-23 14:38   ` Will Deacon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox