diff options
Diffstat (limited to 'target-arm/cpu.c')
-rw-r--r-- | target-arm/cpu.c | 33 |
1 files changed, 32 insertions, 1 deletions
diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 285947f911..d38af747ac 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -113,7 +113,14 @@ static void arm_cpu_reset(CPUState *s) /* and to the FP/Neon instructions */ env->cp15.c1_coproc = deposit64(env->cp15.c1_coproc, 20, 2, 3); #else - env->pstate = PSTATE_MODE_EL1h; + /* Reset into the highest available EL */ + if (arm_feature(env, ARM_FEATURE_EL3)) { + env->pstate = PSTATE_MODE_EL3h; + } else if (arm_feature(env, ARM_FEATURE_EL2)) { + env->pstate = PSTATE_MODE_EL2h; + } else { + env->pstate = PSTATE_MODE_EL1h; + } env->pc = cpu->rvbar; #endif } else { @@ -320,6 +327,29 @@ static void arm_cpu_kvm_set_irq(void *opaque, int irq, int level) kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0); #endif } + +static bool arm_cpu_is_big_endian(CPUState *cs) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + int cur_el; + + cpu_synchronize_state(cs); + + /* In 32bit guest endianness is determined by looking at CPSR's E bit */ + if (!is_a64(env)) { + return (env->uncached_cpsr & CPSR_E) ? 1 : 0; + } + + cur_el = arm_current_el(env); + + if (cur_el == 0) { + return (env->cp15.sctlr_el[1] & SCTLR_E0E) != 0; + } + + return (env->cp15.sctlr_el[cur_el] & SCTLR_EE) != 0; +} + #endif static inline void set_feature(CPUARMState *env, int feature) @@ -1189,6 +1219,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) cc->do_interrupt = arm_cpu_do_interrupt; cc->get_phys_page_debug = arm_cpu_get_phys_page_debug; cc->vmsd = &vmstate_arm_cpu; + cc->virtio_is_big_endian = arm_cpu_is_big_endian; #endif cc->gdb_num_core_regs = 26; cc->gdb_core_xml_file = "arm-core.xml"; |