[Android-virt] [PATCH v2 02/11] ARM: KVM: Initial VGIC infrastructure support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Wire the basic framework code for VGIC support. Nothing to enable
yet.

Signed-off-by: Marc Zyngier <marc.zyngier at arm.com>
---
 arch/arm/include/asm/kvm_emulate.h |    9 +++++++
 arch/arm/include/asm/kvm_host.h    |    8 ++++++
 arch/arm/include/asm/kvm_vgic.h    |   47 ++++++++++++++++++++++++++++++++++++
 arch/arm/kvm/arm.c                 |   18 ++++++++++++++
 arch/arm/kvm/emulate.c             |    2 +-
 arch/arm/kvm/interrupts.S          |   18 ++++++++++++++
 arch/arm/kvm/mmu.c                 |    3 +++
 virt/kvm/kvm_main.c                |    5 ++--
 8 files changed, 107 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/include/asm/kvm_vgic.h

diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h
index c41537b..7774ec4 100644
--- a/arch/arm/include/asm/kvm_emulate.h
+++ b/arch/arm/include/asm/kvm_emulate.h
@@ -22,6 +22,15 @@
 #include <linux/kvm_host.h>
 #include <asm/kvm_asm.h>
 
+/*
+ * The in-kernel MMIO emulation code wants to use a copy of run->mmio,
+ * which is an anonymous type. In order to avoid keeping the two types
+ * in sync, use the below horror. Yes, this is beyond ugly.
+ */
+struct kvm_exit_mmio {
+	typeof(((struct kvm_run *)0)->mmio)	mmio;
+};
+
 u32 *vcpu_reg_mode(struct kvm_vcpu *vcpu, u8 reg_num, enum vcpu_mode mode);
 
 static inline u8 __vcpu_mode(u32 cpsr)
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 91be029..3b289b8 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -24,6 +24,8 @@
 #define KVM_PRIVATE_MEM_SLOTS 4
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
 
+#include <asm/kvm_vgic.h>
+
 /* We don't currently support large pages. */
 #define KVM_HPAGE_GFN_SHIFT(x)	0
 #define KVM_NR_PAGE_SIZES	1
@@ -45,6 +47,9 @@ struct kvm_arch {
 
 	/* VTTBR value associated with above pgd and vmid */
 	u64    vttbr;
+
+	/* Interrupt controller */
+	struct vgic_dist	vgic;
 };
 
 #define EXCEPTION_NONE      0
@@ -125,6 +130,9 @@ struct kvm_vcpu_arch {
 
 	/* Hyp exception information */
 	u32 hyp_pc;		/* PC when exception was taken from Hyp mode */
+
+	/* VGIC state */
+	struct vgic_cpu vgic_cpu;
 };
 
 struct kvm_vm_stat {
diff --git a/arch/arm/include/asm/kvm_vgic.h b/arch/arm/include/asm/kvm_vgic.h
new file mode 100644
index 0000000..8e8bd6d
--- /dev/null
+++ b/arch/arm/include/asm/kvm_vgic.h
@@ -0,0 +1,47 @@
+#ifndef __ASM_ARM_KVM_VGIC_H
+#define __ASM_ARM_KVM_VGIC_H
+
+struct vgic_dist {
+};
+
+struct vgic_cpu {
+};
+
+struct kvm;
+struct kvm_vcpu;
+struct kvm_run;
+struct kvm_exit_mmio;
+
+#ifndef CONFIG_KVM_ARM_VGIC
+static inline int kvm_vgic_hyp_init(void)
+{
+	return 0;
+}
+
+static inline int kvm_vgic_init(struct kvm *kvm)
+{
+	return 0;
+}
+
+static inline void kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu) {}
+static inline void kvm_vgic_sync_to_cpu(struct kvm_vcpu *vcpu) {}
+static inline void kvm_vgic_sync_from_cpu(struct kvm_vcpu *vcpu) {}
+
+static inline int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
+{
+	return 0;
+}
+
+static inline int vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
+				   struct kvm_exit_mmio *mmio)
+{
+	return KVM_EXIT_MMIO;
+}
+
+static inline int irqchip_in_kernel(struct kvm *kvm)
+{
+	return 0;
+}
+#endif
+
+#endif
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 8bb53cb..bdf0f86 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -177,6 +177,9 @@ int kvm_dev_ioctl_check_extension(long ext)
 {
 	int r;
 	switch (ext) {
+#ifdef CONFIG_KVM_ARM_VGIC
+	case KVM_CAP_IRQCHIP:
+#endif
 	case KVM_CAP_USER_MEMORY:
 	case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
 		r = 1;
@@ -289,6 +292,9 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 	if (ret < 0)
 		return ret;
 
+	/* Set up VGIC */
+	kvm_vgic_vcpu_init(vcpu);
+
 	return 0;
 }
 
@@ -343,6 +349,7 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
 {
 	return !!v->arch.irq_lines ||
+		kvm_vgic_vcpu_pending_irq(v) ||
 		!v->arch.wait_for_interrupts;
 }
 
@@ -578,6 +585,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 		update_vttbr(vcpu->kvm);
 
+		kvm_vgic_sync_to_cpu(vcpu);
+
 		/*
 		 * Make sure preemption is disabled while calling handle_exit
 		 * as exit handling touches CPU-specific resources, such as
@@ -626,6 +635,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		} else {
 			exit_reason = ret; /* 0 == KVM_EXIT_UNKNOWN */
 		}
