Skip to contentSkip to conversation

KVM/ARM Implementation

PATCH Superseded Christoffer Dall 9 participants 105 messages Dec 11, 2011 – Feb 9, 2012 3 messages not in the archive

Subsystems (7)

v5 of 10 Superseded Latest is v10 →

lore
Share & tools
lore
#0 lore raw

v5 cover KVM/ARM Implementation

The following series implements KVM support for ARM processors, specifically on the Cortex A-15 platform.

The patch series applies to commit 0ec4044a029b5ba9ed6dc7c52390c25da717e184 on Catalin Marinas' linux-arm-arch tree.

This is Version 5 of the patch series, but the first two versions were reviewed outside of the KVM mailing list. Changes can also be pulled from:
git://github.com/virtualopensystems/linux-kvm-arm.git kvm-a15-v5

The implementation is broken up into a logical set of patches, the first one containing a skeleton of files, makefile changes, the basic user space interface and KVM architecture specific stubs. Subsequent patches implement parts of the system as listed:

 1.  Skeleton
 2.  Identity Mapping for Hyp mode
 3.  Hypervisor initialization
 4.  Memory virtualization setup (hyp mode mappings and 2nd stage)
 5.  Inject IRQs and FIQs from userspace
 6.  World-switch implementation and Hyp exception vectors
 7.  Emulation framework and CP15 emulation
 8.  Handle guest user memory aborts
 9.  Handle guest MMIO aborts

10. Support guest wait-for-interrupt instructions.
11. Initial SMP host support (incomplete!)
12. Fix guest view of MPIDR
13. Initial SMP guest support (incomplete!)

Testing:
Limited testing, but have run GCC inside guest, which compiled a small hello-world program, which was successfully run. Hardware still unavailable, so all testing has been done on ARM Fast Models.

For a guide on how to set up a testing environment and try out these patches, see:
http://www.virtualopensystems.com/media/pdf/kvm-arm-guide.pdf
https://wiki.linaro.org/PeterMaydell/A15OnFastModels

Still on the to-do list:
- Reuse VMIDs
- Fix SMP host support
- Fix SMP guest support
- Support guest Thumb mode for MMIO emulation
- Further testing
- Performance improvements

Changes since v4:
- Addressed reviewer comments from v4
* cleanup debug and trace code
* remove printks
* fixup kvm_arch_vcpu_ioctl_run
* add trace details to mmio emulation
- Fix from Marc Zyngier: Move kvm_guest_enter/exit into non-preemptible section (squashed into world-switch patch)
- Cleanup create_hyp_mappings/remove_hyp_mappings from Marc Zyngier (squashed into hypervisor initialization patch)
- Removed the remove_hyp_mappings feature. Removing hypervisor mappings could potentially unmap other important data shared in the same page.
- Removed the arm_ prefix from the arch-specific files.
- Initial SMP host/guest support

Changes since v3:
- v4 actually works, fully boots a guest
- Support compiling as a module
- Use static inlines instead of macros for vcpu_reg and friends
- Optimize kvm_vcpu_reg function
- Use Ftrace for trace capabilities
- Updated documentation and commenting
- Use KVM_IRQ_LINE instead of KVM_INTERRUPT
- Emulates load/store instructions not supported through HSR syndrome information.
- Frees 2nd stage translation tables on VM teardown
- Handles IRQ/FIQ instructions
- Handles more CP15 accesses
- Support guest WFI calls
- Uses debugfs instead of /proc
- Support compiling in Thumb mode

Changes since v2:
- Performs world-switch code
- Maps guest memory using 2nd stage translation
- Emulates co-processor 15 instructions
- Forwards I/O faults to QEMU.

---

Christoffer Dall (12):
ARM: KVM: Initial skeleton to compile KVM support
ARM: KVM: Hypervisor identity mapping
ARM: KVM: Add hypervisor inititalization
ARM: KVM: Memory virtualization setup
ARM: KVM: Inject IRQs and FIQs from userspace
ARM: KVM: World-switch implementation
ARM: KVM: Emulation framework and CP15 emulation
ARM: KVM: Handle guest faults in KVM
ARM: KVM: Handle I/O aborts
ARM: KVM: Guest wait-for-interrupts (WFI) support
ARM: KVM: Support SMP hosts
ARM: KVM: Support SMP guests

Marc Zyngier (1):
ARM: KVM: Fix guest view of MPIDR

 Documentation/virtual/kvm/api.txt           |   10 
 arch/arm/Kconfig                            |    2 
 arch/arm/Makefile                           |    1 
 arch/arm/include/asm/kvm.h                  |   75 +++
 arch/arm/include/asm/kvm_arm.h              |  130 +++++
 arch/arm/include/asm/kvm_asm.h              |   51 ++
 arch/arm/include/asm/kvm_emulate.h          |  100 ++++
 arch/arm/include/asm/kvm_host.h             |  112 ++++
 arch/arm/include/asm/kvm_mmu.h              |   42 ++
 arch/arm/include/asm/kvm_para.h             |    9 
 arch/arm/include/asm/pgtable-3level-hwdef.h |    5 
 arch/arm/include/asm/pgtable-3level.h       |   12 
 arch/arm/include/asm/pgtable.h              |   11 
 arch/arm/include/asm/unified.h              |   12 
 arch/arm/kernel/armksyms.c                  |    7 
 arch/arm/kernel/asm-offsets.c               |   34 +
 arch/arm/kernel/entry-armv.S                |    1 
 arch/arm/kvm/Kconfig                        |   44 ++
 arch/arm/kvm/Makefile                       |   17 +
 arch/arm/kvm/arm.c                          |  716 +++++++++++++++++++++++++++
 arch/arm/kvm/debug.h                        |   48 ++
 arch/arm/kvm/emulate.c                      |  610 +++++++++++++++++++++++
 arch/arm/kvm/exports.c                      |   26 +
 arch/arm/kvm/guest.c                        |  150 ++++++
 arch/arm/kvm/init.S                         |  115 ++++
 arch/arm/kvm/interrupts.S                   |  496 +++++++++++++++++++
 arch/arm/kvm/mmu.c                          |  512 +++++++++++++++++++
 arch/arm/kvm/trace.h                        |  138 +++++
 arch/arm/mach-vexpress/Kconfig              |    1 
 arch/arm/mm/Kconfig                         |    8 
 arch/arm/mm/idmap.c                         |   54 ++
 arch/arm/mm/mmu.c                           |    3 
 include/linux/kvm.h                         |    1 
 mm/memory.c                                 |    1 
 34 files changed, 3552 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/include/asm/kvm.h
 create mode 100644 arch/arm/include/asm/kvm_arm.h
 create mode 100644 arch/arm/include/asm/kvm_asm.h
 create mode 100644 arch/arm/include/asm/kvm_emulate.h
 create mode 100644 arch/arm/include/asm/kvm_host.h
 create mode 100644 arch/arm/include/asm/kvm_mmu.h
 create mode 100644 arch/arm/include/asm/kvm_para.h
 create mode 100644 arch/arm/kvm/Kconfig
 create mode 100644 arch/arm/kvm/Makefile
 create mode 100644 arch/arm/kvm/arm.c
 create mode 100644 arch/arm/kvm/debug.h
 create mode 100644 arch/arm/kvm/emulate.c
 create mode 100644 arch/arm/kvm/exports.c
 create mode 100644 arch/arm/kvm/guest.c
 create mode 100644 arch/arm/kvm/init.S
 create mode 100644 arch/arm/kvm/interrupts.S
 create mode 100644 arch/arm/kvm/mmu.c
 create mode 100644 arch/arm/kvm/trace.h
#1 lore raw

PATCH v5 1/13 ARM: KVM: Initial skeleton to compile KVM support

Targets KVM support for Cortex A-15 processors.

Contains no real functionality but all the framework components, make files, header files and some tracing functionality.

Most functionality is in arch/arm/kvm/* or arch/arm/include/asm/kvm_*.h.

---
 arch/arm/Kconfig                   |    2 
 arch/arm/Makefile                  |    1 
 arch/arm/include/asm/kvm.h         |   66 +++++++++
 arch/arm/include/asm/kvm_asm.h     |   28 ++++
 arch/arm/include/asm/kvm_emulate.h |   91 ++++++++++++
 arch/arm/include/asm/kvm_host.h    |   93 ++++++++++++
 arch/arm/include/asm/kvm_para.h    |    9 +
 arch/arm/include/asm/unified.h     |   12 ++
 arch/arm/kvm/Kconfig               |   44 ++++++
 arch/arm/kvm/Makefile              |   17 ++
 arch/arm/kvm/arm.c                 |  279 ++++++++++++++++++++++++++++++++++++
 arch/arm/kvm/debug.h               |   48 ++++++
 arch/arm/kvm/emulate.c             |  121 ++++++++++++++++
 arch/arm/kvm/exports.c             |   16 ++
 arch/arm/kvm/guest.c               |  148 +++++++++++++++++++
 arch/arm/kvm/init.S                |   17 ++
 arch/arm/kvm/interrupts.S          |   17 ++
 arch/arm/kvm/mmu.c                 |   15 ++
 arch/arm/kvm/trace.h               |   52 +++++++
 arch/arm/mach-vexpress/Kconfig     |    1 
 arch/arm/mm/Kconfig                |    8 +
 21 files changed, 1085 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/include/asm/kvm.h
 create mode 100644 arch/arm/include/asm/kvm_asm.h
 create mode 100644 arch/arm/include/asm/kvm_emulate.h
 create mode 100644 arch/arm/include/asm/kvm_host.h
 create mode 100644 arch/arm/include/asm/kvm_para.h
 create mode 100644 arch/arm/kvm/Kconfig
 create mode 100644 arch/arm/kvm/Makefile
 create mode 100644 arch/arm/kvm/arm.c
 create mode 100644 arch/arm/kvm/debug.h
 create mode 100644 arch/arm/kvm/emulate.c
 create mode 100644 arch/arm/kvm/exports.c
 create mode 100644 arch/arm/kvm/guest.c
 create mode 100644 arch/arm/kvm/init.S
 create mode 100644 arch/arm/kvm/interrupts.S
 create mode 100644 arch/arm/kvm/mmu.c
 create mode 100644 arch/arm/kvm/trace.h
arch/arm/Kconfig +2 -0
index 00e908b..2a65d7b 100644
@@ -2248,3 +2248,5 @@ source "security/Kconfig"
 source "crypto/Kconfig"
 
 source "lib/Kconfig"
+
+source "arch/arm/kvm/Kconfig"
arch/arm/Makefile +1 -0
index dfcf3b0..621fb8d 100644
@@ -255,6 +255,7 @@ core-$(CONFIG_VFP)		+= arch/arm/vfp/
 
 # If we have a machine-specific directory, then include it in the build.
 core-y				+= arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
+core-y 				+= arch/arm/kvm/
 core-y				+= $(machdirs) $(platdirs)
 
 drivers-$(CONFIG_OPROFILE)      += arch/arm/oprofile/
arch/arm/include/asm/kvm.h new file +66 -0

66 lines not on this page · raw message

arch/arm/include/asm/kvm_asm.h new file +28 -0
new file mode 100644
index 0000000..c3d4458
@@ -0,0 +1,28 @@
+/*
+ * 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_ASM_H__
+#define __ARM_KVM_ASM_H__
+
+#define ARM_EXCEPTION_RESET	  0
+#define ARM_EXCEPTION_UNDEFINED   1
+#define ARM_EXCEPTION_SOFTWARE    2
+#define ARM_EXCEPTION_PREF_ABORT  3
+#define ARM_EXCEPTION_DATA_ABORT  4
+#define ARM_EXCEPTION_IRQ	  5
+#define ARM_EXCEPTION_FIQ	  6
+
+#endif /* __ARM_KVM_ASM_H__ */
arch/arm/include/asm/kvm_emulate.h new file +91 -0

91 lines not on this page · raw message

arch/arm/include/asm/kvm_host.h new file +93 -0

93 lines not on this page · raw message

arch/arm/include/asm/kvm_para.h new file +9 -0
new file mode 100644
index 0000000..7ce5f1c
@@ -0,0 +1,9 @@
+#ifndef _ASM_X86_KVM_PARA_H
+#define _ASM_X86_KVM_PARA_H
+
+static inline unsigned int kvm_arch_para_features(void)
+{
+	return 0;
+}
+
+#endif /* _ASM_X86_KVM_PARA_H */
arch/arm/include/asm/unified.h +12 -0
index bc63116..0d41bde 100644
@@ -54,6 +54,18 @@
 
 #endif	/* CONFIG_THUMB2_KERNEL */
 
+#ifdef CONFIG_KVM_ARM_HOST
+#ifdef __ASSEMBLY__
+.arch_extension sec
+.arch_extension virt
+#else
+__asm__(
+"	.arch_extension sec\n"
+"	.arch_extension virt\n"
+);
+#endif
+#endif
+
 #ifndef CONFIG_ARM_ASM_UNIFIED
 
 /*
arch/arm/kvm/Kconfig new file +44 -0

44 lines not on this page · raw message

arch/arm/kvm/Makefile new file +17 -0
new file mode 100644
index 0000000..e69a8e1
@@ -0,0 +1,17 @@
+#
+# Makefile for Kernel-based Virtual Machine module
+#
+
+ccflags-y += -Ivirt/kvm -Iarch/arm/kvm
+CFLAGS_arm.o     := -I.
+CFLAGS_mmu.o := -I.
+
+AFLAGS_interrupts.o := -I$(obj)
+
+obj-$(CONFIG_KVM_ARM_HOST) += init.o interrupts.o exports.o
+
+kvm-arm-y += $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o)
+
+kvm-arm-y += arm.o guest.o mmu.o emulate.o
+
+obj-$(CONFIG_KVM) += kvm-arm.o
arch/arm/kvm/arm.c new file +279 -0

279 lines not on this page · raw message

arch/arm/kvm/debug.h new file +48 -0

48 lines not on this page · raw message

arch/arm/kvm/emulate.c new file +121 -0

121 lines not on this page · raw message

arch/arm/kvm/exports.c new file +16 -0
new file mode 100644
index 0000000..d8a7fd5
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */
+
+#include <linux/module.h>
arch/arm/kvm/guest.c new file +148 -0

148 lines not on this page · raw message

arch/arm/kvm/init.S new file +17 -0
new file mode 100644
index 0000000..073a494
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ *
+ */
+#include <asm/asm-offsets.h>
+#include <asm/kvm_asm.h>
arch/arm/kvm/interrupts.S new file +17 -0
new file mode 100644
index 0000000..073a494
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ *
+ */
+#include <asm/asm-offsets.h>
+#include <asm/kvm_asm.h>
arch/arm/kvm/mmu.c new file +15 -0
new file mode 100644
index 0000000..2cccd48
@@ -0,0 +1,15 @@
+/*
+ * 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.
+ *
+ */
arch/arm/kvm/trace.h new file +52 -0

52 lines not on this page · raw message

arch/arm/mach-vexpress/Kconfig +1 -0
index c294f2b..b9565a7 100644
@@ -37,6 +37,7 @@ config ARCH_VEXPRESS_CA15X4
 	bool "Versatile Express Cortex-A15x4 tile"
 	depends on VEXPRESS_EXTENDED_MEMORY_MAP
 	select CPU_V7
+	select ARM_VIRT_EXT
 	select ARM_GIC
 	select ARM_GIC_VPPI
 	select ARM_ARCH_TIMER
arch/arm/mm/Kconfig +8 -0
index fc9b9f2..e3f5173 100644
@@ -640,6 +640,14 @@ config ARM_LPAE
 
 	  If unsure, say N.
 
+config ARM_VIRT_EXT
+	bool "Support for ARM Virtualization Extensions"
+	depends on ARM_LPAE
+	help
+	  Say Y if you have an ARMv7 processor supporting the ARM hardware
+	  Virtualization extensions. KVM depends on this feature and will
+	  not run without it being selected.
+
 config ARCH_PHYS_ADDR_T_64BIT
 	def_bool ARM_LPAE
 
#2 lore raw

PATCH v5 2/13 ARM: KVM: Hypervisor identity mapping

In reply to Christoffer Dall

From: Christoffer Dall <[email protected]>

Adds support in the identity mapping feature that allows KVM to setup identity mapping for the Hyp mode with the AP[1] bit set as required by the specification and also supports freeing created sub pmd's after finished use.

These two functions:
- hyp_identity_mapping_add(pgd, addr, end);
- hyp_identity_mapping_del(pgd, addr, end);
are essentially calls to the same function as the non-hyp versions but with a different argument value. KVM calls these functions to setup and teardown the identity mapping used to initialize the hypervisor.

Note, the hyp-version of the _del function actually frees the pmd's pointed to by the pgd as opposed to the non-hyp version which just clears them.

---
 arch/arm/include/asm/pgtable-3level-hwdef.h |    1 +
 arch/arm/include/asm/pgtable.h              |    6 +++
 arch/arm/mm/idmap.c                         |   54 +++++++++++++++++++++++++++
 3 files changed, 60 insertions(+), 1 deletions(-)
arch/arm/include/asm/pgtable-3level-hwdef.h +1 -0
index d795282..a2d404e 100644
@@ -44,6 +44,7 @@
 #define PMD_SECT_XN		(_AT(pmdval_t, 1) << 54)
 #define PMD_SECT_AP_WRITE	(_AT(pmdval_t, 0))
 #define PMD_SECT_AP_READ	(_AT(pmdval_t, 0))
+#define PMD_SECT_AP1		(_AT(pmdval_t, 1) << 6)
 #define PMD_SECT_TEX(x)		(_AT(pmdval_t, 0))
 
 /*
arch/arm/include/asm/pgtable.h +6 -0
index aec18ab..19456f4 100644
@@ -318,6 +318,12 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 void identity_mapping_add(pgd_t *, unsigned long, unsigned long);
 void identity_mapping_del(pgd_t *, unsigned long, unsigned long);
 
+#ifdef CONFIG_KVM_ARM_HOST
+void hyp_identity_mapping_add(pgd_t *, unsigned long, unsigned long);
+void hyp_identity_mapping_del(pgd_t *pgd, unsigned long addr,
+			      unsigned long end);
+#endif
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* CONFIG_MMU */
arch/arm/mm/idmap.c +53 -1

79 lines not on this page · raw message

#3 lore raw

PATCH v5 3/13 ARM: KVM: Add hypervisor inititalization

In reply to Christoffer Dall

Sets up the required registers to run code in HYP-mode from the kernel. No major controversies, but we should consider how to deal with SMP support for hypervisor stack page.

By setting the HVBAR the kernel can execute code in Hyp-mode with the MMU disabled. The HVBAR initially points to initialization code, which initializes other Hyp-mode registers and enables the MMU for Hyp-mode. Afterwards, the HVBAR is changed to point to KVM Hyp vectors used to catch guest faults and to switch to Hyp mode to perform a world-switch into a KVM guest.

Also provides memory mapping code to map required code pages and data structures accessed in Hyp mode at the same virtual address as the host kernel virtual addresses, but which conforms to the architectural requirements for translations in Hyp mode. This interface is added in arch/arm/kvm/arm_mmu.c and is comprised of:
- create_hyp_mappings(hyp_pgd, start, end);
- free_hyp_pmds(pgd_hyp);

See the implementation for more details.

---
 arch/arm/include/asm/kvm_arm.h              |  103 +++++++++++++++++
 arch/arm/include/asm/kvm_asm.h              |   23 ++++
 arch/arm/include/asm/kvm_host.h             |    1 
 arch/arm/include/asm/kvm_mmu.h              |   35 ++++++
 arch/arm/include/asm/pgtable-3level-hwdef.h |    4 +
 arch/arm/include/asm/pgtable-3level.h       |    4 +
 arch/arm/include/asm/pgtable.h              |    1 
 arch/arm/kvm/arm.c                          |  166 +++++++++++++++++++++++++++
 arch/arm/kvm/exports.c                      |   10 ++
 arch/arm/kvm/init.S                         |   98 ++++++++++++++++
 arch/arm/kvm/interrupts.S                   |   30 +++++
 arch/arm/kvm/mmu.c                          |  152 +++++++++++++++++++++++++
 mm/memory.c                                 |    1 
 13 files changed, 628 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/include/asm/kvm_arm.h
 create mode 100644 arch/arm/include/asm/kvm_mmu.h
arch/arm/include/asm/kvm_arm.h new file +103 -0
new file mode 100644
index 0000000..835abd1
@@ -0,0 +1,103 @@
+/*
+ * 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 __KVM_ARM_H__
+#define __KVM_ARM_H__
+
+#include <asm/types.h>
+
+/* Hyp Configuration Register (HCR) bits */
+#define HCR_TGE		(1 << 27)
+#define HCR_TVM		(1 << 26)
+#define HCR_TTLB	(1 << 25)
+#define HCR_TPU		(1 << 24)
+#define HCR_TPC		(1 << 23)
+#define HCR_TSW		(1 << 22)
+#define HCR_TAC		(1 << 21)
+#define HCR_TIDCP	(1 << 20)
+#define HCR_TSC		(1 << 19)
+#define HCR_TID3	(1 << 18)
+#define HCR_TID2	(1 << 17)
+#define HCR_TID1	(1 << 16)
+#define HCR_TID0	(1 << 15)
+#define HCR_TWE		(1 << 14)
+#define HCR_TWI		(1 << 13)
+#define HCR_DC		(1 << 12)
+#define HCR_BSU		(3 << 10)
+#define HCR_FB		(1 << 9)
+#define HCR_VA		(1 << 8)
+#define HCR_VI		(1 << 7)
+#define HCR_VF		(1 << 6)
+#define HCR_AMO		(1 << 5)
+#define HCR_IMO		(1 << 4)
+#define HCR_FMO		(1 << 3)
+#define HCR_PTW		(1 << 2)
+#define HCR_SWIO	(1 << 1)
+#define HCR_VM		1
+#define HCR_GUEST_MASK (HCR_TSC | HCR_TWE | HCR_TWI | HCR_VM | HCR_AMO | \
+			HCR_AMO | HCR_IMO | HCR_FMO | HCR_SWIO)
+
+/* Hyp System Control Register (HSCTLR) bits */
+#define HSCTLR_TE	(1 << 30)
+#define HSCTLR_EE	(1 << 25)
+#define HSCTLR_FI	(1 << 21)
+#define HSCTLR_WXN	(1 << 19)
+#define HSCTLR_I	(1 << 12)
+#define HSCTLR_C	(1 << 2)
+#define HSCTLR_A	(1 << 1)
+#define HSCTLR_M	1
+#define HSCTLR_MASK	(HSCTLR_M | HSCTLR_A | HSCTLR_C | HSCTLR_I | \
+			 HSCTLR_WXN | HSCTLR_FI | HSCTLR_EE | HSCTLR_TE)
+
+/* TTBCR and HTCR Registers bits */
+#define TTBCR_EAE	(1 << 31)
+#define TTBCR_IMP	(1 << 30)
+#define TTBCR_SH1	(3 << 28)
+#define TTBCR_ORGN1	(3 << 26)
+#define TTBCR_IRGN1	(3 << 24)
+#define TTBCR_EPD1	(1 << 23)
+#define TTBCR_A1	(1 << 22)
+#define TTBCR_T1SZ	(3 << 16)
+#define TTBCR_SH0	(3 << 12)
+#define TTBCR_ORGN0	(3 << 10)
+#define TTBCR_IRGN0	(3 << 8)
+#define TTBCR_EPD0	(1 << 7)
+#define TTBCR_T0SZ	3
+#define HTCR_MASK	(TTBCR_T0SZ | TTBCR_IRGN0 | TTBCR_ORGN0 | TTBCR_SH0)
+
+
+/* Virtualization Translation Control Register (VTCR) bits */
+#define VTCR_SH0	(3 << 12)
+#define VTCR_ORGN0	(3 << 10)
+#define VTCR_IRGN0	(3 << 8)
+#define VTCR_SL0	(3 << 6)
+#define VTCR_S		(1 << 4)
+#define VTCR_T0SZ	3
+#define VTCR_MASK	(VTCR_SH0 | VTCR_ORGN0 | VTCR_IRGN0 | VTCR_SL0 | \
+			 VTCR_S | VTCR_T0SZ | VTCR_MASK)
+#define VTCR_HTCR_SH	(VTCR_SH0 | VTCR_ORGN0 | VTCR_IRGN0)
+#define VTCR_SL_L2	0		/* Starting-level: 2 */
+#define VTCR_SL_L1	(1 << 6)	/* Starting-level: 1 */
+#define VTCR_GUEST_SL	VTCR_SL_L1
+#define VTCR_GUEST_T0SZ	0
+#if VTCR_GUEST_SL == 0
+#define VTTBR_X		(14 - VTCR_GUEST_T0SZ)
+#else
+#define VTTBR_X		(5 - VTCR_GUEST_T0SZ)
+#endif
+
+
+#endif /* __KVM_ARM_H__ */
arch/arm/include/asm/kvm_asm.h +23 -0
index c3d4458..89c318ea 100644
@@ -24,5 +24,28 @@
 #define ARM_EXCEPTION_DATA_ABORT  4
 #define ARM_EXCEPTION_IRQ	  5
 #define ARM_EXCEPTION_FIQ	  6
+#define ARM_EXCEPTION_HVC	  7
+
+/*
+ * SMC Hypervisor API call numbers
+ */
+#ifdef __ASSEMBLY__
+.equ SMCHYP_HVBAR_W, 0xfffffff0
+#else /* !__ASSEMBLY__ */
+asm(".equ SMCHYP_HVBAR_W, 0xfffffff0");
+#endif /* __ASSEMBLY__ */
+
+#ifndef __ASSEMBLY__
+struct kvm_vcpu;
+
+extern char __kvm_hyp_init[];
+extern char __kvm_hyp_init_end[];
+
+extern char __kvm_hyp_vector[];
+extern char __kvm_hyp_vector_end[];
+
+extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
+extern char __kvm_vcpu_run_end[];
+#endif
 
 #endif /* __ARM_KVM_ASM_H__ */
arch/arm/include/asm/kvm_host.h +1 -0
index b2fcd8a..6a10467 100644
@@ -31,6 +31,7 @@ struct kvm_vcpu;
 u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
 
 struct kvm_arch {
+	pgd_t *pgd;     /* 1-level 2nd stage table */
 };
 
 #define EXCEPTION_NONE      0
arch/arm/include/asm/kvm_mmu.h new file +35 -0
new file mode 100644
index 0000000..13fd8dc
@@ -0,0 +1,35 @@
+/*
+ * 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_MMU_H__
+#define __ARM_KVM_MMU_H__
+
+/*
+ * The architecture supports 40-bit IPA as input to the 2nd stage translations
+ * and PTRS_PER_PGD2 could therefore be 1024.
+ *
+ * To save a bit of memory and to avoid alignment issues we assume 39-bit IPA
+ * for now, but remember that the level-1 table must be aligned to its size.
+ */
+#define PTRS_PER_PGD2	512
+#define PGD2_ORDER	get_order(PTRS_PER_PGD2 * sizeof(pgd_t))
+
+extern pgd_t *kvm_hyp_pgd;
+
+int create_hyp_mappings(pgd_t *hyp_pgd, void *from, void *to);
+void free_hyp_pmds(pgd_t *hyp_pgd);
+
+#endif /* __ARM_KVM_MMU_H__ */
arch/arm/include/asm/pgtable-3level-hwdef.h +4 -0
index a2d404e..18f5cef 100644
@@ -32,6 +32,9 @@
 #define PMD_TYPE_SECT		(_AT(pmdval_t, 1) << 0)
 #define PMD_BIT4		(_AT(pmdval_t, 0))
 #define PMD_DOMAIN(x)		(_AT(pmdval_t, 0))
+#define PMD_APTABLE_SHIFT	(61)
+#define PMD_APTABLE		(_AT(pgdval_t, 3) << PGD_APTABLE_SHIFT)
+#define PMD_PXNTABLE		(_AT(pgdval_t, 1) << 59)
 
 /*
  *   - section
@@ -41,6 +44,7 @@
 #define PMD_SECT_S		(_AT(pmdval_t, 3) << 8)
 #define PMD_SECT_AF		(_AT(pmdval_t, 1) << 10)
 #define PMD_SECT_nG		(_AT(pmdval_t, 1) << 11)
+#define PMD_SECT_PXN		(_AT(pmdval_t, 1) << 53)
 #define PMD_SECT_XN		(_AT(pmdval_t, 1) << 54)
 #define PMD_SECT_AP_WRITE	(_AT(pmdval_t, 0))
 #define PMD_SECT_AP_READ	(_AT(pmdval_t, 0))
arch/arm/include/asm/pgtable-3level.h +4 -0
index 759af70..edc3cb9 100644
@@ -109,6 +109,10 @@
 #define pud_none(pud)		(!pud_val(pud))
 #define pud_bad(pud)		(!(pud_val(pud) & 2))
 #define pud_present(pud)	(pud_val(pud))
+#define pmd_table(pmd)		((pmd_val(pmd) & PMD_TYPE_MASK) == \
+						 PMD_TYPE_TABLE)
+#define pmd_sect(pmd)		((pmd_val(pmd) & PMD_TYPE_MASK) == \
+						 PMD_TYPE_SECT)
 
 #define pud_clear(pudp)			\
 	do {				\
arch/arm/include/asm/pgtable.h +1 -0
index 19456f4..20025cc 100644
@@ -88,6 +88,7 @@ extern pgprot_t		pgprot_kernel;
 #define PAGE_READONLY_EXEC	_MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_RDONLY)
 #define PAGE_KERNEL		_MOD_PROT(pgprot_kernel, L_PTE_XN)
 #define PAGE_KERNEL_EXEC	pgprot_kernel
+#define PAGE_HYP		_MOD_PROT(pgprot_kernel, L_PTE_USER)
 
 #define __PAGE_NONE		__pgprot(_L_PTE_DEFAULT | L_PTE_RDONLY | L_PTE_XN)
 #define __PAGE_SHARED		__pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_XN)
arch/arm/kvm/arm.c +166 -0

191 lines not on this page · raw message

arch/arm/kvm/exports.c +10 -0
index d8a7fd5..0fdd5ff 100644
@@ -14,3 +14,13 @@
  */
 
 #include <linux/module.h>
+#include <asm/kvm_asm.h>
+
+EXPORT_SYMBOL_GPL(__kvm_hyp_init);
+EXPORT_SYMBOL_GPL(__kvm_hyp_init_end);
+
+EXPORT_SYMBOL_GPL(__kvm_hyp_vector);
+EXPORT_SYMBOL_GPL(__kvm_hyp_vector_end);
+
+EXPORT_SYMBOL_GPL(__kvm_vcpu_run);
+EXPORT_SYMBOL_GPL(__kvm_vcpu_run_end);
arch/arm/kvm/init.S +98 -0

103 lines not on this page · raw message

arch/arm/kvm/interrupts.S +30 -0
index 073a494..2edc49b 100644
@@ -13,5 +13,35 @@
  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  *
  */
+
+#include <linux/linkage.h>
+#include <asm/unified.h>
+#include <asm/page.h>
 #include <asm/asm-offsets.h>
 #include <asm/kvm_asm.h>
