From patchwork Thu Dec 11 12:19:53 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 42124 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ee0-f70.google.com (mail-ee0-f70.google.com [74.125.83.70]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 7A2B826C6D for ; Thu, 11 Dec 2014 12:25:45 +0000 (UTC) Received: by mail-ee0-f70.google.com with SMTP id b57sf3623543eek.5 for ; Thu, 11 Dec 2014 04:25:44 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:date:message-id:in-reply-to :references:mime-version:content-type:content-transfer-encoding :subject:precedence:list-id:list-unsubscribe:list-archive:list-post :list-help:list-subscribe:errors-to:sender:x-original-sender :x-original-authentication-results:mailing-list; bh=EwEnH8XyA8oLJ+NMJBlyvjkBuZbwBE6P/4UjWuXeHP0=; b=Zqbfe+0bNSA+7rcemSgwo44iJ2IucMGofBcvAquUFni9B2IiBcupG9WEzxP3Klrh8C vx7u2hEr6JH48RuuOl1FkwprE8loFdhQpX5BhLHTjSjIl3F7umH2wtqx48+HcpYnPHdz iBZceh6GPZgx9YN+90UFesSPgU1SXcoyQApuoN+8jmXEA/WEuOahtmrOAHdesvj2WOYq +bsPzKHFsFfZjGPmSbsq+T0EmnLlD12rO3TXr1536jtT9P6+3+TNcLVzg0RfXN4Ih54l YvhkLIWdBvZkxQQADHPL/i2mg1uvPjOIz/ekvs5BDhkHGndudNfhA2/Kzz/9fWH2MnVM 2/pg== X-Gm-Message-State: ALoCoQnFXGHZC5l7TJNFOsvC8izEoM20urANBYvo07RdP7JAfvAOUgrzu4Xz9hxdZN6jdrX70qTq X-Received: by 10.194.133.39 with SMTP id oz7mr1403852wjb.3.1418300744729; Thu, 11 Dec 2014 04:25:44 -0800 (PST) X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.37.106 with SMTP id x10ls231219laj.58.gmail; Thu, 11 Dec 2014 04:25:44 -0800 (PST) X-Received: by 10.152.37.100 with SMTP id x4mr9663676laj.22.1418300744572; Thu, 11 Dec 2014 04:25:44 -0800 (PST) Received: from mail-lb0-f172.google.com (mail-lb0-f172.google.com. [209.85.217.172]) by mx.google.com with ESMTPS id ln11si1085673lac.114.2014.12.11.04.25.44 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 11 Dec 2014 04:25:44 -0800 (PST) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.217.172 as permitted sender) client-ip=209.85.217.172; Received: by mail-lb0-f172.google.com with SMTP id u10so4060396lbd.17 for ; Thu, 11 Dec 2014 04:25:44 -0800 (PST) X-Received: by 10.112.130.132 with SMTP id oe4mr9517205lbb.82.1418300744431; Thu, 11 Dec 2014 04:25:44 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.142.69 with SMTP id ru5csp504912lbb; Thu, 11 Dec 2014 04:25:43 -0800 (PST) X-Received: by 10.229.66.10 with SMTP id l10mr5926981qci.22.1418300742620; Thu, 11 Dec 2014 04:25:42 -0800 (PST) Received: from lists.gnu.org (lists.gnu.org. [2001:4830:134:3::11]) by mx.google.com with ESMTPS id 104si1027358qgl.65.2014.12.11.04.25.41 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Thu, 11 Dec 2014 04:25:42 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) client-ip=2001:4830:134:3::11; Received: from localhost ([::1]:50565 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Xz2oP-0004xF-E7 for patch@linaro.org; Thu, 11 Dec 2014 07:25:41 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44487) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Xz2j0-0004sI-76 for qemu-devel@nongnu.org; Thu, 11 Dec 2014 07:20:08 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Xz2iy-0007Fh-82 for qemu-devel@nongnu.org; Thu, 11 Dec 2014 07:20:06 -0500 Received: from mnementh.archaic.org.uk ([2001:8b0:1d0::1]:54567) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Xz2ix-0006sg-UM for qemu-devel@nongnu.org; Thu, 11 Dec 2014 07:20:04 -0500 Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.80) (envelope-from ) id 1Xz2ir-0001B6-1g for qemu-devel@nongnu.org; Thu, 11 Dec 2014 12:19:57 +0000 From: Peter Maydell To: qemu-devel@nongnu.org Date: Thu, 11 Dec 2014 12:19:53 +0000 Message-Id: <1418300395-4348-32-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1418300395-4348-1-git-send-email-peter.maydell@linaro.org> References: <1418300395-4348-1-git-send-email-peter.maydell@linaro.org> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2001:8b0:1d0::1 Subject: [Qemu-devel] [PULL 31/33] target-arm/kvm: make reg sync code common between kvm32/64 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: qemu-devel-bounces+patch=linaro.org@nongnu.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: peter.maydell@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.217.172 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 From: Alex Bennée Before we launch a guest we query KVM for the list of "co-processor" registers it knows about. This is used to synchronize system register state for the bulk of coprocessor/system registers. Move this code from the 32-bit specific vcpu init function into a common routine and call it also from the 64-bit vcpu init. This allows system registers to migrate correctly when using KVM, and also permits QEMU code to see the current KVM register state (which will be needed to support big-endian guests, since the virtio endianness callback must check for some system register settings). Since vcpu reset also has to sync registers, we move the 32 bit kvm_arm_reset_vcpu() into common code as well and share it with the 64 bit version. Signed-off-by: Alex Bennée [PMM: just copy the 32-bit code rather than improving it along the way; don't share reg_syncs_via_tuple_list() between 32 and 64 bit; tweak function names; move reset] Signed-off-by: Peter Maydell --- target-arm/kvm.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++ target-arm/kvm32.c | 94 ++----------------------------------------------- target-arm/kvm64.c | 24 +++++++------ target-arm/kvm_arm.h | 22 ++++++++++++ 4 files changed, 137 insertions(+), 101 deletions(-) diff --git a/target-arm/kvm.c b/target-arm/kvm.c index 319784d..191e759 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -21,6 +21,7 @@ #include "sysemu/kvm.h" #include "kvm_arm.h" #include "cpu.h" +#include "internals.h" #include "hw/arm/arm.h" const KVMCapabilityInfo kvm_arch_required_capabilities[] = { @@ -279,6 +280,94 @@ void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid, uint64_t group, memory_region_ref(kd->mr); } +static int compare_u64(const void *a, const void *b) +{ + if (*(uint64_t *)a > *(uint64_t *)b) { + return 1; + } + if (*(uint64_t *)a < *(uint64_t *)b) { + return -1; + } + return 0; +} + +/* Initialize the CPUState's cpreg list according to the kernel's + * definition of what CPU registers it knows about (and throw away + * the previous TCG-created cpreg list). + */ +int kvm_arm_init_cpreg_list(ARMCPU *cpu) +{ + struct kvm_reg_list rl; + struct kvm_reg_list *rlp; + int i, ret, arraylen; + CPUState *cs = CPU(cpu); + + rl.n = 0; + ret = kvm_vcpu_ioctl(cs, KVM_GET_REG_LIST, &rl); + if (ret != -E2BIG) { + return ret; + } + rlp = g_malloc(sizeof(struct kvm_reg_list) + rl.n * sizeof(uint64_t)); + rlp->n = rl.n; + ret = kvm_vcpu_ioctl(cs, KVM_GET_REG_LIST, rlp); + if (ret) { + goto out; + } + /* Sort the list we get back from the kernel, since cpreg_tuples + * must be in strictly ascending order. + */ + qsort(&rlp->reg, rlp->n, sizeof(rlp->reg[0]), compare_u64); + + for (i = 0, arraylen = 0; i < rlp->n; i++) { + if (!kvm_arm_reg_syncs_via_cpreg_list(rlp->reg[i])) { + continue; + } + switch (rlp->reg[i] & KVM_REG_SIZE_MASK) { + case KVM_REG_SIZE_U32: + case KVM_REG_SIZE_U64: + break; + default: + fprintf(stderr, "Can't handle size of register in kernel list\n"); + ret = -EINVAL; + goto out; + } + + arraylen++; + } + + cpu->cpreg_indexes = g_renew(uint64_t, cpu->cpreg_indexes, arraylen); + cpu->cpreg_values = g_renew(uint64_t, cpu->cpreg_values, arraylen); + cpu->cpreg_vmstate_indexes = g_renew(uint64_t, cpu->cpreg_vmstate_indexes, + arraylen); + cpu->cpreg_vmstate_values = g_renew(uint64_t, cpu->cpreg_vmstate_values, + arraylen); + cpu->cpreg_array_len = arraylen; + cpu->cpreg_vmstate_array_len = arraylen; + + for (i = 0, arraylen = 0; i < rlp->n; i++) { + uint64_t regidx = rlp->reg[i]; + if (!kvm_arm_reg_syncs_via_cpreg_list(regidx)) { + continue; + } + cpu->cpreg_indexes[arraylen] = regidx; + arraylen++; + } + assert(cpu->cpreg_array_len == arraylen); + + if (!write_kvmstate_to_list(cpu)) { + /* Shouldn't happen unless kernel is inconsistent about + * what registers exist. + */ + fprintf(stderr, "Initial read of kernel register state failed\n"); + ret = -EINVAL; + goto out; + } + +out: + g_free(rlp); + return ret; +} + bool write_kvmstate_to_list(ARMCPU *cpu) { CPUState *cs = CPU(cpu); @@ -351,6 +440,15 @@ bool write_list_to_kvmstate(ARMCPU *cpu) return ok; } +void kvm_arm_reset_vcpu(ARMCPU *cpu) +{ + /* Re-init VCPU so that all registers are set to + * their respective reset values. + */ + kvm_arm_vcpu_init(CPU(cpu)); + write_kvmstate_to_list(cpu); +} + void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) { } diff --git a/target-arm/kvm32.c b/target-arm/kvm32.c index a5e67da..94030d1 100644 --- a/target-arm/kvm32.c +++ b/target-arm/kvm32.c @@ -138,7 +138,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc) return true; } -static bool reg_syncs_via_tuple_list(uint64_t regidx) +bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx) { /* Return true if the regidx is a register we should synchronize * via the cpreg_tuples array (ie is not a core reg we sync by @@ -153,24 +153,11 @@ static bool reg_syncs_via_tuple_list(uint64_t regidx) } } -static int compare_u64(const void *a, const void *b) -{ - if (*(uint64_t *)a > *(uint64_t *)b) { - return 1; - } - if (*(uint64_t *)a < *(uint64_t *)b) { - return -1; - } - return 0; -} - int kvm_arch_init_vcpu(CPUState *cs) { - int i, ret, arraylen; + int ret; uint64_t v; struct kvm_one_reg r; - struct kvm_reg_list rl; - struct kvm_reg_list *rlp; ARMCPU *cpu = ARM_CPU(cs); if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE) { @@ -206,73 +193,7 @@ int kvm_arch_init_vcpu(CPUState *cs) return -EINVAL; } - /* Populate the cpreg list based on the kernel's idea - * of what registers exist (and throw away the TCG-created list). - */ - rl.n = 0; - ret = kvm_vcpu_ioctl(cs, KVM_GET_REG_LIST, &rl); - if (ret != -E2BIG) { - return ret; - } - rlp = g_malloc(sizeof(struct kvm_reg_list) + rl.n * sizeof(uint64_t)); - rlp->n = rl.n; - ret = kvm_vcpu_ioctl(cs, KVM_GET_REG_LIST, rlp); - if (ret) { - goto out; - } - /* Sort the list we get back from the kernel, since cpreg_tuples - * must be in strictly ascending order. - */ - qsort(&rlp->reg, rlp->n, sizeof(rlp->reg[0]), compare_u64); - - for (i = 0, arraylen = 0; i < rlp->n; i++) { - if (!reg_syncs_via_tuple_list(rlp->reg[i])) { - continue; - } - switch (rlp->reg[i] & KVM_REG_SIZE_MASK) { - case KVM_REG_SIZE_U32: - case KVM_REG_SIZE_U64: - break; - default: - fprintf(stderr, "Can't handle size of register in kernel list\n"); - ret = -EINVAL; - goto out; - } - - arraylen++; - } - - cpu->cpreg_indexes = g_renew(uint64_t, cpu->cpreg_indexes, arraylen); - cpu->cpreg_values = g_renew(uint64_t, cpu->cpreg_values, arraylen); - cpu->cpreg_vmstate_indexes = g_renew(uint64_t, cpu->cpreg_vmstate_indexes, - arraylen); - cpu->cpreg_vmstate_values = g_renew(uint64_t, cpu->cpreg_vmstate_values, - arraylen); - cpu->cpreg_array_len = arraylen; - cpu->cpreg_vmstate_array_len = arraylen; - - for (i = 0, arraylen = 0; i < rlp->n; i++) { - uint64_t regidx = rlp->reg[i]; - if (!reg_syncs_via_tuple_list(regidx)) { - continue; - } - cpu->cpreg_indexes[arraylen] = regidx; - arraylen++; - } - assert(cpu->cpreg_array_len == arraylen); - - if (!write_kvmstate_to_list(cpu)) { - /* Shouldn't happen unless kernel is inconsistent about - * what registers exist. - */ - fprintf(stderr, "Initial read of kernel register state failed\n"); - ret = -EINVAL; - goto out; - } - -out: - g_free(rlp); - return ret; + return kvm_arm_init_cpreg_list(cpu); } typedef struct Reg { @@ -508,12 +429,3 @@ int kvm_arch_get_registers(CPUState *cs) return 0; } - -void kvm_arm_reset_vcpu(ARMCPU *cpu) -{ - /* Re-init VCPU so that all registers are set to - * their respective reset values. - */ - kvm_arm_vcpu_init(CPU(cpu)); - write_kvmstate_to_list(cpu); -} diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c index c615286..ba16821 100644 --- a/target-arm/kvm64.c +++ b/target-arm/kvm64.c @@ -103,9 +103,21 @@ int kvm_arch_init_vcpu(CPUState *cs) return ret; } - /* TODO : support for save/restore/reset of system regs via tuple list */ + return kvm_arm_init_cpreg_list(cpu); +} - return 0; +bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx) +{ + /* Return true if the regidx is a register we should synchronize + * via the cpreg_tuples array (ie is not a core reg we sync by + * hand in kvm_arch_get/put_registers()) + */ + switch (regidx & KVM_REG_ARM_COPROC_MASK) { + case KVM_REG_ARM_CORE: + return false; + default: + return true; + } } #define AARCH64_CORE_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ @@ -260,11 +272,3 @@ int kvm_arch_get_registers(CPUState *cs) /* TODO: other registers */ return ret; } - -void kvm_arm_reset_vcpu(ARMCPU *cpu) -{ - /* Re-init VCPU so that all registers are set to - * their respective reset values. - */ - kvm_arm_vcpu_init(CPU(cpu)); -} diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h index af93105..455dea3 100644 --- a/target-arm/kvm_arm.h +++ b/target-arm/kvm_arm.h @@ -47,6 +47,28 @@ void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid, uint64_t group, uint64_t attr, int dev_fd); /** + * kvm_arm_init_cpreg_list: + * @cs: CPUState + * + * Initialize the CPUState's cpreg list according to the kernel's + * definition of what CPU registers it knows about (and throw away + * the previous TCG-created cpreg list). + * + * Returns: 0 if success, else < 0 error code + */ +int kvm_arm_init_cpreg_list(ARMCPU *cpu); + +/** + * kvm_arm_reg_syncs_via_cpreg_list + * regidx: KVM register index + * + * Return true if this KVM register should be synchronized via the + * cpreg list of arbitrary system registers, false if it is synchronized + * by hand using code in kvm_arch_get/put_registers(). + */ +bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx); + +/** * write_list_to_kvmstate: * @cpu: ARMCPU *