Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-2…
Browse files Browse the repository at this point in the history
…0150401' into staging

target-arm:
 * Fix broken migration on AArch64 KVM
 * Fix minor memory leaks in virt, vexpress, highbank
 * Honour requested filename when loading highbank rom image

# gpg: Signature made Wed Apr  1 18:06:09 2015 BST using RSA key ID 14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"

* remotes/pmaydell/tags/pull-target-arm-20150401:
  target-arm: kvm64 fix save/restore of SPSR regs
  target-arm: kvm64 sync FP register state
  hw/intc: arm_gic_kvm.c restore config first
  target-arm: kvm: save/restore mp state
  target-arm: Store SPSR_EL1 state in banked_spsr[1] (SPSR_svc)
  hw/arm/virt: Fix memory leak reported by Coverity
  hw/arm/vexpress: Fix memory leak reported by Coverity
  hw/arm/highbank: Fix resource leak and wrong image loading

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Apr 1, 2015
2 parents fde069f + 25b9fb1 commit 289494d
Show file tree
Hide file tree
Showing 11 changed files with 207 additions and 15 deletions.
3 changes: 1 addition & 2 deletions hw/arm/highbank.c
Expand Up @@ -278,8 +278,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
if (bios_name != NULL) {
sysboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
if (sysboot_filename != NULL) {
uint32_t filesize = get_image_size(sysboot_filename);
if (load_image_targphys("sysram.bin", 0xfff88000, filesize) < 0) {
if (load_image_targphys(sysboot_filename, 0xfff88000, 0x8000) < 0) {
hw_error("Unable to load %s\n", bios_name);
}
g_free(sysboot_filename);
Expand Down
11 changes: 9 additions & 2 deletions hw/arm/vexpress.c
Expand Up @@ -563,6 +563,7 @@ static void vexpress_common_init(MachineState *machine)
*/
if (bios_name) {
char *fn;
int image_size;

if (drive_get(IF_PFLASH, 0, 0)) {
error_report("The contents of the first flash device may be "
Expand All @@ -571,8 +572,14 @@ static void vexpress_common_init(MachineState *machine)
exit(1);
}
fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
if (!fn || load_image_targphys(fn, map[VE_NORFLASH0],
VEXPRESS_FLASH_SIZE) < 0) {
if (!fn) {
error_report("Could not find ROM image '%s'", bios_name);
exit(1);
}
image_size = load_image_targphys(fn, map[VE_NORFLASH0],
VEXPRESS_FLASH_SIZE);
g_free(fn);
if (image_size < 0) {
error_report("Could not load ROM image '%s'", bios_name);
exit(1);
}
Expand Down
9 changes: 8 additions & 1 deletion hw/arm/virt.c
Expand Up @@ -553,6 +553,7 @@ static void create_flash(const VirtBoardInfo *vbi)

if (bios_name) {
char *fn;
int image_size;

if (drive_get(IF_PFLASH, 0, 0)) {
error_report("The contents of the first flash device may be "
Expand All @@ -561,7 +562,13 @@ static void create_flash(const VirtBoardInfo *vbi)
exit(1);
}
fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
if (!fn || load_image_targphys(fn, flashbase, flashsize) < 0) {
if (!fn) {
error_report("Could not find ROM image '%s'", bios_name);
exit(1);
}
image_size = load_image_targphys(fn, flashbase, flashsize);
g_free(fn);
if (image_size < 0) {
error_report("Could not load ROM image '%s'", bios_name);
exit(1);
}
Expand Down
7 changes: 5 additions & 2 deletions hw/intc/arm_gic_kvm.c
Expand Up @@ -370,6 +370,11 @@ static void kvm_arm_gic_put(GICState *s)
* the appropriate CPU interfaces in the kernel) */
kvm_dist_put(s, 0x800, 8, s->num_irq, translate_targets);

/* irq_state[n].trigger -> GICD_ICFGRn
* (restore configuration registers before pending IRQs so we treat
* level/edge correctly) */
kvm_dist_put(s, 0xc00, 2, s->num_irq, translate_trigger);

/* irq_state[n].pending + irq_state[n].level -> GICD_ISPENDRn */
kvm_dist_put(s, 0x280, 1, s->num_irq, translate_clear);
kvm_dist_put(s, 0x200, 1, s->num_irq, translate_pending);
Expand All @@ -378,8 +383,6 @@ static void kvm_arm_gic_put(GICState *s)
kvm_dist_put(s, 0x380, 1, s->num_irq, translate_clear);
kvm_dist_put(s, 0x300, 1, s->num_irq, translate_active);

/* irq_state[n].trigger -> GICD_ICFRn */
kvm_dist_put(s, 0xc00, 2, s->num_irq, translate_trigger);

/* s->priorityX[irq] -> ICD_IPRIORITYRn */
kvm_dist_put(s, 0x400, 8, s->num_irq, translate_priority);
Expand Down
2 changes: 1 addition & 1 deletion target-arm/helper-a64.c
Expand Up @@ -523,7 +523,7 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
aarch64_save_sp(env, arm_current_el(env));
env->elr_el[new_el] = env->pc;
} else {
env->banked_spsr[0] = cpsr_read(env);
env->banked_spsr[aarch64_banked_spsr_index(new_el)] = cpsr_read(env);
if (!env->thumb) {
env->cp15.esr_el[new_el] |= 1 << 25;
}
Expand Down
2 changes: 1 addition & 1 deletion target-arm/helper.c
Expand Up @@ -2438,7 +2438,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
{ .name = "SPSR_EL1", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_ALIAS,
.opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 0,
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[0]) },
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[1]) },
/* We rely on the access checks not allowing the guest to write to the
* state field when SPSel indicates that it's being used as the stack
* pointer.
Expand Down
5 changes: 4 additions & 1 deletion target-arm/internals.h
Expand Up @@ -82,11 +82,14 @@ static inline void arm_log_exception(int idx)

/*
* For AArch64, map a given EL to an index in the banked_spsr array.
* Note that this mapping and the AArch32 mapping defined in bank_number()
* must agree such that the AArch64<->AArch32 SPSRs have the architecturally
* mandated mapping between each other.
*/
static inline unsigned int aarch64_banked_spsr_index(unsigned int el)
{
static const unsigned int map[4] = {
[1] = 0, /* EL1. */
[1] = 1, /* EL1. */
[2] = 6, /* EL2. */
[3] = 7, /* EL3. */
};
Expand Down
44 changes: 44 additions & 0 deletions target-arm/kvm.c
Expand Up @@ -28,6 +28,8 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
KVM_CAP_LAST_INFO
};

static bool cap_has_mp_state;

int kvm_arm_vcpu_init(CPUState *cs)
{
ARMCPU *cpu = ARM_CPU(cs);
Expand Down Expand Up @@ -157,6 +159,8 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
*/
kvm_async_interrupts_allowed = true;

cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);

type_register_static(&host_arm_cpu_type_info);

return 0;
Expand Down Expand Up @@ -458,6 +462,46 @@ void kvm_arm_reset_vcpu(ARMCPU *cpu)
}
}

/*
* Update KVM's MP_STATE based on what QEMU thinks it is
*/
int kvm_arm_sync_mpstate_to_kvm(ARMCPU *cpu)
{
if (cap_has_mp_state) {
struct kvm_mp_state mp_state = {
.mp_state =
cpu->powered_off ? KVM_MP_STATE_STOPPED : KVM_MP_STATE_RUNNABLE
};
int ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MP_STATE, &mp_state);
if (ret) {
fprintf(stderr, "%s: failed to set MP_STATE %d/%s\n",
__func__, ret, strerror(-ret));
return -1;
}
}

return 0;
}

/*
* Sync the KVM MP_STATE into QEMU
*/
int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu)
{
if (cap_has_mp_state) {
struct kvm_mp_state mp_state;
int ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MP_STATE, &mp_state);
if (ret) {
fprintf(stderr, "%s: failed to get MP_STATE %d/%s\n",
__func__, ret, strerror(-ret));
abort();
}
cpu->powered_off = (mp_state.mp_state == KVM_MP_STATE_STOPPED);
}

return 0;
}

void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
{
}
Expand Down
4 changes: 4 additions & 0 deletions target-arm/kvm32.c
Expand Up @@ -356,6 +356,8 @@ int kvm_arch_put_registers(CPUState *cs, int level)
return EINVAL;
}

kvm_arm_sync_mpstate_to_kvm(cpu);

return ret;
}

Expand Down Expand Up @@ -427,5 +429,7 @@ int kvm_arch_get_registers(CPUState *cs)
*/
write_list_to_cpustate(cpu);

kvm_arm_sync_mpstate_to_qemu(cpu);

return 0;
}
118 changes: 113 additions & 5 deletions target-arm/kvm64.c
Expand Up @@ -15,6 +15,7 @@

#include <linux/kvm.h>

#include "config-host.h"
#include "qemu-common.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
Expand Down Expand Up @@ -126,12 +127,20 @@ bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx)
#define AARCH64_CORE_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x))

#define AARCH64_SIMD_CORE_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U128 | \
KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x))

#define AARCH64_SIMD_CTRL_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U32 | \
KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x))

int kvm_arch_put_registers(CPUState *cs, int level)
{
struct kvm_one_reg reg;
uint32_t fpr;
uint64_t val;
int i;
int ret;
unsigned int el;

ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
Expand Down Expand Up @@ -198,29 +207,79 @@ int kvm_arch_put_registers(CPUState *cs, int level)
return ret;
}