+#include <asm/kvm_arm.h>
+
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@  Hypervisor world-switch code
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
+	.text
+	.arm
+
+ENTRY(__kvm_vcpu_run)
+THUMB(	orr	lr, lr, #1)
+	mov	pc, lr
+__kvm_vcpu_run_end:
+	.globl __kvm_vcpu_run_end
+
+
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@  Hypervisor exception vector and handlers
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
+	.align 5
+__kvm_hyp_vector:
+	.globl __kvm_hyp_vector
+	nop
+__kvm_hyp_vector_end:
+	.globl __kvm_hyp_vector_end
arch/arm/kvm/mmu.c +152 -0

155 lines not on this page · raw message

mm/memory.c +1 -0
index 829d437..e976971 100644
@@ -402,6 +402,7 @@ void pgd_clear_bad(pgd_t *pgd)
 	pgd_ERROR(*pgd);
 	pgd_clear(pgd);
 }
+EXPORT_SYMBOL_GPL(pgd_clear_bad);
 
 void pud_clear_bad(pud_t *pud)
 {
#4 lore raw

PATCH v5 4/13 ARM: KVM: Memory virtualization setup

In reply to Christoffer Dall

This commit introduces the framework for guest memory management through the use of 2nd stage translation. Each VM has a pointer to a level-1 tabled (the pgd field in struct kvm_arch) which is used for the 2nd stage translations. Entries are added when handling guest faults (later patch) and the table itself can be allocated and freed through the following functions implemented in arch/arm/kvm/arm_mmu.c:
- kvm_alloc_stage2_pgd(struct kvm *kvm);
- kvm_free_stage2_pgd(struct kvm *kvm);

Further, each entry in TLBs and caches are tagged with a VMID identifier in addition to ASIDs. The VMIDs are managed using a bitmap and assigned when creating the VM in kvm_arch_init_vm() where the 2nd stage pgd is also allocated. The table is freed in kvm_arch_destroy_vm(). Both functions are called from the main KVM code.

---
 arch/arm/include/asm/kvm_host.h |    4 ++
 arch/arm/include/asm/kvm_mmu.h  |    5 +++
 arch/arm/kvm/arm.c              |   59 +++++++++++++++++++++++++++++++--
 arch/arm/kvm/mmu.c              |   69 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 132 insertions(+), 5 deletions(-)
arch/arm/include/asm/kvm_host.h +3 -1
index 6a10467..06d1263 100644
@@ -31,7 +31,9 @@ struct kvm_vcpu;
 u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
 
 struct kvm_arch {
-	pgd_t *pgd;     /* 1-level 2nd stage table */
+	u32    vmid;	/* The VMID used for the virt. memory system */
+	pgd_t *pgd;	/* 1-level 2nd stage table */
+	u64    vttbr;	/* VTTBR value associated with above pgd and vmid */
 };
 
 #define EXCEPTION_NONE      0
arch/arm/include/asm/kvm_mmu.h +5 -0
index 13fd8dc..9d7440c 100644
@@ -32,4 +32,9 @@ extern pgd_t *kvm_hyp_pgd;
 int create_hyp_mappings(pgd_t *hyp_pgd, void *from, void *to);
 void free_hyp_pmds(pgd_t *hyp_pgd);
 
+int kvm_alloc_stage2_pgd(struct kvm *kvm);
+void kvm_free_stage2_pgd(struct kvm *kvm);
+
+int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run);
+
 #endif /* __ARM_KVM_MMU_H__ */
arch/arm/kvm/arm.c +55 -4

91 lines not on this page · raw message

arch/arm/kvm/mmu.c +69 -0

75 lines not on this page · raw message

#13 lore raw

PATCH v5 5/13 ARM: KVM: Inject IRQs and FIQs from userspace

In reply to Christoffer Dall

Userspace can inject IRQs and FIQs through the KVM_IRQ_LINE VM ioctl. This ioctl is used since the sematics are in fact two lines that can be either raised or lowered on the VCPU - the IRQ and FIQ lines.

KVM needs to know which VCPU it must operate on and whether the FIQ or IRQ line is raised/lowered. Hence both pieces of information is packed in the kvm_irq_level->irq field. The irq fild value will be:
IRQ: vcpu_index * 2
FIQ: (vcpu_index * 2) + 1

This is documented in Documentation/kvm/api.txt.

The effect of the ioctl is simply to simply raise/lower the corresponding virt_irq field on the VCPU struct, which will cause the world-switch code to raise/lower virtual interrupts when running the guest on next switch. The wait_for_interrupt flag is also cleared for raised IRQs causing an idle VCPU to become active again.

Note: The custom trace_kvm_irq_line is used despite a generic definition of trace_kvm_set_irq, since the trace-Kvm_set_irq depends on the x86-specific define of __HAVE_IOAPIC. Either the trace event should be created regardless of this define or it should depend on another ifdef clause, common for both x86 and ARM. However, since the arguments don't really match those used in ARM, I am yet to be convinced why this is necessary.

---
 Documentation/virtual/kvm/api.txt |   10 ++++++-
 arch/arm/include/asm/kvm.h        |    8 ++++++
 arch/arm/include/asm/kvm_arm.h    |    1 +
 arch/arm/kvm/arm.c                |   53 ++++++++++++++++++++++++++++++++++++-
 arch/arm/kvm/trace.h              |   21 +++++++++++++++
 include/linux/kvm.h               |    1 +
 6 files changed, 91 insertions(+), 3 deletions(-)
Documentation/virtual/kvm/api.txt +9 -1
index 7945b0b..4abaa67 100644
@@ -572,7 +572,7 @@ only go to the IOAPIC.  On ia64, a IOSAPIC is created.
 4.25 KVM_IRQ_LINE
 
 Capability: KVM_CAP_IRQCHIP
-Architectures: x86, ia64
+Architectures: x86, ia64, arm
 Type: vm ioctl
 Parameters: struct kvm_irq_level
 Returns: 0 on success, -1 on error
@@ -582,6 +582,14 @@ Requires that an interrupt controller model has been previously created with
 KVM_CREATE_IRQCHIP.  Note that edge-triggered interrupts require the level
 to be set to 1 and then back to 0.
 
