KVM/ARM Implementation
Subsystems (8)
v6 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 24c9a7d43e695f0183ba99638edfcd265bc7a0ca on Catalin Marinas' linux-arm-arch tree.
The patch series further depends on these two patches:
https://lists.cs.columbia.edu/pipermail/android-virt/2012-February/000603.html
https://lists.cs.columbia.edu/pipermail/android-virt/2012-February/000590.html
This is Version 6 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-v6
The implementation is broken up into a logical set of patches, the first one a preparatory patch and the second 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. Preparatory patch introducing KVM 2. Skeleton 3. Identity Mapping for Hyp mode 4. Hypervisor initialization 5. Memory virtualization setup (hyp mode mappings and 2nd stage) 6. Inject IRQs and FIQs from userspace 7. World-switch implementation and Hyp exception vectors 8. Emulation framework and CP15 emulation 9. Handle guest user memory aborts
10. Handle guest MMIO aborts
11. Support guest wait-for-interrupt instructions.
12. Handle CP15 CR9 emulation /* hack alert! */
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/KVM/HowTo/ModelSetup
There is an issue list available using the issue tracker on:
https://github.com/virtualopensystems/linux-kvm-arm
Changes since v5:
- General bugfixes and nit fixes from reviews
- Implemented re-use of VMIDs
- Cleaned up the Hyp-mapping code to be readable by non-mm hackers (including myself)
- Integrated preliminary SMP support in base patches
- Lock-less interrupt injection and WFI support
- Fixed signal-handling in while in guest (increases overall stability)
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 (11):
KVM: Introduce __KVM_HAVE_IRQ_LINE
ARM: KVM: Initial skeleton to compile KVM support
ARM: KVM: Hypervisor identity mapping
ARM: KVM: 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
Marc Zyngier (1):
ARM: KVM: Handle CP15 CR9 accesses for L2CTLR emulation
Documentation/virtual/kvm/api.txt | 12 arch/arm/Kconfig | 2 arch/arm/Makefile | 1 arch/arm/include/asm/kvm.h | 81 +++ arch/arm/include/asm/kvm_arm.h | 130 +++++ arch/arm/include/asm/kvm_asm.h | 51 ++ arch/arm/include/asm/kvm_emulate.h | 101 ++++ arch/arm/include/asm/kvm_host.h | 118 ++++ 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 | 10 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 | 45 ++ arch/arm/kvm/Makefile | 17 + arch/arm/kvm/arm.c | 777 +++++++++++++++++++++++++++ arch/arm/kvm/emulate.c | 640 ++++++++++++++++++++++ arch/arm/kvm/exports.c | 32 + arch/arm/kvm/guest.c | 147 +++++ arch/arm/kvm/init.S | 115 ++++ arch/arm/kvm/interrupts.S | 546 +++++++++++++++++++ arch/arm/kvm/mmu.c | 545 +++++++++++++++++++ arch/arm/kvm/trace.h | 117 ++++ arch/arm/mm/Kconfig | 8 arch/arm/mm/idmap.c | 47 +- arch/arm/mm/mmu.c | 3 arch/ia64/include/asm/kvm.h | 1 arch/x86/include/asm/kvm.h | 1 include/linux/kvm.h | 1 include/trace/events/kvm.h | 4 mm/memory.c | 2 35 files changed, 3667 insertions(+), 9 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/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 v6 1/12 KVM: Introduce __KVM_HAVE_IRQ_LINE
From: Christoffer Dall <[email protected]>
This is a prepatory patch for the KVM/ARM implementation. KVM/ARM will use the KVM_IRQ_LINE ioctl, which is currently conditional on __KVM_HAVE_IOAPIC, but ARM obviously doesn't have any IOAPIC support and we need a separate define.
--- arch/ia64/include/asm/kvm.h | 1 + arch/x86/include/asm/kvm.h | 1 + include/trace/events/kvm.h | 4 +++- 3 files changed, 5 insertions(+), 1 deletions(-)
arch/ia64/include/asm/kvm.h +1 -0
@@ -26,6 +26,7 @@/* Select x86 specific features in <linux/kvm.h> */ #define __KVM_HAVE_IOAPIC +#define __KVM_HAVE_IRQ_LINE#define __KVM_HAVE_DEVICE_ASSIGNMENT/* Architectural interrupt line count. */
arch/x86/include/asm/kvm.h +1 -0
@@ -12,6 +12,7 @@/* Select x86 specific features in <linux/kvm.h> */ #define __KVM_HAVE_PIT#define __KVM_HAVE_IOAPIC +#define __KVM_HAVE_IRQ_LINE#define __KVM_HAVE_DEVICE_ASSIGNMENT#define __KVM_HAVE_MSI#define __KVM_HAVE_USER_NMI
include/trace/events/kvm.h +3 -1
@@ -36,7 +36,7 @@ TRACE_EVENT(kvm_userspace_exit, __entry->errno < 0 ? -__entry->errno : __entry->reason) ); -#if defined(__KVM_HAVE_IOAPIC) +#if defined(__KVM_HAVE_IRQ_LINE) TRACE_EVENT(kvm_set_irq, TP_PROTO(unsigned int gsi, int level, int irq_source_id), TP_ARGS(gsi, level, irq_source_id),
@@ -56,7 +56,9 @@ TRACE_EVENT(kvm_set_irq,TP_printk ("gsi %u level %d source %d" , __entry->gsi, __entry->level, __entry->irq_source_id) ); +#endif +#if defined(__KVM_HAVE_IOAPIC)#define kvm_deliver_mode \ {0x0, "Fixed"}, \ {0x1, "LowPrio"}, \
PATCH v6 2/12 ARM: KVM: Initial skeleton to compile KVM support
In reply to Christoffer DallFrom: Christoffer Dall <[email protected]>
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.
“Nothing to see here. Move along, move along..."
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 | 72 ++++++++++ arch/arm/include/asm/kvm_asm.h | 28 ++++ arch/arm/include/asm/kvm_emulate.h | 92 +++++++++++++ arch/arm/include/asm/kvm_host.h | 116 ++++++++++++++++ arch/arm/include/asm/kvm_para.h | 9 + arch/arm/include/asm/unified.h | 12 ++ arch/arm/kvm/Kconfig | 45 ++++++ arch/arm/kvm/Makefile | 17 ++ arch/arm/kvm/arm.c | 256 ++++++++++++++++++++++++++++++++++++ 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/mm/Kconfig | 8 + 19 files changed, 1044 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/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
@@ -2263,3 +2263,5 @@ source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" + +source "arch/arm/kvm/Kconfig"
arch/arm/Makefile +1 -0
@@ -253,6 +253,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 +72 -0
72 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 +92 -0
92 lines not on this page · raw message
arch/arm/include/asm/kvm_host.h new file +116 -0
116 lines not on this page · raw message
arch/arm/include/asm/kvm_para.h new file +9 -0
@@ -0,0 +1,9 @@ +#ifndef _ASM_ARM_KVM_PARA_H +#define _ASM_ARM_KVM_PARA_H + +static inline unsigned int kvm_arch_para_features (void ) +{ +return 0 ; +} + +#endif /* _ASM_ARM_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 +45 -0
45 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 +256 -0
256 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/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
Re: [PATCH v6 02/12] ARM: KVM: Initial skeleton to compile KVM support
Quoted 97 lines · Christoffer Dall
From: Christoffer Dall <[email protected]>
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.
“Nothing to see here. Move along, move along..."
Most functionality is in
arch/arm/kvm/*orarch/arm/include/asm/kvm_*.h.Signed-off-by Christoffer Dall <[email protected]>--- arch/arm/Kconfig | 2 arch/arm/Makefile | 1 arch/arm/include/asm/kvm.h | 72 ++++++++++ arch/arm/include/asm/kvm_asm.h | 28 ++++ arch/arm/include/asm/kvm_emulate.h | 92 +++++++++++++ arch/arm/include/asm/kvm_host.h | 116 ++++++++++++++++ arch/arm/include/asm/kvm_para.h | 9 + arch/arm/include/asm/unified.h | 12 ++ arch/arm/kvm/Kconfig | 45 ++++++ arch/arm/kvm/Makefile | 17 ++ arch/arm/kvm/arm.c | 256 ++++++++++++++++++++++++++++++++++++ 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/mm/Kconfig | 8 + 19 files changed, 1044 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/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.harch/arm/Kconfig +2
-0@@ -2263,3 +2263,5 @@ source "security/Kconfig" source "crypto/Kconfig" source "lib/Kconfig" + +source "arch/arm/kvm/Kconfig"arch/arm/Makefile +1
-0@@ -253,6 +253,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 +20
-0@@ -0,0 +1,72 @@ +/* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License, version 2, as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#ifndef __ARM_KVM_H__ +#define __ARM_KVM_H__ + +#include <asm/types.h>
arch/arm/include/asm/kvm.h line 30
Quoted 10 lines
arch/arm/include/asm/kvm.h new file +10
-0+ +#define __KVM_HAVE_GUEST_DEBUG + +/* +* Modes used for short-hand mode determinition in the world-switch code and +* in emulation code. +* +* Note: These indices do NOT correspond to the value of the CPSR mode bits! +*/ +enum vcpu_modes {
Nitpick: s/vcpu_modes/vcpu_mode/ ?
...
arch/arm/include/asm/kvm.h line 31
Quoted 1 line
arch/arm/include/asm/kvm.h new file +1
-0+static inline unsigned char vcpu_mode (struct kvm_vcpu *vcpu)
static inline enum vcpu_mode vcpu_mode(struct kvm_vcpu *vcpu)...
Quoted 6 lines
arch/arm/include/asm/kvm.h new file +6
-0+{ +u8 modes_table[16 ] = { +MODE_USR ,/* 0x0 */ +MODE_FIQ ,/* 0x1 */ +MODE_IRQ ,/* 0x2 */ +MODE_SVC ,/* 0x3 */
arch/arm/include/asm/kvm.h line 47
Quoted 10 lines
arch/arm/include/asm/kvm.h new file +10
-0+0xf ,0xf ,0xf , +MODE_ABT ,/* 0x7 */ +0xf ,0xf ,0xf , +MODE_UND ,/* 0xb */ +0xf ,0xf ,0xf , + MODE_SYS}; /* 0xf */ + +BUG_ON (modes_table[vcpu->arch.regs.cpsr &0xf ] ==0xf ); +return modes_table[vcpu->arch.regs.cpsr &0xf ]; +}
Like much of your code, I find this far too readable. How about:
enum vcpu_mode {
MODE_USR,
MODE_FIQ,
MODE_IRQ,
MODE_SVC,
MODE_ABT,
MODE_UND,
MODE_SYS
};
static inline enum vcpu_mode vcpu_mode(const struct kvm_vcpu *vcpu)
{
u8 mode = vcpu->arch.regs.cpsr & 0xf;
return (mode & 3) + (mode >> 2);
}arch/arm/include/asm/kvm.h line 51
Quoted 4 lines
arch/arm/include/asm/kvm.h new file +4
-0+/* +* Return the SPSR for the specified mode of the virtual CPU. +*/ +static inline u32 *kvm_vcpu_spsr (struct kvm_vcpu *vcpu,u32 mode)
s/u32/enum vcpu_mode/
arch/arm/include/asm/kvm.h line 61
Quoted 10 lines
arch/arm/include/asm/kvm.h new file +10
-0+{ +switch (mode) { +case MODE_SVC : +return &vcpu->arch.regs.svc_regs[2 ]; +case MODE_ABT : +return &vcpu->arch.regs.svc_regs[2 ]; +case MODE_UND : +return &vcpu->arch.regs.svc_regs[2 ]; +case MODE_IRQ : +return &vcpu->arch.regs.svc_regs[2 ];
This reminds me: shouldn't these be:
case MODE_ABT: return &vcpu->arch.regs.abt_regs[2]; case MODE_UND: return &vcpu->arch.regs.und_regs[2]; case MODE_IRQ: return &vcpu->arch.regs.irq_regs[2];
?
arch/arm/include/asm/kvm.h line 65
Quoted 4 lines
arch/arm/include/asm/kvm.h new file +4
-0+static inline u32 *vcpu_cpsr (struct kvm_vcpu *vcpu) +{ +return &vcpu->arch.regs.cpsr; +}
In general, do you want accessors like this to all regs? I'd like to know, because injecting an undefined insn trap in the guest needs to access the pc...
arch/arm/include/asm/kvm.h line 67
Quoted 2 lines
arch/arm/include/asm/kvm.h new file +2
-0+struct kvm_vcpu ; +u32 *kvm_vcpu_reg (struct kvm_vcpu *vcpu,u8 reg_num,u32 mode);
s/u32/enum vcpu_mode/
Quoted 13 lines
arch/arm/include/asm/kvm.h new file +13
-0+config KVM + tristate"Kernel-based Virtual Machine (KVM) support" + selectPREEMPT_NOTIFIERS + selectANON_INODES + selectKVM_ARM_HOST + selectKVM_MMIO + depends onCPU_V7 &&ARM_VIRT_EXT + ---help--- + Support hosting virtualized guest machines. You will also + need to select one or more of the processor modules below. + + This module provides access to the hardware capabilities through + a character device node named /dev/kvm.
arch/arm/include/asm/kvm.h
Quoted 10 lines
arch/arm/include/asm/kvm.h new file +10
-0+ + If unsure, say N. + +config KVM_ARM_HOST + bool "KVM host support for ARM cpus." + depends onKVM + depends onMMU + depends onCPU_V7 &&ARM_VIRT_EXT + ---help--- + Provides host support for ARM processors.
I don't think KVM should select KVM_ARM_HOST (I assume there'll be a KVM_ARM_GUEST one day). Otherwise remove the prompt after 'bool' in KVM_ARM_HOST.
arch/arm/include/asm/kvm.h
Quoted 11 lines
arch/arm/include/asm/kvm.h new file +11
-0+/* +* Return a pointer to the register number valid in the specified mode of +* the virtual CPU. +*/ +u32 *kvm_vcpu_reg (struct kvm_vcpu *vcpu,u8 reg_num,u32 mode) +{ +BUG_ON (reg_num >15 ); +BUG_ON (mode >MODE_SYS ); + +return (u32 *)((void *)&vcpu->arch + vcpu_reg_offsets[mode][reg_num]); +}
Hmm.... I tried to neaten this (untested). Not sure if it's a win, your call:
commit 7f99177bac6173968925f7329333e5bdf752be67
Author: Rusty Russell <[email protected]> Date: Fri Feb 24 13:37:44 2012 +1030
ARM: KVM: neaten offset calculations.
If we do this the C-correct way, we use fewer casts and it's a bit clearer.
arch/arm/include/asm/kvm_host.h +5 -1
@@ -84,7 +84,11 @@ enum cp15_regs { };struct kvm_vcpu_arch { -struct kvm_vcpu_regs regs; +/* We sometimes access these as an array for simplicity. */ +union { +struct kvm_vcpu_regs regs; +u32 reg_array[sizeof (struct kvm_vcpu_regs ) /sizeof (u32)]; + };/* System control coprocessor (cp15) */ u32 cp15[nr_cp15_regs];
arch/arm/kvm/emulate.c +31 -29
114 lines not on this page · raw message
arch/arm/include/asm/kvm.h
Quoted 10 lines
arch/arm/include/asm/kvm.h new file +8
-0+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_64BITdef_bool ARM_LPAE
If you say Y here, you won't boot on a machine which hasn't got VIRT, right? That's changing, of course, with Dave's boot changes, but worth mentioning either way I think.
Thanks,
Rusty.
Re: [PATCH v6 02/12] ARM: KVM: Initial skeleton to compile KVM support
Quoted 126 lines · Rusty Russell
Quoted 97 lines · Christoffer Dall
From: Christoffer Dall <[email protected]>
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.
“Nothing to see here. Move along, move along..."
Most functionality is in
arch/arm/kvm/*orarch/arm/include/asm/kvm_*.h.Signed-off-by Christoffer Dall <[email protected]>---
arch/arm/Kconfig | 2arch/arm/Makefile| 1arch/arm/include/asm/kvm.h| 72 ++++++++++arch/arm/include/asm/kvm_asm.h| 28 ++++arch/arm/include/asm/kvm_emulate.h| 92 +++++++++++++arch/arm/include/asm/kvm_host.h | 116 ++++++++++++++++ arch/arm/include/asm/kvm_para.h | 9 + arch/arm/include/asm/unified.h | 12 ++arch/arm/kvm/Kconfig | 45 ++++++
arch/arm/kvm/Makefile| 17 ++
arch/arm/kvm/arm.c | 256 ++++++++++++++++++++++++++++++++++++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/mm/Kconfig| 8 +19 files changed, 1044 insertions(+), 0 deletions(-)create mode 100644
arch/arm/include/asm/kvm.hcreate mode 100644arch/arm/include/asm/kvm_asm.hcreate mode 100644arch/arm/include/asm/kvm_emulate.hcreate mode 100644arch/arm/include/asm/kvm_host.hcreate mode 100644arch/arm/include/asm/kvm_para.hcreate mode 100644arch/arm/kvm/Kconfigcreate mode 100644arch/arm/kvm/Makefilecreate mode 100644arch/arm/kvm/arm.c
create mode 100644arch/arm/kvm/emulate.ccreate mode 100644arch/arm/kvm/exports.ccreate mode 100644arch/arm/kvm/guest.ccreate mode 100644arch/arm/kvm/init.Screate mode 100644arch/arm/kvm/interrupts.Screate mode 100644arch/arm/kvm/mmu.c
create mode 100644arch/arm/kvm/trace.harch/arm/Kconfig +0
-0@@ -2263,3 +2263,5 @@ source "security/Kconfig"source "
crypto/Kconfig"source "lib/Kconfig"
arch/arm/Kconfig +2
-0+ +source "arch/arm/kvm/Kconfig"arch/arm/Makefile +0
-0@@ -253,6 +253,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 +20
-0@@ -0,0 +1,72 @@ +/* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License, version 2, as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#ifndef __ARM_KVM_H__ +#define __ARM_KVM_H__ + +#include <asm/types.h> arch/arm/include/asm/kvm.h line 30
Quoted 10 lines
arch/arm/include/asm/kvm.h new file +10
-0+ +#define __KVM_HAVE_GUEST_DEBUG + +/* +* Modes used for short-hand mode determinition in the world-switch code and +* in emulation code. +* +* Note: These indices do NOT correspond to the value of the CPSR mode bits! +*/ +enum vcpu_modes {Nitpick: s/vcpu_modes/vcpu_mode/ ?
...
arch/arm/include/asm/kvm.h line 31
Quoted 1 line
arch/arm/include/asm/kvm.h new file +1
-0+static inline unsigned char vcpu_mode (struct kvm_vcpu *vcpu)static inline enum
vcpu_modevcpu_mode(struct kvm_vcpu *vcpu)...Quoted 10 lines
arch/arm/include/asm/kvm.h new file +10
-0+{ + u8 modes_table[16] = { + MODE_USR, /* 0x0 */ + MODE_FIQ, /* 0x1 */ + MODE_IRQ, /* 0x2 */ + MODE_SVC, /* 0x3 */ + 0xf, 0xf, 0xf, + MODE_ABT, /* 0x7 */ + 0xf, 0xf, 0xf, + MODE_UND, /* 0xb */
Quoted 9 lines
arch/arm/include/asm/kvm.h line 47
Quoted 6 lines
arch/arm/include/asm/kvm.h new file +6
-0+ 0xf, 0xf, 0xf, + MODE_SYS}; /* 0xf */ + + BUG_ON(modes_table[vcpu->arch.regs.cpsr & 0xf] == 0xf); + return modes_table[vcpu->arch.regs.cpsr & 0xf]; +}Like much of your code, I find this far too readable. How about:
"far too readable" - what does this mean?
Quoted 275 lines
enum
vcpu_mode{
MODE_USR,
MODE_FIQ,
MODE_IRQ,
MODE_SVC,
MODE_ABT,
MODE_UND,
MODE_SYS
};static inline enum
vcpu_modevcpu_mode(const struct kvm_vcpu *vcpu){
u8 mode =vcpu->arch.regs.cpsr&0xf;
return (mode & 3) + (mode >> 2);
}arch/arm/include/asm/kvm.h line 51
Quoted 4 lines
arch/arm/include/asm/kvm.h new file +4
-0+/* +* Return the SPSR for the specified mode of the virtual CPU. +*/ +static inline u32 *kvm_vcpu_spsr (struct kvm_vcpu *vcpu,u32 mode)s/u32/enum vcpu_mode/
arch/arm/include/asm/kvm.h line 61
Quoted 10 lines
arch/arm/include/asm/kvm.h new file +10
-0+{ + switch (mode) { + case MODE_SVC: + return &vcpu->arch.regs.svc_regs[2]; + case MODE_ABT: + return &vcpu->arch.regs.svc_regs[2]; + case MODE_UND: + return &vcpu->arch.regs.svc_regs[2]; + case MODE_IRQ: + return &vcpu->arch.regs.svc_regs[2];This reminds me: shouldn't these be:
case
MODE_ABT:
return &vcpu->arch.regs.abt_regs[2]; caseMODE_UND:
return &vcpu->arch.regs.und_regs[2]; caseMODE_IRQ:
return &vcpu->arch.regs.irq_regs[2];?
arch/arm/include/asm/kvm.h line 65
Quoted 4 lines
arch/arm/include/asm/kvm.h new file +4
-0+static inline u32 *vcpu_cpsr (struct kvm_vcpu *vcpu) +{ + return &vcpu->arch.regs.cpsr; +}In general, do you want accessors like this to all regs? I'd like to know, because injecting an undefined insn trap in the guest needs to access the pc...
arch/arm/include/asm/kvm.h line 67
Quoted 2 lines
arch/arm/include/asm/kvm.h new file +2
-0+struct kvm_vcpu ; +u32 *kvm_vcpu_reg (struct kvm_vcpu *vcpu,u8 reg_num,u32 mode);s/u32/enum vcpu_mode/
Quoted 13 lines
arch/arm/include/asm/kvm.h new file +13
-0+config KVM + tristate "Kernel-based Virtual Machine (KVM) support" + select PREEMPT_NOTIFIERS + select ANON_INODES + select KVM_ARM_HOST + select KVM_MMIO + depends on CPU_V7 && ARM_VIRT_EXT + ---help--- + Support hosting virtualized guest machines. You will also + need to select one or more of the processor modules below. + + This module provides access to the hardware capabilities through + a character device node named /dev/kvm.arch/arm/include/asm/kvm.h
Quoted 10 lines
arch/arm/include/asm/kvm.h new file +10
-0+ + If unsure, say N. + +config KVM_ARM_HOST + bool "KVM host support for ARM cpus." + depends on KVM + depends on MMU + depends on CPU_V7 && ARM_VIRT_EXT + ---help--- + Provides host support for ARM processors.I don't think KVM should select
KVM_ARM_HOST(I assume there'll be aKVM_ARM_GUESTone day). Otherwise remove the prompt after 'bool' inKVM_ARM_HOST.arch/arm/include/asm/kvm.h
Quoted 11 lines
arch/arm/include/asm/kvm.h new file +11
-0+/* +* Return a pointer to the register number valid in the specified mode of +* the virtual CPU. +*/ +u32 *kvm_vcpu_reg (struct kvm_vcpu *vcpu,u8 reg_num,u32 mode) +{ + BUG_ON(reg_num > 15); + BUG_ON(mode > MODE_SYS); + + return (u32 *)((void *)&vcpu->arch + vcpu_reg_offsets[mode][reg_num]); +}Hmm.... I tried to neaten this (untested). Not sure if it's a win, your call:
commit
7f99177bac6173968925f7329333e5bdf752be67
Author: Rusty Russell <[email protected]>
Date: Fri Feb 24 13:37:44 2012 +1030ARM: KVM: neaten offset calculations.
If we do this the C-correct way, we use fewer casts and it's a bit clearer.
Signed-off-by Rusty Russell <[email protected]>arch/arm/include/asm/kvm_host.h +5
-1@@ -84,7 +84,11 @@ enum cp15_regs { }; struct kvm_vcpu_arch { - struct kvm_vcpu_regs regs; + /* We sometimes access these as an array for simplicity. */ + union { + struct kvm_vcpu_regs regs; + u32 reg_array[sizeof(struct kvm_vcpu_regs) / sizeof(u32)]; + }; /* System control coprocessor (cp15) */ u32 cp15[nr_cp15_regs];arch/arm/kvm/emulate.c +31
-29@@ -22,8 +22,10 @@ #include "trace.h" -#define USR_REG_OFFSET (_reg) \ - offsetof(struct kvm_vcpu_arch, regs.usr_regs[_reg]) +#define REG_OFFSET (_reg) \ + (offsetof(struct kvm_vcpu_regs, _reg) / sizeof(u32)) + +#define USR_REG_OFFSET (_num) REG_OFFSET(usr_regs[_num]) static const unsigned long vcpu_reg_offsets[MODE_SYS + 1][16] = { /* FIQ Registers */@@ -31,14 +33,14 @@ static const unsigned long vcpu_reg_offsets[MODE_SYS + 1][16] = { USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2), USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5), USR_REG_OFFSET(6), USR_REG_OFFSET(7), - offsetof(struct kvm_vcpu_arch, regs.fiq_regs[1]), /* r8 */ - offsetof(struct kvm_vcpu_arch, regs.fiq_regs[1]), /* r9 */ - offsetof(struct kvm_vcpu_arch, regs.fiq_regs[2]), /* r10 */ - offsetof(struct kvm_vcpu_arch, regs.fiq_regs[3]), /* r11 */ - offsetof(struct kvm_vcpu_arch, regs.fiq_regs[4]), /* r12 */ - offsetof(struct kvm_vcpu_arch, regs.fiq_regs[5]), /* r13 */ - offsetof(struct kvm_vcpu_arch, regs.fiq_regs[6]), /* r14 */ - offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */ + REG_OFFSET(fiq_regs[1]), /* r8 */ + REG_OFFSET(fiq_regs[1]), /* r9 */ + REG_OFFSET(fiq_regs[2]), /* r10 */ + REG_OFFSET(fiq_regs[3]), /* r11 */ + REG_OFFSET(fiq_regs[4]), /* r12 */ + REG_OFFSET(fiq_regs[5]), /* r13 */ + REG_OFFSET(fiq_regs[6]), /* r14 */ + REG_OFFSET(pc) /* r15 */ }, /* IRQ Registers */@@ -48,9 +50,9 @@ static const unsigned long vcpu_reg_offsets[MODE_SYS + 1][16] = { USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8), USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11), USR_REG_OFFSET(12), - offsetof(struct kvm_vcpu_arch, regs.irq_regs[0]), /* r13 */ - offsetof(struct kvm_vcpu_arch, regs.irq_regs[1]), /* r14 */ - offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */ + REG_OFFSET(irq_regs[0]), /* r13 */ + REG_OFFSET(irq_regs[1]), /* r14 */ + REG_OFFSET(pc) /* r15 */ }, /* SVC Registers */@@ -60,9 +62,9 @@ static const unsigned long vcpu_reg_offsets[MODE_SYS + 1][16] = { USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8), USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11), USR_REG_OFFSET(12), - offsetof(struct kvm_vcpu_arch, regs.svc_regs[0]), /* r13 */ - offsetof(struct kvm_vcpu_arch, regs.svc_regs[1]), /* r14 */ - offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */ + REG_OFFSET(svc_regs[0]), /* r13 */ + REG_OFFSET(svc_regs[1]), /* r14 */ + REG_OFFSET(pc) /* r15 */ }, /* ABT Registers */@@ -72,9 +74,9 @@ static const unsigned long vcpu_reg_offsets[MODE_SYS + 1][16] = { USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8), USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11), USR_REG_OFFSET(12), - offsetof(struct kvm_vcpu_arch, regs.abt_regs[0]), /* r13 */ - offsetof(struct kvm_vcpu_arch, regs.abt_regs[1]), /* r14 */ - offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */ + REG_OFFSET(abt_regs[0]), /* r13 */ + REG_OFFSET(abt_regs[1]), /* r14 */ + REG_OFFSET(pc) /* r15 */ }, /* UND Registers */@@ -84,9 +86,9 @@ static const unsigned long vcpu_reg_offsets[MODE_SYS + 1][16] = { USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8), USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11), USR_REG_OFFSET(12), - offsetof(struct kvm_vcpu_arch, regs.und_regs[0]), /* r13 */ - offsetof(struct kvm_vcpu_arch, regs.und_regs[1]), /* r14 */ - offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */ + REG_OFFSET(und_regs[0]), /* r13 */ + REG_OFFSET(und_regs[1]), /* r14 */ + REG_OFFSET(pc) /* r15 */ }, /* USR Registers */@@ -96,9 +98,9 @@ static const unsigned long vcpu_reg_offsets[MODE_SYS + 1][16] = { USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8), USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11), USR_REG_OFFSET(12), - offsetof(struct kvm_vcpu_arch, regs.usr_regs[13]), /* r13 */ - offsetof(struct kvm_vcpu_arch, regs.usr_regs[14]), /* r14 */ - offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */ + REG_OFFSET(usr_regs[13]), /* r13 */ + REG_OFFSET(usr_regs[14]), /* r14 */ + REG_OFFSET(pc) /* r15 */ }, /* SYS Registers */@@ -108,9 +110,9 @@ static const unsigned long vcpu_reg_offsets[MODE_SYS + 1][16] = { USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8), USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11), USR_REG_OFFSET(12), - offsetof(struct kvm_vcpu_arch, regs.usr_regs[13]), /* r13 */ - offsetof(struct kvm_vcpu_arch, regs.usr_regs[14]), /* r14 */ - offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */ + REG_OFFSET(usr_regs[13]), /* r13 */ + REG_OFFSET(usr_regs[14]), /* r14 */ + REG_OFFSET(pc) /* r15 */ }, };@@ -123,7 +125,7 @@ u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode) BUG_ON(reg_num > 15); BUG_ON(mode > MODE_SYS); - return (u32 *)((void *)&vcpu->arch + vcpu_reg_offsets[mode][reg_num]); + return &vcpu->arch.reg_array[vcpu_reg_offsets[mode][reg_num]]; } /******************************************************************************Quoted 11 lines
arch/arm/include/asm/kvm.h new file +8
-0+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_boolARM_LPAEIf you say Y here, you won't boot on a machine which hasn't got VIRT, right? That's changing, of course, with Dave's boot changes, but worth mentioning either way I think.
Thanks,
Rusty.
Re: [PATCH v6 02/12] ARM: KVM: Initial skeleton to compile KVM support
Quoted 3 lines · Christoffer Dall
Quoted 1 line
Like much of your code, I find this far too readable. How about:
"far too readable" - what does this mean?
It means I was joking with my suggestion.
I do this so often as I review patches just to keep my mind engaged.
Clearly, my humor failed here.
Rusty.
Re: [PATCH v6 02/12] ARM: KVM: Initial skeleton to compile KVM support
Quoted 10 lines · Rusty Russell
Quoted 3 lines · Christoffer Dall
Quoted 1 line
Like much of your code, I find this far too readable. How about:
"far too readable" - what does this mean?
It means I was joking with my suggestion.
I do this so often as I review patches just to keep my mind engaged.
Clearly, my humor failed here.
lol, wow, I completely missed that. Thanks :)
Consider my senses tuned for next time around...
-Christoffer
Re: [PATCH v6 02/12] ARM: KVM: Initial skeleton to compile KVM support
In reply to Rusty RussellQuoted 172 lines · Rusty Russell
Quoted 97 lines · Christoffer Dall
From: Christoffer Dall <[email protected]>
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.
“Nothing to see here. Move along, move along..."
Most functionality is in
arch/arm/kvm/*orarch/arm/include/asm/kvm_*.h.Signed-off-by Christoffer Dall <[email protected]>---
arch/arm/Kconfig | 2arch/arm/Makefile| 1arch/arm/include/asm/kvm.h| 72 ++++++++++arch/arm/include/asm/kvm_asm.h| 28 ++++arch/arm/include/asm/kvm_emulate.h| 92 +++++++++++++arch/arm/include/asm/kvm_host.h | 116 ++++++++++++++++ arch/arm/include/asm/kvm_para.h | 9 + arch/arm/include/asm/unified.h | 12 ++arch/arm/kvm/Kconfig | 45 ++++++
arch/arm/kvm/Makefile| 17 ++
arch/arm/kvm/arm.c | 256 ++++++++++++++++++++++++++++++++++++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/mm/Kconfig| 8 +19 files changed, 1044 insertions(+), 0 deletions(-)create mode 100644
arch/arm/include/asm/kvm.hcreate mode 100644arch/arm/include/asm/kvm_asm.hcreate mode 100644arch/arm/include/asm/kvm_emulate.hcreate mode 100644arch/arm/include/asm/kvm_host.hcreate mode 100644arch/arm/include/asm/kvm_para.hcreate mode 100644arch/arm/kvm/Kconfigcreate mode 100644arch/arm/kvm/Makefilecreate mode 100644arch/arm/kvm/arm.c
create mode 100644arch/arm/kvm/emulate.ccreate mode 100644arch/arm/kvm/exports.ccreate mode 100644arch/arm/kvm/guest.ccreate mode 100644arch/arm/kvm/init.Screate mode 100644arch/arm/kvm/interrupts.Screate mode 100644arch/arm/kvm/mmu.c
create mode 100644arch/arm/kvm/trace.harch/arm/Kconfig +0
-0@@ -2263,3 +2263,5 @@ source "security/Kconfig"source "
crypto/Kconfig"source "lib/Kconfig"
arch/arm/Kconfig +2
-0+ +source "arch/arm/kvm/Kconfig"arch/arm/Makefile +0
-0@@ -253,6 +253,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 +20
-0@@ -0,0 +1,72 @@ +/* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License, version 2, as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#ifndef __ARM_KVM_H__ +#define __ARM_KVM_H__ + +#include <asm/types.h> arch/arm/include/asm/kvm.h line 30
Quoted 10 lines
arch/arm/include/asm/kvm.h new file +10
-0+ +#define __KVM_HAVE_GUEST_DEBUG + +/* +* Modes used for short-hand mode determinition in the world-switch code and +* in emulation code. +* +* Note: These indices do NOT correspond to the value of the CPSR mode bits! +*/ +enum vcpu_modes {Nitpick: s/vcpu_modes/vcpu_mode/ ?
...
arch/arm/include/asm/kvm.h line 31
Quoted 1 line
arch/arm/include/asm/kvm.h new file +1
-0+static inline unsigned char vcpu_mode (struct kvm_vcpu *vcpu)static inline enum
vcpu_modevcpu_mode(struct kvm_vcpu *vcpu)...Quoted 6 lines
arch/arm/include/asm/kvm.h new file +6
-0+{ + u8 modes_table[16] = { + MODE_USR, /* 0x0 */ + MODE_FIQ, /* 0x1 */ + MODE_IRQ, /* 0x2 */ + MODE_SVC, /* 0x3 */arch/arm/include/asm/kvm.h line 47
Quoted 10 lines
arch/arm/include/asm/kvm.h new file +10
-0+ 0xf, 0xf, 0xf, + MODE_ABT, /* 0x7 */ + 0xf, 0xf, 0xf, + MODE_UND, /* 0xb */ + 0xf, 0xf, 0xf, + MODE_SYS}; /* 0xf */ + + BUG_ON(modes_table[vcpu->arch.regs.cpsr & 0xf] == 0xf); + return modes_table[vcpu->arch.regs.cpsr & 0xf]; +}Like much of your code, I find this far too readable. How about:
enum
vcpu_mode{
MODE_USR,
MODE_FIQ,
MODE_IRQ,
MODE_SVC,
MODE_ABT,
MODE_UND,
MODE_SYS
};static inline enum
vcpu_modevcpu_mode(const struct kvm_vcpu *vcpu){
u8 mode =vcpu->arch.regs.cpsr&0xf;
return (mode & 3) + (mode >> 2);
}arch/arm/include/asm/kvm.h line 51
Quoted 4 lines
arch/arm/include/asm/kvm.h new file +4
-0+/* +* Return the SPSR for the specified mode of the virtual CPU. +*/ +static inline u32 *kvm_vcpu_spsr (struct kvm_vcpu *vcpu,u32 mode)s/u32/enum vcpu_mode/
arch/arm/include/asm/kvm.h line 61
Quoted 10 lines
arch/arm/include/asm/kvm.h new file +10
-0+{ + switch (mode) { + case MODE_SVC: + return &vcpu->arch.regs.svc_regs[2]; + case MODE_ABT: + return &vcpu->arch.regs.svc_regs[2]; + case MODE_UND: + return &vcpu->arch.regs.svc_regs[2]; + case MODE_IRQ: + return &vcpu->arch.regs.svc_regs[2];This reminds me: shouldn't these be:
Quoted 9 lines
case
MODE_ABT:
return &vcpu->arch.regs.abt_regs[2]; caseMODE_UND:
return &vcpu->arch.regs.und_regs[2]; caseMODE_IRQ:
return &vcpu->arch.regs.irq_regs[2];?
yes, definitely should. thanks.
Quoted 9 lines
arch/arm/include/asm/kvm.h line 65
Quoted 4 lines
arch/arm/include/asm/kvm.h new file +4
-0+static inline u32 *vcpu_cpsr (struct kvm_vcpu *vcpu) +{ + return &vcpu->arch.regs.cpsr; +}In general, do you want accessors like this to all regs? I'd like to know, because injecting an undefined insn trap in the guest needs to access the pc...
hmm, not really, but I kind of like it for simplicity and it goes nice with kvm_vcpu_spsr, which should be called vcpu_spsr in the same light of things by the way. I would have no problem having a vcpu_pc() accessor as well, that wraps around vcpu_reg.
Quoted 24 lines
arch/arm/include/asm/kvm.h line 67
Quoted 2 lines
arch/arm/include/asm/kvm.h new file +2
-0+struct kvm_vcpu ; +u32 *kvm_vcpu_reg (struct kvm_vcpu *vcpu,u8 reg_num,u32 mode);s/u32/enum vcpu_mode/
Quoted 19 lines
arch/arm/include/asm/kvm.h new file +19
-0+config KVM + tristate "Kernel-based Virtual Machine (KVM) support" + select PREEMPT_NOTIFIERS + select ANON_INODES + select KVM_ARM_HOST + select KVM_MMIO + depends on CPU_V7 && ARM_VIRT_EXT + ---help--- + Support hosting virtualized guest machines. You will also + need to select one or more of the processor modules below. + + This module provides access to the hardware capabilities through + a character device node named /dev/kvm. + + If unsure, say N. + +config KVM_ARM_HOST + bool "KVM host support for ARM cpus." + depends on KVM
Quoted 9 lines
Quoted 4 lines
+ depends on MMU
+ depends onCPU_V7&&ARM_VIRT_EXT
+ ---help---
+ Provides host support for ARM processors.I don't think KVM should select
KVM_ARM_HOST(I assume there'll be aKVM_ARM_GUESTone day). Otherwise remove the prompt after 'bool' inKVM_ARM_HOST.
I see. I removed the select.
Quoted 6 lines
Quoted 6 lines
arch/arm/include/asm/kvm.h new file +6
-0+/* +* Return a pointer to the register number valid in the specified mode of +* the virtual CPU. +*/ +u32 *kvm_vcpu_reg (struct kvm_vcpu *vcpu,u8 reg_num,u32 mode) +{
Quoted 9 lines
arch/arm/include/asm/kvm.h
Quoted 5 lines
+
BUG_ON(reg_num > 15);
+BUG_ON(mode > MODE_SYS);arch/arm/include/asm/kvm.h new file +3
-0+ + return (u32 *)((void *)&vcpu->arch + vcpu_reg_offsets[mode][reg_num]); +}Hmm.... I tried to neaten this (untested). Not sure if it's a win, your call:
I like the macros and getting rid of the horrible casts. I am not sure about the union in the struct though as people might have to grep for both access names if they wish to see where something is modified and such - and since it serves only that single access point. How about creating that array in kvm_vcpu_reg function instead? I'll take your newer patch and modify it and see where that takes me.
Thanks for reworking this.
Quoted 155 lines
commit
7f99177bac6173968925f7329333e5bdf752be67
Author: Rusty Russell <[email protected]>
Date: Fri Feb 24 13:37:44 2012 +1030ARM: KVM: neaten offset calculations.
If we do this the C-correct way, we use fewer casts and it's a bit clearer.
Signed-off-by Rusty Russell <[email protected]>arch/arm/include/asm/kvm_host.h +5
-1@@ -84,7 +84,11 @@ enum cp15_regs { }; struct kvm_vcpu_arch { - struct kvm_vcpu_regs regs; + /* We sometimes access these as an array for simplicity. */ + union { + struct kvm_vcpu_regs regs; + u32 reg_array[sizeof(struct kvm_vcpu_regs) / sizeof(u32)]; + }; /* System control coprocessor (cp15) */ u32 cp15[nr_cp15_regs];arch/arm/kvm/emulate.c +31
-29@@ -22,8 +22,10 @@ #include "trace.h" -#define USR_REG_OFFSET (_reg) \ - offsetof(struct kvm_vcpu_arch, regs.usr_regs[_reg]) +#define REG_OFFSET (_reg) \ + (offsetof(struct kvm_vcpu_regs, _reg) / sizeof(u32)) + +#define USR_REG_OFFSET (_num) REG_OFFSET(usr_regs[_num]) static const unsigned long vcpu_reg_offsets[MODE_SYS + 1][16] = { /* FIQ Registers */@@ -31,14 +33,14 @@ static const unsigned long vcpu_reg_offsets[MODE_SYS + 1][16] = { USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2), USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5), USR_REG_OFFSET(6), USR_REG_OFFSET(7), - offsetof(struct kvm_vcpu_arch, regs.fiq_regs[1]), /* r8 */ - offsetof(struct kvm_vcpu_arch, regs.fiq_regs[1]), /* r9 */ - offsetof(struct kvm_vcpu_arch, regs.fiq_regs[2]), /* r10 */ - offsetof(struct kvm_vcpu_arch, regs.fiq_regs[3]), /* r11 */ - offsetof(struct kvm_vcpu_arch, regs.fiq_regs[4]), /* r12 */ - offsetof(struct kvm_vcpu_arch, regs.fiq_regs[5]), /* r13 */ - offsetof(struct kvm_vcpu_arch, regs.fiq_regs[6]), /* r14 */ - offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */ + REG_OFFSET(fiq_regs[1]), /* r8 */ + REG_OFFSET(fiq_regs[1]), /* r9 */ + REG_OFFSET(fiq_regs[2]), /* r10 */ + REG_OFFSET(fiq_regs[3]), /* r11 */ + REG_OFFSET(fiq_regs[4]), /* r12 */ + REG_OFFSET(fiq_regs[5]), /* r13 */ + REG_OFFSET(fiq_regs[6]), /* r14 */ + REG_OFFSET(pc) /* r15 */ }, /* IRQ Registers */@@ -48,9 +50,9 @@ static const unsigned long vcpu_reg_offsets[MODE_SYS + 1][16] = { USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8), USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11), USR_REG_OFFSET(12), - offsetof(struct kvm_vcpu_arch, regs.irq_regs[0]), /* r13 */ - offsetof(struct kvm_vcpu_arch, regs.irq_regs[1]), /* r14 */ - offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */ + REG_OFFSET(irq_regs[0]), /* r13 */ + REG_OFFSET(irq_regs[1]), /* r14 */ + REG_OFFSET(pc) /* r15 */ }, /* SVC Registers */@@ -60,9 +62,9 @@ static const unsigned long vcpu_reg_offsets[MODE_SYS + 1][16] = { USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8), USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11), USR_REG_OFFSET(12), - offsetof(struct kvm_vcpu_arch, regs.svc_regs[0]), /* r13 */ - offsetof(struct kvm_vcpu_arch, regs.svc_regs[1]), /* r14 */ - offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */ + REG_OFFSET(svc_regs[0]), /* r13 */ + REG_OFFSET(svc_regs[1]), /* r14 */ + REG_OFFSET(pc) /* r15 */ }, /* ABT Registers */@@ -72,9 +74,9 @@ static const unsigned long vcpu_reg_offsets[MODE_SYS + 1][16] = { USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8), USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11), USR_REG_OFFSET(12), - offsetof(struct kvm_vcpu_arch, regs.abt_regs[0]), /* r13 */ - offsetof(struct kvm_vcpu_arch, regs.abt_regs[1]), /* r14 */ - offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */ + REG_OFFSET(abt_regs[0]), /* r13 */ + REG_OFFSET(abt_regs[1]), /* r14 */ + REG_OFFSET(pc) /* r15 */ }, /* UND Registers */@@ -84,9 +86,9 @@ static const unsigned long vcpu_reg_offsets[MODE_SYS + 1][16] = { USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8), USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11), USR_REG_OFFSET(12), - offsetof(struct kvm_vcpu_arch, regs.und_regs[0]), /* r13 */ - offsetof(struct kvm_vcpu_arch, regs.und_regs[1]), /* r14 */ - offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */ + REG_OFFSET(und_regs[0]), /* r13 */ + REG_OFFSET(und_regs[1]), /* r14 */ + REG_OFFSET(pc) /* r15 */ }, /* USR Registers */@@ -96,9 +98,9 @@ static const unsigned long vcpu_reg_offsets[MODE_SYS + 1][16] = { USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8), USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11), USR_REG_OFFSET(12), - offsetof(struct kvm_vcpu_arch, regs.usr_regs[13]), /* r13 */ - offsetof(struct kvm_vcpu_arch, regs.usr_regs[14]), /* r14 */ - offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */ + REG_OFFSET(usr_regs[13]), /* r13 */ + REG_OFFSET(usr_regs[14]), /* r14 */ + REG_OFFSET(pc) /* r15 */ }, /* SYS Registers */@@ -108,9 +110,9 @@ static const unsigned long vcpu_reg_offsets[MODE_SYS + 1][16] = { USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8), USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11), USR_REG_OFFSET(12), - offsetof(struct kvm_vcpu_arch, regs.usr_regs[13]), /* r13 */ - offsetof(struct kvm_vcpu_arch, regs.usr_regs[14]), /* r14 */ - offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */ + REG_OFFSET(usr_regs[13]), /* r13 */ + REG_OFFSET(usr_regs[14]), /* r14 */ + REG_OFFSET(pc) /* r15 */ }, };@@ -123,7 +125,7 @@ u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode) BUG_ON(reg_num > 15); BUG_ON(mode > MODE_SYS); - return (u32 *)((void *)&vcpu->arch + vcpu_reg_offsets[mode][reg_num]); + return &vcpu->arch.reg_array[vcpu_reg_offsets[mode][reg_num]]; } /******************************************************************************
Quoted 15 lines
Quoted 10 lines
arch/arm/include/asm/kvm.h new file +8
-0+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_boolARM_LPAEIf you say Y here, you won't boot on a machine which hasn't got VIRT, right? That's changing, of course, with Dave's boot changes, but worth mentioning either way I think.
definitely. comment added.
-Christoffer
PATCH v6 3/12 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_idmap_add(pgd, addr, end);
- hyp_idmap_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 | 5 +++ arch/arm/kvm/guest.c | 1 - arch/arm/mm/idmap.c | 47 +++++++++++++++++++++++++-- 4 files changed, 49 insertions(+), 5 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 +5 -0
@@ -310,6 +310,11 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)#define pgtable_cache_init () do { } while (0) +#ifdef CONFIG_KVM_ARM_HOST +void hyp_idmap_add (pgd_t *,unsigned long ,unsigned long ); +void hyp_idmap_del (pgd_t *pgd,unsigned long addr,unsigned long end); +#endif +#endif /* !__ASSEMBLY__ */ #endif /* CONFIG_MMU */
arch/arm/kvm/guest.c +0 -1
@@ -24,7 +24,6 @@#include <asm/kvm_asm.h> #include <asm/kvm_emulate.h> -struct kvm_stats_debugfs_item debugfs_entries[] = { {NULL } };
arch/arm/mm/idmap.c +43 -4
69 lines not on this page · raw message
Re: [PATCH v6 03/12] ARM: KVM: Hypervisor identity mapping
arch/arm/kvm/guest.c line 29
Quoted 12 lines · Christoffer Dall
arch/arm/kvm/guest.c +0
-1@@ -24,7 +24,6 @@#include <asm/kvm_asm.h> #include <asm/kvm_emulate.h> -struct kvm_stats_debugfs_item debugfs_entries[] = { {NULL } };
Cheers,
Rusty.
PATCH v6 4/12 ARM: KVM: Hypervisor inititalization
In reply to Christoffer DallFrom: Christoffer Dall <[email protected]>
Sets up the required registers to run code in HYP-mode from the kernel.
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);
Note: The initialization mechanism currently relies on an SMC #0 call to the secure monitor, which was merely a fast way of getting to the hypervisor. Dave Marting and Rusty Russel have patches out to make the boot-wrapper and the kernel boot in Hyp-mode and setup a generic way for hypervisors to get access to Hyp-mode if the boot-loader allows such access.
--- arch/arm/include/asm/kvm_arm.h | 103 +++++++++++++++ arch/arm/include/asm/kvm_asm.h | 23 +++ arch/arm/include/asm/kvm_mmu.h | 36 +++++ 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 | 182 +++++++++++++++++++++++++++ arch/arm/kvm/exports.c | 16 ++ arch/arm/kvm/init.S | 98 +++++++++++++++ arch/arm/kvm/interrupts.S | 41 ++++++ arch/arm/kvm/mmu.c | 153 +++++++++++++++++++++++ mm/memory.c | 2 12 files changed, 663 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 number +*/ +#define SMCHYP_HVBAR_W 0xfffffff0 + +#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 char __kvm_hyp_code_start[]; +extern char __kvm_hyp_code_end[]; + +extern void __kvm_flush_vm_context (void ); + +extern int __kvm_vcpu_run (struct kvm_vcpu *vcpu); +#endif #endif /* __ARM_KVM_ASM_H__ */
arch/arm/include/asm/kvm_mmu.h new file +36 -0
@@ -0,0 +1,36 @@ +/* +* 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; +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); + +#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
@@ -82,6 +82,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 +182 -0
201 lines not on this page · raw message
arch/arm/kvm/exports.c +16 -0
@@ -14,3 +14,19 @@*/ #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_hyp_code_start); +EXPORT_SYMBOL_GPL (__kvm_hyp_code_end); + +EXPORT_SYMBOL_GPL (__kvm_vcpu_run); + +EXPORT_SYMBOL_GPL (__kvm_flush_vm_context); + +EXPORT_SYMBOL_GPL (smp_send_reschedule);
arch/arm/kvm/init.S +98 -0
103 lines not on this page · raw message
arch/arm/kvm/interrupts.S +41 -0
46 lines not on this page · raw message
arch/arm/kvm/mmu.c +153 -0
156 lines not on this page · raw message
mm/memory.c +2 -0
@@ -402,12 +402,14 @@ 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) {pud_ERROR (*pud);pud_clear (pud); } +EXPORT_SYMBOL_GPL (pud_clear_bad);void pmd_clear_bad (pmd_t *pmd) {
Re: [PATCH v6 04/12] ARM: KVM: Hypervisor inititalization
arch/arm/kvm/arm.c long kvm_arch_vm_ioctl(struct file *filp, · line 305
Quoted 5 lines · Christoffer Dall
arch/arm/kvm/arm.c +5
-0+/* +* Allocate stack pages for Hypervisor-mode +*/ +for_each_possible_cpu (cpu) +per_cpu (kvm_arm_hyp_stack_page, cpu) =NULL ;
This is weird; we can't call this init function multiple times without reloading the module.
arch/arm/kvm/arm.c long kvm_arch_vm_ioctl(struct file *filp, · line 309
Quoted 4 lines
arch/arm/kvm/arm.c +4
-0+for_each_possible_cpu (cpu) { +void *stack_page; + + stack_page = (void *)__get_free_page (GFP_KERNEL );
Actually, if you change kvm_arm_hyp_stack_page to an unsigned long, and your mapping functions to take unsigned long too, you can avoid many casts.
Cheers,
Rusty.
Re: [PATCH v6 04/12] ARM: KVM: Hypervisor inititalization
Quoted 10 lines · Rusty Russell
Quoted 5 lines · Christoffer Dall
+ /*
+ * Allocate stack pages for Hypervisor-mode
+ */
+for_each_possible_cpu(cpu)
+per_cpu(kvm_arm_hyp_stack_page, cpu)= NULL;This is weird; we can't call this init function multiple times without reloading the module.
what you're saying is that static DEFINE_PER_CPU will still be initialized to zero? I don't actually have experience with this, but I assumed that the data..percpu section would not necessarily be zeroed out when loading a module... Now I tried to look, but I couldn't convince myself. Can you enlighten me?
Quoted 9 lines
Quoted 4 lines
+
for_each_possible_cpu(cpu){
+ void*stack_page;
+
+stack_page= (void *)__get_free_page(GFP_KERNEL);Actually, if you change
kvm_arm_hyp_stack_pageto an unsigned long, and your mapping functions to take unsigned long too, you can avoid many casts.
true, thanks.
-Christoffer
Re: [PATCH v6 04/12] ARM: KVM: Hypervisor inititalization
Quoted 12 lines · Christoffer Dall
Quoted 10 lines · Rusty Russell
Quoted 5 lines · Christoffer Dall
+ /*
+ * Allocate stack pages for Hypervisor-mode
+ */
+for_each_possible_cpu(cpu)
+per_cpu(kvm_arm_hyp_stack_page, cpu)= NULL;This is weird; we can't call this init function multiple times without reloading the module.
Quoted 5 lines
what you're saying is that static
DEFINE_PER_CPUwill still be initialized to zero? I don't actually have experience with this, but I assumed that the data..percpu section would not necessarily be zeroed out when loading a module... Now I tried to look, but I couldn't convince myself. Can you enlighten me?
Absolutely and definitely. It's placed in a special section, and from there copied into the per-cpu sections by the module loader but still follows the C semantics of being zero-initialized.
Cheers,
Rusty.
Signature · 1 line
How could I marry someone with more hair than me? http://baldalex.org
Re: [PATCH v6 04/12] ARM: KVM: Hypervisor inititalization
In reply to Christoffer DallQuoted 10 lines · Christoffer Dall
From: Christoffer Dall <[email protected]>
(quoted diff) +8
-0+static void cpu_set_vector(void *vector) +{ + unsigned long vector_ptr; + unsigned long smc_hyp_nr; + + vector_ptr = (unsigned long)vector; + smc_hyp_nr = SMCHYP_HVBAR_W; +
Review
Quoted 10 lines
(quoted diff) +10
-0+ /* + * Set the HVBAR + */ + asm volatile ( + "mov r0, %[vector_ptr]\n\t" + "mov r7, %[smc_hyp_nr]\n\t" + "smc #0\n\t" : : + [vector_ptr] "r" (vector_ptr), + [smc_hyp_nr] "r" (smc_hyp_nr) : + "r0", "r1");
Testing this recently, trying to get a kvm guest to boot. No success yet, but I did get another issue when I compiled the host non-SMP: you need to mark r7 as clobbered here (on SMP we didn't clobber anything important, but on UP it hit init_end_phys_addr and changed it to 0xffffffff and we died horribly in hyp_idmap_del().
Thanks,
Rusty.
arch/arm/kvm/arm.c +1 -1
@@ -585,7 +585,7 @@ static void cpu_set_vector(void *vector) "smc #0\n\t" : : [vector_ptr] "r" (vector_ptr), [smc_hyp_nr] "r" (smc_hyp_nr) : - "r0", "r1"); + "r0", "r1", "r7"); } static void cpu_init_hyp_mode(void *vector)
Cheers,
Rusty.
Re: [PATCH v6 04/12] ARM: KVM: Hypervisor inititalization
Quoted 19 lines · Rusty Russell
Quoted 18 lines · Christoffer Dall
From: Christoffer Dall <[email protected]>
(quoted diff) +16
-0+static void cpu_set_vector(void *vector) +{ + unsigned long vector_ptr; + unsigned long smc_hyp_nr; + + vector_ptr = (unsigned long)vector; + smc_hyp_nr = SMCHYP_HVBAR_W; + + /* + * Set the HVBAR + */ + asm volatile ( + "mov r0, %[vector_ptr]\n\t" + "mov r7, %[smc_hyp_nr]\n\t" + "smc #0\n\t" : : + [vector_ptr] "r" (vector_ptr),
Quoted 9 lines
Quoted 2 lines
+ [
smc_hyp_nr] "r" (smc_hyp_nr) :
+ "r0", "r1");Testing this recently, trying to get a kvm guest to boot. No success yet, but I did get another issue when I compiled the host non-SMP: you need to mark r7 as clobbered here (on SMP we didn't clobber anything important, but on UP it hit
init_end_phys_addrand changed it to0xffffffffand we died horribly inhyp_idmap_del().
you're absolutely right. Nice catch. Thanks.
PATCH v6 5/12 ARM: KVM: Memory virtualization setup
In reply to Christoffer DallFrom: Christoffer Dall <[email protected]>
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 table (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 assigned consecutively to VMs in the order that VMs are executed, and caches and tlbs are invalidated when the VMID space has been used to allow for more than 255 simultaenously running guests.
The 2nd stage pgd is allocated in kvm_arch_init_vm(). The table is freed in kvm_arch_destroy_vm(). Both functions are called from the main KVM code.
--- arch/arm/include/asm/kvm_mmu.h | 5 ++ arch/arm/kvm/arm.c | 51 +++++++++++++++++++- arch/arm/kvm/mmu.c | 103 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 1 deletions(-)
arch/arm/include/asm/kvm_mmu.h +5 -0
@@ -33,4 +33,9 @@ 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); +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 +50 -1
89 lines not on this page · raw message
arch/arm/kvm/mmu.c +103 -0
109 lines not on this page · raw message
PATCH v6 6/12 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 << 1
FIQ: (vcpu_index << 1) | 1
This is documented in Documentation/kvm/api.txt.
The effect of the ioctl is simply to simply raise/lower the corresponding irq_line 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 or FIQs causing an idle VCPU to become active again. CPUs in guest mode are kicked to make sure they refresh their interrupt status.
--- Documentation/virtual/kvm/api.txt | 12 +++++-- arch/arm/include/asm/kvm.h | 9 +++++ arch/arm/include/asm/kvm_arm.h | 1 + arch/arm/kvm/arm.c | 62 ++++++++++++++++++++++++++++++++++++- include/linux/kvm.h | 1 + 5 files changed, 80 insertions(+), 5 deletions(-)
Documentation/virtual/kvm/api.txt +8 -4
@@ -572,15 +572,19 @@ 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 Sets the level of a GSI input to the interrupt controller model in the kernel. -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. +On some architectures it is required 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. + +ARM uses two types of interrupt lines per CPU: IRQ and FIQ. The value of the +irq field should be (vcpu_index << 1) for IRQs and ((vcpu_index << 1) | 1) for +FIQs. Level is used to raise/lower the line. struct kvm_irq_level { union {
arch/arm/include/asm/kvm.h +9 -0
@@ -20,6 +20,15 @@#include <asm/types.h> #define __KVM_HAVE_GUEST_DEBUG +#define __KVM_HAVE_IRQ_LINE + +/* +* 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
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 +61 -1
86 lines not on this page · raw message
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;
PATCH v6 7/12 ARM: KVM: World-switch implementation
In reply to Christoffer DallFrom: Christoffer Dall <[email protected]>
Provides complete world-switch implementation to switch to other guests running in non-secure modes. Includes Hyp exception handlers that capture 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.
SMP support using the VMPIDR calculated on the basis of the host MPIDR and overriding the low bits with KVM vcpu_id contributed by Marc Zyngier.
Reuse of VMIDs has been implemented by Antonios Motakis and adapated from a separate patch into the appropriate patches introducing the functionality. Note that the VMIDs are stored per VM as required by the ARM architecture reference manual.
--- arch/arm/include/asm/kvm_arm.h | 26 ++ arch/arm/include/asm/kvm_host.h | 1 arch/arm/kernel/armksyms.c | 7 + arch/arm/kernel/asm-offsets.c | 34 +++ arch/arm/kernel/entry-armv.S | 1 arch/arm/kvm/arm.c | 136 +++++++++++ arch/arm/kvm/interrupts.S | 492 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 693 insertions(+), 4 deletions(-)
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 +1 -0
@@ -96,6 +96,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 +34 -0
@@ -13,6 +13,7 @@#include <linux/sched.h> #include <linux/mm.h> #include <linux/dma-mapping.h> +#include <linux/kvm_host.h> #include <asm/cacheflush.h> #include <asm/glue-df.h> #include <asm/glue-pf.h>
@@ -144,5 +145,38 @@ 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_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])); + 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_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines)); + 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 +134 -2
158 lines not on this page · raw message
arch/arm/kvm/interrupts.S +490 -2
521 lines not on this page · raw message
PATCH v6 8/12 ARM: KVM: Emulation framework and CP15 emulation
In reply to Christoffer DallAdds 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 commit handles these exits by emulating the intended operation in software and skip the guest instruction.
--- arch/arm/include/asm/kvm_emulate.h | 7 + arch/arm/kvm/arm.c | 79 ++++++++++++++ arch/arm/kvm/emulate.c | 198 ++++++++++++++++++++++++++++++++++++ arch/arm/kvm/trace.h | 28 +++++ 4 files changed, 312 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 +79 -0
97 lines not on this page · raw message
arch/arm/kvm/emulate.c +198 -0
208 lines not on this page · raw message
arch/arm/kvm/trace.h +28 -0
@@ -39,7 +39,35 @@ TRACE_EVENT(kvm_exit,TP_printk ("PC: 0x%08lx" , __entry->vcpu_pc) ); +/* 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), +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) +);#endif /* _TRACE_KVM_H */
PATCH v6 9/12 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 | 127 +++++++++++++++++++++++++++++++++ arch/arm/mm/mmu.c | 3 + 4 files changed, 141 insertions(+), 1 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
@@ -70,6 +70,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))
@@ -83,6 +84,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 +126 -1
145 lines not on this page · raw message
arch/arm/mm/mmu.c +3 -0
@@ -54,9 +54,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 ];
@@ -504,6 +506,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;
PATCH v6 10/12 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 | 6 + arch/arm/kvm/emulate.c | 275 ++++++++++++++++++++++++++++++++++++ arch/arm/kvm/mmu.c | 153 ++++++++++++++++++++ arch/arm/kvm/trace.h | 21 +++ 7 files changed, 456 insertions(+), 3 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
@@ -99,6 +99,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;/* Interrupt related fields */
arch/arm/include/asm/kvm_mmu.h +1 -0
@@ -36,6 +36,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 +6 -0
@@ -425,6 +425,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)int ret =0 ;sigset_t sigsaved; +if (run->exit_reason ==KVM_EXIT_MMIO ) { + ret =kvm_handle_mmio_return (vcpu, vcpu->run); +if (ret) +return ret; + } +if (vcpu->sigset_active)sigprocmask (SIG_SETMASK , &vcpu->sigset, &sigsaved);
arch/arm/kvm/emulate.c +274 -1
285 lines not on this page · raw message
arch/arm/kvm/mmu.c +151 -2
174 lines not on this page · raw message
arch/arm/kvm/trace.h +21 -0
@@ -39,6 +39,27 @@ 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,
PATCH v6 11/12 ARM: KVM: Guest wait-for-interrupts (WFI) support
In reply to Christoffer DallWhen 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 putting 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 | 15 ++++++++++++++- arch/arm/kvm/emulate.c | 12 ++++++++++++ arch/arm/kvm/trace.h | 16 ++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletions(-)
arch/arm/kvm/arm.c +14 -1
@@ -268,9 +268,17 @@ 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 (or waiting and +* an interrupt is pending) then it is by definition runnable. +*/ int kvm_arch_vcpu_runnable (struct kvm_vcpu *v) { -return 0 ; +return !!v->arch.irq_lines || + !v->arch.wait_for_interrupts; }int kvm_arch_vcpu_in_guest_mode (struct kvm_vcpu *v)
@@ -448,6 +456,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)break ; } +if (vcpu->arch.wait_for_interrupts) +kvm_vcpu_block (vcpu); +/* * Enter the guest */
@@ -520,6 +531,8 @@ static int kvm_arch_vm_ioctl_irq_line(struct kvm *kvm,* trigger a world-switch round on the running physical CPU to set the * virtual IRQ/FIQ fields in the HCR appropriately. */ +if (irq_level->level) + vcpu->arch.wait_for_interrupts =0 ;kvm_vcpu_kick (vcpu);return 0 ;
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.irq_lines) + vcpu->arch.wait_for_interrupts =1 ;return 0 ; }
arch/arm/kvm/trace.h +16 -0
@@ -90,6 +90,22 @@ TRACE_EVENT(kvm_emulate_cp15_imp, __entry->CRm, __entry->Op2) ); +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 */ #undef TRACE_INCLUDE_PATH
PATCH v6 12/12 ARM: KVM: Handle CP15 CR9 accesses for L2CTLR emulation
In reply to Christoffer DallFrom: Marc Zyngier <[email protected]>
Note: This is an awful hack and will go away as soon as the emulation and decoding code has been changed to a table-driven approach.
--- arch/arm/kvm/emulate.c | 36 ++++++++++++++++++++++++++++++++++++ 1 files changed, 36 insertions(+), 0 deletions(-)
arch/arm/kvm/emulate.c +36 -0
@@ -206,6 +206,39 @@ int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run) }/** +* emulate_cp15_c9_access -- emulates cp15 accesses for CRn == 9 +* @vcpu: The VCPU pointer +* @p: The coprocessor parameters struct pointer holding trap inst. details +*/ +static int emulate_cp15_c9_access (struct kvm_vcpu *vcpu, +struct coproc_params *p) +{ +BUG_ON (p->CRn !=9 ); +BUG_ON (p->is_64bit); + +if (p->CRm ==0 && p->Op1 ==1 && p->Op2 ==2 ) { +/* Emulate L2CTLR access */ +u32 l2ctlr, ncores; + +if (p->is_write) +return 0 ; + + asmvolatile ("mrc p15, 1, %0, c9, c0, 2\n" :"=r" (l2ctlr)); + l2ctlr &= ~(3 <<24 ); + ncores =atomic_read (&vcpu->kvm->online_vcpus) -1 ; + l2ctlr |= (ncores &3 ) <<24 ; + *vcpu_reg (vcpu, p->Rt1) = l2ctlr; + +return 0 ; + } + +/* hack alert!!! */ +if (!p->is_write) + *vcpu_reg (vcpu, p->Rt1) =0 ; +return 0 ; +} + +/** * emulate_cp15_c10_access -- emulates cp15 accesses for CRn == 10 * @vcpu: The VCPU pointer * @p: The coprocessor parameters struct pointer holding trap inst. details
@@ -310,6 +343,9 @@ int kvm_handle_cp15_access(struct kvm_vcpu *vcpu, struct kvm_run *run) goto unsupp_err_out;switch (params.CRn) { +case 9 : + ret =emulate_cp15_c9_access (vcpu, ¶ms); +break ;case 10 : ret =emulate_cp15_c10_access (vcpu, ¶ms);break ;