+
+		kvm_vgic_sync_from_cpu(vcpu);
 	}
 
 	if (vcpu->sigset_active)
@@ -808,6 +819,13 @@ static int init_hyp_mode(void)
 	}
 
 	/*
+	 * Init HYP view of VGIC
+	 */
+	err = kvm_vgic_hyp_init();
+	if (err)
+		goto out_free_mappings;
+
+	/*
 	 * Set the HVBAR to the virtual kernel address
 	 */
 	for_each_online_cpu(cpu)
diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
index 564add2..4580c1f4 100644
--- a/arch/arm/kvm/emulate.c
+++ b/arch/arm/kvm/emulate.c
@@ -518,7 +518,7 @@ int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
 	trace_kvm_wfi(vcpu->arch.regs.pc);
 	vcpu->stat.wfi_exits++;
-	if (!vcpu->arch.irq_lines)
+	if (!vcpu->arch.irq_lines && !kvm_vgic_vcpu_pending_irq(vcpu))
 		vcpu->arch.wait_for_interrupts = 1;
 	return 0;
 }
diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S
index fd7331c..f3e4c3c 100644
--- a/arch/arm/kvm/interrupts.S
+++ b/arch/arm/kvm/interrupts.S
@@ -267,6 +267,20 @@ ENDPROC(__kvm_flush_vm_context)
 	mcr	p15, 0, r11, c10, c2, 1	@ NMRR
 .endm
 
+/*
+ * Save the VGIC CPU state into memory
+ * @vcpup: Register pointing to VCPU struct
+ */
+.macro save_vgic_state	vcpup
+.endm
+	
+/*
+ * Restore the VGIC CPU state from memory
+ * @vcpup: Register pointing to VCPU struct
+ */
+.macro restore_vgic_state	vcpup
+.endm
+	
 /* Configures the HSTR (Hyp System Trap Register) on entry/return
  * (hardware reset value is 0) */
 .macro set_hstr entry
@@ -324,6 +338,8 @@ ENTRY(__kvm_vcpu_run)
 	store_mode_state sp, irq
 	store_mode_state sp, fiq
 
+	restore_vgic_state r0
+
 	@ Store hardware CP15 state and load guest state
 	read_cp15_state
 	write_cp15_state 1, r0
@@ -412,6 +428,8 @@ __kvm_vcpu_return:
 	read_cp15_state 1, r1
 	write_cp15_state
 
+	save_vgic_state	r1
+
 	load_mode_state sp, fiq
 	load_mode_state sp, irq
 	load_mode_state sp, und
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index ca76be0..4955a51 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -598,6 +598,7 @@ static int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
 {
 	unsigned long rd, len, instr_len;
 	bool is_write, sign_extend;
+	struct kvm_exit_mmio mmio;
 
 	if (!(vcpu->arch.hsr & HSR_ISV))
 		return invalid_io_mem_abort(vcpu, fault_ipa);
@@ -654,6 +655,8 @@ static int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
 	if (is_write)
 		memcpy(run->mmio.data, vcpu_reg(vcpu, rd), len);
 
+	run->exit_reason = vgic_handle_mmio(vcpu, run);
+
 	/*
 	 * The MMIO instruction is emulated and should not be re-executed
 	 * in the guest.
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 1d33877..d19c0f0 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1756,12 +1756,13 @@ static long kvm_vcpu_ioctl(struct file *filp,
 	if (vcpu->kvm->mm != current->mm)
 		return -EIO;
 
-#if defined(CONFIG_S390) || defined(CONFIG_PPC)
+#if defined(CONFIG_S390) || defined(CONFIG_PPC) || defined(CONFIG_ARM)
 	/*
 	 * Special cases: vcpu ioctls that are asynchronous to vcpu execution,
 	 * so vcpu_load() would break it.
 	 */
-	if (ioctl == KVM_S390_INTERRUPT || ioctl == KVM_INTERRUPT)
+	if (ioctl == KVM_S390_INTERRUPT || ioctl == KVM_INTERRUPT ||
+	    ioctl == KVM_IRQ_LINE)
 		return kvm_arch_vcpu_ioctl(filp, ioctl, arg);
 #endif
 
-- 
1.7.10.3





[Index of Archives]     [Linux KVM]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux