KVM/ARM Implementation
Subsystems (8)
v7 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 a mashup of v3.3-rc6, the vexpress support, and kvm-next. I apologize for this mess, but there's really no good way around this, since we need vexpress support and we want to keep up with kvm-next for QEMU support. I strongly recommend cloning the repo below instead of applying the patches to some base.
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 7 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-v7
A non-flattened edition of the patch series can be found at:
git://github.com/virtualopensystems/linux-kvm-arm.git kvm-a15-v7-stage
The implementation is broken up into a logical set of patches, the first two are preparatory patches and the third contains 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_HAVE_IRQ_LINE 2. Preparatory patch guarding mmu_notifier code with CONFIG_MMU_NOTIFIER 3. Skeleton 4. Identity Mapping for Hyp mode 5. Hypervisor initialization 6. Memory virtualization setup (hyp mode mappings and 2nd stage) 7. Inject IRQs and FIQs from userspace 8. World-switch implementation and Hyp exception vectors 9. Emulation framework and CP15 emulation
10. Handle guest user memory aborts
11. Handle guest MMIO aborts
12. Support guest wait-for-interrupt instructions
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 v6:
- Support for MMU notifiers to not pin user pages in memory
- Suport build with log debugging
- Bugfix: v6 clobbered r7 in init code
- Simplify hyp code mapping
- Cleanup of register access code
- Table-based CP15 emulation from Rusty Russell
- Various other bug fixes and cleanups
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):
KVM: Guard mmu_notifier specific code with CONFIG_MMU_NOTIFIER
Documentation/virtual/kvm/api.txt | 12 arch/arm/Kconfig | 2 arch/arm/Makefile | 1 arch/arm/include/asm/kvm.h | 87 +++ arch/arm/include/asm/kvm_arm.h | 130 ++++ arch/arm/include/asm/kvm_asm.h | 53 ++ arch/arm/include/asm/kvm_emulate.h | 107 ++++ arch/arm/include/asm/kvm_host.h | 137 +++++ 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 | 797 +++++++++++++++++++++++++++ arch/arm/kvm/emulate.c | 676 +++++++++++++++++++++++ arch/arm/kvm/exports.c | 31 + arch/arm/kvm/guest.c | 147 +++++ arch/arm/kvm/init.S | 115 ++++ arch/arm/kvm/interrupts.S | 588 ++++++++++++++++++++ arch/arm/kvm/mmu.c | 580 ++++++++++++++++++++ arch/arm/kvm/trace.h | 117 ++++ arch/arm/mm/Kconfig | 10 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/linux/kvm_host.h | 4 include/trace/events/kvm.h | 4 mm/memory.c | 2 36 files changed, 3836 insertions(+), 11 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 v7 1/12 KVM: Introduce __KVM_HAVE_IRQ_LINE
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 1/1 ARM: KVM: Check the cpuid we're being asked to emulate.
As our emulation gets more sophisticated, we need to know what CPU model we're dealing with. Particularly for some of the nastier workarounds.
Let's start with Cortex A-15. We can then test the MIDR elsewhere in the code, knowing that it's one of a finite set of allowed values.
arch/arm/kvm/guest.c +18 -0
@@ -82,6 +82,24 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)int kvm_arch_vcpu_ioctl_set_regs (struct kvm_vcpu *vcpu,struct kvm_regs *regs) {struct kvm_vcpu_regs *vcpu_regs = &vcpu->arch.regs; +u32 impl, var, arch, part; + +/* Check we understand what CPU we're being asked to emulate. */ + impl = (regs->cp15.c0_midr &0xFF000000 ) >>24 ; + var = (regs->cp15.c0_midr &0x00F00000 ) >>20 ; + arch = (regs->cp15.c0_midr &0x000F0000 ) >>16 ; + part = (regs->cp15.c0_midr &0x0000FFF0 ) >>4 ; + +switch (regs->cp15.c0_midr >>24 ) { +case 'A' :/* ARM */ +/* Cortex-A15 */ +if (var ==0x2 && arch ==0xF && part ==0xC0F ) +break ; +else +return -EINVAL ; +default : +return -EINVAL ; + }memcpy (&(vcpu_regs->usr_regs[0 ]), regs->regs0_7,sizeof (u32) *8 );memcpy (&(vcpu_regs->usr_regs[8 ]), regs->usr_regs8_12,sizeof (u32) *5 );
Re: [PATCH] ARM: KVM: Check the cpuid we're being asked to emulate.
Quoted 24 lines · Rusty Russell
As our emulation gets more sophisticated, we need to know what CPU model we're dealing with. Particularly for some of the nastier workarounds.
Let's start with Cortex A-15. We can then test the MIDR elsewhere in the code, knowing that it's one of a finite set of allowed values.
Signed-off-by Rusty Russell <[email protected]>arch/arm/kvm/guest.c +8
-0@@ -82,6 +82,24 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) { struct kvm_vcpu_regs *vcpu_regs = &vcpu->arch.regs; + u32 impl, var, arch, part; + + /* Check we understand what CPU we're being asked to emulate. */ + impl = (regs->cp15.c0_midr & 0xFF000000) >> 24; + var = (regs->cp15.c0_midr & 0x00F00000) >> 20; + arch = (regs->cp15.c0_midr & 0x000F0000) >> 16; + part = (regs->cp15.c0_midr & 0x0000FFF0) >> 4; +
arch/arm/kvm/guest.c int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) · line 102
Quoted 10 lines
arch/arm/kvm/guest.c +10
-0+ switch (regs->cp15.c0_midr >> 24) { + case 'A': /* ARM */ + /* Cortex-A15 */ + if (var == 0x2 && arch == 0xF && part == 0xC0F) + break; + else + return -EINVAL; + default: + return -EINVAL; + }
perhaps factor this out? The switch statement is there because you suspect it might grow I assume...
no need to check the revision field?
arch/arm/kvm/guest.c int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) · line 105
Quoted 3 lines
arch/arm/kvm/guest.c +0
-0memcpy(&(vcpu_regs->usr_regs[0]), regs->regs0_7, sizeof(u32) * 8); memcpy(&(vcpu_regs->usr_regs[8]), regs->usr_regs8_12, sizeof(u32) * 5);
Thanks,
Christoffer
Re: [PATCH] ARM: KVM: Check the cpuid we're being asked to emulate.
Quoted 6 lines · Christoffer Dall
Quoted 5 lines · Rusty Russell
As our emulation gets more sophisticated, we need to know what CPU model we're dealing with. Particularly for some of the nastier workarounds.
Let's start with Cortex A-15. We can then test the MIDR elsewhere in the code, knowing that it's one of a finite set of allowed values.
(Revisiting this now)
The intent is good, this patch is not the right way to do it though. I think want an explicit ioctl to tell the kernel what CPU; since the kernel initialized the regs, it needs to know.
Cheers,
Rusty.
Re: [PATCH] ARM: KVM: Check the cpuid we're being asked to emulate.
Quoted 5 lines · Rusty Russell
Quoted 4 lines · Christoffer Dall
Quoted 3 lines · Rusty Russell
As our emulation gets more sophisticated, we need to know what CPU model we're dealing with. Particularly for some of the nastier workarounds.
Quoted 9 lines
Quoted 2 lines
Quoted 2 lines
Let's start with Cortex A-15. We can then test the MIDR elsewhere in the code, knowing that it's one of a finite set of allowed values.
(Revisiting this now)
The intent is good, this patch is not the right way to do it though. I think want an explicit ioctl to tell the kernel what CPU; since the kernel initialized the regs, it needs to know.
not sure of your point exactly, but if I understand correctly, what you're saying is that since the kernel initializes all the regs (at least it's going to) we want an ioctl to say "this is the cpu for which you will initialize the regs"?
that also makes for a more friendly user space interface than "you need to set this register to this cryptic value to emulate this cpu"...
-Christoffer
Re: [PATCH] ARM: KVM: Check the cpuid we're being asked to emulate.
Quoted 15 lines · Christoffer Dall
Quoted 5 lines · Rusty Russell
Quoted 4 lines · Christoffer Dall
Quoted 3 lines · Rusty Russell
As our emulation gets more sophisticated, we need to know what CPU model we're dealing with. Particularly for some of the nastier workarounds.
Quoted 9 lines
Quoted 2 lines
Quoted 2 lines
Let's start with Cortex A-15. We can then test the MIDR elsewhere in the code, knowing that it's one of a finite set of allowed values.
(Revisiting this now)
The intent is good, this patch is not the right way to do it though. I think want an explicit ioctl to tell the kernel what CPU; since the kernel initialized the regs, it needs to know.
Quoted 8 lines
not sure of your point exactly, but if I understand correctly, what you're saying is that since the kernel initializes all the regs (at least it's going to) we want an ioctl to say "this is the cpu for which you will initialize the regs"?
that also makes for a more friendly user space interface than "you need to set this register to this cryptic value to emulate this cpu"...
Yes, exactly. Esp. since it also effects some of the cp15 emulation hacks.
Cheers,
Rusty.
PATCH v7 2/12 KVM: Guard mmu_notifier specific code with CONFIG_MMU_NOTIFIER
In reply to Christoffer DallFrom: Marc Zyngier <[email protected]>
In order to avoid compilation failure when KVM is not compiled in, guard the mmu_notifier specific sections with both CONFIG_MMU_NOTIFIER and KVM_ARCH_WANT_MMU_NOTIFIER, like it is being done in the rest of the KVM code.
--- include/linux/kvm_host.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
include/linux/kvm_host.h +2 -2
@@ -282,7 +282,7 @@ struct kvm {struct hlist_head irq_ack_notifier_list;#endif -#ifdef KVM_ARCH_WANT_MMU_NOTIFIER +#if defined(CONFIG_MMU_NOTIFIER ) && defined(KVM_ARCH_WANT_MMU_NOTIFIER )struct mmu_notifier mmu_notifier;unsigned long mmu_notifier_seq;long mmu_notifier_count;
@@ -740,7 +740,7 @@ struct kvm_stats_debugfs_item {extern struct kvm_stats_debugfs_item debugfs_entries[];extern struct dentry *kvm_debugfs_dir; -#ifdef KVM_ARCH_WANT_MMU_NOTIFIER +#if defined(CONFIG_MMU_NOTIFIER ) && defined(KVM_ARCH_WANT_MMU_NOTIFIER )static inline int mmu_notifier_retry (struct kvm_vcpu *vcpu,unsigned long mmu_seq) {if (unlikely (vcpu->kvm->mmu_notifier_count))
Re: [PATCH v7 02/12] KVM: Guard mmu_notifier specific code with CONFIG_MMU_NOTIFIER
Quoted 27 lines · Christoffer Dall
From: Marc Zyngier <[email protected]>
In order to avoid compilation failure when KVM is not compiled in, guard the
mmu_notifierspecific sections with bothCONFIG_MMU_NOTIFIERandKVM_ARCH_WANT_MMU_NOTIFIER, like it is being done in the rest of the KVM code.Signed-off-by Marc Zyngier <[email protected]>--- include/linux/kvm_host.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)include/linux/kvm_host.h +1
-1@@ -282,7 +282,7 @@ struct kvm {struct hlist_head irq_ack_notifier_list;#endif -#ifdef KVM_ARCH_WANT_MMU_NOTIFIER +#if defined(CONFIG_MMU_NOTIFIER ) && defined(KVM_ARCH_WANT_MMU_NOTIFIER )struct mmu_notifier mmu_notifier;unsigned long mmu_notifier_seq;long mmu_notifier_count;
include/linux/kvm_host.h struct kvm_stats_debugfs_item { · line 746
Quoted 8 lines
include/linux/kvm_host.h +1
-1@@ -740,7 +740,7 @@ struct kvm_stats_debugfs_item {extern struct kvm_stats_debugfs_item debugfs_entries[];extern struct dentry *kvm_debugfs_dir; -#ifdef KVM_ARCH_WANT_MMU_NOTIFIER +#if defined(CONFIG_MMU_NOTIFIER ) && defined(KVM_ARCH_WANT_MMU_NOTIFIER )static inline int mmu_notifier_retry (struct kvm_vcpu *vcpu,unsigned long mmu_seq) {if (unlikely (vcpu->kvm->mmu_notifier_count))
Should not be needed. If you have KVM_ARCH_WANT_MMU_NOTIFIER, it should also select MMU_NOTIFIER if KVM is selected.
The following should always hold:
!KVM || (KVM_ARCH_WANT_MMU_NOTIFIER && MMU_NOTIFIER)
Signature · 1 line
error compiling committee.c: too many arguments to function
PATCH v7 3/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 | 78 ++++++++++ arch/arm/include/asm/kvm_asm.h | 28 ++++ arch/arm/include/asm/kvm_emulate.h | 97 +++++++++++++ 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 | 44 ++++++ arch/arm/kvm/Makefile | 17 ++ arch/arm/kvm/arm.c | 279 ++++++++++++++++++++++++++++++++++++ arch/arm/kvm/emulate.c | 125 ++++++++++++++++ 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 | 10 + 19 files changed, 1083 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
@@ -252,6 +252,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 +78 -0
78 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 +97 -0
97 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 +44 -0
44 lines not on this page · raw message
arch/arm/kvm/Makefile new file +17 -0
@@ -0,0 +1,17 @@ +# +# Makefile for Kernel-based Virtual Machine module +# + +ccflags-y += -Ivirt/kvm -Iarch/arm/kvm +CFLAGS_arm.o := -I. +CFLAGS_mmu.o := -I. + +AFLAGS_interrupts.o := -I$(obj) + +obj-$(CONFIG_KVM_ARM_HOST) += init.o interrupts.o exports.o + +kvm-arm-y += $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o) + +kvm-arm-y += arm.o guest.o mmu.o emulate.o + +obj-$(CONFIG_KVM) += kvm-arm.o
arch/arm/kvm/arm.c new file +279 -0
279 lines not on this page · raw message
arch/arm/kvm/emulate.c new file +125 -0
125 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 +10 -0
@@ -641,6 +641,16 @@ 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. If you say Y here, the kernel + will not boot on a machine without virtualization extensions and + will not boot as a KVM guest. + config ARCH_PHYS_ADDR_T_64BIT def_bool ARM_LPAE
PATCH v7 4/12 ARM: KVM: Hypervisor identity mapping
In reply to Christoffer DallAdds 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
PATCH v7 5/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 | 22 +++ 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 | 171 +++++++++++++++++++++++++++ arch/arm/kvm/exports.c | 15 ++ arch/arm/kvm/init.S | 98 +++++++++++++++ arch/arm/kvm/interrupts.S | 49 ++++++++ arch/arm/kvm/mmu.c | 153 ++++++++++++++++++++++++ mm/memory.c | 2 12 files changed, 658 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 +22 -0
@@ -24,5 +24,27 @@#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_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 +171 -0
190 lines not on this page · raw message
arch/arm/kvm/exports.c +15 -0
@@ -14,3 +14,18 @@*/ #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_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 +49 -0
54 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) {
PATCH v7 6/12 ARM: KVM: Memory virtualization setup
In reply to Christoffer DallThis commit introduces the framework for guest memory management through the use of 2nd stage translation. Each VM has a pointer to a level-1 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 | 65 ++++++++++++++++++++++--- arch/arm/kvm/mmu.c | 103 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+), 8 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 +57 -8
105 lines not on this page · raw message
arch/arm/kvm/mmu.c +103 -0
109 lines not on this page · raw message
PATCH v7 7/12 ARM: KVM: Inject IRQs and FIQs from userspace
In reply to Christoffer DallFrom: Christoffer Dall <[email protected]>
Userspace can inject IRQs and FIQs through the KVM_IRQ_LINE VM ioctl. This ioctl is used since the sematics are in fact two lines that can be either raised or lowered on the VCPU - the IRQ and FIQ lines.
KVM needs to know which VCPU it must operate on and whether the FIQ or IRQ line is raised/lowered. Hence both pieces of information is packed in the kvm_irq_level->irq field. The irq fild value will be:
IRQ: vcpu_index << 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
@@ -582,15 +582,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 v7 8/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 | 489 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 690 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 +487 -2
516 lines not on this page · raw message
Re: [PATCH v7 08/12] ARM: KVM: World-switch implementation
Quoted 14 lines · Christoffer Dall
arch/arm/kvm/arm.c +10
-0@@ -236,6 +237,24 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)int kvm_arch_vcpu_init (struct kvm_vcpu *vcpu) { +unsigned long cpsr; +unsigned long sctlr; + + +/* Init execution CPSR */ + asmvolatile ("mrs %[cpsr], cpsr" : + [cpsr]"=r" (cpsr)); + vcpu->arch.regs.cpsr =SVC_MODE |PSR_I_BIT |PSR_F_BIT |PSR_A_BIT | + (cpsr &PSR_E_BIT ); +
arch/arm/kvm/arm.c int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) · line 259
Quoted 10 lines
arch/arm/kvm/arm.c +8
-0+/* Init SCTLR with MMU disabled */ + asmvolatile ("mrc p15, 0, %[sctlr], c1, c0, 0" : + [sctlr]"=r" (sctlr)); + vcpu->arch.cp15[c1_SCTLR] = sctlr & ~1U ; + +/* Compute guest MPIDR */ + vcpu->arch.cp15[c0_MPIDR] = (read_cpuid_mpidr () & ~0xff ) + | vcpu->vcpu_id;return 0 ; }
Hi Christoffer!
I started cleaning this up, on the theory that we should use the
defined reset values rather than basing them on host values. Then I discovered that this is ignored by qemu anyway, which overrides the values (except for MPIDR: I set that to 0x80000000 | vcpu->vcpu_id, which seems correct to me).
Should this code be dropped altogether? Peter points out that once we add new regs, they *must* be initialized to correct reset values in case older QEMU knows nothing about them, but for the rest it just seems confusing...
Thanks,
Rusty.
Signature · 1 line
How could I marry someone with more hair than me? http://baldalex.org
Re: [PATCH v7 08/12] ARM: KVM: World-switch implementation
Quoted 34 lines · Rusty Russell
Quoted 14 lines · Christoffer Dall
arch/arm/kvm/arm.c +10
-0@@ -236,6 +237,24 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)int kvm_arch_vcpu_init (struct kvm_vcpu *vcpu) { +unsigned long cpsr; +unsigned long sctlr; + + +/* Init execution CPSR */ + asmvolatile ("mrs %[cpsr], cpsr" : + [cpsr]"=r" (cpsr)); + vcpu->arch.regs.cpsr =SVC_MODE |PSR_I_BIT |PSR_F_BIT |PSR_A_BIT | + (cpsr &PSR_E_BIT ); +arch/arm/kvm/arm.c int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) · line 259
Quoted 10 lines
arch/arm/kvm/arm.c +8
-0+/* Init SCTLR with MMU disabled */ + asmvolatile ("mrc p15, 0, %[sctlr], c1, c0, 0" : + [sctlr]"=r" (sctlr)); + vcpu->arch.cp15[c1_SCTLR] = sctlr & ~1U ; + +/* Compute guest MPIDR */ + vcpu->arch.cp15[c0_MPIDR] = (read_cpuid_mpidr () & ~0xff ) + | vcpu->vcpu_id;return 0 ; }Hi Christoffer!
I started cleaning this up, on the theory that we should use the
defined reset values rather than basing them on host values. Then I discovered that this is ignored by qemu anyway, which overrides the values (except for MPIDR: I set that to0x80000000|vcpu->vcpu_id, which seems correct to me).
Quoted 5 lines
Should this code be dropped altogether? Peter points out that once we add new regs, they *must* be initialized to correct reset values in case older QEMU knows nothing about them, but for the rest it just seems confusing...
It's best to initialize everything. As far as this code is concerned qemu is just another user and we shouldn't rely on its implementation.
Signature · 1 line
error compiling committee.c: too many arguments to function
Re: [PATCH v7 08/12] ARM: KVM: World-switch implementation
Quoted 35 lines · Avi Kivity
Quoted 34 lines · Rusty Russell
Quoted 14 lines · Christoffer Dall
arch/arm/kvm/arm.c +10
-0@@ -236,6 +237,24 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)int kvm_arch_vcpu_init (struct kvm_vcpu *vcpu) { +unsigned long cpsr; +unsigned long sctlr; + + +/* Init execution CPSR */ + asmvolatile ("mrs %[cpsr], cpsr" : + [cpsr]"=r" (cpsr)); + vcpu->arch.regs.cpsr =SVC_MODE |PSR_I_BIT |PSR_F_BIT |PSR_A_BIT | + (cpsr &PSR_E_BIT ); +arch/arm/kvm/arm.c int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) · line 259
Quoted 10 lines
arch/arm/kvm/arm.c +8
-0+/* Init SCTLR with MMU disabled */ + asmvolatile ("mrc p15, 0, %[sctlr], c1, c0, 0" : + [sctlr]"=r" (sctlr)); + vcpu->arch.cp15[c1_SCTLR] = sctlr & ~1U ; + +/* Compute guest MPIDR */ + vcpu->arch.cp15[c0_MPIDR] = (read_cpuid_mpidr () & ~0xff ) + | vcpu->vcpu_id;return 0 ; }Hi Christoffer!
I started cleaning this up, on the theory that we should use the
defined reset values rather than basing them on host values. Then I discovered that this is ignored by qemu anyway, which overrides the values (except for MPIDR: I set that to0x80000000|vcpu->vcpu_id, which seems correct to me).
Quoted 8 lines
Quoted 5 lines
Should this code be dropped altogether? Peter points out that once we add new regs, they *must* be initialized to correct reset values in case older QEMU knows nothing about them, but for the rest it just seems confusing...
It's best to initialize everything. As far as this code is concerned qemu is just another user and we shouldn't rely on its implementation.
In which case, qemu should not initialize anything, but read the registers from the kernel to start with.
Cheers,
Rusty.
Signature · 1 line
How could I marry someone with more hair than me? http://baldalex.org
Re: [PATCH v7 08/12] ARM: KVM: World-switch implementation
Quoted 7 lines · Rusty Russell
Quoted 7 lines
Quoted 6 lines
Should this code be dropped altogether? Peter points out that once we add new regs, they *must* be initialized to correct reset values in case older QEMU knows nothing about them, but for the rest it just seems confusing...
Quoted 5 lines
Quoted 2 lines
It's best to initialize everything. As far as this code is concerned qemu is just another user and we shouldn't rely on its implementation.
In which case, qemu should not initialize anything, but read the registers from the kernel to start with.
qemu has its own set of considerations. For example, it needs to initialize registers in tcg mode. But that's another discussion.
Signature · 1 line
error compiling committee.c: too many arguments to function
Re: [PATCH v7 08/12] ARM: KVM: World-switch implementation
Quoted 8 lines · Avi Kivity
Quoted 7 lines · Rusty Russell
Quoted 7 lines
Quoted 6 lines
Should this code be dropped altogether? Peter points out that once we add new regs, they *must* be initialized to correct reset values in case older QEMU knows nothing about them, but for the rest it just seems confusing...
Quoted 9 lines
Quoted 5 lines
Quoted 2 lines
It's best to initialize everything. As far as this code is concerned qemu is just another user and we shouldn't rely on its implementation.
In which case, qemu should not initialize anything, but read the registers from the kernel to start with.
qemu has its own set of considerations. For example, it needs to initialize registers in tcg mode. But that's another discussion.
sorry about the late response on this one. This code should be changed to initialize to reset values for all the registers. Thanks.
PATCH v7 9/12 ARM: KVM: Emulation framework and CP15 emulation
In reply to Christoffer DallFrom: Christoffer Dall <[email protected]>
Adds a new important function in the main KVM/ARM code called handle_exit() which is called from kvm_arch_vcpu_ioctl_run() on returns from guest execution. This function examines the Hyp-Syndrome-Register (HSR), which contains information telling KVM what caused the exit from the guest.
Some of the reasons for an exit are CP15 accesses, which are not allowed from the guest and this commit handles these exits by emulating the intended operation in software and skip the guest instruction.
--- arch/arm/include/asm/kvm_emulate.h | 8 + arch/arm/kvm/arm.c | 87 ++++++++++++ arch/arm/kvm/emulate.c | 266 ++++++++++++++++++++++++++++++++++++ arch/arm/kvm/trace.h | 28 ++++ 4 files changed, 389 insertions(+), 0 deletions(-)
arch/arm/include/asm/kvm_emulate.h +8 -0
@@ -40,6 +40,14 @@ static inline enum vcpu_mode 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_32 (struct kvm_vcpu *vcpu,struct kvm_run *run); +int kvm_handle_cp15_64 (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 +87 -0
105 lines not on this page · raw message
arch/arm/kvm/emulate.c +266 -0
276 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 v7 10/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.
Leverages MMU notifiers on KVM/ARM by supporting the kvm_unmap_hva() operation, where we remove the HVA from the 2nd stage translation. All other KVM MMU notifierhooks are NOPs.
--- arch/arm/include/asm/kvm_asm.h | 3 + arch/arm/include/asm/kvm_host.h | 19 ++++ arch/arm/include/asm/pgtable-3level.h | 8 ++ arch/arm/include/asm/pgtable.h | 4 + arch/arm/kvm/Kconfig | 1 arch/arm/kvm/interrupts.S | 37 ++++++++ arch/arm/kvm/mmu.c | 162 +++++++++++++++++++++++++++++++++ arch/arm/mm/mmu.c | 3 + 8 files changed, 236 insertions(+), 1 deletions(-)
arch/arm/include/asm/kvm_asm.h +3 -0
@@ -32,6 +32,7 @@#define SMCHYP_HVBAR_W 0xfffffff0#ifndef __ASSEMBLY__ +struct kvm ;struct kvm_vcpu ;extern char __kvm_hyp_init[];
@@ -42,6 +43,8 @@ extern char __kvm_hyp_vector[];extern char __kvm_hyp_code_start[];extern char __kvm_hyp_code_end[]; +extern void __kvm_tlb_flush_vmid (struct kvm *kvm); +extern void __kvm_flush_vm_context (void );extern int __kvm_vcpu_run (struct kvm_vcpu *vcpu);
arch/arm/include/asm/kvm_host.h +19 -0
@@ -114,4 +114,23 @@ struct kvm_vcpu_stat { u32 halt_wakeup; }; +#define KVM_ARCH_WANT_MMU_NOTIFIER +struct kvm ; +int kvm_unmap_hva (struct kvm *kvm,unsigned long hva); + +/* We do not have shadow page tables, hence the empty hooks */ +static inline int kvm_age_hva (struct kvm *kvm,unsigned long hva) +{ +return 0 ; +} + +static inline int kvm_test_age_hva (struct kvm *kvm,unsigned long hva) +{ +return 0 ; +} + +static inline void kvm_set_spte_hva (struct kvm *kvm,unsigned long hva,pte_t pte) +{ +} +#endif /* __ARM_KVM_HOST_H__ */
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/Kconfig +1 -0
@@ -36,6 +36,7 @@ config KVM_ARM_HOST depends on KVM depends on MMU depends on CPU_V7 && ARM_VIRT_EXT + select MMU_NOTIFIER ---help--- Provides host support for ARM processors.
arch/arm/kvm/interrupts.S +37 -0
@@ -35,9 +35,46 @@ __kvm_hyp_code_start: .globl __kvm_hyp_code_start @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ Flush per-VMID TLBs +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +/* + * void __kvm_tlb_flush_vmid(struct kvm *kvm); + * + * We rely on the hardware to broadcast the TLB invalidation to all CPUs + * inside the inner-shareable domain (which is the case for all v7 + * implementations). If we come across a non-IS SMP implementation, we'll + * have to use an IPI based mechanism. Until then, we stick to the simple + * hardware assisted version. + */ +ENTRY(__kvm_tlb_flush_vmid) + hvc #0 @ Switch to Hyp mode + push {r2, r3} + + add r0, r0, #KVM_VTTBR + ldrd r2, r3, [r0] + mcrr p15, 6, r2, r3, c2 @ Write VTTBR + isb + mcr p15, 0, r0, c8, c3, 0 @ TLBIALLIS (rt ignored) + dsb + isb + mov r2, #0 + mov r3, #0 + mcrr p15, 6, r2, r3, c2 @ Back to VMID #0 + isb + + pop {r2, r3} + hvc #0 @ Back to SVC + mov pc, lr +ENDPROC(__kvm_tlb_flush_vmid) + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ Flush TLBs and instruction caches of current CPU for all VMIDs @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +/* + * void __kvm_flush_vm_context(void); + */ ENTRY(__kvm_flush_vm_context) hvc #0 @ switch to hyp-mode
arch/arm/kvm/mmu.c +161 -1
186 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;
Re: [Android-virt] [PATCH v7 10/12] ARM: KVM: Handle guest faults in KVM
Quoted 11 lines · Christoffer Dall
From: Christoffer Dall <[email protected]>
Handles the guest faults in KVM by mapping in corresponding user pages in the 2nd stage page tables.
Introduces new ARM-specific kernel memory types,
PAGE_KVM_GUESTandpgprot_guestvariables used to map 2nd stage memory for KVM guests.Leverages MMU notifiers on KVM/ARM by supporting the
kvm_unmap_hva()operation, where we remove the HVA from the 2nd stage translation. All other KVM MMU notifierhooks are NOPs.
This seem to be a rather old version of my notifier patches (I have a newer one in my kvm-arm-next-wip branch).
I'll respin a patch set against the v7 branch.
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
Re: [Android-virt] [PATCH v7 10/12] ARM: KVM: Handle guest faults in KVM
Quoted 9 lines · Marc Zyngier
Quoted 8 lines · Christoffer Dall
From: Christoffer Dall <[email protected]>
Handles the guest faults in KVM by mapping in corresponding user pages in the 2nd stage page tables.
Introduces new ARM-specific kernel memory types,
PAGE_KVM_GUESTandpgprot_guestvariables used to map 2nd stage memory for KVM guests.
Quoted 9 lines
Quoted 3 lines
Leverages MMU notifiers on KVM/ARM by supporting the
kvm_unmap_hva()operation, where we remove the HVA from the 2nd stage translation. All other KVM MMU notifierhooks are NOPs.This seem to be a rather old version of my notifier patches (I have a newer one in my kvm-arm-next-wip branch).
I'll respin a patch set against the v7 branch.
ok, I assumed that you mailed the patches you wanted merged, but I can look in your tree instead next time around.
It will probably be a good idea if you can rebase whatever you have on top of the v7 branch.
-Christoffer
Re: [Android-virt] [PATCH v7 10/12] ARM: KVM: Handle guest faults in KVM
Quoted 14 lines · Christoffer Dall
Quoted 13 lines · Marc Zyngier
Quoted 11 lines · Christoffer Dall
From: Christoffer Dall <[email protected]>
Handles the guest faults in KVM by mapping in corresponding user pages in the 2nd stage page tables.
Introduces new ARM-specific kernel memory types,
PAGE_KVM_GUESTandpgprot_guestvariables used to map 2nd stage memory for KVM guests.Leverages MMU notifiers on KVM/ARM by supporting the
kvm_unmap_hva()operation, where we remove the HVA from the 2nd stage translation. All other KVM MMU notifierhooks are NOPs.
Quoted 7 lines
Quoted 5 lines
This seem to be a rather old version of my notifier patches (I have a newer one in my kvm-arm-next-wip branch).
I'll respin a patch set against the v7 branch.
ok, I assumed that you mailed the patches you wanted merged, but I can look in your tree instead next time around.
My bad. I thought I had sent the patches to the ML, but obviously only did that in my dreams.
Quoted 2 lines
It will probably be a good idea if you can rebase whatever you have on top of the v7 branch.
Will do that tonight.
Thanks,
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
PATCH v7 11/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
@@ -47,6 +47,8 @@ int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run);int kvm_handle_cp15_32 (struct kvm_vcpu *vcpu,struct kvm_run *run);int kvm_handle_cp15_64 (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
@@ -456,6 +456,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
175 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 v7 12/12 ARM: KVM: Guest wait-for-interrupts (WFI) support
In reply to Christoffer DallFrom: Christoffer Dall <[email protected]>
When the guest executes a WFI instruction the operation is trapped to KVM, which emulates the instruction in software. There is no correlation between a guest executing a WFI instruction and actually 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
@@ -291,9 +291,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)
@@ -479,6 +487,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 */
@@ -551,6 +562,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
@@ -407,8 +407,20 @@ int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run)return emulate_cp15 (vcpu, ¶ms); } +/** +* 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
Quoted 7 lines · Christoffer Dall
The following series implements KVM support for ARM processors, specifically on the Cortex A-15 platform.
The patch series applies to a mashup of v3.3-rc6, the vexpress support, and kvm-next. I apologize for this mess, but there's really no good way around this, since we need vexpress support and we want to keep up with kvm-next for QEMU support.
That's not a mess, that's how distributed development works.
Note you could base your patches on linux-next, if it includes vexpress support, since it already includes kvm.git next (with some lag). In any case basing patches on a merge of all required trees is fine.
Quoted 2 lines
Changes since v6:
- Support for MMU notifiers to not pin user pages in memory
Nice! As I repeat at every possible opportunity, mmu notifiers are a big part of what makes kvm successful.
Signature · 1 line
error compiling committee.c: too many arguments to function
PATCH 1/1 ARM: KVM: Remove l2ctlr write.
In reply to Christoffer DallCurrent guests don't do this, and it's not clear what we should do if they try to turn on ECC or set various RAM latencies. When someone does this, we'll have a better idea of what we should do about it.
arch/arm/kvm/emulate.c +1 -4
@@ -290,13 +290,10 @@ static const struct coproc_emulate coproc_emulate[] = { { CRn( 0), CRm( 1), Op1( 0), Op2( 2), is32, READ, read_id_dfr0},/* -* L2CTLR access: -* -* Ignore writes completely. +* L2CTLR access (guest wants to know #CPUs). * * FIXME: Hack Alert: Read zero as default case. */ - { CRn( 9), CRm( 0), Op1( 1), Op2( 2), is32, WRITE, ignore_write}, { CRn( 9), CRm( 0), Op1( 1), Op2( 2), is32, READ, read_l2ctlr}, { CRn( 9), CRm(DF), Op1(DF), Op2(DF), is32, WRITE, ignore_write}, { CRn( 9), CRm(DF), Op1(DF), Op2(DF), is32, READ, read_zero},
Re: [PATCH] ARM: KVM: Remove l2ctlr write.
Quoted 15 lines · Rusty Russell
Current guests don't do this, and it's not clear what we should do if they try to turn on ECC or set various RAM latencies. When someone does this, we'll have a better idea of what we should do about it.
Signed-off-by Rusty Russell <[email protected]>arch/arm/kvm/emulate.c +0
-1@@ -290,13 +290,10 @@ static const struct coproc_emulate coproc_emulate[] = { { CRn( 0), CRm( 1), Op1( 0), Op2( 2), is32, READ, read_id_dfr0}, /* -* L2CTLR access:
arch/arm/kvm/emulate.c static const struct coproc_emulate coproc_emulate[] = { · line 299
Quoted 10 lines
arch/arm/kvm/emulate.c +1
-3-* -* Ignore writes completely. +* L2CTLR access (guest wants to know #CPUs). * * FIXME: Hack Alert: Read zero as default case. */ - { CRn( 9), CRm( 0), Op1( 1), Op2( 2), is32, WRITE, ignore_write}, { CRn( 9), CRm( 0), Op1( 1), Op2( 2), is32, READ, read_l2ctlr}, { CRn( 9), CRm(DF), Op1(DF), Op2(DF), is32, WRITE, ignore_write}, { CRn( 9), CRm(DF), Op1(DF), Op2(DF), is32, READ, read_zero},
ack
cover Emulation cleanups
In reply to Christoffer DallUnfortunately, my time got stolen by other projects during the last two weeks, but I wanted to post these before my wedding/honeymoon next week (back May 7).
Nothing too radical, though the last one might effect anyone trying to make an A9 guest. If so, they'll notice, and we can probably tag the emulation entries appropriately...
Thanks!
Rusty.
Signature · 1 line
How could I marry someone with more hair than me? http://baldalex.org
PATCH 1/3 ARM: KVM: Remove l2ctlr write.
Current guests don't do this, and it's not clear what we should do if they try to turn on ECC or set various RAM latencies. When someone does this, we'll have a better idea of what we should do about it.
--- arch/arm/kvm/emulate.c | 5 +---- 1 files changed, 1 insertions(+), 4 deletions(-)
arch/arm/kvm/emulate.c +1 -4
@@ -278,13 +278,10 @@ struct coproc_emulate {static const struct coproc_emulate coproc_emulate[] = {/* -* L2CTLR access: -* -* Ignore writes completely. +* L2CTLR access (guest wants to know #CPUs). * * FIXME: Hack Alert: Read zero as default case. */ - {CRn (9 ),CRm (0 ),Op1 (1 ),Op2 (2 ), is32,WRITE , ignore_write}, {CRn (9 ),CRm (0 ),Op1 (1 ),Op2 (2 ), is32,READ , read_l2ctlr}, {CRn (9 ),CRm (DF ),Op1 (DF ),Op2 (DF ), is32,WRITE , ignore_write}, {CRn (9 ),CRm (DF ),Op1 (DF ),Op2 (DF ), is32,READ , read_zero},
Signature · 1 line
How could I marry someone with more hair than me? http://baldalex.org
PATCH 2/3 ARM: KVM: Fake up performance counters a little more precisely.
In reply to [email protected]Rather than just making all of c9 read-zero/write-discard, this changes it to the explicit profiling registers we need. This is a start for the future implementation were we actually implement performance monitoring, and makes sure we're not discarding important things.
--- arch/arm/kvm/emulate.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 65 insertions(+), 2 deletions(-)
arch/arm/kvm/emulate.c +65 -2
@@ -238,6 +238,64 @@ static bool read_l2ctlr(struct kvm_vcpu *vcpu,return true; } +static bool read_pmcr (struct kvm_vcpu *vcpu, +const struct coproc_params *p, +unsigned long arg) +{ +u32 imp, idcode, num; + + imp = (vcpu->arch.cp15[c0_MIDR] &0xFF000000 ) >>24 ; + idcode = (vcpu->arch.cp15[c0_MIDR] &0x00000FF0 ) >>4 ; +/* No counters. */ + num =0 ; + +/* Other bits are at reset value. */ + *vcpu_reg (vcpu, p->Rt1) = (imp <<24 ) | (idcode <<16 ) | (num <<11 ); +return true; +} + +/* FIXME: We ignore them enabling performance monitoring. */ +static bool write_pmcr (struct kvm_vcpu *vcpu, +const struct coproc_params *p, +unsigned long arg) +{ +u32 val = *vcpu_reg (vcpu, p->Rt1); + +kvm_debug ("pmcr write:%s%s%s%s%s%s\n" , + val & (1 <<5 ) ?" DP" :"" , + val & (1 <<4 ) ?" X" :"" , + val & (1 <<3 ) ?" D" :"" , + val & (1 <<2 ) ?" C" :"" , + val & (1 <<1 ) ?" P" :"" , + val & (1 <<0 ) ?" E" :"" ); +return true; +} + +static bool read_pmcntenclr (struct kvm_vcpu *vcpu, +const struct coproc_params *p, +unsigned long arg) +{ +/* Cycle counter is off, there are no others. */ + *vcpu_reg (vcpu, p->Rt1) =0 ; +return true; +} + +static bool write_pmcntenclr (struct kvm_vcpu *vcpu, +const struct coproc_params *p, +unsigned long arg) +{ +/* Writing a 1 means disable a counter. That's cool. */ +return true; +} + +static bool write_pmintenclr (struct kvm_vcpu *vcpu, +const struct coproc_params *p, +unsigned long arg) +{ +/* Writing a 1 means disable an overflow interrupt. That's cool. */ +return true; +} +static bool access_cp15_reg (struct kvm_vcpu *vcpu,const struct coproc_params *p,unsigned long cp15_reg)
@@ -279,13 +337,18 @@ struct coproc_emulate {static const struct coproc_emulate coproc_emulate[] = {/* * L2CTLR access (guest wants to know #CPUs). -* -* FIXME: Hack Alert: Read zero as default case. */ {CRn (9 ),CRm (0 ),Op1 (1 ),Op2 (2 ), is32,READ , read_l2ctlr}, {CRn (9 ),CRm (DF ),Op1 (DF ),Op2 (DF ), is32,WRITE , ignore_write}, {CRn (9 ),CRm (DF ),Op1 (DF ),Op2 (DF ), is32,READ , read_zero}, +/* Guest reads/writes PMU, assuming there will be one. */ + {CRn (9 ),CRm (12 ),Op1 (0 ),Op2 (0 ), is32,READ , read_pmcr}, + {CRn (9 ),CRm (12 ),Op1 (0 ),Op2 (0 ), is32,WRITE , write_pmcr}, + {CRn (9 ),CRm (12 ),Op1 (0 ),Op2 (2 ), is32,READ , read_pmcntenclr}, + {CRn (9 ),CRm (12 ),Op1 (0 ),Op2 (2 ), is32,WRITE , write_pmcntenclr}, + {CRn (9 ),CRm (14 ),Op1 (0 ),Op2 (2 ), is32,WRITE , write_pmintenclr}, +/* * These CRn == 10 entries may not need to exist - if we can * ignore guest attempts to tamper with TLB lockdowns then it
Signature · 1 line
How could I marry someone with more hair than me? http://baldalex.org
Re: [PATCH 2/3] ARM: KVM: Fake up performance counters a little more precisely.
Quoted 16 lines · Rusty Russell
Rather than just making all of c9 read-zero/write-discard, this changes it to the explicit profiling registers we need. This is a start for the future implementation were we actually implement performance monitoring, and makes sure we're not discarding important things.
Signed-off-by Rusty Russell <[email protected]>---
arch/arm/kvm/emulate.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++-1 files changed, 65 insertions(+), 2 deletions(-)arch/arm/kvm/emulate.c +0
-0@@ -238,6 +238,64 @@ static bool read_l2ctlr(struct kvm_vcpu *vcpu, return true;
arch/arm/kvm/emulate.c static bool read_l2ctlr(struct kvm_vcpu *vcpu, · line 248
Quoted 10 lines
arch/arm/kvm/emulate.c +8
-0} +static bool read_pmcr (struct kvm_vcpu *vcpu, + const struct coproc_params *p, + unsigned long arg) +{ + u32 imp, idcode, num; + + imp = (vcpu->arch.cp15[c0_MIDR] & 0xFF000000) >> 24; + idcode = (vcpu->arch.cp15[c0_MIDR] & 0x00000FF0) >> 4;
where does it say that idcode is always te same as MIDR?
arch/arm/kvm/emulate.c static bool read_l2ctlr(struct kvm_vcpu *vcpu, · line 252
Quoted 4 lines
arch/arm/kvm/emulate.c +4
-0+ /* No counters. */ + num = 0; + + /* Other bits are at reset value. */
what's the point of writing anything below then? I would assume that you can have really weird behavior if you read something different from what you once wrote, shouldn't you read num from the vcpu value with the bit-filter below?
arch/arm/kvm/emulate.c static bool read_l2ctlr(struct kvm_vcpu *vcpu, · line 257
Quoted 5 lines
arch/arm/kvm/emulate.c +5
-0+ *vcpu_reg(vcpu, p->Rt1) = (imp << 24) | (idcode << 16) | (num << 11); + return true; +} + +/* FIXME: We ignore them enabling performance monitoring. */
if this is a FIXME, then how is it eventually going to be fixed?
Quoted 52 lines
arch/arm/kvm/emulate.c +41
-2+static bool write_pmcr (struct kvm_vcpu *vcpu, + const struct coproc_params *p, + unsigned long arg) +{ + u32 val = *vcpu_reg(vcpu, p->Rt1); + + kvm_debug("pmcr write:%s%s%s%s%s%s\n", + val & (1 << 5) ? " DP" : "", + val & (1 << 4) ? " X" : "", + val & (1 << 3) ? " D" : "", + val & (1 << 2) ? " C" : "", + val & (1 << 1) ? " P" : "", + val & (1 << 0) ? " E" : ""); + return true; +} + +static bool read_pmcntenclr (struct kvm_vcpu *vcpu, + const struct coproc_params *p, + unsigned long arg) +{ + /* Cycle counter is off, there are no others. */ + *vcpu_reg(vcpu, p->Rt1) = 0; + return true; +} + +static bool write_pmcntenclr (struct kvm_vcpu *vcpu, + const struct coproc_params *p, + unsigned long arg) +{ + /* Writing a 1 means disable a counter. That's cool. */ + return true; +} + +static bool write_pmintenclr (struct kvm_vcpu *vcpu, + const struct coproc_params *p, + unsigned long arg) +{ + /* Writing a 1 means disable an overflow interrupt. That's cool. */ + return true; +} + static bool access_cp15_reg(struct kvm_vcpu *vcpu, const struct coproc_params *p, unsigned long cp15_reg)@@ -279,13 +337,18 @@ struct coproc_emulate { static const struct coproc_emulate coproc_emulate[] = { /* * L2CTLR access (guest wants to know #CPUs). - * - * FIXME: Hack Alert: Read zero as default case. */ { CRn( 9), CRm( 0), Op1( 1), Op2( 2), is32, READ, read_l2ctlr},
arch/arm/kvm/emulate.c struct coproc_emulate { · line 351
Quoted 10 lines
arch/arm/kvm/emulate.c +7
-0{ CRn( 9), CRm(DF), Op1(DF), Op2(DF), is32, WRITE, ignore_write}, { CRn( 9), CRm(DF), Op1(DF), Op2(DF), is32, READ, read_zero}, + /* Guest reads/writes PMU, assuming there will be one. */ + { CRn( 9), CRm(12), Op1( 0), Op2( 0), is32, READ, read_pmcr}, + { CRn( 9), CRm(12), Op1( 0), Op2( 0), is32, WRITE, write_pmcr}, + { CRn( 9), CRm(12), Op1( 0), Op2( 2), is32, READ, read_pmcntenclr}, + { CRn( 9), CRm(12), Op1( 0), Op2( 2), is32, WRITE, write_pmcntenclr}, + { CRn( 9), CRm(14), Op1( 0), Op2( 2), is32, WRITE, write_pmintenclr}, +
won't all the DF versions above "eat" these calls? Should they just go away or are there still default cases to catch in which case the comment about reading zero should perhaps be modified to specifically mention these cases?
arch/arm/kvm/emulate.c struct coproc_emulate { · line 354
Quoted 3 lines
arch/arm/kvm/emulate.c +0
-0/** These CRn == 10 entries may not need to exist - if we can * ignore guest attempts to tamper with TLB lockdowns then it
Thanks,
Christoffer
Re: [PATCH 2/3] ARM: KVM: Fake up performance counters a little more precisely.
Quoted 19 lines · Christoffer Dall
Quoted 18 lines · Rusty Russell
Rather than just making all of c9 read-zero/write-discard, this changes it to the explicit profiling registers we need. This is a start for the future implementation were we actually implement performance monitoring, and makes sure we're not discarding important things.
Signed-off-by Rusty Russell <[email protected]>---
arch/arm/kvm/emulate.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++-1 files changed, 65 insertions(+), 2 deletions(-)arch/arm/kvm/emulate.c +0
-0@@ -238,6 +238,64 @@ static bool read_l2ctlr(struct kvm_vcpu *vcpu, return true; }
Quoted 10 lines
arch/arm/kvm/emulate.c static bool read_l2ctlr(struct kvm_vcpu *vcpu, · line 248
Quoted 8 lines
arch/arm/kvm/emulate.c +8
-0+static bool read_pmcr (struct kvm_vcpu *vcpu, + const struct coproc_params *p, + unsigned long arg) +{ + u32 imp, idcode, num; + + imp = (vcpu->arch.cp15[c0_MIDR] & 0xFF000000) >> 24; + idcode = (vcpu->arch.cp15[c0_MIDR] & 0x00000FF0) >> 4;where does it say that idcode is always te same as MIDR?
Good point, it doesn't. It is true for the Cortex A-15, at least. This would be more generically a switch statement on "what CPU are we" ioctl, as I mentioned in the previous mail.
Quoted 9 lines
arch/arm/kvm/emulate.c static bool read_l2ctlr(struct kvm_vcpu *vcpu, · line 252
Quoted 4 lines
arch/arm/kvm/emulate.c +4
-0+ /* No counters. */ + num = 0; + + /* Other bits are at reset value. */what's the point of writing anything below then? I would assume that you can have really weird behavior if you read something different from what you once wrote, shouldn't you read num from the vcpu value with the bit-filter below?
I think I meant that the other bits are 0 at reset. But yes, some should be read back as written.
This would mean saving what they actually wrote, which is not a bad idea.
Quoted 3 lines
arch/arm/kvm/emulate.c static bool read_l2ctlr(struct kvm_vcpu *vcpu, · line 257
Quoted 1 line
arch/arm/kvm/emulate.c +1
-0+/* FIXME: We ignore them enabling performance monitoring. */ if this is a FIXME, then how is it eventually going to be fixed?
I was thinking that eventually we implement performance monitoring?
Quoted 55 lines
Quoted 55 lines
arch/arm/kvm/emulate.c +41
-2+static bool write_pmcr (struct kvm_vcpu *vcpu, + const struct coproc_params *p, + unsigned long arg) +{ + u32 val = *vcpu_reg(vcpu, p->Rt1); + + kvm_debug("pmcr write:%s%s%s%s%s%s\n", + val & (1 << 5) ? " DP" : "", + val & (1 << 4) ? " X" : "", + val & (1 << 3) ? " D" : "", + val & (1 << 2) ? " C" : "", + val & (1 << 1) ? " P" : "", + val & (1 << 0) ? " E" : ""); + return true; +} + +static bool read_pmcntenclr (struct kvm_vcpu *vcpu, + const struct coproc_params *p, + unsigned long arg) +{ + /* Cycle counter is off, there are no others. */ + *vcpu_reg(vcpu, p->Rt1) = 0; + return true; +} + +static bool write_pmcntenclr (struct kvm_vcpu *vcpu, + const struct coproc_params *p, + unsigned long arg) +{ + /* Writing a 1 means disable a counter. That's cool. */ + return true; +} + +static bool write_pmintenclr (struct kvm_vcpu *vcpu, + const struct coproc_params *p, + unsigned long arg) +{ + /* Writing a 1 means disable an overflow interrupt. That's cool. */ + return true; +} + static bool access_cp15_reg(struct kvm_vcpu *vcpu, const struct coproc_params *p, unsigned long cp15_reg)@@ -279,13 +337,18 @@ struct coproc_emulate { static const struct coproc_emulate coproc_emulate[] = { /* * L2CTLR access (guest wants to know #CPUs). - * - * FIXME: Hack Alert: Read zero as default case. */ { CRn( 9), CRm( 0), Op1( 1), Op2( 2), is32, READ, read_l2ctlr}, { CRn( 9), CRm(DF), Op1(DF), Op2(DF), is32, WRITE, ignore_write}, { CRn( 9), CRm(DF), Op1(DF), Op2(DF), is32, READ, read_zero},
Quoted 12 lines
arch/arm/kvm/emulate.c struct coproc_emulate { · line 351
Quoted 7 lines
arch/arm/kvm/emulate.c +7
-0+ /* Guest reads/writes PMU, assuming there will be one. */ + { CRn( 9), CRm(12), Op1( 0), Op2( 0), is32, READ, read_pmcr}, + { CRn( 9), CRm(12), Op1( 0), Op2( 0), is32, WRITE, write_pmcr}, + { CRn( 9), CRm(12), Op1( 0), Op2( 2), is32, READ, read_pmcntenclr}, + { CRn( 9), CRm(12), Op1( 0), Op2( 2), is32, WRITE, write_pmcntenclr}, + { CRn( 9), CRm(14), Op1( 0), Op2( 2), is32, WRITE, write_pmintenclr}, +won't all the DF versions above "eat" these calls? Should they just go away or are there still default cases to catch in which case the comment about reading zero should perhaps be modified to specifically mention these cases?
Posted in too much of a hurry. Yes, the DFs to get removed.
I'll re-spin this, and re-test.
Thanks,
Rusty.
PATCH 3/3 ARM: KVM: Check the cpuid we're being asked to emulate.
In reply to [email protected]As our emulation gets more sophisticated, we need to know what CPU model we're dealing with. Particularly for some of the nastier workarounds.
Let's start with Cortex A-15. We can then test the MIDR elsewhere in the code, knowing that it's one of a finite set of allowed values.
--- arch/arm/kvm/guest.c | 18 ++++++++++++++++++ 1 files changed, 18 insertions(+), 0 deletions(-)
arch/arm/kvm/guest.c +18 -0
@@ -82,6 +82,24 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)int kvm_arch_vcpu_ioctl_set_regs (struct kvm_vcpu *vcpu,struct kvm_regs *regs) {struct kvm_vcpu_regs *vcpu_regs = &vcpu->arch.regs; +u32 impl, var, arch, part; + +/* Check we understand what CPU we're being asked to emulate. */ + impl = (regs->cp15.c0_midr &0xFF000000 ) >>24 ; + var = (regs->cp15.c0_midr &0x00F00000 ) >>20 ; + arch = (regs->cp15.c0_midr &0x000F0000 ) >>16 ; + part = (regs->cp15.c0_midr &0x0000FFF0 ) >>4 ; + +switch (regs->cp15.c0_midr >>24 ) { +case 'A' :/* ARM */ +/* Cortex-A15 */ +if (var ==0x2 && arch ==0xF && part ==0xC0F ) +break ; +else +return -EINVAL ; +default : +return -EINVAL ; + }memcpy (&(vcpu_regs->usr_regs[0 ]), regs->regs0_7,sizeof (u32) *8 );memcpy (&(vcpu_regs->usr_regs[8 ]), regs->usr_regs8_12,sizeof (u32) *5 );
Signature · 1 line
How could I marry someone with more hair than me? http://baldalex.org