diff options
Diffstat (limited to 'target/arm/kvm.c')
| -rw-r--r-- | target/arm/kvm.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 6672344855..c1ec6654ca 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -900,6 +900,58 @@ bool write_kvmstate_to_list(ARMCPU *cpu) return ok; } +/* pretty-print a KVM register */ +#define CP_REG_ARM64_SYSREG_OP(_reg, _op) \ + ((uint8_t)((_reg & CP_REG_ARM64_SYSREG_ ## _op ## _MASK) >> \ + CP_REG_ARM64_SYSREG_ ## _op ## _SHIFT)) + +static gchar *kvm_print_sve_register_name(uint64_t regidx) +{ + uint16_t sve_reg = regidx & 0x000000000000ffff; + + if (regidx == KVM_REG_ARM64_SVE_VLS) { + return g_strdup_printf("SVE VLS"); + } + /* zreg, preg, ffr */ + switch (sve_reg & 0xfc00) { + case 0: + return g_strdup_printf("SVE zreg n:%d slice:%d", + (sve_reg & 0x03e0) >> 5, sve_reg & 0x001f); + case 0x04: + return g_strdup_printf("SVE preg n:%d slice:%d", + (sve_reg & 0x01e0) >> 5, sve_reg & 0x001f); + case 0x06: + return g_strdup_printf("SVE ffr slice:%d", sve_reg & 0x001f); + default: + return g_strdup_printf("SVE ???"); + } +} + +static gchar *kvm_print_register_name(uint64_t regidx) +{ + switch ((regidx & KVM_REG_ARM_COPROC_MASK)) { + case KVM_REG_ARM_CORE: + return g_strdup_printf("core reg %"PRIx64, regidx); + case KVM_REG_ARM_DEMUX: + return g_strdup_printf("demuxed reg %"PRIx64, regidx); + case KVM_REG_ARM64_SYSREG: + return g_strdup_printf("op0:%d op1:%d crn:%d crm:%d op2:%d", + CP_REG_ARM64_SYSREG_OP(regidx, OP0), + CP_REG_ARM64_SYSREG_OP(regidx, OP1), + CP_REG_ARM64_SYSREG_OP(regidx, CRN), + CP_REG_ARM64_SYSREG_OP(regidx, CRM), + CP_REG_ARM64_SYSREG_OP(regidx, OP2)); + case KVM_REG_ARM_FW: + return g_strdup_printf("fw reg %d", (int)(regidx & 0xffff)); + case KVM_REG_ARM64_SVE: + return kvm_print_sve_register_name(regidx); + case KVM_REG_ARM_FW_FEAT_BMAP: + return g_strdup_printf("fw feat reg %d", (int)(regidx & 0xffff)); + default: + return g_strdup_printf("%"PRIx64, regidx); + } +} + bool write_list_to_kvmstate(ARMCPU *cpu, int level) { CPUState *cs = CPU(cpu); @@ -927,11 +979,45 @@ bool write_list_to_kvmstate(ARMCPU *cpu, int level) g_assert_not_reached(); } if (ret) { + gchar *reg_str = kvm_print_register_name(regidx); + /* 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; + switch (ret) { + case -ENOENT: + error_report("Could not set register %s: unknown to KVM", + reg_str); + break; + case -EINVAL: + if ((regidx & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U32) { + if (!kvm_get_one_reg(cs, regidx, &v32)) { + error_report("Could not set register %s to %x (is %x)", + reg_str, (uint32_t)cpu->cpreg_values[i], + v32); + } else { + error_report("Could not set register %s to %x", + reg_str, (uint32_t)cpu->cpreg_values[i]); + } + } else /* U64 */ { + uint64_t v64; + + if (!kvm_get_one_reg(cs, regidx, &v64)) { + error_report("Could not set register %s to %"PRIx64" (is %"PRIx64")", + reg_str, cpu->cpreg_values[i], v64); + } else { + error_report("Could not set register %s to %"PRIx64, + reg_str, cpu->cpreg_values[i]); + } + } + break; + default: + error_report("Could not set register %s: %s", + reg_str, strerror(-ret)); + } + g_free(reg_str); } } return ok; |