All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC v2 0/6] QEMU: Support KVM on ARM
@ 2012-10-10 15:07 ` Peter Maydell
  0 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-10 15:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvmarm, kvm, patches

This is a v2 RFC of the QEMU patches to support KVM for
ARM on Cortex-A15 hardware. It's intended for use with
the kernel tree at
 git://github.com/virtualopensystems/linux-kvm-arm.git kvm-arm-v12

(ie the 'v2' kernel patches which Christoffer sent out at
the start of the month).

Patch review appreciated -- I think this is more or less
ready to go in once the kernel patches are accepted (assuming
no kernel ABI changes, of course). (There are still a few
things it would be nice to do better, like driving cp15
access from the cp_regs hashtable rather than hardcoding
a small list. If anybody feels any of the todo-type stuff
is a blocker to these patches being committed that would
be good to know too :-))

Git tree if preferred:
 git://git.linaro.org/people/pmaydell/qemu-arm.git kvm-arm-v12

Peter Maydell (6):
  linux-headers: Add ARM KVM headers (not for upstream)
  ARM: KVM: Add support for KVM on ARM architecture
  hw/arm_gic: Add presave/postload hooks
  hw/kvm/arm_gic: Implement support for KVM in-kernel ARM GIC
  ARM KVM: save and load VFP registers from kernel
  configure: Enable KVM on ARM

 configure                            |    2 +-
 hw/a15mpcore.c                       |    8 +-
 hw/arm/Makefile.objs                 |    1 +
 hw/arm_gic_common.c                  |   10 +
 hw/arm_gic_internal.h                |    2 +
 hw/arm_pic.c                         |   28 +++
 hw/kvm/arm_gic.c                     |  162 ++++++++++++++
 linux-headers/asm-arm/kvm.h          |  131 +++++++++++
 linux-headers/asm-arm/kvm_para.h     |    1 +
 linux-headers/asm-generic/kvm_para.h |    5 +
 linux-headers/asm-x86/kvm.h          |    1 +
 linux-headers/linux/kvm.h            |   16 +-
 target-arm/Makefile.objs             |    1 +
 target-arm/cpu.h                     |    1 +
 target-arm/helper.c                  |    2 +-
 target-arm/kvm.c                     |  400 ++++++++++++++++++++++++++++++++++
 16 files changed, 765 insertions(+), 6 deletions(-)
 create mode 100644 hw/kvm/arm_gic.c
 create mode 100644 linux-headers/asm-arm/kvm.h
 create mode 100644 linux-headers/asm-arm/kvm_para.h
 create mode 100644 linux-headers/asm-generic/kvm_para.h
 create mode 100644 target-arm/kvm.c

-- 
1.7.9.5

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

* [Qemu-devel] [RFC v2 0/6] QEMU: Support KVM on ARM
@ 2012-10-10 15:07 ` Peter Maydell
  0 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-10 15:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvmarm, kvm, patches

This is a v2 RFC of the QEMU patches to support KVM for
ARM on Cortex-A15 hardware. It's intended for use with
the kernel tree at
 git://github.com/virtualopensystems/linux-kvm-arm.git kvm-arm-v12

(ie the 'v2' kernel patches which Christoffer sent out at
the start of the month).

Patch review appreciated -- I think this is more or less
ready to go in once the kernel patches are accepted (assuming
no kernel ABI changes, of course). (There are still a few
things it would be nice to do better, like driving cp15
access from the cp_regs hashtable rather than hardcoding
a small list. If anybody feels any of the todo-type stuff
is a blocker to these patches being committed that would
be good to know too :-))

Git tree if preferred:
 git://git.linaro.org/people/pmaydell/qemu-arm.git kvm-arm-v12

Peter Maydell (6):
  linux-headers: Add ARM KVM headers (not for upstream)
  ARM: KVM: Add support for KVM on ARM architecture
  hw/arm_gic: Add presave/postload hooks
  hw/kvm/arm_gic: Implement support for KVM in-kernel ARM GIC
  ARM KVM: save and load VFP registers from kernel
  configure: Enable KVM on ARM

 configure                            |    2 +-
 hw/a15mpcore.c                       |    8 +-
 hw/arm/Makefile.objs                 |    1 +
 hw/arm_gic_common.c                  |   10 +
 hw/arm_gic_internal.h                |    2 +
 hw/arm_pic.c                         |   28 +++
 hw/kvm/arm_gic.c                     |  162 ++++++++++++++
 linux-headers/asm-arm/kvm.h          |  131 +++++++++++
 linux-headers/asm-arm/kvm_para.h     |    1 +
 linux-headers/asm-generic/kvm_para.h |    5 +
 linux-headers/asm-x86/kvm.h          |    1 +
 linux-headers/linux/kvm.h            |   16 +-
 target-arm/Makefile.objs             |    1 +
 target-arm/cpu.h                     |    1 +
 target-arm/helper.c                  |    2 +-
 target-arm/kvm.c                     |  400 ++++++++++++++++++++++++++++++++++
 16 files changed, 765 insertions(+), 6 deletions(-)
 create mode 100644 hw/kvm/arm_gic.c
 create mode 100644 linux-headers/asm-arm/kvm.h
 create mode 100644 linux-headers/asm-arm/kvm_para.h
 create mode 100644 linux-headers/asm-generic/kvm_para.h
 create mode 100644 target-arm/kvm.c

-- 
1.7.9.5

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

* [RFC v2 1/6] linux-headers: Add ARM KVM headers (not for upstream)
  2012-10-10 15:07 ` [Qemu-devel] " Peter Maydell
@ 2012-10-10 15:07   ` Peter Maydell
  -1 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-10 15:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvmarm, kvm, patches

This commit adds the ARM KVM headers. This is not to go to QEMU
upstream -- the correct path there is that the KVM code will be
committed to a mainline upstream kernel, and then upstream QEMU
can do a bulk header update from the upstream kernel, which will
allow us to drop this temporary commit.

This is the result of running update-headers on Christoffer's
kvm-arm-v12 branch (commit d151d7a). It includes the new
interrupt delivery ABI, the switch to ONE_REG for core
and coprocessor registers, and the VFP register definitions.

It currently includes some minor x86 header changes which
hopefully will have made it into QEMU upstream by the time
we submit this for merging.
---
 linux-headers/asm-arm/kvm.h          |  131 ++++++++++++++++++++++++++++++++++
 linux-headers/asm-arm/kvm_para.h     |    1 +
 linux-headers/asm-generic/kvm_para.h |    5 ++
 linux-headers/asm-x86/kvm.h          |    1 +
 linux-headers/linux/kvm.h            |   16 ++++-
 5 files changed, 151 insertions(+), 3 deletions(-)
 create mode 100644 linux-headers/asm-arm/kvm.h
 create mode 100644 linux-headers/asm-arm/kvm_para.h
 create mode 100644 linux-headers/asm-generic/kvm_para.h

diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h
new file mode 100644
index 0000000..b6eaf0c
--- /dev/null
+++ b/linux-headers/asm-arm/kvm.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __ARM_KVM_H__
+#define __ARM_KVM_H__
+
+#include <asm/types.h>
+
+#define __KVM_HAVE_GUEST_DEBUG
+#define __KVM_HAVE_IRQ_LINE
+
+#define KVM_REG_SIZE(id)						\
+	(1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
+
+struct kvm_regs {
+	__u32 usr_regs[15];	/* R0_usr - R14_usr */
+	__u32 svc_regs[3];	/* SP_svc, LR_svc, SPSR_svc */
+	__u32 abt_regs[3];	/* SP_abt, LR_abt, SPSR_abt */
+	__u32 und_regs[3];	/* SP_und, LR_und, SPSR_und */
+	__u32 irq_regs[3];	/* SP_irq, LR_irq, SPSR_irq */
+	__u32 fiq_regs[8];	/* R8_fiq - R14_fiq, SPSR_fiq */
+	__u32 pc;		/* The program counter (r15) */
+	__u32 cpsr;		/* The guest CPSR */
+};
+
+/* Supported Processor Types */
+#define KVM_ARM_TARGET_CORTEX_A15	0
+#define KVM_ARM_NUM_TARGETS		1
+
+struct kvm_vcpu_init {
+	__u32 target;
+	__u32 features[7];
+};
+
+struct kvm_sregs {
+};
+
+struct kvm_fpu {
+};
+
+struct kvm_guest_debug_arch {
+};
+
+struct kvm_debug_exit_arch {
+};
+
+struct kvm_sync_regs {
+};
+
+struct kvm_arch_memory_slot {
+};
+
+/* For KVM_VCPU_GET_REG_LIST. */
+struct kvm_reg_list {
+	__u64 n; /* number of regs */
+	__u64 reg[0];
+};
+
+/* If you need to interpret the index values, here is the key: */
+#define KVM_REG_ARM_COPROC_MASK		0x000000000FFF0000
+#define KVM_REG_ARM_COPROC_SHIFT	16
+#define KVM_REG_ARM_32_OPC2_MASK	0x0000000000000007
+#define KVM_REG_ARM_32_OPC2_SHIFT	0
+#define KVM_REG_ARM_OPC1_MASK		0x0000000000000078
+#define KVM_REG_ARM_OPC1_SHIFT		3
+#define KVM_REG_ARM_CRM_MASK		0x0000000000000780
+#define KVM_REG_ARM_CRM_SHIFT		7
+#define KVM_REG_ARM_32_CRN_MASK		0x0000000000007800
+#define KVM_REG_ARM_32_CRN_SHIFT	11
+
+/* Normal registers are mapped as coprocessor 16. */
+#define KVM_REG_ARM_CORE		(0x0010 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_CORE_REG(name)	(offsetof(struct kvm_regs, name) / 4)
+
+/* Some registers need more space to represent values. */
+#define KVM_REG_ARM_DEMUX		(0x0011 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_DEMUX_ID_MASK	0x000000000000FF00
+#define KVM_REG_ARM_DEMUX_ID_SHIFT	8
+#define KVM_REG_ARM_DEMUX_ID_CCSIDR	(0x00 << KVM_REG_ARM_DEMUX_ID_SHIFT)
+#define KVM_REG_ARM_DEMUX_VAL_MASK	0x00000000000000FF
+#define KVM_REG_ARM_DEMUX_VAL_SHIFT	0
+
+/* VFP registers: we could overload CP10 like ARM does, but that's ugly. */
+#define KVM_REG_ARM_VFP			(0x0012 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_VFP_MASK		0x000000000000FFFF
+#define KVM_REG_ARM_VFP_BASE_REG	0x0
+#define KVM_REG_ARM_VFP_FPSID		0x1000
+#define KVM_REG_ARM_VFP_FPSCR		0x1001
+#define KVM_REG_ARM_VFP_MVFR1		0x1006
+#define KVM_REG_ARM_VFP_MVFR0		0x1007
+#define KVM_REG_ARM_VFP_FPEXC		0x1008
+#define KVM_REG_ARM_VFP_FPINST		0x1009
+#define KVM_REG_ARM_VFP_FPINST2		0x100A
+
+
+/* KVM_IRQ_LINE irq field index values */
+#define KVM_ARM_IRQ_TYPE_SHIFT		24
+#define KVM_ARM_IRQ_TYPE_MASK		0xff
+#define KVM_ARM_IRQ_VCPU_SHIFT		16
+#define KVM_ARM_IRQ_VCPU_MASK		0xff
+#define KVM_ARM_IRQ_NUM_SHIFT		0
+#define KVM_ARM_IRQ_NUM_MASK		0xffff
+
+/* irq_type field */
+#define KVM_ARM_IRQ_TYPE_CPU		0
+#define KVM_ARM_IRQ_TYPE_SPI		1
+#define KVM_ARM_IRQ_TYPE_PPI		2
+
+/* out-of-kernel GIC cpu interrupt injection irq_number field */
+#define KVM_ARM_IRQ_CPU_IRQ		0
+#define KVM_ARM_IRQ_CPU_FIQ		1
+
+/* Highest supported SPI, from VGIC_NR_IRQS */
+#define KVM_ARM_IRQ_GIC_MAX		127
+
+#endif /* __ARM_KVM_H__ */
diff --git a/linux-headers/asm-arm/kvm_para.h b/linux-headers/asm-arm/kvm_para.h
new file mode 100644
index 0000000..14fab8f
--- /dev/null
+++ b/linux-headers/asm-arm/kvm_para.h
@@ -0,0 +1 @@
+#include <asm-generic/kvm_para.h>
diff --git a/linux-headers/asm-generic/kvm_para.h b/linux-headers/asm-generic/kvm_para.h
new file mode 100644
index 0000000..63df88b
--- /dev/null
+++ b/linux-headers/asm-generic/kvm_para.h
@@ -0,0 +1,5 @@
+#ifndef _ASM_GENERIC_KVM_PARA_H
+#define _ASM_GENERIC_KVM_PARA_H
+
+
+#endif
diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h
index 246617e..521bf25 100644
--- a/linux-headers/asm-x86/kvm.h
+++ b/linux-headers/asm-x86/kvm.h
@@ -25,6 +25,7 @@
 #define __KVM_HAVE_DEBUGREGS
 #define __KVM_HAVE_XSAVE
 #define __KVM_HAVE_XCRS
+#define __KVM_HAVE_READONLY_MEM
 
 /* Architectural interrupt line count. */
 #define KVM_NR_INTERRUPTS 256
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 4b9e575..7a02d73 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -101,9 +101,13 @@ struct kvm_userspace_memory_region {
 	__u64 userspace_addr; /* start of the userspace allocated memory */
 };
 
-/* for kvm_memory_region::flags */
-#define KVM_MEM_LOG_DIRTY_PAGES  1UL
-#define KVM_MEMSLOT_INVALID      (1UL << 1)
+/*
+ * The bit 0 ~ bit 15 of kvm_memory_region::flags are visible for userspace,
+ * other bits are reserved for kvm internal use which are defined in
+ * include/linux/kvm_host.h.
+ */
+#define KVM_MEM_LOG_DIRTY_PAGES	(1UL << 0)
+#define KVM_MEM_READONLY	(1UL << 1)
 
 /* for KVM_IRQ_LINE */
 struct kvm_irq_level {
@@ -111,6 +115,7 @@ struct kvm_irq_level {
 	 * ACPI gsi notion of irq.
 	 * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47..
 	 * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
+	 * For ARM: IRQ: irq = (2*vcpu_index). FIQ: irq = (2*vcpu_indx + 1).
 	 */
 	union {
 		__u32 irq;
@@ -618,6 +623,9 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_PPC_GET_SMMU_INFO 78
 #define KVM_CAP_S390_COW 79
 #define KVM_CAP_PPC_ALLOC_HTAB 80
+#ifdef __KVM_HAVE_READONLY_MEM
+#define KVM_CAP_READONLY_MEM 81
+#endif
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -904,6 +912,8 @@ struct kvm_s390_ucas_mapping {
 #define KVM_SET_ONE_REG		  _IOW(KVMIO,  0xac, struct kvm_one_reg)
 /* VM is being stopped by host */
 #define KVM_KVMCLOCK_CTRL	  _IO(KVMIO,   0xad)
+#define KVM_ARM_VCPU_INIT	  _IOW(KVMIO,  0xae, struct kvm_vcpu_init)
+#define KVM_GET_REG_LIST	  _IOWR(KVMIO, 0xb0, struct kvm_reg_list)
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
 #define KVM_DEV_ASSIGN_PCI_2_3		(1 << 1)
-- 
1.7.9.5

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

* [Qemu-devel] [RFC v2 1/6] linux-headers: Add ARM KVM headers (not for upstream)
@ 2012-10-10 15:07   ` Peter Maydell
  0 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-10 15:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvmarm, kvm, patches

This commit adds the ARM KVM headers. This is not to go to QEMU
upstream -- the correct path there is that the KVM code will be
committed to a mainline upstream kernel, and then upstream QEMU
can do a bulk header update from the upstream kernel, which will
allow us to drop this temporary commit.

This is the result of running update-headers on Christoffer's
kvm-arm-v12 branch (commit d151d7a). It includes the new
interrupt delivery ABI, the switch to ONE_REG for core
and coprocessor registers, and the VFP register definitions.

It currently includes some minor x86 header changes which
hopefully will have made it into QEMU upstream by the time
we submit this for merging.
---
 linux-headers/asm-arm/kvm.h          |  131 ++++++++++++++++++++++++++++++++++
 linux-headers/asm-arm/kvm_para.h     |    1 +
 linux-headers/asm-generic/kvm_para.h |    5 ++
 linux-headers/asm-x86/kvm.h          |    1 +
 linux-headers/linux/kvm.h            |   16 ++++-
 5 files changed, 151 insertions(+), 3 deletions(-)
 create mode 100644 linux-headers/asm-arm/kvm.h
 create mode 100644 linux-headers/asm-arm/kvm_para.h
 create mode 100644 linux-headers/asm-generic/kvm_para.h

diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h
new file mode 100644
index 0000000..b6eaf0c
--- /dev/null
+++ b/linux-headers/asm-arm/kvm.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __ARM_KVM_H__
+#define __ARM_KVM_H__
+
+#include <asm/types.h>
+
+#define __KVM_HAVE_GUEST_DEBUG
+#define __KVM_HAVE_IRQ_LINE
+
+#define KVM_REG_SIZE(id)						\
+	(1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
+
+struct kvm_regs {
+	__u32 usr_regs[15];	/* R0_usr - R14_usr */
+	__u32 svc_regs[3];	/* SP_svc, LR_svc, SPSR_svc */
+	__u32 abt_regs[3];	/* SP_abt, LR_abt, SPSR_abt */
+	__u32 und_regs[3];	/* SP_und, LR_und, SPSR_und */
+	__u32 irq_regs[3];	/* SP_irq, LR_irq, SPSR_irq */
+	__u32 fiq_regs[8];	/* R8_fiq - R14_fiq, SPSR_fiq */
+	__u32 pc;		/* The program counter (r15) */
+	__u32 cpsr;		/* The guest CPSR */
+};
+
+/* Supported Processor Types */
+#define KVM_ARM_TARGET_CORTEX_A15	0
+#define KVM_ARM_NUM_TARGETS		1
+
+struct kvm_vcpu_init {
+	__u32 target;
+	__u32 features[7];
+};
+
+struct kvm_sregs {
+};
+
+struct kvm_fpu {
+};
+
+struct kvm_guest_debug_arch {
+};
+
+struct kvm_debug_exit_arch {
+};
+
+struct kvm_sync_regs {
+};
+
+struct kvm_arch_memory_slot {
+};
+
+/* For KVM_VCPU_GET_REG_LIST. */
+struct kvm_reg_list {
+	__u64 n; /* number of regs */
+	__u64 reg[0];
+};
+
+/* If you need to interpret the index values, here is the key: */
+#define KVM_REG_ARM_COPROC_MASK		0x000000000FFF0000
+#define KVM_REG_ARM_COPROC_SHIFT	16
+#define KVM_REG_ARM_32_OPC2_MASK	0x0000000000000007
+#define KVM_REG_ARM_32_OPC2_SHIFT	0
+#define KVM_REG_ARM_OPC1_MASK		0x0000000000000078
+#define KVM_REG_ARM_OPC1_SHIFT		3
+#define KVM_REG_ARM_CRM_MASK		0x0000000000000780
+#define KVM_REG_ARM_CRM_SHIFT		7
+#define KVM_REG_ARM_32_CRN_MASK		0x0000000000007800
+#define KVM_REG_ARM_32_CRN_SHIFT	11
+
+/* Normal registers are mapped as coprocessor 16. */
+#define KVM_REG_ARM_CORE		(0x0010 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_CORE_REG(name)	(offsetof(struct kvm_regs, name) / 4)
+
+/* Some registers need more space to represent values. */
+#define KVM_REG_ARM_DEMUX		(0x0011 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_DEMUX_ID_MASK	0x000000000000FF00
+#define KVM_REG_ARM_DEMUX_ID_SHIFT	8
+#define KVM_REG_ARM_DEMUX_ID_CCSIDR	(0x00 << KVM_REG_ARM_DEMUX_ID_SHIFT)
+#define KVM_REG_ARM_DEMUX_VAL_MASK	0x00000000000000FF
+#define KVM_REG_ARM_DEMUX_VAL_SHIFT	0
+
+/* VFP registers: we could overload CP10 like ARM does, but that's ugly. */
+#define KVM_REG_ARM_VFP			(0x0012 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_VFP_MASK		0x000000000000FFFF
+#define KVM_REG_ARM_VFP_BASE_REG	0x0
+#define KVM_REG_ARM_VFP_FPSID		0x1000
+#define KVM_REG_ARM_VFP_FPSCR		0x1001
+#define KVM_REG_ARM_VFP_MVFR1		0x1006
+#define KVM_REG_ARM_VFP_MVFR0		0x1007
+#define KVM_REG_ARM_VFP_FPEXC		0x1008
+#define KVM_REG_ARM_VFP_FPINST		0x1009
+#define KVM_REG_ARM_VFP_FPINST2		0x100A
+
+
+/* KVM_IRQ_LINE irq field index values */
+#define KVM_ARM_IRQ_TYPE_SHIFT		24
+#define KVM_ARM_IRQ_TYPE_MASK		0xff
+#define KVM_ARM_IRQ_VCPU_SHIFT		16
+#define KVM_ARM_IRQ_VCPU_MASK		0xff
+#define KVM_ARM_IRQ_NUM_SHIFT		0
+#define KVM_ARM_IRQ_NUM_MASK		0xffff
+
+/* irq_type field */
+#define KVM_ARM_IRQ_TYPE_CPU		0
+#define KVM_ARM_IRQ_TYPE_SPI		1
+#define KVM_ARM_IRQ_TYPE_PPI		2
+
+/* out-of-kernel GIC cpu interrupt injection irq_number field */
+#define KVM_ARM_IRQ_CPU_IRQ		0
+#define KVM_ARM_IRQ_CPU_FIQ		1
+
+/* Highest supported SPI, from VGIC_NR_IRQS */
+#define KVM_ARM_IRQ_GIC_MAX		127
+
+#endif /* __ARM_KVM_H__ */
diff --git a/linux-headers/asm-arm/kvm_para.h b/linux-headers/asm-arm/kvm_para.h
new file mode 100644
index 0000000..14fab8f
--- /dev/null
+++ b/linux-headers/asm-arm/kvm_para.h
@@ -0,0 +1 @@
+#include <asm-generic/kvm_para.h>
diff --git a/linux-headers/asm-generic/kvm_para.h b/linux-headers/asm-generic/kvm_para.h
new file mode 100644
index 0000000..63df88b
--- /dev/null
+++ b/linux-headers/asm-generic/kvm_para.h
@@ -0,0 +1,5 @@
+#ifndef _ASM_GENERIC_KVM_PARA_H
+#define _ASM_GENERIC_KVM_PARA_H
+
+
+#endif
diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h
index 246617e..521bf25 100644
--- a/linux-headers/asm-x86/kvm.h
+++ b/linux-headers/asm-x86/kvm.h
@@ -25,6 +25,7 @@
 #define __KVM_HAVE_DEBUGREGS
 #define __KVM_HAVE_XSAVE
 #define __KVM_HAVE_XCRS
+#define __KVM_HAVE_READONLY_MEM
 
 /* Architectural interrupt line count. */
 #define KVM_NR_INTERRUPTS 256
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 4b9e575..7a02d73 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -101,9 +101,13 @@ struct kvm_userspace_memory_region {
 	__u64 userspace_addr; /* start of the userspace allocated memory */
 };
 
-/* for kvm_memory_region::flags */
-#define KVM_MEM_LOG_DIRTY_PAGES  1UL
-#define KVM_MEMSLOT_INVALID      (1UL << 1)
+/*
+ * The bit 0 ~ bit 15 of kvm_memory_region::flags are visible for userspace,
+ * other bits are reserved for kvm internal use which are defined in
+ * include/linux/kvm_host.h.
+ */
+#define KVM_MEM_LOG_DIRTY_PAGES	(1UL << 0)
+#define KVM_MEM_READONLY	(1UL << 1)
 
 /* for KVM_IRQ_LINE */
 struct kvm_irq_level {
@@ -111,6 +115,7 @@ struct kvm_irq_level {
 	 * ACPI gsi notion of irq.
 	 * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47..
 	 * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
+	 * For ARM: IRQ: irq = (2*vcpu_index). FIQ: irq = (2*vcpu_indx + 1).
 	 */
 	union {
 		__u32 irq;
@@ -618,6 +623,9 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_PPC_GET_SMMU_INFO 78
 #define KVM_CAP_S390_COW 79
 #define KVM_CAP_PPC_ALLOC_HTAB 80
+#ifdef __KVM_HAVE_READONLY_MEM
+#define KVM_CAP_READONLY_MEM 81
+#endif
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -904,6 +912,8 @@ struct kvm_s390_ucas_mapping {
 #define KVM_SET_ONE_REG		  _IOW(KVMIO,  0xac, struct kvm_one_reg)
 /* VM is being stopped by host */
 #define KVM_KVMCLOCK_CTRL	  _IO(KVMIO,   0xad)
+#define KVM_ARM_VCPU_INIT	  _IOW(KVMIO,  0xae, struct kvm_vcpu_init)
+#define KVM_GET_REG_LIST	  _IOWR(KVMIO, 0xb0, struct kvm_reg_list)
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
 #define KVM_DEV_ASSIGN_PCI_2_3		(1 << 1)
-- 
1.7.9.5

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

* [RFC v2 2/6] ARM: KVM: Add support for KVM on ARM architecture
  2012-10-10 15:07 ` [Qemu-devel] " Peter Maydell
@ 2012-10-10 15:07   ` Peter Maydell
  -1 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-10 15:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvm, kvmarm, patches

From: Christoffer Dall <cdall@cs.columbia.edu>

Add basic support for KVM on ARM architecture.

Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
[PMM: Minor tweaks and code cleanup, switch to ONE_REG]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm_pic.c             |   28 ++++
 target-arm/Makefile.objs |    1 +
 target-arm/cpu.h         |    1 +
 target-arm/helper.c      |    2 +-
 target-arm/kvm.c         |  328 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 359 insertions(+), 1 deletion(-)
 create mode 100644 target-arm/kvm.c

diff --git a/hw/arm_pic.c b/hw/arm_pic.c
index ffb4d41..72272dc 100644
--- a/hw/arm_pic.c
+++ b/hw/arm_pic.c
@@ -9,6 +9,7 @@
 
 #include "hw.h"
 #include "arm-misc.h"
+#include "kvm.h"
 
 /* Input 0 is IRQ and input 1 is FIQ.  */
 static void arm_pic_cpu_handler(void *opaque, int irq, int level)
@@ -34,7 +35,34 @@ static void arm_pic_cpu_handler(void *opaque, int irq, int level)
     }
 }
 
+#ifdef CONFIG_KVM
+static void kvm_arm_pic_cpu_handler(void *opaque, int irq, int level)
+{
+    ARMCPU *cpu = opaque;
+    CPUARMState *env = &cpu->env;
+    int kvm_irq = KVM_ARM_IRQ_TYPE_CPU << KVM_ARM_IRQ_TYPE_SHIFT;
+
+    switch (irq) {
+    case ARM_PIC_CPU_IRQ:
+        kvm_irq |= KVM_ARM_IRQ_CPU_IRQ;
+        break;
+    case ARM_PIC_CPU_FIQ:
+        kvm_irq |= KVM_ARM_IRQ_CPU_FIQ;
+        break;
+    default:
+        hw_error("kvm_arm_pic_cpu_handler: Bad interrupt line %d\n", irq);
+    }
+    kvm_irq |= env->cpu_index << KVM_ARM_IRQ_VCPU_SHIFT;
+    kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0);
+}
+#endif
+
 qemu_irq *arm_pic_init_cpu(ARMCPU *cpu)
 {
+#ifdef CONFIG_KVM
+    if (kvm_enabled()) {
+        return qemu_allocate_irqs(kvm_arm_pic_cpu_handler, cpu, 2);
+    }
+#endif
     return qemu_allocate_irqs(arm_pic_cpu_handler, cpu, 2);
 }
diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs
index b6f1a9e..d89b57c 100644
--- a/target-arm/Makefile.objs
+++ b/target-arm/Makefile.objs
@@ -1,4 +1,5 @@
 obj-y += arm-semi.o
 obj-$(CONFIG_SOFTMMU) += machine.o
+obj-$(CONFIG_KVM) += kvm.o
 obj-y += translate.o op_helper.o helper.o cpu.o
 obj-y += neon_helper.o iwmmxt_helper.o
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index ff4de10..8c7e574 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -236,6 +236,7 @@ ARMCPU *cpu_arm_init(const char *cpu_model);
 void arm_translate_init(void);
 int cpu_arm_exec(CPUARMState *s);
 void do_interrupt(CPUARMState *);
+int bank_number(CPUARMState *env, int mode);
 void switch_mode(CPUARMState *, int);
 uint32_t do_arm_semihosting(CPUARMState *env);
 
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 58340bd..f62f3da 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1619,7 +1619,7 @@ uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode)
 #else
 
 /* Map CPU modes onto saved register banks.  */
-static inline int bank_number(CPUARMState *env, int mode)
+int bank_number(CPUARMState *env, int mode)
 {
     switch (mode) {
     case ARM_CPU_MODE_USR:
diff --git a/target-arm/kvm.c b/target-arm/kvm.c
new file mode 100644
index 0000000..fee60e1
--- /dev/null
+++ b/target-arm/kvm.c
@@ -0,0 +1,328 @@
+/*
+ * ARM implementation of KVM hooks
+ *
+ * Copyright Christoffer Dall 2009-2010
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <linux/kvm.h>
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "kvm.h"
+#include "cpu.h"
+#include "device_tree.h"
+#include "hw/arm-misc.h"
+
+const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
+    KVM_CAP_LAST_INFO
+};
+
+int kvm_arch_init(KVMState *s)
+{
+    /* For ARM interrupt delivery is always asynchronous,
+     * whether we are using an in-kernel VGIC or not.
+     */
+    kvm_async_interrupts_allowed = true;
+    return 0;
+}
+
+int kvm_arch_init_vcpu(CPUARMState *env)
+{
+    struct kvm_vcpu_init init;
+
+    init.target = KVM_ARM_TARGET_CORTEX_A15;
+    memset(init.features, 0, sizeof(init.features));
+    return kvm_vcpu_ioctl(env, KVM_ARM_VCPU_INIT, &init);
+}
+
+struct reg {
+    uint64_t id;
+    int offset;
+};
+
+#define COREREG(KERNELNAME, QEMUFIELD)                       \
+    {                                                        \
+        KVM_REG_ARM | KVM_REG_SIZE_U32 |                     \
+        KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(KERNELNAME), \
+        offsetof(CPUARMState, QEMUFIELD)                     \
+    }
+
+#define CP15REG(CRN, CRM, OPC1, OPC2, QEMUFIELD) \
+    {                                            \
+        KVM_REG_ARM | KVM_REG_SIZE_U32 |         \
+        (15 << KVM_REG_ARM_COPROC_SHIFT) |       \
+        ((CRN) << KVM_REG_ARM_32_CRN_SHIFT) |    \
+        ((CRM) << KVM_REG_ARM_CRM_SHIFT) |       \
+        ((OPC1) << KVM_REG_ARM_OPC1_SHIFT) |     \
+        ((OPC2) << KVM_REG_ARM_32_OPC2_SHIFT),   \
+        offsetof(CPUARMState, QEMUFIELD)         \
+    }
+
+const struct reg regs[] = {
+    /* R0_usr .. R14_usr */
+    COREREG(usr_regs[0], regs[0]),
+    COREREG(usr_regs[1], regs[1]),
+    COREREG(usr_regs[2], regs[2]),
+    COREREG(usr_regs[3], regs[3]),
+    COREREG(usr_regs[4], regs[4]),
+    COREREG(usr_regs[5], regs[5]),
+    COREREG(usr_regs[6], regs[6]),
+    COREREG(usr_regs[7], regs[7]),
+    COREREG(usr_regs[8], usr_regs[0]),
+    COREREG(usr_regs[9], usr_regs[1]),
+    COREREG(usr_regs[10], usr_regs[2]),
+    COREREG(usr_regs[11], usr_regs[3]),
+    COREREG(usr_regs[12], usr_regs[4]),
+    COREREG(usr_regs[13], banked_r13[0]),
+    COREREG(usr_regs[14], banked_r14[0]),
+    /* R13, R14, SPSR for SVC, ABT, UND, IRQ banks */
+    COREREG(svc_regs[0], banked_r13[1]),
+    COREREG(svc_regs[1], banked_r14[1]),
+    COREREG(svc_regs[2], banked_spsr[1]),
+    COREREG(abt_regs[0], banked_r13[2]),
+    COREREG(abt_regs[1], banked_r14[2]),
+    COREREG(abt_regs[2], banked_spsr[2]),
+    COREREG(und_regs[0], banked_r13[3]),
+    COREREG(und_regs[1], banked_r14[3]),
+    COREREG(und_regs[2], banked_spsr[3]),
+    COREREG(irq_regs[0], banked_r13[4]),
+    COREREG(irq_regs[1], banked_r14[4]),
+    COREREG(irq_regs[2], banked_spsr[4]),
+    /* R8_fiq .. R14_fiq and SPSR_fiq */
+    COREREG(fiq_regs[0], fiq_regs[0]),
+    COREREG(fiq_regs[1], fiq_regs[1]),
+    COREREG(fiq_regs[2], fiq_regs[2]),
+    COREREG(fiq_regs[3], fiq_regs[3]),
+    COREREG(fiq_regs[4], fiq_regs[4]),
+    COREREG(fiq_regs[0], banked_r13[5]),
+    COREREG(fiq_regs[1], banked_r14[5]),
+    COREREG(fiq_regs[2], banked_spsr[5]),
+    /* R15 */
+    COREREG(pc, regs[15]),
+    /* A non-comprehensive set of cp15 registers.
+     * TODO: drive this from the cp_regs hashtable instead.
+     */
+    CP15REG(1, 0, 0, 0, cp15.c1_sys), /* SCTLR */
+    CP15REG(2, 0, 0, 2, cp15.c2_control), /* TTBCR */
+    CP15REG(3, 0, 0, 0, cp15.c3), /* DACR */
+};
+
+int kvm_arch_put_registers(CPUARMState *env, int level)
+{
+    struct kvm_one_reg r;
+    int mode, bn;
+    int ret, i;
+    uint32_t cpsr;
+    uint64_t ttbr;
+
+    /* Make sure the banked regs are properly set */
+    mode = env->uncached_cpsr & CPSR_M;
+    bn = bank_number(env, mode);
+    if (mode == ARM_CPU_MODE_FIQ) {
+        memcpy(env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t));
+    } else {
+        memcpy(env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t));
+    }
+    env->banked_r13[bn] = env->regs[13];
+    env->banked_r14[bn] = env->regs[14];
+    env->banked_spsr[bn] = env->spsr;
+
+    /* Now we can safely copy stuff down to the kernel */
+    for (i = 0; i < ARRAY_SIZE(regs); i++) {
+        r.id = regs[i].id;
+        r.addr = (uintptr_t)(env) + regs[i].offset;
+        ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
+        if (ret) {
+            return ret;
+        }
+    }
+
+    /* Special cases which aren't a single CPUARMState field */
+    cpsr = cpsr_read(env);
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 |
+        KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(cpsr);
+    r.addr = (uintptr_t)(&cpsr);
+    ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
+    if (ret) {
+        return ret;
+    }
+
+    /* TTBR0: cp15 crm=2 opc1=0 */
+    ttbr = ((uint64_t)env->cp15.c2_base0_hi << 32) | env->cp15.c2_base0;
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
+        (2 << KVM_REG_ARM_CRM_SHIFT) | (0 << KVM_REG_ARM_OPC1_SHIFT);
+    r.addr = (uintptr_t)(&ttbr);
+    ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
+    if (ret) {
+        return ret;
+    }
+
+    /* TTBR1: cp15 crm=2 opc1=1 */
+    ttbr = ((uint64_t)env->cp15.c2_base1_hi << 32) | env->cp15.c2_base1;
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
+        (2 << KVM_REG_ARM_CRM_SHIFT) | (1 << KVM_REG_ARM_OPC1_SHIFT);
+    r.addr = (uintptr_t)(&ttbr);
+    ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
+
+    return ret;
+}
+
+int kvm_arch_get_registers(CPUARMState *env)
+{
+    struct kvm_one_reg r;
+    int mode, bn;
+    int ret, i;
+    uint32_t cpsr;
+    uint64_t ttbr;
+
+    for (i = 0; i < ARRAY_SIZE(regs); i++) {
+        r.id = regs[i].id;
+        r.addr = (uintptr_t)(env) + regs[i].offset;
+        ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
+        if (ret) {
+            return ret;
+        }
+    }
+
+    /* Special cases which aren't a single CPUARMState field */
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 |
+        KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(cpsr);
+    r.addr = (uintptr_t)(&cpsr);
+    ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
+    if (ret) {
+        return ret;
+    }
+    cpsr_write(env, cpsr, 0xffffffff);
+
+    /* TTBR0: cp15 crm=2 opc1=0 */
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
+        (2 << KVM_REG_ARM_CRM_SHIFT) | (0 << KVM_REG_ARM_OPC1_SHIFT);
+    r.addr = (uintptr_t)(&ttbr);
+    ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
+    if (ret) {
+        return ret;
+    }
+    env->cp15.c2_base0_hi = ttbr >> 32;
+    env->cp15.c2_base0 = ttbr;
+
+    /* TTBR1: cp15 crm=2 opc1=1 */
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
+        (2 << KVM_REG_ARM_CRM_SHIFT) | (1 << KVM_REG_ARM_OPC1_SHIFT);
+    r.addr = (uintptr_t)(&ttbr);
+    ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
+    if (ret) {
+        return ret;
+    }
+    env->cp15.c2_base1_hi = ttbr >> 32;
+    env->cp15.c2_base1 = ttbr;
+
+    /* Make sure the current mode regs are properly set */
+    mode = env->uncached_cpsr & CPSR_M;
+    bn = bank_number(env, mode);
+    if (mode == ARM_CPU_MODE_FIQ) {
+        memcpy(env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t));
+    } else {
+        memcpy(env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t));
+    }
+    env->regs[13] = env->banked_r13[bn];
+    env->regs[14] = env->banked_r14[bn];
+    env->spsr = env->banked_spsr[bn];
+
+    /* The main GET_ONE_REG loop above set c2_control, but we need to
+     * update some extra cached precomputed values too.
+     * When this is driven from the cp_regs hashtable then this ugliness
+     * can disappear because we'll use the access function which sets
+     * these values automatically.
+     */
+    env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> env->cp15.c2_control);
+    env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> env->cp15.c2_control);
+
+    return 0;
+}
+
+void kvm_arch_pre_run(CPUARMState *env, struct kvm_run *run)
+{
+}
+
+void kvm_arch_post_run(CPUARMState *env, struct kvm_run *run)
+{
+}
+
+int kvm_arch_handle_exit(CPUARMState *env, struct kvm_run *run)
+{
+    int ret = 0;
+
+    return ret;
+}
+
+void kvm_arch_reset_vcpu(CPUARMState *env)
+{
+}
+
+bool kvm_arch_stop_on_emulation_error(CPUARMState *env)
+{
+    return true;
+}
+
+int kvm_arch_process_async_events(CPUARMState *env)
+{
+    return 0;
+}
+
+int kvm_arch_on_sigbus_vcpu(CPUARMState *env, int code, void *addr)
+{
+    return 1;
+}
+
+int kvm_arch_on_sigbus(int code, void *addr)
+{
+    return 1;
+}
+
+void kvm_arch_update_guest_debug(CPUARMState *env, struct kvm_guest_debug *dbg)
+{
+    fprintf(stderr, "%s: not implemented\n", __func__);
+}
+
+int kvm_arch_insert_sw_breakpoint(CPUARMState *env,
+                                  struct kvm_sw_breakpoint *bp)
+{
+    fprintf(stderr, "%s: not implemented\n", __func__);
+    return -EINVAL;
+}
+
+int kvm_arch_insert_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type)
+{
+    fprintf(stderr, "%s: not implemented\n", __func__);
+    return -EINVAL;
+}
+
+int kvm_arch_remove_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type)
+{
+    fprintf(stderr, "%s: not implemented\n", __func__);
+    return -EINVAL;
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUARMState *env,
+                                  struct kvm_sw_breakpoint *bp)
+{
+    fprintf(stderr, "%s: not implemented\n", __func__);
+    return -EINVAL;
+}
+
+void kvm_arch_remove_all_hw_breakpoints(void)
+{
+    fprintf(stderr, "%s: not implemented\n", __func__);
+}
-- 
1.7.9.5


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

* [Qemu-devel] [RFC v2 2/6] ARM: KVM: Add support for KVM on ARM architecture
@ 2012-10-10 15:07   ` Peter Maydell
  0 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-10 15:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvmarm, kvm, patches

From: Christoffer Dall <cdall@cs.columbia.edu>

Add basic support for KVM on ARM architecture.

Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
[PMM: Minor tweaks and code cleanup, switch to ONE_REG]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm_pic.c             |   28 ++++
 target-arm/Makefile.objs |    1 +
 target-arm/cpu.h         |    1 +
 target-arm/helper.c      |    2 +-
 target-arm/kvm.c         |  328 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 359 insertions(+), 1 deletion(-)
 create mode 100644 target-arm/kvm.c

diff --git a/hw/arm_pic.c b/hw/arm_pic.c
index ffb4d41..72272dc 100644
--- a/hw/arm_pic.c
+++ b/hw/arm_pic.c
@@ -9,6 +9,7 @@
 
 #include "hw.h"
 #include "arm-misc.h"
+#include "kvm.h"
 
 /* Input 0 is IRQ and input 1 is FIQ.  */
 static void arm_pic_cpu_handler(void *opaque, int irq, int level)
@@ -34,7 +35,34 @@ static void arm_pic_cpu_handler(void *opaque, int irq, int level)
     }
 }
 
+#ifdef CONFIG_KVM
+static void kvm_arm_pic_cpu_handler(void *opaque, int irq, int level)
+{
+    ARMCPU *cpu = opaque;
+    CPUARMState *env = &cpu->env;
+    int kvm_irq = KVM_ARM_IRQ_TYPE_CPU << KVM_ARM_IRQ_TYPE_SHIFT;
+
+    switch (irq) {
+    case ARM_PIC_CPU_IRQ:
+        kvm_irq |= KVM_ARM_IRQ_CPU_IRQ;
+        break;
+    case ARM_PIC_CPU_FIQ:
+        kvm_irq |= KVM_ARM_IRQ_CPU_FIQ;
+        break;
+    default:
+        hw_error("kvm_arm_pic_cpu_handler: Bad interrupt line %d\n", irq);
+    }
+    kvm_irq |= env->cpu_index << KVM_ARM_IRQ_VCPU_SHIFT;
+    kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0);
+}
+#endif
+
 qemu_irq *arm_pic_init_cpu(ARMCPU *cpu)
 {
+#ifdef CONFIG_KVM
+    if (kvm_enabled()) {
+        return qemu_allocate_irqs(kvm_arm_pic_cpu_handler, cpu, 2);
+    }
+#endif
     return qemu_allocate_irqs(arm_pic_cpu_handler, cpu, 2);
 }
diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs
index b6f1a9e..d89b57c 100644
--- a/target-arm/Makefile.objs
+++ b/target-arm/Makefile.objs
@@ -1,4 +1,5 @@
 obj-y += arm-semi.o
 obj-$(CONFIG_SOFTMMU) += machine.o
+obj-$(CONFIG_KVM) += kvm.o
 obj-y += translate.o op_helper.o helper.o cpu.o
 obj-y += neon_helper.o iwmmxt_helper.o
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index ff4de10..8c7e574 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -236,6 +236,7 @@ ARMCPU *cpu_arm_init(const char *cpu_model);
 void arm_translate_init(void);
 int cpu_arm_exec(CPUARMState *s);
 void do_interrupt(CPUARMState *);
+int bank_number(CPUARMState *env, int mode);
 void switch_mode(CPUARMState *, int);
 uint32_t do_arm_semihosting(CPUARMState *env);
 
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 58340bd..f62f3da 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1619,7 +1619,7 @@ uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode)
 #else
 
 /* Map CPU modes onto saved register banks.  */
-static inline int bank_number(CPUARMState *env, int mode)
+int bank_number(CPUARMState *env, int mode)
 {
     switch (mode) {
     case ARM_CPU_MODE_USR:
diff --git a/target-arm/kvm.c b/target-arm/kvm.c
new file mode 100644
index 0000000..fee60e1
--- /dev/null
+++ b/target-arm/kvm.c
@@ -0,0 +1,328 @@
+/*
+ * ARM implementation of KVM hooks
+ *
+ * Copyright Christoffer Dall 2009-2010
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <linux/kvm.h>
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "kvm.h"
+#include "cpu.h"
+#include "device_tree.h"
+#include "hw/arm-misc.h"
+
+const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
+    KVM_CAP_LAST_INFO
+};
+
+int kvm_arch_init(KVMState *s)
+{
+    /* For ARM interrupt delivery is always asynchronous,
+     * whether we are using an in-kernel VGIC or not.
+     */
+    kvm_async_interrupts_allowed = true;
+    return 0;
+}
+
+int kvm_arch_init_vcpu(CPUARMState *env)
+{
+    struct kvm_vcpu_init init;
+
+    init.target = KVM_ARM_TARGET_CORTEX_A15;
+    memset(init.features, 0, sizeof(init.features));
+    return kvm_vcpu_ioctl(env, KVM_ARM_VCPU_INIT, &init);
+}
+
+struct reg {
+    uint64_t id;
+    int offset;
+};
+
+#define COREREG(KERNELNAME, QEMUFIELD)                       \
+    {                                                        \
+        KVM_REG_ARM | KVM_REG_SIZE_U32 |                     \
+        KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(KERNELNAME), \
+        offsetof(CPUARMState, QEMUFIELD)                     \
+    }
+
+#define CP15REG(CRN, CRM, OPC1, OPC2, QEMUFIELD) \
+    {                                            \
+        KVM_REG_ARM | KVM_REG_SIZE_U32 |         \
+        (15 << KVM_REG_ARM_COPROC_SHIFT) |       \
+        ((CRN) << KVM_REG_ARM_32_CRN_SHIFT) |    \
+        ((CRM) << KVM_REG_ARM_CRM_SHIFT) |       \
+        ((OPC1) << KVM_REG_ARM_OPC1_SHIFT) |     \
+        ((OPC2) << KVM_REG_ARM_32_OPC2_SHIFT),   \
+        offsetof(CPUARMState, QEMUFIELD)         \
+    }
+
+const struct reg regs[] = {
+    /* R0_usr .. R14_usr */
+    COREREG(usr_regs[0], regs[0]),
+    COREREG(usr_regs[1], regs[1]),
+    COREREG(usr_regs[2], regs[2]),
+    COREREG(usr_regs[3], regs[3]),
+    COREREG(usr_regs[4], regs[4]),
+    COREREG(usr_regs[5], regs[5]),
+    COREREG(usr_regs[6], regs[6]),
+    COREREG(usr_regs[7], regs[7]),
+    COREREG(usr_regs[8], usr_regs[0]),
+    COREREG(usr_regs[9], usr_regs[1]),
+    COREREG(usr_regs[10], usr_regs[2]),
+    COREREG(usr_regs[11], usr_regs[3]),
+    COREREG(usr_regs[12], usr_regs[4]),
+    COREREG(usr_regs[13], banked_r13[0]),
+    COREREG(usr_regs[14], banked_r14[0]),
+    /* R13, R14, SPSR for SVC, ABT, UND, IRQ banks */
+    COREREG(svc_regs[0], banked_r13[1]),
+    COREREG(svc_regs[1], banked_r14[1]),
+    COREREG(svc_regs[2], banked_spsr[1]),
+    COREREG(abt_regs[0], banked_r13[2]),
+    COREREG(abt_regs[1], banked_r14[2]),
+    COREREG(abt_regs[2], banked_spsr[2]),
+    COREREG(und_regs[0], banked_r13[3]),
+    COREREG(und_regs[1], banked_r14[3]),
+    COREREG(und_regs[2], banked_spsr[3]),
+    COREREG(irq_regs[0], banked_r13[4]),
+    COREREG(irq_regs[1], banked_r14[4]),
+    COREREG(irq_regs[2], banked_spsr[4]),
+    /* R8_fiq .. R14_fiq and SPSR_fiq */
+    COREREG(fiq_regs[0], fiq_regs[0]),
+    COREREG(fiq_regs[1], fiq_regs[1]),
+    COREREG(fiq_regs[2], fiq_regs[2]),
+    COREREG(fiq_regs[3], fiq_regs[3]),
+    COREREG(fiq_regs[4], fiq_regs[4]),
+    COREREG(fiq_regs[0], banked_r13[5]),
+    COREREG(fiq_regs[1], banked_r14[5]),
+    COREREG(fiq_regs[2], banked_spsr[5]),
+    /* R15 */
+    COREREG(pc, regs[15]),
+    /* A non-comprehensive set of cp15 registers.
+     * TODO: drive this from the cp_regs hashtable instead.
+     */
+    CP15REG(1, 0, 0, 0, cp15.c1_sys), /* SCTLR */
+    CP15REG(2, 0, 0, 2, cp15.c2_control), /* TTBCR */
+    CP15REG(3, 0, 0, 0, cp15.c3), /* DACR */
+};
+
+int kvm_arch_put_registers(CPUARMState *env, int level)
+{
+    struct kvm_one_reg r;
+    int mode, bn;
+    int ret, i;
+    uint32_t cpsr;
+    uint64_t ttbr;
+
+    /* Make sure the banked regs are properly set */
+    mode = env->uncached_cpsr & CPSR_M;
+    bn = bank_number(env, mode);
+    if (mode == ARM_CPU_MODE_FIQ) {
+        memcpy(env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t));
+    } else {
+        memcpy(env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t));
+    }
+    env->banked_r13[bn] = env->regs[13];
+    env->banked_r14[bn] = env->regs[14];
+    env->banked_spsr[bn] = env->spsr;
+
+    /* Now we can safely copy stuff down to the kernel */
+    for (i = 0; i < ARRAY_SIZE(regs); i++) {
+        r.id = regs[i].id;
+        r.addr = (uintptr_t)(env) + regs[i].offset;
+        ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
+        if (ret) {
+            return ret;
+        }
+    }
+
+    /* Special cases which aren't a single CPUARMState field */
+    cpsr = cpsr_read(env);
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 |
+        KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(cpsr);
+    r.addr = (uintptr_t)(&cpsr);
+    ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
+    if (ret) {
+        return ret;
+    }
+
+    /* TTBR0: cp15 crm=2 opc1=0 */
+    ttbr = ((uint64_t)env->cp15.c2_base0_hi << 32) | env->cp15.c2_base0;
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
+        (2 << KVM_REG_ARM_CRM_SHIFT) | (0 << KVM_REG_ARM_OPC1_SHIFT);
+    r.addr = (uintptr_t)(&ttbr);
+    ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
+    if (ret) {
+        return ret;
+    }
+
+    /* TTBR1: cp15 crm=2 opc1=1 */
+    ttbr = ((uint64_t)env->cp15.c2_base1_hi << 32) | env->cp15.c2_base1;
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
+        (2 << KVM_REG_ARM_CRM_SHIFT) | (1 << KVM_REG_ARM_OPC1_SHIFT);
+    r.addr = (uintptr_t)(&ttbr);
+    ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
+
+    return ret;
+}
+
+int kvm_arch_get_registers(CPUARMState *env)
+{
+    struct kvm_one_reg r;
+    int mode, bn;
+    int ret, i;
+    uint32_t cpsr;
+    uint64_t ttbr;
+
+    for (i = 0; i < ARRAY_SIZE(regs); i++) {
+        r.id = regs[i].id;
+        r.addr = (uintptr_t)(env) + regs[i].offset;
+        ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
+        if (ret) {
+            return ret;
+        }
+    }
+
+    /* Special cases which aren't a single CPUARMState field */
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 |
+        KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(cpsr);
+    r.addr = (uintptr_t)(&cpsr);
+    ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
+    if (ret) {
+        return ret;
+    }
+    cpsr_write(env, cpsr, 0xffffffff);
+
+    /* TTBR0: cp15 crm=2 opc1=0 */
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
+        (2 << KVM_REG_ARM_CRM_SHIFT) | (0 << KVM_REG_ARM_OPC1_SHIFT);
+    r.addr = (uintptr_t)(&ttbr);
+    ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
+    if (ret) {
+        return ret;
+    }
+    env->cp15.c2_base0_hi = ttbr >> 32;
+    env->cp15.c2_base0 = ttbr;
+
+    /* TTBR1: cp15 crm=2 opc1=1 */
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
+        (2 << KVM_REG_ARM_CRM_SHIFT) | (1 << KVM_REG_ARM_OPC1_SHIFT);
+    r.addr = (uintptr_t)(&ttbr);
+    ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
+    if (ret) {
+        return ret;
+    }
+    env->cp15.c2_base1_hi = ttbr >> 32;
+    env->cp15.c2_base1 = ttbr;
+
+    /* Make sure the current mode regs are properly set */
+    mode = env->uncached_cpsr & CPSR_M;
+    bn = bank_number(env, mode);
+    if (mode == ARM_CPU_MODE_FIQ) {
+        memcpy(env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t));
+    } else {
+        memcpy(env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t));
+    }
+    env->regs[13] = env->banked_r13[bn];
+    env->regs[14] = env->banked_r14[bn];
+    env->spsr = env->banked_spsr[bn];
+
+    /* The main GET_ONE_REG loop above set c2_control, but we need to
+     * update some extra cached precomputed values too.
+     * When this is driven from the cp_regs hashtable then this ugliness
+     * can disappear because we'll use the access function which sets
+     * these values automatically.
+     */
+    env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> env->cp15.c2_control);
+    env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> env->cp15.c2_control);
+
+    return 0;
+}
+
+void kvm_arch_pre_run(CPUARMState *env, struct kvm_run *run)
+{
+}
+
+void kvm_arch_post_run(CPUARMState *env, struct kvm_run *run)
+{
+}
+
+int kvm_arch_handle_exit(CPUARMState *env, struct kvm_run *run)
+{
+    int ret = 0;
+
+    return ret;
+}
+
+void kvm_arch_reset_vcpu(CPUARMState *env)
+{
+}
+
+bool kvm_arch_stop_on_emulation_error(CPUARMState *env)
+{
+    return true;
+}
+
+int kvm_arch_process_async_events(CPUARMState *env)
+{
+    return 0;
+}
+
+int kvm_arch_on_sigbus_vcpu(CPUARMState *env, int code, void *addr)
+{
+    return 1;
+}
+
+int kvm_arch_on_sigbus(int code, void *addr)
+{
+    return 1;
+}
+
+void kvm_arch_update_guest_debug(CPUARMState *env, struct kvm_guest_debug *dbg)
+{
+    fprintf(stderr, "%s: not implemented\n", __func__);
+}
+
+int kvm_arch_insert_sw_breakpoint(CPUARMState *env,
+                                  struct kvm_sw_breakpoint *bp)
+{
+    fprintf(stderr, "%s: not implemented\n", __func__);
+    return -EINVAL;
+}
+
+int kvm_arch_insert_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type)
+{
+    fprintf(stderr, "%s: not implemented\n", __func__);
+    return -EINVAL;
+}
+
+int kvm_arch_remove_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type)
+{
+    fprintf(stderr, "%s: not implemented\n", __func__);
+    return -EINVAL;
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUARMState *env,
+                                  struct kvm_sw_breakpoint *bp)
+{
+    fprintf(stderr, "%s: not implemented\n", __func__);
+    return -EINVAL;
+}
+
+void kvm_arch_remove_all_hw_breakpoints(void)
+{
+    fprintf(stderr, "%s: not implemented\n", __func__);
+}
-- 
1.7.9.5

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