+KVM_CREATE_IRQCHIP (except for ARM).  Note that edge-triggered interrupts
+require the level to be set to 1 and then back to 0.
+
+ARM uses two types of interrupt lines per CPU, ie. IRQ and FIQ. The value of the
+irq field should be (VCPU_INDEX * 2) for IRQs and ((VCPU_INDEX * 2) + 1) for
+FIQs. Level is used to raise/lower the line. See arch/arm/include/asm/kvm.h for
+convenience macros.
+
 struct kvm_irq_level {
 	union {
 		__u32 irq;     /* GSI */
arch/arm/include/asm/kvm.h +8 -0
index 87dc33b..8935062 100644
@@ -20,6 +20,14 @@
 #include <asm/types.h>
 
 /*
+ * KVM_IRQ_LINE macros to set/read IRQ/FIQ for specific VCPU index.
+ */
+enum KVM_ARM_IRQ_LINE_TYPE {
+	KVM_ARM_IRQ_LINE = 0,
+	KVM_ARM_FIQ_LINE = 1,
+};
+
+/*
  * Modes used for short-hand mode determinition in the world-switch code and
  * in emulation code.
  *
arch/arm/include/asm/kvm_arm.h +1 -0
index 835abd1..e378a37 100644
@@ -49,6 +49,7 @@
 #define HCR_VM		1
 #define HCR_GUEST_MASK (HCR_TSC | HCR_TWE | HCR_TWI | HCR_VM | HCR_AMO | \
 			HCR_AMO | HCR_IMO | HCR_FMO | HCR_SWIO)
+#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
 
 /* Hyp System Control Register (HSCTLR) bits */
 #define HSCTLR_TE	(1 << 30)
arch/arm/kvm/arm.c +51 -2

65 lines not on this page · raw message

arch/arm/kvm/trace.h +21 -0
index f8869c1..ac64e3a 100644
@@ -40,6 +40,27 @@ TRACE_EVENT(kvm_exit,
 );
 
 
+TRACE_EVENT(kvm_irq_line,
+	TP_PROTO(unsigned int type, unsigned int level, unsigned int vcpu_idx),
+	TP_ARGS(type, level, vcpu_idx),
+
+	TP_STRUCT__entry(
+		__field(	unsigned int,	type			)
+		__field(	unsigned int,	level			)
+		__field(	unsigned int,	vcpu_idx		)
+	),
+
+	TP_fast_assign(
+		__entry->type			= type;
+		__entry->level			= level;
+		__entry->vcpu_idx		= vcpu_idx;
+	),
+
+	TP_printk("KVM_IRQ_LINE: type: %s, level: %u, vcpu: %u",
+		(__entry->type == KVM_ARM_IRQ_LINE) ? "IRQ" : "FIQ",
+		__entry->level, __entry->vcpu_idx)
+);
+
 
 #endif /* _TRACE_KVM_H */
 
include/linux/kvm.h +1 -0
index c3892fc..679abbb 100644
@@ -111,6 +111,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;
#38 lore raw

PATCH v5 6/13 ARM: KVM: World-switch implementation

In reply to Christoffer Dall

Provides complete world-switch implementation to switch to other guests runinng in non-secure modes. Includes Hyp exception handlers that captures necessary exception information and stores the information on the VCPU and KVM structures.

Switching to Hyp mode is done through a simple HVC instructions. The exception vector code will check that the HVC comes from VMID==0 and if so will store the necessary state on the Hyp stack, which will look like this (see hyp_hvc):
...
Hyp_Sp + 4: lr_usr
Hyp_Sp : spsr (Host-SVC cpsr)

When returning from Hyp mode to SVC mode, another HVC instruction is executed from Hyp mode, which is taken in the Hyp_Svc handler. The Hyp stack pointer should be where it was left from the above initial call, since the values on the stack will be used to restore state (see hyp_svc).

Otherwise, the world-switch is pretty straight-forward. All state that can be modified by the guest is first backed up on the Hyp stack and the VCPU values is loaded onto the hardware. State, which is not loaded, but theoretically modifiable by the guest is protected through the virtualiation features to generate a trap and cause software emulation. Upon guest returns, all state is restored from hardware onto the VCPU struct and the original state is restored from the Hyp-stack onto the hardware.

One controversy may be the back-door call to __irq_svc (the host kernel's own physical IRQ handler) which is called when a physical IRQ exception is taken in Hyp mode while running in the guest.

---
 arch/arm/include/asm/kvm.h      |    1 
 arch/arm/include/asm/kvm_arm.h  |   26 ++
 arch/arm/include/asm/kvm_host.h |    8 +
 arch/arm/kernel/armksyms.c      |    7 +
 arch/arm/kernel/asm-offsets.c   |   33 +++
 arch/arm/kernel/entry-armv.S    |    1 
 arch/arm/kvm/arm.c              |   45 ++++
 arch/arm/kvm/guest.c            |    2 
 arch/arm/kvm/interrupts.S       |  443 +++++++++++++++++++++++++++++++++++++++
 9 files changed, 562 insertions(+), 4 deletions(-)
arch/arm/include/asm/kvm.h +1 -0
index 8935062..ff88ca0 100644
@@ -51,6 +51,7 @@ struct kvm_regs {
 	__u32 cpsr;
 	__u32 spsr[5];		/* Banked SPSR,  indexed by MODE_  */
 	struct {
+		__u32 c0_midr;
 		__u32 c1_sys;
 		__u32 c2_base0;
 		__u32 c2_base1;
arch/arm/include/asm/kvm_arm.h +26 -0
index e378a37..1769187 100644
@@ -100,5 +100,31 @@
 #define VTTBR_X		(5 - VTCR_GUEST_T0SZ)
 #endif
 
+/* Hyp Syndrome Register (HSR) bits */
+#define HSR_EC_SHIFT	(26)
+#define HSR_EC		(0x3fU << HSR_EC_SHIFT)
+#define HSR_IL		(1U << 25)
+#define HSR_ISS		(HSR_IL - 1)
+#define HSR_ISV_SHIFT	(24)
+#define HSR_ISV		(1U << HSR_ISV_SHIFT)
+
+#define HSR_EC_UNKNOWN	(0x00)
+#define HSR_EC_WFI	(0x01)
+#define HSR_EC_CP15_32	(0x03)
+#define HSR_EC_CP15_64	(0x04)
+#define HSR_EC_CP14_MR	(0x05)
+#define HSR_EC_CP14_LS	(0x06)
+#define HSR_EC_CP_0_13	(0x07)
+#define HSR_EC_CP10_ID	(0x08)
+#define HSR_EC_JAZELLE	(0x09)
+#define HSR_EC_BXJ	(0x0A)
+#define HSR_EC_CP14_64	(0x0C)
+#define HSR_EC_SVC_HYP	(0x11)
+#define HSR_EC_HVC	(0x12)
+#define HSR_EC_SMC	(0x13)
+#define HSR_EC_IABT	(0x20)
+#define HSR_EC_IABT_HYP	(0x21)
+#define HSR_EC_DABT	(0x24)
+#define HSR_EC_DABT_HYP	(0x25)
 
 #endif /* __KVM_ARM_H__ */
arch/arm/include/asm/kvm_host.h +8 -0
index 06d1263..59fcd15 100644
@@ -62,6 +62,7 @@ struct kvm_vcpu_arch {
 
 	/* System control coprocessor (cp15) */
 	struct {
+		u32 c0_MIDR;		/* Main ID Register */
 		u32 c1_SCTLR;		/* System Control Register */
 		u32 c1_ACTLR;		/* Auxilliary Control Register */
 		u32 c1_CPACR;		/* Coprocessor Access Control */
@@ -69,6 +70,12 @@ struct kvm_vcpu_arch {
 		u64 c2_TTBR1;		/* Translation Table Base Register 1 */
 		u32 c2_TTBCR;		/* Translation Table Base Control R. */
 		u32 c3_DACR;		/* Domain Access Control Register */
+		u32 c10_PRRR;		/* Primary Region Remap Register */
+		u32 c10_NMRR;		/* Normal Memory Remap Register */
+		u32 c13_CID;		/* Context ID Register */
+		u32 c13_TID_URW;	/* Thread ID, User R/W */
+		u32 c13_TID_URO;	/* Thread ID, User R/O */
+		u32 c13_TID_PRIV;	/* Thread ID, Priveleged */
 	} cp15;
 
 	u32 virt_irq;		/* HCR exception mask */
@@ -78,6 +85,7 @@ struct kvm_vcpu_arch {
 	u32 hdfar;		/* Hyp Data Fault Address Register */
 	u32 hifar;		/* Hyp Inst. Fault Address Register */
 	u32 hpfar;		/* Hyp IPA Fault Address Register */
+	u64 pc_ipa;		/* IPA for the current PC (VA to PA result) */
 
 	/* IO related fields */
 	u32 mmio_rd;
arch/arm/kernel/armksyms.c +7 -0
index 5b0bce6..2a14b6e 100644
@@ -49,6 +49,13 @@ extern void __aeabi_ulcmp(void);
 
 extern void fpundefinstr(void);
 
+#ifdef CONFIG_KVM_ARM_HOST
+/* This is needed for KVM */
+extern void __irq_svc(void);
+
+EXPORT_SYMBOL_GPL(__irq_svc);
+#endif
+
 	/* platform dependent support */
 EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(__const_udelay);
arch/arm/kernel/asm-offsets.c +33 -0
index 1429d89..c126cfb 100644
@@ -16,6 +16,7 @@
 #include <asm/cacheflush.h>
 #include <asm/glue-df.h>
 #include <asm/glue-pf.h>
+#include <linux/kvm_host.h>
 #include <asm/mach/arch.h>
 #include <asm/thread_info.h>
 #include <asm/memory.h>
@@ -144,5 +145,37 @@ int main(void)
   DEFINE(DMA_BIDIRECTIONAL,	DMA_BIDIRECTIONAL);
   DEFINE(DMA_TO_DEVICE,		DMA_TO_DEVICE);
   DEFINE(DMA_FROM_DEVICE,	DMA_FROM_DEVICE);
+#ifdef CONFIG_KVM_ARM_HOST
+  DEFINE(VCPU_KVM,		offsetof(struct kvm_vcpu, kvm));
+  DEFINE(VCPU_MIDR,		offsetof(struct kvm_vcpu, arch.cp15.c0_MIDR));
+  DEFINE(VCPU_SCTLR,		offsetof(struct kvm_vcpu, arch.cp15.c1_SCTLR));
+  DEFINE(VCPU_CPACR,		offsetof(struct kvm_vcpu, arch.cp15.c1_CPACR));
+  DEFINE(VCPU_TTBR0,		offsetof(struct kvm_vcpu, arch.cp15.c2_TTBR0));
+  DEFINE(VCPU_TTBR1,		offsetof(struct kvm_vcpu, arch.cp15.c2_TTBR1));
+  DEFINE(VCPU_TTBCR,		offsetof(struct kvm_vcpu, arch.cp15.c2_TTBCR));
+  DEFINE(VCPU_DACR,		offsetof(struct kvm_vcpu, arch.cp15.c3_DACR));
+  DEFINE(VCPU_PRRR,		offsetof(struct kvm_vcpu, arch.cp15.c10_PRRR));
+  DEFINE(VCPU_NMRR,		offsetof(struct kvm_vcpu, arch.cp15.c10_NMRR));
+  DEFINE(VCPU_CID,		offsetof(struct kvm_vcpu, arch.cp15.c13_CID));
+  DEFINE(VCPU_TID_URW,		offsetof(struct kvm_vcpu, arch.cp15.c13_TID_URW));
+  DEFINE(VCPU_TID_URO,		offsetof(struct kvm_vcpu, arch.cp15.c13_TID_URO));
+  DEFINE(VCPU_TID_PRIV,		offsetof(struct kvm_vcpu, arch.cp15.c13_TID_PRIV));
+  DEFINE(VCPU_REGS,		offsetof(struct kvm_vcpu, arch.regs));
+  DEFINE(VCPU_USR_REGS,		offsetof(struct kvm_vcpu, arch.regs.usr_regs));
+  DEFINE(VCPU_SVC_REGS,		offsetof(struct kvm_vcpu, arch.regs.svc_regs));
+  DEFINE(VCPU_ABT_REGS,		offsetof(struct kvm_vcpu, arch.regs.abt_regs));
+  DEFINE(VCPU_UND_REGS,		offsetof(struct kvm_vcpu, arch.regs.und_regs));
+  DEFINE(VCPU_IRQ_REGS,		offsetof(struct kvm_vcpu, arch.regs.irq_regs));
+  DEFINE(VCPU_FIQ_REGS,		offsetof(struct kvm_vcpu, arch.regs.fiq_regs));
+  DEFINE(VCPU_PC,		offsetof(struct kvm_vcpu, arch.regs.pc));
+  DEFINE(VCPU_CPSR,		offsetof(struct kvm_vcpu, arch.regs.cpsr));
+  DEFINE(VCPU_VIRT_IRQ,		offsetof(struct kvm_vcpu, arch.virt_irq));
+  DEFINE(VCPU_HSR,		offsetof(struct kvm_vcpu, arch.hsr));
+  DEFINE(VCPU_HDFAR,		offsetof(struct kvm_vcpu, arch.hdfar));
+  DEFINE(VCPU_HIFAR,		offsetof(struct kvm_vcpu, arch.hifar));
+  DEFINE(VCPU_HPFAR,		offsetof(struct kvm_vcpu, arch.hpfar));
+  DEFINE(VCPU_PC_IPA,		offsetof(struct kvm_vcpu, arch.pc_ipa));
+  DEFINE(KVM_VTTBR,		offsetof(struct kvm, arch.vttbr));
+#endif
   return 0; 
 }
arch/arm/kernel/entry-armv.S +1 -0
index 3a456c6..aaa557b 100644
@@ -206,6 +206,7 @@ __dabt_svc:
 ENDPROC(__dabt_svc)
 
 	.align	5
+	.globl __irq_svc
 __irq_svc:
 	svc_entry
 	irq_handler
arch/arm/kvm/arm.c +42 -3

59 lines not on this page · raw message

arch/arm/kvm/guest.c +2 -0
index 94a5c54..3a23bee 100644
@@ -73,6 +73,7 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 	/*
 	 * Co-processor registers.
 	 */
+	regs->cp15.c0_midr = vcpu->arch.cp15.c0_MIDR;
 	regs->cp15.c1_sys = vcpu->arch.cp15.c1_SCTLR;
 	regs->cp15.c2_base0 = vcpu->arch.cp15.c2_TTBR0;
 	regs->cp15.c2_base1 = vcpu->arch.cp15.c2_TTBR1;
@@ -111,6 +112,7 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 	/*
 	 * Co-processor registers.
 	 */
+	vcpu->arch.cp15.c0_MIDR = regs->cp15.c0_midr;
 	vcpu->arch.cp15.c1_SCTLR = regs->cp15.c1_sys;
 
 	vcpu_regs->pc = regs->reg15;
arch/arm/kvm/interrupts.S +442 -1

466 lines not on this page · raw message

#39 lore raw

PATCH v5 7/13 ARM: KVM: Emulation framework and CP15 emulation

In reply to Christoffer Dall

From: Christoffer Dall <[email protected]>

Adds a new important function in the main KVM/ARM code called handle_exit() which is called from kvm_arch_vcpu_ioctl_run() on returns from guest execution. This function examines the Hyp-Syndrome-Register (HSR), which contains information telling KVM what caused the exit from the guest.

Some of the reasons for an exit are CP15 accesses, which are not allowed from the guest and this commits handles these exits by emulating the intented operation in software and skip the guest instruction.

---
 arch/arm/include/asm/kvm_emulate.h |    7 +
 arch/arm/kvm/arm.c                 |   77 ++++++++++++++
 arch/arm/kvm/emulate.c             |  195 ++++++++++++++++++++++++++++++++++++
 arch/arm/kvm/trace.h               |   28 +++++
 4 files changed, 307 insertions(+), 0 deletions(-)
arch/arm/include/asm/kvm_emulate.h +7 -0
index 91d461a..af21fd5 100644
@@ -40,6 +40,13 @@ static inline unsigned char vcpu_mode(struct kvm_vcpu *vcpu)
 	return modes_table[vcpu->arch.regs.cpsr & 0xf];
 }
 
+int kvm_handle_cp10_id(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_cp_0_13_access(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_cp15_access(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run);
+
 /*
  * Return the SPSR for the specified mode of the virtual CPU.
  */
arch/arm/kvm/arm.c +77 -0

95 lines not on this page · raw message

arch/arm/kvm/emulate.c +195 -0

205 lines not on this page · raw message

arch/arm/kvm/trace.h +28 -0
index ac64e3a..381ea4a 100644
@@ -39,6 +39,34 @@ TRACE_EVENT(kvm_exit,
 	TP_printk("PC: 0x%08lx", __entry->vcpu_pc)
 );
 
+TRACE_EVENT(kvm_emulate_cp15_imp,
+	TP_PROTO(unsigned long Op1, unsigned long Rt1, unsigned long CRn,
+		 unsigned long CRm, unsigned long Op2, bool is_write),
+	TP_ARGS(Op1, Rt1, CRn, CRm, Op2, is_write),
+
+	TP_STRUCT__entry(
+		__field(	unsigned int,	Op1		)
+		__field(	unsigned int,	Rt1		)
+		__field(	unsigned int,	CRn		)
+		__field(	unsigned int,	CRm		)
+		__field(	unsigned int,	Op2		)
+		__field(	bool,		is_write	)
+	),
+
+	TP_fast_assign(
+		__entry->is_write		= is_write;
+		__entry->Op1			= Op1;
+		__entry->Rt1			= Rt1;
+		__entry->CRn			= CRn;
+		__entry->CRm			= CRm;
+		__entry->Op2			= Op2;
+	),
+
+	TP_printk("Implementation defined CP15: %s\tp15, %u, r%u, c%u, c%u, %u",
+			(__entry->is_write) ? "mcr" : "mrc",
+			__entry->Op1, __entry->Rt1, __entry->CRn,
+			__entry->CRm, __entry->Op2)
+);
 
 TRACE_EVENT(kvm_irq_line,
 	TP_PROTO(unsigned int type, unsigned int level, unsigned int vcpu_idx),
#42 lore raw

PATCH v5 8/13 ARM: KVM: Handle guest faults in KVM

In reply to Christoffer Dall

From: Christoffer Dall <[email protected]>

Handles the guest faults in KVM by mapping in corresponding user pages in the 2nd stage page tables.

Introduces new ARM-specific kernel memory types, PAGE_KVM_GUEST and pgprot_guest variables used to map 2nd stage memory for KVM guests.

---
 arch/arm/include/asm/pgtable-3level.h |    8 ++
 arch/arm/include/asm/pgtable.h        |    4 +
 arch/arm/kvm/mmu.c                    |  107 ++++++++++++++++++++++++++++++++-
 arch/arm/mm/mmu.c                     |    3 +
 4 files changed, 120 insertions(+), 2 deletions(-)
arch/arm/include/asm/pgtable-3level.h +8 -0
index edc3cb9..6dc5331 100644
@@ -104,6 +104,14 @@
  */
 #define L_PGD_SWAPPER		(_AT(pgdval_t, 1) << 55)	/* swapper_pg_dir entry */
 
+/*
+ * 2-nd stage PTE definitions for LPAE.
+ */
+#define L_PTE2_READ		(_AT(pteval_t, 1) << 6)	/* HAP[0] */
+#define L_PTE2_WRITE		(_AT(pteval_t, 1) << 7)	/* HAP[1] */
+#define L_PTE2_NORM_WB		(_AT(pteval_t, 3) << 4)	/* MemAttr[3:2] */
+#define L_PTE2_INNER_WB		(_AT(pteval_t, 3) << 2)	/* MemAttr[1:0] */
+
 #ifndef __ASSEMBLY__
 
 #define pud_none(pud)		(!pud_val(pud))
arch/arm/include/asm/pgtable.h +4 -0
index 20025cc..778856b 100644
@@ -76,6 +76,7 @@ extern void __pgd_error(const char *file, int line, pgd_t);
 
 extern pgprot_t		pgprot_user;
 extern pgprot_t		pgprot_kernel;
+extern pgprot_t		pgprot_guest;
 
 #define _MOD_PROT(p, b)	__pgprot(pgprot_val(p) | (b))
 
@@ -89,6 +90,9 @@ extern pgprot_t		pgprot_kernel;
 #define PAGE_KERNEL		_MOD_PROT(pgprot_kernel, L_PTE_XN)
 #define PAGE_KERNEL_EXEC	pgprot_kernel
 #define PAGE_HYP		_MOD_PROT(pgprot_kernel, L_PTE_USER)
+#define PAGE_KVM_GUEST		_MOD_PROT(pgprot_guest, L_PTE2_READ | \
+					  L_PTE2_WRITE | L_PTE2_NORM_WB | \
+					  L_PTE2_INNER_WB)
 
 #define __PAGE_NONE		__pgprot(_L_PTE_DEFAULT | L_PTE_RDONLY | L_PTE_XN)
 #define __PAGE_SHARED		__pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_XN)
arch/arm/kvm/mmu.c +105 -2

113 lines not on this page · raw message

arch/arm/mm/mmu.c +3 -0
index b836d6b..1aa6e2c 100644
@@ -53,9 +53,11 @@ static unsigned int cachepolicy __initdata = CPOLICY_WRITEBACK;
 static unsigned int ecc_mask __initdata = 0;
 pgprot_t pgprot_user;
 pgprot_t pgprot_kernel;
+pgprot_t pgprot_guest;
 
 EXPORT_SYMBOL(pgprot_user);
 EXPORT_SYMBOL(pgprot_kernel);
+EXPORT_SYMBOL(pgprot_guest);
 
 struct cachepolicy {
 	const char	policy[16];
@@ -503,6 +505,7 @@ static void __init build_mem_type_table(void)
 	pgprot_user   = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | user_pgprot);
 	pgprot_kernel = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
 				 L_PTE_DIRTY | kern_pgprot);
+	pgprot_guest  = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG);
 
 	mem_types[MT_LOW_VECTORS].prot_l1 |= ecc_mask;
 	mem_types[MT_HIGH_VECTORS].prot_l1 |= ecc_mask;
#51 lore raw

PATCH v5 9/13 ARM: KVM: Handle I/O aborts

In reply to Christoffer Dall

From: Christoffer Dall <[email protected]>

When the guest accesses I/O memory this will create data abort exceptions and they are handled by decoding the HSR information (physical address, read/write, length, register) and forwarding reads and writes to QEMU which performs the device emulation.

Certain classes of load/store operations do not support the syndrome information provided in the HSR and we therefore must be able to fetch the offending instruction from guest memory and decode it manually.

This requires changing the general flow somewhat since new calls to run the VCPU must check if there's a pending MMIO load and perform the write after userspace has made the data available.

---
 arch/arm/include/asm/kvm_emulate.h |    2 
 arch/arm/include/asm/kvm_host.h    |    1 
 arch/arm/include/asm/kvm_mmu.h     |    1 
 arch/arm/kvm/arm.c                 |    8 +
 arch/arm/kvm/emulate.c             |  288 ++++++++++++++++++++++++++++++++++++
 arch/arm/kvm/mmu.c                 |  155 +++++++++++++++++++
 arch/arm/kvm/trace.h               |   22 +++
 7 files changed, 470 insertions(+), 7 deletions(-)
arch/arm/include/asm/kvm_emulate.h +2 -0
index af21fd5..9899474 100644
@@ -46,6 +46,8 @@ int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run);
 int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run);
 int kvm_handle_cp15_access(struct kvm_vcpu *vcpu, struct kvm_run *run);
 int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_emulate_mmio_ls(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
+			unsigned long instr);
 
 /*
  * Return the SPSR for the specified mode of the virtual CPU.
arch/arm/include/asm/kvm_host.h +1 -0
index 59fcd15..86f6cf1 100644
@@ -88,6 +88,7 @@ struct kvm_vcpu_arch {
 	u64 pc_ipa;		/* IPA for the current PC (VA to PA result) */
 
 	/* IO related fields */
+	bool mmio_sign_extend;	/* for byte/halfword loads */
 	u32 mmio_rd;
 
 	/* Misc. fields */
arch/arm/include/asm/kvm_mmu.h +1 -0
index 9d7440c..e82eae9 100644
@@ -35,6 +35,7 @@ void free_hyp_pmds(pgd_t *hyp_pgd);
 int kvm_alloc_stage2_pgd(struct kvm *kvm);
 void kvm_free_stage2_pgd(struct kvm *kvm);
 
+int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
 int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run);
 
 #endif /* __ARM_KVM_MMU_H__ */
arch/arm/kvm/arm.c +8 -0
index a6e1763..e5348a7 100644
@@ -379,6 +379,14 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 	int ret;
 
 	for (;;) {
+		if (run->exit_reason == KVM_EXIT_MMIO) {
+			ret = kvm_handle_mmio_return(vcpu, vcpu->run);
+			if (ret)
+				break;
+		}
+
+		run->exit_reason = KVM_EXIT_UNKNOWN;
+
 		trace_kvm_entry(vcpu->arch.regs.pc);
 
 		local_irq_disable();
arch/arm/kvm/emulate.c +284 -4

310 lines not on this page · raw message

arch/arm/kvm/mmu.c +152 -3

177 lines not on this page · raw message

arch/arm/kvm/trace.h +22 -0
index 381ea4a..8ba3db9 100644
@@ -39,6 +39,28 @@ TRACE_EVENT(kvm_exit,
 	TP_printk("PC: 0x%08lx", __entry->vcpu_pc)
 );
 
+TRACE_EVENT(kvm_mmio_emulate,
+	TP_PROTO(unsigned long vcpu_pc, unsigned long instr,
+		 unsigned long cpsr),
+	TP_ARGS(vcpu_pc, instr, cpsr),
+
+	TP_STRUCT__entry(
+		__field(	unsigned long,	vcpu_pc		)
+		__field(	unsigned long,	instr		)
+		__field(	unsigned long,	cpsr		)
+	),
+
+	TP_fast_assign(
+		__entry->vcpu_pc		= vcpu_pc;
+		__entry->vcpu_pc		= instr;
+		__entry->vcpu_pc		= cpsr;
+	),
+
+	TP_printk("Emulate MMIO at: 0x%08lx (instr: %08lx, cpsr: %08lx)",
+		  __entry->vcpu_pc, __entry->instr, __entry->cpsr)
+);
+
+/* Architecturally implementation defined CP15 register access */
 TRACE_EVENT(kvm_emulate_cp15_imp,
 	TP_PROTO(unsigned long Op1, unsigned long Rt1, unsigned long CRn,
 		 unsigned long CRm, unsigned long Op2, bool is_write),
#54 lore raw

PATCH v5 10/13 ARM: KVM: Guest wait-for-interrupts (WFI) support

In reply to Christoffer Dall

From: Christoffer Dall <[email protected]>

When the guest executes a WFI instruction the operation is trapped to KVM, which emulates the instruction in software. There is no correlation between a guest executing a WFI instruction and actually puttin the hardware into a low-power mode, since a KVM guest is essentially a process and the WFI instruction can be seen as 'sleep' call from this process. Therefore, we flag the VCPU to be in wait_for_interrupts mode and call the main KVM function kvm_vcpu_block() function. This function will put the thread on a wait-queue and call schedule.

When an interrupt comes in through KVM_IRQ_LINE (see previous patch) we signal the VCPU thread and unflag the VCPU to no longer wait for interrupts. All calls to kvm_arch_vcpu_ioctl_run() result in a call to kvm_vcpu_block() as long as the VCPU is in wfi-mode.

---
 arch/arm/kvm/arm.c     |   33 ++++++++++++++++++++++++---------
 arch/arm/kvm/emulate.c |   12 ++++++++++++
 arch/arm/kvm/trace.h   |   15 +++++++++++++++
 3 files changed, 51 insertions(+), 9 deletions(-)
arch/arm/kvm/arm.c +24 -9
index e5348a7..00215a1 100644
@@ -302,9 +302,16 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
 	return -EINVAL;
 }
 
+/**
+ * kvm_arch_vcpu_runnable - determine if the vcpu can be scheduled
+ * @v:		The VCPU pointer
+ *
+ * If the guest CPU is not waiting for interrupts then it is by definition
+ * runnable.
+ */
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
 {
-	return 0;
+	return !v->arch.wait_for_interrupts;
 }
 
 static inline int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
@@ -379,6 +386,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 	int ret;
 
 	for (;;) {
+		if (vcpu->arch.wait_for_interrupts)
+			goto wait_for_interrupts;
+
 		if (run->exit_reason == KVM_EXIT_MMIO) {
 			ret = kvm_handle_mmio_return(vcpu, vcpu->run);
 			if (ret)
@@ -408,16 +418,19 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		if (run->exit_reason == KVM_EXIT_MMIO)
 			break;
 
-		if (need_resched()) {
-			vcpu_put(vcpu);
-			schedule();
-			vcpu_load(vcpu);
-		}
-
-		if (signal_pending(current) && !(run->exit_reason)) {
-			run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
+		if (need_resched())
+			kvm_resched(vcpu);
+wait_for_interrupts:
+		if (signal_pending(current)) {
+			if (!run->exit_reason) {
+				ret = -EINTR;
+				run->exit_reason = KVM_EXIT_INTR;
+			}
 			break;
 		}
+
+		if (vcpu->arch.wait_for_interrupts)
+			kvm_vcpu_block(vcpu);
 	}
 
 	return ret;
@@ -454,6 +467,8 @@ static int kvm_arch_vm_ioctl_irq_line(struct kvm *kvm,
 	if (irq_level->level) {
 		vcpu->arch.virt_irq |= mask;
 		vcpu->arch.wait_for_interrupts = 0;
+		if (waitqueue_active(&vcpu->wq))
+			wake_up_interruptible(&vcpu->wq);
 	} else
 		vcpu->arch.virt_irq &= ~mask;
 
arch/arm/kvm/emulate.c +12 -0
index 4fb5a7d..f60c75a 100644
@@ -335,8 +335,20 @@ unsupp_err_out:
 	return -EINVAL;
 }
 
+/**
+ * kvm_handle_wfi - handle a wait-for-interrupts instruction executed by a guest
+ * @vcpu:	the vcpu pointer
+ * @run:	the kvm_run structure pointer
+ *
+ * Simply sets the wait_for_interrupts flag on the vcpu structure, which will
+ * halt execution of world-switches and schedule other host processes until
+ * there is an incoming IRQ or FIQ to the VM.
+ */
 int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
+	trace_kvm_wfi(vcpu->arch.regs.pc);
+	if (!vcpu->arch.virt_irq)
+		vcpu->arch.wait_for_interrupts = 1;
 	return 0;
 }
 
arch/arm/kvm/trace.h +15 -0
index 8ba3db9..693da82 100644
@@ -111,6 +111,21 @@ TRACE_EVENT(kvm_irq_line,
 		__entry->level, __entry->vcpu_idx)
 );
 
+TRACE_EVENT(kvm_wfi,
+	TP_PROTO(unsigned long vcpu_pc),
+	TP_ARGS(vcpu_pc),
+
+	TP_STRUCT__entry(
+		__field(	unsigned long,	vcpu_pc		)
+	),
+
+	TP_fast_assign(
+		__entry->vcpu_pc		= vcpu_pc;
+	),
+
+	TP_printk("guest executed wfi at: 0x%08lx", __entry->vcpu_pc)
+);
+
 
 #endif /* _TRACE_KVM_H */
 
#60 lore raw

PATCH v5 11/13 ARM: KVM: Support SMP hosts

In reply to Christoffer Dall

In order to support KVM on a SMP host, it is necessary to initialize the hypervisor on all CPUs, mostly by making sure each CPU gets its own hypervisor stack and runs the HYP init code.

We also take care of some missing locking of modifications to the hypervisor page tables and ensure synchronized consistency between virtual IRQ masks and wait_for_interrupt flags on the VPUs.

Note that this code doesn't handle CPU hotplug yet. Note that this code doesn't support SMP guests.

WARNING: This code is in development and guests do not fully boot on SMP hosts yet.

---
 arch/arm/include/asm/kvm_host.h |    4 -
 arch/arm/include/asm/kvm_mmu.h  |    1 
 arch/arm/kvm/arm.c              |  175 +++++++++++++++++++++++----------------
 arch/arm/kvm/emulate.c          |    2 
 arch/arm/kvm/mmu.c              |    9 ++
 5 files changed, 114 insertions(+), 77 deletions(-)
arch/arm/include/asm/kvm_host.h +2 -2
index 86f6cf1..a0ffbe8 100644
@@ -78,8 +78,6 @@ struct kvm_vcpu_arch {
 		u32 c13_TID_PRIV;	/* Thread ID, Priveleged */
 	} cp15;
 
-	u32 virt_irq;		/* HCR exception mask */
-
 	/* Exception Information */
 	u32 hsr;		/* Hyp Syndrom Register */
 	u32 hdfar;		/* Hyp Data Fault Address Register */
@@ -92,6 +90,8 @@ struct kvm_vcpu_arch {
 	u32 mmio_rd;
 
 	/* Misc. fields */
+	spinlock_t irq_lock;
+	u32 virt_irq;		/* HCR exception mask */
 	u32 wait_for_interrupts;
 };
 
arch/arm/include/asm/kvm_mmu.h +1 -0
index e82eae9..917edd7 100644
@@ -28,6 +28,7 @@
 #define PGD2_ORDER	get_order(PTRS_PER_PGD2 * sizeof(pgd_t))
 
 extern pgd_t *kvm_hyp_pgd;
+extern struct mutex kvm_hyp_pgd_mutex;
 
 int create_hyp_mappings(pgd_t *hyp_pgd, void *from, void *to);
 void free_hyp_pmds(pgd_t *hyp_pgd);
arch/arm/kvm/arm.c +101 -74

254 lines not on this page · raw message

arch/arm/kvm/emulate.c +2 -0
index f60c75a..3cb2fe4 100644
@@ -347,8 +347,10 @@ unsupp_err_out:
 int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
 	trace_kvm_wfi(vcpu->arch.regs.pc);
+	spin_lock(&vcpu->arch.irq_lock);
 	if (!vcpu->arch.virt_irq)
 		vcpu->arch.wait_for_interrupts = 1;
+	spin_unlock(&vcpu->arch.irq_lock);
 	return 0;
 }
 
arch/arm/kvm/mmu.c +8 -1
index 7732c48..50c9571 100644
@@ -26,6 +26,7 @@
 #include "debug.h"
 
 pgd_t *kvm_hyp_pgd;
+DEFINE_MUTEX(kvm_hyp_pgd_mutex);
 
 static void free_ptes(pmd_t *pmd, unsigned long addr)
 {
@@ -55,6 +56,7 @@ void free_hyp_pmds(pgd_t *hyp_pgd)
 	pmd_t *pmd;
 	unsigned long addr, next, end;
 
+	mutex_lock(&kvm_hyp_pgd_mutex);
 	addr = PAGE_OFFSET;
 	end = ~0;
 	do {
@@ -71,6 +73,7 @@ void free_hyp_pmds(pgd_t *hyp_pgd)
 		free_ptes(pmd, addr);
 		pmd_free(NULL, pmd);
 	} while (addr = next, addr != end);
+	mutex_unlock(&kvm_hyp_pgd_mutex);
 }
 
 static void create_hyp_pte_mappings(pmd_t *pmd, unsigned long addr,
@@ -140,6 +143,7 @@ int create_hyp_mappings(pgd_t *hyp_pgd, void *from, void *to)
 	if (start < PAGE_OFFSET)
 		return -EINVAL;
 
+	mutex_lock(&kvm_hyp_pgd_mutex);
 	addr = start;
 	do {
 		next = pgd_addr_end(addr, end);
@@ -150,7 +154,8 @@ int create_hyp_mappings(pgd_t *hyp_pgd, void *from, void *to)
 			pmd = pmd_alloc_one(NULL, addr);
 			if (!pmd) {
 				kvm_err(-ENOMEM, "Cannot allocate Hyp pmd");
-				return -ENOMEM;
+				err = -ENOMEM;
+				goto out;
 			}
 			pud_populate(NULL, pud, pmd);
 		}
@@ -160,6 +165,8 @@ int create_hyp_mappings(pgd_t *hyp_pgd, void *from, void *to)
 			return err;
 	} while (addr = next, addr < end);
 
+out:
+	mutex_unlock(&kvm_hyp_pgd_mutex);
 	return err;
 }
 
#84 lore raw

PATCH v5 12/13 ARM: KVM: Fix guest view of MPIDR

In reply to Christoffer Dall

From: Marc Zyngier <[email protected]>

A guest may need to know which CPU it has booted on (and Linux does). Now that we can run KVM on a SMP host, QEMU may be running on any CPU. In that case, directly reading MPIDR will give an inconsistent view on the guest CPU number (among other problems).

The solution is to use the VMPIDR register, which is computed by using the host MPIDR and overriding the low bits with KVM vcpu_id.

---
 arch/arm/include/asm/kvm_host.h |    1 +
 arch/arm/kernel/asm-offsets.c   |    1 +
 arch/arm/kvm/arm.c              |    4 ++++
 arch/arm/kvm/interrupts.S       |    8 ++++++++
 4 files changed, 14 insertions(+), 0 deletions(-)
arch/arm/include/asm/kvm_host.h +1 -0
index a0ffbe8..7fcc412 100644
@@ -63,6 +63,7 @@ struct kvm_vcpu_arch {
 	/* System control coprocessor (cp15) */
 	struct {
 		u32 c0_MIDR;		/* Main ID Register */
+		u32 c0_MPIDR;		/* MultiProcessor ID Register */
 		u32 c1_SCTLR;		/* System Control Register */
 		u32 c1_ACTLR;		/* Auxilliary Control Register */
 		u32 c1_CPACR;		/* Coprocessor Access Control */
arch/arm/kernel/asm-offsets.c +1 -0
index c126cfb..1c6e2ee 100644
@@ -148,6 +148,7 @@ int main(void)
 #ifdef CONFIG_KVM_ARM_HOST
   DEFINE(VCPU_KVM,		offsetof(struct kvm_vcpu, kvm));
   DEFINE(VCPU_MIDR,		offsetof(struct kvm_vcpu, arch.cp15.c0_MIDR));
+  DEFINE(VCPU_MPIDR,		offsetof(struct kvm_vcpu, arch.cp15.c0_MPIDR));
   DEFINE(VCPU_SCTLR,		offsetof(struct kvm_vcpu, arch.cp15.c1_SCTLR));
   DEFINE(VCPU_CPACR,		offsetof(struct kvm_vcpu, arch.cp15.c1_CPACR));
   DEFINE(VCPU_TTBR0,		offsetof(struct kvm_vcpu, arch.cp15.c2_TTBR0));
arch/arm/kvm/arm.c +4 -0
index 6e384e2..9c5c38e 100644
@@ -32,6 +32,7 @@
 #include <asm/ptrace.h>
 #include <asm/mman.h>
 #include <asm/tlbflush.h>
+#include <asm/cputype.h>
 #include <asm/kvm_arm.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_mmu.h>
@@ -270,6 +271,9 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 			[sctlr] "=r" (sctlr));
 	vcpu->arch.cp15.c1_SCTLR = sctlr & ~1U;
 
+	/* Compute guest MPIDR */
+	vcpu->arch.cp15.c0_MPIDR = (read_cpuid_mpidr() & ~0xff) | vcpu->vcpu_id;
+
 	return 0;
 }
 
arch/arm/kvm/interrupts.S +8 -0
index d516bf4..fbc26ca 100644
@@ -245,6 +245,10 @@ ENTRY(__kvm_vcpu_run)
 	ldr	r1, [r0, #VCPU_MIDR]
 	mcr	p15, 4, r1, c0, c0, 0
 
+	@ Write guest view of MPIDR into VMPIDR
+	ldr	r1, [r0, #VCPU_MPIDR]
+	mcr	p15, 4, r1, c0, c0, 5
+
 	@ Load guest registers
 	add	r0, r0, #(VCPU_USR_SP)
 	load_mode_state r0, usr
@@ -291,6 +295,10 @@ __kvm_vcpu_return:
 	mrc	p15, 0, r2, c0, c0, 0
 	mcr	p15, 4, r2, c0, c0, 0
 
+	@ Back to hardware MPIDR
+	mrc	p15, 0, r2, c0, c0, 5
+	mcr	p15, 4, r2, c0, c0, 5
+
 	@ Set VMID == 0
 	mov	r2, #0
 	mov	r3, #0
#91 lore raw

PATCH v5 13/13 ARM: KVM: Support SMP guests

In reply to Christoffer Dall

This patch is a beginning attempt to support SMP guests. So far we only add locking for the second stage PGD stored on the kvm_arch struct.

WARNING: This code is untested and does not yet support SMP guests.

---
 arch/arm/include/asm/kvm_host.h |   12 ++++++--
 arch/arm/kvm/arm.c              |    1 +
 arch/arm/kvm/mmu.c              |   57 +++++++++++++++++++++++++--------------
 3 files changed, 47 insertions(+), 23 deletions(-)
arch/arm/include/asm/kvm_host.h +9 -3
index 7fcc412..555a6f1 100644
@@ -31,9 +31,15 @@ struct kvm_vcpu;
 u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
 
 struct kvm_arch {
-	u32    vmid;	/* The VMID used for the virt. memory system */
-	pgd_t *pgd;	/* 1-level 2nd stage table */
-	u64    vttbr;	/* VTTBR value associated with above pgd and vmid */
+	/* The VMID used for the virt. memory system */
+	u32    vmid;
+
+	/* 1-level 2nd stage table and lock */
+	struct mutex pgd_mutex;
+	pgd_t *pgd;
+
+	/* VTTBR value associated with above pgd and vmid */
+	u64    vttbr;
 };
 
 #define EXCEPTION_NONE      0
arch/arm/kvm/arm.c +1 -0
index 9c5c38e..14ccc4d 100644
@@ -119,6 +119,7 @@ int kvm_arch_init_vm(struct kvm *kvm)
 	ret = kvm_alloc_stage2_pgd(kvm);
 	if (ret)
 		goto out_fail_alloc;
+	mutex_init(&kvm->arch.pgd_mutex);
 
 	pgd_phys = virt_to_phys(kvm->arch.pgd);
 	kvm->arch.vttbr = pgd_phys & ((1LLU << 40) - 1) & ~((2 << VTTBR_X) - 1);
arch/arm/kvm/mmu.c +37 -20

104 lines not on this page · raw message

#92 lore raw
In reply to Christoffer Dall
Quoted 10 lines · Christoffer Dall

The following series implements KVM support for ARM processors, specifically on the Cortex A-15 platform.

Still on the to-do list:
 - Reuse VMIDs
 - Fix SMP host support
 - Fix SMP guest support
 - Support guest Thumb mode for MMIO emulation
 - Further testing
 - Performance improvements

Other items for this list:
- Support Neon/VFP in guests (the fpu regs struct is empty ATM)
- Support guest debugging

I couldn't see any support for the TLS registers in your cp15 emulation:
did I miss it, or do we handle it without needing to trap?

-- PMM

#14 lore raw

Re: [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

In reply to Christoffer Dall

Just found two, maybe three nits while browsing by:

Quoted 49 lines · Christoffer Dall

Userspace can inject IRQs and FIQs through the KVM_IRQ_LINE VM ioctl. This ioctl is used since the sematics are in fact two lines that can be either raised or lowered on the VCPU - the IRQ and FIQ lines.

KVM needs to know which VCPU it must operate on and whether the FIQ or IRQ line is raised/lowered. Hence both pieces of information is packed in the kvm_irq_level->irq field. The irq fild value will be:
IRQ: vcpu_index * 2
FIQ: (vcpu_index * 2) + 1

This is documented in Documentation/kvm/api.txt.

The effect of the ioctl is simply to simply raise/lower the corresponding virt_irq field on the VCPU struct, which will cause the world-switch code to raise/lower virtual interrupts when running the guest on next switch. The wait_for_interrupt flag is also cleared for raised IRQs causing an idle VCPU to become active again.

Note: The custom trace_kvm_irq_line is used despite a generic definition of trace_kvm_set_irq, since the trace-Kvm_set_irq depends on the x86-specific define of __HAVE_IOAPIC. Either the trace event should be created regardless of this define or it should depend on another ifdef clause, common for both x86 and ARM. However, since the arguments don't really match those used in ARM, I am yet to be convinced why this is necessary.

---
 Documentation/virtual/kvm/api.txt |   10 ++++++-
 arch/arm/include/asm/kvm.h        |    8 ++++++
 arch/arm/include/asm/kvm_arm.h    |    1 +
 arch/arm/kvm/arm.c                |   53 ++++++++++++++++++++++++++++++++++++-
 arch/arm/kvm/trace.h              |   21 +++++++++++++++
 include/linux/kvm.h               |    1 +
 6 files changed, 91 insertions(+), 3 deletions(-)
Documentation/virtual/kvm/api.txt +1 -1
index 7945b0b..4abaa67 100644
@@ -572,7 +572,7 @@ only go to the IOAPIC.  On ia64, a IOSAPIC is created.
 4.25 KVM_IRQ_LINE
 
 Capability: KVM_CAP_IRQCHIP
-Architectures: x86, ia64
+Architectures: x86, ia64, arm
 Type: vm ioctl
 Parameters: struct kvm_irq_level
 Returns: 0 on success, -1 on error

Documentation/virtual/kvm/api.txt Requires that an interrupt controller model has been previously created with · line 586

Quoted 5 lines
Documentation/virtual/kvm/api.txt +2 -0
@@ -582,6 +582,14 @@ Requires that an interrupt controller model has been previously created with
 KVM_CREATE_IRQCHIP.  Note that edge-triggered interrupts require the level
 to be set to 1 and then back to 0.
 
+KVM_CREATE_IRQCHIP (except for ARM).  Note that edge-triggered interrupts
+require the level to be set to 1 and then back to 0.

You probably wanted to replace the original lines with these two, no?

Quoted 62 lines
Documentation/virtual/kvm/api.txt +6 -0
+
+ARM uses two types of interrupt lines per CPU, ie. IRQ and FIQ. The value of the
+irq field should be (VCPU_INDEX * 2) for IRQs and ((VCPU_INDEX * 2) + 1) for
+FIQs. Level is used to raise/lower the line. See arch/arm/include/asm/kvm.h for
+convenience macros.
+
 struct kvm_irq_level {
 	union {
 		__u32 irq;     /* GSI */
arch/arm/include/asm/kvm.h +8 -0
index 87dc33b..8935062 100644
@@ -20,6 +20,14 @@
 #include <asm/types.h>
 
 /*
+ * KVM_IRQ_LINE macros to set/read IRQ/FIQ for specific VCPU index.
+ */
+enum KVM_ARM_IRQ_LINE_TYPE {
+	KVM_ARM_IRQ_LINE = 0,
+	KVM_ARM_FIQ_LINE = 1,
+};
+
+/*
  * Modes used for short-hand mode determinition in the world-switch code and
  * in emulation code.
  *
arch/arm/include/asm/kvm_arm.h +1 -0
index 835abd1..e378a37 100644
@@ -49,6 +49,7 @@
 #define HCR_VM		1
 #define HCR_GUEST_MASK (HCR_TSC | HCR_TWE | HCR_TWI | HCR_VM | HCR_AMO | \
 			HCR_AMO | HCR_IMO | HCR_FMO | HCR_SWIO)
+#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
 
 /* Hyp System Control Register (HSCTLR) bits */
 #define HSCTLR_TE	(1 << 30)
arch/arm/kvm/arm.c +14 -0
index 89ba18d..fc0bd6b 100644
@@ -299,6 +299,43 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 	return -EINVAL;
 }
 
+static int kvm_arch_vm_ioctl_irq_line(struct kvm *kvm,
+				      struct kvm_irq_level *irq_level)
+{
+	u32 mask;
+	unsigned int vcpu_idx;
+	struct kvm_vcpu *vcpu;
+
+	vcpu_idx = irq_level->irq / 2;
+	if (vcpu_idx >= KVM_MAX_VCPUS)
+		return -EINVAL;
+
+	vcpu = kvm_get_vcpu(kvm, vcpu_idx);
+	if (!vcpu)
+		return -EINVAL;

arch/arm/kvm/arm.c int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) · line 325

Quoted 10 lines
arch/arm/kvm/arm.c +10 -0
+
+	switch (irq_level->irq % 2) {
+	case KVM_ARM_IRQ_LINE:
+		mask = HCR_VI;
+		break;
+	case KVM_ARM_FIQ_LINE:
+		mask = HCR_VF;
+		break;
+	default:
+		return -EINVAL;

Due to % 2, default is unreachable. Remove the masking?

arch/arm/kvm/arm.c int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) · line 334

Quoted 9 lines
arch/arm/kvm/arm.c +9 -0
+	}
+
+	trace_kvm_irq_line(irq_level->irq % 2, irq_level->level, vcpu_idx);
+
+	if (irq_level->level) {
+		vcpu->arch.virt_irq |= mask;
+		vcpu->arch.wait_for_interrupts = 0;
+	} else
+		vcpu->arch.virt_irq &= ~mask;

No need to protect the bitops on virt_irq? Or what lock does this?

Quoted 76 lines
arch/arm/kvm/arm.c +18 -2
+
+	return 0;
+}
+
 long kvm_arch_vcpu_ioctl(struct file *filp,
 			 unsigned int ioctl, unsigned long arg)
 {
@@ -313,8 +350,20 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
 long kvm_arch_vm_ioctl(struct file *filp,
 		       unsigned int ioctl, unsigned long arg)
 {
-	printk(KERN_ERR "kvm_arch_vm_ioctl: Unsupported ioctl (%d)\n", ioctl);
-	return -EINVAL;
+	struct kvm *kvm = filp->private_data;
+	void __user *argp = (void __user *)arg;
+
+	switch (ioctl) {
+	case KVM_IRQ_LINE: {
+		struct kvm_irq_level irq_event;
+
+		if (copy_from_user(&irq_event, argp, sizeof irq_event))
+			return -EFAULT;
+		return kvm_arch_vm_ioctl_irq_line(kvm, &irq_event);
+	}
+	default:
+		return -EINVAL;
+	}
 }
 
 /**
arch/arm/kvm/trace.h +21 -0
index f8869c1..ac64e3a 100644
@@ -40,6 +40,27 @@ TRACE_EVENT(kvm_exit,
 );
 
 
+TRACE_EVENT(kvm_irq_line,
+	TP_PROTO(unsigned int type, unsigned int level, unsigned int vcpu_idx),
+	TP_ARGS(type, level, vcpu_idx),
+
+	TP_STRUCT__entry(
+		__field(	unsigned int,	type			)
+		__field(	unsigned int,	level			)
+		__field(	unsigned int,	vcpu_idx		)
+	),
+
+	TP_fast_assign(
+		__entry->type			= type;
+		__entry->level			= level;
+		__entry->vcpu_idx		= vcpu_idx;
+	),
+
+	TP_printk("KVM_IRQ_LINE: type: %s, level: %u, vcpu: %u",
+		(__entry->type == KVM_ARM_IRQ_LINE) ? "IRQ" : "FIQ",
+		__entry->level, __entry->vcpu_idx)
+);
+
 
 #endif /* _TRACE_KVM_H */
 
include/linux/kvm.h +1 -1
index c3892fc..679abbb 100644
@@ -111,6 +111,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;
 
--
Quoted 4 lines

To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Jan

#15 lore raw

Re: [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

Quoted 6 lines · Jan Kiszka

Just found two, maybe three nits while browsing by:

Documentation/virtual/kvm/api.txt Requires that an interrupt controller model has been previously created with

Quoted 3 lines · Christoffer Dall
Documentation/virtual/kvm/api.txt +3 -0
+ARM uses two types of interrupt lines per CPU, ie. IRQ and FIQ. The value of the
+irq field should be (VCPU_INDEX * 2) for IRQs and ((VCPU_INDEX * 2) + 1) for
+FIQs.

This seems to me a slightly obscure way of defining the two fields in this word (ie bits [31..1] cpu number, bit [0] irq-vs-fiq).

Quoted 18 lines
Quoted 18 lines
arch/arm/kvm/arm.c +18 -0
+static int kvm_arch_vm_ioctl_irq_line(struct kvm *kvm,
+                                   struct kvm_irq_level *irq_level)
+{
+     u32 mask;
+     unsigned int vcpu_idx;
+     struct kvm_vcpu *vcpu;
+
+     vcpu_idx = irq_level->irq / 2;
+     if (vcpu_idx >= KVM_MAX_VCPUS)
+             return -EINVAL;
+
+     vcpu = kvm_get_vcpu(kvm, vcpu_idx);
+     if (!vcpu)
+             return -EINVAL;
+
+     switch (irq_level->irq % 2) {
+     case KVM_ARM_IRQ_LINE:
+             mask = HCR_VI;
Quoted 8 lines
Quoted 6 lines

+             break;
+     case KVM_ARM_FIQ_LINE:
+             mask = HCR_VF;
+             break;
+     default:
+             return -EINVAL;

Due to % 2, default is unreachable. Remove the masking?

Removing the mask would be wrong since the irq field here is encoding both cpu number and irq-vs-fiq. The default is just an unreachable condition. (Why are we using % here rather than the obvious bit operation, incidentally?)

-- PMM

#32 lore raw

Re: [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

In reply to Jan Kiszka
Quoted 55 lines · Jan Kiszka

Just found two, maybe three nits while browsing by:

Quoted 52 lines · Christoffer Dall

Userspace can inject IRQs and FIQs through the KVM_IRQ_LINE VM ioctl. This ioctl is used since the sematics are in fact two lines that can be either raised or lowered on the VCPU - the IRQ and FIQ lines.

KVM needs to know which VCPU it must operate on and whether the FIQ or IRQ line is raised/lowered. Hence both pieces of information is packed in the kvm_irq_level->irq field. The irq fild value will be:
  IRQ: vcpu_index * 2
  FIQ: (vcpu_index * 2) + 1

This is documented in Documentation/kvm/api.txt.

The effect of the ioctl is simply to simply raise/lower the corresponding virt_irq field on the VCPU struct, which will cause the world-switch code to raise/lower virtual interrupts when running the guest on next switch. The wait_for_interrupt flag is also cleared for raised IRQs causing an idle VCPU to become active again.

Note: The custom trace_kvm_irq_line is used despite a generic definition of trace_kvm_set_irq, since the trace-Kvm_set_irq depends on the x86-specific define of __HAVE_IOAPIC. Either the trace event should be created regardless of this define or it should depend on another ifdef clause, common for both x86 and ARM. However, since the arguments don't really match those used in ARM, I am yet to be convinced why this is necessary.

---
 Documentation/virtual/kvm/api.txt |   10 ++++++- arch/arm/include/asm/kvm.h        |    8 ++++++ arch/arm/include/asm/kvm_arm.h    |    1 +
 arch/arm/kvm/arm.c                |   53 ++++++++++++++++++++++++++++++++++++- arch/arm/kvm/trace.h              |   21 +++++++++++++++ include/linux/kvm.h               |    1 +

 6 files changed, 91 insertions(+), 3 deletions(-)
Documentation/virtual/kvm/api.txt +0 -0
index 7945b0b..4abaa67 100644
@@ -572,7 +572,7 @@ only go to the IOAPIC.  On ia64, a IOSAPIC is created.

 4.25 KVM_IRQ_LINE

 Capability: KVM_CAP_IRQCHIP

Documentation/virtual/kvm/api.txt +1 -1
-Architectures: x86, ia64
+Architectures: x86, ia64, arm

 Type: vm ioctl
 Parameters: struct kvm_irq_level
 Returns: 0 on success, -1 on error

Documentation/virtual/kvm/api.txt +0 -0
@@ -582,6 +582,14 @@ Requires that an interrupt controller model has been previously created with

 KVM_CREATE_IRQCHIP.  Note that edge-triggered interrupts require the level to be set to 1 and then back to 0.

Quoted 5 lines

Documentation/virtual/kvm/api.txt Requires that an interrupt controller model has been previously created with · line 586

Quoted 2 lines
Documentation/virtual/kvm/api.txt +2 -0
+KVM_CREATE_IRQCHIP (except for ARM).  Note that edge-triggered interrupts
+require the level to be set to 1 and then back to 0.

You probably wanted to replace the original lines with these two, no?

ah yes, some stgit re-ordering artifact.

Quoted 66 lines
Quoted 66 lines
Documentation/virtual/kvm/api.txt +6 -0
+
+ARM uses two types of interrupt lines per CPU, ie. IRQ and FIQ. The value of the
+irq field should be (VCPU_INDEX * 2) for IRQs and ((VCPU_INDEX * 2) + 1) for
+FIQs. Level is used to raise/lower the line. See arch/arm/include/asm/kvm.h for
+convenience macros.
+

 struct kvm_irq_level {
      union {
              __u32 irq;     /* GSI */

arch/arm/include/asm/kvm.h +8 -0
index 87dc33b..8935062 100644
@@ -20,6 +20,14 @@
  #include <asm/types.h>
 
  /*
+ * KVM_IRQ_LINE macros to set/read IRQ/FIQ for specific VCPU index.
+ */
+enum KVM_ARM_IRQ_LINE_TYPE {
+     KVM_ARM_IRQ_LINE = 0,
+     KVM_ARM_FIQ_LINE = 1,
+};
+
+/*
   * Modes used for short-hand mode determinition in the world-switch code and
   * in emulation code.
   *
arch/arm/include/asm/kvm_arm.h +1 -0
index 835abd1..e378a37 100644
@@ -49,6 +49,7 @@
  #define HCR_VM               1
  #define HCR_GUEST_MASK (HCR_TSC | HCR_TWE | HCR_TWI | HCR_VM | HCR_AMO | \
                       HCR_AMO | HCR_IMO | HCR_FMO | HCR_SWIO)
+#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
 
  /* Hyp System Control Register (HSCTLR) bits */
  #define HSCTLR_TE    (1 << 30)
arch/arm/kvm/arm.c +18 -0
index 89ba18d..fc0bd6b 100644
@@ -299,6 +299,43 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
       return -EINVAL;
  }
 
+static int kvm_arch_vm_ioctl_irq_line(struct kvm *kvm,
+                                   struct kvm_irq_level *irq_level)
+{
+     u32 mask;
+     unsigned int vcpu_idx;
+     struct kvm_vcpu *vcpu;
+
+     vcpu_idx = irq_level->irq / 2;
+     if (vcpu_idx >= KVM_MAX_VCPUS)
+             return -EINVAL;
+
+     vcpu = kvm_get_vcpu(kvm, vcpu_idx);
+     if (!vcpu)
+             return -EINVAL;
+
+     switch (irq_level->irq % 2) {
+     case KVM_ARM_IRQ_LINE:
+             mask = HCR_VI;
Quoted 9 lines

arch/arm/kvm/arm.c int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) · line 325

Quoted 6 lines
arch/arm/kvm/arm.c +6 -0
+             break;
+     case KVM_ARM_FIQ_LINE:
+             mask = HCR_VF;
+             break;
+     default:
+             return -EINVAL;

Due to % 2, default is unreachable. Remove the masking?

nah, the masking should be there, it's just th default case that should go away.

Quoted 12 lines

arch/arm/kvm/arm.c int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) · line 334

Quoted 9 lines
arch/arm/kvm/arm.c +9 -0
+     }
+
+     trace_kvm_irq_line(irq_level->irq % 2, irq_level->level, vcpu_idx);
+
+     if (irq_level->level) {
+             vcpu->arch.virt_irq |= mask;
+             vcpu->arch.wait_for_interrupts = 0;
+     } else
+             vcpu->arch.virt_irq &= ~mask;

No need to protect the bitops on virt_irq? Or what lock does this?

that's fixed in the SMP host patch (but I guess with I/O thread that doesn't really apply only to SMP, so I could move that logging down the patch stream. In any case, yes, there should be locking, and there is).

Quoted 62 lines
Quoted 62 lines
arch/arm/kvm/arm.c +18 -2
+
+     return 0;
+}
+
  long kvm_arch_vcpu_ioctl(struct file *filp,
                        unsigned int ioctl, unsigned long arg)
  {
@@ -313,8 +350,20 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
  long kvm_arch_vm_ioctl(struct file *filp,
                      unsigned int ioctl, unsigned long arg)
  {
-     printk(KERN_ERR "kvm_arch_vm_ioctl: Unsupported ioctl (%d)\n", ioctl);
-     return -EINVAL;
+     struct kvm *kvm = filp->private_data;
+     void __user *argp = (void __user *)arg;
+
+     switch (ioctl) {
+     case KVM_IRQ_LINE: {
+             struct kvm_irq_level irq_event;
+
+             if (copy_from_user(&irq_event, argp, sizeof irq_event))
+                     return -EFAULT;
+             return kvm_arch_vm_ioctl_irq_line(kvm, &irq_event);
+     }
+     default:
+             return -EINVAL;
+     }
  }
 
  /**
arch/arm/kvm/trace.h +21 -0
index f8869c1..ac64e3a 100644
@@ -40,6 +40,27 @@ TRACE_EVENT(kvm_exit,
  );
 
 
+TRACE_EVENT(kvm_irq_line,
+     TP_PROTO(unsigned int type, unsigned int level, unsigned int vcpu_idx),
+     TP_ARGS(type, level, vcpu_idx),
+
+     TP_STRUCT__entry(
+             __field(        unsigned int,   type                    )
+             __field(        unsigned int,   level                   )
+             __field(        unsigned int,   vcpu_idx                )
+     ),
+
+     TP_fast_assign(
+             __entry->type                   = type;
+             __entry->level                  = level;
+             __entry->vcpu_idx               = vcpu_idx;
+     ),
+
+     TP_printk("KVM_IRQ_LINE: type: %s, level: %u, vcpu: %u",
+             (__entry->type == KVM_ARM_IRQ_LINE) ? "IRQ" : "FIQ",
+             __entry->level, __entry->vcpu_idx)
+);
+
 
  #endif /* _TRACE_KVM_H */
 
Quoted 13 lines

include/linux/kvm.h struct kvm_irq_level { · line 117

Quoted 13 lines
include/linux/kvm.h +1 -0
index c3892fc..679abbb 100644
@@ -111,6 +111,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;

Thanks,
-Christoffer

#93 lore raw
In reply to Peter Maydell
Quoted 13 lines · Peter Maydell
Quoted 10 lines · Christoffer Dall

The following series implements KVM support for ARM processors, specifically on the Cortex A-15 platform.

Still on the to-do list:
 - Reuse VMIDs
 - Fix SMP host support
 - Fix SMP guest support
 - Support guest Thumb mode for MMIO emulation
 - Further testing
 - Performance improvements

Quoted 4 lines

Other items for this list:
 - Support Neon/VFP in guests (the fpu regs struct is empty ATM)
 - Support guest debugging

ok, thanks, will add these to the list. I have a feeling it will keep growing for a while :)

Quoted 2 lines

I couldn't see any support for the TLS registers in your cp15 emulation:
did I miss it, or do we handle it without needing to trap?

by TLS you mean the cp15, c13 registers (tid and friends?) If so, I handle these in the world-switch code (look at read_cp15_state and write_cp15_state).

otherwise, help me out on the acronym...

-Christoffer

#94 lore raw
Quoted 5 lines · Christoffer Dall

by TLS you mean the cp15, c13 registers (tid and friends?) If so, I handle these in the world-switch code (look at read_cp15_state and write_cp15_state).

otherwise, help me out on the acronym...

Yes, those are the ones (TLS == thread local storage). Thanks for the pointer.

-- PMM

#16 lore raw

Re: [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

In reply to Peter Maydell
Quoted 11 lines · Peter Maydell
Quoted 6 lines · Jan Kiszka

Just found two, maybe three nits while browsing by:

Documentation/virtual/kvm/api.txt Requires that an interrupt controller model has been previously created with

Quoted 3 lines · Christoffer Dall
Documentation/virtual/kvm/api.txt +3 -0
+ARM uses two types of interrupt lines per CPU, ie. IRQ and FIQ. The value of the
+irq field should be (VCPU_INDEX * 2) for IRQs and ((VCPU_INDEX * 2) + 1) for
+FIQs.

This seems to me a slightly obscure way of defining the two fields in this word (ie bits [31..1] cpu number, bit [0] irq-vs-fiq).

Isn't that just personal preference? The other scheme was suggested by Avi, and nobody else complained then, so I'd be inclined to just leave it as is.

Quoted 27 lines
Quoted 18 lines
Quoted 18 lines
arch/arm/kvm/arm.c +18 -0
+static int kvm_arch_vm_ioctl_irq_line(struct kvm *kvm,
+                                   struct kvm_irq_level *irq_level)
+{
+     u32 mask;
+     unsigned int vcpu_idx;
+     struct kvm_vcpu *vcpu;
+
+     vcpu_idx = irq_level->irq / 2;
+     if (vcpu_idx >= KVM_MAX_VCPUS)
+             return -EINVAL;
+
+     vcpu = kvm_get_vcpu(kvm, vcpu_idx);
+     if (!vcpu)
+             return -EINVAL;
+
+     switch (irq_level->irq % 2) {
+     case KVM_ARM_IRQ_LINE:
+             mask = HCR_VI;
Quoted 8 lines
Quoted 6 lines

+             break;
+     case KVM_ARM_FIQ_LINE:
+             mask = HCR_VF;
+             break;
+     default:
+             return -EINVAL;

Due to % 2, default is unreachable. Remove the masking?

Quoted 5 lines

Removing the mask would be wrong since the irq field here is encoding both cpu number and irq-vs-fiq. The default is just an unreachable condition. (Why are we using % here rather than the obvious bit operation, incidentally?)

right, I will remove the default case.

I highly doubt that the difference in using a bitop will be measurably more efficient, but if you feel strongly about it, I can change it to a shift and bitwise and, which I assume is what you mean by the obvious bit operation? I think my CS background speaks for using %, but whatever.

#17 lore raw

Re: [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

Quoted 7 lines · Christoffer Dall
Quoted 5 lines · Peter Maydell

Removing the mask would be wrong since the irq field here is encoding both cpu number and irq-vs-fiq. The default is just an unreachable condition. (Why are we using % here rather than the obvious bit operation, incidentally?)

Quoted 7 lines

right, I will remove the default case.

I highly doubt that the difference in using a bitop will be measurably more efficient, but if you feel strongly about it, I can change it to a shift and bitwise and, which I assume is what you mean by the obvious bit operation? I think my CS background speaks for using %, but whatever.

Certainly the compiler ought to be able to figure out the two are the same thing; I just think "irq & 1" is more readable than "irq % 2" (because it's being clear that it's treating the variable as a pile of bits rather than an integer). This is bikeshedding rather, though, and style issues in kernel code are a matter for the kernel folk. So you can ignore me :-)

-- PMM

#18 lore raw

Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

Quoted 17 lines · Peter Maydell
Quoted 7 lines · Christoffer Dall
Quoted 5 lines · Peter Maydell

Removing the mask would be wrong since the irq field here is encoding both cpu number and irq-vs-fiq. The default is just an unreachable condition. (Why are we using % here rather than the obvious bit operation, incidentally?)

Quoted 7 lines

right, I will remove the default case.

I highly doubt that the difference in using a bitop will be measurably more efficient, but if you feel strongly about it, I can change it to a shift and bitwise and, which I assume is what you mean by the obvious bit operation? I think my CS background speaks for using %, but whatever.

Quoted 7 lines

Certainly the compiler ought to be able to figure out the two are the same thing; I just think "irq & 1" is more readable than "irq % 2" (because it's being clear that it's treating the variable as a pile of bits rather than an integer). This is bikeshedding rather, though, and style issues in kernel code are a matter for the kernel folk. So you can ignore me :-)

Well, if it was just "irq & 1", then I hear you, but it would be "(irq

Quoted 1 line
Quoted 1 line

cpu_idx) & 1" which I don't think is more clear.

But yes let's see what the kernel folks say.

#19 lore raw

Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

Quoted 2 lines · Christoffer Dall

Well, if it was just "irq & 1", then I hear you, but it would be "(irq

Quoted 1 line
Quoted 1 line

cpu_idx) & 1" which I don't think is more clear.

Er, what? The fields are [31..1] CPU index and [0] irqtype, right? So what you have now is:

     vcpu_idx = irq_level->irq / 2;
     irqtype = irq_level->irq % 2;
and the bitshifting equivalent is:
     vcpu_idx = irq_level->irq >> 1;
     irqtype = irq_level->irq & 1;

surely?

Shifting by the cpuindex is definitely wrong.

(Incidentally I fixed a bug in your QEMU-side code which wasn't feeding this field to the kernel in the way it expects:

http://git.linaro.org/gitweb?p=qemu/qemu-linaro.git;a=commitdiff;h=2502ba067e795e48d346f9816fad45177ca64bca

Sorry, I should have posted that to the list. I'll do that now.)

-- PMM

#20 lore raw

Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

Quoted 14 lines · Peter Maydell
Quoted 2 lines · Christoffer Dall

Well, if it was just "irq & 1", then I hear you, but it would be "(irq

Quoted 1 line
Quoted 1 line

cpu_idx) & 1" which I don't think is more clear.

Er, what? The fields are [31..1] CPU index and [0] irqtype, right? So what you have now is:
    vcpu_idx = irq_level->irq / 2;
    irqtype = irq_level->irq % 2;
and the bitshifting equivalent is:
    vcpu_idx = irq_level->irq >> 1;
    irqtype = irq_level->irq & 1;
surely?

Quoted 1 line

Shifting by the cpuindex is definitely wrong.

actually, that's not how the irq_level field is defined. If you look in Documentation/virtual/kvm/api.txt:

"ARM uses two types of interrupt lines per CPU, ie. IRQ and FIQ. The value of the
irq field should be (VCPU_INDEX * 2) for IRQs and ((VCPU_INDEX * 2) + 1) for FIQs. Level is used to raise/lower the line. See arch/arm/include/asm/kvm.h for convenience macros."

also, in the kernel code the cpu_index is achieved by a simple integer division by 2.

as I said, this was the proposal from the last round of reviews after a lengthy discussion, so I sticked with that.

we should definitely fix either side, and the only sane argument is that this is an irq_line field, so an index resembling an actual line seems more semantically in line with the field purpose rather than a bit encoding, but I am open to arguments and not married to the current implementation.

Quoted 6 lines

(Incidentally I fixed a bug in your QEMU-side code which wasn't feeding this field to the kernel in the way it expects:

http://git.linaro.org/gitweb?p=qemu/qemu-linaro.git;a=commitdiff;h=2502ba067e795e48d346f9816fad45177ca64bca

Sorry, I should have posted that to the list. I'll do that now.)

#21 lore raw

Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

Quoted 15 lines · Christoffer Dall
Quoted 14 lines · Peter Maydell
Quoted 2 lines · Christoffer Dall

Well, if it was just "irq & 1", then I hear you, but it would be "(irq

Quoted 1 line
Quoted 1 line

cpu_idx) & 1" which I don't think is more clear.

Er, what? The fields are [31..1] CPU index and [0] irqtype, right? So what you have now is:
    vcpu_idx = irq_level->irq / 2;
    irqtype = irq_level->irq % 2;
and the bitshifting equivalent is:
    vcpu_idx = irq_level->irq >> 1;
    irqtype = irq_level->irq & 1;
surely?

Quoted 3 lines
Quoted 1 line

Shifting by the cpuindex is definitely wrong.

actually, that's not how the irq_level field is defined.

It's not clear to me which part of my comment this is aimed at. Shifting by the cpuindex doesn't give the right answer whether you define irq_level by bitfields or with the current phrasing you quote below.

Quoted 8 lines

If you look
in Documentation/virtual/kvm/api.txt:

"ARM uses two types of interrupt lines per CPU, ie. IRQ and FIQ. The value of the
irq field should be (VCPU_INDEX * 2) for IRQs and ((VCPU_INDEX * 2) + 1) for FIQs. Level is used to raise/lower the line. See arch/arm/include/asm/kvm.h for convenience macros."

That's exactly the same thing, though, right? It's just a matter of how you choose to phrase it (in either text or in code; the values come out identical). When I was sorting out the QEMU side, I started out by looking at the kernel source code, deduced that we were encoding CPU number and irq-vs-fiq as described above (and documenting it in a slightly confusing way as a multiplication) and then wrote the qemu code in what seemed to me the clearest way.

(Actually what would be clearest would be if the ioctl took the (interrupt-target, interrupt-line-for-that-target, value-of-line) tuple as three separate values rather than encoding two of them into a single integer, but I assume there's a reason we can't have that.)

Quoted 5 lines

we should definitely fix either side, and the only sane argument is that this is an irq_line field, so an index resembling an actual line seems more semantically in line with the field purpose rather than a bit encoding, but I am open to arguments and not married to the current implementation.

To be clear, I'm not attempting to suggest a change in the semantics of this field. (The qemu patch fixes the qemu side to adhere to what the kernel requires.)

-- PMM

#22 lore raw

Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

Quoted 4 lines · Peter Maydell

(Actually what would be clearest would be if the ioctl took the (interrupt-target, interrupt-line-for-that-target, value-of-line) tuple as three separate values rather than encoding two of them into a single integer, but I assume there's a reason we can't have that.)

Have you thought about how this encoding scheme would be extended when we move to using the VGIC and an in-kernel interrupt controller implementation, incidentally? I haven't really looked into that at all, but I assume that then QEMU is going to start having to tell the kernel it wants to deliver interrupt 35 to the GIC, and so on...

-- PMM

#23 lore raw

Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

Quoted 6 lines · Peter Maydell
Quoted 4 lines · Peter Maydell

(Actually what would be clearest would be if the ioctl took the (interrupt-target, interrupt-line-for-that-target, value-of-line) tuple as three separate values rather than encoding two of them into a single integer, but I assume there's a reason we can't have that.)

Quoted 7 lines

Have you thought about how this encoding scheme would be extended when we move to using the VGIC and an in-kernel interrupt controller implementation, incidentally? I haven't really looked into that at all, but I assume that then QEMU is going to start having to tell the kernel it wants to deliver interrupt 35 to the GIC, and so on...

no, I haven't looked into that at all. My plan was to decipher the common irq, ioapic stuff for x86 and see how much we can re-use and if there will be some nice way to either use what's there or change some bits to accomodate both existing archs and ARM. But the short answer is, no not really, I was focusing so far on getting a stable implementation upstream.

yes, we are going to have to have some interface with QEMU for this and if we need new features from what's already there that should probably be discussed in the same round as the mechanism for handing of CP15 stuff to QEMU that we touched upon earlier.

-Christoffer

#24 lore raw

Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

Quoted 21 lines · Christoffer Dall
Quoted 6 lines · Peter Maydell
Quoted 4 lines · Peter Maydell

(Actually what would be clearest would be if the ioctl took the (interrupt-target, interrupt-line-for-that-target, value-of-line) tuple as three separate values rather than encoding two of them into a single integer, but I assume there's a reason we can't have that.)

Quoted 7 lines

Have you thought about how this encoding scheme would be extended when we move to using the VGIC and an in-kernel interrupt controller implementation, incidentally? I haven't really looked into that at all, but I assume that then QEMU is going to start having to tell the kernel it wants to deliver interrupt 35 to the GIC, and so on...

no, I haven't looked into that at all. My plan was to decipher the common irq, ioapic stuff for x86 and see how much we can re-use and if there will be some nice way to either use what's there or change some bits to accomodate both existing archs and ARM. But the short answer is, no not really, I was focusing so far on getting a stable implementation upstream.

Quoted 4 lines

yes, we are going to have to have some interface with QEMU for this and if we need new features from what's already there that should probably be discussed in the same round as the mechanism for handing of CP15 stuff to QEMU that we touched upon earlier.

Enabling in-kernel irqchips usually means "switching worlds". So the semantics of these particular IRQ inject interface details may change without breaking anything.

However, things might look different if there will be a need to inject also the CPU IRQs directly, not only the irqchip inputs. In that case, it may make some sense to reserve more space for interrupt types than just one bit and use a common encoding scheme.

Jan

#31 lore raw

Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

In reply to Peter Maydell
Quoted 17 lines · Peter Maydell
Quoted 7 lines · Christoffer Dall
Quoted 5 lines · Peter Maydell

Removing the mask would be wrong since the irq field here is encoding both cpu number and irq-vs-fiq. The default is just an unreachable condition. (Why are we using % here rather than the obvious bit operation, incidentally?)

Quoted 7 lines

right, I will remove the default case.

I highly doubt that the difference in using a bitop will be measurably more efficient, but if you feel strongly about it, I can change it to a shift and bitwise and, which I assume is what you mean by the obvious bit operation? I think my CS background speaks for using %, but whatever.

Quoted 6 lines

Certainly the compiler ought to be able to figure out the two are the same thing; I just think "irq & 1" is more readable than "irq % 2" (because it's being clear that it's treating the variable as a pile of bits rather than an integer). This is bikeshedding rather, though, and style issues in kernel code are a matter for the kernel folk. So you can ignore me :-)

Yes, the general rule of thumb is to use bit operations where you can. And in this case it certainly makes sense :).

Plus, bit operations are an order of magnitude faster than div/mod usually.

Alex

#29 lore raw

Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

In reply to Christoffer Dall
Quoted 26 lines · Christoffer Dall
Quoted 17 lines · Peter Maydell
Quoted 7 lines · Christoffer Dall
Quoted 5 lines · Peter Maydell

Removing the mask would be wrong since the irq field here is encoding both cpu number and irq-vs-fiq. The default is just an unreachable condition. (Why are we using % here rather than the obvious bit operation, incidentally?)

Quoted 7 lines

right, I will remove the default case.

I highly doubt that the difference in using a bitop will be measurably more efficient, but if you feel strongly about it, I can change it to a shift and bitwise and, which I assume is what you mean by the obvious bit operation? I think my CS background speaks for using %, but whatever.

Quoted 7 lines

Certainly the compiler ought to be able to figure out the two are the same thing; I just think "irq & 1" is more readable than "irq % 2" (because it's being clear that it's treating the variable as a pile of bits rather than an integer). This is bikeshedding rather, though, and style issues in kernel code are a matter for the kernel folk. So you can ignore me :-)

Quoted 4 lines

Well, if it was just "irq & 1", then I hear you, but it would be "(irq

Quoted 1 line
Quoted 1 line

cpu_idx) & 1" which I don't think is more clear.

But yes let's see what the kernel folks say.

The general consensus is to use bit operations rather than arithmetic. The compiler will usually convert the "% 2" pattern into a shift, but I tend to agree with Peter on the readability of the thing. When encoding multiple information in a word, bit operations should be used, as they make it obvious which part of the word contains the bit you're interested in.

But I've probably been corrupted by working with HW guys for a bit too long... ;-)

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#30 lore raw

Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

Quoted 39 lines · Marc Zyngier
Quoted 26 lines · Christoffer Dall
Quoted 17 lines · Peter Maydell
Quoted 7 lines · Christoffer Dall
Quoted 5 lines · Peter Maydell

Removing the mask would be wrong since the irq field here is encoding both cpu number and irq-vs-fiq. The default is just an unreachable condition. (Why are we using % here rather than the obvious bit operation, incidentally?)

Quoted 7 lines

right, I will remove the default case.

I highly doubt that the difference in using a bitop will be measurably more efficient, but if you feel strongly about it, I can change it to a shift and bitwise and, which I assume is what you mean by the obvious bit operation? I think my CS background speaks for using %, but whatever.

Quoted 7 lines

Certainly the compiler ought to be able to figure out the two are the same thing; I just think "irq & 1" is more readable than "irq % 2" (because it's being clear that it's treating the variable as a pile of bits rather than an integer). This is bikeshedding rather, though, and style issues in kernel code are a matter for the kernel folk. So you can ignore me :-)

Quoted 4 lines

Well, if it was just "irq & 1", then I hear you, but it would be "(irq

Quoted 1 line
Quoted 1 line

cpu_idx) & 1" which I don't think is more clear.

But yes let's see what the kernel folks say.

The general consensus is to use bit operations rather than arithmetic. The compiler will usually convert the "% 2" pattern into a shift, but I tend to agree with Peter on the readability of the thing. When encoding multiple information in a word, bit operations should be used, as they make it obvious which part of the word contains the bit you're interested in.

Quoted 4 lines

But I've probably been corrupted by working with HW guys for a bit too long... ;-)

ok, ok, I'll change it to a bit op. Can't wait for the dazzling performance improvement ;)

#33 lore raw

Re: [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

In reply to Christoffer Dall
Quoted 18 lines · Christoffer Dall

Userspace can inject IRQs and FIQs through the KVM_IRQ_LINE VM ioctl. This ioctl is used since the sematics are in fact two lines that can be either raised or lowered on the VCPU - the IRQ and FIQ lines.

KVM needs to know which VCPU it must operate on and whether the FIQ or IRQ line is raised/lowered. Hence both pieces of information is packed in the kvm_irq_level->irq field. The irq fild value will be:
IRQ: vcpu_index * 2
FIQ: (vcpu_index * 2) + 1

This is documented in Documentation/kvm/api.txt.

The effect of the ioctl is simply to simply raise/lower the corresponding virt_irq field on the VCPU struct, which will cause the world-switch code to raise/lower virtual interrupts when running the guest on next switch. The wait_for_interrupt flag is also cleared for raised IRQs causing an idle VCPU to become active again.

Quoted 6 lines

Note: The custom trace_kvm_irq_line is used despite a generic definition of trace_kvm_set_irq, since the trace-Kvm_set_irq depends on the x86-specific define of __HAVE_IOAPIC. Either the trace event should be created regardless of this define or it should depend on another ifdef clause, common for both x86 and ARM. However, since the arguments don't really match those used in ARM, I am yet to be convinced why this is necessary.

Why don't they match? The assignment of lines to actual pins differs, but essentially it's the same thing (otherwise we'd use a different ioctl).

Documentation/virtual/kvm/api.txt Requires that an interrupt controller model has been previously created with · line 586

Quoted 13 lines

Capability: KVM_CAP_IRQCHIP

Documentation/virtual/kvm/api.txt +3 -1
-Architectures: x86, ia64
+Architectures: x86, ia64, arm
 Type: vm ioctl
 Parameters: struct kvm_irq_level
 Returns: 0 on success, -1 on error
@@ -582,6 +582,14 @@ Requires that an interrupt controller model has been previously created with
 KVM_CREATE_IRQCHIP.  Note that edge-triggered interrupts require the level
 to be set to 1 and then back to 0.
 
+KVM_CREATE_IRQCHIP (except for ARM).  Note that edge-triggered interrupts
+require the level to be set to 1 and then back to 0.

Need to replace the previous line beginning with KVM_CREATE_IRQCHIP, not duplicate it.

Documentation/virtual/kvm/api.txt Requires that an interrupt controller model has been previously created with · line 591

Quoted 5 lines
Documentation/virtual/kvm/api.txt +5 -0
+
+ARM uses two types of interrupt lines per CPU, ie. IRQ and FIQ. The value of the
+irq field should be (VCPU_INDEX * 2) for IRQs and ((VCPU_INDEX * 2) + 1) for
+FIQs. Level is used to raise/lower the line. See arch/arm/include/asm/kvm.h for
+convenience macros.

Userspace only includes <linux/kvm.h>; also please name the macros here.

Quoted 21 lines
arch/arm/kvm/arm.c +20 -0
+static int kvm_arch_vm_ioctl_irq_line(struct kvm *kvm,
+				      struct kvm_irq_level *irq_level)
+{
+	u32 mask;
+	unsigned int vcpu_idx;
+	struct kvm_vcpu *vcpu;
+
+	vcpu_idx = irq_level->irq / 2;
+	if (vcpu_idx >= KVM_MAX_VCPUS)
+		return -EINVAL;
+
+	vcpu = kvm_get_vcpu(kvm, vcpu_idx);
+	if (!vcpu)
+		return -EINVAL;
+
+	switch (irq_level->irq % 2) {
+	case KVM_ARM_IRQ_LINE:
+		mask = HCR_VI;
+		break;
+	case KVM_ARM_FIQ_LINE:

arch/arm/kvm/arm.c int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) · line 331

Quoted 10 lines
arch/arm/kvm/arm.c +10 -0
+		mask = HCR_VF;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	trace_kvm_irq_line(irq_level->irq % 2, irq_level->level, vcpu_idx);
+
+	if (irq_level->level) {
+		vcpu->arch.virt_irq |= mask;

racy - this is a vm ioctl, and so can (and usually is) invoked from outside the vcpu thread.

arch/arm/kvm/arm.c int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) · line 332

Quoted 1 line
arch/arm/kvm/arm.c +1 -0
+		vcpu->arch.wait_for_interrupts = 0;

Need an actual wakeup here (see x86's kvm_vcpu_kick() - should really be common code; it takes care of both the 'vcpu sleeping and needs a wakeup' and 'vcpu is in guest mode and needs to go to the host to evaluate interrupt state').

Quoted 7 lines
arch/arm/kvm/arm.c +6 -0
+	} else
+		vcpu->arch.virt_irq &= ~mask;
+
+	return 0;
+}
+
Signature · 1 line
error compiling committee.c: too many arguments to function
#40 lore raw

Re: [PATCH v5 07/13] ARM: KVM: Emulation framework and CP15 emulation

In reply to Christoffer Dall
Quoted 10 lines · Christoffer Dall

From: Christoffer Dall <[email protected]>

Adds a new important function in the main KVM/ARM code called handle_exit() which is called from kvm_arch_vcpu_ioctl_run() on returns from guest execution. This function examines the Hyp-Syndrome-Register (HSR), which contains information telling KVM what caused the exit from the guest.

Some of the reasons for an exit are CP15 accesses, which are not allowed from the guest and this commits handles these exits by

commit

Quoted 1 line

emulating the intented operation in software and skip the guest

intended

Quoted 48 lines

instruction.

arch/arm/kvm/arm.c +42 -0
@@ -306,6 +307,62 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
 	return 0;
 }
 
+static inline int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
+			      int exception_index)
+{
+	unsigned long hsr_ec;
+
+	if (exception_index == ARM_EXCEPTION_IRQ)
+		return 0;
+
+	if (exception_index != ARM_EXCEPTION_HVC) {
+		kvm_err(-EINVAL, "Unsupported exception type");
+		return -EINVAL;
+	}
+
+	hsr_ec = (vcpu->arch.hsr & HSR_EC) >> HSR_EC_SHIFT;
+	switch (hsr_ec) {
+	case HSR_EC_WFI:
+		return kvm_handle_wfi(vcpu, run);
+	case HSR_EC_CP15_32:
+	case HSR_EC_CP15_64:
+		return kvm_handle_cp15_access(vcpu, run);
+	case HSR_EC_CP14_MR:
+		return kvm_handle_cp14_access(vcpu, run);
+	case HSR_EC_CP14_LS:
+		return kvm_handle_cp14_load_store(vcpu, run);
+	case HSR_EC_CP14_64:
+		return kvm_handle_cp14_access(vcpu, run);
+	case HSR_EC_CP_0_13:
+		return kvm_handle_cp_0_13_access(vcpu, run);
+	case HSR_EC_CP10_ID:
+		return kvm_handle_cp10_id(vcpu, run);
+	case HSR_EC_SVC_HYP:
+		/* SVC called from Hyp mode should never get here */
+		kvm_msg("SVC called from Hyp mode shouldn't go here");
+		BUG();
+	case HSR_EC_HVC:
+		kvm_msg("hvc: %x (at %08x)", vcpu->arch.hsr & ((1 << 16) - 1),
+					     vcpu->arch.regs.pc);
+		kvm_msg("         HSR: %8x", vcpu->arch.hsr);
+		break;
+	case HSR_EC_IABT:
+	case HSR_EC_DABT:
+		return kvm_handle_guest_abort(vcpu, run);

arch/arm/kvm/arm.c int kvm_arch_vcpu_runnable(struct kvm_vcpu *v) · line 361

Quoted 10 lines
arch/arm/kvm/arm.c +10 -0
+	case HSR_EC_IABT_HYP:
+	case HSR_EC_DABT_HYP:
+		/* The hypervisor should never cause aborts */
+		kvm_msg("The hypervisor itself shouldn't cause aborts");
+		BUG();
+	default:
+		kvm_msg("Unkown exception class: %08x (%08x)", hsr_ec,
+				vcpu->arch.hsr);
+		BUG();
+	}

x86 uses a function table, which is slightly nicer.

Quoted 16 lines
arch/arm/kvm/arm.c +9 -0
+
+	return 0;
+}
+
 /**
  * kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code
  * @vcpu:	The VCPU pointer
@@ -333,6 +390,26 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		local_irq_enable();
 
 		trace_kvm_exit(vcpu->arch.regs.pc);
+
+		ret = handle_exit(vcpu, run, ret);
+		if (ret) {
+			kvm_err(ret, "Error in handle_exit");
+			break;

arch/arm/kvm/arm.c int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) · line 407

Quoted 10 lines
arch/arm/kvm/arm.c +10 -0
+		}
+
+		if (run->exit_reason == KVM_EXIT_MMIO)
+			break;
+
+		if (need_resched()) {
+			vcpu_put(vcpu);
+			schedule();
+			vcpu_load(vcpu);
+		}

I don't think you need the vcpu_put()/vcpu_load() here; you can replace the whole thing with cond_resched().

arch/arm/kvm/arm.c int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) · line 410

Quoted 3 lines
arch/arm/kvm/arm.c +3 -0
+
+		if (signal_pending(current) && !(run->exit_reason)) {
+			run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;

This exit reason doesn't fit with KVM_IRQ_LINE.

With KVM_INTERRUPT, userspace is responsible for determining when to inject interrupts, so it needs to know when guest interrupts become enabled (this is KVM_EXIT_IRQ_WINDOWS_OPEN). With KVM_IRQ_LINE, userspace just sets the line status, and the kernel takes care of everything.

Oh, and you need to exit to userspace unconditionally if a signal is pending.

Quoted 17 lines
arch/arm/kvm/emulate.c +15 -0
+			break;
+		}
 	}
 
+
+/******************************************************************************
+ * Co-processor emulation
+ */
+
+struct coproc_params {
+	unsigned long CRm;
+	unsigned long CRn;
+	unsigned long Op1;
+	unsigned long Op2;
+	unsigned long Rt1;
+	unsigned long Rt2;
+	bool is_64bit;

arch/arm/kvm/emulate.c u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode) · line 151

Quoted 10 lines
arch/arm/kvm/emulate.c +10 -0
+	bool is_write;
+};
+
+#define CP15_OP(_vcpu, _params, _cp15_reg) \
+do { \
+	if (_params->is_write) \
+		_vcpu->arch.cp15._cp15_reg = *vcpu_reg(_vcpu, _params->Rt1); \
+	else \
+		*vcpu_reg(_vcpu, _params->Rt1) = _vcpu->arch.cp15._cp15_reg; \
+} while (0);

