armv8: Add support of pointer authentication 48/7248/4
authorKoudai Iwahori <koudai@google.com>
Tue, 4 Oct 2022 11:21:35 +0000 (04:21 -0700)
committerAntonio Borneo <borneo.antonio@gmail.com>
Sun, 15 Jan 2023 14:51:44 +0000 (14:51 +0000)
When pointer authentication is enabled, some upper bits of the link
register (LR[63:VA_SIZE]) are used to store a signature. Therefore, GDB
need to remove the signature to get backtraces.
GDB has support of pointer authentication. When pointer authenticaion is
enabled, GDB requests 8-bytes mask to the target to remove the
signature. mask[63:VA_SIZE] should be all set and mask[VA_SIZE-1:0]
should be all cleared. GDB removes the signature by addr&~mask or
addr|mask.
I added a feature to provide the mask for pointer authentication.

Signed-off-by: Koudai Iwahori <koudai@google.com>
Change-Id: I56fbbf9cc23619b6536ecd326f350c8bf137f322
Reviewed-on: https://review.openocd.org/c/openocd/+/7248
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
doc/openocd.texi
src/target/armv8.c
src/target/armv8.h

index c7fee3e716446ced12159c8c6b96ab74232f91bc..aa1707b7dfae81e21278fa62b319244b1596e53b 100644 (file)
@@ -10297,6 +10297,16 @@ the target, the exception catch must be disabled again with @command{$target_nam
 Issuing the command without options prints the current configuration.
 @end deffn
 
+@deffn {Command} {$target_name pauth} [@option{off}|@option{on}]
+Enable or disable pointer authentication features.
+When pointer authentication is used on ARM cores, GDB asks GDB servers for an 8-bytes mask to remove signature bits added by pointer authentication.
+If this feature is enabled, OpenOCD provides GDB with an 8-bytes mask.
+Pointer authentication feature is broken until gdb 12.1, going to be fixed.
+Consider using a newer version of gdb if you want to enable pauth feature.
+The default configuration is @option{off}.
+@end deffn
+
+
 @section EnSilica eSi-RISC Architecture
 
 eSi-RISC is a highly configurable microprocessor architecture for embedded systems
index de0bddb3eaec0759653a22f4299ca5aa6bb30310..ff71a8e63456b9ff474d5b29018e966eaac3d175 100644 (file)
@@ -114,6 +114,166 @@ const char *armv8_mode_name(unsigned psr_mode)
        return "UNRECOGNIZED";
 }
 
+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;
+}
+
 static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regval)
 {
        struct arm_dpm *dpm = &armv8->dpm;
@@ -191,6 +351,10 @@ static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regv
                                ARMV8_MRS(SYSTEM_SPSR_EL3, 0), &value);
                value_64 = value;
                break;
+       case ARMV8_PAUTH_CMASK:
+       case ARMV8_PAUTH_DMASK:
+               retval = armv8_get_pauth_mask(armv8, &value_64);
+               break;
        default:
                retval = ERROR_FAIL;
                break;
@@ -772,152 +936,6 @@ static __attribute__((unused)) void armv8_show_fault_registers(struct target *ta
                armv8_show_fault_registers32(armv8);
 }
 
-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 __attribute__((unused)) 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;
-}
-
 /*  method adapted to cortex A : reused arm v4 v5 method*/
 int armv8_mmu_translate_va(struct target *target,  target_addr_t va, target_addr_t *val)
 {
@@ -1083,6 +1101,15 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(armv8_pauth_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct armv8_common *armv8 = target_to_armv8(target);
+       return CALL_COMMAND_HANDLER(handle_command_parse_bool,
+                                   &armv8->enable_pauth,
+                                   "pauth feature");
+}
+
 int armv8_handle_cache_info_command(struct command_invocation *cmd,
        struct armv8_cache_common *armv8_cache)
 {
@@ -1421,6 +1448,8 @@ static const struct {
                                                                                                                NULL},
        { ARMV8_SPSR_EL3, "SPSR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked",
                                                                                                                NULL},
+       { ARMV8_PAUTH_DMASK, "pauth_dmask", 64, ARM_MODE_ANY, REG_TYPE_UINT64, NULL, "org.gnu.gdb.aarch64.pauth", NULL},
+       { ARMV8_PAUTH_CMASK, "pauth_cmask", 64, ARM_MODE_ANY, REG_TYPE_UINT64, NULL, "org.gnu.gdb.aarch64.pauth", NULL},
 };
 
 static const struct {
@@ -1650,6 +1679,9 @@ struct reg_cache *armv8_build_reg_cache(struct target *target)
                                *reg_list[i].reg_data_type = *armv8_regs[i].data_type;
                } else
                        LOG_ERROR("unable to allocate reg type list");
+
+               if (i == ARMV8_PAUTH_CMASK || i == ARMV8_PAUTH_DMASK)
+                       reg_list[i].hidden = !armv8->enable_pauth;
        }
 
        arm->cpsr = reg_list + ARMV8_XPSR;
@@ -1745,6 +1777,17 @@ const struct command_registration armv8_command_handlers[] = {
                .help = "configure exception catch",
                .usage = "[(nsec_el1,nsec_el2,sec_el1,sec_el3)+,off]",
        },
+       {
+               .name = "pauth",
+               .handler = armv8_pauth_command,
+               .mode = COMMAND_CONFIG,
+               .help = "enable or disable providing GDB with an 8-bytes mask to "
+                       "remove signature bits added by pointer authentication."
+                       "Pointer authentication feature is broken until gdb 12.1, going to be fixed. "
+                       "Consider using a newer version of gdb if you want enable "
+                       "pauth feature.",
+               .usage = "[on|off]",
+       },
        COMMAND_REGISTRATION_DONE
 };
 
index 2ed3a65acd9e8fb3f015f99b690a71090d3a9d2a..54aa08634ccdb3c0256a392013c55212696444c1 100644 (file)
@@ -98,6 +98,10 @@ enum {
        ARMV8_ESR_EL3 = 75,
        ARMV8_SPSR_EL3 = 76,
 
+       /* Pseudo registers defined by GDB to remove the pauth signature. */
+       ARMV8_PAUTH_DMASK = 77,
+       ARMV8_PAUTH_CMASK = 78,
+
        ARMV8_LAST_REG,
 };
 
@@ -205,6 +209,9 @@ struct armv8_common {
 
        struct arm_cti *cti;
 
+       /* True if OpenOCD provides pointer auth related info to GDB */
+       bool enable_pauth;
+
        /* last run-control command issued to this target (resume, halt, step) */
        enum run_control_op last_run_control_op;
 

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)