]> git.proxmox.com Git - qemu.git/blobdiff - target-arm/helper.c
target-i386: Emulate X86CPU subclasses for global properties
[qemu.git] / target-arm / helper.c
index 23099236adc9d56872c437d9159d32b90ee7a5a6..fd055e89f264ed55396d6cfef432d153b554744f 100644 (file)
@@ -1,13 +1,14 @@
 #include "cpu.h"
-#include "gdbstub.h"
+#include "exec/gdbstub.h"
 #include "helper.h"
-#include "host-utils.h"
-#include "sysemu.h"
+#include "qemu/host-utils.h"
+#include "sysemu/sysemu.h"
+#include "qemu/bitops.h"
 
 #ifndef CONFIG_USER_ONLY
 static inline int get_phys_addr(CPUARMState *env, uint32_t address,
                                 int access_type, int is_user,
-                                uint32_t *phys_ptr, int *prot,
+                                hwaddr *phys_ptr, int *prot,
                                 target_ulong *page_size);
 #endif
 
@@ -216,9 +217,9 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
       .access = PL1_W, .type = ARM_CP_NOP },
     { .name = "ISB", .cp = 15, .crn = 7, .crm = 5, .opc1 = 0, .opc2 = 4,
       .access = PL0_W, .type = ARM_CP_NOP },
