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
…0140804' 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>
  • Loading branch information
pm215 committed Aug 4, 2014
2 parents cc11a06 + dbb1fb2 commit 69f87f7
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 54 deletions.
8 changes: 6 additions & 2 deletions hw/arm/boot.c
Expand Up @@ -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) {
Expand Down
16 changes: 8 additions & 8 deletions hw/arm/virt.c
Expand Up @@ -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[] = {
Expand Down
3 changes: 2 additions & 1 deletion hw/sd/sdhci.c
Expand Up @@ -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++) {
Expand Down
2 changes: 1 addition & 1 deletion target-arm/cpu.c
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions target-arm/cpu.h
Expand Up @@ -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;
Expand Down
8 changes: 4 additions & 4 deletions target-arm/helper-a64.c
Expand Up @@ -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:
Expand All @@ -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);
Expand All @@ -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;
Expand Down
42 changes: 31 additions & 11 deletions target-arm/helper.c
Expand Up @@ -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.
Expand Down Expand Up @@ -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
};
Expand Down Expand Up @@ -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);
}

Expand All @@ -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);
}

Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down
29 changes: 20 additions & 9 deletions target-arm/internals.h
Expand Up @@ -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);
Expand All @@ -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 */
Expand Down
13 changes: 3 additions & 10 deletions target-arm/kvm64.c
Expand Up @@ -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)
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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;
Expand Down
8 changes: 2 additions & 6 deletions target-arm/op_helper.c
Expand Up @@ -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;

Expand Down Expand Up @@ -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];
}

Expand Down

0 comments on commit 69f87f7

Please sign in to comment.