Ugly. How about an array of registers instead?

Signature · 1 line
error compiling committee.c: too many arguments to function
#52 lore raw

Re: [PATCH v5 09/13] ARM: KVM: Handle I/O aborts

In reply to Christoffer Dall
Quoted 15 lines · Christoffer Dall

From: Christoffer Dall <[email protected]>

When the guest accesses I/O memory this will create data abort exceptions and they are handled by decoding the HSR information (physical address, read/write, length, register) and forwarding reads and writes to QEMU which performs the device emulation.

Certain classes of load/store operations do not support the syndrome information provided in the HSR and we therefore must be able to fetch the offending instruction from guest memory and decode it manually.

This requires changing the general flow somewhat since new calls to run the VCPU must check if there's a pending MMIO load and perform the write after userspace has made the data available.

Quoted 8 lines

}

+/**
+ * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
+ * @vcpu: The VCPU pointer
+ * @run: The VCPU run struct containing the mmio data
+ *
+ * This should only be called after returning to QEMU for MMIO load emulation.

s/to QEMU/from userspace/

Quoted 5 lines

+ */

arch/arm/kvm/mmu.c +4 -0
+int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+	int *dest;
+	unsigned int len;

arch/arm/kvm/mmu.c static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, · line 306

Quoted 10 lines
arch/arm/kvm/mmu.c +10 -0
+	int mask;
+
+	if (!run->mmio.is_write) {
+		dest = vcpu_reg(vcpu, vcpu->arch.mmio_rd);
+		memset(dest, 0, sizeof(int));
+
+		if (run->mmio.len > 4) {
+			kvm_err(-EINVAL, "Incorrect mmio length");
+			return -EINVAL;
+		}

Time of check...

arch/arm/kvm/mmu.c static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, · line 309

Quoted 3 lines
arch/arm/kvm/mmu.c +3 -0
+
+		len = run->mmio.len;
+		memcpy(dest, run->mmio.data, len);

... time of use. Anything in run-> is untrusted. Best to use the kernel's copy of len.

Quoted 14 lines
arch/arm/kvm/mmu.c +13 -0
+
+		trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr,
+				*((u64 *)run->mmio.data));
+
+		if (vcpu->arch.mmio_sign_extend && len < 4) {
+			mask = 1U << ((len * 8) - 1);
+			*dest = (*dest ^ mask) - mask;
+		}
+	}
+
+	return 0;
+}
+
Signature · 1 line
error compiling committee.c: too many arguments to function
#55 lore raw