/* Saved Program State Registers
*
* Before we restore from the banked_spsr[] array we need to
* ensure that any modifications to env->spsr are correctly
* reflected in the banks.
*/
el = arm_current_el(env);
if (el > 0 && !is_a64(env)) {
i = bank_number(env->uncached_cpsr & CPSR_M);
env->banked_spsr[i] = env->spsr;
}

/* KVM 0-4 map to QEMU banks 1-5 */
for (i = 0; i < KVM_NR_SPSR; i++) {
reg.id = AARCH64_CORE_REG(spsr[i]);
reg.addr = (uintptr_t) &env->banked_spsr[i - 1];
reg.addr = (uintptr_t) &env->banked_spsr[i + 1];
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
if (ret) {
return ret;
}
}

/* Advanced SIMD and FP registers
* We map Qn = regs[2n+1]:regs[2n]
*/
for (i = 0; i < 32; i++) {
int rd = i << 1;
uint64_t fp_val[2];
#ifdef HOST_WORDS_BIGENDIAN
fp_val[0] = env->vfp.regs[rd + 1];
fp_val[1] = env->vfp.regs[rd];
#else
fp_val[1] = env->vfp.regs[rd + 1];
fp_val[0] = env->vfp.regs[rd];
#endif
reg.id = AARCH64_SIMD_CORE_REG(fp_regs.vregs[i]);
reg.addr = (uintptr_t)(&fp_val);
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
if (ret) {
return ret;
}
}

reg.addr = (uintptr_t)(&fpr);
fpr = vfp_get_fpsr(env);
reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpsr);
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
if (ret) {
return ret;
}

fpr = vfp_get_fpcr(env);
reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpcr);
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
if (ret) {
return ret;
}

if (!write_list_to_kvmstate(cpu)) {
return EINVAL;
}

/* TODO:
* FP state
*/
kvm_arm_sync_mpstate_to_kvm(cpu);

return ret;
}

int kvm_arch_get_registers(CPUState *cs)
{
struct kvm_one_reg reg;
uint64_t val;
uint32_t fpr;
unsigned int el;
int i;
int ret;

Expand Down Expand Up @@ -293,15 +352,62 @@ int kvm_arch_get_registers(CPUState *cs)
return ret;
}

/* Fetch the SPSR registers
*
* KVM SPSRs 0-4 map to QEMU banks 1-5
*/
for (i = 0; i < KVM_NR_SPSR; i++) {
reg.id = AARCH64_CORE_REG(spsr[i]);
reg.addr = (uintptr_t) &env->banked_spsr[i - 1];
reg.addr = (uintptr_t) &env->banked_spsr[i + 1];
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
if (ret) {
return ret;
}
}

el = arm_current_el(env);
if (el > 0 && !is_a64(env)) {
i = bank_number(env->uncached_cpsr & CPSR_M);
env->spsr = env->banked_spsr[i];
}

/* Advanced SIMD and FP registers
* We map Qn = regs[2n+1]:regs[2n]
*/
for (i = 0; i < 32; i++) {
uint64_t fp_val[2];
reg.id = AARCH64_SIMD_CORE_REG(fp_regs.vregs[i]);
reg.addr = (uintptr_t)(&fp_val);
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
if (ret) {
return ret;
} else {
int rd = i << 1;
#ifdef HOST_WORDS_BIGENDIAN
env->vfp.regs[rd + 1] = fp_val[0];
env->vfp.regs[rd] = fp_val[1];
#else
env->vfp.regs[rd + 1] = fp_val[1];
env->vfp.regs[rd] = fp_val[0];
#endif
}
}

reg.addr = (uintptr_t)(&fpr);
reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpsr);
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
if (ret) {
return ret;
}
vfp_set_fpsr(env, fpr);

reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpcr);
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
if (ret) {
return ret;
}
vfp_set_fpcr(env, fpr);

if (!write_kvmstate_to_list(cpu)) {
return EINVAL;
}
Expand All @@ -310,6 +416,8 @@ int kvm_arch_get_registers(CPUState *cs)
*/
write_list_to_cpustate(cpu);

kvm_arm_sync_mpstate_to_qemu(cpu);

/* TODO: other registers */
return ret;
}

0 comments on commit 289494d

Please sign in to comment.