-    { .name = "ISB", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 4,
+    { .name = "DSB", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 4,
       .access = PL0_W, .type = ARM_CP_NOP },
-    { .name = "ISB", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 5,
+    { .name = "DMB", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 5,
       .access = PL0_W, .type = ARM_CP_NOP },
     { .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 2,
       .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c6_insn),
@@ -346,7 +347,7 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
      */
     { .name = "DBGDRAR", .cp = 14, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
       .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 },
-    { .name = "DBGDRAR", .cp = 14, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
+    { .name = "DBGDSAR", .cp = 14, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
       .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 },
     /* the old v6 WFI, UNPREDICTABLE in v7 but we choose to NOP */
     { .name = "NOP", .cp = 15, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 4,
@@ -491,7 +492,9 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
 
 static int par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
 {
-    if (arm_feature(env, ARM_FEATURE_V7)) {
+    if (arm_feature(env, ARM_FEATURE_LPAE)) {
+        env->cp15.c7_par = value;
+    } else if (arm_feature(env, ARM_FEATURE_V7)) {
         env->cp15.c7_par = value & 0xfffff6ff;
     } else {
         env->cp15.c7_par = value & 0xfffff1ff;
@@ -501,9 +504,20 @@ static int par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
 
 #ifndef CONFIG_USER_ONLY
 /* get_phys_addr() isn't present for user-mode-only targets */
+
+/* Return true if extended addresses are enabled, ie this is an
+ * LPAE implementation and we are using the long-descriptor translation
+ * table format because the TTBCR EAE bit is set.
+ */
+static inline bool extended_addresses_enabled(CPUARMState *env)
+{
+    return arm_feature(env, ARM_FEATURE_LPAE)
+        && (env->cp15.c2_control & (1 << 31));
+}
+
 static int ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
 {
-    uint32_t phys_addr;
+    hwaddr phys_addr;
     target_ulong page_size;
     int prot;
     int ret, is_user = ri->opc2 & 2;
@@ -515,18 +529,44 @@ static int ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
     }
     ret = get_phys_addr(env, value, access_type, is_user,
                         &phys_addr, &prot, &page_size);
-    if (ret == 0) {
-        /* We do not set any attribute bits in the PAR */
-        if (page_size == (1 << 24)
-            && arm_feature(env, ARM_FEATURE_V7)) {
-            env->cp15.c7_par = (phys_addr & 0xff000000) | 1 << 1;
+    if (extended_addresses_enabled(env)) {
+        /* ret is a DFSR/IFSR value for the long descriptor
+         * translation table format, but with WnR always clear.
+         * Convert it to a 64-bit PAR.
+         */
+        uint64_t par64 = (1 << 11); /* LPAE bit always set */
+        if (ret == 0) {
+            par64 |= phys_addr & ~0xfffULL;
+            /* We don't set the ATTR or SH fields in the PAR. */
         } else {
-            env->cp15.c7_par = phys_addr & 0xfffff000;
+            par64 |= 1; /* F */
+            par64 |= (ret & 0x3f) << 1; /* FS */
+            /* Note that S2WLK and FSTAGE are always zero, because we don't
+             * implement virtualization and therefore there can't be a stage 2
+             * fault.
+             */
         }
+        env->cp15.c7_par = par64;
+        env->cp15.c7_par_hi = par64 >> 32;
     } else {
-        env->cp15.c7_par = ((ret & (10 << 1)) >> 5) |
-            ((ret & (12 << 1)) >> 6) |
-            ((ret & 0xf) << 1) | 1;
+        /* ret is a DFSR/IFSR value for the short descriptor
+         * translation table format (with WnR always clear).
+         * Convert it to a 32-bit PAR.
+         */
+        if (ret == 0) {
+            /* We do not set any attribute bits in the PAR */
+            if (page_size == (1 << 24)
+                && arm_feature(env, ARM_FEATURE_V7)) {
+                env->cp15.c7_par = (phys_addr & 0xff000000) | 1 << 1;
+            } else {
+                env->cp15.c7_par = phys_addr & 0xfffff000;
+            }
+        } else {
+            env->cp15.c7_par = ((ret & (10 << 1)) >> 5) |
+                ((ret & (12 << 1)) >> 6) |
+                ((ret & 0xf) << 1) | 1;
+        }
+        env->cp15.c7_par_hi = 0;
     }
     return 0;
 }
@@ -605,7 +645,7 @@ static int pmsav5_insn_ap_read(CPUARMState *env, const ARMCPRegInfo *ri,
 static int arm946_prbs_read(CPUARMState *env, const ARMCPRegInfo *ri,
                             uint64_t *value)
 {
-    if (ri->crm > 8) {
+    if (ri->crm >= 8) {
         return EXCP_UDEF;
     }
     *value = env->cp15.c6_region[ri->crm];
@@ -615,7 +655,7 @@ static int arm946_prbs_read(CPUARMState *env, const ARMCPRegInfo *ri,
 static int arm946_prbs_write(CPUARMState *env, const ARMCPRegInfo *ri,
                              uint64_t value)
 {
-    if (ri->crm > 8) {
+    if (ri->crm >= 8) {
         return EXCP_UDEF;
     }
     env->cp15.c6_region[ri->crm] = value;
@@ -653,7 +693,20 @@ static const ARMCPRegInfo pmsav5_cp_reginfo[] = {
 static int vmsa_ttbcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
                             uint64_t value)
 {
-    value &= 7;
+    if (arm_feature(env, ARM_FEATURE_LPAE)) {
+        value &= ~((7 << 19) | (3 << 14) | (0xf << 3));
+        /* With LPAE the TTBCR could result in a change of ASID
+         * via the TTBCR.A1 bit, so do a TLB flush.
+         */
+        tlb_flush(env, 1);
+    } else {
+        value &= 7;
+    }
+    /* Note that we always calculate c2_mask and c2_base_mask, but
+     * they are only used for short-descriptor tables (ie if EAE is 0);
+     * for long-descriptor tables the TTBCR fields are used differently
+     * and the c2_mask and c2_base_mask values are meaningless.
+     */
     env->cp15.c2_control = value;
     env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> value);
     env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> value);
@@ -679,7 +732,7 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
       .fieldoffset = offsetof(CPUARMState, cp15.c2_base0), .resetvalue = 0, },
     { .name = "TTBR1", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 1,
       .access = PL1_RW,
-      .fieldoffset = offsetof(CPUARMState, cp15.c2_base0), .resetvalue = 0, },
+      .fieldoffset = offsetof(CPUARMState, cp15.c2_base1), .resetvalue = 0, },
     { .name = "TTBCR", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2,
       .access = PL1_RW, .writefn = vmsa_ttbcr_write,
       .resetfn = vmsa_ttbcr_reset,
@@ -711,7 +764,7 @@ static int omap_wfi_write(CPUARMState *env, const ARMCPRegInfo *ri,
                           uint64_t value)
 {
     /* Wait-for-interrupt (deprecated) */
-    cpu_interrupt(env, CPU_INTERRUPT_HALT);
+    cpu_interrupt(CPU(arm_env_get_cpu(env)), CPU_INTERRUPT_HALT);
     return 0;
 }
 
@@ -849,7 +902,8 @@ static const ARMCPRegInfo strongarm_cp_reginfo[] = {
 static int mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri,
                       uint64_t *value)
 {
-    uint32_t mpidr = env->cpu_index;
+    CPUState *cs = CPU(arm_env_get_cpu(env));
+    uint32_t mpidr = cs->cpu_index;
     /* We don't support setting cluster ID ([8..11])
      * so these bits always RAZ.
      */
@@ -871,6 +925,96 @@ static const ARMCPRegInfo mpidr_cp_reginfo[] = {
     REGINFO_SENTINEL
 };
 
+static int par64_read(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value)
+{
+    *value = ((uint64_t)env->cp15.c7_par_hi << 32) | env->cp15.c7_par;
+    return 0;
+}
+
+static int par64_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
+{
+    env->cp15.c7_par_hi = value >> 32;
+    env->cp15.c7_par = value;
+    return 0;
+}
+
+static void par64_reset(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    env->cp15.c7_par_hi = 0;
+    env->cp15.c7_par = 0;
+}
+
+static int ttbr064_read(CPUARMState *env, const ARMCPRegInfo *ri,
+                        uint64_t *value)
+{
+    *value = ((uint64_t)env->cp15.c2_base0_hi << 32) | env->cp15.c2_base0;
+    return 0;
+}
+
+static int ttbr064_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                         uint64_t value)
+{
+    env->cp15.c2_base0_hi = value >> 32;
+    env->cp15.c2_base0 = value;
+    /* Writes to the 64 bit format TTBRs may change the ASID */
+    tlb_flush(env, 1);
+    return 0;
+}
+
+static void ttbr064_reset(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    env->cp15.c2_base0_hi = 0;
+    env->cp15.c2_base0 = 0;
+}
+
+static int ttbr164_read(CPUARMState *env, const ARMCPRegInfo *ri,
+                        uint64_t *value)
+{
+    *value = ((uint64_t)env->cp15.c2_base1_hi << 32) | env->cp15.c2_base1;
+    return 0;
+}
+
+static int ttbr164_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                         uint64_t value)
+{
+    env->cp15.c2_base1_hi = value >> 32;
+    env->cp15.c2_base1 = value;
+    return 0;
+}
+
+static void ttbr164_reset(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    env->cp15.c2_base1_hi = 0;
+    env->cp15.c2_base1 = 0;
+}
+
+static const ARMCPRegInfo lpae_cp_reginfo[] = {
+    /* NOP AMAIR0/1: the override is because these clash with the rather
+     * broadly specified TLB_LOCKDOWN entry in the generic cp_reginfo.
+     */
+    { .name = "AMAIR0", .cp = 15, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 0,
+      .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_OVERRIDE,
+      .resetvalue = 0 },
+    { .name = "AMAIR1", .cp = 15, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 1,
+      .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_OVERRIDE,
+      .resetvalue = 0 },
+    /* 64 bit access versions of the (dummy) debug registers */
+    { .name = "DBGDRAR", .cp = 14, .crm = 1, .opc1 = 0,
+      .access = PL0_R, .type = ARM_CP_CONST|ARM_CP_64BIT, .resetvalue = 0 },
+    { .name = "DBGDSAR", .cp = 14, .crm = 2, .opc1 = 0,
+      .access = PL0_R, .type = ARM_CP_CONST|ARM_CP_64BIT, .resetvalue = 0 },
+    { .name = "PAR", .cp = 15, .crm = 7, .opc1 = 0,
+      .access = PL1_RW, .type = ARM_CP_64BIT,
+      .readfn = par64_read, .writefn = par64_write, .resetfn = par64_reset },
+    { .name = "TTBR0", .cp = 15, .crm = 2, .opc1 = 0,
+      .access = PL1_RW, .type = ARM_CP_64BIT, .readfn = ttbr064_read,
+      .writefn = ttbr064_write, .resetfn = ttbr064_reset },
+    { .name = "TTBR1", .cp = 15, .crm = 2, .opc1 = 1,
+      .access = PL1_RW, .type = ARM_CP_64BIT, .readfn = ttbr164_read,
+      .writefn = ttbr164_write, .resetfn = ttbr164_reset },
+    REGINFO_SENTINEL
+};
+
 static int sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
 {
     env->cp15.c1_sys = value;
@@ -1016,6 +1160,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
     if (arm_feature(env, ARM_FEATURE_MPIDR)) {
         define_arm_cp_regs(cpu, mpidr_cp_reginfo);
     }
+    if (arm_feature(env, ARM_FEATURE_LPAE)) {
+        define_arm_cp_regs(cpu, lpae_cp_reginfo);
+    }
     /* Slightly awkwardly, the OMAP and StrongARM cores need all of
      * cp15 crn=0 to be writes-ignored, whereas for other cores they should
      * be read-only (ie write causes UNDEF exception).
@@ -1115,22 +1262,26 @@ ARMCPU *cpu_arm_init(const char *cpu_model)
 {
     ARMCPU *cpu;
     CPUARMState *env;
-    static int inited = 0;
+    ObjectClass *oc;
 
-    if (!object_class_by_name(cpu_model)) {
+    oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
+    if (!oc) {
         return NULL;
     }
-    cpu = ARM_CPU(object_new(cpu_model));
+    cpu = ARM_CPU(object_new(object_class_get_name(oc)));
     env = &cpu->env;
     env->cpu_model_str = cpu_model;
-    arm_cpu_realize(cpu);
 
-    if (tcg_enabled() && !inited) {
-        inited = 1;
-        arm_translate_init();
-    }
+    /* TODO this should be set centrally, once possible */
+    object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
+
+    return cpu;
+}
+
+void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
+{
+    CPUARMState *env = &cpu->env;
 
-    cpu_reset(CPU(cpu));
     if (arm_feature(env, ARM_FEATURE_NEON)) {
         gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
                                  51, "arm-neon.xml", 0);
@@ -1141,15 +1292,8 @@ ARMCPU *cpu_arm_init(const char *cpu_model)
         gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
                                  19, "arm-vfp.xml", 0);
     }
-    qemu_init_vcpu(env);
-    return cpu;
 }
 
-typedef struct ARMCPUListState {
-    fprintf_function cpu_fprintf;
-    FILE *file;
-} ARMCPUListState;
-
 /* Sort alphabetically by type name, except for "any". */
 static gint arm_cpu_list_compare(gconstpointer a, gconstpointer b)
 {
@@ -1159,9 +1303,9 @@ static gint arm_cpu_list_compare(gconstpointer a, gconstpointer b)
 
     name_a = object_class_get_name(class_a);
     name_b = object_class_get_name(class_b);
-    if (strcmp(name_a, "any") == 0) {
+    if (strcmp(name_a, "any-" TYPE_ARM_CPU) == 0) {
         return 1;
-    } else if (strcmp(name_b, "any") == 0) {
+    } else if (strcmp(name_b, "any-" TYPE_ARM_CPU) == 0) {
         return -1;
     } else {
         return strcmp(name_a, name_b);
@@ -1171,15 +1315,20 @@ static gint arm_cpu_list_compare(gconstpointer a, gconstpointer b)
 static void arm_cpu_list_entry(gpointer data, gpointer user_data)
 {
     ObjectClass *oc = data;
-    ARMCPUListState *s = user_data;
+    CPUListState *s = user_data;
+    const char *typename;
+    char *name;
 
+    typename = object_class_get_name(oc);
+    name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_ARM_CPU));
     (*s->cpu_fprintf)(s->file, "  %s\n",
-                      object_class_get_name(oc));
+                      name);
+    g_free(name);
 }
 
 void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 {
-    ARMCPUListState s = {
+    CPUListState s = {
         .file = f,
         .cpu_fprintf = cpu_fprintf,
     };
@@ -1416,15 +1565,13 @@ uint32_t HELPER(rbit)(uint32_t x)
     return x;
 }
 
-uint32_t HELPER(abs)(uint32_t x)
-{
-    return ((int32_t)x < 0) ? -x : x;
-}
-
 #if defined(CONFIG_USER_ONLY)
 
-void do_interrupt (CPUARMState *env)
+void arm_cpu_do_interrupt(CPUState *cs)
 {
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+
     env->exception_index = -1;
 }
 
@@ -1473,7 +1620,7 @@ uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode)
 #else
 
 /* Map CPU modes onto saved register banks.  */
-static inline int bank_number(CPUARMState *env, int mode)
+int bank_number(int mode)
 {
     switch (mode) {
     case ARM_CPU_MODE_USR:
@@ -1490,8 +1637,7 @@ static inline int bank_number(CPUARMState *env, int mode)
     case ARM_CPU_MODE_FIQ:
         return 5;
     }
-    cpu_abort(env, "Bad mode %x\n", mode);
-    return -1;
+    hw_error("bank number requested for bad CPSR mode value 0x%x\n", mode);
 }
 
 void switch_mode(CPUARMState *env, int mode)
@@ -1511,12 +1657,12 @@ void switch_mode(CPUARMState *env, int mode)
         memcpy (env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t));
     }
 
-    i = bank_number(env, old_mode);
+    i = bank_number(old_mode);
     env->banked_r13[i] = env->regs[13];
     env->banked_r14[i] = env->regs[14];
     env->banked_spsr[i] = env->spsr;
 
-    i = bank_number(env, mode);
+    i = bank_number(mode);
     env->regs[13] = env->banked_r13[i];
     env->regs[14] = env->banked_r14[i];
     env->spsr = env->banked_spsr[i];
@@ -1579,8 +1725,10 @@ static void do_v7m_exception_exit(CPUARMState *env)
        pointer.  */
 }
 
-static void do_interrupt_v7m(CPUARMState *env)
+void arm_v7m_cpu_do_interrupt(CPUState *cs)
 {
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
     uint32_t xpsr = xpsr_read(env);
     uint32_t lr;
     uint32_t addr;
@@ -1600,7 +1748,7 @@ static void do_interrupt_v7m(CPUARMState *env)
         armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
         return;
     case EXCP_SWI:
-        env->regs[15] += 2;
+        /* The PC already points to the next instruction.  */
         armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC);
         return;
     case EXCP_PREFETCH_ABORT:
@@ -1610,7 +1758,7 @@ static void do_interrupt_v7m(CPUARMState *env)
     case EXCP_BKPT:
         if (semihosting_enabled) {
             int nr;
-            nr = arm_lduw_code(env->regs[15], env->bswap_code) & 0xff;
+            nr = arm_lduw_code(env, env->regs[15], env->bswap_code) & 0xff;
             if (nr == 0xab) {
                 env->regs[15] += 2;
                 env->regs[0] = do_arm_semihosting(env);
@@ -1656,17 +1804,17 @@ static void do_interrupt_v7m(CPUARMState *env)
 }
 
 /* Handle a CPU exception.  */
-void do_interrupt(CPUARMState *env)
+void arm_cpu_do_interrupt(CPUState *cs)
 {
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
     uint32_t addr;
     uint32_t mask;
     int new_mode;
     uint32_t offset;
 
-    if (IS_M(env)) {
-        do_interrupt_v7m(env);
-        return;
-    }
+    assert(!IS_M(env));
+
     /* TODO: Vectored interrupt controller.  */
     switch (env->exception_index) {
     case EXCP_UDEF:
@@ -1682,9 +1830,10 @@ void do_interrupt(CPUARMState *env)
         if (semihosting_enabled) {
             /* Check for semihosting interrupt.  */
             if (env->thumb) {
-                mask = arm_lduw_code(env->regs[15] - 2, env->bswap_code) & 0xff;
+                mask = arm_lduw_code(env, env->regs[15] - 2, env->bswap_code)
+                    & 0xff;
             } else {
-                mask = arm_ldl_code(env->regs[15] - 4, env->bswap_code)
+                mask = arm_ldl_code(env, env->regs[15] - 4, env->bswap_code)
                     & 0xffffff;
             }
             /* Only intercept calls from privileged modes, to provide some
@@ -1705,7 +1854,7 @@ void do_interrupt(CPUARMState *env)
     case EXCP_BKPT:
         /* See if this is a semihosting syscall.  */
         if (env->thumb && semihosting_enabled) {
-            mask = arm_lduw_code(env->regs[15], env->bswap_code) & 0xff;
+            mask = arm_lduw_code(env, env->regs[15], env->bswap_code) & 0xff;
             if (mask == 0xab
                   && (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) {
                 env->regs[15] += 2;
@@ -1763,7 +1912,7 @@ void do_interrupt(CPUARMState *env)
     }
     env->regs[14] = env->regs[15] + offset;
     env->regs[15] = addr;
-    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+    cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
 }
 
 /* Check section/page access permissions.
@@ -1833,8 +1982,8 @@ static uint32_t get_level1_table_address(CPUARMState *env, uint32_t address)
 }
 
 static int get_phys_addr_v5(CPUARMState *env, uint32_t address, int access_type,
-                           int is_user, uint32_t *phys_ptr, int *prot,
-                            target_ulong *page_size)
+                            int is_user, hwaddr *phys_ptr,
+                            int *prot, target_ulong *page_size)
 {
     int code;
     uint32_t table;
@@ -1843,7 +1992,7 @@ static int get_phys_addr_v5(CPUARMState *env, uint32_t address, int access_type,
     int ap;
     int domain;
     int domain_prot;
-    uint32_t phys_addr;
+    hwaddr phys_addr;
 
     /* Pagetable walk.  */
     /* Lookup l1 descriptor.  */
@@ -1928,45 +2077,46 @@ do_fault:
 }
 
 static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
-                           int is_user, uint32_t *phys_ptr, int *prot,
-                            target_ulong *page_size)
+                            int is_user, hwaddr *phys_ptr,
+                            int *prot, target_ulong *page_size)
 {
     int code;
     uint32_t table;
     uint32_t desc;
     uint32_t xn;
+    uint32_t pxn = 0;
     int type;
     int ap;
-    int domain;
+    int domain = 0;
     int domain_prot;
-    uint32_t phys_addr;
+    hwaddr phys_addr;
 
     /* Pagetable walk.  */
     /* Lookup l1 descriptor.  */
     table = get_level1_table_address(env, address);
     desc = ldl_phys(table);
     type = (desc & 3);
-    if (type == 0) {
-        /* Section translation fault.  */
+    if (type == 0 || (type == 3 && !arm_feature(env, ARM_FEATURE_PXN))) {
+        /* Section translation fault, or attempt to use the encoding
+         * which is Reserved on implementations without PXN.
+         */
         code = 5;
-        domain = 0;
         goto do_fault;
-    } else if (type == 2 && (desc & (1 << 18))) {
-        /* Supersection.  */
-        domain = 0;
-    } else {
-        /* Section or page.  */
+    }
+    if ((type == 1) || !(desc & (1 << 18))) {
+        /* Page or Section.  */
         domain = (desc >> 5) & 0x0f;
     }
     domain_prot = (env->cp15.c3 >> (domain * 2)) & 3;
     if (domain_prot == 0 || domain_prot == 2) {
-        if (type == 2)
+        if (type != 1) {
             code = 9; /* Section domain fault.  */
-        else
+        } else {
             code = 11; /* Page domain fault.  */
+        }
         goto do_fault;
     }
-    if (type == 2) {
+    if (type != 1) {
         if (desc & (1 << 18)) {
             /* Supersection.  */
             phys_addr = (desc & 0xff000000) | (address & 0x00ffffff);
@@ -1978,8 +2128,12 @@ static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
         }
         ap = ((desc >> 10) & 3) | ((desc >> 13) & 4);
         xn = desc & (1 << 4);
+        pxn = desc & 1;
         code = 13;
     } else {
+        if (arm_feature(env, ARM_FEATURE_PXN)) {
+            pxn = (desc >> 2) & 1;
+        }
         /* Lookup l2 entry.  */
         table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc);
         desc = ldl_phys(table);
@@ -2007,6 +2161,9 @@ static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
     if (domain_prot == 3) {
         *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
     } else {
+        if (pxn && !is_user) {
+            xn = 1;
+        }
         if (xn && access_type == 2)
             goto do_fault;
 
@@ -2031,8 +2188,187 @@ do_fault:
     return code | (domain << 4);
 }
 
-static int get_phys_addr_mpu(CPUARMState *env, uint32_t address, int access_type,
-                            int is_user, uint32_t *phys_ptr, int *prot)
+/* Fault type for long-descriptor MMU fault reporting; this corresponds
+ * to bits [5..2] in the STATUS field in long-format DFSR/IFSR.
+ */
+typedef enum {
+    translation_fault = 1,
+    access_fault = 2,
+    permission_fault = 3,
+} MMUFaultType;
+
+static int get_phys_addr_lpae(CPUARMState *env, uint32_t address,
+                              int access_type, int is_user,
+                              hwaddr *phys_ptr, int *prot,
+                              target_ulong *page_size_ptr)
+{
+    /* Read an LPAE long-descriptor translation table. */
+    MMUFaultType fault_type = translation_fault;
+    uint32_t level = 1;
+    uint32_t epd;
+    uint32_t tsz;
+    uint64_t ttbr;
+    int ttbr_select;
+    int n;
+    hwaddr descaddr;
+    uint32_t tableattrs;
+    target_ulong page_size;
+    uint32_t attrs;
+
+    /* Determine whether this address is in the region controlled by
+     * TTBR0 or TTBR1 (or if it is in neither region and should fault).
+     * This is a Non-secure PL0/1 stage 1 translation, so controlled by
+     * TTBCR/TTBR0/TTBR1 in accordance with ARM ARM DDI0406C table B-32:
+     */
+    uint32_t t0sz = extract32(env->cp15.c2_control, 0, 3);
+    uint32_t t1sz = extract32(env->cp15.c2_control, 16, 3);
+    if (t0sz && !extract32(address, 32 - t0sz, t0sz)) {
+        /* there is a ttbr0 region and we are in it (high bits all zero) */
+        ttbr_select = 0;
+    } else if (t1sz && !extract32(~address, 32 - t1sz, t1sz)) {
+        /* there is a ttbr1 region and we are in it (high bits all one) */
+        ttbr_select = 1;
+    } else if (!t0sz) {
+        /* ttbr0 region is "everything not in the ttbr1 region" */
+        ttbr_select = 0;
+    } else if (!t1sz) {
+        /* ttbr1 region is "everything not in the ttbr0 region" */
+        ttbr_select = 1;
+    } else {
+        /* in the gap between the two regions, this is a Translation fault */
+        fault_type = translation_fault;
+        goto do_fault;
+    }
+
+    /* Note that QEMU ignores shareability and cacheability attributes,
+     * so we don't need to do anything with the SH, ORGN, IRGN fields
+     * in the TTBCR.  Similarly, TTBCR:A1 selects whether we get the
+     * ASID from TTBR0 or TTBR1, but QEMU's TLB doesn't currently
+     * implement any ASID-like capability so we can ignore it (instead
+     * we will always flush the TLB any time the ASID is changed).
+     */
+    if (ttbr_select == 0) {
+        ttbr = ((uint64_t)env->cp15.c2_base0_hi << 32) | env->cp15.c2_base0;
+        epd = extract32(env->cp15.c2_control, 7, 1);
+        tsz = t0sz;
+    } else {
+        ttbr = ((uint64_t)env->cp15.c2_base1_hi << 32) | env->cp15.c2_base1;
+        epd = extract32(env->cp15.c2_control, 23, 1);
+        tsz = t1sz;
+    }
+
+    if (epd) {
+        /* Translation table walk disabled => Translation fault on TLB miss */
+        goto do_fault;
+    }
+
+    /* If the region is small enough we will skip straight to a 2nd level
+     * lookup. This affects the number of bits of the address used in
+     * combination with the TTBR to find the first descriptor. ('n' here
+     * matches the usage in the ARM ARM sB3.6.6, where bits [39..n] are
+     * from the TTBR, [n-1..3] from the vaddr, and [2..0] always zero).
+     */
+    if (tsz > 1) {
+        level = 2;
+        n = 14 - tsz;
+    } else {
+        n = 5 - tsz;
+    }
+
+    /* Clear the vaddr bits which aren't part of the within-region address,
+     * so that we don't have to special case things when calculating the
+     * first descriptor address.
+     */
+    address &= (0xffffffffU >> tsz);
+
+    /* Now we can extract the actual base address from the TTBR */
+    descaddr = extract64(ttbr, 0, 40);
+    descaddr &= ~((1ULL << n) - 1);
+
+    tableattrs = 0;
+    for (;;) {
+        uint64_t descriptor;
+
+        descaddr |= ((address >> (9 * (4 - level))) & 0xff8);
+        descriptor = ldq_phys(descaddr);
+        if (!(descriptor & 1) ||
+            (!(descriptor & 2) && (level == 3))) {
+            /* Invalid, or the Reserved level 3 encoding */
+            goto do_fault;
+        }
+        descaddr = descriptor & 0xfffffff000ULL;
+
+        if ((descriptor & 2) && (level < 3)) {
+            /* Table entry. The top five bits are attributes which  may
+             * propagate down through lower levels of the table (and
+             * which are all arranged so that 0 means "no effect", so
+             * we can gather them up by ORing in the bits at each level).
+             */
+            tableattrs |= extract64(descriptor, 59, 5);
+            level++;
+            continue;
+        }
+        /* Block entry at level 1 or 2, or page entry at level 3.
+         * These are basically the same thing, although the number
+         * of bits we pull in from the vaddr varies.
+         */
+        page_size = (1 << (39 - (9 * level)));
+        descaddr |= (address & (page_size - 1));
+        /* Extract attributes from the descriptor and merge with table attrs */
+        attrs = extract64(descriptor, 2, 10)
+            | (extract64(descriptor, 52, 12) << 10);
+        attrs |= extract32(tableattrs, 0, 2) << 11; /* XN, PXN */
+        attrs |= extract32(tableattrs, 3, 1) << 5; /* APTable[1] => AP[2] */
+        /* The sense of AP[1] vs APTable[0] is reversed, as APTable[0] == 1
+         * means "force PL1 access only", which means forcing AP[1] to 0.
+         */
+        if (extract32(tableattrs, 2, 1)) {
+            attrs &= ~(1 << 4);
+        }
+        /* Since we're always in the Non-secure state, NSTable is ignored. */
+        break;
+    }
+    /* Here descaddr is the final physical address, and attributes
+     * are all in attrs.
+     */
+    fault_type = access_fault;
+    if ((attrs & (1 << 8)) == 0) {
+        /* Access flag */
+        goto do_fault;
+    }
+    fault_type = permission_fault;
+    if (is_user && !(attrs & (1 << 4))) {
+        /* Unprivileged access not enabled */
+        goto do_fault;
+    }
+    *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+    if (attrs & (1 << 12) || (!is_user && (attrs & (1 << 11)))) {
+        /* XN or PXN */
+        if (access_type == 2) {
+            goto do_fault;
+        }
+        *prot &= ~PAGE_EXEC;
+    }
+    if (attrs & (1 << 5)) {
+        /* Write access forbidden */
+        if (access_type == 1) {
+            goto do_fault;
+        }
+        *prot &= ~PAGE_WRITE;
+    }
+
+    *phys_ptr = descaddr;
+    *page_size_ptr = page_size;
+    return 0;
+
+do_fault:
+    /* Long-descriptor format IFSR/DFSR value */
+    return (1 << 9) | (fault_type << 2) | level;
+}
+
+static int get_phys_addr_mpu(CPUARMState *env, uint32_t address,
+                             int access_type, int is_user,
+                             hwaddr *phys_ptr, int *prot)
 {
     int n;
     uint32_t mask;
@@ -2091,9 +2427,32 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address, int access_type
     return 0;
 }
 
+/* get_phys_addr - get the physical address for this virtual address
+ *
+ * Find the physical address corresponding to the given virtual address,
+ * by doing a translation table walk on MMU based systems or using the
+ * MPU state on MPU based systems.
+ *
+ * Returns 0 if the translation was successful. Otherwise, phys_ptr,
+ * prot and page_size are not filled in, and the return value provides
+ * information on why the translation aborted, in the format of a
+ * DFSR/IFSR fault register, with the following caveats:
+ *  * we honour the short vs long DFSR format differences.
+ *  * the WnR bit is never set (the caller must do this).
+ *  * for MPU based systems we don't bother to return a full FSR format
+ *    value.
+ *
+ * @env: CPUARMState
+ * @address: virtual address to get physical address for
+ * @access_type: 0 for read, 1 for write, 2 for execute
+ * @is_user: 0 for privileged access, 1 for user
+ * @phys_ptr: set to the physical address corresponding to the virtual address
+ * @prot: set to the permissions for the page containing phys_ptr
+ * @page_size: set to the size of the page containing phys_ptr
+ */
 static inline int get_phys_addr(CPUARMState *env, uint32_t address,
                                 int access_type, int is_user,
-                                uint32_t *phys_ptr, int *prot,
+                                hwaddr *phys_ptr, int *prot,
                                 target_ulong *page_size)
 {
     /* Fast Context Switch Extension.  */
@@ -2110,6 +2469,9 @@ static inline int get_phys_addr(CPUARMState *env, uint32_t address,
         *page_size = TARGET_PAGE_SIZE;
        return get_phys_addr_mpu(env, address, access_type, is_user, phys_ptr,
                                 prot);
+    } else if (extended_addresses_enabled(env)) {
+        return get_phys_addr_lpae(env, address, access_type, is_user, phys_ptr,
+                                  prot, page_size);
     } else if (env->cp15.c1_sys & (1 << 23)) {
         return get_phys_addr_v6(env, address, access_type, is_user, phys_ptr,
                                 prot, page_size);
@@ -2122,7 +2484,7 @@ static inline int get_phys_addr(CPUARMState *env, uint32_t address,
 int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address,
                               int access_type, int mmu_idx)
 {
-    uint32_t phys_addr;
+    hwaddr phys_addr;
     target_ulong page_size;
     int prot;
     int ret, is_user;
@@ -2132,7 +2494,7 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address,
                         &page_size);
     if (ret == 0) {
         /* Map a single [sub]page.  */
-        phys_addr &= ~(uint32_t)0x3ff;
+        phys_addr &= ~(hwaddr)0x3ff;
         address &= ~(uint32_t)0x3ff;
         tlb_set_page (env, address, phys_addr, prot, mmu_idx, page_size);
         return 0;
@@ -2152,9 +2514,9 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address,
     return 1;
 }
 
-target_phys_addr_t cpu_get_phys_page_debug(CPUARMState *env, target_ulong addr)
+hwaddr cpu_get_phys_page_debug(CPUARMState *env, target_ulong addr)
 {
-    uint32_t phys_addr;
+    hwaddr phys_addr;
     target_ulong page_size;
     int prot;
     int ret;
@@ -2172,7 +2534,7 @@ void HELPER(set_r13_banked)(CPUARMState *env, uint32_t mode, uint32_t val)
     if ((env->uncached_cpsr & CPSR_M) == mode) {
         env->regs[13] = val;
     } else {
-        env->banked_r13[bank_number(env, mode)] = val;
+        env->banked_r13[bank_number(mode)] = val;
     }
 }
 
@@ -2181,7 +2543,7 @@ uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode)
     if ((env->uncached_cpsr & CPSR_M) == mode) {
         return env->regs[13];
     } else {
-        return env->banked_r13[bank_number(env, mode)];
+        return env->banked_r13[bank_number(mode)];
     }
 }
 
@@ -2535,13 +2897,8 @@ uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b)
     return (a & mask) | (b & ~mask);
 }
 
-uint32_t HELPER(logicq_cc)(uint64_t val)
-{
-    return (val >> 32) | (val != 0);
-}
-
-/* VFP support.  We follow the convention used for VFP instrunctions:
-   Single precition routines have a "s" suffix, double precision a
+/* VFP support.  We follow the convention used for VFP instructions:
+   Single precision routines have a "s" suffix, double precision a
    "d" suffix.  */
 
 /* Convert host exception flags to vfp form.  */