* [RFC v2 3/6] hw/arm_gic: Add presave/postload hooks
  2012-10-10 15:07 ` [Qemu-devel] " Peter Maydell
@ 2012-10-10 15:07   ` Peter Maydell
  -1 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-10 15:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvmarm, kvm, patches

Add presave/postload hooks to the ARM GIC common base class.
These will be used by the KVM in-kernel GIC subclass to sync
state between kernel and userspace when migrating.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm_gic_common.c   |   10 ++++++++++
 hw/arm_gic_internal.h |    2 ++
 2 files changed, 12 insertions(+)

diff --git a/hw/arm_gic_common.c b/hw/arm_gic_common.c
index 360e782..d972755 100644
--- a/hw/arm_gic_common.c
+++ b/hw/arm_gic_common.c
@@ -23,9 +23,14 @@
 static void gic_save(QEMUFile *f, void *opaque)
 {
     gic_state *s = (gic_state *)opaque;
+    ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
     int i;
     int j;
 
+    if (c->pre_save) {
+        c->pre_save(s);
+    }
+
     qemu_put_be32(f, s->enabled);
     for (i = 0; i < s->num_cpu; i++) {
         qemu_put_be32(f, s->cpu_enabled[i]);
@@ -57,6 +62,7 @@ static void gic_save(QEMUFile *f, void *opaque)
 static int gic_load(QEMUFile *f, void *opaque, int version_id)
 {
     gic_state *s = (gic_state *)opaque;
+    ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
     int i;
     int j;
 
@@ -91,6 +97,10 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id)
         s->irq_state[i].trigger = qemu_get_byte(f);
     }
 
+    if (c->post_load) {
+        c->post_load(s);
+    }
+
     return 0;
 }
 
diff --git a/hw/arm_gic_internal.h b/hw/arm_gic_internal.h
index db4fad5..183dca6 100644
--- a/hw/arm_gic_internal.h
+++ b/hw/arm_gic_internal.h
@@ -118,6 +118,8 @@ void gic_init_irqs_and_distributor(gic_state *s, int num_irq);
 
 typedef struct ARMGICCommonClass {
     SysBusDeviceClass parent_class;
+    void (*pre_save)(gic_state *s);
+    void (*post_load)(gic_state *s);
 } ARMGICCommonClass;
 
 #define TYPE_ARM_GIC "arm_gic"
-- 
1.7.9.5

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

* [Qemu-devel] [RFC v2 3/6] hw/arm_gic: Add presave/postload hooks
@ 2012-10-10 15:07   ` Peter Maydell
  0 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-10 15:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvmarm, kvm, patches

Add presave/postload hooks to the ARM GIC common base class.
These will be used by the KVM in-kernel GIC subclass to sync
state between kernel and userspace when migrating.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm_gic_common.c   |   10 ++++++++++
 hw/arm_gic_internal.h |    2 ++
 2 files changed, 12 insertions(+)

diff --git a/hw/arm_gic_common.c b/hw/arm_gic_common.c
index 360e782..d972755 100644
--- a/hw/arm_gic_common.c
+++ b/hw/arm_gic_common.c
@@ -23,9 +23,14 @@
 static void gic_save(QEMUFile *f, void *opaque)
 {
     gic_state *s = (gic_state *)opaque;
+    ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
     int i;
     int j;
 
+    if (c->pre_save) {
+        c->pre_save(s);
+    }
+
     qemu_put_be32(f, s->enabled);
     for (i = 0; i < s->num_cpu; i++) {
         qemu_put_be32(f, s->cpu_enabled[i]);
@@ -57,6 +62,7 @@ static void gic_save(QEMUFile *f, void *opaque)
 static int gic_load(QEMUFile *f, void *opaque, int version_id)
 {
     gic_state *s = (gic_state *)opaque;
+    ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
     int i;
     int j;
 
@@ -91,6 +97,10 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id)
         s->irq_state[i].trigger = qemu_get_byte(f);
     }
 
+    if (c->post_load) {
+        c->post_load(s);
+    }
+
     return 0;
 }
 
diff --git a/hw/arm_gic_internal.h b/hw/arm_gic_internal.h
index db4fad5..183dca6 100644
--- a/hw/arm_gic_internal.h
+++ b/hw/arm_gic_internal.h
@@ -118,6 +118,8 @@ void gic_init_irqs_and_distributor(gic_state *s, int num_irq);
 
 typedef struct ARMGICCommonClass {
     SysBusDeviceClass parent_class;
+    void (*pre_save)(gic_state *s);
+    void (*post_load)(gic_state *s);
 } ARMGICCommonClass;
 
 #define TYPE_ARM_GIC "arm_gic"
-- 
1.7.9.5

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

* [RFC v2 4/6] hw/kvm/arm_gic: Implement support for KVM in-kernel ARM GIC
  2012-10-10 15:07 ` [Qemu-devel] " Peter Maydell
@ 2012-10-10 15:07   ` Peter Maydell
  -1 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-10 15:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvmarm, kvm, patches

Implement support for using the KVM in-kernel GIC for ARM.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/a15mpcore.c       |    8 ++-
 hw/arm/Makefile.objs |    1 +
 hw/kvm/arm_gic.c     |  162 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 170 insertions(+), 1 deletion(-)
 create mode 100644 hw/kvm/arm_gic.c

diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c
index fc0a02a..a37fc61 100644
--- a/hw/a15mpcore.c
+++ b/hw/a15mpcore.c
@@ -19,6 +19,7 @@
  */
 
 #include "sysbus.h"
+#include "kvm.h"
 
 /* A15MP private memory region.  */
 
@@ -41,7 +42,12 @@ static int a15mp_priv_init(SysBusDevice *dev)
     A15MPPrivState *s = FROM_SYSBUS(A15MPPrivState, dev);
     SysBusDevice *busdev;
 
-    s->gic = qdev_create(NULL, "arm_gic");
+    if (kvm_irqchip_in_kernel()) {
+        s->gic = qdev_create(NULL, "kvm-arm_gic");
+    } else {
+        s->gic = qdev_create(NULL, "arm_gic");
+    }
+
     qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
     qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
     qdev_prop_set_uint32(s->gic, "revision", 2);
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 6d049e7..38b10a8 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -31,5 +31,6 @@ obj-y += collie.o
 obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o
 obj-y += kzm.o
 obj-$(CONFIG_FDT) += ../device_tree.o
+obj-$(CONFIG_KVM) += kvm/arm_gic.o
 
 obj-y := $(addprefix ../,$(obj-y))
diff --git a/hw/kvm/arm_gic.c b/hw/kvm/arm_gic.c
new file mode 100644
index 0000000..3ec538d
--- /dev/null
+++ b/hw/kvm/arm_gic.c
@@ -0,0 +1,162 @@
+/*
+ * ARM Generic Interrupt Controller using KVM in-kernel support
+ *
+ * Copyright (c) 2012 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/sysbus.h"
+#include "kvm.h"
+#include "hw/arm_gic_internal.h"
+
+#define TYPE_KVM_ARM_GIC "kvm-arm_gic"
+#define KVM_ARM_GIC(obj) \
+     OBJECT_CHECK(gic_state, (obj), TYPE_KVM_ARM_GIC)
+#define KVM_ARM_GIC_CLASS(klass) \
+     OBJECT_CLASS_CHECK(KVMARMGICClass, (klass), TYPE_KVM_ARM_GIC)
+#define KVM_ARM_GIC_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(KVMARMGICClass, (obj), TYPE_KVM_ARM_GIC)
+
+typedef struct KVMARMGICClass {
+    ARMGICCommonClass parent_class;
+    int (*parent_init)(SysBusDevice *dev);
+    void (*parent_reset)(DeviceState *dev);
+} KVMARMGICClass;
+
+static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
+{
+    /* Meaning of the 'irq' parameter:
+     *  [0..N-1] : external interrupts
+     *  [N..N+31] : PPI (internal) interrupts for CPU 0
+     *  [N+32..N+63] : PPI (internal interrupts for CPU 1
+     *  ...
+     * Convert this to the kernel's desired encoding, which
+     * has separate fields in the irq number for type,
+     * CPU number and interrupt number.
+     */
+    gic_state *s = (gic_state *)opaque;
+    int kvm_irq, irqtype, cpu;
+
+    if (irq < (s->num_irq - GIC_INTERNAL)) {
+        /* External interrupt. The kernel numbers these like the GIC
+         * hardware, with external interrupt IDs starting after the
+         * internal ones.
+         */
+        irqtype = KVM_ARM_IRQ_TYPE_SPI;
+        cpu = 0;
+        irq += GIC_INTERNAL;
+    } else {
+        /* Internal interrupt: decode into (cpu, interrupt id) */
+        irqtype = KVM_ARM_IRQ_TYPE_PPI;
+        irq -= (s->num_irq - GIC_INTERNAL);
+        cpu = irq / GIC_INTERNAL;
+        irq %= GIC_INTERNAL;
+    }
+    kvm_irq = (irqtype << KVM_ARM_IRQ_TYPE_SHIFT)
+        | (cpu << KVM_ARM_IRQ_VCPU_SHIFT) | irq;
+
+    kvm_set_irq(kvm_state, kvm_irq, !!level);
+}
+
+static void kvm_arm_gic_put(gic_state *s)
+{
+    /* TODO: there isn't currently a kernel interface to set the GIC state */
+}
+
+static void kvm_arm_gic_get(gic_state *s)
+{
+    /* TODO: there isn't currently a kernel interface to get the GIC state */
+}
+
+static void kvm_arm_gic_reset(DeviceState *dev)
+{
+    gic_state *s = ARM_GIC_COMMON(dev);
+    KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
+    kgc->parent_reset(dev);
+    kvm_arm_gic_put(s);
+}
+
+static int kvm_arm_gic_init(SysBusDevice *dev)
+{
+    /* Device instance init function for the GIC sysbus device */
+    int i;
+    gic_state *s = FROM_SYSBUS(gic_state, dev);
+    KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
+
+    kgc->parent_init(dev);
+
+    i = s->num_irq - GIC_INTERNAL;
+    /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
+     * GPIO array layout is thus:
+     *  [0..N-1] SPIs
+     *  [N..N+31] PPIs for CPU 0
+     *  [N+32..N+63] PPIs for CPU 1
+     *   ...
+     */
+    i += (GIC_INTERNAL * s->num_cpu);
+    qdev_init_gpio_in(&s->busdev.qdev, kvm_arm_gic_set_irq, i);
+    /* We never use our outbound IRQ lines but provide them so that
+     * we maintain the same interface as the non-KVM GIC.
+     */
+    for (i = 0; i < s->num_cpu; i++) {
+        sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
+    }
+    /* Distributor */
+    memory_region_init_reservation(&s->iomem, "kvm-gic_dist", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    /* CPU interface for current core. Unlike arm_gic, we don't
+     * provide the "interface for core #N" memory regions, because
+     * cores with a VGIC don't have those.
+     */
+    memory_region_init_reservation(&s->cpuiomem[0], "kvm-gic_cpu", 0x1000);
+    sysbus_init_mmio(dev, &s->cpuiomem[0]);
+    /* TODO: we should tell the kernel at some point the address
+     * of the private peripheral base. However we don't currently have
+     * any convenient infrastructure to do that, and in any case the
+     * kernel doesn't yet implement an ioctl to let us tell it.
+     */
+    return 0;
+}
+
+static void kvm_arm_gic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+    ARMGICCommonClass *agcc = ARM_GIC_COMMON_CLASS(klass);
+    KVMARMGICClass *kgc = KVM_ARM_GIC_CLASS(klass);
+    agcc->pre_save = kvm_arm_gic_get;
+    agcc->post_load = kvm_arm_gic_put;
+    kgc->parent_init = sbc->init;
+    kgc->parent_reset = dc->reset;
+    sbc->init = kvm_arm_gic_init;
+    dc->reset = kvm_arm_gic_reset;
+    dc->no_user = 1;
+}
+
+static TypeInfo arm_gic_info = {
+    .name = TYPE_KVM_ARM_GIC,
+    .parent = TYPE_ARM_GIC_COMMON,
+    .instance_size = sizeof(gic_state),
+    .class_init = kvm_arm_gic_class_init,
+    .class_size = sizeof(KVMARMGICClass),
+};
+
+static void arm_gic_register_types(void)
+{
+    type_register_static(&arm_gic_info);
+}
+
+type_init(arm_gic_register_types)
-- 
1.7.9.5

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

* [Qemu-devel] [RFC v2 4/6] hw/kvm/arm_gic: Implement support for KVM in-kernel ARM GIC
@ 2012-10-10 15:07   ` Peter Maydell
  0 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-10 15:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvmarm, kvm, patches

Implement support for using the KVM in-kernel GIC for ARM.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/a15mpcore.c       |    8 ++-
 hw/arm/Makefile.objs |    1 +
 hw/kvm/arm_gic.c     |  162 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 170 insertions(+), 1 deletion(-)
 create mode 100644 hw/kvm/arm_gic.c

diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c
index fc0a02a..a37fc61 100644
--- a/hw/a15mpcore.c
+++ b/hw/a15mpcore.c
@@ -19,6 +19,7 @@
  */
 
 #include "sysbus.h"
+#include "kvm.h"
 
 /* A15MP private memory region.  */
 
@@ -41,7 +42,12 @@ static int a15mp_priv_init(SysBusDevice *dev)
     A15MPPrivState *s = FROM_SYSBUS(A15MPPrivState, dev);
     SysBusDevice *busdev;
 
-    s->gic = qdev_create(NULL, "arm_gic");
+    if (kvm_irqchip_in_kernel()) {
+        s->gic = qdev_create(NULL, "kvm-arm_gic");
+    } else {
+        s->gic = qdev_create(NULL, "arm_gic");
+    }
+
     qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
     qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
     qdev_prop_set_uint32(s->gic, "revision", 2);
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 6d049e7..38b10a8 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -31,5 +31,6 @@ obj-y += collie.o
 obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o
 obj-y += kzm.o
 obj-$(CONFIG_FDT) += ../device_tree.o
+obj-$(CONFIG_KVM) += kvm/arm_gic.o
 
 obj-y := $(addprefix ../,$(obj-y))
diff --git a/hw/kvm/arm_gic.c b/hw/kvm/arm_gic.c
new file mode 100644
index 0000000..3ec538d
--- /dev/null
+++ b/hw/kvm/arm_gic.c
@@ -0,0 +1,162 @@
+/*
+ * ARM Generic Interrupt Controller using KVM in-kernel support
+ *
+ * Copyright (c) 2012 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/sysbus.h"
+#include "kvm.h"
+#include "hw/arm_gic_internal.h"
+
+#define TYPE_KVM_ARM_GIC "kvm-arm_gic"
+#define KVM_ARM_GIC(obj) \
+     OBJECT_CHECK(gic_state, (obj), TYPE_KVM_ARM_GIC)
+#define KVM_ARM_GIC_CLASS(klass) \
+     OBJECT_CLASS_CHECK(KVMARMGICClass, (klass), TYPE_KVM_ARM_GIC)
+#define KVM_ARM_GIC_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(KVMARMGICClass, (obj), TYPE_KVM_ARM_GIC)
+
+typedef struct KVMARMGICClass {
+    ARMGICCommonClass parent_class;
+    int (*parent_init)(SysBusDevice *dev);
+    void (*parent_reset)(DeviceState *dev);
+} KVMARMGICClass;
+
+static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
+{
+    /* Meaning of the 'irq' parameter:
+     *  [0..N-1] : external interrupts
+     *  [N..N+31] : PPI (internal) interrupts for CPU 0
+     *  [N+32..N+63] : PPI (internal interrupts for CPU 1
+     *  ...
+     * Convert this to the kernel's desired encoding, which
+     * has separate fields in the irq number for type,
+     * CPU number and interrupt number.
+     */
+    gic_state *s = (gic_state *)opaque;
+    int kvm_irq, irqtype, cpu;
+
+    if (irq < (s->num_irq - GIC_INTERNAL)) {
+        /* External interrupt. The kernel numbers these like the GIC
+         * hardware, with external interrupt IDs starting after the
+         * internal ones.
+         */
+        irqtype = KVM_ARM_IRQ_TYPE_SPI;
+        cpu = 0;
+        irq += GIC_INTERNAL;
+    } else {
+        /* Internal interrupt: decode into (cpu, interrupt id) */
+        irqtype = KVM_ARM_IRQ_TYPE_PPI;
+        irq -= (s->num_irq - GIC_INTERNAL);
+        cpu = irq / GIC_INTERNAL;
+        irq %= GIC_INTERNAL;
+    }
+    kvm_irq = (irqtype << KVM_ARM_IRQ_TYPE_SHIFT)
+        | (cpu << KVM_ARM_IRQ_VCPU_SHIFT) | irq;
+
+    kvm_set_irq(kvm_state, kvm_irq, !!level);
+}
+
+static void kvm_arm_gic_put(gic_state *s)
+{
+    /* TODO: there isn't currently a kernel interface to set the GIC state */
+}
+
+static void kvm_arm_gic_get(gic_state *s)
+{
+    /* TODO: there isn't currently a kernel interface to get the GIC state */
+}
+
+static void kvm_arm_gic_reset(DeviceState *dev)
+{
+    gic_state *s = ARM_GIC_COMMON(dev);
+    KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
+    kgc->parent_reset(dev);
+    kvm_arm_gic_put(s);
+}
+
+static int kvm_arm_gic_init(SysBusDevice *dev)
+{
+    /* Device instance init function for the GIC sysbus device */
+    int i;
+    gic_state *s = FROM_SYSBUS(gic_state, dev);
+    KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
+
+    kgc->parent_init(dev);
+
+    i = s->num_irq - GIC_INTERNAL;
+    /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
+     * GPIO array layout is thus:
+     *  [0..N-1] SPIs
+     *  [N..N+31] PPIs for CPU 0
+     *  [N+32..N+63] PPIs for CPU 1
+     *   ...
+     */
+    i += (GIC_INTERNAL * s->num_cpu);
+    qdev_init_gpio_in(&s->busdev.qdev, kvm_arm_gic_set_irq, i);
+    /* We never use our outbound IRQ lines but provide them so that
+     * we maintain the same interface as the non-KVM GIC.
+     */
+    for (i = 0; i < s->num_cpu; i++) {
+        sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
+    }
+    /* Distributor */
+    memory_region_init_reservation(&s->iomem, "kvm-gic_dist", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    /* CPU interface for current core. Unlike arm_gic, we don't
+     * provide the "interface for core #N" memory regions, because
+     * cores with a VGIC don't have those.
+     */
+    memory_region_init_reservation(&s->cpuiomem[0], "kvm-gic_cpu", 0x1000);
+    sysbus_init_mmio(dev, &s->cpuiomem[0]);
+    /* TODO: we should tell the kernel at some point the address
+     * of the private peripheral base. However we don't currently have
+     * any convenient infrastructure to do that, and in any case the
+     * kernel doesn't yet implement an ioctl to let us tell it.
+     */
+    return 0;
+}
+
+static void kvm_arm_gic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+    ARMGICCommonClass *agcc = ARM_GIC_COMMON_CLASS(klass);
+    KVMARMGICClass *kgc = KVM_ARM_GIC_CLASS(klass);
+    agcc->pre_save = kvm_arm_gic_get;
+    agcc->post_load = kvm_arm_gic_put;
+    kgc->parent_init = sbc->init;
+    kgc->parent_reset = dc->reset;
+    sbc->init = kvm_arm_gic_init;
+    dc->reset = kvm_arm_gic_reset;
+    dc->no_user = 1;
+}
+
+static TypeInfo arm_gic_info = {
+    .name = TYPE_KVM_ARM_GIC,
+    .parent = TYPE_ARM_GIC_COMMON,
+    .instance_size = sizeof(gic_state),
+    .class_init = kvm_arm_gic_class_init,
+    .class_size = sizeof(KVMARMGICClass),
+};
+
+static void arm_gic_register_types(void)
+{
+    type_register_static(&arm_gic_info);
+}
+
+type_init(arm_gic_register_types)
-- 
1.7.9.5

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

* [RFC v2 5/6] ARM KVM: save and load VFP registers from kernel
  2012-10-10 15:07 ` [Qemu-devel] " Peter Maydell
@ 2012-10-10 15:07   ` Peter Maydell
  -1 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-10 15:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvmarm, kvm, patches

Add support for saving and restoring VFP register state from the
kernel. This includes a check that the KVM-created CPU has full
VFP support (as the TCG Cortex-A15 model always does), since for
the moment ARM QEMU doesn't have any way to tweak optional features
on created CPUs.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/kvm.c |   78 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 75 insertions(+), 3 deletions(-)

diff --git a/target-arm/kvm.c b/target-arm/kvm.c
index fee60e1..f17e7fd 100644
--- a/target-arm/kvm.c
+++ b/target-arm/kvm.c
@@ -39,10 +39,28 @@ int kvm_arch_init(KVMState *s)
 int kvm_arch_init_vcpu(CPUARMState *env)
 {
     struct kvm_vcpu_init init;
+    int ret;
+    uint64_t v;
+    struct kvm_one_reg r;
 
     init.target = KVM_ARM_TARGET_CORTEX_A15;
     memset(init.features, 0, sizeof(init.features));
-    return kvm_vcpu_ioctl(env, KVM_ARM_VCPU_INIT, &init);
+    ret = kvm_vcpu_ioctl(env, KVM_ARM_VCPU_INIT, &init);
+    if (ret) {
+        return ret;
+    }
+    /* Query the kernel to make sure it supports 32 VFP
+     * registers: QEMU's "cortex-a15" CPU is always a
+     * VFP-D32 core. The simplest way to do this is just
+     * to attempt to read register d31.
+     */
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP | 31;
+    r.addr = (uintptr_t)(&v);
+    ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
+    if (ret == ENOENT) {
+        return EINVAL;
+    }
+    return ret;
 }
 
 struct reg {
@@ -68,6 +86,13 @@ struct reg {
         offsetof(CPUARMState, QEMUFIELD)         \
     }
 
+#define VFPSYSREG(R)                                       \
+    {                                                      \
+        KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP | \
+        KVM_REG_ARM_VFP_##R,                               \
+        offsetof(CPUARMState, vfp.xregs[ARM_VFP_##R])      \
+    }
+
 const struct reg regs[] = {
     /* R0_usr .. R14_usr */
     COREREG(usr_regs[0], regs[0]),
@@ -115,6 +140,13 @@ const struct reg regs[] = {
     CP15REG(1, 0, 0, 0, cp15.c1_sys), /* SCTLR */
     CP15REG(2, 0, 0, 2, cp15.c2_control), /* TTBCR */
     CP15REG(3, 0, 0, 0, cp15.c3), /* DACR */
+    /* VFP system registers */
+    VFPSYSREG(FPSID),
+    VFPSYSREG(MVFR1),
+    VFPSYSREG(MVFR0),
+    VFPSYSREG(FPEXC),
+    VFPSYSREG(FPINST),
+    VFPSYSREG(FPINST2),
 };
 
 int kvm_arch_put_registers(CPUARMState *env, int level)
@@ -122,7 +154,7 @@ int kvm_arch_put_registers(CPUARMState *env, int level)
     struct kvm_one_reg r;
     int mode, bn;
     int ret, i;
-    uint32_t cpsr;
+    uint32_t cpsr, fpscr;
     uint64_t ttbr;
 
     /* Make sure the banked regs are properly set */
@@ -173,6 +205,26 @@ int kvm_arch_put_registers(CPUARMState *env, int level)
         (2 << KVM_REG_ARM_CRM_SHIFT) | (1 << KVM_REG_ARM_OPC1_SHIFT);
     r.addr = (uintptr_t)(&ttbr);
     ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
+    if (ret) {
+        return ret;
+    }
+
+    /* VFP registers */
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP;
+    for (i = 0; i < 32; i++) {
+        r.addr = (uintptr_t)(&env->vfp.regs[i]);
+        ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
+        if (ret) {
+            return ret;
+        }
+        r.id++;
+    }
+
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP |
+        KVM_REG_ARM_VFP_FPSCR;
+    fpscr = vfp_get_fpscr(env);
+    r.addr = (uintptr_t)&fpscr;
+    ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
 
     return ret;
 }
@@ -182,7 +234,7 @@ int kvm_arch_get_registers(CPUARMState *env)
     struct kvm_one_reg r;
     int mode, bn;
     int ret, i;
-    uint32_t cpsr;
+    uint32_t cpsr, fpscr;
     uint64_t ttbr;
 
     for (i = 0; i < ARRAY_SIZE(regs); i++) {
@@ -247,6 +299,26 @@ int kvm_arch_get_registers(CPUARMState *env)
     env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> env->cp15.c2_control);
     env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> env->cp15.c2_control);
 
+    /* VFP registers */
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP;
+    for (i = 0; i < 32; i++) {
+        r.addr = (uintptr_t)(&env->vfp.regs[i]);
+        ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
+        if (ret) {
+            return ret;
+        }
+        r.id++;
+    }
+
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP |
+        KVM_REG_ARM_VFP_FPSCR;
+    r.addr = (uintptr_t)&fpscr;
+    ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
+    if (ret) {
+        return ret;
+    }
+    vfp_set_fpscr(env, fpscr);
+
     return 0;
 }
 
-- 
1.7.9.5

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

* [Qemu-devel] [RFC v2 5/6] ARM KVM: save and load VFP registers from kernel
@ 2012-10-10 15:07   ` Peter Maydell
  0 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-10 15:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvmarm, kvm, patches

Add support for saving and restoring VFP register state from the
kernel. This includes a check that the KVM-created CPU has full
VFP support (as the TCG Cortex-A15 model always does), since for
the moment ARM QEMU doesn't have any way to tweak optional features
on created CPUs.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/kvm.c |   78 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 75 insertions(+), 3 deletions(-)

diff --git a/target-arm/kvm.c b/target-arm/kvm.c
index fee60e1..f17e7fd 100644
--- a/target-arm/kvm.c
+++ b/target-arm/kvm.c
@@ -39,10 +39,28 @@ int kvm_arch_init(KVMState *s)
 int kvm_arch_init_vcpu(CPUARMState *env)
 {
     struct kvm_vcpu_init init;
+    int ret;
+    uint64_t v;
+    struct kvm_one_reg r;
 
     init.target = KVM_ARM_TARGET_CORTEX_A15;
     memset(init.features, 0, sizeof(init.features));
-    return kvm_vcpu_ioctl(env, KVM_ARM_VCPU_INIT, &init);
+    ret = kvm_vcpu_ioctl(env, KVM_ARM_VCPU_INIT, &init);
+    if (ret) {
+        return ret;
+    }
+    /* Query the kernel to make sure it supports 32 VFP
+     * registers: QEMU's "cortex-a15" CPU is always a
+     * VFP-D32 core. The simplest way to do this is just
+     * to attempt to read register d31.
+     */
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP | 31;
+    r.addr = (uintptr_t)(&v);
+    ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
+    if (ret == ENOENT) {
+        return EINVAL;
+    }
+    return ret;
 }
 
 struct reg {
@@ -68,6 +86,13 @@ struct reg {
         offsetof(CPUARMState, QEMUFIELD)         \
     }
 
+#define VFPSYSREG(R)                                       \
+    {                                                      \
+        KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP | \
+        KVM_REG_ARM_VFP_##R,                               \
+        offsetof(CPUARMState, vfp.xregs[ARM_VFP_##R])      \
+    }
+
 const struct reg regs[] = {
     /* R0_usr .. R14_usr */
     COREREG(usr_regs[0], regs[0]),
@@ -115,6 +140,13 @@ const struct reg regs[] = {
     CP15REG(1, 0, 0, 0, cp15.c1_sys), /* SCTLR */
     CP15REG(2, 0, 0, 2, cp15.c2_control), /* TTBCR */
     CP15REG(3, 0, 0, 0, cp15.c3), /* DACR */
+    /* VFP system registers */
+    VFPSYSREG(FPSID),
+    VFPSYSREG(MVFR1),
+    VFPSYSREG(MVFR0),
+    VFPSYSREG(FPEXC),
+    VFPSYSREG(FPINST),
+    VFPSYSREG(FPINST2),
 };
 
 int kvm_arch_put_registers(CPUARMState *env, int level)
@@ -122,7 +154,7 @@ int kvm_arch_put_registers(CPUARMState *env, int level)
     struct kvm_one_reg r;
     int mode, bn;
     int ret, i;
-    uint32_t cpsr;
+    uint32_t cpsr, fpscr;
     uint64_t ttbr;
 
     /* Make sure the banked regs are properly set */
@@ -173,6 +205,26 @@ int kvm_arch_put_registers(CPUARMState *env, int level)
         (2 << KVM_REG_ARM_CRM_SHIFT) | (1 << KVM_REG_ARM_OPC1_SHIFT);
     r.addr = (uintptr_t)(&ttbr);
     ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
+    if (ret) {
+        return ret;
+    }
+
+    /* VFP registers */
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP;
+    for (i = 0; i < 32; i++) {
+        r.addr = (uintptr_t)(&env->vfp.regs[i]);
+        ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
+        if (ret) {
+            return ret;
+        }
+        r.id++;
+    }
+
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP |
+        KVM_REG_ARM_VFP_FPSCR;
+    fpscr = vfp_get_fpscr(env);
+    r.addr = (uintptr_t)&fpscr;
+    ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
 
     return ret;
 }
@@ -182,7 +234,7 @@ int kvm_arch_get_registers(CPUARMState *env)
     struct kvm_one_reg r;
     int mode, bn;
     int ret, i;
-    uint32_t cpsr;
+    uint32_t cpsr, fpscr;
     uint64_t ttbr;
 
     for (i = 0; i < ARRAY_SIZE(regs); i++) {
@@ -247,6 +299,26 @@ int kvm_arch_get_registers(CPUARMState *env)
     env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> env->cp15.c2_control);
     env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> env->cp15.c2_control);
 
+    /* VFP registers */
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP;
+    for (i = 0; i < 32; i++) {
+        r.addr = (uintptr_t)(&env->vfp.regs[i]);
+        ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
+        if (ret) {
+            return ret;
+        }
+        r.id++;
+    }
+
+    r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP |
+        KVM_REG_ARM_VFP_FPSCR;
+    r.addr = (uintptr_t)&fpscr;
+    ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
+    if (ret) {
+        return ret;
+    }
+    vfp_set_fpscr(env, fpscr);
+
     return 0;
 }
 
-- 
1.7.9.5

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

* [RFC v2 6/6] configure: Enable KVM on ARM
  2012-10-10 15:07 ` [Qemu-devel] " Peter Maydell
@ 2012-10-10 15:07   ` Peter Maydell
  -1 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-10 15:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvm, kvmarm, patches

Enable KVM on ARM hosts, now that all the necessary components
for it exist.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 configure |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/configure b/configure
index c4a7837..f87bcd6 100755
--- a/configure
+++ b/configure
@@ -3886,7 +3886,7 @@ case "$target_arch2" in
     echo "CONFIG_NO_XEN=y" >> $config_target_mak
 esac
 case "$target_arch2" in
-  i386|x86_64|ppcemb|ppc|ppc64|s390x)
+  arm|i386|x86_64|ppcemb|ppc|ppc64|s390x)
     # Make sure the target and host cpus are compatible
     if test "$kvm" = "yes" -a "$target_softmmu" = "yes" -a \
       \( "$target_arch2" = "$cpu" -o \
-- 
1.7.9.5


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

* [Qemu-devel] [RFC v2 6/6] configure: Enable KVM on ARM
@ 2012-10-10 15:07   ` Peter Maydell
  0 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-10 15:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvmarm, kvm, patches

Enable KVM on ARM hosts, now that all the necessary components
for it exist.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 configure |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/configure b/configure
index c4a7837..f87bcd6 100755
--- a/configure
+++ b/configure
@@ -3886,7 +3886,7 @@ case "$target_arch2" in
     echo "CONFIG_NO_XEN=y" >> $config_target_mak
 esac
 case "$target_arch2" in
-  i386|x86_64|ppcemb|ppc|ppc64|s390x)
+  arm|i386|x86_64|ppcemb|ppc|ppc64|s390x)
     # Make sure the target and host cpus are compatible
     if test "$kvm" = "yes" -a "$target_softmmu" = "yes" -a \
       \( "$target_arch2" = "$cpu" -o \
-- 
1.7.9.5

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

* Re: [Qemu-devel] [RFC v2 4/6] hw/kvm/arm_gic: Implement support for KVM in-kernel ARM GIC
  2012-10-10 15:07   ` [Qemu-devel] " Peter Maydell
@ 2012-10-10 17:23     ` Andreas Färber
  -1 siblings, 0 replies; 30+ messages in thread
From: Andreas Färber @ 2012-10-10 17:23 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-devel, kvmarm, kvm, patches

Am 10.10.2012 17:07, schrieb Peter Maydell:
> Implement support for using the KVM in-kernel GIC for ARM.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  hw/a15mpcore.c       |    8 ++-
>  hw/arm/Makefile.objs |    1 +
>  hw/kvm/arm_gic.c     |  162 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 170 insertions(+), 1 deletion(-)
>  create mode 100644 hw/kvm/arm_gic.c
> 
> diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c
> index fc0a02a..a37fc61 100644
> --- a/hw/a15mpcore.c
> +++ b/hw/a15mpcore.c
> @@ -19,6 +19,7 @@
>   */
>  
>  #include "sysbus.h"
> +#include "kvm.h"
>  
>  /* A15MP private memory region.  */
>  
> @@ -41,7 +42,12 @@ static int a15mp_priv_init(SysBusDevice *dev)
>      A15MPPrivState *s = FROM_SYSBUS(A15MPPrivState, dev);
>      SysBusDevice *busdev;
>  
> -    s->gic = qdev_create(NULL, "arm_gic");
> +    if (kvm_irqchip_in_kernel()) {
> +        s->gic = qdev_create(NULL, "kvm-arm_gic");
> +    } else {
> +        s->gic = qdev_create(NULL, "arm_gic");
> +    }

You could follow x86 more closely by just selecting apic_type. (Then if
we drop/change qdev_create() at some point it's one change less.)

> +
>      qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
>      qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
>      qdev_prop_set_uint32(s->gic, "revision", 2);
[...]
> diff --git a/hw/kvm/arm_gic.c b/hw/kvm/arm_gic.c
> new file mode 100644
> index 0000000..3ec538d
> --- /dev/null
> +++ b/hw/kvm/arm_gic.c
> @@ -0,0 +1,162 @@
> +/*
> + * ARM Generic Interrupt Controller using KVM in-kernel support
> + *
> + * Copyright (c) 2012 Linaro Limited
> + * Written by Peter Maydell
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "hw/sysbus.h"
> +#include "kvm.h"
> +#include "hw/arm_gic_internal.h"
> +
> +#define TYPE_KVM_ARM_GIC "kvm-arm_gic"

"kvm-arm-gic"?

> +#define KVM_ARM_GIC(obj) \
> +     OBJECT_CHECK(gic_state, (obj), TYPE_KVM_ARM_GIC)
> +#define KVM_ARM_GIC_CLASS(klass) \
> +     OBJECT_CLASS_CHECK(KVMARMGICClass, (klass), TYPE_KVM_ARM_GIC)
> +#define KVM_ARM_GIC_GET_CLASS(obj) \
> +     OBJECT_GET_CLASS(KVMARMGICClass, (obj), TYPE_KVM_ARM_GIC)
> +
> +typedef struct KVMARMGICClass {
> +    ARMGICCommonClass parent_class;
> +    int (*parent_init)(SysBusDevice *dev);
> +    void (*parent_reset)(DeviceState *dev);
> +} KVMARMGICClass;
> +
> +static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
> +{
> +    /* Meaning of the 'irq' parameter:
> +     *  [0..N-1] : external interrupts
> +     *  [N..N+31] : PPI (internal) interrupts for CPU 0
> +     *  [N+32..N+63] : PPI (internal interrupts for CPU 1
> +     *  ...
> +     * Convert this to the kernel's desired encoding, which
> +     * has separate fields in the irq number for type,
> +     * CPU number and interrupt number.
> +     */
> +    gic_state *s = (gic_state *)opaque;

You don't happen to have time to clean up gic_state -> GICState before
spreading its use? ;)

[...]
> +static TypeInfo arm_gic_info = {

static const

> +    .name = TYPE_KVM_ARM_GIC,
> +    .parent = TYPE_ARM_GIC_COMMON,
> +    .instance_size = sizeof(gic_state),
> +    .class_init = kvm_arm_gic_class_init,
> +    .class_size = sizeof(KVMARMGICClass),
> +};
> +
> +static void arm_gic_register_types(void)

kvm_arm_gic_register_types?

> +{
> +    type_register_static(&arm_gic_info);
> +}
> +
> +type_init(arm_gic_register_types)
> 

Andreas

-- 
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg

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

* Re: [Qemu-devel] [RFC v2 4/6] hw/kvm/arm_gic: Implement support for KVM in-kernel ARM GIC
@ 2012-10-10 17:23     ` Andreas Färber
  0 siblings, 0 replies; 30+ messages in thread
From: Andreas Färber @ 2012-10-10 17:23 UTC (permalink / raw)
  To: Peter Maydell; +Cc: patches, qemu-devel, kvm, kvmarm

Am 10.10.2012 17:07, schrieb Peter Maydell:
> Implement support for using the KVM in-kernel GIC for ARM.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  hw/a15mpcore.c       |    8 ++-
>  hw/arm/Makefile.objs |    1 +
>  hw/kvm/arm_gic.c     |  162 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 170 insertions(+), 1 deletion(-)
>  create mode 100644 hw/kvm/arm_gic.c
> 
> diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c
> index fc0a02a..a37fc61 100644
> --- a/hw/a15mpcore.c
> +++ b/hw/a15mpcore.c
> @@ -19,6 +19,7 @@
>   */
>  
>  #include "sysbus.h"
> +#include "kvm.h"
>  
>  /* A15MP private memory region.  */
>  
> @@ -41,7 +42,12 @@ static int a15mp_priv_init(SysBusDevice *dev)
>      A15MPPrivState *s = FROM_SYSBUS(A15MPPrivState, dev);
>      SysBusDevice *busdev;
>  
> -    s->gic = qdev_create(NULL, "arm_gic");
> +    if (kvm_irqchip_in_kernel()) {
> +        s->gic = qdev_create(NULL, "kvm-arm_gic");
> +    } else {
> +        s->gic = qdev_create(NULL, "arm_gic");
> +    }

You could follow x86 more closely by just selecting apic_type. (Then if
we drop/change qdev_create() at some point it's one change less.)

> +
>      qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
>      qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
>      qdev_prop_set_uint32(s->gic, "revision", 2);
[...]
> diff --git a/hw/kvm/arm_gic.c b/hw/kvm/arm_gic.c
> new file mode 100644
> index 0000000..3ec538d
> --- /dev/null
> +++ b/hw/kvm/arm_gic.c
> @@ -0,0 +1,162 @@
> +/*
> + * ARM Generic Interrupt Controller using KVM in-kernel support
> + *
> + * Copyright (c) 2012 Linaro Limited
> + * Written by Peter Maydell
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "hw/sysbus.h"
> +#include "kvm.h"
> +#include "hw/arm_gic_internal.h"
> +
> +#define TYPE_KVM_ARM_GIC "kvm-arm_gic"

"kvm-arm-gic"?

> +#define KVM_ARM_GIC(obj) \
> +     OBJECT_CHECK(gic_state, (obj), TYPE_KVM_ARM_GIC)
> +#define KVM_ARM_GIC_CLASS(klass) \
> +     OBJECT_CLASS_CHECK(KVMARMGICClass, (klass), TYPE_KVM_ARM_GIC)
> +#define KVM_ARM_GIC_GET_CLASS(obj) \
> +     OBJECT_GET_CLASS(KVMARMGICClass, (obj), TYPE_KVM_ARM_GIC)
> +
> +typedef struct KVMARMGICClass {
> +    ARMGICCommonClass parent_class;
> +    int (*parent_init)(SysBusDevice *dev);
> +    void (*parent_reset)(DeviceState *dev);
> +} KVMARMGICClass;
> +
> +static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
> +{
> +    /* Meaning of the 'irq' parameter:
> +     *  [0..N-1] : external interrupts
> +     *  [N..N+31] : PPI (internal) interrupts for CPU 0
> +     *  [N+32..N+63] : PPI (internal interrupts for CPU 1
> +     *  ...
> +     * Convert this to the kernel's desired encoding, which
> +     * has separate fields in the irq number for type,
> +     * CPU number and interrupt number.
> +     */
> +    gic_state *s = (gic_state *)opaque;

You don't happen to have time to clean up gic_state -> GICState before
spreading its use? ;)

[...]
> +static TypeInfo arm_gic_info = {

static const

> +    .name = TYPE_KVM_ARM_GIC,
> +    .parent = TYPE_ARM_GIC_COMMON,
> +    .instance_size = sizeof(gic_state),
> +    .class_init = kvm_arm_gic_class_init,
> +    .class_size = sizeof(KVMARMGICClass),
> +};
> +
> +static void arm_gic_register_types(void)

kvm_arm_gic_register_types?

> +{
> +    type_register_static(&arm_gic_info);
> +}
> +
> +type_init(arm_gic_register_types)
> 

Andreas

-- 
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg

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

* Re: [Qemu-devel] [RFC v2 3/6] hw/arm_gic: Add presave/postload hooks
  2012-10-10 15:07   ` [Qemu-devel] " Peter Maydell
@ 2012-10-10 17:29     ` Andreas Färber
  -1 siblings, 0 replies; 30+ messages in thread
From: Andreas Färber @ 2012-10-10 17:29 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-devel, kvmarm, kvm, patches

Am 10.10.2012 17:07, schrieb Peter Maydell:
> Add presave/postload hooks to the ARM GIC common base class.
> These will be used by the KVM in-kernel GIC subclass to sync
> state between kernel and userspace when migrating.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Andreas Färber <afaerber@suse.de>

/-F

-- 
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg

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

* Re: [Qemu-devel] [RFC v2 3/6] hw/arm_gic: Add presave/postload hooks
@ 2012-10-10 17:29     ` Andreas Färber
  0 siblings, 0 replies; 30+ messages in thread
From: Andreas Färber @ 2012-10-10 17:29 UTC (permalink / raw)
  To: Peter Maydell; +Cc: patches, qemu-devel, kvm, kvmarm

Am 10.10.2012 17:07, schrieb Peter Maydell:
> Add presave/postload hooks to the ARM GIC common base class.
> These will be used by the KVM in-kernel GIC subclass to sync
> state between kernel and userspace when migrating.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Andreas Färber <afaerber@suse.de>

/-F

-- 
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg

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

* Re: [Qemu-devel] [RFC v2 4/6] hw/kvm/arm_gic: Implement support for KVM in-kernel ARM GIC
  2012-10-10 17:23     ` Andreas Färber
@ 2012-10-10 17:35       ` Peter Maydell
  -1 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-10 17:35 UTC (permalink / raw)
  To: Andreas Färber; +Cc: qemu-devel, kvmarm, kvm, patches

On 10 October 2012 18:23, Andreas Färber <afaerber@suse.de> wrote:
> Am 10.10.2012 17:07, schrieb Peter Maydell:
>> Implement support for using the KVM in-kernel GIC for ARM.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>>  hw/a15mpcore.c       |    8 ++-
>>  hw/arm/Makefile.objs |    1 +
>>  hw/kvm/arm_gic.c     |  162 ++++++++++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 170 insertions(+), 1 deletion(-)
>>  create mode 100644 hw/kvm/arm_gic.c
>>
>> diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c
>> index fc0a02a..a37fc61 100644
>> --- a/hw/a15mpcore.c
>> +++ b/hw/a15mpcore.c
>> @@ -19,6 +19,7 @@
>>   */
>>
>>  #include "sysbus.h"
>> +#include "kvm.h"
>>
>>  /* A15MP private memory region.  */
>>
>> @@ -41,7 +42,12 @@ static int a15mp_priv_init(SysBusDevice *dev)
>>      A15MPPrivState *s = FROM_SYSBUS(A15MPPrivState, dev);
>>      SysBusDevice *busdev;
>>
>> -    s->gic = qdev_create(NULL, "arm_gic");
>> +    if (kvm_irqchip_in_kernel()) {
>> +        s->gic = qdev_create(NULL, "kvm-arm_gic");
>> +    } else {
>> +        s->gic = qdev_create(NULL, "arm_gic");
>> +    }
>
> You could follow x86 more closely by just selecting apic_type. (Then if
> we drop/change qdev_create() at some point it's one change less.)

Good idea.

>
>> +
>>      qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
>>      qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
>>      qdev_prop_set_uint32(s->gic, "revision", 2);
> [...]
>> diff --git a/hw/kvm/arm_gic.c b/hw/kvm/arm_gic.c
>> new file mode 100644
>> index 0000000..3ec538d
>> --- /dev/null
>> +++ b/hw/kvm/arm_gic.c
>> @@ -0,0 +1,162 @@
>> +/*
>> + * ARM Generic Interrupt Controller using KVM in-kernel support
>> + *
>> + * Copyright (c) 2012 Linaro Limited
>> + * Written by Peter Maydell
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation, either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along
>> + * with this program; if not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include "hw/sysbus.h"
>> +#include "kvm.h"
>> +#include "hw/arm_gic_internal.h"
>> +
>> +#define TYPE_KVM_ARM_GIC "kvm-arm_gic"
>
> "kvm-arm-gic"?

I was trying to follow arm_gic but yes, I guess it's better
to go with the recommended style (which is all-hyphens, right?)

>> +#define KVM_ARM_GIC(obj) \
>> +     OBJECT_CHECK(gic_state, (obj), TYPE_KVM_ARM_GIC)
>> +#define KVM_ARM_GIC_CLASS(klass) \
>> +     OBJECT_CLASS_CHECK(KVMARMGICClass, (klass), TYPE_KVM_ARM_GIC)
>> +#define KVM_ARM_GIC_GET_CLASS(obj) \
>> +     OBJECT_GET_CLASS(KVMARMGICClass, (obj), TYPE_KVM_ARM_GIC)
>> +
>> +typedef struct KVMARMGICClass {
>> +    ARMGICCommonClass parent_class;
>> +    int (*parent_init)(SysBusDevice *dev);
>> +    void (*parent_reset)(DeviceState *dev);
>> +} KVMARMGICClass;
>> +
>> +static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
>> +{
>> +    /* Meaning of the 'irq' parameter:
>> +     *  [0..N-1] : external interrupts
>> +     *  [N..N+31] : PPI (internal) interrupts for CPU 0
>> +     *  [N+32..N+63] : PPI (internal interrupts for CPU 1
>> +     *  ...
>> +     * Convert this to the kernel's desired encoding, which
>> +     * has separate fields in the irq number for type,
>> +     * CPU number and interrupt number.
>> +     */
>> +    gic_state *s = (gic_state *)opaque;
>
> You don't happen to have time to clean up gic_state -> GICState before
> spreading its use? ;)

I can submit a patch if you like...

> [...]
>> +static TypeInfo arm_gic_info = {
>
> static const

Yep.

>> +    .name = TYPE_KVM_ARM_GIC,
>> +    .parent = TYPE_ARM_GIC_COMMON,
>> +    .instance_size = sizeof(gic_state),
>> +    .class_init = kvm_arm_gic_class_init,
>> +    .class_size = sizeof(KVMARMGICClass),
>> +};
>> +
>> +static void arm_gic_register_types(void)
>
> kvm_arm_gic_register_types?

Oops, yes, cut-n-pasto.

-- PMM

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

* Re: [Qemu-devel] [RFC v2 4/6] hw/kvm/arm_gic: Implement support for KVM in-kernel ARM GIC
@ 2012-10-10 17:35       ` Peter Maydell
  0 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-10 17:35 UTC (permalink / raw)
  To: Andreas Färber; +Cc: patches, qemu-devel, kvm, kvmarm

On 10 October 2012 18:23, Andreas Färber <afaerber@suse.de> wrote:
> Am 10.10.2012 17:07, schrieb Peter Maydell:
>> Implement support for using the KVM in-kernel GIC for ARM.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>>  hw/a15mpcore.c       |    8 ++-
>>  hw/arm/Makefile.objs |    1 +
>>  hw/kvm/arm_gic.c     |  162 ++++++++++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 170 insertions(+), 1 deletion(-)
>>  create mode 100644 hw/kvm/arm_gic.c
>>
>> diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c
>> index fc0a02a..a37fc61 100644
>> --- a/hw/a15mpcore.c
>> +++ b/hw/a15mpcore.c
>> @@ -19,6 +19,7 @@
>>   */
>>
>>  #include "sysbus.h"
>> +#include "kvm.h"
>>
>>  /* A15MP private memory region.  */
>>
>> @@ -41,7 +42,12 @@ static int a15mp_priv_init(SysBusDevice *dev)
>>      A15MPPrivState *s = FROM_SYSBUS(A15MPPrivState, dev);
>>      SysBusDevice *busdev;
>>
>> -    s->gic = qdev_create(NULL, "arm_gic");
>> +    if (kvm_irqchip_in_kernel()) {
>> +        s->gic = qdev_create(NULL, "kvm-arm_gic");
>> +    } else {
>> +        s->gic = qdev_create(NULL, "arm_gic");
>> +    }
>
> You could follow x86 more closely by just selecting apic_type. (Then if
> we drop/change qdev_create() at some point it's one change less.)

Good idea.

>
>> +
>>      qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
>>      qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
>>      qdev_prop_set_uint32(s->gic, "revision", 2);
> [...]
>> diff --git a/hw/kvm/arm_gic.c b/hw/kvm/arm_gic.c
>> new file mode 100644
>> index 0000000..3ec538d
>> --- /dev/null
>> +++ b/hw/kvm/arm_gic.c
>> @@ -0,0 +1,162 @@
>> +/*
>> + * ARM Generic Interrupt Controller using KVM in-kernel support
>> + *
>> + * Copyright (c) 2012 Linaro Limited
>> + * Written by Peter Maydell
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation, either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along
>> + * with this program; if not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include "hw/sysbus.h"
>> +#include "kvm.h"
>> +#include "hw/arm_gic_internal.h"
>> +
>> +#define TYPE_KVM_ARM_GIC "kvm-arm_gic"
>
> "kvm-arm-gic"?

I was trying to follow arm_gic but yes, I guess it's better
to go with the recommended style (which is all-hyphens, right?)

>> +#define KVM_ARM_GIC(obj) \
>> +     OBJECT_CHECK(gic_state, (obj), TYPE_KVM_ARM_GIC)
>> +#define KVM_ARM_GIC_CLASS(klass) \
>> +     OBJECT_CLASS_CHECK(KVMARMGICClass, (klass), TYPE_KVM_ARM_GIC)
>> +#define KVM_ARM_GIC_GET_CLASS(obj) \
>> +     OBJECT_GET_CLASS(KVMARMGICClass, (obj), TYPE_KVM_ARM_GIC)
>> +
>> +typedef struct KVMARMGICClass {
>> +    ARMGICCommonClass parent_class;
>> +    int (*parent_init)(SysBusDevice *dev);
>> +    void (*parent_reset)(DeviceState *dev);
>> +} KVMARMGICClass;
>> +
>> +static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
>> +{
>> +    /* Meaning of the 'irq' parameter:
>> +     *  [0..N-1] : external interrupts
>> +     *  [N..N+31] : PPI (internal) interrupts for CPU 0
>> +     *  [N+32..N+63] : PPI (internal interrupts for CPU 1
>> +     *  ...
>> +     * Convert this to the kernel's desired encoding, which
>> +     * has separate fields in the irq number for type,
>> +     * CPU number and interrupt number.
>> +     */
>> +    gic_state *s = (gic_state *)opaque;
>
> You don't happen to have time to clean up gic_state -> GICState before
> spreading its use? ;)

I can submit a patch if you like...

> [...]
>> +static TypeInfo arm_gic_info = {
>
> static const

Yep.

>> +    .name = TYPE_KVM_ARM_GIC,
>> +    .parent = TYPE_ARM_GIC_COMMON,
>> +    .instance_size = sizeof(gic_state),
>> +    .class_init = kvm_arm_gic_class_init,
>> +    .class_size = sizeof(KVMARMGICClass),
>> +};
>> +
>> +static void arm_gic_register_types(void)
>
> kvm_arm_gic_register_types?

Oops, yes, cut-n-pasto.

-- PMM

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

* Re: [Qemu-devel] [RFC v2 2/6] ARM: KVM: Add support for KVM on ARM architecture
  2012-10-10 15:07   ` [Qemu-devel] " Peter Maydell
@ 2012-10-13  9:09     ` Blue Swirl
  -1 siblings, 0 replies; 30+ messages in thread
From: Blue Swirl @ 2012-10-13  9:09 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-devel, kvmarm, kvm, patches

On Wed, Oct 10, 2012 at 3:07 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
> From: Christoffer Dall <cdall@cs.columbia.edu>
>
> Add basic support for KVM on ARM architecture.
>
> Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> [PMM: Minor tweaks and code cleanup, switch to ONE_REG]
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  hw/arm_pic.c             |   28 ++++
>  target-arm/Makefile.objs |    1 +
>  target-arm/cpu.h         |    1 +
>  target-arm/helper.c      |    2 +-
>  target-arm/kvm.c         |  328 ++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 359 insertions(+), 1 deletion(-)
>  create mode 100644 target-arm/kvm.c
>
> diff --git a/hw/arm_pic.c b/hw/arm_pic.c
> index ffb4d41..72272dc 100644
> --- a/hw/arm_pic.c
> +++ b/hw/arm_pic.c
> @@ -9,6 +9,7 @@
>
>  #include "hw.h"
>  #include "arm-misc.h"
> +#include "kvm.h"
>
>  /* Input 0 is IRQ and input 1 is FIQ.  */
>  static void arm_pic_cpu_handler(void *opaque, int irq, int level)
> @@ -34,7 +35,34 @@ static void arm_pic_cpu_handler(void *opaque, int irq, int level)
>      }
>  }
>
> +#ifdef CONFIG_KVM
> +static void kvm_arm_pic_cpu_handler(void *opaque, int irq, int level)
> +{
> +    ARMCPU *cpu = opaque;
> +    CPUARMState *env = &cpu->env;
> +    int kvm_irq = KVM_ARM_IRQ_TYPE_CPU << KVM_ARM_IRQ_TYPE_SHIFT;
> +
> +    switch (irq) {
> +    case ARM_PIC_CPU_IRQ:
> +        kvm_irq |= KVM_ARM_IRQ_CPU_IRQ;
> +        break;
> +    case ARM_PIC_CPU_FIQ:
> +        kvm_irq |= KVM_ARM_IRQ_CPU_FIQ;
> +        break;
> +    default:
> +        hw_error("kvm_arm_pic_cpu_handler: Bad interrupt line %d\n", irq);
> +    }
> +    kvm_irq |= env->cpu_index << KVM_ARM_IRQ_VCPU_SHIFT;
> +    kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0);
> +}
> +#endif
> +
>  qemu_irq *arm_pic_init_cpu(ARMCPU *cpu)
>  {
> +#ifdef CONFIG_KVM
> +    if (kvm_enabled()) {
> +        return qemu_allocate_irqs(kvm_arm_pic_cpu_handler, cpu, 2);
> +    }
> +#endif
>      return qemu_allocate_irqs(arm_pic_cpu_handler, cpu, 2);
>  }
> diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs
> index b6f1a9e..d89b57c 100644
> --- a/target-arm/Makefile.objs
> +++ b/target-arm/Makefile.objs
> @@ -1,4 +1,5 @@
>  obj-y += arm-semi.o
>  obj-$(CONFIG_SOFTMMU) += machine.o
> +obj-$(CONFIG_KVM) += kvm.o
>  obj-y += translate.o op_helper.o helper.o cpu.o
>  obj-y += neon_helper.o iwmmxt_helper.o
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index ff4de10..8c7e574 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -236,6 +236,7 @@ ARMCPU *cpu_arm_init(const char *cpu_model);
>  void arm_translate_init(void);
>  int cpu_arm_exec(CPUARMState *s);
>  void do_interrupt(CPUARMState *);
> +int bank_number(CPUARMState *env, int mode);
>  void switch_mode(CPUARMState *, int);
>  uint32_t do_arm_semihosting(CPUARMState *env);
>
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 58340bd..f62f3da 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -1619,7 +1619,7 @@ uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode)
>  #else
>
>  /* Map CPU modes onto saved register banks.  */
> -static inline int bank_number(CPUARMState *env, int mode)
> +int bank_number(CPUARMState *env, int mode)
>  {
>      switch (mode) {
>      case ARM_CPU_MODE_USR:
> diff --git a/target-arm/kvm.c b/target-arm/kvm.c
> new file mode 100644
> index 0000000..fee60e1
> --- /dev/null
> +++ b/target-arm/kvm.c
> @@ -0,0 +1,328 @@
> +/*
> + * ARM implementation of KVM hooks
> + *
> + * Copyright Christoffer Dall 2009-2010
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + *
> + */
> +
> +#include <stdio.h>
> +#include <sys/types.h>
> +#include <sys/ioctl.h>
> +#include <sys/mman.h>
> +
> +#include <linux/kvm.h>
> +
> +#include "qemu-common.h"
> +#include "qemu-timer.h"
> +#include "sysemu.h"
> +#include "kvm.h"
> +#include "cpu.h"
> +#include "device_tree.h"

Is this used?

> +#include "hw/arm-misc.h"
> +
> +const KVMCapabilityInfo kvm_arch_required_capabilities[] = {

'static'. In fact, 'static' not used at all in this file, probably it
could be used a lot more.

> +    KVM_CAP_LAST_INFO
> +};
> +
> +int kvm_arch_init(KVMState *s)
> +{
> +    /* For ARM interrupt delivery is always asynchronous,
> +     * whether we are using an in-kernel VGIC or not.
> +     */
> +    kvm_async_interrupts_allowed = true;
> +    return 0;
> +}
> +
> +int kvm_arch_init_vcpu(CPUARMState *env)
> +{
> +    struct kvm_vcpu_init init;
> +
> +    init.target = KVM_ARM_TARGET_CORTEX_A15;
> +    memset(init.features, 0, sizeof(init.features));
> +    return kvm_vcpu_ioctl(env, KVM_ARM_VCPU_INIT, &init);
> +}
> +
> +struct reg {

Reg or other CamelCase version and a typedef, please.

> +    uint64_t id;
> +    int offset;
> +};
> +
> +#define COREREG(KERNELNAME, QEMUFIELD)                       \
> +    {                                                        \
> +        KVM_REG_ARM | KVM_REG_SIZE_U32 |                     \
> +        KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(KERNELNAME), \
> +        offsetof(CPUARMState, QEMUFIELD)                     \
> +    }
> +
> +#define CP15REG(CRN, CRM, OPC1, OPC2, QEMUFIELD) \
> +    {                                            \
> +        KVM_REG_ARM | KVM_REG_SIZE_U32 |         \
> +        (15 << KVM_REG_ARM_COPROC_SHIFT) |       \
> +        ((CRN) << KVM_REG_ARM_32_CRN_SHIFT) |    \
> +        ((CRM) << KVM_REG_ARM_CRM_SHIFT) |       \
> +        ((OPC1) << KVM_REG_ARM_OPC1_SHIFT) |     \
> +        ((OPC2) << KVM_REG_ARM_32_OPC2_SHIFT),   \
> +        offsetof(CPUARMState, QEMUFIELD)         \
> +    }
> +
> +const struct reg regs[] = {
> +    /* R0_usr .. R14_usr */
> +    COREREG(usr_regs[0], regs[0]),
> +    COREREG(usr_regs[1], regs[1]),
> +    COREREG(usr_regs[2], regs[2]),
> +    COREREG(usr_regs[3], regs[3]),
> +    COREREG(usr_regs[4], regs[4]),
> +    COREREG(usr_regs[5], regs[5]),
> +    COREREG(usr_regs[6], regs[6]),
> +    COREREG(usr_regs[7], regs[7]),
> +    COREREG(usr_regs[8], usr_regs[0]),
> +    COREREG(usr_regs[9], usr_regs[1]),
> +    COREREG(usr_regs[10], usr_regs[2]),
> +    COREREG(usr_regs[11], usr_regs[3]),
> +    COREREG(usr_regs[12], usr_regs[4]),
> +    COREREG(usr_regs[13], banked_r13[0]),
> +    COREREG(usr_regs[14], banked_r14[0]),
> +    /* R13, R14, SPSR for SVC, ABT, UND, IRQ banks */
> +    COREREG(svc_regs[0], banked_r13[1]),
> +    COREREG(svc_regs[1], banked_r14[1]),
> +    COREREG(svc_regs[2], banked_spsr[1]),
> +    COREREG(abt_regs[0], banked_r13[2]),
> +    COREREG(abt_regs[1], banked_r14[2]),
> +    COREREG(abt_regs[2], banked_spsr[2]),
> +    COREREG(und_regs[0], banked_r13[3]),
> +    COREREG(und_regs[1], banked_r14[3]),
> +    COREREG(und_regs[2], banked_spsr[3]),
> +    COREREG(irq_regs[0], banked_r13[4]),
> +    COREREG(irq_regs[1], banked_r14[4]),
> +    COREREG(irq_regs[2], banked_spsr[4]),
> +    /* R8_fiq .. R14_fiq and SPSR_fiq */
> +    COREREG(fiq_regs[0], fiq_regs[0]),
> +    COREREG(fiq_regs[1], fiq_regs[1]),
> +    COREREG(fiq_regs[2], fiq_regs[2]),
> +    COREREG(fiq_regs[3], fiq_regs[3]),
> +    COREREG(fiq_regs[4], fiq_regs[4]),
> +    COREREG(fiq_regs[0], banked_r13[5]),
> +    COREREG(fiq_regs[1], banked_r14[5]),
> +    COREREG(fiq_regs[2], banked_spsr[5]),
> +    /* R15 */
> +    COREREG(pc, regs[15]),
> +    /* A non-comprehensive set of cp15 registers.
> +     * TODO: drive this from the cp_regs hashtable instead.
> +     */
> +    CP15REG(1, 0, 0, 0, cp15.c1_sys), /* SCTLR */
> +    CP15REG(2, 0, 0, 2, cp15.c2_control), /* TTBCR */
> +    CP15REG(3, 0, 0, 0, cp15.c3), /* DACR */
> +};
> +
> +int kvm_arch_put_registers(CPUARMState *env, int level)
> +{
> +    struct kvm_one_reg r;
> +    int mode, bn;
> +    int ret, i;
> +    uint32_t cpsr;
> +    uint64_t ttbr;
> +
> +    /* Make sure the banked regs are properly set */
> +    mode = env->uncached_cpsr & CPSR_M;
> +    bn = bank_number(env, mode);
> +    if (mode == ARM_CPU_MODE_FIQ) {
> +        memcpy(env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t));
> +    } else {
> +        memcpy(env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t));
> +    }
> +    env->banked_r13[bn] = env->regs[13];
> +    env->banked_r14[bn] = env->regs[14];
> +    env->banked_spsr[bn] = env->spsr;
> +
> +    /* Now we can safely copy stuff down to the kernel */
> +    for (i = 0; i < ARRAY_SIZE(regs); i++) {
> +        r.id = regs[i].id;
> +        r.addr = (uintptr_t)(env) + regs[i].offset;
> +        ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
> +        if (ret) {
> +            return ret;
> +        }
> +    }
> +
> +    /* Special cases which aren't a single CPUARMState field */
> +    cpsr = cpsr_read(env);
> +    r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 |
> +        KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(cpsr);
> +    r.addr = (uintptr_t)(&cpsr);
> +    ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
> +    if (ret) {
> +        return ret;
> +    }
> +
> +    /* TTBR0: cp15 crm=2 opc1=0 */
> +    ttbr = ((uint64_t)env->cp15.c2_base0_hi << 32) | env->cp15.c2_base0;
> +    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
> +        (2 << KVM_REG_ARM_CRM_SHIFT) | (0 << KVM_REG_ARM_OPC1_SHIFT);
> +    r.addr = (uintptr_t)(&ttbr);
> +    ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
> +    if (ret) {
> +        return ret;
> +    }
> +
> +    /* TTBR1: cp15 crm=2 opc1=1 */
> +    ttbr = ((uint64_t)env->cp15.c2_base1_hi << 32) | env->cp15.c2_base1;
> +    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
> +        (2 << KVM_REG_ARM_CRM_SHIFT) | (1 << KVM_REG_ARM_OPC1_SHIFT);
> +    r.addr = (uintptr_t)(&ttbr);
> +    ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
> +
> +    return ret;
> +}
> +
> +int kvm_arch_get_registers(CPUARMState *env)
> +{
> +    struct kvm_one_reg r;
> +    int mode, bn;
> +    int ret, i;
> +    uint32_t cpsr;
> +    uint64_t ttbr;
> +
> +    for (i = 0; i < ARRAY_SIZE(regs); i++) {
> +        r.id = regs[i].id;
> +        r.addr = (uintptr_t)(env) + regs[i].offset;
> +        ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
> +        if (ret) {
> +            return ret;
> +        }
> +    }
> +
> +    /* Special cases which aren't a single CPUARMState field */
> +    r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 |
> +        KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(cpsr);
> +    r.addr = (uintptr_t)(&cpsr);
> +    ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
> +    if (ret) {
> +        return ret;
> +    }
> +    cpsr_write(env, cpsr, 0xffffffff);
> +
> +    /* TTBR0: cp15 crm=2 opc1=0 */
> +    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
> +        (2 << KVM_REG_ARM_CRM_SHIFT) | (0 << KVM_REG_ARM_OPC1_SHIFT);
> +    r.addr = (uintptr_t)(&ttbr);
> +    ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
> +    if (ret) {
> +        return ret;
> +    }
> +    env->cp15.c2_base0_hi = ttbr >> 32;
> +    env->cp15.c2_base0 = ttbr;
> +
> +    /* TTBR1: cp15 crm=2 opc1=1 */
> +    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
> +        (2 << KVM_REG_ARM_CRM_SHIFT) | (1 << KVM_REG_ARM_OPC1_SHIFT);
> +    r.addr = (uintptr_t)(&ttbr);
> +    ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
> +    if (ret) {
> +        return ret;
> +    }
> +    env->cp15.c2_base1_hi = ttbr >> 32;
> +    env->cp15.c2_base1 = ttbr;
> +
> +    /* Make sure the current mode regs are properly set */
> +    mode = env->uncached_cpsr & CPSR_M;
> +    bn = bank_number(env, mode);
> +    if (mode == ARM_CPU_MODE_FIQ) {
> +        memcpy(env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t));
> +    } else {
> +        memcpy(env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t));
> +    }
> +    env->regs[13] = env->banked_r13[bn];
> +    env->regs[14] = env->banked_r14[bn];
> +    env->spsr = env->banked_spsr[bn];
> +
> +    /* The main GET_ONE_REG loop above set c2_control, but we need to
> +     * update some extra cached precomputed values too.
> +     * When this is driven from the cp_regs hashtable then this ugliness
> +     * can disappear because we'll use the access function which sets
> +     * these values automatically.
> +     */
> +    env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> env->cp15.c2_control);
> +    env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> env->cp15.c2_control);

The casts don't look useful.

> +
> +    return 0;
> +}
> +
> +void kvm_arch_pre_run(CPUARMState *env, struct kvm_run *run)
> +{
> +}
> +
> +void kvm_arch_post_run(CPUARMState *env, struct kvm_run *run)
> +{
> +}
> +
> +int kvm_arch_handle_exit(CPUARMState *env, struct kvm_run *run)
> +{
> +    int ret = 0;
> +
> +    return ret;
> +}
> +
> +void kvm_arch_reset_vcpu(CPUARMState *env)
> +{
> +}
> +
> +bool kvm_arch_stop_on_emulation_error(CPUARMState *env)
> +{
> +    return true;
> +}
> +
> +int kvm_arch_process_async_events(CPUARMState *env)
> +{
> +    return 0;
> +}
> +
> +int kvm_arch_on_sigbus_vcpu(CPUARMState *env, int code, void *addr)
> +{
> +    return 1;
> +}
> +
> +int kvm_arch_on_sigbus(int code, void *addr)
> +{
> +    return 1;
> +}
> +
> +void kvm_arch_update_guest_debug(CPUARMState *env, struct kvm_guest_debug *dbg)
> +{
> +    fprintf(stderr, "%s: not implemented\n", __func__);

Please use qemu_log_mask(LOG_UNIMP, ...) instead.

> +}
> +
> +int kvm_arch_insert_sw_breakpoint(CPUARMState *env,
> +                                  struct kvm_sw_breakpoint *bp)
> +{
> +    fprintf(stderr, "%s: not implemented\n", __func__);
> +    return -EINVAL;
> +}
> +
> +int kvm_arch_insert_hw_breakpoint(target_ulong addr,
> +                                  target_ulong len, int type)
> +{
> +    fprintf(stderr, "%s: not implemented\n", __func__);
> +    return -EINVAL;
> +}
> +
> +int kvm_arch_remove_hw_breakpoint(target_ulong addr,
> +                                  target_ulong len, int type)
> +{
> +    fprintf(stderr, "%s: not implemented\n", __func__);
> +    return -EINVAL;
> +}
> +
> +int kvm_arch_remove_sw_breakpoint(CPUARMState *env,
> +                                  struct kvm_sw_breakpoint *bp)
> +{
> +    fprintf(stderr, "%s: not implemented\n", __func__);
> +    return -EINVAL;
> +}
> +
> +void kvm_arch_remove_all_hw_breakpoints(void)
> +{
> +    fprintf(stderr, "%s: not implemented\n", __func__);
> +}
> --
> 1.7.9.5
>
>

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

* Re: [Qemu-devel] [RFC v2 2/6] ARM: KVM: Add support for KVM on ARM architecture
@ 2012-10-13  9:09     ` Blue Swirl
  0 siblings, 0 replies; 30+ messages in thread
From: Blue Swirl @ 2012-10-13  9:09 UTC (permalink / raw)
  To: Peter Maydell; +Cc: patches, qemu-devel, kvm, kvmarm

On Wed, Oct 10, 2012 at 3:07 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
> From: Christoffer Dall <cdall@cs.columbia.edu>
>
> Add basic support for KVM on ARM architecture.
>
> Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> [PMM: Minor tweaks and code cleanup, switch to ONE_REG]
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  hw/arm_pic.c             |   28 ++++
>  target-arm/Makefile.objs |    1 +
>  target-arm/cpu.h         |    1 +
>  target-arm/helper.c      |    2 +-
>  target-arm/kvm.c         |  328 ++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 359 insertions(+), 1 deletion(-)
>  create mode 100644 target-arm/kvm.c
>
> diff --git a/hw/arm_pic.c b/hw/arm_pic.c
> index ffb4d41..72272dc 100644
> --- a/hw/arm_pic.c
> +++ b/hw/arm_pic.c
> @@ -9,6 +9,7 @@
>
>  #include "hw.h"
>  #include "arm-misc.h"
> +#include "kvm.h"
>
>  /* Input 0 is IRQ and input 1 is FIQ.  */
>  static void arm_pic_cpu_handler(void *opaque, int irq, int level)
> @@ -34,7 +35,34 @@ static void arm_pic_cpu_handler(void *opaque, int irq, int level)
>      }
>  }
>
> +#ifdef CONFIG_KVM
> +static void kvm_arm_pic_cpu_handler(void *opaque, int irq, int level)
> +{
> +    ARMCPU *cpu = opaque;
> +    CPUARMState *env = &cpu->env;
> +    int kvm_irq = KVM_ARM_IRQ_TYPE_CPU << KVM_ARM_IRQ_TYPE_SHIFT;
> +
> +    switch (irq) {
> +    case ARM_PIC_CPU_IRQ:
> +        kvm_irq |= KVM_ARM_IRQ_CPU_IRQ;
> +        break;
> +    case ARM_PIC_CPU_FIQ:
> +        kvm_irq |= KVM_ARM_IRQ_CPU_FIQ;
> +        break;
> +    default:
> +        hw_error("kvm_arm_pic_cpu_handler: Bad interrupt line %d\n", irq);
> +    }
> +    kvm_irq |= env->cpu_index << KVM_ARM_IRQ_VCPU_SHIFT;
> +    kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0);
> +}
> +#endif
> +
>  qemu_irq *arm_pic_init_cpu(ARMCPU *cpu)
>  {
> +#ifdef CONFIG_KVM
> +    if (kvm_enabled()) {
> +        return qemu_allocate_irqs(kvm_arm_pic_cpu_handler, cpu, 2);
> +    }
> +#endif
>      return qemu_allocate_irqs(arm_pic_cpu_handler, cpu, 2);
>  }
> diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs
> index b6f1a9e..d89b57c 100644
> --- a/target-arm/Makefile.objs
> +++ b/target-arm/Makefile.objs
> @@ -1,4 +1,5 @@
>  obj-y += arm-semi.o
>  obj-$(CONFIG_SOFTMMU) += machine.o
> +obj-$(CONFIG_KVM) += kvm.o
>  obj-y += translate.o op_helper.o helper.o cpu.o
>  obj-y += neon_helper.o iwmmxt_helper.o
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index ff4de10..8c7e574 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -236,6 +236,7 @@ ARMCPU *cpu_arm_init(const char *cpu_model);
>  void arm_translate_init(void);
>  int cpu_arm_exec(CPUARMState *s);
>  void do_interrupt(CPUARMState *);
> +int bank_number(CPUARMState *env, int mode);
>  void switch_mode(CPUARMState *, int);
>  uint32_t do_arm_semihosting(CPUARMState *env);
>
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 58340bd..f62f3da 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -1619,7 +1619,7 @@ uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode)
>  #else
>
>  /* Map CPU modes onto saved register banks.  */
> -static inline int bank_number(CPUARMState *env, int mode)
> +int bank_number(CPUARMState *env, int mode)
>  {
>      switch (mode) {
>      case ARM_CPU_MODE_USR:
> diff --git a/target-arm/kvm.c b/target-arm/kvm.c
> new file mode 100644
> index 0000000..fee60e1
> --- /dev/null
> +++ b/target-arm/kvm.c
> @@ -0,0 +1,328 @@
> +/*
> + * ARM implementation of KVM hooks
> + *
> + * Copyright Christoffer Dall 2009-2010
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + *
> + */
> +
> +#include <stdio.h>
> +#include <sys/types.h>
> +#include <sys/ioctl.h>
> +#include <sys/mman.h>
> +
> +#include <linux/kvm.h>
> +
> +#include "qemu-common.h"
> +#include "qemu-timer.h"
> +#include "sysemu.h"
> +#include "kvm.h"
> +#include "cpu.h"
> +#include "device_tree.h"

Is this used?

> +#include "hw/arm-misc.h"
> +
> +const KVMCapabilityInfo kvm_arch_required_capabilities[] = {

'static'. In fact, 'static' not used at all in this file, probably it
could be used a lot more.

> +    KVM_CAP_LAST_INFO
> +};
> +
> +int kvm_arch_init(KVMState *s)
> +{
> +    /* For ARM interrupt delivery is always asynchronous,
> +     * whether we are using an in-kernel VGIC or not.
> +     */
> +    kvm_async_interrupts_allowed = true;
> +    return 0;
> +}
> +
> +int kvm_arch_init_vcpu(CPUARMState *env)
> +{
> +    struct kvm_vcpu_init init;
> +
> +    init.target = KVM_ARM_TARGET_CORTEX_A15;
> +    memset(init.features, 0, sizeof(init.features));
> +    return kvm_vcpu_ioctl(env, KVM_ARM_VCPU_INIT, &init);
> +}
> +
> +struct reg {

Reg or other CamelCase version and a typedef, please.

> +    uint64_t id;
> +    int offset;
> +};
> +
> +#define COREREG(KERNELNAME, QEMUFIELD)                       \
> +    {                                                        \
> +        KVM_REG_ARM | KVM_REG_SIZE_U32 |                     \
> +        KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(KERNELNAME), \
> +        offsetof(CPUARMState, QEMUFIELD)                     \
> +    }
> +
> +#define CP15REG(CRN, CRM, OPC1, OPC2, QEMUFIELD) \
> +    {                                            \
> +        KVM_REG_ARM | KVM_REG_SIZE_U32 |         \
> +        (15 << KVM_REG_ARM_COPROC_SHIFT) |       \
> +        ((CRN) << KVM_REG_ARM_32_CRN_SHIFT) |    \
> +        ((CRM) << KVM_REG_ARM_CRM_SHIFT) |       \
> +        ((OPC1) << KVM_REG_ARM_OPC1_SHIFT) |     \
> +        ((OPC2) << KVM_REG_ARM_32_OPC2_SHIFT),   \
> +        offsetof(CPUARMState, QEMUFIELD)         \
> +    }
> +
> +const struct reg regs[] = {
> +    /* R0_usr .. R14_usr */
> +    COREREG(usr_regs[0], regs[0]),
> +    COREREG(usr_regs[1], regs[1]),
> +    COREREG(usr_regs[2], regs[2]),
> +    COREREG(usr_regs[3], regs[3]),
> +    COREREG(usr_regs[4], regs[4]),
> +    COREREG(usr_regs[5], regs[5]),
> +    COREREG(usr_regs[6], regs[6]),
> +    COREREG(usr_regs[7], regs[7]),
> +    COREREG(usr_regs[8], usr_regs[0]),
> +    COREREG(usr_regs[9], usr_regs[1]),
> +    COREREG(usr_regs[10], usr_regs[2]),
> +    COREREG(usr_regs[11], usr_regs[3]),
> +    COREREG(usr_regs[12], usr_regs[4]),
> +    COREREG(usr_regs[13], banked_r13[0]),
> +    COREREG(usr_regs[14], banked_r14[0]),
> +    /* R13, R14, SPSR for SVC, ABT, UND, IRQ banks */
> +    COREREG(svc_regs[0], banked_r13[1]),
> +    COREREG(svc_regs[1], banked_r14[1]),
> +    COREREG(svc_regs[2], banked_spsr[1]),
> +    COREREG(abt_regs[0], banked_r13[2]),
> +    COREREG(abt_regs[1], banked_r14[2]),
> +    COREREG(abt_regs[2], banked_spsr[2]),
> +    COREREG(und_regs[0], banked_r13[3]),
> +    COREREG(und_regs[1], banked_r14[3]),
> +    COREREG(und_regs[2], banked_spsr[3]),
> +    COREREG(irq_regs[0], banked_r13[4]),
> +    COREREG(irq_regs[1], banked_r14[4]),
> +    COREREG(irq_regs[2], banked_spsr[4]),
> +    /* R8_fiq .. R14_fiq and SPSR_fiq */
> +    COREREG(fiq_regs[0], fiq_regs[0]),
> +    COREREG(fiq_regs[1], fiq_regs[1]),
> +    COREREG(fiq_regs[2], fiq_regs[2]),
> +    COREREG(fiq_regs[3], fiq_regs[3]),
> +    COREREG(fiq_regs[4], fiq_regs[4]),
> +    COREREG(fiq_regs[0], banked_r13[5]),
> +    COREREG(fiq_regs[1], banked_r14[5]),
> +    COREREG(fiq_regs[2], banked_spsr[5]),
> +    /* R15 */
> +    COREREG(pc, regs[15]),
> +    /* A non-comprehensive set of cp15 registers.
> +     * TODO: drive this from the cp_regs hashtable instead.
> +     */
> +    CP15REG(1, 0, 0, 0, cp15.c1_sys), /* SCTLR */
> +    CP15REG(2, 0, 0, 2, cp15.c2_control), /* TTBCR */
> +    CP15REG(3, 0, 0, 0, cp15.c3), /* DACR */
> +};
> +
> +int kvm_arch_put_registers(CPUARMState *env, int level)
> +{
> +    struct kvm_one_reg r;
> +    int mode, bn;
> +    int ret, i;
> +    uint32_t cpsr;
> +    uint64_t ttbr;
> +
> +    /* Make sure the banked regs are properly set */
> +    mode = env->uncached_cpsr & CPSR_M;
> +    bn = bank_number(env, mode);
> +    if (mode == ARM_CPU_MODE_FIQ) {
> +        memcpy(env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t));
> +    } else {
> +        memcpy(env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t));
> +    }
> +    env->banked_r13[bn] = env->regs[13];
> +    env->banked_r14[bn] = env->regs[14];
> +    env->banked_spsr[bn] = env->spsr;
> +
> +    /* Now we can safely copy stuff down to the kernel */
> +    for (i = 0; i < ARRAY_SIZE(regs); i++) {
> +        r.id = regs[i].id;
> +        r.addr = (uintptr_t)(env) + regs[i].offset;
> +        ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
> +        if (ret) {
> +            return ret;
> +        }
> +    }
> +
> +    /* Special cases which aren't a single CPUARMState field */
> +    cpsr = cpsr_read(env);
> +    r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 |
> +        KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(cpsr);
> +    r.addr = (uintptr_t)(&cpsr);
> +    ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
> +    if (ret) {
> +        return ret;
> +    }
> +
> +    /* TTBR0: cp15 crm=2 opc1=0 */
> +    ttbr = ((uint64_t)env->cp15.c2_base0_hi << 32) | env->cp15.c2_base0;
> +    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
> +        (2 << KVM_REG_ARM_CRM_SHIFT) | (0 << KVM_REG_ARM_OPC1_SHIFT);
> +    r.addr = (uintptr_t)(&ttbr);
> +    ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
> +    if (ret) {
> +        return ret;
> +    }
> +
> +    /* TTBR1: cp15 crm=2 opc1=1 */
> +    ttbr = ((uint64_t)env->cp15.c2_base1_hi << 32) | env->cp15.c2_base1;
> +    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
> +        (2 << KVM_REG_ARM_CRM_SHIFT) | (1 << KVM_REG_ARM_OPC1_SHIFT);
> +    r.addr = (uintptr_t)(&ttbr);
> +    ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &r);
> +
> +    return ret;
> +}
> +
> +int kvm_arch_get_registers(CPUARMState *env)
> +{
> +    struct kvm_one_reg r;
> +    int mode, bn;
> +    int ret, i;
> +    uint32_t cpsr;
> +    uint64_t ttbr;
> +
> +    for (i = 0; i < ARRAY_SIZE(regs); i++) {
> +        r.id = regs[i].id;
> +        r.addr = (uintptr_t)(env) + regs[i].offset;
> +        ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
> +        if (ret) {
> +            return ret;
> +        }
> +    }
> +
> +    /* Special cases which aren't a single CPUARMState field */
> +    r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 |
> +        KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(cpsr);
> +    r.addr = (uintptr_t)(&cpsr);
> +    ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
> +    if (ret) {
> +        return ret;
> +    }
> +    cpsr_write(env, cpsr, 0xffffffff);
> +
> +    /* TTBR0: cp15 crm=2 opc1=0 */
> +    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
> +        (2 << KVM_REG_ARM_CRM_SHIFT) | (0 << KVM_REG_ARM_OPC1_SHIFT);
> +    r.addr = (uintptr_t)(&ttbr);
> +    ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
> +    if (ret) {
> +        return ret;
> +    }
> +    env->cp15.c2_base0_hi = ttbr >> 32;
> +    env->cp15.c2_base0 = ttbr;
> +
> +    /* TTBR1: cp15 crm=2 opc1=1 */
> +    r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
> +        (2 << KVM_REG_ARM_CRM_SHIFT) | (1 << KVM_REG_ARM_OPC1_SHIFT);
> +    r.addr = (uintptr_t)(&ttbr);
> +    ret = kvm_vcpu_ioctl(env, KVM_GET_ONE_REG, &r);
> +    if (ret) {
> +        return ret;
> +    }
> +    env->cp15.c2_base1_hi = ttbr >> 32;
> +    env->cp15.c2_base1 = ttbr;
> +
> +    /* Make sure the current mode regs are properly set */
> +    mode = env->uncached_cpsr & CPSR_M;
> +    bn = bank_number(env, mode);
> +    if (mode == ARM_CPU_MODE_FIQ) {
> +        memcpy(env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t));
> +    } else {
> +        memcpy(env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t));
> +    }
> +    env->regs[13] = env->banked_r13[bn];
> +    env->regs[14] = env->banked_r14[bn];
> +    env->spsr = env->banked_spsr[bn];
> +
> +    /* The main GET_ONE_REG loop above set c2_control, but we need to
> +     * update some extra cached precomputed values too.
> +     * When this is driven from the cp_regs hashtable then this ugliness
> +     * can disappear because we'll use the access function which sets
> +     * these values automatically.
> +     */
> +    env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> env->cp15.c2_control);
> +    env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> env->cp15.c2_control);

The casts don't look useful.

> +
> +    return 0;
> +}
> +
> +void kvm_arch_pre_run(CPUARMState *env, struct kvm_run *run)
> +{
> +}
> +
> +void kvm_arch_post_run(CPUARMState *env, struct kvm_run *run)
> +{
> +}
> +
> +int kvm_arch_handle_exit(CPUARMState *env, struct kvm_run *run)
> +{
> +    int ret = 0;
> +
> +    return ret;
> +}
> +
> +void kvm_arch_reset_vcpu(CPUARMState *env)
> +{
> +}
> +
> +bool kvm_arch_stop_on_emulation_error(CPUARMState *env)
> +{
> +    return true;
> +}
> +
> +int kvm_arch_process_async_events(CPUARMState *env)
> +{
> +    return 0;
> +}
> +
> +int kvm_arch_on_sigbus_vcpu(CPUARMState *env, int code, void *addr)
> +{
> +    return 1;
> +}
> +
> +int kvm_arch_on_sigbus(int code, void *addr)
> +{
> +    return 1;
> +}
> +
> +void kvm_arch_update_guest_debug(CPUARMState *env, struct kvm_guest_debug *dbg)
> +{
> +    fprintf(stderr, "%s: not implemented\n", __func__);

Please use qemu_log_mask(LOG_UNIMP, ...) instead.

> +}
> +
> +int kvm_arch_insert_sw_breakpoint(CPUARMState *env,
> +                                  struct kvm_sw_breakpoint *bp)
> +{
> +    fprintf(stderr, "%s: not implemented\n", __func__);
> +    return -EINVAL;
> +}
> +
> +int kvm_arch_insert_hw_breakpoint(target_ulong addr,
> +                                  target_ulong len, int type)
> +{
> +    fprintf(stderr, "%s: not implemented\n", __func__);
> +    return -EINVAL;
> +}
> +
> +int kvm_arch_remove_hw_breakpoint(target_ulong addr,
> +                                  target_ulong len, int type)
> +{
> +    fprintf(stderr, "%s: not implemented\n", __func__);
> +    return -EINVAL;
> +}
> +
> +int kvm_arch_remove_sw_breakpoint(CPUARMState *env,
> +                                  struct kvm_sw_breakpoint *bp)
> +{
> +    fprintf(stderr, "%s: not implemented\n", __func__);
> +    return -EINVAL;
> +}
> +
> +void kvm_arch_remove_all_hw_breakpoints(void)
> +{
> +    fprintf(stderr, "%s: not implemented\n", __func__);
> +}
> --
> 1.7.9.5
>
>

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