Re: [PATCH v5 10/13] ARM: KVM: Guest wait-for-interrupts (WFI) support

In reply to Christoffer Dall
Quoted 5 lines · Christoffer Dall

From: Christoffer Dall <[email protected]>

When the guest executes a WFI instruction the operation is trapped to KVM, which emulates the instruction in software. There is no correlation between a guest executing a WFI instruction and actually puttin the

putting (puttin'? putin?)

Quoted 11 lines

hardware into a low-power mode, since a KVM guest is essentially a process and the WFI instruction can be seen as 'sleep' call from this process. Therefore, we flag the VCPU to be in wait_for_interrupts mode and call the main KVM function kvm_vcpu_block() function. This function will put the thread on a wait-queue and call schedule.

When an interrupt comes in through KVM_IRQ_LINE (see previous patch) we signal the VCPU thread and unflag the VCPU to no longer wait for interrupts. All calls to kvm_arch_vcpu_ioctl_run() result in a call to kvm_vcpu_block() as long as the VCPU is in wfi-mode.

Ah, this addresses my previous comment on this issue.

arch/arm/kvm/arm.c static int kvm_arch_vm_ioctl_irq_line(struct kvm *kvm, · line 473

Quoted 10 lines
arch/arm/kvm/arm.c +2 -0
 	return ret;
@@ -454,6 +467,8 @@ static int kvm_arch_vm_ioctl_irq_line(struct kvm *kvm,
 	if (irq_level->level) {
 		vcpu->arch.virt_irq |= mask;
 		vcpu->arch.wait_for_interrupts = 0;
 
 
+		if (waitqueue_active(&vcpu->wq))
+			wake_up_interruptible(&vcpu->wq);

Not sufficient. If the guest is running, you need to kick it out of guest mode and back into kvm, so that it samples the interrupt lines.

Also, racy:

racy:
vcpu host thread
KVM_IRQ_LINE
WFI
if (!vcpu->arch.virt_irq)

                 vcpu->arch.virt_irq = x
                 vcpu->arch.wait_for_interrupts = 0

vcpu->arch.wait_for_interrupts = 1
if (waitqueue_active()) (fails)
schedule()

Quoted 5 lines
arch/arm/kvm/emulate.c +4 -0
+/**
+ * kvm_handle_wfi - handle a wait-for-interrupts instruction executed by a guest
+ * @vcpu:	the vcpu pointer
+ * @run:	the kvm_run structure pointer

arch/arm/kvm/emulate.c unsupp_err_out: · line 351

Quoted 10 lines
arch/arm/kvm/emulate.c +8 -0
+ *
+ * Simply sets the wait_for_interrupts flag on the vcpu structure, which will
+ * halt execution of world-switches and schedule other host processes until
+ * there is an incoming IRQ or FIQ to the VM.
+ */
 int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
+	trace_kvm_wfi(vcpu->arch.regs.pc);
+	if (!vcpu->arch.virt_irq)
+		vcpu->arch.wait_for_interrupts = 1;

Why not just block here?

Signature · 1 line
error compiling committee.c: too many arguments to function
#61 lore raw

Re: [PATCH v5 11/13] ARM: KVM: Support SMP hosts

In reply to Christoffer Dall
Quoted 8 lines · Christoffer Dall

In order to support KVM on a SMP host, it is necessary to initialize the hypervisor on all CPUs, mostly by making sure each CPU gets its own hypervisor stack and runs the HYP init code.

We also take care of some missing locking of modifications to the hypervisor page tables and ensure synchronized consistency between virtual IRQ masks and wait_for_interrupt flags on the VPUs.

Quoted 5 lines

Note that this code doesn't handle CPU hotplug yet. Note that this code doesn't support SMP guests.

WARNING: This code is in development and guests do not fully boot on SMP hosts yet.

Damn, I just reviewed all that breakage.

arch/arm/include/asm/kvm_host.h struct kvm_vcpu_arch { · line 95

Quoted 5 lines
arch/arm/include/asm/kvm_host.h +2 -0
 	/* Misc. fields */
+	spinlock_t irq_lock;
+	u32 virt_irq;		/* HCR exception mask */
 	u32 wait_for_interrupts;

Better to use atomics, IMO.

Quoted 16 lines
arch/arm/kvm/arm.c +10 -0
@@ -464,13 +466,27 @@ static int kvm_arch_vm_ioctl_irq_line(struct kvm *kvm,
 
 	trace_kvm_irq_line(irq_level->irq % 2, irq_level->level, vcpu_idx);
 
+	spin_lock(&vcpu->arch.irq_lock);
 	if (irq_level->level) {
 		vcpu->arch.virt_irq |= mask;
+
+		/*
+		 * Note that we grab the wq.lock before clearing the wfi flag
+		 * since this ensures that a concurrent call to kvm_vcpu_block
+		 * will either sleep before we grab the lock, in which case we
+		 * wake it up, or will never sleep due to
+		 * kvm_arch_vcpu_runnable being true (iow. this avoids having
+		 * to grab the irq_lock in kvm_arch_vcpu_runnable).
+		 */

arch/arm/kvm/arm.c static int kvm_arch_vm_ioctl_irq_line(struct kvm *kvm, · line 489

Quoted 10 lines
arch/arm/kvm/arm.c +5 -1
+		spin_lock(&vcpu->wq.lock);
 		vcpu->arch.wait_for_interrupts = 0;
+
 		if (waitqueue_active(&vcpu->wq))
-			wake_up_interruptible(&vcpu->wq);
+			__wake_up_locked(&vcpu->wq, TASK_INTERRUPTIBLE);
+		spin_unlock(&vcpu->wq.lock);
 	} else
 		vcpu->arch.virt_irq &= ~mask;
+	spin_unlock(&vcpu->arch.irq_lock);

This looks overly complicated with two levels of locks. x86 gets by with no locks, and a much more complicated interrupt architecture.

My recommendation is:
wait_for_interrupts is managed solely by the vcpu thread KVM_IRQ_LINE does a set_bit(, virt_irq) for the appropriate irq type,
then IPI/wakeups the vcpu to make it examine both wait_for_interrupts and virt_irq.

Quoted 12 lines
arch/arm/kvm/arm.c +12 -0
+
+static void cpu_init_hyp_mode(void *vector)
+{
+	unsigned long hyp_stack_ptr;
+	void *stack_page;
+
+	stack_page = __get_cpu_var(kvm_arm_hyp_stack_page);
+	hyp_stack_ptr = (unsigned long)stack_page + PAGE_SIZE;
+
+	cpu_set_vector(vector);
+
+	/*

arch/arm/kvm/arm.c long kvm_arch_vm_ioctl(struct file *filp, · line 557

Quoted 10 lines
arch/arm/kvm/arm.c +10 -0
+	 * Call initialization code
+	 */
+	asm volatile (
+		"mov	r0, %[pgd_ptr]\n\t"
+		"mov	r1, %[stack_ptr]\n\t"
+		"hvc	#0\n\t" : :
+		[pgd_ptr] "r" (virt_to_phys(kvm_hyp_pgd)),
+		[stack_ptr] "r" (hyp_stack_ptr) :
+		"r0", "r1");
+}

(slightly nicer is to allocate hyp_stack_ptr and pgd_ptr to "register asm("r0")" and "register asm("r1")" to avoid the extra mov instruction)

Quoted 7 lines
arch/arm/kvm/arm.c +1 -1
@@ -522,47 +573,42 @@ static int init_hyp_mode(void)
 		return -ENOMEM;
 
 	/*
-	 * Allocate stack page for Hypervisor-mode
+	 * Allocate stack pages for Hypervisor-mode
 	 */

arch/arm/kvm/arm.c static int init_hyp_mode(void) · line 581

Quoted 10 lines
arch/arm/kvm/arm.c +3 -6
-	kvm_arm_hyp_stack_page = (void *)__get_free_page(GFP_KERNEL);
-	if (!kvm_arm_hyp_stack_page) {
-		err = -ENOMEM;
-		goto out_free_pgd;
-	}
+	for_each_possible_cpu(cpu) {
+		void *stack_page;
 
-	hyp_stack_ptr = (unsigned long)kvm_arm_hyp_stack_page + PAGE_SIZE;
+		stack_page = (void *)__get_free_page(GFP_KERNEL);

Best to allocate this (and other per-cpu state) on the cpu's node.

Quoted 14 lines
arch/arm/kvm/arm.c +8 -1
+		if (!stack_page) {
+			err = -ENOMEM;
+			goto out_free_pgd;
+		}
+
+		per_cpu(kvm_arm_hyp_stack_page, cpu) = stack_page;
+	}
 
 	init_phys_addr = virt_to_phys(__kvm_hyp_init);
 	init_end_phys_addr = virt_to_phys(__kvm_hyp_init_end);
+	BUG_ON(init_phys_addr & 0x1f);
 
 	/*
-	 * Create identity mapping

arch/arm/kvm/arm.c static int init_hyp_mode(void) · line 611

Quoted 10 lines
arch/arm/kvm/arm.c +5 -0
+	 * Create identity mapping for the init code.
 	 */
 	hyp_identity_mapping_add(kvm_hyp_pgd,
 				 (unsigned long)init_phys_addr,
 				 (unsigned long)init_end_phys_addr);
 
+	for_each_online_cpu(cpu) {
+		smp_call_function_single(cpu, cpu_init_hyp_mode,
+					 (void *)(long)init_phys_addr, 1);
+	}

Need similar code for cpu hotplug. See kvm_cpu_hotplug() and kvm_arch_hardware_enable() which do all this for you.

Signature · 1 line
error compiling committee.c: too many arguments to function
#85 lore raw

Re: [PATCH v5 12/13] ARM: KVM: Fix guest view of MPIDR

In reply to Christoffer Dall
Quoted 4 lines · Christoffer Dall

From: Marc Zyngier <[email protected]>

A guest may need to know which CPU it has booted on (and Linux does). Now that we can run KVM on a SMP host, QEMU may be running on any

s/QEMU/userspace/

Quoted 7 lines

CPU. In that case, directly reading MPIDR will give an inconsistent view on the guest CPU number (among other problems).

The solution is to use the VMPIDR register, which is computed by using the host MPIDR and overriding the low bits with KVM vcpu_id.

Since you're posting the patch for (eventual) inclusion, you need to sign off as well.

Signature · 1 line
error compiling committee.c: too many arguments to function
#34 lore raw

Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

In reply to Avi Kivity
Quoted 26 lines · Avi Kivity
Quoted 18 lines · Christoffer Dall

Userspace can inject IRQs and FIQs through the KVM_IRQ_LINE VM ioctl. This ioctl is used since the sematics are in fact two lines that can be either raised or lowered on the VCPU - the IRQ and FIQ lines.

KVM needs to know which VCPU it must operate on and whether the FIQ or IRQ line is raised/lowered. Hence both pieces of information is packed in the kvm_irq_level->irq field. The irq fild value will be:
  IRQ: vcpu_index * 2
  FIQ: (vcpu_index * 2) + 1

This is documented in Documentation/kvm/api.txt.

The effect of the ioctl is simply to simply raise/lower the corresponding virt_irq field on the VCPU struct, which will cause the world-switch code to raise/lower virtual interrupts when running the guest on next switch. The wait_for_interrupt flag is also cleared for raised IRQs causing an idle VCPU to become active again.

Quoted 6 lines

Note: The custom trace_kvm_irq_line is used despite a generic definition of trace_kvm_set_irq, since the trace-Kvm_set_irq depends on the x86-specific define of __HAVE_IOAPIC. Either the trace event should be created regardless of this define or it should depend on another ifdef clause, common for both x86 and ARM. However, since the arguments don't really match those used in ARM, I am yet to be convinced why this is necessary.

Quoted 3 lines

Why don't they match?  The assignment of lines to actual pins differs, but essentially it's the same thing (otherwise we'd use a different ioctl).

because there is no notion of gsi and irq_source_id on ARM. What's the harm of this additional tracepoint?

If I should re-use the existing one, should I simply move it outside of __KVM_HAVE_IOAPIC?

Quoted 11 lines
Quoted 11 lines

 Capability: KVM_CAP_IRQCHIP

Documentation/virtual/kvm/api.txt +1 -1
-Architectures: x86, ia64
+Architectures: x86, ia64, arm

 Type: vm ioctl
 Parameters: struct kvm_irq_level
 Returns: 0 on success, -1 on error

(quoted diff) +0 -0
@@ -582,6 +582,14 @@ Requires that an interrupt controller model has been previously created with

 KVM_CREATE_IRQCHIP.  Note that edge-triggered interrupts require the level to be set to 1 and then back to 0.

Quoted 6 lines

Documentation/virtual/kvm/api.txt Requires that an interrupt controller model has been previously created with · line 586

Quoted 2 lines
Documentation/virtual/kvm/api.txt +2 -0
+KVM_CREATE_IRQCHIP (except for ARM).  Note that edge-triggered interrupts
+require the level to be set to 1 and then back to 0.

Need to replace the previous line beginning with KVM_CREATE_IRQCHIP, not duplicate it.

right, has been noted and will be fixed. It's a merge error.

Quoted 8 lines

Documentation/virtual/kvm/api.txt Requires that an interrupt controller model has been previously created with · line 591

Quoted 5 lines
Documentation/virtual/kvm/api.txt +5 -0
+
+ARM uses two types of interrupt lines per CPU, ie. IRQ and FIQ. The value of the
+irq field should be (VCPU_INDEX * 2) for IRQs and ((VCPU_INDEX * 2) + 1) for
+FIQs. Level is used to raise/lower the line. See arch/arm/include/asm/kvm.h for
+convenience macros.

Userspace only includes <linux/kvm.h>; also please name the macros here.

I simply dropped this idea and changed the explanation to (vcpu_index << 1) and ((vcpu_index << 1) | 1).

Quoted 26 lines
Quoted 26 lines
arch/arm/kvm/arm.c +25 -0
+static int kvm_arch_vm_ioctl_irq_line(struct kvm *kvm,
+                                   struct kvm_irq_level *irq_level)
+{
+     u32 mask;
+     unsigned int vcpu_idx;
+     struct kvm_vcpu *vcpu;
+
+     vcpu_idx = irq_level->irq / 2;
+     if (vcpu_idx >= KVM_MAX_VCPUS)
+             return -EINVAL;
+
+     vcpu = kvm_get_vcpu(kvm, vcpu_idx);
+     if (!vcpu)
+             return -EINVAL;
+
+     switch (irq_level->irq % 2) {
+     case KVM_ARM_IRQ_LINE:
+             mask = HCR_VI;
+             break;
+     case KVM_ARM_FIQ_LINE:
+             mask = HCR_VF;
+             break;
+     default:
+             return -EINVAL;
+     }
Quoted 9 lines

arch/arm/kvm/arm.c int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) · line 331

Quoted 5 lines
arch/arm/kvm/arm.c +5 -0
+
+     trace_kvm_irq_line(irq_level->irq % 2, irq_level->level, vcpu_idx);
+
+     if (irq_level->level) {
+             vcpu->arch.virt_irq |= mask;

racy - this is a vm ioctl, and so can (and usually is) invoked from outside the vcpu thread.

this is taken care of in SMP host patch, but will be moved down the patches for next revision.

Quoted 7 lines
Quoted 1 line

+             vcpu->arch.wait_for_interrupts = 0;

Need an actual wakeup here (see x86's kvm_vcpu_kick() - should really be common code; it takes care of both the 'vcpu sleeping and needs a wakeup' and 'vcpu is in guest mode and needs to go to the host to evaluate interrupt state').

the wakeup - same as above. Good point that we need to signal the other CPU. Will come, maybe not next revision, but the one after that.

Quoted 7 lines

arch/arm/kvm/arm.c int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) · line 338

Quoted 7 lines

+     } else
+             vcpu->arch.virt_irq &= ~mask;

arch/arm/kvm/arm.c +4 -0
+
+     return 0;
+}
+

Thanks,
Christoffer

#5 lore raw

Re: [PATCH v5 04/13] ARM: KVM: Memory virtualization setup

In reply to Christoffer Dall
Quoted 20 lines · Christoffer Dall

This commit introduces the framework for guest memory management through the use of 2nd stage translation. Each VM has a pointer to a level-1 tabled (the pgd field in struct kvm_arch) which is used for the 2nd stage translations. Entries are added when handling guest faults (later patch) and the table itself can be allocated and freed through the following functions implemented in arch/arm/kvm/arm_mmu.c:
- kvm_alloc_stage2_pgd(struct kvm *kvm);
- kvm_free_stage2_pgd(struct kvm *kvm);

Further, each entry in TLBs and caches are tagged with a VMID identifier in addition to ASIDs. The VMIDs are managed using a bitmap and assigned when creating the VM in kvm_arch_init_vm() where the 2nd stage pgd is also allocated. The table is freed in kvm_arch_destroy_vm(). Both functions are called from the main KVM code.

struct kvm_arch {

arch/arm/include/asm/kvm_host.h struct kvm_vcpu; · line 37

Quoted 5 lines
arch/arm/include/asm/kvm_host.h +3 -1
-	pgd_t *pgd;     /* 1-level 2nd stage table */
+	u32    vmid;	/* The VMID used for the virt. memory system */
+	pgd_t *pgd;	/* 1-level 2nd stage table */
+	u64    vttbr;	/* VTTBR value associated with above pgd and vmid */
 };

I can't say I have a solid grasp here, but my feeling is that vmid needs to be per-vcpu. Otherwise vcpu 1 can migrate to a cpu that previously ran vcpu 0, and reuse its tlb since they have the same vmid.

Signature · 1 line
error compiling committee.c: too many arguments to function
#35 lore raw

Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

In reply to Christoffer Dall
Quoted 6 lines · Christoffer Dall
Quoted 4 lines

Why don't they match? The assignment of lines to actual pins differs, but essentially it's the same thing (otherwise we'd use a different ioctl).

because there is no notion of gsi and irq_source_id on ARM.

gsi = number of irq line, just a bad name, but you do have it on ARM.

irq_source_id really shouldn't have been in kvm_set_irq(), it's an implementation detail rather than an architectural feature; just ignore it.

Quoted 2 lines

What's the
harm of this additional tracepoint?

If we get tools that use them, they have an additional difference to consider. It's a weak argument but it's there.

Quoted 2 lines

If I should re-use the existing one, should I simply move it outside of __KVM_HAVE_IOAPIC?

Protect it with __KVM_HAVE_IRQ_LINE so we don't leak unused tracepoints for other archs.

Quoted 11 lines
Quoted 8 lines

arch/arm/kvm/arm.c int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) · line 331

Quoted 4 lines
arch/arm/kvm/arm.c +4 -0
+     trace_kvm_irq_line(irq_level->irq % 2, irq_level->level, vcpu_idx);
+
+     if (irq_level->level) {
+             vcpu->arch.virt_irq |= mask;

racy - this is a vm ioctl, and so can (and usually is) invoked from outside the vcpu thread.

this is taken care of in SMP host patch, but will be moved down the patches for next revision.

Yes please. It's hard to review this way. Fold all the smp stuff into the patches which introduce the functionality.

Quoted 11 lines
Quoted 8 lines
Quoted 2 lines

+ vcpu->arch.wait_for_interrupts = 0;

Need an actual wakeup here (see x86's kvm_vcpu_kick() - should really be common code; it takes care of both the 'vcpu sleeping and needs a wakeup' and 'vcpu is in guest mode and needs to go to the host to evaluate interrupt state').

the wakeup - same as above. Good point that we need to signal the other CPU. Will come, maybe not next revision, but the one after that.

Ok. I think you can reuse x86 concepts and even code. I'll accept patches to make code arch independent ahead of the merge if it helps.

Signature · 1 line
error compiling committee.c: too many arguments to function
#53 lore raw

Re: [Android-virt] [PATCH v5 09/13] ARM: KVM: Handle I/O aborts

In reply to Avi Kivity
Quoted 45 lines · Avi Kivity
Quoted 15 lines · Christoffer Dall

From: Christoffer Dall <[email protected]>

When the guest accesses I/O memory this will create data abort exceptions and they are handled by decoding the HSR information (physical address, read/write, length, register) and forwarding reads and writes to QEMU which performs the device emulation.

Certain classes of load/store operations do not support the syndrome information provided in the HSR and we therefore must be able to fetch the offending instruction from guest memory and decode it manually.

This requires changing the general flow somewhat since new calls to run the VCPU must check if there's a pending MMIO load and perform the write after userspace has made the data available.

Quoted 8 lines

 }

+/**
+ * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
+ * @vcpu: The VCPU pointer
+ * @run:  The VCPU run struct containing the mmio data
+ *
+ * This should only be called after returning to QEMU for MMIO load emulation.

s/to QEMU/from userspace/

Quoted 5 lines

+ */

arch/arm/kvm/mmu.c +4 -0
+int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+     int *dest;
+     unsigned int len;

arch/arm/kvm/mmu.c static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, · line 306

Quoted 10 lines
arch/arm/kvm/mmu.c +10 -0
+     int mask;
+
+     if (!run->mmio.is_write) {
+             dest = vcpu_reg(vcpu, vcpu->arch.mmio_rd);
+             memset(dest, 0, sizeof(int));
+
+             if (run->mmio.len > 4) {
+                     kvm_err(-EINVAL, "Incorrect mmio length");
+                     return -EINVAL;
+             }

Time of check...

Quoted 6 lines
Quoted 3 lines

+
+             len = run->mmio.len;
+             memcpy(dest, run->mmio.data, len);

... time of use.  Anything in run-> is untrusted.  Best to use the kernel's copy of len.

nice. thanks.

#43 lore raw

Re: [PATCH v5 08/13] ARM: KVM: Handle guest faults in KVM

In reply to Christoffer Dall
Quoted 11 lines · Christoffer Dall

From: Christoffer Dall <[email protected]>

Handles the guest faults in KVM by mapping in corresponding user pages in the 2nd stage page tables.

Introduces new ARM-specific kernel memory types, PAGE_KVM_GUEST and pgprot_guest variables used to map 2nd stage memory for KVM guests.

arch/arm/kvm/mmu.c +2 -0
+static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
+			  gfn_t gfn, struct kvm_memory_slot *memslot)

arch/arm/kvm/mmu.c void kvm_free_stage2_pgd(struct kvm *kvm) · line 243

Quoted 10 lines
arch/arm/kvm/mmu.c +10 -0
+{
+	pfn_t pfn;
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte, new_pte;
+
+	pfn = gfn_to_pfn(vcpu->kvm, gfn);
+
+	if (is_error_pfn(pfn)) {

put_page()

arch/arm/kvm/mmu.c void kvm_free_stage2_pgd(struct kvm *kvm) · line 256

Quoted 13 lines
arch/arm/kvm/mmu.c +13 -0
+		kvm_err(-EFAULT, "Guest gfn %u (0x%08lx) does not have "
+				"corresponding host mapping",
+				gfn, gfn << PAGE_SHIFT);
+		return -EFAULT;
+	}
+
+	/* Create 2nd stage page table mapping - Level 1 */
+	pgd = vcpu->kvm->arch.pgd + pgd_index(fault_ipa);
+	pud = pud_offset(pgd, fault_ipa);
+	if (pud_none(*pud)) {
+		pmd = pmd_alloc_one(NULL, fault_ipa);
+		if (!pmd) {
+			kvm_err(-ENOMEM, "Cannot allocate 2nd stage pmd");

put_page()

Quoted 12 lines
arch/arm/kvm/mmu.c +12 -0
+			return -ENOMEM;
+		}
+		pud_populate(NULL, pud, pmd);
+		pmd += pmd_index(fault_ipa);
+	} else
+		pmd = pmd_offset(pud, fault_ipa);
+
+	/* Create 2nd stage page table mapping - Level 2 */
+	if (pmd_none(*pmd)) {
+		pte = pte_alloc_one_kernel(NULL, fault_ipa);
+		if (!pte) {
+			kvm_err(-ENOMEM, "Cannot allocate 2nd stage pte");

arch/arm/kvm/mmu.c void kvm_free_stage2_pgd(struct kvm *kvm) · line 278

Quoted 10 lines
arch/arm/kvm/mmu.c +10 -0
+			return -ENOMEM;
+		}
+		pmd_populate_kernel(NULL, pmd, pte);
+		pte += pte_index(fault_ipa);
+	} else
+		pte = pte_offset_kernel(pmd, fault_ipa);
+
+	/* Create 2nd stage page table mapping - Level 3 */
+	new_pte = pfn_pte(pfn, PAGE_KVM_GUEST);
+	set_pte_ext(pte, new_pte, 0);

With LPAE and 40-bit addresses, a guest can cause 2GBs worth of page tables to be pinned in host memory; this can be used as a denial of service attack. x86 handles this by having a shrinker that can dynamically free page tables, see mmu_shrinker.

An alternative way may be to impose RLIMIT_AS on the sum of a guest's memory slots; though I prefer having a shrinker.

A bigger problem is that you pin all memory; what are the plans wrt mmu notifiers?

Signature · 1 line
error compiling committee.c: too many arguments to function
#6 lore raw

Re: [Android-virt] [PATCH v5 04/13] ARM: KVM: Memory virtualization setup

In reply to Avi Kivity
Quoted 27 lines · Avi Kivity
Quoted 18 lines · Christoffer Dall

This commit introduces the framework for guest memory management through the use of 2nd stage translation. Each VM has a pointer to a level-1 tabled (the pgd field in struct kvm_arch) which is used for the 2nd stage translations. Entries are added when handling guest faults (later patch) and the table itself can be allocated and freed through the following functions implemented in arch/arm/kvm/arm_mmu.c:
 - kvm_alloc_stage2_pgd(struct kvm *kvm);
 - kvm_free_stage2_pgd(struct kvm *kvm);

Further, each entry in TLBs and caches are tagged with a VMID identifier in addition to ASIDs. The VMIDs are managed using a bitmap and assigned when creating the VM in kvm_arch_init_vm() where the 2nd stage pgd is also allocated. The table is freed in kvm_arch_destroy_vm(). Both functions are called from the main KVM code.

Quoted 7 lines

 struct kvm_arch {
-     pgd_t *pgd;     /* 1-level 2nd stage table */
+     u32    vmid;    /* The VMID used for the virt. memory system */
+     pgd_t *pgd;     /* 1-level 2nd stage table */
+     u64    vttbr;   /* VTTBR value associated with above pgd and vmid */ };

Quoted 4 lines

I can't say I have a solid grasp here, but my feeling is that vmid needs to be per-vcpu.  Otherwise vcpu 1 can migrate to a cpu that previously ran vcpu 0, and reuse its tlb since they have the same vmid.

According to the ARM guys, the same rules apply as for ASIDs which results into 1 vmid per VM. The vmid is checked along with a guest-specific asid, so they would only share TLB entries when running the same guest process, which I assume is fine then. Actually desirable. But, granted, my SMP knowledge is limited so far, so if Marc or Catalin feels like chipping in here...

#36 lore raw

Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

In reply to Avi Kivity
Quoted 11 lines · Avi Kivity
Quoted 6 lines · Christoffer Dall
Quoted 4 lines

Why don't they match?  The assignment of lines to actual pins differs, but essentially it's the same thing (otherwise we'd use a different ioctl).

because there is no notion of gsi and irq_source_id on ARM.

gsi = number of irq line, just a bad name, but you do have it on ARM.

Quoted 9 lines

irq_source_id really shouldn't have been in kvm_set_irq(), it's an implementation detail rather than an architectural feature; just ignore it.

Quoted 2 lines

What's the
harm of this additional tracepoint?

If we get tools that use them, they have an additional difference to consider.  It's a weak argument but it's there.

ok, I am all for re-using as much as possible.

Quoted 6 lines
Quoted 2 lines

If I should re-use the existing one, should I simply move it outside of __KVM_HAVE_IOAPIC?

Protect it with __KVM_HAVE_IRQ_LINE so we don't leak unused tracepoints for other archs.

ok. I used to be scared of touching your arch independent stuff, but maybe I should ease up there...

Quoted 9 lines
Quoted 9 lines
Quoted 8 lines
Quoted 4 lines

+     trace_kvm_irq_line(irq_level->irq % 2, irq_level->level, vcpu_idx); +
+     if (irq_level->level) {
+             vcpu->arch.virt_irq |= mask;

racy - this is a vm ioctl, and so can (and usually is) invoked from outside the vcpu thread.

Quoted 6 lines
Quoted 2 lines

this is taken care of in SMP host patch, but will be moved down the patches for next revision.

Yes please.  It's hard to review this way.  Fold all the smp stuff into the patches which introduce the functionality.

sorry about that, I see this pretty clearly after the fact.

Quoted 9 lines
Quoted 9 lines
Quoted 8 lines
Quoted 2 lines

+             vcpu->arch.wait_for_interrupts = 0;

Need an actual wakeup here (see x86's kvm_vcpu_kick() - should really be common code; it takes care of both the 'vcpu sleeping and needs a wakeup' and 'vcpu is in guest mode and needs to go to the host to evaluate interrupt state').

Quoted 6 lines
Quoted 2 lines

the wakeup - same as above. Good point that we need to signal the other CPU. Will come, maybe not next revision, but the one after that.

Ok.  I think you can reuse x86 concepts and even code.  I'll accept patches to make code arch independent ahead of the merge if it helps.

ok, I'll look into it.

#7 lore raw

Re: [Android-virt] [PATCH v5 04/13] ARM: KVM: Memory virtualization setup

In reply to Christoffer Dall
Quoted 32 lines · Christoffer Dall
Quoted 27 lines · Avi Kivity
Quoted 20 lines · Christoffer Dall

This commit introduces the framework for guest memory management through the use of 2nd stage translation. Each VM has a pointer to a level-1 tabled (the pgd field in struct kvm_arch) which is used for the 2nd stage translations. Entries are added when handling guest faults (later patch) and the table itself can be allocated and freed through the following functions implemented in arch/arm/kvm/arm_mmu.c:
- kvm_alloc_stage2_pgd(struct kvm *kvm);
- kvm_free_stage2_pgd(struct kvm *kvm);

Further, each entry in TLBs and caches are tagged with a VMID identifier in addition to ASIDs. The VMIDs are managed using a bitmap and assigned when creating the VM in kvm_arch_init_vm() where the 2nd stage pgd is also allocated. The table is freed in kvm_arch_destroy_vm(). Both functions are called from the main KVM code.

struct kvm_arch {

arch/arm/include/asm/kvm_host.h struct kvm_vcpu; · line 37

Quoted 5 lines
arch/arm/include/asm/kvm_host.h +3 -1
-     pgd_t *pgd;     /* 1-level 2nd stage table */
+     u32    vmid;    /* The VMID used for the virt. memory system */
+     pgd_t *pgd;     /* 1-level 2nd stage table */
+     u64    vttbr;   /* VTTBR value associated with above pgd and vmid */
 };
Quoted 4 lines

I can't say I have a solid grasp here, but my feeling is that vmid needs to be per-vcpu. Otherwise vcpu 1 can migrate to a cpu that previously ran vcpu 0, and reuse its tlb since they have the same vmid.

Quoted 6 lines

According to the ARM guys, the same rules apply as for ASIDs which results into 1 vmid per VM. The vmid is checked along with a guest-specific asid, so they would only share TLB entries when running the same guest process, which I assume is fine then. Actually desirable. But, granted, my SMP knowledge is limited so far, so if Marc or Catalin feels like chipping in here...

We need to differentiate in how Linux-as-a-guest acts and how the cpu is supposed to work. A guest operating system can theoretically assign the ASID x to process A running on vcpu 0, and the same ASID x to process B running on vcpu 1, and be sure that TLB entries don't leak from A to B since the TLB is cpu local (is that in fact correct?). Does the ARM arch allow this, or does it forbid running different contexts on different vcpus with the same ASID?

Signature · 1 line
error compiling committee.c: too many arguments to function
#37 lore raw

Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

In reply to Christoffer Dall
Quoted 9 lines · Christoffer Dall
Quoted 6 lines
Quoted 2 lines

If I should re-use the existing one, should I simply move it outside of __KVM_HAVE_IOAPIC?

Protect it with __KVM_HAVE_IRQ_LINE so we don't leak unused tracepoints for other archs.

ok. I used to be scared of touching your arch independent stuff, but maybe I should ease up there...

Yup. We should also make more x86 code arch indepedent where possible.

Signature · 1 line
error compiling committee.c: too many arguments to function
#8 lore raw

Re: [Android-virt] [PATCH v5 04/13] ARM: KVM: Memory virtualization setup

In reply to Avi Kivity
Quoted 4 lines · Avi Kivity

We need to differentiate in how Linux-as-a-guest acts and how the cpu is supposed to work.  A guest operating system can theoretically assign the ASID x to process A running on vcpu 0, and the same ASID x to process B running on vcpu 1

That would be a guest bug. From the ARM ARM:
"For a symmetric multiprocessor cluster where a single operating system is running on the set of processing elements, ARMv7 requires all ASID values to be assigned uniquely within any single Inner Shareable domain. In other words, each ASID value must have the same meaning to all processing elements in the system."

-- PMM

#9 lore raw

Re: [Android-virt] [PATCH v5 04/13] ARM: KVM: Memory virtualization setup

Quoted 6 lines · Peter Maydell
Quoted 4 lines · Avi Kivity

We need to differentiate in how Linux-as-a-guest acts and how the cpu is supposed to work. A guest operating system can theoretically assign the ASID x to process A running on vcpu 0, and the same ASID x to process B running on vcpu 1

Quoted 6 lines

That would be a guest bug. From the ARM ARM:
"For a symmetric multiprocessor cluster where a single operating system is running on the set of processing elements, ARMv7 requires all ASID values to be assigned uniquely within any single Inner Shareable domain. In other words, each ASID value must have the same meaning to all processing elements in the system."

Thanks. So per-vm vmids should work.

Signature · 1 line
error compiling committee.c: too many arguments to function
#41 lore raw

Re: [PATCH v5 07/13] ARM: KVM: Emulation framework and CP15 emulation

In reply to Avi Kivity
Quoted 70 lines · Avi Kivity
Quoted 10 lines · Christoffer Dall

From: Christoffer Dall <[email protected]>

Adds a new important function in the main KVM/ARM code called handle_exit() which is called from kvm_arch_vcpu_ioctl_run() on returns from guest execution. This function examines the Hyp-Syndrome-Register (HSR), which contains information telling KVM what caused the exit from the guest.

Some of the reasons for an exit are CP15 accesses, which are not allowed from the guest and this commits handles these exits by

commit

Quoted 1 line

emulating the intented operation in software and skip the guest

intended

Quoted 52 lines

instruction.

arch/arm/kvm/arm.c +46 -0
@@ -306,6 +307,62 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
       return 0;
  }
 
+static inline int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
+                           int exception_index)
+{
+     unsigned long hsr_ec;
+
+     if (exception_index == ARM_EXCEPTION_IRQ)
+             return 0;
+
+     if (exception_index != ARM_EXCEPTION_HVC) {
+             kvm_err(-EINVAL, "Unsupported exception type");
+             return -EINVAL;
+     }
+
+     hsr_ec = (vcpu->arch.hsr & HSR_EC) >> HSR_EC_SHIFT;
+     switch (hsr_ec) {
+     case HSR_EC_WFI:
+             return kvm_handle_wfi(vcpu, run);
+     case HSR_EC_CP15_32:
+     case HSR_EC_CP15_64:
+             return kvm_handle_cp15_access(vcpu, run);
+     case HSR_EC_CP14_MR:
+             return kvm_handle_cp14_access(vcpu, run);
+     case HSR_EC_CP14_LS:
+             return kvm_handle_cp14_load_store(vcpu, run);
+     case HSR_EC_CP14_64:
+             return kvm_handle_cp14_access(vcpu, run);
+     case HSR_EC_CP_0_13:
+             return kvm_handle_cp_0_13_access(vcpu, run);
+     case HSR_EC_CP10_ID:
+             return kvm_handle_cp10_id(vcpu, run);
+     case HSR_EC_SVC_HYP:
+             /* SVC called from Hyp mode should never get here */
+             kvm_msg("SVC called from Hyp mode shouldn't go here");
+             BUG();
+     case HSR_EC_HVC:
+             kvm_msg("hvc: %x (at %08x)", vcpu->arch.hsr & ((1 << 16) - 1),
+                                          vcpu->arch.regs.pc);
+             kvm_msg("         HSR: %8x", vcpu->arch.hsr);
+             break;
+     case HSR_EC_IABT:
+     case HSR_EC_DABT:
+             return kvm_handle_guest_abort(vcpu, run);
+     case HSR_EC_IABT_HYP:
+     case HSR_EC_DABT_HYP:
+             /* The hypervisor should never cause aborts */
+             kvm_msg("The hypervisor itself shouldn't cause aborts");
Quoted 9 lines

arch/arm/kvm/arm.c int kvm_arch_vcpu_runnable(struct kvm_vcpu *v) · line 361

Quoted 6 lines
arch/arm/kvm/arm.c +6 -0
+             BUG();
+     default:
+             kvm_msg("Unkown exception class: %08x (%08x)", hsr_ec,
+                             vcpu->arch.hsr);
+             BUG();
+     }

x86 uses a function table, which is slightly nicer.

ok, completely stole the design from x86.

Quoted 21 lines
Quoted 21 lines
arch/arm/kvm/arm.c +14 -0
+
+     return 0;
+}
+
  /**
   * kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code
   * @vcpu:    The VCPU pointer
@@ -333,6 +390,26 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
               local_irq_enable();
 
               trace_kvm_exit(vcpu->arch.regs.pc);
+
+             ret = handle_exit(vcpu, run, ret);
+             if (ret) {
+                     kvm_err(ret, "Error in handle_exit");
+                     break;
+             }
+
+             if (run->exit_reason == KVM_EXIT_MMIO)
+                     break;
+
Quoted 9 lines

arch/arm/kvm/arm.c int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) · line 407

Quoted 5 lines
arch/arm/kvm/arm.c +5 -0
+             if (need_resched()) {
+                     vcpu_put(vcpu);
+                     schedule();
+                     vcpu_load(vcpu);
+             }

I don't think you need the vcpu_put()/vcpu_load() here; you can replace the whole thing with cond_resched().

sorry again about the stupid patch layout.

Quoted 6 lines

arch/arm/kvm/arm.c int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) · line 410

Quoted 3 lines
arch/arm/kvm/arm.c +3 -0
+
+             if (signal_pending(current) && !(run->exit_reason)) {
+                     run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;

This exit reason doesn't fit with KVM_IRQ_LINE.

Quoted 9 lines

With KVM_INTERRUPT, userspace is responsible for determining when to inject interrupts, so it needs to know when guest interrupts become enabled (this is KVM_EXIT_IRQ_WINDOWS_OPEN).  With KVM_IRQ_LINE, userspace just sets the line status, and the kernel takes care of everything.

Oh, and you need to exit to userspace unconditionally if a signal is pending.

also fixed. sorry again agin.

Quoted 21 lines
Quoted 21 lines
arch/arm/kvm/emulate.c +19 -0
+                     break;
+             }
       }
 
+
+/******************************************************************************
+ * Co-processor emulation
+ */
+
+struct coproc_params {
+     unsigned long CRm;
+     unsigned long CRn;
+     unsigned long Op1;
+     unsigned long Op2;
+     unsigned long Rt1;
+     unsigned long Rt2;
+     bool is_64bit;
+     bool is_write;
+};
+
+#define CP15_OP(_vcpu, _params, _cp15_reg) \
Quoted 8 lines

arch/arm/kvm/emulate.c u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode) · line 151

Quoted 6 lines
arch/arm/kvm/emulate.c +6 -0
+do { \
+     if (_params->is_write) \
+             _vcpu->arch.cp15._cp15_reg = *vcpu_reg(_vcpu, _params->Rt1); \
+     else \
+             *vcpu_reg(_vcpu, _params->Rt1) = _vcpu->arch.cp15._cp15_reg; \
+} while (0);

Ugly.  How about an array of registers instead?

ugly, but fast work-around. it has been fixed, wait for new patch revision.

#56 lore raw

Re: [PATCH v5 10/13] ARM: KVM: Guest wait-for-interrupts (WFI) support

In reply to Avi Kivity
Quoted 9 lines · Avi Kivity
Quoted 5 lines · Christoffer Dall

From: Christoffer Dall <[email protected]>

When the guest executes a WFI instruction the operation is trapped to KVM, which emulates the instruction in software. There is no correlation between a guest executing a WFI instruction and actually puttin the

putting (puttin'? putin?)

putting, no hidden political agenda this time.

Quoted 7 lines
Quoted 7 lines

hardware into a low-power mode, since a KVM guest is essentially a process and the WFI instruction can be seen as 'sleep' call from this process. Therefore, we flag the VCPU to be in wait_for_interrupts mode and call the main KVM function kvm_vcpu_block() function. This function will put the thread on a wait-queue and call schedule.

Quoted 7 lines
Quoted 4 lines

When an interrupt comes in through KVM_IRQ_LINE (see previous patch) we signal the VCPU thread and unflag the VCPU to no longer wait for interrupts. All calls to kvm_arch_vcpu_ioctl_run() result in a call to kvm_vcpu_block() as long as the VCPU is in wfi-mode.

Ah, this addresses my previous comment on this issue.

sorry....

Quoted 17 lines

arch/arm/kvm/arm.c static int kvm_arch_vm_ioctl_irq_line(struct kvm *kvm, · line 473

Quoted 10 lines

      return ret;

arch/arm/kvm/arm.c +2 -0
@@ -454,6 +467,8 @@ static int kvm_arch_vm_ioctl_irq_line(struct kvm *kvm,
       if (irq_level->level) {
               vcpu->arch.virt_irq |= mask;
               vcpu->arch.wait_for_interrupts = 0;
 
 
+             if (waitqueue_active(&vcpu->wq))
+                     wake_up_interruptible(&vcpu->wq);

Not sufficient.  If the guest is running, you need to kick it out of guest mode and back into kvm, so that it samples the interrupt lines.

Also, racy:

Quoted 12 lines

racy:
  vcpu          host thread
                KVM_IRQ_LINE
  WFI
  if (!vcpu->arch.virt_irq) vcpu->arch.virt_irq = x vcpu->arch.wait_for_interrupts = 0 vcpu->arch.wait_for_interrupts = 1
                if (waitqueue_active()) (fails) schedule()

ignoring this comment, will deal with your suggestion in the following patch. SORRY.

Quoted 16 lines
Quoted 10 lines
arch/arm/kvm/emulate.c +9 -0
+/**
+ * kvm_handle_wfi - handle a wait-for-interrupts instruction executed by a guest
+ * @vcpu:    the vcpu pointer
+ * @run:     the kvm_run structure pointer
+ *
+ * Simply sets the wait_for_interrupts flag on the vcpu structure, which will
+ * halt execution of world-switches and schedule other host processes until
+ * there is an incoming IRQ or FIQ to the VM.
+ */
Quoted 5 lines

 int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run) {
+     trace_kvm_wfi(vcpu->arch.regs.pc);
+     if (!vcpu->arch.virt_irq)
+             vcpu->arch.wait_for_interrupts = 1;

Quoted 2 lines

Why not just block here?

well, if we block, but receive a signal that we want to go back into userspace for, and then come back but the guest should still be waiting, then I want that flag set, and I think it's the most logical control flow. Am I missing something completely?

Thanks,
Christoffer

#25 lore raw

Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

In reply to Jan Kiszka
Quoted 8 lines · Jan Kiszka

Enabling in-kernel irqchips usually means "switching worlds". So the semantics of these particular IRQ inject interface details may change without breaking anything.

However, things might look different if there will be a need to inject also the CPU IRQs directly, not only the irqchip inputs. In that case, it may make some sense to reserve more space for interrupt types than just one bit and use a common encoding scheme.

I think with an in-kernel GIC model you'd only need to be able to set one of the (256 including internal-to-the-CPU inputs) GIC input lines; the GIC itself then connects directly to the vcpu IRQ and FIQ.

So we could just have different semantics for the ioctl in the 'kernel GIC model enabled' config, as you suggest.

-- PMM

#62 lore raw

Re: [PATCH v5 11/13] ARM: KVM: Support SMP hosts

In reply to Avi Kivity
Quoted 9 lines · Avi Kivity
Quoted 8 lines · Christoffer Dall

In order to support KVM on a SMP host, it is necessary to initialize the hypervisor on all CPUs, mostly by making sure each CPU gets its own hypervisor stack and runs the HYP init code.

We also take care of some missing locking of modifications to the hypervisor page tables and ensure synchronized consistency between virtual IRQ masks and wait_for_interrupt flags on the VPUs.

Quoted 8 lines
Quoted 5 lines

Note that this code doesn't handle CPU hotplug yet. Note that this code doesn't support SMP guests.

WARNING: This code is in development and guests do not fully boot on SMP hosts yet.

Damn, I just reviewed all that breakage.

so sorry...,

Quoted 7 lines
Quoted 5 lines

      /* Misc. fields */
+     spinlock_t irq_lock;
+     u32 virt_irq;           /* HCR exception mask */ u32 wait_for_interrupts;

Better to use atomics, IMO.

hmm, yeah, I guess the way to do it would be to have two fields - one atomic field used for interrupt injection, which is read atomically in the C-code into a plain u32 variable, which can then be copied directly onto the hardware during the world-switch...

Quoted 31 lines
Quoted 17 lines
arch/arm/kvm/arm.c +10 -0
@@ -464,13 +466,27 @@ static int kvm_arch_vm_ioctl_irq_line(struct kvm *kvm,
 
       trace_kvm_irq_line(irq_level->irq % 2, irq_level->level, vcpu_idx);
 
+     spin_lock(&vcpu->arch.irq_lock);
       if (irq_level->level) {
               vcpu->arch.virt_irq |= mask;
+
+             /*
+              * Note that we grab the wq.lock before clearing the wfi flag
+              * since this ensures that a concurrent call to kvm_vcpu_block
+              * will either sleep before we grab the lock, in which case we
+              * wake it up, or will never sleep due to
+              * kvm_arch_vcpu_runnable being true (iow. this avoids having
+              * to grab the irq_lock in kvm_arch_vcpu_runnable).
+              */

arch/arm/kvm/arm.c static int kvm_arch_vm_ioctl_irq_line(struct kvm *kvm, · line 489

Quoted 10 lines
arch/arm/kvm/arm.c +5 -1
+             spin_lock(&vcpu->wq.lock);
               vcpu->arch.wait_for_interrupts = 0;
+
               if (waitqueue_active(&vcpu->wq))
-                     wake_up_interruptible(&vcpu->wq);
+                     __wake_up_locked(&vcpu->wq, TASK_INTERRUPTIBLE);
+             spin_unlock(&vcpu->wq.lock);
       } else
               vcpu->arch.virt_irq &= ~mask;
+     spin_unlock(&vcpu->arch.irq_lock);

This looks overly complicated with two levels of locks.  x86 gets by with no locks, and a much more complicated interrupt architecture.

Quoted 7 lines

My recommendation is:
 wait_for_interrupts is managed solely by the vcpu thread KVM_IRQ_LINE does a set_bit(, virt_irq) for the appropriate irq type, then IPI/wakeups the vcpu to make it examine both wait_for_interrupts and virt_irq.

this sounds pretty good to me.

something like this:

if (irq_level->level) {
	set_bit(&vcpu->arch.irq_lines, bit_nr);
	smp_mb();
	wake_up_interruptible(&vcpu->wq);
} else
	clear_bit(&vcpu->arch.irq_lines, bit_nr);

and the vcpu thread would clear the wait_for_interrupts flag if it ever sees the mask field be non-zero?

Quoted 17 lines
Quoted 17 lines
arch/arm/kvm/arm.c +17 -0
+
+static void cpu_init_hyp_mode(void *vector)
+{
+     unsigned long hyp_stack_ptr;
+     void *stack_page;
+
+     stack_page = __get_cpu_var(kvm_arm_hyp_stack_page);
+     hyp_stack_ptr = (unsigned long)stack_page + PAGE_SIZE;
+
+     cpu_set_vector(vector);
+
+     /*
+      * Call initialization code
+      */
+     asm volatile (
+             "mov    r0, %[pgd_ptr]\n\t"
+             "mov    r1, %[stack_ptr]\n\t"
Quoted 9 lines
Quoted 5 lines

+             "hvc    #0\n\t" : :
+             [pgd_ptr] "r" (virt_to_phys(kvm_hyp_pgd)),
+             [stack_ptr] "r" (hyp_stack_ptr) :
+             "r0", "r1");
+}

(slightly nicer is to allocate hyp_stack_ptr and pgd_ptr to "register asm("r0")" and "register asm("r1")" to avoid the extra mov instruction)

I agree

Quoted 15 lines
Quoted 15 lines
arch/arm/kvm/arm.c +3 -6
@@ -522,47 +573,42 @@ static int init_hyp_mode(void)
               return -ENOMEM;
 
       /*
-      * Allocate stack page for Hypervisor-mode
+      * Allocate stack pages for Hypervisor-mode
        */
-     kvm_arm_hyp_stack_page = (void *)__get_free_page(GFP_KERNEL);
-     if (!kvm_arm_hyp_stack_page) {
-             err = -ENOMEM;
-             goto out_free_pgd;
-     }
+     for_each_possible_cpu(cpu) {
+             void *stack_page;
 
Quoted 5 lines

arch/arm/kvm/arm.c static int init_hyp_mode(void) · line 581

Quoted 2 lines
arch/arm/kvm/arm.c +1 -1
-     hyp_stack_ptr = (unsigned long)kvm_arm_hyp_stack_page + PAGE_SIZE;
+             stack_page = (void *)__get_free_page(GFP_KERNEL);

Best to allocate this (and other per-cpu state) on the cpu's node.

why, for performance reasons? The code get slightly more complicated, since we have to pass the return value through the argument so we have to pass an opaque pointer to the struct or something like that.

Quoted 20 lines
Quoted 20 lines
arch/arm/kvm/arm.c +9 -1
+             if (!stack_page) {
+                     err = -ENOMEM;
+                     goto out_free_pgd;
+             }
+
+             per_cpu(kvm_arm_hyp_stack_page, cpu) = stack_page;
+     }
 
       init_phys_addr = virt_to_phys(__kvm_hyp_init);
       init_end_phys_addr = virt_to_phys(__kvm_hyp_init_end);
+     BUG_ON(init_phys_addr & 0x1f);
 
       /*
-      * Create identity mapping
+      * Create identity mapping for the init code.
        */
       hyp_identity_mapping_add(kvm_hyp_pgd,
                                (unsigned long)init_phys_addr,
                                (unsigned long)init_end_phys_addr);
 
Quoted 8 lines

arch/arm/kvm/arm.c static int init_hyp_mode(void) · line 611

Quoted 4 lines
arch/arm/kvm/arm.c +4 -0
+     for_each_online_cpu(cpu) {
+             smp_call_function_single(cpu, cpu_init_hyp_mode,
+                                      (void *)(long)init_phys_addr, 1);
+     }

Need similar code for cpu hotplug.  See kvm_cpu_hotplug() and kvm_arch_hardware_enable() which do all this for you.

so just to be sure, this will only be called for cpus that are hotplugged right? we still call the cpu_init_hyp_mode for each cpu that's online at this point.

Do we need some locking to make sure the two don't overlap (like should I grab the kvm_lock here)?

author Applied
#86 lore raw

Re: [PATCH v5 12/13] ARM: KVM: Fix guest view of MPIDR

In reply to Avi Kivity
Quoted 11 lines · Avi Kivity
Quoted 4 lines · Christoffer Dall

From: Marc Zyngier <[email protected]>

A guest may need to know which CPU it has booted on (and Linux does). Now that we can run KVM on a SMP host, QEMU may be running on any

s/QEMU/userspace/

Quoted 3 lines

CPU. In that case, directly reading MPIDR will give an inconsistent view on the guest CPU number (among other problems).

Quoted 8 lines
Quoted 4 lines

The solution is to use the VMPIDR register, which is computed by using the host MPIDR and overriding the low bits with KVM vcpu_id.

Since you're posting the patch for (eventual) inclusion, you need to sign off as well.

I merged this into the world-switch patch.

Can I add mark as signed-off-by in there then or should he really have written that entire patch then. Marc?

#10 lore raw

Re: [Android-virt] [PATCH v5 04/13] ARM: KVM: Memory virtualization setup

In reply to Avi Kivity
Quoted 7 lines · Avi Kivity
Quoted 6 lines · Peter Maydell
Quoted 4 lines · Avi Kivity

We need to differentiate in how Linux-as-a-guest acts and how the cpu is supposed to work.  A guest operating system can theoretically assign the ASID x to process A running on vcpu 0, and the same ASID x to process B running on vcpu 1

Quoted 9 lines
Quoted 6 lines

That would be a guest bug. From the ARM ARM:
"For a symmetric multiprocessor cluster where a single operating system is running on the set of processing elements, ARMv7 requires all ASID values to be assigned uniquely within any single Inner Shareable domain. In other words, each ASID value must have the same meaning to all processing elements in the system."

Thanks.  So per-vm vmids should work.

yep.

#26 lore raw

Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

In reply to Peter Maydell
Quoted 10 lines · Peter Maydell
Quoted 8 lines · Jan Kiszka

Enabling in-kernel irqchips usually means "switching worlds". So the semantics of these particular IRQ inject interface details may change without breaking anything.

However, things might look different if there will be a need to inject also the CPU IRQs directly, not only the irqchip inputs. In that case, it may make some sense to reserve more space for interrupt types than just one bit and use a common encoding scheme.

Quoted 6 lines

I think with an in-kernel GIC model you'd only need to be able to set one of the (256 including internal-to-the-CPU inputs) GIC input lines; the GIC itself then connects directly to the vcpu IRQ and FIQ.

So we could just have different semantics for the ioctl in the 'kernel GIC model enabled' config, as you suggest.

btw, since we use the KVM_IRQ_LINE ioctl, it may make sense to require KVM_CREATE_IRQCHIP. To create a kernel GIC model, just call KVM_CREATE_IRQCHIP with a different parameter. This removes an "except for ARM" from the documentation.

Signature · 1 line
error compiling committee.c: too many arguments to function
#57 lore raw

Re: [PATCH v5 10/13] ARM: KVM: Guest wait-for-interrupts (WFI) support

In reply to Christoffer Dall
Quoted 16 lines · Christoffer Dall
Quoted 16 lines
Quoted 15 lines
arch/arm/kvm/emulate.c +12 -0
+/**
+ * kvm_handle_wfi - handle a wait-for-interrupts instruction executed by a guest
+ * @vcpu:    the vcpu pointer
+ * @run:     the kvm_run structure pointer
+ *
+ * Simply sets the wait_for_interrupts flag on the vcpu structure, which will
+ * halt execution of world-switches and schedule other host processes until
+ * there is an incoming IRQ or FIQ to the VM.
+ */
 int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
+     trace_kvm_wfi(vcpu->arch.regs.pc);
+     if (!vcpu->arch.virt_irq)
+             vcpu->arch.wait_for_interrupts = 1;
Quoted 7 lines
Quoted 2 lines

Why not just block here?

well, if we block, but receive a signal that we want to go back into userspace for, and then come back but the guest should still be waiting, then I want that flag set, and I think it's the most logical control flow. Am I missing something completely?

That's just not the flow that the other archs use, I don't think that it really matters. kvm_vcpu_block() checks for and wakes up on signals, so it's okay to call it from here directly.

Signature · 1 line
error compiling committee.c: too many arguments to function
#87 lore raw

Re: [PATCH v5 12/13] ARM: KVM: Fix guest view of MPIDR

In reply to Christoffer Dall
Quoted 17 lines · Christoffer Dall
Quoted 16 lines · Avi Kivity
Quoted 4 lines · Christoffer Dall

From: Marc Zyngier <[email protected]>

A guest may need to know which CPU it has booted on (and Linux does). Now that we can run KVM on a SMP host, QEMU may be running on any

s/QEMU/userspace/

Quoted 7 lines

CPU. In that case, directly reading MPIDR will give an inconsistent view on the guest CPU number (among other problems).

The solution is to use the VMPIDR register, which is computed by using the host MPIDR and overriding the low bits with KVM vcpu_id.

Quoted 7 lines
Quoted 3 lines

Since you're posting the patch for (eventual) inclusion, you need to sign off as well.

I merged this into the world-switch patch.

Can I add mark as signed-off-by in there then or should he really have written that entire patch then. Marc?

I don't mind if my name appears or not, really. As long as the functionality is in, I'm happy ;-).

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#63 lore raw

Re: [PATCH v5 11/13] ARM: KVM: Support SMP hosts

In reply to Christoffer Dall
Quoted 11 lines · Christoffer Dall
Quoted 11 lines

This looks overly complicated with two levels of locks. x86 gets by with no locks, and a much more complicated interrupt architecture.

My recommendation is:
wait_for_interrupts is managed solely by the vcpu thread KVM_IRQ_LINE does a set_bit(, virt_irq) for the appropriate irq type,
then IPI/wakeups the vcpu to make it examine both wait_for_interrupts and virt_irq.

Quoted 8 lines

this sounds pretty good to me.

something like this:

if (irq_level->level) {
	set_bit(&vcpu->arch.irq_lines, bit_nr);
	smp_mb();
	wake_up_interruptible(&vcpu->wq);

or, smp_send_reschedule(). See kvm_vcpu_kick().

An optimization: do a cmpxchg() and don't wakeup if the operation raised IRQ file FIQ was set (assuming that FIQ has a higher priority than IRQ).

Quoted 6 lines

} else

	clear_bit(&vcpu->arch.irq_lines, bit_nr);

and the vcpu thread would clear the wait_for_interrupts flag if it ever sees the mask field be non-zero?

Yes. This is what x86 does, except it's a lot more complicated.

Quoted 15 lines
Quoted 15 lines
Quoted 15 lines
arch/arm/kvm/arm.c +3 -6
@@ -522,47 +573,42 @@ static int init_hyp_mode(void)
              return -ENOMEM;
 
      /*
-      * Allocate stack page for Hypervisor-mode
+      * Allocate stack pages for Hypervisor-mode
       */
-     kvm_arm_hyp_stack_page = (void *)__get_free_page(GFP_KERNEL);
-     if (!kvm_arm_hyp_stack_page) {
-             err = -ENOMEM;
-             goto out_free_pgd;
-     }
+     for_each_possible_cpu(cpu) {
+             void *stack_page;
 
Quoted 7 lines
Quoted 5 lines

arch/arm/kvm/arm.c static int init_hyp_mode(void) · line 581

Quoted 2 lines
arch/arm/kvm/arm.c +1 -1
-     hyp_stack_ptr = (unsigned long)kvm_arm_hyp_stack_page + PAGE_SIZE;
+             stack_page = (void *)__get_free_page(GFP_KERNEL);

Best to allocate this (and other per-cpu state) on the cpu's node.

why, for performance reasons?

Yes, I'm assuming that all multi-socket A15s will be numa?

Quoted 3 lines

The code get slightly more complicated,
since we have to pass the return value through the argument so we have to pass an opaque pointer to the struct or something like that.

Don't see why, just use alloc_pages_node().

Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
arch/arm/kvm/arm.c +4 -0
+     for_each_online_cpu(cpu) {
+             smp_call_function_single(cpu, cpu_init_hyp_mode,
+                                      (void *)(long)init_phys_addr, 1);
+     }
Quoted 6 lines
Quoted 3 lines

Need similar code for cpu hotplug. See kvm_cpu_hotplug() and kvm_arch_hardware_enable() which do all this for you.

so just to be sure, this will only be called for cpus that are hotplugged right? we still call the cpu_init_hyp_mode for each cpu that's online at this point.

The infrastructure will call kvm_arch_hardware_enable() for all currently online cpus and any future hotplugged cpu. Just follow kvm_init() and fill in the arch callbacks. You do have a call to kvm_init() somewhere, yes?

Quoted 2 lines

Do we need some locking to make sure the two don't overlap (like should I grab the kvm_lock here)?

Let kvm_init() do the driving and relax.

Signature · 1 line
error compiling committee.c: too many arguments to function
#58 lore raw

Re: [Android-virt] [PATCH v5 10/13] ARM: KVM: Guest wait-for-interrupts (WFI) support

In reply to Avi Kivity
Quoted 20 lines · Avi Kivity
Quoted 19 lines · Christoffer Dall
Quoted 18 lines
Quoted 15 lines

+/**
+ * kvm_handle_wfi - handle a wait-for-interrupts instruction executed by a guest
+ * @vcpu:    the vcpu pointer
+ * @run:     the kvm_run structure pointer
+ *
+ * Simply sets the wait_for_interrupts flag on the vcpu structure, which will
+ * halt execution of world-switches and schedule other host processes until
+ * there is an incoming IRQ or FIQ to the VM.
+ */
 int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
+     trace_kvm_wfi(vcpu->arch.regs.pc);
+     if (!vcpu->arch.virt_irq)
+             vcpu->arch.wait_for_interrupts = 1;

Why not just block here?

Quoted 9 lines
Quoted 4 lines

well, if we block, but receive a signal that we want to go back into userspace for, and then come back but the guest should still be waiting, then I want that flag set, and I think it's the most logical control flow. Am I missing something completely?

That's just not the flow that the other archs use, I don't think that it really matters.  kvm_vcpu_block() checks for and wakes up on signals, so it's okay to call it from here directly.

yes, but I still have to perform the check again in the main run function if it woke up for anything else than a guest interrupt, so why call it twice...

#64 lore raw

Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts

In reply to Avi Kivity
Quoted 56 lines · Avi Kivity
Quoted 11 lines · Christoffer Dall
Quoted 11 lines

This looks overly complicated with two levels of locks.  x86 gets by with no locks, and a much more complicated interrupt architecture.

My recommendation is:
 wait_for_interrupts is managed solely by the vcpu thread KVM_IRQ_LINE does a set_bit(, virt_irq) for the appropriate irq type, then IPI/wakeups the vcpu to make it examine both wait_for_interrupts and virt_irq.

Quoted 8 lines

this sounds pretty good to me.

something like this:

if (irq_level->level) {
      set_bit(&vcpu->arch.irq_lines, bit_nr);
      smp_mb();
      wake_up_interruptible(&vcpu->wq);

or, smp_send_reschedule().  See kvm_vcpu_kick().

An optimization: do a cmpxchg() and don't wakeup if the operation raised IRQ file FIQ was set (assuming that FIQ has a higher priority than IRQ).

Quoted 6 lines

} else
      clear_bit(&vcpu->arch.irq_lines, bit_nr);

and the vcpu thread would clear the wait_for_interrupts flag if it ever sees the mask field be non-zero?

Yes.  This is what x86 does, except it's a lot more complicated.

Quoted 21 lines
Quoted 20 lines
Quoted 7 lines
arch/arm/kvm/arm.c +1 -1
@@ -522,47 +573,42 @@ static int init_hyp_mode(void)
               return -ENOMEM;
 
       /*
-      * Allocate stack page for Hypervisor-mode
+      * Allocate stack pages for Hypervisor-mode
        */

arch/arm/kvm/arm.c static int init_hyp_mode(void) · line 581

Quoted 10 lines
arch/arm/kvm/arm.c +3 -6
-     kvm_arm_hyp_stack_page = (void *)__get_free_page(GFP_KERNEL);
-     if (!kvm_arm_hyp_stack_page) {
-             err = -ENOMEM;
-             goto out_free_pgd;
-     }
+     for_each_possible_cpu(cpu) {
+             void *stack_page;
 
-     hyp_stack_ptr = (unsigned long)kvm_arm_hyp_stack_page + PAGE_SIZE;
+             stack_page = (void *)__get_free_page(GFP_KERNEL);

Best to allocate this (and other per-cpu state) on the cpu's node.

Quoted 4 lines
Quoted 1 line

why, for performance reasons?

Yes, I'm assuming that all multi-socket A15s will be numa?

I have no idea. Marc, Peter, Catalin?

Quoted 6 lines
Quoted 3 lines

The code get slightly more complicated,
since we have to pass the return value through the argument so we have to pass an opaque pointer to the struct or something like that.

Don't see why, just use alloc_pages_node().

got it, I thought you wanted to issue the actual allocation from each cpu as to parallelize the work. Now I understand.

Quoted 18 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
arch/arm/kvm/arm.c +4 -0
+     for_each_online_cpu(cpu) {
+             smp_call_function_single(cpu, cpu_init_hyp_mode,
+                                      (void *)(long)init_phys_addr, 1);
+     }
Quoted 6 lines
Quoted 3 lines

Need similar code for cpu hotplug.  See kvm_cpu_hotplug() and kvm_arch_hardware_enable() which do all this for you.

so just to be sure, this will only be called for cpus that are hotplugged right? we still call the cpu_init_hyp_mode for each cpu that's online at this point.

The infrastructure will call kvm_arch_hardware_enable() for all currently online cpus and any future hotplugged cpu.  Just follow kvm_init() and fill in the arch callbacks.  You do have a call to kvm_init() somewhere, yes?

Quoted 5 lines
Quoted 2 lines

Do we need some locking to make sure the two don't overlap (like should I grab the kvm_lock here)?

Let kvm_init() do the driving and relax.

This sounds good (actually looking into this was on my todo list, so now is a good time I guess).

#88 lore raw

Re: [PATCH v5 12/13] ARM: KVM: Fix guest view of MPIDR

In reply to Marc Zyngier
Quoted 21 lines · Marc Zyngier
Quoted 20 lines · Christoffer Dall
Quoted 19 lines · Avi Kivity
Quoted 4 lines · Christoffer Dall

From: Marc Zyngier <[email protected]>

A guest may need to know which CPU it has booted on (and Linux does). Now that we can run KVM on a SMP host, QEMU may be running on any

s/QEMU/userspace/

Quoted 7 lines

CPU. In that case, directly reading MPIDR will give an inconsistent view on the guest CPU number (among other problems).

The solution is to use the VMPIDR register, which is computed by using the host MPIDR and overriding the low bits with KVM vcpu_id.

Since you're posting the patch for (eventual) inclusion, you need to sign off as well.

Quoted 8 lines
Quoted 4 lines

I merged this into the world-switch patch.

Can I add mark as signed-off-by in there then or should he really have written that entire patch then. Marc?

I don't mind if my name appears or not, really. As long as the functionality is in, I'm happy ;-).

ok, focus will be on patch readability for next round then. thanks.

#44 lore raw

Re: [PATCH v5 08/13] ARM: KVM: Handle guest faults in KVM

In reply to Avi Kivity
Quoted 10 lines · Avi Kivity
Quoted 9 lines · Christoffer Dall

From: Christoffer Dall <[email protected]>

Handles the guest faults in KVM by mapping in corresponding user pages in the 2nd stage page tables.

Introduces new ARM-specific kernel memory types, PAGE_KVM_GUEST and pgprot_guest variables used to map 2nd stage memory for KVM guests.

Quoted 15 lines

arch/arm/kvm/mmu.c void kvm_free_stage2_pgd(struct kvm *kvm) · line 243

Quoted 12 lines
arch/arm/kvm/mmu.c +12 -0
+static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
+                       gfn_t gfn, struct kvm_memory_slot *memslot)
+{
+     pfn_t pfn;
+     pgd_t *pgd;
+     pud_t *pud;
+     pmd_t *pmd;
+     pte_t *pte, new_pte;
+
+     pfn = gfn_to_pfn(vcpu->kvm, gfn);
+
+     if (is_error_pfn(pfn)) {

put_page()

ack

Quoted 14 lines
Quoted 5 lines

+             kvm_err(-EFAULT, "Guest gfn %u (0x%08lx) does not have "
+                             "corresponding host mapping",
+                             gfn, gfn << PAGE_SHIFT);
+             return -EFAULT;
+     }

Quoted 8 lines

+
+     /* Create 2nd stage page table mapping - Level 1 */
+     pgd = vcpu->kvm->arch.pgd + pgd_index(fault_ipa);
+     pud = pud_offset(pgd, fault_ipa);
+     if (pud_none(*pud)) {
+             pmd = pmd_alloc_one(NULL, fault_ipa);
+             if (!pmd) {
+                     kvm_err(-ENOMEM, "Cannot allocate 2nd stage pmd");

Quoted 2 lines

put_page()

ack

Quoted 29 lines
Quoted 12 lines

+                     return -ENOMEM;
+             }
+             pud_populate(NULL, pud, pmd);
+             pmd += pmd_index(fault_ipa);
+     } else
+             pmd = pmd_offset(pud, fault_ipa);

arch/arm/kvm/mmu.c +6 -0
+
+     /* Create 2nd stage page table mapping - Level 2 */
+     if (pmd_none(*pmd)) {
+             pte = pte_alloc_one_kernel(NULL, fault_ipa);
+             if (!pte) {
+                     kvm_err(-ENOMEM, "Cannot allocate 2nd stage pte");

arch/arm/kvm/mmu.c void kvm_free_stage2_pgd(struct kvm *kvm) · line 278

Quoted 10 lines
arch/arm/kvm/mmu.c +10 -0
+                     return -ENOMEM;
+             }
+             pmd_populate_kernel(NULL, pmd, pte);
+             pte += pte_index(fault_ipa);
+     } else
+             pte = pte_offset_kernel(pmd, fault_ipa);
+
+     /* Create 2nd stage page table mapping - Level 3 */
+     new_pte = pfn_pte(pfn, PAGE_KVM_GUEST);
+     set_pte_ext(pte, new_pte, 0);

With LPAE and 40-bit addresses, a guest can cause 2GBs worth of page tables to be pinned in host memory; this can be used as a denial of service attack.  x86 handles this by having a shrinker that can dynamically free page tables, see mmu_shrinker.

Quoted 6 lines

An alternative way may be to impose RLIMIT_AS on the sum of a guest's memory slots; though I prefer having a shrinker.

A bigger problem is that you pin all memory; what are the plans wrt mmu notifiers?

hmm, I have no plans (yet).

I haven't looked into neither MMU shrinker nor MMU notifier.

As I see it, the problems of consuming too much memory just for the page tables should be solved by somehow reclaiming pages used for the second stage mappings, the question is just which mappings are the most efficient to reclaim.

The other problem, the actual guest memory consuming too much memory, I assumed this limit would be set by the user when creating his/her VM, or can we do something smarter? (again, forgive my ignorance). What is the alternative to pinning actual guest pages - as far as I know it's not common to have swap space on ARM architectures, but I could be wrong.

#59 lore raw

Re: [Android-virt] [PATCH v5 10/13] ARM: KVM: Guest wait-for-interrupts (WFI) support

In reply to Christoffer Dall
Quoted 6 lines · Christoffer Dall
Quoted 6 lines
Quoted 5 lines

well, if we block, but receive a signal that we want to go back into userspace for, and then come back but the guest should still be waiting, then I want that flag set, and I think it's the most logical control flow. Am I missing something completely?

Quoted 7 lines
Quoted 4 lines

That's just not the flow that the other archs use, I don't think that it really matters. kvm_vcpu_block() checks for and wakes up on signals, so it's okay to call it from here directly.

yes, but I still have to perform the check again in the main run function if it woke up for anything else than a guest interrupt, so why call it twice...

You're right and in fact that's how x86 works too. I misremembered.

Signature · 1 line
error compiling committee.c: too many arguments to function
#45 lore raw

Re: [PATCH v5 08/13] ARM: KVM: Handle guest faults in KVM

In reply to Christoffer Dall
Quoted 11 lines · Christoffer Dall
Quoted 4 lines

A bigger problem is that you pin all memory; what are the plans wrt mmu notifiers?

hmm, I have no plans (yet).

I haven't looked into neither MMU shrinker nor MMU notifier.

As I see it, the problems of consuming too much memory just for the page tables should be solved by somehow reclaiming pages used for the second stage mappings,

That's what the shrinker does.

Quoted 2 lines

the question is just which mappings are the
most efficient to reclaim.

Do you have accessed bits in those PTEs?

It's not really critical to have efficient reclaim here, since it happens so rarely. It just needs to do something.

Quoted 4 lines

The other problem, the actual guest memory consuming too much memory, I assumed this limit would be set by the user when creating his/her VM, or can we do something smarter? (again, forgive my ignorance). What is the alternative to pinning actual guest pages

mmu notifiers - pages aren't pinned; instead, Linux calls back into kvm when modifying a host pte, and kvm responds by dropping or modifying its translation (second stage pte in your case).

Quoted 3 lines

- as far as I
know it's not common to have swap space on ARM architectures, but I could be wrong.

It will become common once you start doing servers.

mmu notifiers are also useful for other optimizations, like ksm, ballooning, and transparent huge pages.

Signature · 1 line
error compiling committee.c: too many arguments to function
#89 lore raw

Re: [PATCH v5 12/13] ARM: KVM: Fix guest view of MPIDR

In reply to Christoffer Dall
Quoted 2 lines · Christoffer Dall
Quoted 1 line

ok, focus will be on patch readability for next round then. thanks.

Great, please try to keep your submarine surfaced for longer periods of time so we can interact better.

Signature · 1 line
error compiling committee.c: too many arguments to function
#46 lore raw

Re: [Android-virt] [PATCH v5 08/13] ARM: KVM: Handle guest faults in KVM

In reply to Avi Kivity
Quoted 7 lines · Avi Kivity
Quoted 6 lines · Christoffer Dall
Quoted 4 lines

A bigger problem is that you pin all memory; what are the plans wrt mmu notifiers?

hmm, I have no plans (yet).

Quoted 8 lines
Quoted 5 lines

I haven't looked into neither MMU shrinker nor MMU notifier.

As I see it, the problems of consuming too much memory just for the page tables should be solved by somehow reclaiming pages used for the second stage mappings,

That's what the shrinker does.

ok, that's what I thought.

Quoted 5 lines
Quoted 2 lines

the question is just which mappings are the
most efficient to reclaim.

Do you have accessed bits in those PTEs?

nope. We can protect the underlying target pages though, but...

Quoted 3 lines

It's not really critical to have efficient reclaim here, since it happens so rarely.  It just needs to do something.

when would you trigger it - when it reaches a certain limit, or? And then what, free the lot and re-allocate what's needed?

Quoted 9 lines
Quoted 4 lines

The other problem, the actual guest memory consuming too much memory, I assumed this limit would be set by the user when creating his/her VM, or can we do something smarter? (again, forgive my ignorance). What is the alternative to pinning actual guest pages

mmu notifiers - pages aren't pinned; instead, Linux calls back into kvm when modifying a host pte, and kvm responds by dropping or modifying its translation (second stage pte in your case).

ah ok, so this works across VM boundary. Based on hyper-calls I presume?

Quoted 6 lines
Quoted 3 lines

 - as far as I
know it's not common to have swap space on ARM architectures, but I could be wrong.

It will become common once you start doing servers.

I think so too, but I am not sure if it's completely supported for ARM. Is it all arch-independent or do we miss arm-specific pieces? Marc?

Quoted 3 lines

mmu notifiers are also useful for other optimizations, like ksm, ballooning, and transparent huge pages.

I know those features have to be supported eventually. The question is if all this must be in place before a merge upstream?

Thanks,
Christoffer

#47 lore raw

Re: [Android-virt] [PATCH v5 08/13] ARM: KVM: Handle guest faults in KVM

Quoted 6 lines · Christoffer Dall
Quoted 5 lines · Avi Kivity
Quoted 3 lines · Christoffer Dall

- as far as I
know it's not common to have swap space on ARM architectures, but I could be wrong.

Quoted 6 lines
Quoted 2 lines

It will become common once you start doing servers.

I think so too, but I am not sure if it's completely supported for ARM. Is it all arch-independent or do we miss arm-specific pieces? Marc?

Swapping definitely works as expected on ARM (and if it doesn't, it's a major bug and should be tackled immediately).

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#48 lore raw

Re: [Android-virt] [PATCH v5 08/13] ARM: KVM: Handle guest faults in KVM

In reply to Christoffer Dall
Quoted 7 lines · Christoffer Dall
Quoted 5 lines
Quoted 2 lines

the question is just which mappings are the
most efficient to reclaim.

Do you have accessed bits in those PTEs?

nope. We can protect the underlying target pages though, but...

Yeah, we have the same issue with one of the vendors. Fortunately only 90% of the market is affected.

Quoted 6 lines
Quoted 3 lines

It's not really critical to have efficient reclaim here, since it happens so rarely. It just needs to do something.

when would you trigger it - when it reaches a certain limit, or? And then what, free the lot and re-allocate what's needed?

The kernel triggers it based on internal pressure. It tells you how much pressure to apply, so you just translate it to a number of pages to free.

Quoted 11 lines
Quoted 9 lines
Quoted 4 lines

The other problem, the actual guest memory consuming too much memory, I assumed this limit would be set by the user when creating his/her VM, or can we do something smarter? (again, forgive my ignorance). What is the alternative to pinning actual guest pages

mmu notifiers - pages aren't pinned; instead, Linux calls back into kvm when modifying a host pte, and kvm responds by dropping or modifying its translation (second stage pte in your case).

ah ok, so this works across VM boundary. Based on hyper-calls I presume?

No, it's completely internal to the host.

See for example kvm_mmu_notifier_invalidate_page() (in common code). It's called when Linux-as-host wants to change a pte (say to swap a page). kvm responds by translating the host virtual address into a guest physical address (via the memory slots table), then zapping the relevant pte and flushing and TLBs which may have cached the pte.

Quoted 6 lines
Quoted 3 lines

mmu notifiers are also useful for other optimizations, like ksm, ballooning, and transparent huge pages.

I know those features have to be supported eventually. The question is if all this must be in place before a merge upstream?

It doesn't have to be there for the merge but I recommend giving it high priority. At least read and understand the code so the addition will follow naturally.

Signature · 1 line
error compiling committee.c: too many arguments to function
#67 lore raw

Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts

In reply to a message not in the archive
Quoted 26 lines · Avi Kivity
Quoted 10 lines · Christoffer Dall
Quoted 10 lines
Quoted 7 lines

something like this:

if (irq_level->level) {
      set_bit(&vcpu->arch.irq_lines, bit_nr);
      smp_mb();
      wake_up_interruptible(&vcpu->wq);

or, smp_send_reschedule().  See kvm_vcpu_kick().

Quoted 7 lines
Quoted 3 lines

An optimization: do a cmpxchg() and don't wakeup if the operation raised IRQ file FIQ was set (assuming that FIQ has a higher priority than IRQ).

forgive my lack of experience here:

how would you use cmpxchg exactly?

cmpxchg is used as a fallback for general test-and-change which doesn't fit any other atomic operation.  In this case:

 do {
   virt_intr = ACCESS_ONCE(vcpu->virt_intr)
   new_virt_intr = virt_intr | mask

Quoted 8 lines

   if (new_virt_intr == virt_intr)
       return;  /* no change */

 } while (!cmpxchg(vcpu->virt_intr, virt_intr, new_virt_intr)

 /* at this point, we know the old and new values, and we know the update was atomic */

heh, nice. thanks.

Quoted 5 lines

 if (new_virt_intr == IRQ | FIQ && virt_intr == FIQ) { /* IRQ raised, FIQ already set */ return;
 }

hmm, so what you want to avoid here is sending an IPI to the other CPU in case we already have FIQ raised? But I think we have to do this anyhow. If a guest is servicing a raised FIQ and have FIQs masked, but the GIC hasn't lowered the FIQ line yet, and now comes an IRQ, if the IRQ is unmasked we want to change the hypervisor virtual IRQ register right away as to signal an IRQ immediately and if the guest masks IRQ we still want to change the hypervisor virtual register so that the moment the guest unmasks the IRQ, an exception is raised. The only way to set the hypervisor register for another CPU would be to have it take a world-switch round.

So, I think if we simply change either of these lines, we need to signal the other CPU.

Marc, can you confirm?

Quoted 8 lines
Quoted 8 lines

yes, FIQ takes priority over IRQ, but we need to raise the IRQ flag anyway.

I can see that we don't have to call the wake_up function unless the old value was 0 (no interrupts pending == raising the first one). Is this what you mean? If so, I can't seem to wrap my head around how to accomplish this elegantly with cmpxchg...?

Quoted 8 lines
Quoted 4 lines

Then, another issue. I am going to need to two fields and then a memcpy, since I don't want to be reading an atomic value from my world-switch code. (I would need this copy even with a spinlock). Agree?

Don't follow.  Why a memcpy?  why don't you want to read an atomic value during world switch?

if it was declared as an atomic_t, since that's theoretically opaque, could change to 64-bit and so on, I thought it would be ugly to read that in the world-switch assembler code. But using atomic bitops on a standard long field, we should be fine.

Quoted 6 lines
Quoted 2 lines

But, if I am doing atomic bitops on an unsigned long field, how do I read that (or test two bits at once) atomically?

Reads (and writes) are always atomic.  Its read-modify-write that needs special treatment.

embarrassing. I actually thought read/writes of a word could be partial to the byte between SMP nodes, but it turns out, and as you say, they cannot. Got it.

Thanks again!

#90 lore raw

Re: [PATCH v5 12/13] ARM: KVM: Fix guest view of MPIDR

In reply to Avi Kivity
Quoted 7 lines · Avi Kivity
Quoted 2 lines · Christoffer Dall
Quoted 1 line

ok, focus will be on patch readability for next round then. thanks.

Great, please try to keep your submarine surfaced for longer periods of time so we can interact better.

we will do our best, now there's also Virtual Open Systems and ARM people involved, so let's try and push this as much as we can in the near coming future.

#49 lore raw

Re: [Android-virt] [PATCH v5 08/13] ARM: KVM: Handle guest faults in KVM

In reply to Avi Kivity
Quoted 4 lines · Avi Kivity
Quoted 3 lines · Christoffer Dall
Quoted 3 lines
Quoted 2 lines

the question is just which mappings are the
most efficient to reclaim.

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

Do you have accessed bits in those PTEs?

nope. We can protect the underlying target pages though, but...

Yeah, we have the same issue with one of the vendors.  Fortunately only 90% of the market is affected.

:)

Quoted 4 lines
Quoted 4 lines
Quoted 3 lines

It's not really critical to have efficient reclaim here, since it happens so rarely.  It just needs to do something.

Quoted 8 lines
Quoted 2 lines

when would you trigger it - when it reaches a certain limit, or? And then what, free the lot and re-allocate what's needed?

The kernel triggers it based on internal pressure.  It tells you how much pressure to apply, so you just translate it to a number of pages to free.

ok, so we pick those pages at random? (perhaps trying to avoid hitting the guest kernel at least for Linux, or...?)

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 4 lines

The other problem, the actual guest memory consuming too much memory, I assumed this limit would be set by the user when creating his/her VM, or can we do something smarter? (again, forgive my ignorance). What is the alternative to pinning actual guest pages

Quoted 9 lines
Quoted 6 lines
Quoted 4 lines

mmu notifiers - pages aren't pinned; instead, Linux calls back into kvm when modifying a host pte, and kvm responds by dropping or modifying its translation (second stage pte in your case).

ah ok, so this works across VM boundary. Based on hyper-calls I presume?

No, it's completely internal to the host.

ok, got you. I got thrown off by the "Linux calls back into kvm" statement.

Quoted 10 lines

See for example kvm_mmu_notifier_invalidate_page() (in common code). It's called when Linux-as-host wants to change a pte (say to swap a page).  kvm responds by translating the host virtual address into a guest physical address (via the memory slots table), then zapping the relevant pte and flushing and TLBs which may have cached the pte.

Quoted 4 lines
Quoted 3 lines

mmu notifiers are also useful for other optimizations, like ksm, ballooning, and transparent huge pages.

Quoted 7 lines
Quoted 2 lines

I know those features have to be supported eventually. The question is if all this must be in place before a merge upstream?

It doesn't have to be there for the merge but I recommend giving it high priority.  At least read and understand the code so the addition will follow naturally.

will do - I will make it a Christmas activity.

#68 lore raw

Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts

In reply to Christoffer Dall
Quoted 6 lines · Christoffer Dall
Quoted 5 lines
 if (new_virt_intr == IRQ | FIQ && virt_intr == FIQ) {
     /* IRQ raised, FIQ already set */
     return;

}

Quoted 10 lines

hmm, so what you want to avoid here is sending an IPI to the other CPU in case we already have FIQ raised? But I think we have to do this anyhow. If a guest is servicing a raised FIQ and have FIQs masked, but the GIC hasn't lowered the FIQ line yet, and now comes an IRQ, if the IRQ is unmasked we want to change the hypervisor virtual IRQ register right away as to signal an IRQ immediately and if the guest masks IRQ we still want to change the hypervisor virtual register so that the moment the guest unmasks the IRQ, an exception is raised. The only way to set the hypervisor register for another CPU would be to have it take a world-switch round.

Ah, if the register is virtualized, indeed you need to signal immediately.

Quoted 9 lines
Quoted 6 lines
Quoted 2 lines

But, if I am doing atomic bitops on an unsigned long field, how do I read that (or test two bits at once) atomically?

Reads (and writes) are always atomic. Its read-modify-write that needs special treatment.

embarrassing. I actually thought read/writes of a word could be partial to the byte between SMP nodes, but it turns out, and as you say, they cannot. Got it.

Read Documentation/atomic_ops.txt and Documentation/memory-barriers.txt, it's a tricky subject.

Signature · 1 line
error compiling committee.c: too many arguments to function
#70 lore raw

Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts

In reply to Christoffer Dall
Quoted 18 lines · Christoffer Dall
Quoted 5 lines · Avi Kivity
 if (new_virt_intr == IRQ | FIQ && virt_intr == FIQ) {
     /* IRQ raised, FIQ already set */
     return;

}

hmm, so what you want to avoid here is sending an IPI to the other CPU in case we already have FIQ raised? But I think we have to do this anyhow. If a guest is servicing a raised FIQ and have FIQs masked, but the GIC hasn't lowered the FIQ line yet, and now comes an IRQ, if the IRQ is unmasked we want to change the hypervisor virtual IRQ register right away as to signal an IRQ immediately and if the guest masks IRQ we still want to change the hypervisor virtual register so that the moment the guest unmasks the IRQ, an exception is raised. The only way to set the hypervisor register for another CPU would be to have it take a world-switch round.

Quoted 4 lines

So, I think if we simply change either of these lines, we need to signal the other CPU.

Marc, can you confirm?

We definitely need to signal the CPU an IRQ is pending. The VGIC may help us here, as we can access another CPU's VGIC List Registers (via the processor-specific base address of the Virtual interface control). That would save sending an IPI to the target CPU.

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#50 lore raw

Re: [Android-virt] [PATCH v5 08/13] ARM: KVM: Handle guest faults in KVM

In reply to Christoffer Dall
Quoted 7 lines · Christoffer Dall
Quoted 7 lines
Quoted 6 lines
Quoted 3 lines

It's not really critical to have efficient reclaim here, since it happens so rarely. It just needs to do something.

when would you trigger it - when it reaches a certain limit, or? And then what, free the lot and re-allocate what's needed?

Quoted 8 lines
Quoted 5 lines

The kernel triggers it based on internal pressure. It tells you how much pressure to apply, so you just translate it to a number of pages to free.

ok, so we pick those pages at random? (perhaps trying to avoid hitting the guest kernel at least for Linux, or...?)

x86 has a sort of poorly managed LRU; it's wildly inaccurate but doesn't hurt in practice since it only triggers under severe memory pressure anyway.

Quoted 5 lines
Quoted 4 lines

It doesn't have to be there for the merge but I recommend giving it high priority. At least read and understand the code so the addition will follow naturally.

will do - I will make it a Christmas activity.

I was hoping to to get the ARM port as a present...

Signature · 1 line
error compiling committee.c: too many arguments to function
#69 lore raw

Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts

In reply to Avi Kivity
Quoted 26 lines · Avi Kivity
Quoted 6 lines · Christoffer Dall
Quoted 5 lines
if (new_virt_intr == IRQ | FIQ && virt_intr == FIQ) {
    /* IRQ raised, FIQ already set */
    return;
}
Quoted 10 lines

hmm, so what you want to avoid here is sending an IPI to the other CPU in case we already have FIQ raised? But I think we have to do this anyhow. If a guest is servicing a raised FIQ and have FIQs masked, but the GIC hasn't lowered the FIQ line yet, and now comes an IRQ, if the IRQ is unmasked we want to change the hypervisor virtual IRQ register right away as to signal an IRQ immediately and if the guest masks IRQ we still want to change the hypervisor virtual register so that the moment the guest unmasks the IRQ, an exception is raised. The only way to set the hypervisor register for another CPU would be to have it take a world-switch round.

Ah, if the register is virtualized, indeed you need to signal immediately.

Quoted 6 lines
Quoted 6 lines
Quoted 2 lines

But, if I am doing atomic bitops on an unsigned long field, how do I read that (or test two bits at once) atomically?

Reads (and writes) are always atomic. Its read-modify-write that needs special treatment.

Quoted 7 lines
Quoted 3 lines

embarrassing. I actually thought read/writes of a word could be partial to the byte between SMP nodes, but it turns out, and as you say, they cannot. Got it.

Read Documentation/atomic_ops.txt and Documentation/memory-barriers.txt, it's a tricky subject.

Actually I did (yes the memory barriers hurt my brain), but I kind of missed the most basic level of memory atomicity - there was a nice section about this in the ARM arm though.

Thanks for helping out on all this!

#11 lore raw

Re: [Android-virt] [PATCH v5 04/13] ARM: KVM: Memory virtualization setup

In reply to Avi Kivity
Quoted 6 lines · Avi Kivity
Quoted 5 lines · Peter Maydell
Quoted 4 lines · Avi Kivity

We need to differentiate in how Linux-as-a-guest acts and how the cpu is supposed to work. A guest operating system can theoretically assign the ASID x to process A running on vcpu 0, and the same ASID x to process B running on vcpu 1

Quoted 8 lines
Quoted 6 lines

That would be a guest bug. From the ARM ARM:
"For a symmetric multiprocessor cluster where a single operating system is running on the set of processing elements, ARMv7 requires all ASID values to be assigned uniquely within any single Inner Shareable domain. In other words, each ASID value must have the same meaning to all processing elements in the system."

Thanks. So per-vm vmids should work.

We where playing with a VMID recycling patch based on the assumption of per-cpu VMIDs being possible, which would have the advantage of recycling VMIDs without much complicated locking (inspired by the KVM SVM implementation). However we killed it with fire and hot plasma when it became clear it violated the ARM spec...

On the other hand, maybe we could do something with per vcpu VMIDs, but with proper synchronization accross physical CPUs in order to be compatible with the spec, but at the same time potentially allow a buggy guest to run? Since in practice a lot of CPUs will not share TLB (and instruction cache) structures, maybe it's possible that there is software out there that violates the spec, without having problems on the real hw.

Anyway VMID reuse will be available soon, and the difference between a per vm and per vcpu implementation is a couple of trivial lines of code.

#12 lore raw

Re: [Android-virt] [PATCH v5 04/13] ARM: KVM: Memory virtualization setup

Quoted 29 lines · Antonios Motakis
Quoted 6 lines · Avi Kivity
Quoted 5 lines · Peter Maydell
Quoted 4 lines · Avi Kivity

We need to differentiate in how Linux-as-a-guest acts and how the cpu is supposed to work.  A guest operating system can theoretically assign the ASID x to process A running on vcpu 0, and the same ASID x to process B running on vcpu 1

Quoted 8 lines
Quoted 6 lines

That would be a guest bug. From the ARM ARM:
"For a symmetric multiprocessor cluster where a single operating system is running on the set of processing elements, ARMv7 requires all ASID values to be assigned uniquely within any single Inner Shareable domain. In other words, each ASID value must have the same meaning to all processing elements in the system."

Thanks.  So per-vm vmids should work.

We where playing with a VMID recycling patch based on the assumption of per-cpu VMIDs being possible, which would have the advantage of recycling VMIDs without much complicated locking (inspired by the KVM SVM implementation). However we killed it with fire and hot plasma when it became clear it violated the ARM spec...

On the other hand, maybe we could do something with per vcpu VMIDs, but with proper synchronization accross physical CPUs in order to be compatible with the spec, but at the same time potentially allow a buggy guest to run? Since in practice a lot of CPUs will not share TLB (and instruction cache) structures, maybe it's possible that there is software out there that violates the spec, without having problems on the real hw.

Quoted 3 lines

Anyway VMID reuse will be available soon, and the difference between a per vm and per vcpu implementation is a couple of trivial lines of code.

yes, this is going to be a simple per-vm implementation that flushes TLBs on roll-over for the next patch series, let's leave it at that for now!

#71 lore raw

Re: [PATCH v5 11/13] ARM: KVM: Support SMP hosts

In reply to Christoffer Dall
Quoted 2 lines · Christoffer Dall

WARNING: This code is in development and guests do not fully boot on SMP hosts yet.

Hello,

What would still be needed to fully booted SMP? For example, are there identified critical sections and structures that need to be worked on, or there are parts that still need to be reviewed to find those? Or is it only a matter of fixing up any existing locking/syncing introduced in this patch?

I'd like to throw some cycles on this, so I'll start by looking in this patch again more carefully (and guest SMP as well).

Antonios

#72 lore raw

Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts

Quoted 11 lines · Antonios Motakis
Quoted 2 lines · Christoffer Dall

WARNING: This code is in development and guests do not fully boot on SMP hosts yet.

Hello,

What would still be needed to fully booted SMP? For example, are there identified critical sections and structures that need to be worked on, or there are parts that still need to be reviewed to find those? Or is it only a matter of fixing up any existing locking/syncing introduced in this patch?

You should simply start booting a UP guest on an SMP host, see where it crashes and start tracking it down.

Same procedure for guest SMP.

Quoted 3 lines

I'd like to throw some cycles on this, so I'll start by looking in this patch again more carefully (and guest SMP as well).

that sounds good, just go for it.

#73 lore raw

Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts

Quoted 14 lines · Christoffer Dall
Quoted 11 lines · Antonios Motakis
Quoted 2 lines · Christoffer Dall

WARNING: This code is in development and guests do not fully boot on SMP hosts yet.

Hello,

What would still be needed to fully booted SMP? For example, are there identified critical sections and structures that need to be worked on, or there are parts that still need to be reviewed to find those? Or is it only a matter of fixing up any existing locking/syncing introduced in this patch?

Quoted 2 lines

You should simply start booting a UP guest on an SMP host, see where it crashes and start tracking it down.

For the time being, I've yet to see UP guest crashing on SMP host. On the model, that is...

Quoted 1 line

Same procedure for guest SMP.

That's a very different kettle of fish. I see both CPUs starting to run, and end up with both in WFI after a while, without any interrupt pending...

I'll investigate that as soon as I can.

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#74 lore raw

Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts

Quoted 9 lines · Marc Zyngier
Quoted 4 lines · Christoffer Dall

You should simply start booting a UP guest on an SMP host, see where it crashes and start tracking it down.

For the time being, I've yet to see UP guest crashing on SMP host. On the model, that is...

Last time I tried to run a guest in a 2 core model, it hanged and crashed after a while. Anyway, I will investigate. So I gather critical sections have been dealt with and it's just a matter of ironing bugs right now?

#75 lore raw

Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts

Quoted 11 lines · Antonios Motakis
Quoted 9 lines · Marc Zyngier
Quoted 4 lines · Christoffer Dall

You should simply start booting a UP guest on an SMP host, see where it crashes and start tracking it down.

For the time being, I've yet to see UP guest crashing on SMP host. On the model, that is...

Quoted 4 lines

Last time I tried to run a guest in a 2 core model, it hanged and crashed after a while. Anyway, I will investigate. So I gather critical sections have been dealt with and it's just a matter of ironing bugs right now?

Depends when you tested. V4 was definitely unusable on SMP.

With my patches merged in Christoffer's v5 release, the basics should be covered (correct SMP setup in the boot-wrapper and KVM, MPIDR virtualization).

If you find any problem (and let's face it, I'm sure you will... ;-), I'll be happy to investigate.

Cheers,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#76 lore raw

Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts

Quoted 17 lines · Marc Zyngier
Quoted 11 lines · Antonios Motakis
Quoted 9 lines · Marc Zyngier
Quoted 4 lines · Christoffer Dall

You should simply start booting a UP guest on an SMP host, see where it crashes and start tracking it down.

For the time being, I've yet to see UP guest crashing on SMP host. On the model, that is...

Quoted 4 lines

Last time I tried to run a guest in a 2 core model, it hanged and crashed after a while. Anyway, I will investigate. So I gather critical sections have been dealt with and it's just a matter of ironing bugs right now?

Quoted 9 lines

Depends when you tested. V4 was definitely unusable on SMP.

With my patches merged in Christoffer's v5 release, the basics should be covered (correct SMP setup in the boot-wrapper and KVM, MPIDR virtualization).

If you find any problem (and let's face it, I'm sure you will... ;-), I'll be happy to investigate.

I had the guest boot process crash on a page fault on the v5 series. Consistently. I just didn't have time to investigate yet.

#77 lore raw

Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts

Quoted 21 lines · Christoffer Dall
Quoted 20 lines · Marc Zyngier
Quoted 5 lines · Antonios Motakis
Quoted 4 lines · Marc Zyngier
Quoted 3 lines · Christoffer Dall

You should simply start booting a UP guest on an SMP host, see where it crashes and start tracking it down.

Quoted 8 lines
Quoted 4 lines

For the time being, I've yet to see UP guest crashing on SMP host. On the model, that is...

Last time I tried to run a guest in a 2 core model, it hanged and crashed after a while. Anyway, I will investigate. So I gather critical sections have been dealt with and it's just a matter of ironing bugs right now?

Depends when you tested. V4 was definitely unusable on SMP.

With my patches merged in Christoffer's v5 release, the basics should be covered (correct SMP setup in the boot-wrapper and KVM, MPIDR virtualization).

Quoted 5 lines
Quoted 3 lines

If you find any problem (and let's face it, I'm sure you will... ;-), I'll be happy to investigate.

I had the guest boot process crash on a page fault on the v5 series. Consistently. I just didn't have time to investigate yet.

I was also running v5, however I didn't record the exact crash behavior, since I assumed I was having the same results as everyone. I will look into it now.

#78 lore raw

Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts

Quoted 25 lines · Antonios Motakis
Quoted 24 lines · Christoffer Dall
Quoted 23 lines · Marc Zyngier
Quoted 5 lines · Antonios Motakis
Quoted 4 lines · Marc Zyngier
Quoted 3 lines · Christoffer Dall

You should simply start booting a UP guest on an SMP host, see where it crashes and start tracking it down.

Quoted 8 lines
Quoted 4 lines

For the time being, I've yet to see UP guest crashing on SMP host. On the model, that is...

Last time I tried to run a guest in a 2 core model, it hanged and crashed after a while. Anyway, I will investigate. So I gather critical sections have been dealt with and it's just a matter of ironing bugs right now?

Depends when you tested. V4 was definitely unusable on SMP.

With my patches merged in Christoffer's v5 release, the basics should be covered (correct SMP setup in the boot-wrapper and KVM, MPIDR virtualization).

If you find any problem (and let's face it, I'm sure you will... ;-), I'll be happy to investigate.

Quoted 6 lines
Quoted 2 lines

I had the guest boot process crash on a page fault on the v5 series. Consistently. I just didn't have time to investigate yet.

I was also running v5, however I didn't record the exact crash behavior, since I assumed I was having the same results as everyone. I will look into it now.

If you manage to find a way to reliably reproduce it, I really want help having it fixed ASAP. Kernel config and co much appreciated.

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#80 lore raw

Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts

In reply to a message not in the archive

2011/12/19 Christoffer Dall <[email protected]>:

Quoted 10 lines

ok, just reproduced.

Using the AEM v7 model, 2 cores, attached guest and host config.

Host running on the v5 of the KVM/ARM branch, found here:
https://github.com/virtualopensystems/linux-kvm-arm

Guest kernel revision: f6b252b6b92671d2633008408c06d35c26e55ecf

Guest file system is a Linaro min-debug cramfs.

You should probably also say which revision of qemu you were running...

-- PMM

#81 lore raw

Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts

Quoted 8 lines · Peter Maydell

2011/12/19 Christoffer Dall <[email protected]>:

Quoted 7 lines

ok, just reproduced.

Using the AEM v7 model, 2 cores, attached guest and host config.

Host running on the v5 of the KVM/ARM branch, found here:
https://github.com/virtualopensystems/linux-kvm-arm

Quoted 7 lines
Quoted 3 lines

Guest kernel revision: f6b252b6b92671d2633008408c06d35c26e55ecf

Guest file system is a Linaro min-debug cramfs.

You should probably also say which revision of qemu you were running...

I don't think it would make a difference, but it's the upstream linaro branch that you maintain.

#82 lore raw

Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts

Quoted 12 lines · Christoffer Dall
Quoted 10 lines · Peter Maydell

2011/12/19 Christoffer Dall <[email protected]>:

Quoted 9 lines

ok, just reproduced.

Using the AEM v7 model, 2 cores, attached guest and host config.

Host running on the v5 of the KVM/ARM branch, found here:
https://github.com/virtualopensystems/linux-kvm-arm

Guest kernel revision: f6b252b6b92671d2633008408c06d35c26e55ecf

Quoted 7 lines
Quoted 5 lines
Quoted 1 line

Guest file system is a Linaro min-debug cramfs.

You should probably also say which revision of qemu you were running...

I don't think it would make a difference, but it's the upstream linaro branch that you maintain.

Well, in particular, anything predating qemu-linaro commit bd40be95d1 won't do the right thing for interrupt delivery to SMP guests.

-- PMM

#83 lore raw

Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts

the problem so far is SMP hosts, but I used this revision:
c3ea1e4ac8b2ff0f13d86289562a477f0ae3fd6b

Quoted 26 lines · Peter Maydell
Quoted 12 lines · Christoffer Dall
Quoted 10 lines · Peter Maydell

2011/12/19 Christoffer Dall <[email protected]>:

Quoted 9 lines

ok, just reproduced.

Using the AEM v7 model, 2 cores, attached guest and host config.

Host running on the v5 of the KVM/ARM branch, found here:
https://github.com/virtualopensystems/linux-kvm-arm

Guest kernel revision: f6b252b6b92671d2633008408c06d35c26e55ecf

Quoted 7 lines
Quoted 5 lines
Quoted 1 line

Guest file system is a Linaro min-debug cramfs.

You should probably also say which revision of qemu you were running...

I don't think it would make a difference, but it's the upstream linaro branch that you maintain.

Well, in particular, anything predating qemu-linaro commit bd40be95d1 won't do the right thing for interrupt delivery to SMP guests.

-- PMM

#27 lore raw

Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

In reply to Avi Kivity
Quoted 15 lines · Avi Kivity
Quoted 14 lines · Peter Maydell
Quoted 8 lines · Jan Kiszka

Enabling in-kernel irqchips usually means "switching worlds". So the semantics of these particular IRQ inject interface details may change without breaking anything.

However, things might look different if there will be a need to inject also the CPU IRQs directly, not only the irqchip inputs. In that case, it may make some sense to reserve more space for interrupt types than just one bit and use a common encoding scheme.

I think with an in-kernel GIC model you'd only need to be able to set one of the (256 including internal-to-the-CPU inputs) GIC input lines; the GIC itself then connects directly to the vcpu IRQ and FIQ.

Quoted 7 lines
Quoted 2 lines

So we could just have different semantics for the ioctl in the 'kernel GIC model enabled' config, as you suggest.

btw, since we use the KVM_IRQ_LINE ioctl, it may make sense to require KVM_CREATE_IRQCHIP. To create a kernel GIC model, just call KVM_CREATE_IRQCHIP with a different parameter. This removes an "except for ARM" from the documentation.

I added this, but it feels a bit contrived. Please take a look when I post the next patch series if this is what you have in mind.

Thanks.

#95 lore raw
In reply to Christoffer Dall
Quoted 11 lines · Christoffer Dall
Quoted 10 lines · Peter Maydell
Quoted 7 lines · Christoffer Dall

Still on the to-do list:
 - Reuse VMIDs
 - Fix SMP host support
 - Fix SMP guest support
 - Support guest Thumb mode for MMIO emulation
 - Further testing
 - Performance improvements

Quoted 6 lines
Quoted 3 lines

Other items for this list:
 - Support Neon/VFP in guests (the fpu regs struct is empty ATM)
 - Support guest debugging

ok, thanks, will add these to the list. I have a feeling it will keep growing for a while :)

Do you have a kernel-side TODO list somewhere public (wiki page?)

(It would be quite useful to be able to boot a reasonably modern [read, ARMv7, Thumb2, VFPv3] guest userspace; does anybody plan to work on this part soon?)

thanks
-- PMM

#96 lore raw
Quoted 13 lines · Peter Maydell
Quoted 11 lines · Christoffer Dall
Quoted 10 lines · Peter Maydell
Quoted 7 lines · Christoffer Dall

Still on the to-do list:
- Reuse VMIDs
- Fix SMP host support
- Fix SMP guest support
- Support guest Thumb mode for MMIO emulation
- Further testing
- Performance improvements

Quoted 9 lines
Quoted 6 lines
Quoted 3 lines

Other items for this list:
- Support Neon/VFP in guests (the fpu regs struct is empty ATM)
- Support guest debugging

ok, thanks, will add these to the list. I have a feeling it will keep growing for a while :)

Do you have a kernel-side TODO list somewhere public (wiki page?)

I wanted to create this as issues on the github repos...

Quoted 3 lines

(It would be quite useful to be able to boot a reasonably modern [read, ARMv7, Thumb2, VFPv3] guest userspace; does anybody plan to work on this part soon?)

We have booted the linaro init environment and recent Angstrom distributions. Android is being actively tested. What specifically did you have in mind?

-Christoffer

#97 lore raw
Quoted 8 lines · Christoffer Dall
Quoted 3 lines · Peter Maydell

(It would be quite useful to be able to boot a reasonably modern [read, ARMv7, Thumb2, VFPv3] guest userspace; does anybody plan to work on this part soon?)

We have booted the linaro init environment and recent Angstrom distributions. Android is being actively tested. What specifically did you have in mind?

I meant fixes for these todo list items:

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

- Support guest Thumb mode for MMIO emulation
- Support Neon/VFP in guests (the fpu regs struct is empty ATM)

Have I missed patches which added these? Last time I tried booting a stock linaro userspace it died very early because of the missing Thumb2 guest support.

-- PMM

#98 lore raw
Quoted 11 lines · Peter Maydell
Quoted 8 lines · Christoffer Dall
Quoted 3 lines · Peter Maydell

(It would be quite useful to be able to boot a reasonably modern [read, ARMv7, Thumb2, VFPv3] guest userspace; does anybody plan to work on this part soon?)

We have booted the linaro init environment and recent Angstrom distributions. Android is being actively tested. What specifically did you have in mind?

Quoted 8 lines

I meant fixes for these todo list items:

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

 - Support guest Thumb mode for MMIO emulation
 - Support Neon/VFP in guests (the fpu regs struct is empty ATM)

Have I missed patches which added these? Last time I tried booting a stock linaro userspace it died very early because of the missing Thumb2 guest support.

no, you're not missing anything. I am in fact working on these.

#99 lore raw

There's a new list of issues available at:

https://github.com/virtualopensystems/linux-kvm-arm/issues

-Christoffer

Quoted 22 lines · Christoffer Dall
Quoted 11 lines · Peter Maydell
Quoted 8 lines · Christoffer Dall
Quoted 3 lines · Peter Maydell

(It would be quite useful to be able to boot a reasonably modern [read, ARMv7, Thumb2, VFPv3] guest userspace; does anybody plan to work on this part soon?)

We have booted the linaro init environment and recent Angstrom distributions. Android is being actively tested. What specifically did you have in mind?

Quoted 8 lines

I meant fixes for these todo list items:

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

 - Support guest Thumb mode for MMIO emulation
 - Support Neon/VFP in guests (the fpu regs struct is empty ATM)

Have I missed patches which added these? Last time I tried booting a stock linaro userspace it died very early because of the missing Thumb2 guest support.

no, you're not missing anything. I am in fact working on these.

#100 lore raw
Quoted 3 lines · Christoffer Dall

There's a new list of issues available at:

https://github.com/virtualopensystems/linux-kvm-arm/issues

Thanks for putting this up. Here's a couple more for you :-)

* Support guest kernels configured for LPAE

At the moment (well, if you have Marc's 3.3rc1 tree with the A15 L2 cache control register bodge in it) you can boot an A15 kernel configured without LPAE as a KVM guest, but an LPAE kernel with LPAE enabled will not boot. This probably mostly requires supporting the 64 bit wide cp15 registers that LPAE implies.

* handle QEMU being ^C'd

Currently if you ^C the qemu process then instead of a nice clean exit things go a bit pear shaped, with apparently part of the qemu/kvm combo having quit and the rest not and lots of error messages being emitted. (I admit to not having looked at this one enough to be certain tht it's a kernel side thing rather than a QEMU one; I'm just guessing.)

-- PMM

#101 lore raw
Quoted 16 lines · Peter Maydell
Quoted 3 lines · Christoffer Dall

There's a new list of issues available at:

https://github.com/virtualopensystems/linux-kvm-arm/issues

Thanks for putting this up. Here's a couple more for you :-)

* Support guest kernels configured for LPAE

At the moment (well, if you have Marc's 3.3rc1 tree with the A15 L2 cache control register bodge in it) you can boot an A15 kernel configured without LPAE as a KVM guest, but an LPAE kernel with LPAE enabled will not boot. This probably mostly requires supporting the 64 bit wide cp15 registers that LPAE implies.

Quoted 8 lines

* handle QEMU being ^C'd

Currently if you ^C the qemu process then instead of a nice clean exit things go a bit pear shaped, with apparently part of the qemu/kvm combo having quit and the rest not and lots of error messages being emitted. (I admit to not having looked at this one enough to be certain tht it's a kernel side thing rather than a QEMU one; I'm just guessing.)

That one sounds like missing signal detection in the kvm code. I remember having had that in ppc kvm too during early development.

Alex

#102 lore raw
In reply to Peter Maydell
Quoted 17 lines · Peter Maydell
Quoted 3 lines · Christoffer Dall

There's a new list of issues available at:

https://github.com/virtualopensystems/linux-kvm-arm/issues

Thanks for putting this up. Here's a couple more for you :-)

* Support guest kernels configured for LPAE

At the moment (well, if you have Marc's 3.3rc1 tree with the A15 L2 cache control register bodge in it) you can boot an A15 kernel configured without LPAE as a KVM guest, but an LPAE kernel with LPAE enabled will not boot. This probably mostly requires supporting the 64 bit wide cp15 registers that LPAE implies.

* handle QEMU being ^C'd

Quoted 8 lines

Currently if you ^C the qemu process then instead of a nice clean exit things go a bit pear shaped, with apparently part of the qemu/kvm combo having quit and the rest not and lots of error messages being emitted. (I admit to not having looked at this one enough to be certain tht it's a kernel side thing rather than a QEMU one; I'm just guessing.)

-- PMM

I took the initiative to add them to that list, thanks.

-Antonios

#103 lore raw
In reply to Peter Maydell
Quoted 8 lines · Peter Maydell
Quoted 3 lines · Christoffer Dall

There's a new list of issues available at:

https://github.com/virtualopensystems/linux-kvm-arm/issues

Thanks for putting this up. Here's a couple more for you :-)

Quoted 7 lines

* Support guest kernels configured for LPAE

At the moment (well, if you have Marc's 3.3rc1 tree with the A15 L2 cache control register bodge in it) you can boot an A15 kernel configured without LPAE as a KVM guest, but an LPAE kernel with LPAE enabled will not boot. This probably mostly requires supporting the 64 bit wide cp15 registers that LPAE implies.

So I had a look at that one. LPAE is not the problem (an LPAE kernel runs fine as a guest), but a KVM-enabled kernel dies trying to execute an SMC instruction.

The obvious fix would be to test for the virt extensions in ID_PFR1 before enabling KVM, and mask out the virt extensions from the same register in the guest by trapping CP15-c0. But c0 is used by cache maintenance operations, and trapping would lead to unacceptable performance degradation.

Ideas anyone?

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#104 lore raw
Quoted 5 lines · Marc Zyngier

The obvious fix would be to test for the virt extensions in ID_PFR1 before enabling KVM, and mask out the virt extensions from the same register in the guest by trapping CP15-c0. But c0 is used by cache maintenance operations, and trapping would lead to unacceptable performance degradation.

You can just set HCR.TID3 to get hyp traps on only the feature ID registers, right? (traps access to only ID_PFR0, ID_PFR1, ID_DFR0, ID_AFR0, ID_MMFR0, ID_MMFR1, ID_MMFR2, ID_MMFR3, ID_ISAR0, ID_ISAR1, ID_ISAR2, ID_ISAR3, ID_ISAR4, ID_ISAR5, MVFR0, and MVFR1, none of which should be on performance-critical paths I hope.)

-- PMM

#105 lore raw
Quoted 7 lines · Peter Maydell
Quoted 5 lines · Marc Zyngier

The obvious fix would be to test for the virt extensions in ID_PFR1 before enabling KVM, and mask out the virt extensions from the same register in the guest by trapping CP15-c0. But c0 is used by cache maintenance operations, and trapping would lead to unacceptable performance degradation.

Quoted 5 lines

You can just set HCR.TID3 to get hyp traps on only the feature ID registers, right? (traps access to only ID_PFR0, ID_PFR1, ID_DFR0, ID_AFR0, ID_MMFR0, ID_MMFR1, ID_MMFR2, ID_MMFR3, ID_ISAR0, ID_ISAR1, ID_ISAR2, ID_ISAR3, ID_ISAR4, ID_ISAR5, MVFR0, and MVFR1, none of which should be on performance-critical paths I hope.)

Good catch. It looks much better, except that ID_MMFR3 is used in cpu_v7_set_pte_ext(), which is called each time you map a page. Ouch.

I'm not even sure we can the cache ID_MMFR3 in the kernel (multi-cluster systems may have different features).

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#106 lore raw
Quoted 14 lines · Marc Zyngier
Quoted 7 lines · Peter Maydell
Quoted 5 lines · Marc Zyngier

The obvious fix would be to test for the virt extensions in ID_PFR1 before enabling KVM, and mask out the virt extensions from the same register in the guest by trapping CP15-c0. But c0 is used by cache maintenance operations, and trapping would lead to unacceptable performance degradation.

Quoted 5 lines

You can just set HCR.TID3 to get hyp traps on only the feature ID registers, right? (traps access to only ID_PFR0, ID_PFR1, ID_DFR0, ID_AFR0, ID_MMFR0, ID_MMFR1, ID_MMFR2, ID_MMFR3, ID_ISAR0, ID_ISAR1, ID_ISAR2, ID_ISAR3, ID_ISAR4, ID_ISAR5, MVFR0, and MVFR1, none of which should be on performance-critical paths I hope.)

Quoted 5 lines

Good catch. It looks much better, except that ID_MMFR3 is used in cpu_v7_set_pte_ext(), which is called each time you map a page. Ouch.

I'm not even sure we can the cache ID_MMFR3 in the kernel (multi-cluster systems may have different features).

We only look at the coherent-walk bits there, right? We can just cache a single "does any core require clean-to-PoU after translation table update?" [ie "does any core have 0 in this field?"] flag, I guess. The chances that you actually have a cluster with different cores differing here seem quite low[*], and if we do encounter one then cleaning the dcache line even on the cores that don't need it would be a safe if slightly less than optimal approach...
[*] particularly since every multicore Cortex A-class processor supports coherent walk...

-- PMM

#107 lore raw
In reply to Marc Zyngier

If the final implementation is going to be as per this thread:
http://lists.linaro.org/pipermail/boot-architecture/2011-August/000058.html

then this shouldn't actually be an issue right?

Quoted 24 lines · Marc Zyngier
Quoted 7 lines · Peter Maydell
Quoted 5 lines · Marc Zyngier

The obvious fix would be to test for the virt extensions in ID_PFR1 before enabling KVM, and mask out the virt extensions from the same register in the guest by trapping CP15-c0. But c0 is used by cache maintenance operations, and trapping would lead to unacceptable performance degradation.

Quoted 5 lines

You can just set HCR.TID3 to get hyp traps on only the feature ID registers, right? (traps access to only ID_PFR0, ID_PFR1, ID_DFR0, ID_AFR0, ID_MMFR0, ID_MMFR1, ID_MMFR2, ID_MMFR3, ID_ISAR0, ID_ISAR1, ID_ISAR2, ID_ISAR3, ID_ISAR4, ID_ISAR5, MVFR0, and MVFR1, none of which should be on performance-critical paths I hope.)

Good catch. It looks much better, except that ID_MMFR3 is used in cpu_v7_set_pte_ext(), which is called each time you map a page. Ouch.

I'm not even sure we can the cache ID_MMFR3 in the kernel (multi-cluster systems may have different features).

       M.
--
Jazz is not dead. It just smells funny...

#28 lore raw

Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace

In reply to Avi Kivity
Quoted 5 lines · Avi Kivity
Quoted 4 lines · Peter Maydell

I think with an in-kernel GIC model you'd only need to be able to set one of the (256 including internal-to-the-CPU inputs) GIC input lines; the GIC itself then connects directly to the vcpu IRQ and FIQ.

Quoted 7 lines
Quoted 2 lines

So we could just have different semantics for the ioctl in the 'kernel GIC model enabled' config, as you suggest.

btw, since we use the KVM_IRQ_LINE ioctl, it may make sense to require KVM_CREATE_IRQCHIP.  To create a kernel GIC model, just call KVM_CREATE_IRQCHIP with a different parameter.  This removes an "except for ARM" from the documentation.

Just to yank this thread back from the dead, Christoffer pointed out that at the moment QEMU only calls KVM_CREATE_IRQCHIP if the user asked for one on the command line. This makes sense to me, since KVM_CREATE_IRQCHIP is saying "create me an in-kernel interrupt controller", and so for ARM it ought to mean "create an in-kernel GIC model"... So I think it would be better just to fix the documentation to note that on some architectures it doesn't make sense to call KVM_IRQ_LINE unless you've previously asked for an in kernel irq chip via KVM_CREATE_IRQCHIP.

-- PMM