mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-24 12:09:58 +00:00
target-arm queue:
* Set PC correctly when loading AArch64 ELF files * sdhci: Fix ADMA dma_memory_read access * some more foundational work for EL2/EL3 support * fix bugs which reveal themselves if the TARGET_PAGE_SIZE is not set to 1K -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJT34/mAAoJEDwlJe0UNgzeRF4P/ReSuK7+woe1GCuUQAsVnl/K IN1Y9HpOcepAjGJk2TWTPiE8xA4d1wiIICWpFd3PLyxRjmcholUEiU0du2Joayi0 uHF7HHSXdtYSu3HkA6VJyLXJU8rsfmGofBtodMiloTPEs1cSvxYQIJeD95ah1Qgy AdH9mCI07fjYUuDrwkLLspXMa//pbqZcpJHBjaW7X4XdJOC5c/MOFlAYPGQWng51 BwNEy73Olp9mByLPsLjdbWyoF8GO4VnnMzbtEtV1EJDI+xUW+8Cl/QUsh7dEKzMQ yAGsL9etLVT6PDDs8b9SBUtPzDsDpniFofMIyPuPUppdtKkdQPbMfkBaAn3h6pl1 p/PO2FARyiu72rWN2T3GQlpP6S0phjdFig7OlwWrvBVBDdgJyqMbCLuYFD1wzZLH tKb1/+J7FQoc8D25wtsEqL+tQdQ9FEIjVuoMMSG+U+uvkd8UJczrewy3sYBE68Dy /XeypTimBUx1Fr8GvM7DfKycJJZZsH5sVppq/vGJwwP5+ArYyiKARY82arcW86pB q4kuVFlpIYRv5Ef/hP3VhYr6ytczhwUsdVQ5la0EHIbVTex9/5rzNENAWl2jkalS kWfo6cFMR4p4V9oZTccx9KvOWodxO1DNqyw0cwla8nxSTxNXD+MJeB8hw0/4Tplp C6aYEpJb44n6CNfBIzgl =UNXb -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20140804' into staging target-arm queue: * Set PC correctly when loading AArch64 ELF files * sdhci: Fix ADMA dma_memory_read access * some more foundational work for EL2/EL3 support * fix bugs which reveal themselves if the TARGET_PAGE_SIZE is not set to 1K # gpg: Signature made Mon 04 Aug 2014 14:51:34 BST using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" * remotes/pmaydell/tags/pull-target-arm-20140804: target-arm: A64: fix TLB flush instructions target-arm: don't hardcode mask values in arm_cpu_handle_mmu_fault target-arm: Fix bit test in sp_el0_access target-arm: Add FAR_EL2 and 3 target-arm: Add ESR_EL2 and 3 target-arm: Make far_el1 an array target-arm: A64: Respect SPSEL when taking exceptions target-arm: A64: Respect SPSEL in ERET SP restore target-arm: A64: Break out aarch64_save/restore_sp sd: sdhci: Fix ADMA dma_memory_read access hw/arm/virt: formatting: memory map hw/arm/boot: Set PC correctly when loading AArch64 ELF files Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
69f87f7130
@ -417,8 +417,12 @@ static void do_cpu_reset(void *opaque)
|
||||
if (info) {
|
||||
if (!info->is_linux) {
|
||||
/* Jump to the entry point. */
|
||||
env->regs[15] = info->entry & 0xfffffffe;
|
||||
env->thumb = info->entry & 1;
|
||||
if (env->aarch64) {
|
||||
env->pc = info->entry;
|
||||
} else {
|
||||
env->regs[15] = info->entry & 0xfffffffe;
|
||||
env->thumb = info->entry & 1;
|
||||
}
|
||||
} else {
|
||||
if (CPU(cpu) == first_cpu) {
|
||||
if (env->aarch64) {
|
||||
|
@ -98,17 +98,17 @@ typedef struct VirtBoardInfo {
|
||||
*/
|
||||
static const MemMapEntry a15memmap[] = {
|
||||
/* Space up to 0x8000000 is reserved for a boot ROM */
|
||||
[VIRT_FLASH] = { 0, 0x8000000 },
|
||||
[VIRT_CPUPERIPHS] = { 0x8000000, 0x20000 },
|
||||
[VIRT_FLASH] = { 0, 0x08000000 },
|
||||
[VIRT_CPUPERIPHS] = { 0x08000000, 0x00020000 },
|
||||
/* GIC distributor and CPU interfaces sit inside the CPU peripheral space */
|
||||
[VIRT_GIC_DIST] = { 0x8000000, 0x10000 },
|
||||
[VIRT_GIC_CPU] = { 0x8010000, 0x10000 },
|
||||
[VIRT_UART] = { 0x9000000, 0x1000 },
|
||||
[VIRT_RTC] = { 0x9010000, 0x1000 },
|
||||
[VIRT_MMIO] = { 0xa000000, 0x200 },
|
||||
[VIRT_GIC_DIST] = { 0x08000000, 0x00010000 },
|
||||
[VIRT_GIC_CPU] = { 0x08010000, 0x00010000 },
|
||||
[VIRT_UART] = { 0x09000000, 0x00001000 },
|
||||
[VIRT_RTC] = { 0x09010000, 0x00001000 },
|
||||
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
|
||||
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
|
||||
/* 0x10000000 .. 0x40000000 reserved for PCI */
|
||||
[VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
|
||||
[VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
|
||||
};
|
||||
|
||||
static const int a15irqmap[] = {
|
||||
|
@ -702,7 +702,8 @@ static void sdhci_do_adma(SDHCIState *s)
|
||||
length -= block_size - begin;
|
||||
}
|
||||
dma_memory_read(&address_space_memory, dscr.addr,
|
||||
&s->fifo_buffer[begin], s->data_count);
|
||||
&s->fifo_buffer[begin],
|
||||
s->data_count - begin);
|
||||
dscr.addr += s->data_count - begin;
|
||||
if (s->data_count == block_size) {
|
||||
for (n = 0; n < block_size; n++) {
|
||||
|
@ -447,7 +447,7 @@ static void arm1026_initfn(Object *obj)
|
||||
ARMCPRegInfo ifar = {
|
||||
.name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1,
|
||||
.access = PL1_RW,
|
||||
.fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1),
|
||||
.fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el[1]),
|
||||
.resetvalue = 0
|
||||
};
|
||||
define_one_arm_cp_reg(cpu, &ifar);
|
||||
|
@ -185,9 +185,9 @@ typedef struct CPUARMState {
|
||||
uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */
|
||||
uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */
|
||||
uint32_t ifsr_el2; /* Fault status registers. */
|
||||
uint64_t esr_el[2];
|
||||
uint64_t esr_el[4];
|
||||
uint32_t c6_region[8]; /* MPU base/size registers. */
|
||||
uint64_t far_el1; /* Fault address registers. */
|
||||
uint64_t far_el[4]; /* Fault address registers. */
|
||||
uint64_t par_el1; /* Translation result. */
|
||||
uint32_t c9_insn; /* Cache lockdown registers. */
|
||||
uint32_t c9_data;
|
||||
|
@ -465,13 +465,13 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
|
||||
}
|
||||
|
||||
env->cp15.esr_el[1] = env->exception.syndrome;
|
||||
env->cp15.far_el1 = env->exception.vaddress;
|
||||
env->cp15.far_el[1] = env->exception.vaddress;
|
||||
|
||||
switch (cs->exception_index) {
|
||||
case EXCP_PREFETCH_ABORT:
|
||||
case EXCP_DATA_ABORT:
|
||||
qemu_log_mask(CPU_LOG_INT, "...with FAR 0x%" PRIx64 "\n",
|
||||
env->cp15.far_el1);
|
||||
env->cp15.far_el[1]);
|
||||
break;
|
||||
case EXCP_BKPT:
|
||||
case EXCP_UDEF:
|
||||
@ -489,8 +489,7 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
|
||||
|
||||
if (is_a64(env)) {
|
||||
env->banked_spsr[aarch64_banked_spsr_index(1)] = pstate_read(env);
|
||||
env->sp_el[arm_current_pl(env)] = env->xregs[31];
|
||||
env->xregs[31] = env->sp_el[1];
|
||||
aarch64_save_sp(env, arm_current_pl(env));
|
||||
env->elr_el[1] = env->pc;
|
||||
} else {
|
||||
env->banked_spsr[0] = cpsr_read(env);
|
||||
@ -508,6 +507,7 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
|
||||
|
||||
pstate_write(env, PSTATE_DAIF | PSTATE_MODE_EL1h);
|
||||
env->aarch64 = 1;
|
||||
aarch64_restore_sp(env, 1);
|
||||
|
||||
env->pc = addr;
|
||||
cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
|
||||
|
@ -521,7 +521,7 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
|
||||
.access = PL0_W, .type = ARM_CP_NOP },
|
||||
{ .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 2,
|
||||
.access = PL1_RW,
|
||||
.fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1),
|
||||
.fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el[1]),
|
||||
.resetvalue = 0, },
|
||||
/* Watchpoint Fault Address Register : should actually only be present
|
||||
* for 1136, 1176, 11MPCore.
|
||||
@ -1516,7 +1516,7 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
|
||||
/* 64-bit FAR; this entry also gives us the AArch32 DFAR */
|
||||
{ .name = "FAR_EL1", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
|
||||
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el1),
|
||||
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]),
|
||||
.resetvalue = 0, },
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
@ -1801,12 +1801,17 @@ static CPAccessResult aa64_cacheop_access(CPUARMState *env,
|
||||
return CP_ACCESS_OK;
|
||||
}
|
||||
|
||||
/* See: D4.7.2 TLB maintenance requirements and the TLB maintenance instructions
|
||||
* Page D4-1736 (DDI0487A.b)
|
||||
*/
|
||||
|
||||
static void tlbi_aa64_va_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
/* Invalidate by VA (AArch64 version) */
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
uint64_t pageaddr = value << 12;
|
||||
uint64_t pageaddr = sextract64(value << 12, 0, 56);
|
||||
|
||||
tlb_flush_page(CPU(cpu), pageaddr);
|
||||
}
|
||||
|
||||
@ -1815,7 +1820,8 @@ static void tlbi_aa64_vaa_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
{
|
||||
/* Invalidate by VA, all ASIDs (AArch64 version) */
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
uint64_t pageaddr = value << 12;
|
||||
uint64_t pageaddr = sextract64(value << 12, 0, 56);
|
||||
|
||||
tlb_flush_page(CPU(cpu), pageaddr);
|
||||
}
|
||||
|
||||
@ -1853,7 +1859,7 @@ static uint64_t aa64_dczid_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
|
||||
static CPAccessResult sp_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
if (!env->pstate & PSTATE_SP) {
|
||||
if (!(env->pstate & PSTATE_SP)) {
|
||||
/* Access to SP_EL0 is undefined if it's being used as
|
||||
* the stack pointer.
|
||||
*/
|
||||
@ -2127,6 +2133,13 @@ static const ARMCPRegInfo v8_el2_cp_reginfo[] = {
|
||||
.opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 1,
|
||||
.access = PL2_RW,
|
||||
.fieldoffset = offsetof(CPUARMState, elr_el[2]) },
|
||||
{ .name = "ESR_EL2", .state = ARM_CP_STATE_AA64,
|
||||
.type = ARM_CP_NO_MIGRATE,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 0,
|
||||
.access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.esr_el[2]) },
|
||||
{ .name = "FAR_EL2", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 0,
|
||||
.access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[2]) },
|
||||
{ .name = "SPSR_EL2", .state = ARM_CP_STATE_AA64,
|
||||
.type = ARM_CP_NO_MIGRATE,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 0,
|
||||
@ -2145,6 +2158,13 @@ static const ARMCPRegInfo v8_el3_cp_reginfo[] = {
|
||||
.opc0 = 3, .opc1 = 6, .crn = 4, .crm = 0, .opc2 = 1,
|
||||
.access = PL3_RW,
|
||||
.fieldoffset = offsetof(CPUARMState, elr_el[3]) },
|
||||
{ .name = "ESR_EL3", .state = ARM_CP_STATE_AA64,
|
||||
.type = ARM_CP_NO_MIGRATE,
|
||||
.opc0 = 3, .opc1 = 6, .crn = 5, .crm = 2, .opc2 = 0,
|
||||
.access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.esr_el[3]) },
|
||||
{ .name = "FAR_EL3", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 6, .crn = 6, .crm = 0, .opc2 = 0,
|
||||
.access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[3]) },
|
||||
{ .name = "SPSR_EL3", .state = ARM_CP_STATE_AA64,
|
||||
.type = ARM_CP_NO_MIGRATE,
|
||||
.opc0 = 3, .opc1 = 6, .crn = 4, .crm = 0, .opc2 = 0,
|
||||
@ -3425,8 +3445,8 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
||||
/* Fall through to prefetch abort. */
|
||||
case EXCP_PREFETCH_ABORT:
|
||||
env->cp15.ifsr_el2 = env->exception.fsr;
|
||||
env->cp15.far_el1 = deposit64(env->cp15.far_el1, 32, 32,
|
||||
env->exception.vaddress);
|
||||
env->cp15.far_el[1] = deposit64(env->cp15.far_el[1], 32, 32,
|
||||
env->exception.vaddress);
|
||||
qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x IFAR 0x%x\n",
|
||||
env->cp15.ifsr_el2, (uint32_t)env->exception.vaddress);
|
||||
new_mode = ARM_CPU_MODE_ABT;
|
||||
@ -3436,8 +3456,8 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
||||
break;
|
||||
case EXCP_DATA_ABORT:
|
||||
env->cp15.esr_el[1] = env->exception.fsr;
|
||||
env->cp15.far_el1 = deposit64(env->cp15.far_el1, 0, 32,
|
||||
env->exception.vaddress);
|
||||
env->cp15.far_el[1] = deposit64(env->cp15.far_el[1], 0, 32,
|
||||
env->exception.vaddress);
|
||||
qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n",
|
||||
(uint32_t)env->cp15.esr_el[1],
|
||||
(uint32_t)env->exception.vaddress);
|
||||
@ -4142,8 +4162,8 @@ int arm_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
|
||||
&page_size);
|
||||
if (ret == 0) {
|
||||
/* Map a single [sub]page. */
|
||||
phys_addr &= ~(hwaddr)0x3ff;
|
||||
address &= ~(target_ulong)0x3ff;
|
||||
phys_addr &= TARGET_PAGE_MASK;
|
||||
address &= TARGET_PAGE_MASK;
|
||||
tlb_set_page(cs, address, phys_addr, prot, mmu_idx, page_size);
|
||||
return 0;
|
||||
}
|
||||
|
@ -105,6 +105,24 @@ enum arm_fprounding {
|
||||
|
||||
int arm_rmode_to_sf(int rmode);
|
||||
|
||||
static inline void aarch64_save_sp(CPUARMState *env, int el)
|
||||
{
|
||||
if (env->pstate & PSTATE_SP) {
|
||||
env->sp_el[el] = env->xregs[31];
|
||||
} else {
|
||||
env->sp_el[0] = env->xregs[31];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void aarch64_restore_sp(CPUARMState *env, int el)
|
||||
{
|
||||
if (env->pstate & PSTATE_SP) {
|
||||
env->xregs[31] = env->sp_el[el];
|
||||
} else {
|
||||
env->xregs[31] = env->sp_el[0];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void update_spsel(CPUARMState *env, uint32_t imm)
|
||||
{
|
||||
unsigned int cur_el = arm_current_pl(env);
|
||||
@ -114,21 +132,14 @@ static inline void update_spsel(CPUARMState *env, uint32_t imm)
|
||||
if (!((imm ^ env->pstate) & PSTATE_SP)) {
|
||||
return;
|
||||
}
|
||||
aarch64_save_sp(env, cur_el);
|
||||
env->pstate = deposit32(env->pstate, 0, 1, imm);
|
||||
|
||||
/* We rely on illegal updates to SPsel from EL0 to get trapped
|
||||
* at translation time.
|
||||
*/
|
||||
assert(cur_el >= 1 && cur_el <= 3);
|
||||
if (env->pstate & PSTATE_SP) {
|
||||
/* Switch from using SP_EL0 to using SP_ELx */
|
||||
env->sp_el[0] = env->xregs[31];
|
||||
env->xregs[31] = env->sp_el[cur_el];
|
||||
} else {
|
||||
/* Switch from SP_EL0 to SP_ELx */
|
||||
env->sp_el[cur_el] = env->xregs[31];
|
||||
env->xregs[31] = env->sp_el[0];
|
||||
}
|
||||
aarch64_restore_sp(env, cur_el);
|
||||
}
|
||||
|
||||
/* Valid Syndrome Register EC field values */
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "sysemu/kvm.h"
|
||||
#include "kvm_arm.h"
|
||||
#include "cpu.h"
|
||||
#include "internals.h"
|
||||
#include "hw/arm/arm.h"
|
||||
|
||||
static inline void set_feature(uint64_t *features, int feature)
|
||||
@ -132,11 +133,7 @@ int kvm_arch_put_registers(CPUState *cs, int level)
|
||||
/* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
|
||||
* QEMU side we keep the current SP in xregs[31] as well.
|
||||
*/
|
||||
if (env->pstate & PSTATE_SP) {
|
||||
env->sp_el[1] = env->xregs[31];
|
||||
} else {
|
||||
env->sp_el[0] = env->xregs[31];
|
||||
}
|
||||
aarch64_save_sp(env, 1);
|
||||
|
||||
reg.id = AARCH64_CORE_REG(regs.sp);
|
||||
reg.addr = (uintptr_t) &env->sp_el[0];
|
||||
@ -235,11 +232,7 @@ int kvm_arch_get_registers(CPUState *cs)
|
||||
/* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
|
||||
* QEMU side we keep the current SP in xregs[31] as well.
|
||||
*/
|
||||
if (env->pstate & PSTATE_SP) {
|
||||
env->xregs[31] = env->sp_el[1];
|
||||
} else {
|
||||
env->xregs[31] = env->sp_el[0];
|
||||
}
|
||||
aarch64_restore_sp(env, 1);
|
||||
|
||||
reg.id = AARCH64_CORE_REG(regs.pc);
|
||||
reg.addr = (uintptr_t) &env->pc;
|
||||
|
@ -376,11 +376,7 @@ void HELPER(exception_return)(CPUARMState *env)
|
||||
uint32_t spsr = env->banked_spsr[spsr_idx];
|
||||
int new_el, i;
|
||||
|
||||
if (env->pstate & PSTATE_SP) {
|
||||
env->sp_el[cur_el] = env->xregs[31];
|
||||
} else {
|
||||
env->sp_el[0] = env->xregs[31];
|
||||
}
|
||||
aarch64_save_sp(env, cur_el);
|
||||
|
||||
env->exclusive_addr = -1;
|
||||
|
||||
@ -414,7 +410,7 @@ void HELPER(exception_return)(CPUARMState *env)
|
||||
}
|
||||
env->aarch64 = 1;
|
||||
pstate_write(env, spsr);
|
||||
env->xregs[31] = env->sp_el[new_el];
|
||||
aarch64_restore_sp(env, new_el);
|
||||
env->pc = env->elr_el[cur_el];
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user