* Re: [Qemu-devel] [RFC v2 2/6] ARM: KVM: Add support for KVM on ARM architecture
  2012-10-13  9:09     ` Blue Swirl
@ 2012-10-13 19:19       ` Peter Maydell
  -1 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-13 19:19 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel, kvmarm, kvm, patches

On 13 October 2012 10:09, Blue Swirl <blauwirbel@gmail.com> wrote:
> On Wed, Oct 10, 2012 at 3:07 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> From: Christoffer Dall <cdall@cs.columbia.edu>
>>
>> Add basic support for KVM on ARM architecture.
>> +#include "device_tree.h"
>
> Is this used?

Don't think so, will remove.

>> +#include "hw/arm-misc.h"
>> +
>> +const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
>
> 'static'. In fact, 'static' not used at all in this file, probably it
> could be used a lot more.

Agreed.

>> +struct reg {
>
> Reg or other CamelCase version and a typedef, please.

OK.

>> +    env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> env->cp15.c2_control);
>> +    env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> env->cp15.c2_control);
>
> The casts don't look useful.

This is just a copy of the equivalent lines in target-arm/helper.c's
vmsa_ttbcr_write() function, which also have the casts... I agree
they don't look like they're actually doing anything useful though.

>> +void kvm_arch_update_guest_debug(CPUARMState *env, struct kvm_guest_debug *dbg)
>> +{
>> +    fprintf(stderr, "%s: not implemented\n", __func__);
>
> Please use qemu_log_mask(LOG_UNIMP, ...) instead.

Happy to -- hadn't noticed that had made it in. (There are a bunch
of similar printfs in various bits of ARM code I should probably
update to use that...)

