@@ -2049,3 +2049,5 @@ source "security/Kconfig"
source "crypto/Kconfig"
source "lib/Kconfig"
+
+source "arch/arm/kvm/Kconfig"
@@ -258,6 +258,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/
new file mode 100644
@@ -0,0 +1,66 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __ARM_KVM_H__
+#define __ARM_KVM_H__
+
+#include <asm/types.h>
+
+/*
+ * Modes used for short-hand mode determinition in the world-switch code and
+ * in emulation code.
+ *
+ * Note: These indices do NOT correspond to the value of the CPSR mode bits!
+ */
+#define MODE_FIQ 0
+#define MODE_IRQ 1
+#define MODE_SVC 2
+#define MODE_ABT 3
+#define MODE_UND 4
+#define MODE_USR 5
+#define MODE_SYS 6
+
+struct kvm_regs {
+ __u32 regs0_7[8]; /* Unbanked regs. (r0 - r7) */
+ __u32 fiq_regs8_12[5]; /* Banked fiq regs. (r8 - r12) */
+ __u32 usr_regs8_12[5]; /* Banked usr registers (r8 - r12) */
+ __u32 reg13[6]; /* Banked r13, indexed by MODE_ */
+ __u32 reg14[6]; /* Banked r13, indexed by MODE_ */
+ __u32 reg15;
+ __u32 cpsr;
+ __u32 spsr[5]; /* Banked SPSR, indexed by MODE_ */
+ struct {
+ __u32 c1_sys;
+ __u32 c2_base0;
+ __u32 c2_base1;
+ __u32 c3_dacr;
+ } cp15;
+
+};
+
+struct kvm_sregs {
+};
+
+struct kvm_fpu {
+};
+
+struct kvm_guest_debug_arch {
+};
+
+struct kvm_debug_exit_arch {
+};
+
+#endif /* __ARM_KVM_H__ */
new file mode 100644
@@ -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__ */
new file mode 100644
@@ -0,0 +1,91 @@
+/*
+ * 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_EMULATE_H__
+#define __ARM_KVM_EMULATE_H__
+
+#include <linux/kvm_host.h>
+#include <asm/kvm_asm.h>
+
+u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
+
+static inline unsigned char vcpu_mode(struct kvm_vcpu *vcpu)
+{
+ u8 modes_table[16] = {
+ MODE_USR, /* 0x0 */
+ MODE_FIQ, /* 0x1 */
+ MODE_IRQ, /* 0x2 */
+ MODE_SVC, /* 0x3 */
+ 0xf, 0xf, 0xf,
+ MODE_ABT, /* 0x7 */
+ 0xf, 0xf, 0xf,
+ MODE_UND, /* 0xb */
+ 0xf, 0xf, 0xf,
+ MODE_SYS}; /* 0xf */
+
+ BUG_ON(modes_table[vcpu->arch.regs.cpsr & 0xf] == 0xf);
+ return modes_table[vcpu->arch.regs.cpsr & 0xf];
+}
+
+/*
+ * Return the SPSR for the specified mode of the virtual CPU.
+ */
+static inline u32 *kvm_vcpu_spsr(struct kvm_vcpu *vcpu, u32 mode)
+{
+ switch (mode) {
+ case MODE_SVC:
+ return &vcpu->arch.regs.svc_regs[2];
+ case MODE_ABT:
+ return &vcpu->arch.regs.svc_regs[2];
+ case MODE_UND:
+ return &vcpu->arch.regs.svc_regs[2];
+ case MODE_IRQ:
+ return &vcpu->arch.regs.svc_regs[2];
+ case MODE_FIQ:
+ return &vcpu->arch.regs.fiq_regs[7];
+ default:
+ BUG();
+ }
+}
+
+/* Get vcpu register for current mode */
+static inline u32 *vcpu_reg(struct kvm_vcpu *vcpu, unsigned long reg_num)
+{
+ return kvm_vcpu_reg(vcpu, reg_num, vcpu_mode(vcpu));
+}
+
+static inline u32 *vcpu_cpsr(struct kvm_vcpu *vcpu)
+{
+ return &vcpu->arch.regs.cpsr;
+}
+
+/* Get vcpu SPSR for current mode */
+static inline u32 *vcpu_spsr(struct kvm_vcpu *vcpu)
+{
+ return kvm_vcpu_spsr(vcpu, vcpu_mode(vcpu));
+}
+
+static inline bool mode_has_spsr(struct kvm_vcpu *vcpu)
+{
+ return (vcpu_mode(vcpu) < MODE_USR);
+}
+
+static inline bool vcpu_mode_priv(struct kvm_vcpu *vcpu)
+{
+ return ((vcpu_mode(vcpu)) == MODE_USR) ? 0 : 1;
+}
+
+#endif /* __ARM_KVM_EMULATE_H__ */
new file mode 100644
@@ -0,0 +1,93 @@
+/*
+ * 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_HOST_H__
+#define __ARM_KVM_HOST_H__
+
+#define KVM_MAX_VCPUS 1
+#define KVM_MEMORY_SLOTS 32
+#define KVM_PRIVATE_MEM_SLOTS 4
+#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
+
+/* We don't currently support large pages. */
+#define KVM_HPAGE_GFN_SHIFT(x) 0
+#define KVM_NR_PAGE_SIZES 1
+#define KVM_PAGES_PER_HPAGE(x) (1UL<<31)
+
+struct kvm_vcpu;
+u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
+
+struct kvm_arch {
+};
+
+#define EXCEPTION_NONE 0
+#define EXCEPTION_RESET 0x80
+#define EXCEPTION_UNDEFINED 0x40
+#define EXCEPTION_SOFTWARE 0x20
+#define EXCEPTION_PREFETCH 0x10
+#define EXCEPTION_DATA 0x08
+#define EXCEPTION_IMPRECISE 0x04
+#define EXCEPTION_IRQ 0x02
+#define EXCEPTION_FIQ 0x01
+
+struct kvm_vcpu_regs {
+ u32 usr_regs[15]; /* R0_usr - R14_usr */
+ u32 svc_regs[3]; /* SP_svc, LR_svc, SPSR_svc */
+ u32 abt_regs[3]; /* SP_abt, LR_abt, SPSR_abt */
+ u32 und_regs[3]; /* SP_und, LR_und, SPSR_und */
+ u32 irq_regs[3]; /* SP_irq, LR_irq, SPSR_irq */
+ u32 fiq_regs[8]; /* R8_fiq - R14_fiq, SPSR_fiq */
+ u32 pc; /* The program counter (r15) */
+ u32 cpsr; /* The guest CPSR */
+} __packed;
+
+struct kvm_vcpu_arch {
+ struct kvm_vcpu_regs regs;
+
+ /* System control coprocessor (cp15) */
+ struct {
+ u32 c1_SCTLR; /* System Control Register */
+ u32 c1_ACTLR; /* Auxilliary Control Register */
+ u32 c1_CPACR; /* Coprocessor Access Control */
+ u64 c2_TTBR0; /* Translation Table Base Register 0 */
+ u64 c2_TTBR1; /* Translation Table Base Register 1 */
+ u32 c2_TTBCR; /* Translation Table Base Control R. */
+ u32 c3_DACR; /* Domain Access Control Register */
+ } cp15;
+
+ u32 virt_irq; /* HCR exception mask */
+
+ /* Exception Information */
+ u32 hsr; /* Hyp Syndrom Register */
+ u32 hdfar; /* Hyp Data Fault Address Register */
+ u32 hifar; /* Hyp Inst. Fault Address Register */
+ u32 hpfar; /* Hyp IPA Fault Address Register */
+
+ /* IO related fields */
+ u32 mmio_rd;
+
+ /* Misc. fields */
+ u32 wait_for_interrupts;
+};
+
+struct kvm_vm_stat {
+ u32 remote_tlb_flush;
+};
+
+struct kvm_vcpu_stat {
+};
+
+#endif /* __ARM_KVM_HOST_H__ */
new file mode 100644
@@ -0,0 +1,9 @@
+#ifndef _ASM_X86_KVM_PARA_H
+#define _ASM_X86_KVM_PARA_H
+
+static inline unsigned int kvm_arch_para_features(void)
+{
+ return 0;
+}
+
+#endif /* _ASM_X86_KVM_PARA_H */
@@ -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
/*
new file mode 100644
@@ -0,0 +1,44 @@
+#
+# KVM configuration
+#
+
+source "virt/kvm/Kconfig"
+
+menuconfig VIRTUALIZATION
+ bool "Virtualization"
+ ---help---
+ Say Y here to get to see options for using your Linux host to run
+ other operating systems inside virtual machines (guests).
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and
+ disabled.
+
+if VIRTUALIZATION
+
+config KVM
+ tristate "Kernel-based Virtual Machine (KVM) support"
+ select PREEMPT_NOTIFIERS
+ select ANON_INODES
+ select KVM_ARM_HOST
+ select KVM_MMIO
+ ---help---
+ Support hosting virtualized guest machines. You will also
+ need to select one or more of the processor modules below.
+
+ This module provides access to the hardware capabilities through
+ a character device node named /dev/kvm.
+
+ If unsure, say N.
+
+config KVM_ARM_HOST
+ bool "KVM host support for ARM cpus."
+ depends on KVM
+ depends on MMU
+ depends on CPU_V7 || ARM_VIRT_EXT
+ ---help---
+ Provides host support for ARM processors.
+
+source drivers/virtio/Kconfig
+
+endif # VIRTUALIZATION
new file mode 100644
@@ -0,0 +1,18 @@
+#
+# Makefile for Kernel-based Virtual Machine module
+#
+
+ccflags-y += -Ivirt/kvm -Iarch/arm/kvm
+CFLAGS_arm.o := -I.
+CFLAGS_arm_mmu.o := -I.
+
+EXTRA_CFLAGS += -Ivirt/kvm -Iarch/arm/kvm
+AFLAGS_arm_interrupts.o := -I$(obj)
+
+obj-$(CONFIG_KVM_ARM_HOST) += arm_init.o arm_interrupts.o arm_exports.o
+
+kvm-arm-y += $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o)
+
+kvm-arm-y += arm.o arm_guest.o arm_mmu.o arm_emulate.o debug.o
+
+obj-$(CONFIG_KVM) += kvm-arm.o
new file mode 100644
@@ -0,0 +1,272 @@
+/*
+ * 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/errno.h>
+#include <linux/err.h>
+#include <linux/kvm_host.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/mman.h>
+#include <linux/sched.h>
+#include <trace/events/kvm.h>
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+#include <asm/unified.h>
+#include <asm/uaccess.h>
+#include <asm/ptrace.h>
+#include <asm/mman.h>
+
+#include "debug.h"
+
+int kvm_arch_hardware_enable(void *garbage)
+{
+ return 0;
+}
+
+void kvm_arch_hardware_disable(void *garbage)
+{
+}
+
+int kvm_arch_hardware_setup(void)
+{
+ return 0;
+}
+
+void kvm_arch_hardware_unsetup(void)
+{
+}
+
+void kvm_arch_check_processor_compat(void *rtn)
+{
+ *(int *)rtn = 0;
+}
+
+void kvm_arch_sync_events(struct kvm *kvm)
+{
+}
+
+int kvm_arch_init_vm(struct kvm *kvm)
+{
+ return 0;
+}
+
+void kvm_arch_destroy_vm(struct kvm *kvm)
+{
+ int i;
+
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ if (kvm->vcpus[i]) {
+ kvm_arch_vcpu_free(kvm->vcpus[i]);
+ kvm->vcpus[i] = NULL;
+ }
+ }
+}
+
+int kvm_dev_ioctl_check_extension(long ext)
+{
+ int r;
+ switch (ext) {
+ case KVM_CAP_USER_MEMORY:
+ case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
+ r = 1;
+ break;
+ case KVM_CAP_COALESCED_MMIO:
+ r = KVM_COALESCED_MMIO_PAGE_OFFSET;
+ break;
+ default:
+ r = 0;
+ break;
+ }
+ return r;
+}
+
+long kvm_arch_dev_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ int ret = 0;
+
+ switch (ioctl) {
+ default:
+ ret = -EINVAL;
+ }
+
+ if (ret < 0)
+ printk(KERN_ERR "error processing ARM ioct: %d", ret);
+ return ret;
+}
+
+int kvm_arch_set_memory_region(struct kvm *kvm,
+ struct kvm_userspace_memory_region *mem,
+ struct kvm_memory_slot old,
+ int user_alloc)
+{
+ return 0;
+}
+
+int kvm_arch_prepare_memory_region(struct kvm *kvm,
+ struct kvm_memory_slot *memslot,
+ struct kvm_memory_slot old,
+ struct kvm_userspace_memory_region *mem,
+ int user_alloc)
+{
+ return 0;
+}
+
+void kvm_arch_commit_memory_region(struct kvm *kvm,
+ struct kvm_userspace_memory_region *mem,
+ struct kvm_memory_slot old,
+ int user_alloc)
+{
+}
+
+void kvm_arch_flush_shadow(struct kvm *kvm)
+{
+}
+
+struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
+{
+ int err;
+ struct kvm_vcpu *vcpu;
+
+ vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
+ if (!vcpu) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = kvm_vcpu_init(vcpu, kvm, id);
+ if (err)
+ goto free_vcpu;
+
+ latest_vcpu = vcpu;
+ return vcpu;
+free_vcpu:
+ kmem_cache_free(kvm_vcpu_cache, vcpu);
+out:
+ return ERR_PTR(err);
+}
+
+void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
+{
+ latest_vcpu = NULL;
+ KVMARM_NOT_IMPLEMENTED();
+}
+
+void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
+{
+ kvm_arch_vcpu_free(vcpu);
+}
+
+int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
+{
+ return 0;
+}
+
+int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
+{
+ KVMARM_NOT_IMPLEMENTED();
+ return 0;
+}
+
+void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+}
+
+void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
+{
+}
+
+void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
+{
+}
+
+int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
+ struct kvm_guest_debug *dbg)
+{
+ return -EINVAL;
+}
+
+
+int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
+ struct kvm_mp_state *mp_state)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
+ struct kvm_mp_state *mp_state)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
+{
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ KVMARM_NOT_IMPLEMENTED();
+ return -EINVAL;
+}
+
+long kvm_arch_vcpu_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ kvm_err(-EINVAL, "Unsupported ioctl (%d)", ioctl);
+ return -EINVAL;
+}
+
+int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
+{
+ return -EINVAL;
+}
+
+long kvm_arch_vm_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ printk(KERN_ERR "kvm_arch_vm_ioctl: Unsupported ioctl (%d)\n", ioctl);
+ return -EINVAL;
+}
+
+int kvm_arch_init(void *opaque)
+{
+ return 0;
+}
+
+void kvm_arch_exit(void)
+{
+}
+
+static int arm_init(void)
+{
+ int rc = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE);
+ if (rc == 0)
+ kvm_arm_debugfs_init();
+ return rc;
+}
+
+static void __exit arm_exit(void)
+{
+ kvm_exit();
+ kvm_arm_debugfs_exit();
+}
+
+module_init(arm_init);
+module_exit(arm_exit)
new file mode 100644
@@ -0,0 +1,121 @@
+/*
+ * 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/kvm_emulate.h>
+
+#define USR_REG_OFFSET(_reg) \
+ offsetof(struct kvm_vcpu_arch, regs.usr_regs[_reg])
+
+static unsigned long vcpu_reg_offsets[MODE_SYS + 1][16] = {
+ /* FIQ Registers */
+ {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7),
+ offsetof(struct kvm_vcpu_arch, regs.fiq_regs[1]), /* r8 */
+ offsetof(struct kvm_vcpu_arch, regs.fiq_regs[1]), /* r9 */
+ offsetof(struct kvm_vcpu_arch, regs.fiq_regs[2]), /* r10 */
+ offsetof(struct kvm_vcpu_arch, regs.fiq_regs[3]), /* r11 */
+ offsetof(struct kvm_vcpu_arch, regs.fiq_regs[4]), /* r12 */
+ offsetof(struct kvm_vcpu_arch, regs.fiq_regs[5]), /* r13 */
+ offsetof(struct kvm_vcpu_arch, regs.fiq_regs[6]), /* r14 */
+ offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */
+ },
+
+ /* IRQ Registers */
+ {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+ USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+ USR_REG_OFFSET(12),
+ offsetof(struct kvm_vcpu_arch, regs.irq_regs[0]), /* r13 */
+ offsetof(struct kvm_vcpu_arch, regs.irq_regs[1]), /* r14 */
+ offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */
+ },
+
+ /* SVC Registers */
+ {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+ USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+ USR_REG_OFFSET(12),
+ offsetof(struct kvm_vcpu_arch, regs.svc_regs[0]), /* r13 */
+ offsetof(struct kvm_vcpu_arch, regs.svc_regs[1]), /* r14 */
+ offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */
+ },
+
+ /* ABT Registers */
+ {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+ USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+ USR_REG_OFFSET(12),
+ offsetof(struct kvm_vcpu_arch, regs.abt_regs[0]), /* r13 */
+ offsetof(struct kvm_vcpu_arch, regs.abt_regs[1]), /* r14 */
+ offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */
+ },
+
+ /* UND Registers */
+ {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+ USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+ USR_REG_OFFSET(12),
+ offsetof(struct kvm_vcpu_arch, regs.und_regs[0]), /* r13 */
+ offsetof(struct kvm_vcpu_arch, regs.und_regs[1]), /* r14 */
+ offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */
+ },
+
+ /* USR Registers */
+ {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+ USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+ USR_REG_OFFSET(12),
+ offsetof(struct kvm_vcpu_arch, regs.usr_regs[13]), /* r13 */
+ offsetof(struct kvm_vcpu_arch, regs.usr_regs[14]), /* r14 */
+ offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */
+ },
+
+ /* SYS Registers */
+ {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+ USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+ USR_REG_OFFSET(12),
+ offsetof(struct kvm_vcpu_arch, regs.usr_regs[13]), /* r13 */
+ offsetof(struct kvm_vcpu_arch, regs.usr_regs[14]), /* r14 */
+ offsetof(struct kvm_vcpu_arch, regs.pc) /* r15 */
+ },
+};
+
+/*
+ * Return a pointer to the register number valid in the specified mode of
+ * the virtual CPU.
+ */
+u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode)
+{
+ BUG_ON(reg_num > 15);
+ BUG_ON(mode > MODE_SYS);
+
+ return (u32 *)((void *)&vcpu->arch + vcpu_reg_offsets[mode][reg_num]);
+}
new file mode 100644
@@ -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>
new file mode 100644
@@ -0,0 +1,148 @@
+/*
+ * 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/errno.h>
+#include <linux/err.h>
+#include <linux/kvm_host.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_emulate.h>
+
+
+#define VM_STAT(x) (offsetof(struct kvm, stat.x), KVM_STAT_VM)
+#define VCPU_STAT(x) (offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU)
+
+struct kvm_stats_debugfs_item debugfs_entries[] = {
+ { NULL }
+};
+
+int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
+{
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+ struct kvm_vcpu_regs *vcpu_regs = &vcpu->arch.regs;
+
+ /*
+ * GPRs and PSRs
+ */
+ memcpy(regs->regs0_7, &(vcpu_regs->usr_regs[0]), sizeof(u32) * 8);
+ memcpy(regs->usr_regs8_12, &(vcpu_regs->usr_regs[8]), sizeof(u32) * 5);
+ memcpy(regs->fiq_regs8_12, &(vcpu_regs->fiq_regs[0]), sizeof(u32) * 5);
+ regs->reg13[MODE_FIQ] = vcpu_regs->fiq_regs[5];
+ regs->reg14[MODE_FIQ] = vcpu_regs->fiq_regs[6];
+ regs->reg13[MODE_IRQ] = vcpu_regs->irq_regs[0];
+ regs->reg14[MODE_IRQ] = vcpu_regs->irq_regs[1];
+ regs->reg13[MODE_SVC] = vcpu_regs->svc_regs[0];
+ regs->reg14[MODE_SVC] = vcpu_regs->svc_regs[1];
+ regs->reg13[MODE_ABT] = vcpu_regs->abt_regs[0];
+ regs->reg14[MODE_ABT] = vcpu_regs->abt_regs[1];
+ regs->reg13[MODE_UND] = vcpu_regs->und_regs[0];
+ regs->reg14[MODE_UND] = vcpu_regs->und_regs[1];
+ regs->reg13[MODE_USR] = vcpu_regs->usr_regs[0];
+ regs->reg14[MODE_USR] = vcpu_regs->usr_regs[1];
+
+ regs->spsr[MODE_FIQ] = vcpu_regs->fiq_regs[7];
+ regs->spsr[MODE_IRQ] = vcpu_regs->irq_regs[2];
+ regs->spsr[MODE_SVC] = vcpu_regs->svc_regs[2];
+ regs->spsr[MODE_ABT] = vcpu_regs->abt_regs[2];
+ regs->spsr[MODE_UND] = vcpu_regs->und_regs[2];
+
+ regs->reg15 = vcpu_regs->pc;
+ regs->cpsr = vcpu_regs->cpsr;
+
+
+ /*
+ * Co-processor registers.
+ */
+ regs->cp15.c1_sys = vcpu->arch.cp15.c1_SCTLR;
+ regs->cp15.c2_base0 = vcpu->arch.cp15.c2_TTBR0;
+ regs->cp15.c2_base1 = vcpu->arch.cp15.c2_TTBR1;
+ regs->cp15.c3_dacr = vcpu->arch.cp15.c3_DACR;
+
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+ struct kvm_vcpu_regs *vcpu_regs = &vcpu->arch.regs;
+
+ 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);
+ memcpy(&(vcpu_regs->fiq_regs[0]), regs->fiq_regs8_12, sizeof(u32) * 5);
+
+ vcpu_regs->fiq_regs[5] = regs->reg13[MODE_FIQ];
+ vcpu_regs->fiq_regs[6] = regs->reg14[MODE_FIQ];
+ vcpu_regs->irq_regs[0] = regs->reg13[MODE_IRQ];
+ vcpu_regs->irq_regs[1] = regs->reg14[MODE_IRQ];
+ vcpu_regs->svc_regs[0] = regs->reg13[MODE_SVC];
+ vcpu_regs->svc_regs[1] = regs->reg14[MODE_SVC];
+ vcpu_regs->abt_regs[0] = regs->reg13[MODE_ABT];
+ vcpu_regs->abt_regs[1] = regs->reg14[MODE_ABT];
+ vcpu_regs->und_regs[0] = regs->reg13[MODE_UND];
+ vcpu_regs->und_regs[1] = regs->reg14[MODE_UND];
+ vcpu_regs->usr_regs[0] = regs->reg13[MODE_USR];
+ vcpu_regs->usr_regs[1] = regs->reg14[MODE_USR];
+
+ vcpu_regs->fiq_regs[7] = regs->spsr[MODE_FIQ];
+ vcpu_regs->irq_regs[2] = regs->spsr[MODE_IRQ];
+ vcpu_regs->svc_regs[2] = regs->spsr[MODE_SVC];
+ vcpu_regs->abt_regs[2] = regs->spsr[MODE_ABT];
+ vcpu_regs->und_regs[2] = regs->spsr[MODE_UND];
+
+ /*
+ * Co-processor registers.
+ */
+ vcpu->arch.cp15.c1_SCTLR = regs->cp15.c1_sys;
+
+ vcpu_regs->pc = regs->reg15;
+ vcpu_regs->cpsr = regs->cpsr;
+
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
+ struct kvm_translation *tr)
+{
+ return -EINVAL;
+}
new file mode 100644
@@ -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>
new file mode 100644
@@ -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>
new file mode 100644
@@ -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.
+ *
+ */
new file mode 100644
@@ -0,0 +1,377 @@
+/*
+ * 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>
+#include <linux/types.h>
+#include <linux/kvm_types.h>
+#include <linux/kvm_host.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <asm/kvm_emulate.h>
+
+#include "debug.h"
+
+static struct dentry *vcpu_debugfs_file;
+static struct dentry *ws_debugfs_file;
+
+/******************************************************************************
+ * World-switch ring-buffer
+ */
+
+#define WS_TRACE_ITEMS 10
+static u32 ws_trace_enter[WS_TRACE_ITEMS];
+static int ws_trace_enter_index;
+static u32 ws_trace_exit[WS_TRACE_ITEMS];
+static int ws_trace_exit_index;
+DEFINE_MUTEX(ws_trace_mutex);
+
+void debug_ws_enter(u32 guest_pc)
+{
+ mutex_lock(&ws_trace_mutex);
+ ws_trace_enter[ws_trace_enter_index++] = guest_pc;
+ if (ws_trace_enter_index >= WS_TRACE_ITEMS)
+ ws_trace_enter_index = 0;
+ mutex_unlock(&ws_trace_mutex);
+}
+
+void debug_ws_exit(u32 guest_pc)
+{
+ mutex_lock(&ws_trace_mutex);
+ ws_trace_exit[ws_trace_exit_index++] = guest_pc;
+ if (ws_trace_exit_index >= WS_TRACE_ITEMS)
+ ws_trace_exit_index = 0;
+ mutex_unlock(&ws_trace_mutex);
+}
+
+void print_ws_trace(void)
+{
+ int i;
+ mutex_lock(&ws_trace_mutex);
+
+ if (ws_trace_enter_index != ws_trace_exit_index) {
+ kvm_msg("enter and exit WS trace count differ");
+ mutex_unlock(&ws_trace_mutex);
+ return;
+ }
+
+ /* Avoid potential endless loop */
+ if (ws_trace_enter_index < 0 ||
+ ws_trace_enter_index >= WS_TRACE_ITEMS) {
+ kvm_msg("ws_trace_enter_index out of bounds: %d",
+ ws_trace_enter_index);
+ mutex_unlock(&ws_trace_mutex);
+ return;
+ }
+
+ for (i = ws_trace_enter_index - 1; i != ws_trace_enter_index; i--) {
+ if (i < 0) {
+ i = WS_TRACE_ITEMS;
+ continue;
+ }
+
+ printk(KERN_ERR "Enter: %08x Exit: %08x\n",
+ ws_trace_enter[i],
+ ws_trace_exit[i]);
+ }
+ mutex_unlock(&ws_trace_mutex);
+}
+
+/******************************************************************************
+ * Dump total debug info, or write to debugfs entry
+ */
+
+struct kvm_vcpu *latest_vcpu;
+
+void print_kvm_vcpu_info(int (*print_fn)(print_fn_args), struct seq_file *m)
+{
+ int i;
+ struct kvm_vcpu_regs *regs;
+ char *mode = NULL;
+ struct kvm_vcpu *vcpu = latest_vcpu;
+
+ print_fn(m, "KVM/ARM runtime info\n");
+ print_fn(m, "======================================================");
+ print_fn(m, "\n\n");
+
+ if (vcpu == NULL) {
+ print_fn(m, "No registered VCPU\n");
+ goto out;
+ }
+
+ switch (vcpu_mode(vcpu)) {
+ case MODE_USR:
+ mode = "USR";
+ break;
+ case MODE_FIQ:
+ mode = "FIQ";
+ break;
+ case MODE_IRQ:
+ mode = "IRQ";
+ break;
+ case MODE_SVC:
+ mode = "SVC";
+ break;
+ case MODE_ABT:
+ mode = "ABT";
+ break;
+ case MODE_UND:
+ mode = "UND";
+ break;
+ case MODE_SYS:
+ mode = "SYS";
+ break;
+ }
+
+ vcpu_load(vcpu);
+ regs = &vcpu->arch.regs;
+
+ print_fn(m, "Virtual CPU state:\n\n");
+ print_fn(m, "PC is at: \t%08x\n", vcpu_reg(vcpu, 15));
+ print_fn(m, "CPSR: \t%08x\n(Mode: %s) (IRQs: %s) (FIQs: %s) "
+ " (Vec: %s)\n",
+ regs->cpsr, mode,
+ (regs->cpsr & PSR_I_BIT) ? "off" : "on",
+ (regs->cpsr & PSR_F_BIT) ? "off" : "on",
+ (regs->cpsr & PSR_V_BIT) ? "high" : "low");
+
+ for (i = 0; i <= 12; i++) {
+ if ((i % 4) == 0)
+ print_fn(m, "\nregs[%u]: ", i);
+
+ print_fn(m, "\t0x%08x", *kvm_vcpu_reg(vcpu, i, MODE_USR));
+ }
+
+ print_fn(m, "\n\n");
+ print_fn(m, "Banked registers: \tr13\t\tr14\t\tspsr\n");
+ print_fn(m, "-------------------\t--------\t--------\t--------\n");
+ print_fn(m, " USR: \t%08x\t%08x\t////////\n",
+ *kvm_vcpu_reg(vcpu, 13, MODE_USR),
+ *kvm_vcpu_reg(vcpu, 14, MODE_USR));
+ print_fn(m, " SVC: \t%08x\t%08x\t%08x\n",
+ *kvm_vcpu_reg(vcpu, 13, MODE_SVC),
+ *kvm_vcpu_reg(vcpu, 14, MODE_SVC),
+ *kvm_vcpu_spsr(vcpu, MODE_SVC));
+ print_fn(m, " ABT: \t%08x\t%08x\t%08x\n",
+ *kvm_vcpu_reg(vcpu, 13, MODE_ABT),
+ *kvm_vcpu_reg(vcpu, 14, MODE_ABT),
+ *kvm_vcpu_spsr(vcpu, MODE_ABT));
+ print_fn(m, " UND: \t%08x\t%08x\t%08x\n",
+ *kvm_vcpu_reg(vcpu, 13, MODE_UND),
+ *kvm_vcpu_reg(vcpu, 14, MODE_UND),
+ *kvm_vcpu_spsr(vcpu, MODE_UND));
+ print_fn(m, " IRQ: \t%08x\t%08x\t%08x\n",
+ *kvm_vcpu_reg(vcpu, 13, MODE_IRQ),
+ *kvm_vcpu_reg(vcpu, 14, MODE_IRQ),
+ *kvm_vcpu_spsr(vcpu, MODE_IRQ));
+ print_fn(m, " FIQ: \t%08x\t%08x\t%08x\n",
+ *kvm_vcpu_reg(vcpu, 13, MODE_FIQ),
+ *kvm_vcpu_reg(vcpu, 14, MODE_FIQ),
+ *kvm_vcpu_spsr(vcpu, MODE_FIQ));
+
+ print_fn(m, "\n");
+ print_fn(m, "fiq regs:\t%08x\t%08x\t%08x\t%08x\n"
+ " \t%08x\n",
+ *kvm_vcpu_reg(vcpu, 8, MODE_FIQ),
+ *kvm_vcpu_reg(vcpu, 9, MODE_FIQ),
+ *kvm_vcpu_reg(vcpu, 10, MODE_FIQ),
+ *kvm_vcpu_reg(vcpu, 11, MODE_FIQ),
+ *kvm_vcpu_reg(vcpu, 12, MODE_FIQ));
+
+out:
+ if (vcpu != NULL)
+ vcpu_put(vcpu);
+}
+
+void print_kvm_ws_info(int (*print_fn)(print_fn_args), struct seq_file *m)
+{
+ int i;
+
+ /*
+ * Print world-switch trace circular buffer
+ */
+ print_fn(m, "World switch history:\n");
+ print_fn(m, "---------------------\n");
+ mutex_lock(&ws_trace_mutex);
+
+ if (ws_trace_enter_index != ws_trace_exit_index ||
+ ws_trace_enter_index < 0 ||
+ ws_trace_enter_index >= WS_TRACE_ITEMS) {
+ mutex_unlock(&ws_trace_mutex);
+ return;
+ }
+
+ for (i = ws_trace_enter_index - 1; i != ws_trace_enter_index; i--) {
+ if (i < 0) {
+ i = WS_TRACE_ITEMS;
+ continue;
+ }
+
+ print_fn(m, "Enter: %08x Exit: %08x\n",
+ ws_trace_enter[i], ws_trace_exit[i]);
+ }
+ mutex_unlock(&ws_trace_mutex);
+}
+
+static int __printk_relay(struct seq_file *m, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vprintk(fmt, ap);
+ va_end(ap);
+ return 0;
+}
+
+void kvm_dump_vcpu_state(void)
+{
+ print_kvm_vcpu_info(&__printk_relay, NULL);
+}
+
+void kvm_arm_trace_init(void)
+{
+
+}
+
+/******************************************************************************
+ * debugfs handling
+ */
+
+static int vcpu_debugfs_show(struct seq_file *m, void *v)
+{
+ print_kvm_vcpu_info(&seq_printf, m);
+ return 0;
+}
+
+static int ws_debugfs_show(struct seq_file *m, void *v)
+{
+ print_kvm_ws_info(&seq_printf, m);
+ return 0;
+}
+
+static void *k_start(struct seq_file *m, loff_t *pos)
+{
+ return *pos < 1 ? (void *)1 : NULL;
+}
+
+static void *k_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ ++*pos;
+ return NULL;
+}
+
+static void k_stop(struct seq_file *m, void *v)
+{
+}
+
+static const struct seq_operations vcpu_debugfs_op = {
+ .start = k_start,
+ .next = k_next,
+ .stop = k_stop,
+ .show = vcpu_debugfs_show
+};
+
+static const struct seq_operations ws_debugfs_op = {
+ .start = k_start,
+ .next = k_next,
+ .stop = k_stop,
+ .show = ws_debugfs_show
+};
+
+static int vcpu_debugfs_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &vcpu_debugfs_op);
+}
+
+static int ws_debugfs_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &ws_debugfs_op);
+}
+
+static const struct file_operations vcpu_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = vcpu_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static const struct file_operations ws_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = ws_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/**
+ * kvm_arm_debugfs_init - create debugfs directory and files
+ *
+ * Create the debugfs entries for KVM/ARM
+ */
+void kvm_arm_debugfs_init(void)
+{
+ struct dentry *file;
+
+ file = debugfs_create_file("vcpu", 0444, kvm_debugfs_dir,
+ NULL, &vcpu_debugfs_fops);
+ if (IS_ERR(file) || !file) {
+ kvm_err(PTR_ERR(file),
+ "cannot create debugfs KVM/ARM vcpu file\n");
+ return;
+ }
+ vcpu_debugfs_file = file;
+
+ file = debugfs_create_file("ws", 0444, kvm_debugfs_dir,
+ NULL, &ws_debugfs_fops);
+ if (IS_ERR(file) || !file) {
+ kvm_err(PTR_ERR(file),
+ "cannot create debugfs KVM/ARM ws file\n");
+ }
+ ws_debugfs_file = file;
+}
+
+void kvm_arm_debugfs_exit(void)
+{
+ if (vcpu_debugfs_file)
+ debugfs_remove(vcpu_debugfs_file);
+ if (ws_debugfs_file)
+ debugfs_remove(ws_debugfs_file);
+}
+
+
+/******************************************************************************
+ * Printk-log-wrapping functionality
+ */
+
+#define TMP_LOG_LEN 512
+static char __tmp_log_data[TMP_LOG_LEN];
+DEFINE_MUTEX(__tmp_log_lock);
+void __kvm_print_msg(char *fmt, ...)
+{
+ va_list ap;
+ unsigned int size;
+
+ mutex_lock(&__tmp_log_lock);
+
+ va_start(ap, fmt);
+ size = vsnprintf(__tmp_log_data, TMP_LOG_LEN, fmt, ap);
+ va_end(ap);
+
+ if (size >= TMP_LOG_LEN)
+ printk(KERN_ERR "Message exceeded log length!\n");
+ else
+ printk(KERN_INFO "%s", __tmp_log_data);
+
+ mutex_unlock(&__tmp_log_lock);
+}
new file mode 100644
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ *
+ *
+ * This file contains debugging and tracing functions and definitions
+ * for KVM/ARM.
+ */
+#ifndef __ARM_KVM_TRACE_H__
+#define __ARM_KVM_TRACE_H__
+
+#include <linux/types.h>
+#include <linux/kvm_types.h>
+#include <linux/kvm_host.h>
+
+extern struct kvm_vcpu *latest_vcpu;
+
+void kvm_dump_vcpu_state(void);
+
+void debug_ws_enter(u32 guest_pc);
+void debug_ws_exit(u32 guest_pc);
+
+#define print_fn_args struct seq_file *, const char *, ...
+void print_kvm_debug_info(int (*print_fn)(print_fn_args), struct seq_file *m);
+
+void __kvm_print_msg(char *_fmt, ...);
+
+#define kvm_err(err, fmt, args...) do { \
+ __kvm_print_msg(KERN_ERR "KVM error [%s:%d]: (%d) ", \
+ __func__, __LINE__, err); \
+ __kvm_print_msg(fmt "\n", ##args); \
+} while (0)
+
+#define __kvm_msg(fmt, args...) do { \
+ __kvm_print_msg(KERN_ERR "KVM [%s:%d]: ", __func__, __LINE__); \
+ __kvm_print_msg(fmt, ##args); \
+} while (0)
+
+#define kvm_msg(__fmt, __args...) __kvm_msg(__fmt "\n", ##__args)
+
+
+#define KVMARM_NOT_IMPLEMENTED() \
+{ \
+ printk(KERN_ERR "KVM not implemented [%s:%d] in %s\n", \
+ __FILE__, __LINE__, __func__); \
+}
+
+void print_ws_trace(void);
+
+void kvm_arm_debugfs_init(void);
+void kvm_arm_debugfs_exit(void);
+
+#endif /* __ARM_KVM_TRACE_H__ */
new file mode 100644
@@ -0,0 +1,52 @@
+#if !defined(_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_KVM_H
+
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kvm
+
+/*
+ * Tracepoints for entry/exit to guest
+ */
+TRACE_EVENT(kvm_entry,
+ 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("PC: 0x%08lx", __entry->vcpu_pc)
+);
+
+TRACE_EVENT(kvm_exit,
+ 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("PC: 0x%08lx", __entry->vcpu_pc)
+);
+
+
+
+#endif /* _TRACE_KVM_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH arch/arm/kvm
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
@@ -36,6 +36,7 @@ config ARCH_VEXPRESS_CA15X4
bool "Versatile Express Cortex-A15x4 tile"
depends on VEXPRESS_EXTENDED_MEMORY_MAP
select CPU_V7
+ select ARM_VIRT_EXT
select ARM_GIC
select HAVE_ARCH_TIMERS
@@ -636,6 +636,13 @@ config ARM_LPAE
Say Y if you have an ARMv7 processor supporting the LPAE page table
format and you would like to access memory beyond the 4GB limit.
+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.
+
config ARCH_PHYS_ADDR_T_64BIT
def_bool ARM_LPAE
Targets KVM support for Cortex A-15 processors. Contains no real functionality but all the framework components, make files, header files and some tracing functionality. Most functionality is in arch/arm/kvm/* or arch/arm/include/asm/kvm_*.h. Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com> --- arch/arm/Kconfig | 2 arch/arm/Makefile | 1 arch/arm/include/asm/kvm.h | 66 ++++++ arch/arm/include/asm/kvm_asm.h | 28 +++ arch/arm/include/asm/kvm_emulate.h | 91 +++++++++ arch/arm/include/asm/kvm_host.h | 93 +++++++++ arch/arm/include/asm/kvm_para.h | 9 + arch/arm/include/asm/unified.h | 12 + arch/arm/kvm/Kconfig | 44 ++++ arch/arm/kvm/Makefile | 18 ++ arch/arm/kvm/arm.c | 272 ++++++++++++++++++++++++++ arch/arm/kvm/arm_emulate.c | 121 ++++++++++++ arch/arm/kvm/arm_exports.c | 16 ++ arch/arm/kvm/arm_guest.c | 148 ++++++++++++++ arch/arm/kvm/arm_init.S | 17 ++ arch/arm/kvm/arm_interrupts.S | 17 ++ arch/arm/kvm/arm_mmu.c | 15 + arch/arm/kvm/debug.c | 377 ++++++++++++++++++++++++++++++++++++ arch/arm/kvm/debug.h | 63 ++++++ arch/arm/kvm/trace.h | 52 +++++ arch/arm/mach-vexpress/Kconfig | 1 arch/arm/mm/Kconfig | 7 + 22 files changed, 1470 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/arm_emulate.c create mode 100644 arch/arm/kvm/arm_exports.c create mode 100644 arch/arm/kvm/arm_guest.c create mode 100644 arch/arm/kvm/arm_init.S create mode 100644 arch/arm/kvm/arm_interrupts.S create mode 100644 arch/arm/kvm/arm_mmu.c create mode 100644 arch/arm/kvm/debug.c create mode 100644 arch/arm/kvm/debug.h create mode 100644 arch/arm/kvm/trace.h -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html