From patchwork Tue Aug 27 14:08:01 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 19548 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-qc0-f200.google.com (mail-qc0-f200.google.com [209.85.216.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 3A31C248E8 for ; Tue, 27 Aug 2013 14:09:18 +0000 (UTC) Received: by mail-qc0-f200.google.com with SMTP id b11sf1563177qcw.3 for ; Tue, 27 Aug 2013 07:09:17 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=mime-version:x-gm-message-state:delivered-to:from:to:cc:subject :date:message-id:x-original-sender:x-original-authentication-results :precedence:mailing-list:list-id:list-post:list-help:list-archive :list-unsubscribe; bh=4uuey8L48WKsVBIuQBtuL9fywLTp7Hrl4Wwh/ACUpdw=; b=SMzxA7L/vGhWs3+M+arfY8lSIZdpN3v/YfCTJUV2vaAvQWlh02vTAcFdPHiJi6wEau 1vZ65L0VmMntOhd+KlZcn89ICod1ELbdec3Ztxd8uZ7lXBnx+meUlbPgzKyr0P9uYm5O PbWI2uPKz6Gyoq0VGQF2DPH+bvJF9LFWCeWxbZNPFKi33iACSZsfNIaqdFT39ZnHP1zo TAhFK8C+6cCnTuXELQ7OQnWjtz54pWKPRbGQrrsToi94j3lcESZAjDzwvx5gDQxu/nIC /OIekzyr8bjGN2+59+JpgSFcwEazNXVDX4+Vrh5UiFuNzUnuKnVQYwdxuUO6/1tP2k5S mgvQ== X-Received: by 10.236.167.138 with SMTP id i10mr8311584yhl.9.1377612557646; Tue, 27 Aug 2013 07:09:17 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.3.169 with SMTP id d9ls2873767qed.61.gmail; Tue, 27 Aug 2013 07:09:17 -0700 (PDT) X-Received: by 10.220.169.203 with SMTP id a11mr1172613vcz.26.1377612557563; Tue, 27 Aug 2013 07:09:17 -0700 (PDT) Received: from mail-ve0-f180.google.com (mail-ve0-f180.google.com [209.85.128.180]) by mx.google.com with ESMTPS id sk7si4940027vdc.12.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 27 Aug 2013 07:09:17 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.128.180 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.128.180; Received: by mail-ve0-f180.google.com with SMTP id pb11so3247885veb.11 for ; Tue, 27 Aug 2013 07:09:17 -0700 (PDT) X-Gm-Message-State: ALoCoQk4jnPmwmXH5cSBnzL5HVxSypVx2aM5w+I4pEmYtOPHo7PcCxh1jZoeO2TKSxwm5OCcQTbC X-Received: by 10.58.237.105 with SMTP id vb9mr20144607vec.2.1377612557451; Tue, 27 Aug 2013 07:09:17 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.220.174.196 with SMTP id u4csp296859vcz; Tue, 27 Aug 2013 07:09:16 -0700 (PDT) X-Received: by 10.182.128.6 with SMTP id nk6mr2112943obb.11.1377612556263; Tue, 27 Aug 2013 07:09:16 -0700 (PDT) Received: from mail-ob0-f177.google.com (mail-ob0-f177.google.com [209.85.214.177]) by mx.google.com with ESMTPS id ke7si6335130oeb.79.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 27 Aug 2013 07:09:16 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.214.177 is neither permitted nor denied by best guess record for domain of andre.przywara@linaro.org) client-ip=209.85.214.177; Received: by mail-ob0-f177.google.com with SMTP id f8so4671990obp.8 for ; Tue, 27 Aug 2013 07:09:16 -0700 (PDT) X-Received: by 10.182.225.162 with SMTP id rl2mr2095720obc.72.1377612555904; Tue, 27 Aug 2013 07:09:15 -0700 (PDT) Received: from slackpad.drs.calxeda.com (g224197136.adsl.alicedsl.de. [92.224.197.136]) by mx.google.com with ESMTPSA id u3sm8675692oeq.3.1969.12.31.16.00.00 (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 27 Aug 2013 07:09:15 -0700 (PDT) From: Andre Przywara To: christoffer.dall@linaro.org, marc.zyngier@arm.com Cc: peter.maydell@linaro.org, kvmarm@lists.cs.columbia.edu, linux-arm-kernel@lists.infradead.org, patches@linaro.org, Andre Przywara Subject: [PATCH v3] ARM/KVM: save and restore generic timer registers Date: Tue, 27 Aug 2013 16:08:01 +0200 Message-Id: <1377612481-21079-1-git-send-email-andre.przywara@linaro.org> X-Mailer: git-send-email 1.7.12.1 X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: andre.przywara@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.128.180 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , For migration to work we need to save (and later restore) the state of each cores virtual generic timer. Since this is per VCPU, we can use the [gs]et_one_reg ioctl and export the three needed registers (control, counter, compare value). Though they live in cp15 space, we don't use the existing list, since they need special accessor functions and the arch timer is optional. Changes from v1: - move code out of coproc.c and into guest.c and arch_timer.c - present the registers with their native CP15 addresses, but without using space in the VCPU's cp15 array - do the user space copying in the accessor functions Changes from v2: - fix compilation without CONFIG_ARCH_TIMER - fix compilation for arm64 by defining the appropriate registers there - move userspace access out of arch_timer.c into coproc.c Signed-off-by: Andre Przywara Reviewed-by: Christoffer Dall --- arch/arm/include/asm/kvm_host.h | 3 ++ arch/arm/include/uapi/asm/kvm.h | 16 +++++++ arch/arm/kvm/guest.c | 92 ++++++++++++++++++++++++++++++++++++++- arch/arm64/include/uapi/asm/kvm.h | 25 +++++++++++ virt/kvm/arm/arch_timer.c | 34 +++++++++++++++ 5 files changed, 169 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 7d22517..b02753d 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -229,4 +229,7 @@ static inline int kvm_arch_dev_ioctl_check_extension(long ext) int kvm_perf_init(void); int kvm_perf_teardown(void); +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid); +int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value); + #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h index c1ee007..e3b0115 100644 --- a/arch/arm/include/uapi/asm/kvm.h +++ b/arch/arm/include/uapi/asm/kvm.h @@ -118,6 +118,22 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM_32_CRN_MASK 0x0000000000007800 #define KVM_REG_ARM_32_CRN_SHIFT 11 +#define KVM_REG_ARM_32_CP15 (KVM_REG_ARM | KVM_REG_SIZE_U32 | \ + (15ULL << KVM_REG_ARM_COPROC_SHIFT)) +#define KVM_REG_ARM_64_CP15 (KVM_REG_ARM | KVM_REG_SIZE_U64 | \ + (15ULL << KVM_REG_ARM_COPROC_SHIFT)) +#define KVM_REG_ARM_TIMER_CTL (KVM_REG_ARM_32_CP15 | \ + ( 3ULL << KVM_REG_ARM_CRM_SHIFT) | \ + (14ULL << KVM_REG_ARM_32_CRN_SHIFT) | \ + ( 0ULL << KVM_REG_ARM_OPC1_SHIFT) | \ + ( 1ULL << KVM_REG_ARM_32_OPC2_SHIFT)) +#define KVM_REG_ARM_TIMER_CNT (KVM_REG_ARM_64_CP15 | \ + (14ULL << KVM_REG_ARM_CRM_SHIFT) | \ + ( 1ULL << KVM_REG_ARM_OPC1_SHIFT)) +#define KVM_REG_ARM_TIMER_CVAL (KVM_REG_ARM_64_CP15 | \ + (14ULL << KVM_REG_ARM_CRM_SHIFT) | \ + ( 3ULL << KVM_REG_ARM_OPC1_SHIFT)) + /* Normal registers are mapped as coprocessor 16. */ #define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT) #define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / 4) diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c index 152d036..c028d1e 100644 --- a/arch/arm/kvm/guest.c +++ b/arch/arm/kvm/guest.c @@ -109,6 +109,83 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) return -EINVAL; } +#ifndef CONFIG_KVM_ARM_TIMER + +#define NUM_TIMER_REGS 0 + +static int copy_timer_indices (struct kvm_vcpu *vcpu, u64 __user *uindices) +{ + return 0; +} + +static bool is_timer_reg(u64 index) +{ + return false; +} + +int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value) +{ + return 0; +} + +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid) +{ + return 0; +} + +#else + +#define NUM_TIMER_REGS 3 + +static bool is_timer_reg(u64 index) +{ + switch (index) { + case KVM_REG_ARM_TIMER_CTL: + case KVM_REG_ARM_TIMER_CNT: + case KVM_REG_ARM_TIMER_CVAL: + return true; + } + return false; +} + +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) +{ + if (put_user(KVM_REG_ARM_TIMER_CTL, uindices)) + return -EFAULT; + uindices++; + if (put_user(KVM_REG_ARM_TIMER_CNT, uindices)) + return -EFAULT; + uindices++; + if (put_user(KVM_REG_ARM_TIMER_CVAL, uindices)) + return -EFAULT; + + return 0; +} + +#endif + +static int set_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) +{ + void __user *uaddr = (void __user *)(long)reg->addr; + u64 val; + int ret; + + ret = copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)); + if (ret != 0) + return ret; + + return kvm_arm_timer_set_reg(vcpu, reg->id, val); +} + +static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) +{ + void __user *uaddr = (void __user *)(long)reg->addr; + u64 val; + + val = kvm_arm_timer_get_reg(vcpu, reg->id); + return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)); +} + static unsigned long num_core_regs(void) { return sizeof(struct kvm_regs) / sizeof(u32); @@ -121,7 +198,8 @@ static unsigned long num_core_regs(void) */ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu) { - return num_core_regs() + kvm_arm_num_coproc_regs(vcpu); + return num_core_regs() + kvm_arm_num_coproc_regs(vcpu) + + NUM_TIMER_REGS; } /** @@ -133,6 +211,7 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) { unsigned int i; const u64 core_reg = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_CORE; + int ret; for (i = 0; i < sizeof(struct kvm_regs)/sizeof(u32); i++) { if (put_user(core_reg | i, uindices)) @@ -140,6 +219,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) uindices++; } + ret = copy_timer_indices(vcpu, uindices); + if (ret) + return ret; + uindices += NUM_TIMER_REGS; + return kvm_arm_copy_coproc_indices(vcpu, uindices); } @@ -153,6 +237,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) return get_core_reg(vcpu, reg); + if (is_timer_reg(reg->id)) + return get_timer_reg(vcpu, reg); + return kvm_arm_coproc_get_reg(vcpu, reg); } @@ -166,6 +253,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) return set_core_reg(vcpu, reg); + if (is_timer_reg(reg->id)) + return set_timer_reg(vcpu, reg); + return kvm_arm_coproc_set_reg(vcpu, reg); } diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 5031f42..9e2ab9e 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -129,6 +129,31 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM64_SYSREG_OP2_MASK 0x0000000000000007 #define KVM_REG_ARM64_SYSREG_OP2_SHIFT 0 +#define KVM_REG_ARM64_32_SYSREG (KVM_REG_ARM64 | KVM_REG_SIZE_U32 | \ + KVM_REG_ARM64_SYSREG) +#define KVM_REG_ARM64_64_SYSREG (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ + KVM_REG_ARM64_SYSREG) +#define KVM_REG_ARM_TIMER_CTL (KVM_REG_ARM64_32_SYSREG | \ + ( 3ULL << KVM_REG_ARM64_SYSREG_OP0_SHIFT) | \ + ( 3ULL << KVM_REG_ARM64_SYSREG_OP1_SHIFT) | \ + (14ULL << KVM_REG_ARM64_SYSREG_CRN_SHIFT) | \ + ( 3ULL << KVM_REG_ARM64_SYSREG_CRM_SHIFT) | \ + ( 1ULL << KVM_REG_ARM64_SYSREG_OP2_SHIFT)) + +#define KVM_REG_ARM_TIMER_CNT (KVM_REG_ARM64_64_SYSREG | \ + ( 3ULL << KVM_REG_ARM64_SYSREG_OP0_SHIFT) | \ + ( 3ULL << KVM_REG_ARM64_SYSREG_OP1_SHIFT) | \ + (14ULL << KVM_REG_ARM64_SYSREG_CRN_SHIFT) | \ + ( 3ULL << KVM_REG_ARM64_SYSREG_CRM_SHIFT) | \ + ( 2ULL << KVM_REG_ARM64_SYSREG_OP2_SHIFT)) + +#define KVM_REG_ARM_TIMER_CVAL (KVM_REG_ARM64_64_SYSREG | \ + ( 3ULL << KVM_REG_ARM64_SYSREG_OP0_SHIFT) | \ + ( 3ULL << KVM_REG_ARM64_SYSREG_OP1_SHIFT) | \ + (14ULL << KVM_REG_ARM64_SYSREG_CRN_SHIFT) | \ + ( 0ULL << KVM_REG_ARM64_SYSREG_CRM_SHIFT) | \ + ( 2ULL << KVM_REG_ARM64_SYSREG_OP2_SHIFT)) + /* KVM_IRQ_LINE irq field index values */ #define KVM_ARM_IRQ_TYPE_SHIFT 24 #define KVM_ARM_IRQ_TYPE_MASK 0xff diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c index c2e1ef4..5081e80 100644 --- a/virt/kvm/arm/arch_timer.c +++ b/virt/kvm/arm/arch_timer.c @@ -182,6 +182,40 @@ static void kvm_timer_init_interrupt(void *info) enable_percpu_irq(host_vtimer_irq, 0); } +int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value) +{ + struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; + + switch (regid) { + case KVM_REG_ARM_TIMER_CTL: + timer->cntv_ctl = value; + break; + case KVM_REG_ARM_TIMER_CNT: + vcpu->kvm->arch.timer.cntvoff = kvm_phys_timer_read() - value; + break; + case KVM_REG_ARM_TIMER_CVAL: + timer->cntv_cval = value; + break; + default: + return -1; + } + return 0; +} + +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid) +{ + struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; + + switch (regid) { + case KVM_REG_ARM_TIMER_CTL: + return timer->cntv_ctl; + case KVM_REG_ARM_TIMER_CNT: + return kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff; + case KVM_REG_ARM_TIMER_CVAL: + return timer->cntv_cval; + } + return (u64)-1; +} static int kvm_timer_cpu_notify(struct notifier_block *self, unsigned long action, void *cpu)