提交 8c260b11 编写于 作者: A Anthony Liguori

Merge remote-tracking branch 'pmaydell/target-arm.for-upstream' into staging

# By Peter Maydell
# Via Peter Maydell
* pmaydell/target-arm.for-upstream:
  target-arm: Make LPAE feature imply V7MP
  target-arm: Use tuple list to sync cp regs with KVM
  target-arm: Reinitialize all KVM VCPU registers on reset
  target-arm: Initialize cpreg list from KVM when using KVM
  target-arm: Convert TCG to using (index,value) list for cp migration
  target-arm: mark up cpregs for no-migrate or raw access
  target-arm: Add raw_readfn and raw_writefn to ARMCPRegInfo
  target-arm: Allow special cpregs to have flags set

Message-id: 1372181592-32170-1-git-send-email-peter.maydell@linaro.org
Signed-off-by: NAnthony Liguori <aliguori@us.ibm.com>
obj-y += arm-semi.o obj-y += arm-semi.o
obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_SOFTMMU) += machine.o
obj-$(CONFIG_KVM) += kvm.o obj-$(CONFIG_KVM) += kvm.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
obj-y += translate.o op_helper.o helper.o cpu.o obj-y += translate.o op_helper.o helper.o cpu.o
obj-y += neon_helper.o iwmmxt_helper.o obj-y += neon_helper.o iwmmxt_helper.o
...@@ -62,6 +62,29 @@ typedef struct ARMCPU { ...@@ -62,6 +62,29 @@ typedef struct ARMCPU {
/* Coprocessor information */ /* Coprocessor information */
GHashTable *cp_regs; GHashTable *cp_regs;
/* For marshalling (mostly coprocessor) register state between the
* kernel and QEMU (for KVM) and between two QEMUs (for migration),
* we use these arrays.
*/
/* List of register indexes managed via these arrays; (full KVM style
* 64 bit indexes, not CPRegInfo 32 bit indexes)
*/
uint64_t *cpreg_indexes;
/* Values of the registers (cpreg_indexes[i]'s value is cpreg_values[i]) */
uint64_t *cpreg_values;
/* When using KVM, keeps a copy of the initial state of the VCPU,
* so that on reset we can feed the reset values back into the kernel.
*/
uint64_t *cpreg_reset_values;
/* Length of the indexes, values, reset_values arrays */
int32_t cpreg_array_len;
/* These are used only for migration: incoming data arrives in
* these fields and is sanity checked in post_load before copying
* to the working data structures above.
*/
uint64_t *cpreg_vmstate_indexes;
uint64_t *cpreg_vmstate_values;
int32_t cpreg_vmstate_array_len;
/* The instance init functions for implementation-specific subclasses /* The instance init functions for implementation-specific subclasses
* set these fields to specify the implementation-dependent values of * set these fields to specify the implementation-dependent values of
...@@ -116,6 +139,7 @@ extern const struct VMStateDescription vmstate_arm_cpu; ...@@ -116,6 +139,7 @@ extern const struct VMStateDescription vmstate_arm_cpu;
#endif #endif
void register_cp_regs_for_features(ARMCPU *cpu); void register_cp_regs_for_features(ARMCPU *cpu);
void init_cpreg_list(ARMCPU *cpu);
void arm_cpu_do_interrupt(CPUState *cpu); void arm_cpu_do_interrupt(CPUState *cpu);
void arm_v7m_cpu_do_interrupt(CPUState *cpu); void arm_v7m_cpu_do_interrupt(CPUState *cpu);
......
...@@ -198,12 +198,15 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) ...@@ -198,12 +198,15 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
set_feature(env, ARM_FEATURE_VFP); set_feature(env, ARM_FEATURE_VFP);
} }
if (arm_feature(env, ARM_FEATURE_LPAE)) { if (arm_feature(env, ARM_FEATURE_LPAE)) {
set_feature(env, ARM_FEATURE_V7MP);
set_feature(env, ARM_FEATURE_PXN); set_feature(env, ARM_FEATURE_PXN);
} }
register_cp_regs_for_features(cpu); register_cp_regs_for_features(cpu);
arm_cpu_register_gdb_regs_for_features(cpu); arm_cpu_register_gdb_regs_for_features(cpu);
init_cpreg_list(cpu);
cpu_reset(CPU(cpu)); cpu_reset(CPU(cpu));
qemu_init_vcpu(env); qemu_init_vcpu(env);
...@@ -571,7 +574,6 @@ static void cortex_a15_initfn(Object *obj) ...@@ -571,7 +574,6 @@ static void cortex_a15_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_NEON); set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
set_feature(&cpu->env, ARM_FEATURE_ARM_DIV); set_feature(&cpu->env, ARM_FEATURE_ARM_DIV);
set_feature(&cpu->env, ARM_FEATURE_V7MP);
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_LPAE); set_feature(&cpu->env, ARM_FEATURE_LPAE);
......
...@@ -424,6 +424,43 @@ void armv7m_nvic_complete_irq(void *opaque, int irq); ...@@ -424,6 +424,43 @@ void armv7m_nvic_complete_irq(void *opaque, int irq);
(((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \ (((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \
((crm) << 7) | ((opc1) << 3) | (opc2)) ((crm) << 7) | ((opc1) << 3) | (opc2))
/* Note that these must line up with the KVM/ARM register
* ID field definitions (kvm.c will check this, but we
* can't just use the KVM defines here as the kvm headers
* are unavailable to non-KVM-specific files)
*/
#define CP_REG_SIZE_SHIFT 52
#define CP_REG_SIZE_MASK 0x00f0000000000000ULL
#define CP_REG_SIZE_U32 0x0020000000000000ULL
#define CP_REG_SIZE_U64 0x0030000000000000ULL
#define CP_REG_ARM 0x4000000000000000ULL
/* Convert a full 64 bit KVM register ID to the truncated 32 bit
* version used as a key for the coprocessor register hashtable
*/
static inline uint32_t kvm_to_cpreg_id(uint64_t kvmid)
{
uint32_t cpregid = kvmid;
if ((kvmid & CP_REG_SIZE_MASK) == CP_REG_SIZE_U64) {
cpregid |= (1 << 15);
}
return cpregid;
}
/* Convert a truncated 32 bit hashtable key into the full
* 64 bit KVM register ID.
*/
static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
{
uint64_t kvmid = cpregid & ~(1 << 15);
if (cpregid & (1 << 15)) {
kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM;
} else {
kvmid |= CP_REG_SIZE_U32 | CP_REG_ARM;
}
return kvmid;
}
/* ARMCPRegInfo type field bits. If the SPECIAL bit is set this is a /* ARMCPRegInfo type field bits. If the SPECIAL bit is set this is a
* special-behaviour cp reg and bits [15..8] indicate what behaviour * special-behaviour cp reg and bits [15..8] indicate what behaviour
* it has. Otherwise it is a simple cp reg, where CONST indicates that * it has. Otherwise it is a simple cp reg, where CONST indicates that
...@@ -434,19 +471,22 @@ void armv7m_nvic_complete_irq(void *opaque, int irq); ...@@ -434,19 +471,22 @@ void armv7m_nvic_complete_irq(void *opaque, int irq);
* a register definition to override a previous definition for the * a register definition to override a previous definition for the
* same (cp, is64, crn, crm, opc1, opc2) tuple: either the new or the * same (cp, is64, crn, crm, opc1, opc2) tuple: either the new or the
* old must have the OVERRIDE bit set. * old must have the OVERRIDE bit set.
* NO_MIGRATE indicates that this register should be ignored for migration;
* (eg because any state is accessed via some other coprocessor register).
*/ */
#define ARM_CP_SPECIAL 1 #define ARM_CP_SPECIAL 1
#define ARM_CP_CONST 2 #define ARM_CP_CONST 2
#define ARM_CP_64BIT 4 #define ARM_CP_64BIT 4
#define ARM_CP_SUPPRESS_TB_END 8 #define ARM_CP_SUPPRESS_TB_END 8
#define ARM_CP_OVERRIDE 16 #define ARM_CP_OVERRIDE 16
#define ARM_CP_NO_MIGRATE 32
#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8)) #define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8)) #define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
#define ARM_LAST_SPECIAL ARM_CP_WFI #define ARM_LAST_SPECIAL ARM_CP_WFI
/* Used only as a terminator for ARMCPRegInfo lists */ /* Used only as a terminator for ARMCPRegInfo lists */
#define ARM_CP_SENTINEL 0xffff #define ARM_CP_SENTINEL 0xffff
/* Mask of only the flag bits in a type field */ /* Mask of only the flag bits in a type field */
#define ARM_CP_FLAG_MASK 0x1f #define ARM_CP_FLAG_MASK 0x3f
/* Return true if cptype is a valid type field. This is used to try to /* Return true if cptype is a valid type field. This is used to try to
* catch errors where the sentinel has been accidentally left off the end * catch errors where the sentinel has been accidentally left off the end
...@@ -456,7 +496,7 @@ static inline bool cptype_valid(int cptype) ...@@ -456,7 +496,7 @@ static inline bool cptype_valid(int cptype)
{ {
return ((cptype & ~ARM_CP_FLAG_MASK) == 0) return ((cptype & ~ARM_CP_FLAG_MASK) == 0)
|| ((cptype & ARM_CP_SPECIAL) && || ((cptype & ARM_CP_SPECIAL) &&
(cptype <= ARM_LAST_SPECIAL)); ((cptype & ~ARM_CP_FLAG_MASK) <= ARM_LAST_SPECIAL));
} }
/* Access rights: /* Access rights:
...@@ -562,6 +602,19 @@ struct ARMCPRegInfo { ...@@ -562,6 +602,19 @@ struct ARMCPRegInfo {
* by fieldoffset. * by fieldoffset.
*/ */
CPWriteFn *writefn; CPWriteFn *writefn;
/* Function for doing a "raw" read; used when we need to copy
* coprocessor state to the kernel for KVM or out for
* migration. This only needs to be provided if there is also a
* readfn and it makes an access permission check.
*/
CPReadFn *raw_readfn;
/* Function for doing a "raw" write; used when we need to copy KVM
* kernel coprocessor state into userspace, or for inbound
* migration. This only needs to be provided if there is also a
* writefn and it makes an access permission check or masks out
* "unwritable" bits or has write-one-to-clear or similar behaviour.
*/
CPWriteFn *raw_writefn;
/* Function for resetting the register. If NULL, then reset will be done /* Function for resetting the register. If NULL, then reset will be done
* by writing resetvalue to the field specified in fieldoffset. If * by writing resetvalue to the field specified in fieldoffset. If
* fieldoffset is 0 then no reset will be done. * fieldoffset is 0 then no reset will be done.
...@@ -605,6 +658,38 @@ static inline bool cp_access_ok(CPUARMState *env, ...@@ -605,6 +658,38 @@ static inline bool cp_access_ok(CPUARMState *env,
return (ri->access >> ((arm_current_pl(env) * 2) + isread)) & 1; return (ri->access >> ((arm_current_pl(env) * 2) + isread)) & 1;
} }
/**
* write_list_to_cpustate
* @cpu: ARMCPU
*
* For each register listed in the ARMCPU cpreg_indexes list, write
* its value from the cpreg_values list into the ARMCPUState structure.
* This updates TCG's working data structures from KVM data or
* from incoming migration state.
*
* Returns: true if all register values were updated correctly,
* false if some register was unknown or could not be written.
* Note that we do not stop early on failure -- we will attempt
* writing all registers in the list.
*/
bool write_list_to_cpustate(ARMCPU *cpu);
/**
* write_cpustate_to_list:
* @cpu: ARMCPU
*
* For each register listed in the ARMCPU cpreg_indexes list, write
* its value from the ARMCPUState structure into the cpreg_values list.
* This is used to copy info from TCG's working data structures into
* KVM or for outbound migration.
*
* Returns: true if all register values were read correctly,
* false if some register was unknown or could not be read.
* Note that we do not stop early on failure -- we will attempt
* reading all registers in the list.
*/
bool write_cpustate_to_list(ARMCPU *cpu);
/* Does the core conform to the the "MicroController" profile. e.g. Cortex-M3. /* Does the core conform to the the "MicroController" profile. e.g. Cortex-M3.
Note the M in older cores (eg. ARM7TDMI) stands for Multiply. These are Note the M in older cores (eg. ARM7TDMI) stands for Multiply. These are
conventional cores (ie. Application or Realtime profile). */ conventional cores (ie. Application or Realtime profile). */
......
此差异已折叠。
/*
* QEMU KVM ARM specific function stubs
*
* Copyright Linaro Limited 2013
*
* Author: Peter Maydell <peter.maydell@linaro.org>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#include "qemu-common.h"
#include "kvm_arm.h"
bool write_kvmstate_to_list(ARMCPU *cpu)
{
abort();
}
bool write_list_to_kvmstate(ARMCPU *cpu)
{
abort();
}
...@@ -23,6 +23,15 @@ ...@@ -23,6 +23,15 @@
#include "cpu.h" #include "cpu.h"
#include "hw/arm/arm.h" #include "hw/arm/arm.h"
/* Check that cpu.h's idea of coprocessor fields matches KVM's */
#if (CP_REG_SIZE_SHIFT != KVM_REG_SIZE_SHIFT) || \
(CP_REG_SIZE_MASK != KVM_REG_SIZE_MASK) || \
(CP_REG_SIZE_U32 != KVM_REG_SIZE_U32) || \
(CP_REG_SIZE_U64 != KVM_REG_SIZE_U64) || \
(CP_REG_ARM != KVM_REG_ARM)
#error mismatch between cpu.h and KVM header definitions
#endif
const KVMCapabilityInfo kvm_arch_required_capabilities[] = { const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
KVM_CAP_LAST_INFO KVM_CAP_LAST_INFO
}; };
...@@ -41,12 +50,35 @@ unsigned long kvm_arch_vcpu_id(CPUState *cpu) ...@@ -41,12 +50,35 @@ unsigned long kvm_arch_vcpu_id(CPUState *cpu)
return cpu->cpu_index; return cpu->cpu_index;
} }
static bool reg_syncs_via_tuple_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:
case KVM_REG_ARM_VFP:
return false;
default:
return true;
}
}
static int compare_u64(const void *a, const void *b)
{
return *(uint64_t *)a - *(uint64_t *)b;
}
int kvm_arch_init_vcpu(CPUState *cs) int kvm_arch_init_vcpu(CPUState *cs)
{ {
struct kvm_vcpu_init init; struct kvm_vcpu_init init;
int ret; int i, ret, arraylen;
uint64_t v; uint64_t v;
struct kvm_one_reg r; struct kvm_one_reg r;
struct kvm_reg_list rl;
struct kvm_reg_list *rlp;
ARMCPU *cpu = ARM_CPU(cs);
init.target = KVM_ARM_TARGET_CORTEX_A15; init.target = KVM_ARM_TARGET_CORTEX_A15;
memset(init.features, 0, sizeof(init.features)); memset(init.features, 0, sizeof(init.features));
...@@ -65,6 +97,80 @@ int kvm_arch_init_vcpu(CPUState *cs) ...@@ -65,6 +97,80 @@ int kvm_arch_init_vcpu(CPUState *cs)
if (ret == -ENOENT) { if (ret == -ENOENT) {
return -EINVAL; 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;
}
/* Save a copy of the initial register values so that we can
* feed it back to the kernel on VCPU reset.
*/
cpu->cpreg_reset_values = g_memdup(cpu->cpreg_values,
cpu->cpreg_array_len *
sizeof(cpu->cpreg_values[0]));
out:
g_free(rlp);
return ret; return ret;
} }
...@@ -154,6 +260,78 @@ void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid) ...@@ -154,6 +260,78 @@ void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid)
QSLIST_INSERT_HEAD(&kvm_devices_head, kd, entries); QSLIST_INSERT_HEAD(&kvm_devices_head, kd, entries);
} }
bool write_kvmstate_to_list(ARMCPU *cpu)
{
CPUState *cs = CPU(cpu);
int i;
bool ok = true;
for (i = 0; i < cpu->cpreg_array_len; i++) {
struct kvm_one_reg r;
uint64_t regidx = cpu->cpreg_indexes[i];
uint32_t v32;
int ret;
r.id = regidx;
switch (regidx & KVM_REG_SIZE_MASK) {
case KVM_REG_SIZE_U32:
r.addr = (uintptr_t)&v32;
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r);
if (!ret) {
cpu->cpreg_values[i] = v32;
}
break;
case KVM_REG_SIZE_U64:
r.addr = (uintptr_t)(cpu->cpreg_values + i);
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r);
break;
default:
abort();
}
if (ret) {
ok = false;
}
}
return ok;
}
bool write_list_to_kvmstate(ARMCPU *cpu)
{
CPUState *cs = CPU(cpu);
int i;
bool ok = true;
for (i = 0; i < cpu->cpreg_array_len; i++) {
struct kvm_one_reg r;
uint64_t regidx = cpu->cpreg_indexes[i];
uint32_t v32;
int ret;
r.id = regidx;
switch (regidx & KVM_REG_SIZE_MASK) {
case KVM_REG_SIZE_U32:
v32 = cpu->cpreg_values[i];
r.addr = (uintptr_t)&v32;
break;
case KVM_REG_SIZE_U64:
r.addr = (uintptr_t)(cpu->cpreg_values + i);
break;
default:
abort();
}
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r);
if (ret) {
/* We might fail for "unknown register" and also for
* "you tried to set a register which is constant with
* a different value from what it actually contains".
*/
ok = false;
}
}
return ok;
}
typedef struct Reg { typedef struct Reg {
uint64_t id; uint64_t id;
int offset; int offset;
...@@ -166,17 +344,6 @@ typedef struct Reg { ...@@ -166,17 +344,6 @@ typedef struct Reg {
offsetof(CPUARMState, QEMUFIELD) \ offsetof(CPUARMState, QEMUFIELD) \
} }
#define CP15REG(CRN, CRM, OPC1, OPC2, QEMUFIELD) \
{ \
KVM_REG_ARM | KVM_REG_SIZE_U32 | \
(15 << KVM_REG_ARM_COPROC_SHIFT) | \
((CRN) << KVM_REG_ARM_32_CRN_SHIFT) | \
((CRM) << KVM_REG_ARM_CRM_SHIFT) | \
((OPC1) << KVM_REG_ARM_OPC1_SHIFT) | \
((OPC2) << KVM_REG_ARM_32_OPC2_SHIFT), \
offsetof(CPUARMState, QEMUFIELD) \
}
#define VFPSYSREG(R) \ #define VFPSYSREG(R) \
{ \ { \
KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP | \ KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP | \
...@@ -225,12 +392,6 @@ static const Reg regs[] = { ...@@ -225,12 +392,6 @@ static const Reg regs[] = {
COREREG(fiq_regs[7], banked_spsr[5]), COREREG(fiq_regs[7], banked_spsr[5]),
/* R15 */ /* R15 */
COREREG(usr_regs.uregs[15], regs[15]), COREREG(usr_regs.uregs[15], regs[15]),
/* A non-comprehensive set of cp15 registers.
* TODO: drive this from the cp_regs hashtable instead.
*/
CP15REG(1, 0, 0, 0, cp15.c1_sys), /* SCTLR */
CP15REG(2, 0, 0, 2, cp15.c2_control), /* TTBCR */
CP15REG(3, 0, 0, 0, cp15.c3), /* DACR */
/* VFP system registers */ /* VFP system registers */
VFPSYSREG(FPSID), VFPSYSREG(FPSID),
VFPSYSREG(MVFR1), VFPSYSREG(MVFR1),
...@@ -248,7 +409,6 @@ int kvm_arch_put_registers(CPUState *cs, int level) ...@@ -248,7 +409,6 @@ int kvm_arch_put_registers(CPUState *cs, int level)
int mode, bn; int mode, bn;
int ret, i; int ret, i;
uint32_t cpsr, fpscr; uint32_t cpsr, fpscr;
uint64_t ttbr;
/* Make sure the banked regs are properly set */ /* Make sure the banked regs are properly set */
mode = env->uncached_cpsr & CPSR_M; mode = env->uncached_cpsr & CPSR_M;
...@@ -282,26 +442,6 @@ int kvm_arch_put_registers(CPUState *cs, int level) ...@@ -282,26 +442,6 @@ int kvm_arch_put_registers(CPUState *cs, int level)
return ret; return ret;
} }
/* TTBR0: cp15 crm=2 opc1=0 */
ttbr = ((uint64_t)env->cp15.c2_base0_hi << 32) | env->cp15.c2_base0;
r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
(2 << KVM_REG_ARM_CRM_SHIFT) | (0 << KVM_REG_ARM_OPC1_SHIFT);
r.addr = (uintptr_t)(&ttbr);
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r);
if (ret) {
return ret;
}
/* TTBR1: cp15 crm=2 opc1=1 */
ttbr = ((uint64_t)env->cp15.c2_base1_hi << 32) | env->cp15.c2_base1;
r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
(2 << KVM_REG_ARM_CRM_SHIFT) | (1 << KVM_REG_ARM_OPC1_SHIFT);
r.addr = (uintptr_t)(&ttbr);
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r);
if (ret) {
return ret;
}
/* VFP registers */ /* VFP registers */
r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP; r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP;
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
...@@ -318,6 +458,31 @@ int kvm_arch_put_registers(CPUState *cs, int level) ...@@ -318,6 +458,31 @@ int kvm_arch_put_registers(CPUState *cs, int level)
fpscr = vfp_get_fpscr(env); fpscr = vfp_get_fpscr(env);
r.addr = (uintptr_t)&fpscr; r.addr = (uintptr_t)&fpscr;
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r); ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r);
if (ret) {
return ret;
}
/* Note that we do not call write_cpustate_to_list()
* here, so we are only writing the tuple list back to
* KVM. This is safe because nothing can change the
* CPUARMState cp15 fields (in particular gdb accesses cannot)
* and so there are no changes to sync. In fact syncing would
* be wrong at this point: for a constant register where TCG and
* KVM disagree about its value, the preceding write_list_to_cpustate()
* would not have had any effect on the CPUARMState value (since the
* register is read-only), and a write_cpustate_to_list() here would
* then try to write the TCG value back into KVM -- this would either
* fail or incorrectly change the value the guest sees.
*
* If we ever want to allow the user to modify cp15 registers via
* the gdb stub, we would need to be more clever here (for instance
* tracking the set of registers kvm_arch_get_registers() successfully
* managed to update the CPUARMState with, and only allowing those
* to be written back up into the kernel).
*/
if (!write_list_to_kvmstate(cpu)) {
return EINVAL;
}
return ret; return ret;
} }
...@@ -330,7 +495,6 @@ int kvm_arch_get_registers(CPUState *cs) ...@@ -330,7 +495,6 @@ int kvm_arch_get_registers(CPUState *cs)
int mode, bn; int mode, bn;
int ret, i; int ret, i;
uint32_t cpsr, fpscr; uint32_t cpsr, fpscr;
uint64_t ttbr;
for (i = 0; i < ARRAY_SIZE(regs); i++) { for (i = 0; i < ARRAY_SIZE(regs); i++) {
r.id = regs[i].id; r.id = regs[i].id;
...@@ -351,28 +515,6 @@ int kvm_arch_get_registers(CPUState *cs) ...@@ -351,28 +515,6 @@ int kvm_arch_get_registers(CPUState *cs)
} }
cpsr_write(env, cpsr, 0xffffffff); cpsr_write(env, cpsr, 0xffffffff);
/* TTBR0: cp15 crm=2 opc1=0 */
r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
(2 << KVM_REG_ARM_CRM_SHIFT) | (0 << KVM_REG_ARM_OPC1_SHIFT);
r.addr = (uintptr_t)(&ttbr);
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r);
if (ret) {
return ret;
}
env->cp15.c2_base0_hi = ttbr >> 32;
env->cp15.c2_base0 = ttbr;
/* TTBR1: cp15 crm=2 opc1=1 */
r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) |
(2 << KVM_REG_ARM_CRM_SHIFT) | (1 << KVM_REG_ARM_OPC1_SHIFT);
r.addr = (uintptr_t)(&ttbr);
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r);
if (ret) {
return ret;
}
env->cp15.c2_base1_hi = ttbr >> 32;
env->cp15.c2_base1 = ttbr;
/* Make sure the current mode regs are properly set */ /* Make sure the current mode regs are properly set */
mode = env->uncached_cpsr & CPSR_M; mode = env->uncached_cpsr & CPSR_M;
bn = bank_number(mode); bn = bank_number(mode);
...@@ -385,15 +527,6 @@ int kvm_arch_get_registers(CPUState *cs) ...@@ -385,15 +527,6 @@ int kvm_arch_get_registers(CPUState *cs)
env->regs[14] = env->banked_r14[bn]; env->regs[14] = env->banked_r14[bn];
env->spsr = env->banked_spsr[bn]; env->spsr = env->banked_spsr[bn];
/* The main GET_ONE_REG loop above set c2_control, but we need to
* update some extra cached precomputed values too.
* When this is driven from the cp_regs hashtable then this ugliness
* can disappear because we'll use the access function which sets
* these values automatically.
*/
env->cp15.c2_mask = ~(0xffffffffu >> env->cp15.c2_control);
env->cp15.c2_base_mask = ~(0x3fffu >> env->cp15.c2_control);
/* VFP registers */ /* VFP registers */
r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP; r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP;
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
...@@ -414,6 +547,14 @@ int kvm_arch_get_registers(CPUState *cs) ...@@ -414,6 +547,14 @@ int kvm_arch_get_registers(CPUState *cs)
} }
vfp_set_fpscr(env, fpscr); vfp_set_fpscr(env, fpscr);
if (!write_kvmstate_to_list(cpu)) {
return EINVAL;
}
/* Note that it's OK to have registers which aren't in CPUState,
* so we can ignore a failure return here.
*/
write_list_to_cpustate(cpu);
return 0; return 0;
} }
...@@ -432,6 +573,15 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) ...@@ -432,6 +573,15 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
void kvm_arch_reset_vcpu(CPUState *cs) void kvm_arch_reset_vcpu(CPUState *cs)
{ {
/* Feed the kernel back its initial register state */
ARMCPU *cpu = ARM_CPU(cs);
memmove(cpu->cpreg_values, cpu->cpreg_reset_values,
cpu->cpreg_array_len * sizeof(cpu->cpreg_values[0]));
if (!write_list_to_kvmstate(cpu)) {
abort();
}
} }
bool kvm_arch_stop_on_emulation_error(CPUState *cs) bool kvm_arch_stop_on_emulation_error(CPUState *cs)
......
...@@ -29,4 +29,37 @@ ...@@ -29,4 +29,37 @@
*/ */
void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid); void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid);
/**
* write_list_to_kvmstate:
* @cpu: ARMCPU
*
* For each register listed in the ARMCPU cpreg_indexes list, write
* its value from the cpreg_values list into the kernel (via ioctl).
* This updates KVM's working data structures from TCG data or
* from incoming migration state.
*
* Returns: true if all register values were updated correctly,
* false if some register was unknown to the kernel or could not
* be written (eg constant register with the wrong value).
* Note that we do not stop early on failure -- we will attempt
* writing all registers in the list.
*/
bool write_list_to_kvmstate(ARMCPU *cpu);
/**
* write_kvmstate_to_list:
* @cpu: ARMCPU
*
* For each register listed in the ARMCPU cpreg_indexes list, write
* its value from the kernel into the cpreg_values list. This is used to
* copy info from KVM's working data structures into TCG or
* for outbound migration.
*
* Returns: true if all register values were read correctly,
* false if some register was unknown or could not be read.
* Note that we do not stop early on failure -- we will attempt
* reading all registers in the list.
*/
bool write_kvmstate_to_list(ARMCPU *cpu);
#endif #endif
#include "hw/hw.h" #include "hw/hw.h"
#include "hw/boards.h" #include "hw/boards.h"
#include "sysemu/kvm.h"
#include "kvm_arm.h"
static bool vfp_needed(void *opaque) static bool vfp_needed(void *opaque)
{ {
...@@ -148,11 +150,83 @@ static const VMStateInfo vmstate_cpsr = { ...@@ -148,11 +150,83 @@ static const VMStateInfo vmstate_cpsr = {
.put = put_cpsr, .put = put_cpsr,
}; };
static void cpu_pre_save(void *opaque)
{
ARMCPU *cpu = opaque;
if (kvm_enabled()) {
if (!write_kvmstate_to_list(cpu)) {
/* This should never fail */
abort();
}
} else {
if (!write_cpustate_to_list(cpu)) {
/* This should never fail. */
abort();
}
}
cpu->cpreg_vmstate_array_len = cpu->cpreg_array_len;
memcpy(cpu->cpreg_vmstate_indexes, cpu->cpreg_indexes,
cpu->cpreg_array_len * sizeof(uint64_t));
memcpy(cpu->cpreg_vmstate_values, cpu->cpreg_values,
cpu->cpreg_array_len * sizeof(uint64_t));
}
static int cpu_post_load(void *opaque, int version_id)
{
ARMCPU *cpu = opaque;
int i, v;
/* Update the values list from the incoming migration data.
* Anything in the incoming data which we don't know about is
* a migration failure; anything we know about but the incoming
* data doesn't specify retains its current (reset) value.
* The indexes list remains untouched -- we only inspect the
* incoming migration index list so we can match the values array
* entries with the right slots in our own values array.
*/
for (i = 0, v = 0; i < cpu->cpreg_array_len
&& v < cpu->cpreg_vmstate_array_len; i++) {
if (cpu->cpreg_vmstate_indexes[v] > cpu->cpreg_indexes[i]) {
/* register in our list but not incoming : skip it */
continue;
}
if (cpu->cpreg_vmstate_indexes[v] < cpu->cpreg_indexes[i]) {
/* register in their list but not ours: fail migration */
return -1;
}
/* matching register, copy the value over */
cpu->cpreg_values[i] = cpu->cpreg_vmstate_values[v];
v++;
}
if (kvm_enabled()) {
if (!write_list_to_kvmstate(cpu)) {
return -1;
}
/* Note that it's OK for the TCG side not to know about
* every register in the list; KVM is authoritative if
* we're using it.
*/
write_list_to_cpustate(cpu);
} else {
if (!write_list_to_cpustate(cpu)) {
return -1;
}
}
return 0;
}
const VMStateDescription vmstate_arm_cpu = { const VMStateDescription vmstate_arm_cpu = {
.name = "cpu", .name = "cpu",
.version_id = 11, .version_id = 12,
.minimum_version_id = 11, .minimum_version_id = 12,
.minimum_version_id_old = 11, .minimum_version_id_old = 12,
.pre_save = cpu_pre_save,
.post_load = cpu_post_load,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT32_ARRAY(env.regs, ARMCPU, 16), VMSTATE_UINT32_ARRAY(env.regs, ARMCPU, 16),
{ {
...@@ -169,50 +243,16 @@ const VMStateDescription vmstate_arm_cpu = { ...@@ -169,50 +243,16 @@ const VMStateDescription vmstate_arm_cpu = {
VMSTATE_UINT32_ARRAY(env.banked_r14, ARMCPU, 6), VMSTATE_UINT32_ARRAY(env.banked_r14, ARMCPU, 6),
VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5), VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5),
VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5), VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5),
VMSTATE_UINT32(env.cp15.c0_cpuid, ARMCPU), /* The length-check must come before the arrays to avoid
VMSTATE_UINT32(env.cp15.c0_cssel, ARMCPU), * incoming data possibly overflowing the array.
VMSTATE_UINT32(env.cp15.c1_sys, ARMCPU), */
VMSTATE_UINT32(env.cp15.c1_coproc, ARMCPU), VMSTATE_INT32_LE(cpreg_vmstate_array_len, ARMCPU),
VMSTATE_UINT32(env.cp15.c1_xscaleauxcr, ARMCPU), VMSTATE_VARRAY_INT32(cpreg_vmstate_indexes, ARMCPU,
VMSTATE_UINT32(env.cp15.c1_scr, ARMCPU), cpreg_vmstate_array_len,
VMSTATE_UINT32(env.cp15.c2_base0, ARMCPU), 0, vmstate_info_uint64, uint64_t),
VMSTATE_UINT32(env.cp15.c2_base0_hi, ARMCPU), VMSTATE_VARRAY_INT32(cpreg_vmstate_values, ARMCPU,
VMSTATE_UINT32(env.cp15.c2_base1, ARMCPU), cpreg_vmstate_array_len,
VMSTATE_UINT32(env.cp15.c2_base1_hi, ARMCPU), 0, vmstate_info_uint64, uint64_t),
VMSTATE_UINT32(env.cp15.c2_control, ARMCPU),
VMSTATE_UINT32(env.cp15.c2_mask, ARMCPU),
VMSTATE_UINT32(env.cp15.c2_base_mask, ARMCPU),
VMSTATE_UINT32(env.cp15.c2_data, ARMCPU),
VMSTATE_UINT32(env.cp15.c2_insn, ARMCPU),
VMSTATE_UINT32(env.cp15.c3, ARMCPU),
VMSTATE_UINT32(env.cp15.c5_insn, ARMCPU),
VMSTATE_UINT32(env.cp15.c5_data, ARMCPU),
VMSTATE_UINT32_ARRAY(env.cp15.c6_region, ARMCPU, 8),
VMSTATE_UINT32(env.cp15.c6_insn, ARMCPU),
VMSTATE_UINT32(env.cp15.c6_data, ARMCPU),
VMSTATE_UINT32(env.cp15.c7_par, ARMCPU),
VMSTATE_UINT32(env.cp15.c7_par_hi, ARMCPU),
VMSTATE_UINT32(env.cp15.c9_insn, ARMCPU),
VMSTATE_UINT32(env.cp15.c9_data, ARMCPU),
VMSTATE_UINT32(env.cp15.c9_pmcr, ARMCPU),
VMSTATE_UINT32(env.cp15.c9_pmcnten, ARMCPU),
VMSTATE_UINT32(env.cp15.c9_pmovsr, ARMCPU),
VMSTATE_UINT32(env.cp15.c9_pmxevtyper, ARMCPU),
VMSTATE_UINT32(env.cp15.c9_pmuserenr, ARMCPU),
VMSTATE_UINT32(env.cp15.c9_pminten, ARMCPU),
VMSTATE_UINT32(env.cp15.c13_fcse, ARMCPU),
VMSTATE_UINT32(env.cp15.c13_context, ARMCPU),
VMSTATE_UINT32(env.cp15.c13_tls1, ARMCPU),
VMSTATE_UINT32(env.cp15.c13_tls2, ARMCPU),
VMSTATE_UINT32(env.cp15.c13_tls3, ARMCPU),
VMSTATE_UINT32(env.cp15.c15_cpar, ARMCPU),
VMSTATE_UINT32(env.cp15.c15_ticonfig, ARMCPU),
VMSTATE_UINT32(env.cp15.c15_i_max, ARMCPU),
VMSTATE_UINT32(env.cp15.c15_i_min, ARMCPU),
VMSTATE_UINT32(env.cp15.c15_threadid, ARMCPU),
VMSTATE_UINT32(env.cp15.c15_power_control, ARMCPU),
VMSTATE_UINT32(env.cp15.c15_diagnostic, ARMCPU),
VMSTATE_UINT32(env.cp15.c15_power_diagnostic, ARMCPU),
VMSTATE_UINT32(env.exclusive_addr, ARMCPU), VMSTATE_UINT32(env.exclusive_addr, ARMCPU),
VMSTATE_UINT32(env.exclusive_val, ARMCPU), VMSTATE_UINT32(env.exclusive_val, ARMCPU),
VMSTATE_UINT32(env.exclusive_high, ARMCPU), VMSTATE_UINT32(env.exclusive_high, ARMCPU),
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册