+static uint8_t armv8_pa_size(uint32_t ps)
+{
+ uint8_t ret = 0;
+ switch (ps) {
+ case 0:
+ ret = 32;
+ break;
+ case 1:
+ ret = 36;
+ break;
+ case 2:
+ ret = 40;
+ break;
+ case 3:
+ ret = 42;
+ break;
+ case 4:
+ ret = 44;
+ break;
+ case 5:
+ ret = 48;
+ break;
+ default:
+ LOG_INFO("Unknown physical address size");
+ break;
+ }
+ return ret;
+}
+
+static __attribute__((unused)) int armv8_read_ttbcr32(struct target *target)
+{
+ struct armv8_common *armv8 = target_to_armv8(target);
+ struct arm_dpm *dpm = armv8->arm.dpm;
+ uint32_t ttbcr, ttbcr_n;
+ int retval = dpm->prepare(dpm);
+ if (retval != ERROR_OK)
+ goto done;
+ /* MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/
+ retval = dpm->instr_read_data_r0(dpm,
+ ARMV4_5_MRC(15, 0, 0, 2, 0, 2),
+ &ttbcr);
+ if (retval != ERROR_OK)
+ goto done;
+
+ LOG_DEBUG("ttbcr %" PRIx32, ttbcr);
+
+ ttbcr_n = ttbcr & 0x7;
+ armv8->armv8_mmu.ttbcr = ttbcr;
+
+ /*
+ * ARM Architecture Reference Manual (ARMv7-A and ARMv7-R edition),
+ * document # ARM DDI 0406C
+ */
+ armv8->armv8_mmu.ttbr_range[0] = 0xffffffff >> ttbcr_n;
+ armv8->armv8_mmu.ttbr_range[1] = 0xffffffff;
+ armv8->armv8_mmu.ttbr_mask[0] = 0xffffffff << (14 - ttbcr_n);
+ armv8->armv8_mmu.ttbr_mask[1] = 0xffffffff << 14;
+
+ LOG_DEBUG("ttbr1 %s, ttbr0_mask %" PRIx32 " ttbr1_mask %" PRIx32,
+ (ttbcr_n != 0) ? "used" : "not used",
+ armv8->armv8_mmu.ttbr_mask[0],
+ armv8->armv8_mmu.ttbr_mask[1]);
+
+done:
+ dpm->finish(dpm);
+ return retval;
+}
+
+static int armv8_read_ttbcr(struct target *target)
+{
+ struct armv8_common *armv8 = target_to_armv8(target);
+ struct arm_dpm *dpm = armv8->arm.dpm;
+ struct arm *arm = &armv8->arm;
+ uint32_t ttbcr;
+ uint64_t ttbcr_64;
+
+ int retval = dpm->prepare(dpm);
+ if (retval != ERROR_OK)
+ goto done;
+
+ /* clear ttrr1_used and ttbr0_mask */
+ memset(&armv8->armv8_mmu.ttbr1_used, 0, sizeof(armv8->armv8_mmu.ttbr1_used));
+ memset(&armv8->armv8_mmu.ttbr0_mask, 0, sizeof(armv8->armv8_mmu.ttbr0_mask));
+
+ switch (armv8_curel_from_core_mode(arm->core_mode)) {
+ case SYSTEM_CUREL_EL3:
+ retval = dpm->instr_read_data_r0(dpm,
+ ARMV8_MRS(SYSTEM_TCR_EL3, 0),
+ &ttbcr);
+ retval += dpm->instr_read_data_r0_64(dpm,
+ ARMV8_MRS(SYSTEM_TTBR0_EL3, 0),
+ &armv8->ttbr_base);
+ if (retval != ERROR_OK)
+ goto done;
+ armv8->va_size = 64 - (ttbcr & 0x3F);
+ armv8->pa_size = armv8_pa_size((ttbcr >> 16) & 7);
+ armv8->page_size = (ttbcr >> 14) & 3;
+ break;
+ case SYSTEM_CUREL_EL2:
+ retval = dpm->instr_read_data_r0(dpm,
+ ARMV8_MRS(SYSTEM_TCR_EL2, 0),
+ &ttbcr);
+ retval += dpm->instr_read_data_r0_64(dpm,
+ ARMV8_MRS(SYSTEM_TTBR0_EL2, 0),
+ &armv8->ttbr_base);
+ if (retval != ERROR_OK)
+ goto done;
+ armv8->va_size = 64 - (ttbcr & 0x3F);
+ armv8->pa_size = armv8_pa_size((ttbcr >> 16) & 7);
+ armv8->page_size = (ttbcr >> 14) & 3;
+ break;
+ case SYSTEM_CUREL_EL0:
+ armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H);
+ /* fall through */
+ case SYSTEM_CUREL_EL1:
+ retval = dpm->instr_read_data_r0_64(dpm,
+ ARMV8_MRS(SYSTEM_TCR_EL1, 0),
+ &ttbcr_64);
+ armv8->va_size = 64 - (ttbcr_64 & 0x3F);
+ armv8->pa_size = armv8_pa_size((ttbcr_64 >> 32) & 7);
+ armv8->page_size = (ttbcr_64 >> 14) & 3;
+ armv8->armv8_mmu.ttbr1_used = (((ttbcr_64 >> 16) & 0x3F) != 0) ? 1 : 0;
+ armv8->armv8_mmu.ttbr0_mask = 0x0000FFFFFFFFFFFF;
+ retval += dpm->instr_read_data_r0_64(dpm,
+ ARMV8_MRS(SYSTEM_TTBR0_EL1 | (armv8->armv8_mmu.ttbr1_used), 0),
+ &armv8->ttbr_base);
+ if (retval != ERROR_OK)
+ goto done;
+ break;
+ default:
+ LOG_ERROR("unknown core state");
+ retval = ERROR_FAIL;
+ break;
+ }
+ if (retval != ERROR_OK)
+ goto done;
+
+ if (armv8->armv8_mmu.ttbr1_used == 1)
+ LOG_INFO("TTBR0 access above %" PRIx64, (uint64_t)(armv8->armv8_mmu.ttbr0_mask));
+
+done:
+ armv8_dpm_modeswitch(dpm, ARM_MODE_ANY);
+ dpm->finish(dpm);
+ return retval;
+}
+
+static int armv8_get_pauth_mask(struct armv8_common *armv8, uint64_t *mask)
+{
+ struct arm *arm = &armv8->arm;
+ int retval = ERROR_OK;
+ if (armv8->va_size == 0)
+ retval = armv8_read_ttbcr(arm->target);
+ if (retval != ERROR_OK)
+ return retval;
+
+ *mask = ~(((uint64_t)1 << armv8->va_size) - 1);
+
+ return retval;
+}
+