* [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, ®) < 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, ®) < 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, ®) < 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, ®) < 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, ®) < 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, ®) < 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, ®) < 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, ®) < 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, ®) < 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, ®) < 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, ®) < 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, ®) < 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