target-arm:
* Fix broken migration on AArch64 KVM * Fix minor memory leaks in virt, vexpress, highbank * Honour requested filename when loading highbank rom image -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJVHCWBAAoJEDwlJe0UNgze0GIP/jVlkjJ3MLGlWgAlRKzKWKep WgKDu3FUI44/ErkBbzUaq7e/OOQD9T609sjpH57KttacOybTQG4qy551NmxeDLLe EJvMrM13U9isyrVSTsDtk4VLteUR/06ubA5R7z7mBXAwCGkb2ovnlRm9V2zVc+El ZBZ47SdjQzZpsmp7NTqDQjuDDkkaed1RPL015fEy/Hdv5l7ymC+O8EPuj+Cu69w/ oip+leqewiC0J7dO5ppXfmwyoeDI+Mr0seXDm5A+EL9fOT2LGEjTL8M/AIcgESvu aN0mt5XvaeHgS/BEMSWNjc6vCN9YaJz7gtd2MeC+BjrLzTTVpOmzGunB6iwbZz/v EsUNX7ED5aTdszaQezHqRQf7Rx1BuTpQ9wJ7nh6PNO0JLwPaoqjTBSIVmWyiZz9y uGFNbny2uwJJOMZxOJBlmmlUO9S50ZZ6mjTPXYhaetZWdETpPegaVRQIaGNcxsQT /hRRYR90/S+BezcaLo8FReTLj/JuZCNJlT0mLcjzgub9Dt061cJUNN1N+WS4uOPx ecsYHA/ZUCvWh+1g2AczeeT8SoR+bMZLVCrHljBLtH+q/o7L4IiQP9rXqZx0qeRy rnrTQC5OLj3pnoZ7uE6udv4w0pK05s345C4EpKZgVON+HLmR0Wo/WswZ9Iqcqj9n 9CtrxY2OWzZf3vTLBTsi =f87s -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20150401' 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>
This commit is contained in:
commit
289494da25
|
@ -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);
|
||||
|
|
|
@ -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 "
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 "
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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. */
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -356,6 +356,8 @@ int kvm_arch_put_registers(CPUState *cs, int level)
|
|||
return EINVAL;
|
||||
}
|
||||
|
||||
kvm_arm_sync_mpstate_to_kvm(cpu);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <linux/kvm.h>
|
||||
|
||||
#include "config-host.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
@ -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;
|
||||
|
@ -198,22 +207,70 @@ 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, ®);
|
||||
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, ®);
|
||||
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, ®);
|
||||
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, ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!write_list_to_kvmstate(cpu)) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* TODO:
|
||||
* FP state
|
||||
*/
|
||||
kvm_arm_sync_mpstate_to_kvm(cpu);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -221,6 +278,8 @@ 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;
|
||||
|
||||
|
@ -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, ®);
|
||||
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, ®);
|
||||
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, ®);
|
||||
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, ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
vfp_set_fpcr(env, fpr);
|
||||
|
||||
if (!write_kvmstate_to_list(cpu)) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -162,6 +162,23 @@ typedef struct ARMHostCPUClass {
|
|||
*/
|
||||
bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc);
|
||||
|
||||
|
||||
/**
|
||||
* kvm_arm_sync_mpstate_to_kvm
|
||||
* @cpu: ARMCPU
|
||||
*
|
||||
* If supported set the KVM MP_STATE based on QEMU's model.
|
||||
*/
|
||||
int kvm_arm_sync_mpstate_to_kvm(ARMCPU *cpu);
|
||||
|
||||
/**
|
||||
* kvm_arm_sync_mpstate_to_qemu
|
||||
* @cpu: ARMCPU
|
||||
*
|
||||
* If supported get the MP_STATE from KVM and store in QEMU's model.
|
||||
*/
|
||||
int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue