aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-08-04 15:01:38 +0100
committerPeter Maydell <peter.maydell@linaro.org>2014-08-04 15:01:38 +0100
commit69f87f713069f1f70f86cb65883f7d43e3aa21de (patch)
tree816428de782bde87199584b149b74a5203d1d245
parentcc11a0623ab4b16faa6945f1f6dedcb59f993b61 (diff)
parentdbb1fb277ca12acd577403575aa6a2f119ab79ea (diff)
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>
-rw-r--r--hw/arm/boot.c8
-rw-r--r--hw/arm/virt.c16
-rw-r--r--hw/sd/sdhci.c3
-rw-r--r--target-arm/cpu.c2
-rw-r--r--target-arm/cpu.h4
-rw-r--r--target-arm/helper-a64.c8
-rw-r--r--target-arm/helper.c42
-rw-r--r--target-arm/internals.h29
-rw-r--r--target-arm/kvm64.c13
-rw-r--r--target-arm/op_helper.c8
10 files changed, 79 insertions, 54 deletions
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 3d1f4a255b..12417617a3 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -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) {
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 89532bd786..ba94298555 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -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[] = {
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index b5a9eee3e2..f9fe700add 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -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++) {
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 05e52e0e83..7cebb76656 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -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);
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 369d4727ae..79205ba335 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -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;
diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index 2b4ce6ac60..2e9ef64786 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -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;
diff --git a/target-arm/helper.c b/target-arm/helper.c
index d3438560e6..f630d96306 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -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;
}
diff --git a/target-arm/internals.h b/target-arm/internals.h
index 564b5fa602..08fa69757d 100644
--- a/target-arm/internals.h
+++ b/target-arm/internals.h
@@ -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 */
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index 5d217ca2ad..c615286158 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -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;
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 9c1ef525a3..25ad902e04 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -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];
}