diff mbox

KVM: arm/arm64: Route vtimer events to user space

Message ID 1473981320-25387-1-git-send-email-agraf@suse.de (mailing list archive)
State New, archived
Headers show

Commit Message

Alexander Graf Sept. 15, 2016, 11:15 p.m. UTC
We have 2 modes for dealing with interrupts in the ARM world. We can either
handle them all using hardware acceleration through the vgic or we can emulate
a gic in user space and only drive CPU IRQ pins from there.

Unfortunately, when driving IRQs from user space, we never tell user space
about timer events that may result in interrupt line state changes, so we
lose out on timer events if we run with user space gic emulation.

This patch set fixes that by routing vtimer expiration events to user space.
With this patch I can successfully run edk2 and Linux with user space gic
emulation.

Signed-off-by: Alexander Graf <agraf@suse.de>

---

A branch with WIP QEMU code can be found here:

  https://github.com/agraf/qemu.git no-kvm-irqchip
---
 Documentation/virtual/kvm/api.txt |  28 ++++++++-
 arch/arm/include/asm/kvm_host.h   |   3 +
 arch/arm/kvm/arm.c                |  46 +++++++++++---
 arch/arm64/include/asm/kvm_host.h |   3 +
 include/uapi/linux/kvm.h          |  14 +++++
 virt/kvm/arm/arch_timer.c         | 126 ++++++++++++++++++++++++++++----------
 6 files changed, 177 insertions(+), 43 deletions(-)

Comments

kernel test robot Sept. 16, 2016, 8:42 a.m. UTC | #1
Hi Alexander,

[auto build test ERROR on kvm/linux-next]
[also build test ERROR on v4.8-rc6 next-20160916]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Alexander-Graf/KVM-arm-arm64-Route-vtimer-events-to-user-space/20160916-073838
base:   https://git.kernel.org/pub/scm/virt/kvm/kvm.git linux-next
config: arm64-allmodconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 5.4.0-6) 5.4.0 20160609
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm64 

All error/warnings (new ones prefixed by >>):

   arch/arm64/kvm/../../../arch/arm/kvm/arm.c: In function 'kvm_arch_vcpu_ioctl':
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1000:1: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
    int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
    ^
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1016:12: error: invalid storage class for function 'kvm_vm_ioctl_set_device_addr'
    static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
               ^
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1077:13: error: invalid storage class for function 'cpu_init_hyp_mode'
    static void cpu_init_hyp_mode(void *dummy)
                ^
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1098:13: error: invalid storage class for function 'cpu_hyp_reinit'
    static void cpu_hyp_reinit(void)
                ^
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1112:13: error: invalid storage class for function 'cpu_hyp_reset'
    static void cpu_hyp_reset(void)
                ^
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1119:13: error: invalid storage class for function '_kvm_arch_hardware_enable'
    static void _kvm_arch_hardware_enable(void *discard)
                ^
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1133:13: error: invalid storage class for function '_kvm_arch_hardware_disable'
    static void _kvm_arch_hardware_disable(void *discard)
                ^
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1147:12: error: invalid storage class for function 'hyp_init_cpu_pm_notifier'
    static int hyp_init_cpu_pm_notifier(struct notifier_block *self,
               ^
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1180:19: error: initializer element is not constant
     .notifier_call = hyp_init_cpu_pm_notifier,
                      ^
   arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1180:19: note: (near initialization for 'hyp_init_cpu_pm_nb.notifier_call')
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1183:20: error: invalid storage class for function 'hyp_cpu_pm_init'
    static void __init hyp_cpu_pm_init(void)
                       ^
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1187:20: error: invalid storage class for function 'hyp_cpu_pm_exit'
    static void __init hyp_cpu_pm_exit(void)
                       ^
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1200:13: error: invalid storage class for function 'teardown_common_resources'
    static void teardown_common_resources(void)
                ^
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1205:12: error: invalid storage class for function 'init_common_resources'
    static int init_common_resources(void)
               ^
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1216:12: error: invalid storage class for function 'init_subsystems'
    static int init_subsystems(void)
               ^
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1263:13: error: invalid storage class for function 'teardown_hyp_mode'
    static void teardown_hyp_mode(void)
                ^
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1276:12: error: invalid storage class for function 'init_vhe_mode'
    static int init_vhe_mode(void)
               ^
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1289:12: error: invalid storage class for function 'init_hyp_mode'
    static int init_hyp_mode(void)
               ^
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1379:13: error: invalid storage class for function 'check_kvm_target_cpu'
    static void check_kvm_target_cpu(void *ret)
                ^
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1448:12: error: invalid storage class for function 'arm_init'
    static int arm_init(void)
               ^
   In file included from include/linux/printk.h:5:0,
                    from include/linux/kernel.h:13,
                    from include/linux/cpu_pm.h:21,
                    from arch/arm64/kvm/../../../arch/arm/kvm/arm.c:19:
   arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1454:13: error: initializer element is not constant
    module_init(arm_init);
                ^
   include/linux/init.h:182:58: note: in definition of macro '__define_initcall'
     __attribute__((__section__(".initcall" #id ".init"))) = fn; \
                                                             ^
   include/linux/init.h:217:24: note: in expansion of macro 'device_initcall'
    #define __initcall(fn) device_initcall(fn)
                           ^
   include/linux/module.h:86:24: note: in expansion of macro '__initcall'
    #define module_init(x) __initcall(x);
                           ^
>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:1454:1: note: in expansion of macro 'module_init'
    module_init(arm_init);
    ^

vim +/kvm_vm_ioctl_set_device_addr +1016 arch/arm64/kvm/../../../arch/arm/kvm/arm.c

53c810c36 Mario Smarduch    2015-01-15   994   *
53c810c36 Mario Smarduch    2015-01-15   995   *   1. Take a snapshot of the bit and clear it if needed.
53c810c36 Mario Smarduch    2015-01-15   996   *   2. Write protect the corresponding page.
53c810c36 Mario Smarduch    2015-01-15   997   *   3. Copy the snapshot to the userspace.
53c810c36 Mario Smarduch    2015-01-15   998   *   4. Flush TLB's if needed.
53c810c36 Mario Smarduch    2015-01-15   999   */
749cf76c5 Christoffer Dall  2013-01-20 @1000  int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
749cf76c5 Christoffer Dall  2013-01-20  1001  {
53c810c36 Mario Smarduch    2015-01-15  1002  	bool is_dirty = false;
53c810c36 Mario Smarduch    2015-01-15  1003  	int r;
53c810c36 Mario Smarduch    2015-01-15  1004  
53c810c36 Mario Smarduch    2015-01-15  1005  	mutex_lock(&kvm->slots_lock);
53c810c36 Mario Smarduch    2015-01-15  1006  
53c810c36 Mario Smarduch    2015-01-15  1007  	r = kvm_get_dirty_log_protect(kvm, log, &is_dirty);
53c810c36 Mario Smarduch    2015-01-15  1008  
53c810c36 Mario Smarduch    2015-01-15  1009  	if (is_dirty)
53c810c36 Mario Smarduch    2015-01-15  1010  		kvm_flush_remote_tlbs(kvm);
53c810c36 Mario Smarduch    2015-01-15  1011  
53c810c36 Mario Smarduch    2015-01-15  1012  	mutex_unlock(&kvm->slots_lock);
53c810c36 Mario Smarduch    2015-01-15  1013  	return r;
749cf76c5 Christoffer Dall  2013-01-20  1014  }
749cf76c5 Christoffer Dall  2013-01-20  1015  
3401d5469 Christoffer Dall  2013-01-23 @1016  static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
3401d5469 Christoffer Dall  2013-01-23  1017  					struct kvm_arm_device_addr *dev_addr)
3401d5469 Christoffer Dall  2013-01-23  1018  {
330690cdc Christoffer Dall  2013-01-21  1019  	unsigned long dev_id, type;
330690cdc Christoffer Dall  2013-01-21  1020  
330690cdc Christoffer Dall  2013-01-21  1021  	dev_id = (dev_addr->id & KVM_ARM_DEVICE_ID_MASK) >>
330690cdc Christoffer Dall  2013-01-21  1022  		KVM_ARM_DEVICE_ID_SHIFT;
330690cdc Christoffer Dall  2013-01-21  1023  	type = (dev_addr->id & KVM_ARM_DEVICE_TYPE_MASK) >>
330690cdc Christoffer Dall  2013-01-21  1024  		KVM_ARM_DEVICE_TYPE_SHIFT;
330690cdc Christoffer Dall  2013-01-21  1025  
330690cdc Christoffer Dall  2013-01-21  1026  	switch (dev_id) {
330690cdc Christoffer Dall  2013-01-21  1027  	case KVM_ARM_DEVICE_VGIC_V2:
c7da6fa43 Pavel Fedin       2015-12-18  1028  		if (!vgic_present)
c7da6fa43 Pavel Fedin       2015-12-18  1029  			return -ENXIO;
ce01e4e88 Christoffer Dall  2013-09-23  1030  		return kvm_vgic_addr(kvm, type, &dev_addr->addr, true);
330690cdc Christoffer Dall  2013-01-21  1031  	default:
3401d5469 Christoffer Dall  2013-01-23  1032  		return -ENODEV;
3401d5469 Christoffer Dall  2013-01-23  1033  	}
330690cdc Christoffer Dall  2013-01-21  1034  }
3401d5469 Christoffer Dall  2013-01-23  1035  
749cf76c5 Christoffer Dall  2013-01-20  1036  long kvm_arch_vm_ioctl(struct file *filp,
749cf76c5 Christoffer Dall  2013-01-20  1037  		       unsigned int ioctl, unsigned long arg)
749cf76c5 Christoffer Dall  2013-01-20  1038  {
3401d5469 Christoffer Dall  2013-01-23  1039  	struct kvm *kvm = filp->private_data;
3401d5469 Christoffer Dall  2013-01-23  1040  	void __user *argp = (void __user *)arg;
3401d5469 Christoffer Dall  2013-01-23  1041  
3401d5469 Christoffer Dall  2013-01-23  1042  	switch (ioctl) {
5863c2ce7 Marc Zyngier      2013-01-21  1043  	case KVM_CREATE_IRQCHIP: {
a28ebea2a Christoffer Dall  2016-08-09  1044  		int ret;
c7da6fa43 Pavel Fedin       2015-12-18  1045  		if (!vgic_present)
c7da6fa43 Pavel Fedin       2015-12-18  1046  			return -ENXIO;
a28ebea2a Christoffer Dall  2016-08-09  1047  		mutex_lock(&kvm->lock);
a28ebea2a Christoffer Dall  2016-08-09  1048  		ret = kvm_vgic_create(kvm, KVM_DEV_TYPE_ARM_VGIC_V2);
a28ebea2a Christoffer Dall  2016-08-09  1049  		mutex_unlock(&kvm->lock);
a28ebea2a Christoffer Dall  2016-08-09  1050  		return ret;
5863c2ce7 Marc Zyngier      2013-01-21  1051  	}
3401d5469 Christoffer Dall  2013-01-23  1052  	case KVM_ARM_SET_DEVICE_ADDR: {
3401d5469 Christoffer Dall  2013-01-23  1053  		struct kvm_arm_device_addr dev_addr;
3401d5469 Christoffer Dall  2013-01-23  1054  
3401d5469 Christoffer Dall  2013-01-23  1055  		if (copy_from_user(&dev_addr, argp, sizeof(dev_addr)))
3401d5469 Christoffer Dall  2013-01-23  1056  			return -EFAULT;
3401d5469 Christoffer Dall  2013-01-23  1057  		return kvm_vm_ioctl_set_device_addr(kvm, &dev_addr);
3401d5469 Christoffer Dall  2013-01-23  1058  	}
42c4e0c77 Anup Patel        2013-09-30  1059  	case KVM_ARM_PREFERRED_TARGET: {
42c4e0c77 Anup Patel        2013-09-30  1060  		int err;
42c4e0c77 Anup Patel        2013-09-30  1061  		struct kvm_vcpu_init init;
42c4e0c77 Anup Patel        2013-09-30  1062  
42c4e0c77 Anup Patel        2013-09-30  1063  		err = kvm_vcpu_preferred_target(&init);
42c4e0c77 Anup Patel        2013-09-30  1064  		if (err)
42c4e0c77 Anup Patel        2013-09-30  1065  			return err;
42c4e0c77 Anup Patel        2013-09-30  1066  
42c4e0c77 Anup Patel        2013-09-30  1067  		if (copy_to_user(argp, &init, sizeof(init)))
42c4e0c77 Anup Patel        2013-09-30  1068  			return -EFAULT;
42c4e0c77 Anup Patel        2013-09-30  1069  
42c4e0c77 Anup Patel        2013-09-30  1070  		return 0;
42c4e0c77 Anup Patel        2013-09-30  1071  	}
3401d5469 Christoffer Dall  2013-01-23  1072  	default:
749cf76c5 Christoffer Dall  2013-01-20  1073  		return -EINVAL;
749cf76c5 Christoffer Dall  2013-01-20  1074  	}
3401d5469 Christoffer Dall  2013-01-23  1075  }
749cf76c5 Christoffer Dall  2013-01-20  1076  
d157f4a51 Marc Zyngier      2013-04-12 @1077  static void cpu_init_hyp_mode(void *dummy)
342cd0ab0 Christoffer Dall  2013-01-20  1078  {
dac288f7b Marc Zyngier      2013-05-14  1079  	phys_addr_t pgd_ptr;
342cd0ab0 Christoffer Dall  2013-01-20  1080  	unsigned long hyp_stack_ptr;
342cd0ab0 Christoffer Dall  2013-01-20  1081  	unsigned long stack_page;
342cd0ab0 Christoffer Dall  2013-01-20  1082  	unsigned long vector_ptr;
342cd0ab0 Christoffer Dall  2013-01-20  1083  
342cd0ab0 Christoffer Dall  2013-01-20  1084  	/* Switch from the HYP stub to our own HYP init vector */
5a677ce04 Marc Zyngier      2013-04-12  1085  	__hyp_set_vectors(kvm_get_idmap_vector());
342cd0ab0 Christoffer Dall  2013-01-20  1086  
dac288f7b Marc Zyngier      2013-05-14  1087  	pgd_ptr = kvm_mmu_get_httbr();
1436c1aa6 Christoph Lameter 2013-10-21  1088  	stack_page = __this_cpu_read(kvm_arm_hyp_stack_page);
342cd0ab0 Christoffer Dall  2013-01-20  1089  	hyp_stack_ptr = stack_page + PAGE_SIZE;
a0bf9776c Ard Biesheuvel    2016-02-16  1090  	vector_ptr = (unsigned long)kvm_ksym_ref(__kvm_hyp_vector);
342cd0ab0 Christoffer Dall  2013-01-20  1091  
12fda8123 Marc Zyngier      2016-06-30  1092  	__cpu_init_hyp_mode(pgd_ptr, hyp_stack_ptr, vector_ptr);
35a2491a6 Marc Zyngier      2016-02-01  1093  	__cpu_init_stage2();
56c7f5e77 Alex Bennée       2015-07-07  1094  
56c7f5e77 Alex Bennée       2015-07-07  1095  	kvm_arm_init_debug();
342cd0ab0 Christoffer Dall  2013-01-20  1096  }
342cd0ab0 Christoffer Dall  2013-01-20  1097  
5f5560b1c James Morse       2016-03-30 @1098  static void cpu_hyp_reinit(void)
5f5560b1c James Morse       2016-03-30  1099  {
5f5560b1c James Morse       2016-03-30  1100  	if (is_kernel_in_hyp_mode()) {
5f5560b1c James Morse       2016-03-30  1101  		/*
67f691976 AKASHI Takahiro   2016-04-27  1102  		 * __cpu_init_stage2() is safe to call even if the PM
5f5560b1c James Morse       2016-03-30  1103  		 * event was cancelled before the CPU was reset.
5f5560b1c James Morse       2016-03-30  1104  		 */
67f691976 AKASHI Takahiro   2016-04-27  1105  		__cpu_init_stage2();
5f5560b1c James Morse       2016-03-30  1106  	} else {
5f5560b1c James Morse       2016-03-30  1107  		if (__hyp_get_vectors() == hyp_default_vectors)
5f5560b1c James Morse       2016-03-30  1108  			cpu_init_hyp_mode(NULL);
5f5560b1c James Morse       2016-03-30  1109  	}
5f5560b1c James Morse       2016-03-30  1110  }
5f5560b1c James Morse       2016-03-30  1111  
67f691976 AKASHI Takahiro   2016-04-27 @1112  static void cpu_hyp_reset(void)
67f691976 AKASHI Takahiro   2016-04-27  1113  {
12fda8123 Marc Zyngier      2016-06-30  1114  	if (!is_kernel_in_hyp_mode())
e537ecd7e Marc Zyngier      2016-06-30  1115  		__cpu_reset_hyp_mode(hyp_default_vectors,
e537ecd7e Marc Zyngier      2016-06-30  1116  				     kvm_get_idmap_start());
67f691976 AKASHI Takahiro   2016-04-27  1117  }
67f691976 AKASHI Takahiro   2016-04-27  1118  
67f691976 AKASHI Takahiro   2016-04-27 @1119  static void _kvm_arch_hardware_enable(void *discard)
d157f4a51 Marc Zyngier      2013-04-12  1120  {
67f691976 AKASHI Takahiro   2016-04-27  1121  	if (!__this_cpu_read(kvm_arm_hardware_enabled)) {
5f5560b1c James Morse       2016-03-30  1122  		cpu_hyp_reinit();
67f691976 AKASHI Takahiro   2016-04-27  1123  		__this_cpu_write(kvm_arm_hardware_enabled, 1);
67f691976 AKASHI Takahiro   2016-04-27  1124  	}
d157f4a51 Marc Zyngier      2013-04-12  1125  }
d157f4a51 Marc Zyngier      2013-04-12  1126  
67f691976 AKASHI Takahiro   2016-04-27  1127  int kvm_arch_hardware_enable(void)
67f691976 AKASHI Takahiro   2016-04-27  1128  {
67f691976 AKASHI Takahiro   2016-04-27  1129  	_kvm_arch_hardware_enable(NULL);
67f691976 AKASHI Takahiro   2016-04-27  1130  	return 0;
342cd0ab0 Christoffer Dall  2013-01-20  1131  }
342cd0ab0 Christoffer Dall  2013-01-20  1132  
67f691976 AKASHI Takahiro   2016-04-27 @1133  static void _kvm_arch_hardware_disable(void *discard)
67f691976 AKASHI Takahiro   2016-04-27  1134  {
67f691976 AKASHI Takahiro   2016-04-27  1135  	if (__this_cpu_read(kvm_arm_hardware_enabled)) {
67f691976 AKASHI Takahiro   2016-04-27  1136  		cpu_hyp_reset();
67f691976 AKASHI Takahiro   2016-04-27  1137  		__this_cpu_write(kvm_arm_hardware_enabled, 0);
67f691976 AKASHI Takahiro   2016-04-27  1138  	}
67f691976 AKASHI Takahiro   2016-04-27  1139  }
67f691976 AKASHI Takahiro   2016-04-27  1140  
67f691976 AKASHI Takahiro   2016-04-27  1141  void kvm_arch_hardware_disable(void)
67f691976 AKASHI Takahiro   2016-04-27  1142  {
67f691976 AKASHI Takahiro   2016-04-27  1143  	_kvm_arch_hardware_disable(NULL);
67f691976 AKASHI Takahiro   2016-04-27  1144  }
d157f4a51 Marc Zyngier      2013-04-12  1145  
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1146  #ifdef CONFIG_CPU_PM
1fcf7ce0c Lorenzo Pieralisi 2013-08-05 @1147  static int hyp_init_cpu_pm_notifier(struct notifier_block *self,
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1148  				    unsigned long cmd,
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1149  				    void *v)
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1150  {
67f691976 AKASHI Takahiro   2016-04-27  1151  	/*
67f691976 AKASHI Takahiro   2016-04-27  1152  	 * kvm_arm_hardware_enabled is left with its old value over
67f691976 AKASHI Takahiro   2016-04-27  1153  	 * PM_ENTER->PM_EXIT. It is used to indicate PM_EXIT should
67f691976 AKASHI Takahiro   2016-04-27  1154  	 * re-enable hyp.
67f691976 AKASHI Takahiro   2016-04-27  1155  	 */
67f691976 AKASHI Takahiro   2016-04-27  1156  	switch (cmd) {
67f691976 AKASHI Takahiro   2016-04-27  1157  	case CPU_PM_ENTER:
67f691976 AKASHI Takahiro   2016-04-27  1158  		if (__this_cpu_read(kvm_arm_hardware_enabled))
67f691976 AKASHI Takahiro   2016-04-27  1159  			/*
67f691976 AKASHI Takahiro   2016-04-27  1160  			 * don't update kvm_arm_hardware_enabled here
67f691976 AKASHI Takahiro   2016-04-27  1161  			 * so that the hardware will be re-enabled
67f691976 AKASHI Takahiro   2016-04-27  1162  			 * when we resume. See below.
67f691976 AKASHI Takahiro   2016-04-27  1163  			 */
67f691976 AKASHI Takahiro   2016-04-27  1164  			cpu_hyp_reset();
67f691976 AKASHI Takahiro   2016-04-27  1165  
67f691976 AKASHI Takahiro   2016-04-27  1166  		return NOTIFY_OK;
67f691976 AKASHI Takahiro   2016-04-27  1167  	case CPU_PM_EXIT:
67f691976 AKASHI Takahiro   2016-04-27  1168  		if (__this_cpu_read(kvm_arm_hardware_enabled))
67f691976 AKASHI Takahiro   2016-04-27  1169  			/* The hardware was enabled before suspend. */
5f5560b1c James Morse       2016-03-30  1170  			cpu_hyp_reinit();
67f691976 AKASHI Takahiro   2016-04-27  1171  
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1172  		return NOTIFY_OK;
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1173  
67f691976 AKASHI Takahiro   2016-04-27  1174  	default:
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1175  		return NOTIFY_DONE;
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1176  	}
67f691976 AKASHI Takahiro   2016-04-27  1177  }
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1178  
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1179  static struct notifier_block hyp_init_cpu_pm_nb = {
1fcf7ce0c Lorenzo Pieralisi 2013-08-05 @1180  	.notifier_call = hyp_init_cpu_pm_notifier,
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1181  };
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1182  
1fcf7ce0c Lorenzo Pieralisi 2013-08-05 @1183  static void __init hyp_cpu_pm_init(void)
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1184  {
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1185  	cpu_pm_register_notifier(&hyp_init_cpu_pm_nb);
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1186  }
06a71a24b Sudeep Holla      2016-04-04 @1187  static void __init hyp_cpu_pm_exit(void)
06a71a24b Sudeep Holla      2016-04-04  1188  {
06a71a24b Sudeep Holla      2016-04-04  1189  	cpu_pm_unregister_notifier(&hyp_init_cpu_pm_nb);
06a71a24b Sudeep Holla      2016-04-04  1190  }
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1191  #else
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1192  static inline void hyp_cpu_pm_init(void)
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1193  {
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1194  }
06a71a24b Sudeep Holla      2016-04-04  1195  static inline void hyp_cpu_pm_exit(void)
06a71a24b Sudeep Holla      2016-04-04  1196  {
06a71a24b Sudeep Holla      2016-04-04  1197  }
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1198  #endif
1fcf7ce0c Lorenzo Pieralisi 2013-08-05  1199  
1e947bad0 Marc Zyngier      2015-01-29 @1200  static void teardown_common_resources(void)
1e947bad0 Marc Zyngier      2015-01-29  1201  {
1e947bad0 Marc Zyngier      2015-01-29  1202  	free_percpu(kvm_host_cpu_state);
1e947bad0 Marc Zyngier      2015-01-29  1203  }
1e947bad0 Marc Zyngier      2015-01-29  1204  
1e947bad0 Marc Zyngier      2015-01-29 @1205  static int init_common_resources(void)
1e947bad0 Marc Zyngier      2015-01-29  1206  {
1e947bad0 Marc Zyngier      2015-01-29  1207  	kvm_host_cpu_state = alloc_percpu(kvm_cpu_context_t);
1e947bad0 Marc Zyngier      2015-01-29  1208  	if (!kvm_host_cpu_state) {

:::::: The code at line 1016 was first introduced by commit
:::::: 3401d54696f992edf036f00f46c8c399d1b75c2a KVM: ARM: Introduce KVM_ARM_SET_DEVICE_ADDR ioctl

:::::: TO: Christoffer Dall <c.dall@virtualopensystems.com>
:::::: CC: Marc Zyngier <marc.zyngier@arm.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
diff mbox

Patch

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 739db9a..6a64c53 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -997,7 +997,9 @@  documentation when it pops into existence).
 
 Capability: KVM_CAP_ENABLE_CAP, KVM_CAP_ENABLE_CAP_VM
 Architectures: x86 (only KVM_CAP_ENABLE_CAP_VM),
-	       mips (only KVM_CAP_ENABLE_CAP), ppc, s390
+	       mips (only KVM_CAP_ENABLE_CAP), ppc, s390,
+	       arm (only KVM_CAP_ENABLE_CAP),
+	       arm64 (only only KVM_CAP_ENABLE_CAP)
 Type: vcpu ioctl, vm ioctl (with KVM_CAP_ENABLE_CAP_VM)
 Parameters: struct kvm_enable_cap (in)
 Returns: 0 on success; -1 on error
@@ -3200,8 +3202,10 @@  struct kvm_run {
 	/* in */
 	__u8 request_interrupt_window;
 
-Request that KVM_RUN return when it becomes possible to inject external
+[x86] Request that KVM_RUN return when it becomes possible to inject external
 interrupts into the guest.  Useful in conjunction with KVM_INTERRUPT.
+[arm*] Bits set to 1 in here mask IRQ lines that would otherwise potentially
+trigger forever. Useful with KVM_CAP_ARM_TIMER.
 
 	__u8 padding1[7];
 
@@ -3517,6 +3521,16 @@  Hyper-V SynIC state change. Notification is used to remap SynIC
 event/message pages and to enable/disable SynIC messages/events processing
 in userspace.
 
+		/* KVM_EXIT_ARM_TIMER */
+		struct {
+			__u8 timesource;
+		} arm_timer;
+
+Indicates that a timer triggered that user space needs to handle and
+potentially mask with vcpu->run->request_interrupt_window to allow the
+guest to proceed. This only happens for timers that got enabled through
+KVM_CAP_ARM_TIMER.
+
 		/* Fix the size of the union. */
 		char padding[256];
 	};
@@ -3737,6 +3751,16 @@  Once this is done the KVM_REG_MIPS_VEC_* and KVM_REG_MIPS_MSA_* registers can be
 accessed, and the Config5.MSAEn bit is accessible via the KVM API and also from
 the guest.
 
+6.11 KVM_CAP_ARM_TIMER
+
+Architectures: arm, arm64
+Target: vcpu
+Parameters: args[0] contains a bitmap of timers to enable
+
+This capability allows to route per-core timers into user space. When it's
+enabled, the enabled timers trigger KVM_EXIT_ARM_TIMER guest exits when they
+are pending, unless masked by vcpu->run->request_interrupt_window.
+
 7. Capabilities that can be enabled on VMs
 ------------------------------------------
 
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index de338d9..77d1f73 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -180,6 +180,9 @@  struct kvm_vcpu_arch {
 
 	/* Detect first run of a vcpu */
 	bool has_run_once;
+
+	/* User space wants timer notifications */
+	bool user_space_arm_timers;
 };
 
 struct kvm_vm_stat {
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 75f130e..1b4b9a6 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -187,6 +187,7 @@  int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 	case KVM_CAP_ARM_PSCI_0_2:
 	case KVM_CAP_READONLY_MEM:
 	case KVM_CAP_MP_STATE:
+	case KVM_CAP_ARM_TIMER:
 		r = 1;
 		break;
 	case KVM_CAP_COALESCED_MMIO:
@@ -474,13 +475,7 @@  static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
 			return ret;
 	}
 
-	/*
-	 * Enable the arch timers only if we have an in-kernel VGIC
-	 * and it has been properly initialized, since we cannot handle
-	 * interrupts from the virtual timer with a userspace gic.
-	 */
-	if (irqchip_in_kernel(kvm) && vgic_initialized(kvm))
-		ret = kvm_timer_enable(vcpu);
+	ret = kvm_timer_enable(vcpu);
 
 	return ret;
 }
@@ -601,6 +596,13 @@  int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 			run->exit_reason = KVM_EXIT_INTR;
 		}
 
+		if (kvm_check_request(KVM_REQ_PENDING_TIMER, vcpu)) {
+			/* Tell user space about the pending vtimer */
+			ret = 0;
+			run->exit_reason = KVM_EXIT_ARM_TIMER;
+			run->arm_timer.timesource = KVM_ARM_TIMER_VTIMER;
+		}
+
 		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
 			vcpu->arch.power_off || vcpu->arch.pause) {
 			local_irq_enable();
@@ -878,6 +880,29 @@  static int kvm_arm_vcpu_has_attr(struct kvm_vcpu *vcpu,
 	return ret;
 }
 
+static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
+				     struct kvm_enable_cap *cap)
+{
+	int r;
+
+	if (cap->flags)
+		return -EINVAL;
+
+	switch (cap->cap) {
+	case KVM_CAP_ARM_TIMER:
+		r = 0;
+		if (cap->args[0] != KVM_ARM_TIMER_VTIMER)
+			return -EINVAL;
+		vcpu->arch.user_space_arm_timers = true;
+		break;
+	default:
+		r = -EINVAL;
+		break;
+	}
+
+	return r;
+}
+
 long kvm_arch_vcpu_ioctl(struct file *filp,
 			 unsigned int ioctl, unsigned long arg)
 {
@@ -940,6 +965,13 @@  long kvm_arch_vcpu_ioctl(struct file *filp,
 		if (copy_from_user(&attr, argp, sizeof(attr)))
 			return -EFAULT;
 		return kvm_arm_vcpu_has_attr(vcpu, &attr);
+	case KVM_ENABLE_CAP:
+	{
+		struct kvm_enable_cap cap;
+
+		if (copy_from_user(&cap, argp, sizeof(cap)))
+			return -EFAULT;
+		return kvm_vcpu_ioctl_enable_cap(vcpu, &cap);
 	}
 	default:
 		return -EINVAL;
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 3eda975..3d01481 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -270,6 +270,9 @@  struct kvm_vcpu_arch {
 
 	/* Detect first run of a vcpu */
 	bool has_run_once;
+
+	/* User space wants timer notifications */
+	bool user_space_arm_timers;
 };
 
 #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 300ef25..00f4948 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -205,6 +205,7 @@  struct kvm_hyperv_exit {
 #define KVM_EXIT_S390_STSI        25
 #define KVM_EXIT_IOAPIC_EOI       26
 #define KVM_EXIT_HYPERV           27
+#define KVM_EXIT_ARM_TIMER        28
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 /* Emulate instruction failed. */
@@ -361,6 +362,10 @@  struct kvm_run {
 		} eoi;
 		/* KVM_EXIT_HYPERV */
 		struct kvm_hyperv_exit hyperv;
+		/* KVM_EXIT_ARM_TIMER */
+		struct {
+			__u8 timesource;
+		} arm_timer;
 		/* Fix the size of the union. */
 		char padding[256];
 	};
@@ -870,6 +875,7 @@  struct kvm_ppc_smmu_info {
 #define KVM_CAP_S390_USER_INSTR0 130
 #define KVM_CAP_MSI_DEVID 131
 #define KVM_CAP_PPC_HTM 132
+#define KVM_CAP_ARM_TIMER 133
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -1327,4 +1333,12 @@  struct kvm_assigned_msix_entry {
 #define KVM_X2APIC_API_USE_32BIT_IDS            (1ULL << 0)
 #define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK  (1ULL << 1)
 
+/* Available with KVM_CAP_ARM_TIMER */
+
+/* Bits for run->request_interrupt_window */
+#define KVM_IRQWINDOW_VTIMER		(1 << 0)
+
+/* Bits for run->arm_timer.timesource */
+#define KVM_ARM_TIMER_VTIMER		(1 << 0)
+
 #endif /* __LINUX_KVM_H */
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 4309b60..d0e999d 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -24,6 +24,7 @@ 
 
 #include <clocksource/arm_arch_timer.h>
 #include <asm/arch_timer.h>
+#include <asm/kvm_emulate.h>
 
 #include <kvm/arm_vgic.h>
 #include <kvm/arm_arch_timer.h>
@@ -170,16 +171,45 @@  static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level)
 {
 	int ret;
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+	struct kvm_run *run = vcpu->run;
 
-	BUG_ON(!vgic_initialized(vcpu->kvm));
+	BUG_ON(irqchip_in_kernel(vcpu->kvm) && !vgic_initialized(vcpu->kvm));
 
 	timer->active_cleared_last = false;
 	timer->irq.level = new_level;
-	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->irq.irq,
+	trace_kvm_timer_update_irq(vcpu->vcpu_id, host_vtimer_irq,
 				   timer->irq.level);
-	ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id,
-					 timer->irq.irq,
-					 timer->irq.level);
+
+	if (irqchip_in_kernel(vcpu->kvm) && vgic_initialized(vcpu->kvm)) {
+		/* Fire the timer in the VGIC */
+
+		ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id,
+						 timer->irq.irq,
+						 timer->irq.level);
+	} else if (!vcpu->arch.user_space_arm_timers) {
+		/* User space has not activated timer use */
+		ret = 0;
+	} else {
+		/*
+		 * Set PENDING_TIMER so that user space can handle the event if
+		 *
+		 *   1) Level is high
+		 *   2) The vtimer is not suppressed by user space
+		 *   3) We are not in the timer trigger exit path
+		 */
+		if (new_level &&
+		    !(run->request_interrupt_window & KVM_IRQWINDOW_VTIMER) &&
+		    (run->exit_reason != KVM_EXIT_ARM_TIMER)) {
+			/* KVM_REQ_PENDING_TIMER means vtimer triggered */
+			kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu);
+		}
+
+		/* Force a new level high check on next entry */
+		timer->irq.level = 0;
+
+		ret = 0;
+	}
+
 	WARN_ON(ret);
 }
 
@@ -197,7 +227,8 @@  static int kvm_timer_update_state(struct kvm_vcpu *vcpu)
 	 * because the guest would never see the interrupt.  Instead wait
 	 * until we call this function from kvm_timer_flush_hwstate.
 	 */
-	if (!vgic_initialized(vcpu->kvm) || !timer->enabled)
+	if ((irqchip_in_kernel(vcpu->kvm) && !vgic_initialized(vcpu->kvm)) ||
+	    !timer->enabled)
 		return -ENODEV;
 
 	if (kvm_timer_should_fire(vcpu) != timer->irq.level)
@@ -275,35 +306,57 @@  void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
 	* to ensure that hardware interrupts from the timer triggers a guest
 	* exit.
 	*/
-	phys_active = timer->irq.level ||
-			kvm_vgic_map_is_active(vcpu, timer->irq.irq);
-
-	/*
-	 * We want to avoid hitting the (re)distributor as much as
-	 * possible, as this is a potentially expensive MMIO access
-	 * (not to mention locks in the irq layer), and a solution for
-	 * this is to cache the "active" state in memory.
-	 *
-	 * Things to consider: we cannot cache an "active set" state,
-	 * because the HW can change this behind our back (it becomes
-	 * "clear" in the HW). We must then restrict the caching to
-	 * the "clear" state.
-	 *
-	 * The cache is invalidated on:
-	 * - vcpu put, indicating that the HW cannot be trusted to be
-	 *   in a sane state on the next vcpu load,
-	 * - any change in the interrupt state
-	 *
-	 * Usage conditions:
-	 * - cached value is "active clear"
-	 * - value to be programmed is "active clear"
-	 */
-	if (timer->active_cleared_last && !phys_active)
-		return;
+	if (irqchip_in_kernel(vcpu->kvm) && vgic_initialized(vcpu->kvm)) {
+		phys_active = timer->irq.level ||
+				kvm_vgic_map_is_active(vcpu, timer->irq.irq);
+
+		/*
+		 * We want to avoid hitting the (re)distributor as much as
+		 * possible, as this is a potentially expensive MMIO access
+		 * (not to mention locks in the irq layer), and a solution for
+		 * this is to cache the "active" state in memory.
+		 *
+		 * Things to consider: we cannot cache an "active set" state,
+		 * because the HW can change this behind our back (it becomes
+		 * "clear" in the HW). We must then restrict the caching to
+		 * the "clear" state.
+		 *
+		 * The cache is invalidated on:
+		 * - vcpu put, indicating that the HW cannot be trusted to be
+		 *   in a sane state on the next vcpu load,
+		 * - any change in the interrupt state
+		 *
+		 * Usage conditions:
+		 * - cached value is "active clear"
+		 * - value to be programmed is "active clear"
+		 */
+		if (timer->active_cleared_last && !phys_active)
+			return;
+
+		ret = irq_set_irqchip_state(host_vtimer_irq,
+					    IRQCHIP_STATE_ACTIVE,
+					    phys_active);
+	} else {
+		/* User space tells us whether the timer is in active mode */
+		phys_active = vcpu->run->request_interrupt_window &
+			      KVM_IRQWINDOW_VTIMER;
+
+		/* However if the line is high, we exit anyway, so we want
+		 * to keep the IRQ masked */
+		phys_active = phys_active || timer->irq.level;
+
+		/*
+		 * So we can just explicitly mask or unmask the IRQ, gaining
+		 * more compatibility with oddball irq controllers.
+		 */
+		if (phys_active)
+			disable_percpu_irq(host_vtimer_irq);
+		else
+			enable_percpu_irq(host_vtimer_irq, 0);
+
+		ret = 0;
+	}
 
-	ret = irq_set_irqchip_state(host_vtimer_irq,
-				    IRQCHIP_STATE_ACTIVE,
-				    phys_active);
 	WARN_ON(ret);
 
 	timer->active_cleared_last = !phys_active;
@@ -479,6 +532,10 @@  int kvm_timer_enable(struct kvm_vcpu *vcpu)
 	if (timer->enabled)
 		return 0;
 
+	/* No need to route physical IRQs when we don't use the vgic */
+	if (!irqchip_in_kernel(vcpu->kvm))
+		goto no_vgic;
+
 	/*
 	 * Find the physical IRQ number corresponding to the host_vtimer_irq
 	 */
@@ -502,6 +559,7 @@  int kvm_timer_enable(struct kvm_vcpu *vcpu)
 	if (ret)
 		return ret;
 
+no_vgic:
 
 	/*
 	 * There is a potential race here between VCPUs starting for the first