KVM/ARM Implementation
Subsystems (7)
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
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
@@ -2248,3 +2248,5 @@ source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" + +source "arch/arm/kvm/Kconfig"
arch/arm/Makefile +1 -0
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH v5 2/13 ARM: KVM: Hypervisor identity mapping
In reply to Christoffer DallFrom: 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
@@ -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
@@ -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
PATCH v5 3/13 ARM: KVM: Add hypervisor inititalization
In reply to Christoffer DallSets 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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) {
PATCH v5 4/13 ARM: KVM: Memory virtualization setup
In reply to Christoffer DallThis 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
@@ -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
@@ -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
Re: [PATCH v5 04/13] ARM: KVM: Memory virtualization setup
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 inarch/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 inkvm_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
Re: [Android-virt] [PATCH v5 04/13] ARM: KVM: Memory virtualization setup
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 inarch/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 inkvm_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...
Re: [Android-virt] [PATCH v5 04/13] ARM: KVM: Memory virtualization setup
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 inarch/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 inkvm_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
Re: [Android-virt] [PATCH v5 04/13] ARM: KVM: Memory virtualization setup
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
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
Re: [Android-virt] [PATCH v5 04/13] ARM: KVM: Memory virtualization setup
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.
Re: [Android-virt] [PATCH v5 04/13] ARM: KVM: Memory virtualization setup
In reply to Avi KivityQuoted 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.
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!
PATCH v5 5/13 ARM: KVM: Inject IRQs and FIQs from userspace
In reply to Christoffer DallUserspace 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
Re: [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace
Just found two, maybe three nits while browsing by:
Quoted 49 lines · Christoffer Dall
Userspace can inject IRQs and FIQs through the
KVM_IRQ_LINEVM 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->irqfield. The irq fild value will be:
IRQ:vcpu_index* 2
FIQ: (vcpu_index* 2) + 1This is documented in
Documentation/kvm/api.txt.The effect of the ioctl is simply to simply raise/lower the corresponding
virt_irqfield on the VCPU struct, which will cause the world-switch code to raise/lower virtual interrupts when running the guest on next switch. Thewait_for_interruptflag is also cleared for raised IRQs causing an idle VCPU to become active again.Note: The custom
trace_kvm_irq_lineis used despite a generic definition oftrace_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.Signed-off-by Christoffer Dall <[email protected]>--- 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@@ -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@@ -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@@ -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@@ -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@@ -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@@ -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
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;
+ caseKVM_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
Re: [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace
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;
+ caseKVM_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.
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
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.
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:
Sorry, I should have posted that to the list. I'll do that now.)
-- PMM
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:
Sorry, I should have posted that to the list. I'll do that now.)
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_levelfield 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
inDocumentation/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. Seearch/arm/include/asm/kvm.hfor 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_linefield, 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
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
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
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
Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace
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
Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace
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
Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace
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_LINEioctl, it may make sense to requireKVM_CREATE_IRQCHIP. To create a kernel GIC model, just callKVM_CREATE_IRQCHIPwith 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.
Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace
In reply to Avi KivityQuoted 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_LINEioctl, it may make sense to requireKVM_CREATE_IRQCHIP. To create a kernel GIC model, just callKVM_CREATE_IRQCHIPwith 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
Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace
In reply to Christoffer DallQuoted 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...
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 ;)
Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace
In reply to Peter MaydellQuoted 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
Re: [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace
In reply to Jan KiszkaQuoted 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_LINEVM 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->irqfield. The irq fild value will be:
IRQ:vcpu_index* 2
FIQ: (vcpu_index* 2) + 1This is documented in
Documentation/kvm/api.txt.The effect of the ioctl is simply to simply raise/lower the corresponding
virt_irqfield on the VCPU struct, which will cause the world-switch code to raise/lower virtual interrupts when running the guest on next switch. Thewait_for_interruptflag is also cleared for raised IRQs causing an idle VCPU to become active again.Note: The custom
trace_kvm_irq_lineis used despite a generic definition oftrace_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.Signed-off-by Christoffer Dall <[email protected]>---
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@@ -572,7 +572,7 @@ only go to the IOAPIC. On ia64, a IOSAPIC is created.4.25
KVM_IRQ_LINECapability:
KVM_CAP_IRQCHIPDocumentation/virtual/kvm/api.txt +1
-1-Architectures: x86, ia64 +Architectures: x86, ia64, armType: vm ioctl
Parameters: structkvm_irq_level
Returns: 0 on success, -1 on errorDocumentation/virtual/kvm/api.txt +0
-0@@ -582,6 +582,14 @@ Requires that an interrupt controller model has been previously created withKVM_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 {
__u32irq; /* GSI */arch/arm/include/asm/kvm.h +8
-0@@ -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@@ -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@@ -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@@ -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@@ -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
Re: [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace
In reply to Christoffer DallQuoted 18 lines · Christoffer Dall
Userspace can inject IRQs and FIQs through the
KVM_IRQ_LINEVM 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->irqfield. The irq fild value will be:
IRQ:vcpu_index* 2
FIQ: (vcpu_index* 2) + 1This is documented in
Documentation/kvm/api.txt.The effect of the ioctl is simply to simply raise/lower the corresponding
virt_irqfield on the VCPU struct, which will cause the world-switch code to raise/lower virtual interrupts when running the guest on next switch. Thewait_for_interruptflag is also cleared for raised IRQs causing an idle VCPU to become active again.
Quoted 6 lines
Note: The custom
trace_kvm_irq_lineis used despite a generic definition oftrace_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_IRQCHIPDocumentation/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
Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace
Quoted 26 lines · Avi Kivity
Quoted 18 lines · Christoffer Dall
Userspace can inject IRQs and FIQs through the
KVM_IRQ_LINEVM 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->irqfield. The irq fild value will be:
IRQ:vcpu_index* 2
FIQ: (vcpu_index* 2) + 1This is documented in
Documentation/kvm/api.txt.The effect of the ioctl is simply to simply raise/lower the corresponding
virt_irqfield on the VCPU struct, which will cause the world-switch code to raise/lower virtual interrupts when running the guest on next switch. Thewait_for_interruptflag is also cleared for raised IRQs causing an idle VCPU to become active again.Quoted 6 lines
Note: The custom
trace_kvm_irq_lineis used despite a generic definition oftrace_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_IRQCHIPDocumentation/virtual/kvm/api.txt +1
-1-Architectures: x86, ia64 +Architectures: x86, ia64, armType: vm ioctl
Parameters: structkvm_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 withKVM_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
Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace
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_idon 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
Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace
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_idon ARM.gsi = number of irq line, just a bad name, but you do have it on ARM.
Quoted 9 lines
irq_source_idreally shouldn't have been inkvm_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_LINEso 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.
Re: [Android-virt] [PATCH v5 05/13] ARM: KVM: Inject IRQs and FIQs from userspace
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_LINEso 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
PATCH v5 6/13 ARM: KVM: World-switch implementation
In reply to Christoffer DallProvides 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH v5 7/13 ARM: KVM: Emulation framework and CP15 emulation
In reply to Christoffer DallFrom: 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
@@ -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
@@ -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),
Re: [PATCH v5 07/13] ARM: KVM: Emulation framework and CP15 emulation
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 fromkvm_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
Re: [PATCH v5 07/13] ARM: KVM: Emulation framework and CP15 emulation
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 fromkvm_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 isKVM_EXIT_IRQ_WINDOWS_OPEN). WithKVM_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.
PATCH v5 8/13 ARM: KVM: Handle guest faults in KVM
In reply to Christoffer DallFrom: 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
@@ -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
@@ -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
@@ -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;
Re: [PATCH v5 08/13] ARM: KVM: Handle guest faults in KVM
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_GUESTandpgprot_guestvariables 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
Re: [PATCH v5 08/13] ARM: KVM: Handle guest faults in KVM
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_GUESTandpgprot_guestvariables 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_ASon 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.
Re: [PATCH v5 08/13] ARM: KVM: Handle guest faults in KVM
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
Re: [Android-virt] [PATCH v5 08/13] ARM: KVM: Handle guest faults in KVM
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
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...
Re: [Android-virt] [PATCH v5 08/13] ARM: KVM: Handle guest faults in KVM
In reply to Christoffer DallQuoted 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
Re: [Android-virt] [PATCH v5 08/13] ARM: KVM: Handle guest faults in KVM
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.
Re: [Android-virt] [PATCH v5 08/13] ARM: KVM: Handle guest faults in KVM
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
PATCH v5 9/13 ARM: KVM: Handle I/O aborts
In reply to Christoffer DallFrom: 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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),
Re: [PATCH v5 09/13] ARM: KVM: Handle I/O aborts
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
Re: [Android-virt] [PATCH v5 09/13] ARM: KVM: Handle I/O aborts
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.
PATCH v5 10/13 ARM: KVM: Guest wait-for-interrupts (WFI) support
In reply to Christoffer DallFrom: 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
@@ -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
@@ -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
@@ -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 */
Re: [PATCH v5 10/13] ARM: KVM: Guest wait-for-interrupts (WFI) support
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_interruptsmode and call the main KVM functionkvm_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 tokvm_arch_vcpu_ioctl_run()result in a call tokvm_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
-0return 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
Re: [PATCH v5 10/13] ARM: KVM: Guest wait-for-interrupts (WFI) support
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_interruptsmode and call the main KVM functionkvm_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 tokvm_arch_vcpu_ioctl_run()result in a call tokvm_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= xvcpu->arch.wait_for_interrupts= 0vcpu->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
Re: [PATCH v5 10/13] ARM: KVM: Guest wait-for-interrupts (WFI) support
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
Re: [Android-virt] [PATCH v5 10/13] ARM: KVM: Guest wait-for-interrupts (WFI) support
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: thekvm_runstructure pointer
+ *
+ * Simply sets thewait_for_interruptsflag 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.
+ */
intkvm_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...
Re: [Android-virt] [PATCH v5 10/13] ARM: KVM: Guest wait-for-interrupts (WFI) support
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
PATCH v5 11/13 ARM: KVM: Support SMP hosts
In reply to Christoffer DallIn 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
@@ -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
@@ -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
@@ -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
@@ -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; }
Re: [PATCH v5 11/13] ARM: KVM: Support SMP hosts
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_interruptflags 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 +*/ + asmvolatile ( +"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
Re: [PATCH v5 11/13] ARM: KVM: Support SMP hosts
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_interruptflags 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_tirq_lock;
+ u32virt_irq; /* HCR exception mask */ u32wait_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 threadKVM_IRQ_LINEdoes aset_bit(, virt_irq)for the appropriate irq type, then IPI/wakeups the vcpu to make it examine bothwait_for_interruptsandvirt_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_ptrandpgd_ptrto "registerasm("r0")" and "registerasm("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()andkvm_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)?
Re: [PATCH v5 11/13] ARM: KVM: Support SMP hosts
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_interruptsis managed solely by the vcpu threadKVM_IRQ_LINEdoes aset_bit(, virt_irq)for the appropriate irq type,
then IPI/wakeups the vcpu to make it examine bothwait_for_interruptsandvirt_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_interruptsflag 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()andkvm_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_modefor 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_lockhere)?
Let kvm_init() do the driving and relax.
Signature · 1 line
error compiling committee.c: too many arguments to function
Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts
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 threadKVM_IRQ_LINEdoes aset_bit(, virt_irq)for the appropriate irq type, then IPI/wakeups the vcpu to make it examine bothwait_for_interruptsandvirt_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(). Seekvm_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_interruptsflag 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()andkvm_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_modefor 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 followkvm_init()and fill in the arch callbacks. You do have a call tokvm_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_lockhere)?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).
A message that is not in the archive (sent off-list or not yet received): CAEDV+gJ=zeDpfp0kS2uBvmgRMyCpsV1LitjKR66R4W9Y3VGgWw@mail.gmail.com
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts
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(). Seekvm_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_upfunction 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!
Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts
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
Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts
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.txtandDocumentation/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!
Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts
In reply to Christoffer DallQuoted 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...
Re: [PATCH v5 11/13] ARM: KVM: Support SMP hosts
In reply to Christoffer DallQuoted 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
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.
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...
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?
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...
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.
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.
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...
A message that is not in the archive (sent off-list or not yet received): CAEDV+gL929Hpa=PncVWeHRNAa5fBuorNNYFC=iix=PO+5aO2cg@mail.gmail.com
Re: [Android-virt] [PATCH v5 11/13] ARM: KVM: Support SMP hosts
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-armGuest kernel revision:
f6b252b6b92671d2633008408c06d35c26e55ecfGuest file system is a Linaro min-debug cramfs.
You should probably also say which revision of qemu you were running...
-- PMM
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:
f6b252b6b92671d2633008408c06d35c26e55ecfGuest 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.
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-armGuest 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
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-armGuest kernel revision:
f6b252b6b92671d2633008408c06d35c26e55ecfQuoted 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
bd40be95d1won't do the right thing for interrupt delivery to SMP guests.-- PMM
PATCH v5 12/13 ARM: KVM: Fix guest view of MPIDR
In reply to Christoffer DallFrom: 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
@@ -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
@@ -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
@@ -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
@@ -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
Re: [PATCH v5 12/13] ARM: KVM: Fix guest view of MPIDR
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.Signed-off-by Marc Zyngier <[email protected]>
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
Christoffer Dall
AppliedRe: [PATCH v5 12/13] ARM: KVM: Fix guest view of MPIDR
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.Signed-off-by Marc Zyngier <[email protected]>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?
Re: [PATCH v5 12/13] ARM: KVM: Fix guest view of MPIDR
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.Signed-off-by Marc Zyngier <[email protected]>
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...
Re: [PATCH v5 12/13] ARM: KVM: Fix guest view of MPIDR
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.Signed-off-by Marc Zyngier <[email protected]>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.
Re: [PATCH v5 12/13] ARM: KVM: Fix guest view of MPIDR
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
Re: [PATCH v5 12/13] ARM: KVM: Fix guest view of MPIDR
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.
PATCH v5 13/13 ARM: KVM: Support SMP guests
In reply to Christoffer DallThis 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
@@ -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
@@ -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
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
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
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_stateandwrite_cp15_state).otherwise, help me out on the acronym...
Yes, those are the ones (TLS == thread local storage). Thanks for the pointer.
-- PMM
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 debuggingok, 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
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 debuggingok, 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
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
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.
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.
Quoted 3 lines · Christoffer Dall
There's a new list of issues available at:
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
Quoted 16 lines · Peter Maydell
Quoted 3 lines · Christoffer Dall
There's a new list of issues available at:
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
Quoted 17 lines · Peter Maydell
Quoted 3 lines · Christoffer Dall
There's a new list of issues available at:
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
Quoted 8 lines · Peter Maydell
Quoted 3 lines · Christoffer Dall
There's a new list of issues available at:
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...
Quoted 5 lines · Marc Zyngier
The obvious fix would be to test for the virt extensions in
ID_PFR1before 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
Quoted 7 lines · Peter Maydell
Quoted 5 lines · Marc Zyngier
The obvious fix would be to test for the virt extensions in
ID_PFR1before 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...
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_PFR1before 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_MMFR3is used incpu_v7_set_pte_ext(), which is called each time you map a page. Ouch.I'm not even sure we can the cache
ID_MMFR3in 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
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_PFR1before 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_MMFR3is used incpu_v7_set_pte_ext(), which is called each time you map a page. Ouch.I'm not even sure we can the cache
ID_MMFR3in the kernel (multi-cluster systems may have different features).M.
--
Jazz is not dead. It just smells funny...