-- PMM

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

* Re: [Qemu-devel] [RFC v2 2/6] ARM: KVM: Add support for KVM on ARM architecture
@ 2012-10-13 19:19       ` Peter Maydell
  0 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-13 19:19 UTC (permalink / raw)
  To: Blue Swirl; +Cc: patches, qemu-devel, kvm, kvmarm

On 13 October 2012 10:09, Blue Swirl <blauwirbel@gmail.com> wrote:
> On Wed, Oct 10, 2012 at 3:07 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> From: Christoffer Dall <cdall@cs.columbia.edu>
>>
>> Add basic support for KVM on ARM architecture.
>> +#include "device_tree.h"
>
> Is this used?

Don't think so, will remove.

>> +#include "hw/arm-misc.h"
>> +
>> +const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
>
> 'static'. In fact, 'static' not used at all in this file, probably it
> could be used a lot more.

Agreed.

>> +struct reg {
>
> Reg or other CamelCase version and a typedef, please.

OK.

>> +    env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> env->cp15.c2_control);
>> +    env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> env->cp15.c2_control);
>
> The casts don't look useful.

This is just a copy of the equivalent lines in target-arm/helper.c's
vmsa_ttbcr_write() function, which also have the casts... I agree
they don't look like they're actually doing anything useful though.

>> +void kvm_arch_update_guest_debug(CPUARMState *env, struct kvm_guest_debug *dbg)
>> +{
>> +    fprintf(stderr, "%s: not implemented\n", __func__);
>
> Please use qemu_log_mask(LOG_UNIMP, ...) instead.

Happy to -- hadn't noticed that had made it in. (There are a bunch
of similar printfs in various bits of ARM code I should probably
update to use that...)

-- PMM

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

* Re: [Qemu-devel] [RFC v2 2/6] ARM: KVM: Add support for KVM on ARM architecture
  2012-10-13  9:09     ` Blue Swirl
@ 2012-10-18 12:37       ` Peter Maydell
  -1 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-18 12:37 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel, kvmarm, kvm, patches

On 13 October 2012 10:09, Blue Swirl <blauwirbel@gmail.com> wrote:
> On Wed, Oct 10, 2012 at 3:07 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> +#include "hw/arm-misc.h"
>> +
>> +const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
>
> 'static'. In fact, 'static' not used at all in this file, probably it
> could be used a lot more.

Actually this one can't be static -- it's defined here but used in
kvm-all.c. The same applies for most of the functions in this file.
I was able to add a 'static' to the regs[] array, but I couldn't
find anywhere else here where a 'static' was missing.

-- PMM

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

* Re: [Qemu-devel] [RFC v2 2/6] ARM: KVM: Add support for KVM on ARM architecture
@ 2012-10-18 12:37       ` Peter Maydell
  0 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-18 12:37 UTC (permalink / raw)
  To: Blue Swirl; +Cc: patches, qemu-devel, kvm, kvmarm

On 13 October 2012 10:09, Blue Swirl <blauwirbel@gmail.com> wrote:
> On Wed, Oct 10, 2012 at 3:07 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> +#include "hw/arm-misc.h"
>> +
>> +const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
>
> 'static'. In fact, 'static' not used at all in this file, probably it
> could be used a lot more.

Actually this one can't be static -- it's defined here but used in
kvm-all.c. The same applies for most of the functions in this file.
I was able to add a 'static' to the regs[] array, but I couldn't
find anywhere else here where a 'static' was missing.

-- PMM

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

* Re: [RFC v2 2/6] ARM: KVM: Add support for KVM on ARM architecture
  2012-10-10 15:07   ` [Qemu-devel] " Peter Maydell
@ 2012-10-18 17:41     ` Jan Kiszka
  -1 siblings, 0 replies; 30+ messages in thread
From: Jan Kiszka @ 2012-10-18 17:41 UTC (permalink / raw)
  To: Peter Maydell; +Cc: patches, qemu-devel, kvm, kvmarm

On 2012-10-10 17:07, Peter Maydell wrote:
> From: Christoffer Dall <cdall@cs.columbia.edu>
> 
> Add basic support for KVM on ARM architecture.
> 
> Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> [PMM: Minor tweaks and code cleanup, switch to ONE_REG]
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  hw/arm_pic.c             |   28 ++++
>  target-arm/Makefile.objs |    1 +
>  target-arm/cpu.h         |    1 +
>  target-arm/helper.c      |    2 +-
>  target-arm/kvm.c         |  328 ++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 359 insertions(+), 1 deletion(-)
>  create mode 100644 target-arm/kvm.c
> 
> diff --git a/hw/arm_pic.c b/hw/arm_pic.c
> index ffb4d41..72272dc 100644
> --- a/hw/arm_pic.c
> +++ b/hw/arm_pic.c
> @@ -9,6 +9,7 @@
>  
>  #include "hw.h"
>  #include "arm-misc.h"
> +#include "kvm.h"
>  
>  /* Input 0 is IRQ and input 1 is FIQ.  */
>  static void arm_pic_cpu_handler(void *opaque, int irq, int level)
> @@ -34,7 +35,34 @@ static void arm_pic_cpu_handler(void *opaque, int irq, int level)
>      }
>  }
>  
> +#ifdef CONFIG_KVM
> +static void kvm_arm_pic_cpu_handler(void *opaque, int irq, int level)
> +{
> +    ARMCPU *cpu = opaque;
> +    CPUARMState *env = &cpu->env;
> +    int kvm_irq = KVM_ARM_IRQ_TYPE_CPU << KVM_ARM_IRQ_TYPE_SHIFT;
> +
> +    switch (irq) {
> +    case ARM_PIC_CPU_IRQ:
> +        kvm_irq |= KVM_ARM_IRQ_CPU_IRQ;
> +        break;
> +    case ARM_PIC_CPU_FIQ:
> +        kvm_irq |= KVM_ARM_IRQ_CPU_FIQ;
> +        break;
> +    default:
> +        hw_error("kvm_arm_pic_cpu_handler: Bad interrupt line %d\n", irq);
> +    }
> +    kvm_irq |= env->cpu_index << KVM_ARM_IRQ_VCPU_SHIFT;
> +    kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0);
> +}
> +#endif

Minor: If you do

function()
{
#ifdef CONFIG_KVM
...
#endif
}

> +
>  qemu_irq *arm_pic_init_cpu(ARMCPU *cpu)
>  {
> +#ifdef CONFIG_KVM
> +    if (kvm_enabled()) {
> +        return qemu_allocate_irqs(kvm_arm_pic_cpu_handler, cpu, 2);
> +    }
> +#endif

...you can avoid the ifdef'ery here.

Jan

-- 
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux

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

* Re: [Qemu-devel] [RFC v2 2/6] ARM: KVM: Add support for KVM on ARM architecture
@ 2012-10-18 17:41     ` Jan Kiszka
  0 siblings, 0 replies; 30+ messages in thread
From: Jan Kiszka @ 2012-10-18 17:41 UTC (permalink / raw)
  To: Peter Maydell; +Cc: patches, qemu-devel, kvm, kvmarm

On 2012-10-10 17:07, Peter Maydell wrote:
> From: Christoffer Dall <cdall@cs.columbia.edu>
> 
> Add basic support for KVM on ARM architecture.
> 
> Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> [PMM: Minor tweaks and code cleanup, switch to ONE_REG]
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  hw/arm_pic.c             |   28 ++++
>  target-arm/Makefile.objs |    1 +
>  target-arm/cpu.h         |    1 +
>  target-arm/helper.c      |    2 +-
>  target-arm/kvm.c         |  328 ++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 359 insertions(+), 1 deletion(-)
>  create mode 100644 target-arm/kvm.c
> 
> diff --git a/hw/arm_pic.c b/hw/arm_pic.c
> index ffb4d41..72272dc 100644
> --- a/hw/arm_pic.c
> +++ b/hw/arm_pic.c
> @@ -9,6 +9,7 @@
>  
>  #include "hw.h"
>  #include "arm-misc.h"
> +#include "kvm.h"
>  
>  /* Input 0 is IRQ and input 1 is FIQ.  */
>  static void arm_pic_cpu_handler(void *opaque, int irq, int level)
> @@ -34,7 +35,34 @@ static void arm_pic_cpu_handler(void *opaque, int irq, int level)
>      }
>  }
>  
> +#ifdef CONFIG_KVM
> +static void kvm_arm_pic_cpu_handler(void *opaque, int irq, int level)
> +{
> +    ARMCPU *cpu = opaque;
> +    CPUARMState *env = &cpu->env;
> +    int kvm_irq = KVM_ARM_IRQ_TYPE_CPU << KVM_ARM_IRQ_TYPE_SHIFT;
> +
> +    switch (irq) {
> +    case ARM_PIC_CPU_IRQ:
> +        kvm_irq |= KVM_ARM_IRQ_CPU_IRQ;
> +        break;
> +    case ARM_PIC_CPU_FIQ:
> +        kvm_irq |= KVM_ARM_IRQ_CPU_FIQ;
> +        break;
> +    default:
> +        hw_error("kvm_arm_pic_cpu_handler: Bad interrupt line %d\n", irq);
> +    }
> +    kvm_irq |= env->cpu_index << KVM_ARM_IRQ_VCPU_SHIFT;
> +    kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0);
> +}
> +#endif

Minor: If you do

function()
{
#ifdef CONFIG_KVM
...
#endif
}

> +
>  qemu_irq *arm_pic_init_cpu(ARMCPU *cpu)
>  {
> +#ifdef CONFIG_KVM
> +    if (kvm_enabled()) {
> +        return qemu_allocate_irqs(kvm_arm_pic_cpu_handler, cpu, 2);
> +    }
> +#endif

...you can avoid the ifdef'ery here.

Jan

-- 
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux

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

* Re: [RFC v2 2/6] ARM: KVM: Add support for KVM on ARM architecture
  2012-10-18 17:41     ` [Qemu-devel] " Jan Kiszka
@ 2012-10-18 17:53       ` Peter Maydell
  -1 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-18 17:53 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: patches, qemu-devel, kvm, kvmarm

On 18 October 2012 18:41, Jan Kiszka <jan.kiszka@siemens.com> wrote:
> Minor: If you do
>
> function()
> {
> #ifdef CONFIG_KVM
> ...
> #endif
> }
>
>> +
>>  qemu_irq *arm_pic_init_cpu(ARMCPU *cpu)
>>  {
>> +#ifdef CONFIG_KVM
>> +    if (kvm_enabled()) {
>> +        return qemu_allocate_irqs(kvm_arm_pic_cpu_handler, cpu, 2);
>> +    }
>> +#endif
>
> ...you can avoid the ifdef'ery here.

Good idea -- will do that in next version.

-- PMM

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

* Re: [Qemu-devel] [RFC v2 2/6] ARM: KVM: Add support for KVM on ARM architecture
@ 2012-10-18 17:53       ` Peter Maydell
  0 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2012-10-18 17:53 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: patches, qemu-devel, kvm, kvmarm

On 18 October 2012 18:41, Jan Kiszka <jan.kiszka@siemens.com> wrote:
> Minor: If you do
>
> function()
> {
> #ifdef CONFIG_KVM
> ...
> #endif
> }
>
>> +
>>  qemu_irq *arm_pic_init_cpu(ARMCPU *cpu)
>>  {
>> +#ifdef CONFIG_KVM
>> +    if (kvm_enabled()) {
>> +        return qemu_allocate_irqs(kvm_arm_pic_cpu_handler, cpu, 2);
>> +    }
>> +#endif
>
> ...you can avoid the ifdef'ery here.

Good idea -- will do that in next version.

-- PMM

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

end of thread, other threads:[~2012-10-18 17:53 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-10-10 15:07 [RFC v2 0/6] QEMU: Support KVM on ARM Peter Maydell
2012-10-10 15:07 ` [Qemu-devel] " Peter Maydell
2012-10-10 15:07 ` [RFC v2 1/6] linux-headers: Add ARM KVM headers (not for upstream) Peter Maydell
2012-10-10 15:07   ` [Qemu-devel] " Peter Maydell
2012-10-10 15:07 ` [RFC v2 2/6] ARM: KVM: Add support for KVM on ARM architecture Peter Maydell
2012-10-10 15:07   ` [Qemu-devel] " Peter Maydell
2012-10-13  9:09   ` Blue Swirl
2012-10-13  9:09     ` Blue Swirl
2012-10-13 19:19     ` Peter Maydell
2012-10-13 19:19       ` Peter Maydell
2012-10-18 12:37     ` Peter Maydell
2012-10-18 12:37       ` Peter Maydell
2012-10-18 17:41   ` Jan Kiszka
2012-10-18 17:41     ` [Qemu-devel] " Jan Kiszka
2012-10-18 17:53     ` Peter Maydell
2012-10-18 17:53       ` [Qemu-devel] " Peter Maydell
2012-10-10 15:07 ` [RFC v2 3/6] hw/arm_gic: Add presave/postload hooks Peter Maydell
2012-10-10 15:07   ` [Qemu-devel] " Peter Maydell
2012-10-10 17:29   ` Andreas Färber
2012-10-10 17:29     ` Andreas Färber
2012-10-10 15:07 ` [RFC v2 4/6] hw/kvm/arm_gic: Implement support for KVM in-kernel ARM GIC Peter Maydell
2012-10-10 15:07   ` [Qemu-devel] " Peter Maydell
2012-10-10 17:23   ` Andreas Färber
2012-10-10 17:23     ` Andreas Färber
2012-10-10 17:35     ` Peter Maydell
2012-10-10 17:35       ` Peter Maydell
2012-10-10 15:07 ` [RFC v2 5/6] ARM KVM: save and load VFP registers from kernel Peter Maydell
2012-10-10 15:07   ` [Qemu-devel] " Peter Maydell
2012-10-10 15:07 ` [RFC v2 6/6] configure: Enable KVM on ARM Peter Maydell
2012-10-10 15:07   ` [Qemu-devel] " Peter Maydell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.