armv4_5: Improve arm_blank_check_memory() error handling
[openocd.git] / src / target / armv4_5.c
index 633e1c717ff757f46acf545fe0a645260752dda3..18ce7df316c5f7e4397315a5dda1ef096510bec1 100644 (file)
@@ -21,7 +21,7 @@
  *   You should have received a copy of the GNU General Public License     *
  *   along with this program; if not, write to the                         *
  *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
@@ -45,7 +45,7 @@ enum {
        ARMV4_5_SPSR_SVC = 34,
        ARMV4_5_SPSR_ABT = 35,
        ARMV4_5_SPSR_UND = 36,
-       ARM_SPSR_MON = 39,
+       ARM_SPSR_MON = 41,
 };
 
 static const uint8_t arm_usr_indices[17] = {
@@ -73,7 +73,7 @@ static const uint8_t arm_und_indices[3] = {
 };
 
 static const uint8_t arm_mon_indices[3] = {
-       37, 38, ARM_SPSR_MON,
+       39, 40, ARM_SPSR_MON,
 };
 
 static const struct {
@@ -140,6 +140,27 @@ static const struct {
                .n_indices = ARRAY_SIZE(arm_mon_indices),
                .indices = arm_mon_indices,
        },
+       {
+               .name = "Secure Monitor ARM1176JZF-S",
+               .psr = ARM_MODE_1176_MON,
+               .n_indices = ARRAY_SIZE(arm_mon_indices),
+               .indices = arm_mon_indices,
+       },
+
+       /* These special modes are currently only supported
+        * by ARMv6M and ARMv7M profiles */
+       {
+               .name = "Thread",
+               .psr = ARM_MODE_THREAD,
+       },
+       {
+               .name = "Thread (User)",
+               .psr = ARM_MODE_USER_THREAD,
+       },
+       {
+               .name = "Handler",
+               .psr = ARM_MODE_HANDLER,
+       },
 };
 
 /** Map PSR mode bits to the name of an ARM processor operating mode. */
@@ -184,6 +205,7 @@ int arm_mode_to_number(enum arm_mode mode)
                case ARM_MODE_SYS:
                        return 6;
                case ARM_MODE_MON:
+               case ARM_MODE_1176_MON:
                        return 7;
                default:
                        LOG_ERROR("invalid mode value encountered %d", mode);
@@ -243,69 +265,81 @@ static const struct {
         * (Exception modes have both CPSR and SPSR registers ...)
         */
        unsigned cookie;
+       unsigned gdb_index;
        enum arm_mode mode;
 } arm_core_regs[] = {
        /* IMPORTANT:  we guarantee that the first eight cached registers
         * correspond to r0..r7, and the fifteenth to PC, so that callers
         * don't need to map them.
         */
-       { .name = "r0", .cookie = 0, .mode = ARM_MODE_ANY, },
-       { .name = "r1", .cookie = 1, .mode = ARM_MODE_ANY, },
-       { .name = "r2", .cookie = 2, .mode = ARM_MODE_ANY, },
-       { .name = "r3", .cookie = 3, .mode = ARM_MODE_ANY, },
-       { .name = "r4", .cookie = 4, .mode = ARM_MODE_ANY, },
-       { .name = "r5", .cookie = 5, .mode = ARM_MODE_ANY, },
-       { .name = "r6", .cookie = 6, .mode = ARM_MODE_ANY, },
-       { .name = "r7", .cookie = 7, .mode = ARM_MODE_ANY, },
+       { .name = "r0", .cookie = 0, .mode = ARM_MODE_ANY, .gdb_index = 0, },
+       { .name = "r1", .cookie = 1, .mode = ARM_MODE_ANY, .gdb_index = 1, },
+       { .name = "r2", .cookie = 2, .mode = ARM_MODE_ANY, .gdb_index = 2, },
+       { .name = "r3", .cookie = 3, .mode = ARM_MODE_ANY, .gdb_index = 3, },
+       { .name = "r4", .cookie = 4, .mode = ARM_MODE_ANY, .gdb_index = 4, },
+       { .name = "r5", .cookie = 5, .mode = ARM_MODE_ANY, .gdb_index = 5, },
+       { .name = "r6", .cookie = 6, .mode = ARM_MODE_ANY, .gdb_index = 6, },
+       { .name = "r7", .cookie = 7, .mode = ARM_MODE_ANY, .gdb_index = 7, },
 
        /* NOTE: regs 8..12 might be shadowed by FIQ ... flagging
         * them as MODE_ANY creates special cases.  (ANY means
         * "not mapped" elsewhere; here it's "everything but FIQ".)
         */
-       { .name = "r8", .cookie = 8, .mode = ARM_MODE_ANY, },
-       { .name = "r9", .cookie = 9, .mode = ARM_MODE_ANY, },
-       { .name = "r10", .cookie = 10, .mode = ARM_MODE_ANY, },
-       { .name = "r11", .cookie = 11, .mode = ARM_MODE_ANY, },
-       { .name = "r12", .cookie = 12, .mode = ARM_MODE_ANY, },
+       { .name = "r8", .cookie = 8, .mode = ARM_MODE_ANY, .gdb_index = 8, },
+       { .name = "r9", .cookie = 9, .mode = ARM_MODE_ANY, .gdb_index = 9, },
+       { .name = "r10", .cookie = 10, .mode = ARM_MODE_ANY, .gdb_index = 10, },
+       { .name = "r11", .cookie = 11, .mode = ARM_MODE_ANY, .gdb_index = 11, },
+       { .name = "r12", .cookie = 12, .mode = ARM_MODE_ANY, .gdb_index = 12, },
+
+       /* Historical GDB mapping of indices:
+        *  - 13-14 are sp and lr, but banked counterparts are used
+        *  - 16-24 are left for deprecated 8 FPA + 1 FPS
+        *  - 25 is the cpsr
+        */
 
        /* NOTE all MODE_USR registers are equivalent to MODE_SYS ones */
-       { .name = "sp_usr", .cookie = 13, .mode = ARM_MODE_USR, },
-       { .name = "lr_usr", .cookie = 14, .mode = ARM_MODE_USR, },
+       { .name = "sp_usr", .cookie = 13, .mode = ARM_MODE_USR, .gdb_index = 26, },
+       { .name = "lr_usr", .cookie = 14, .mode = ARM_MODE_USR, .gdb_index = 27, },
 
        /* guaranteed to be at index 15 */
-       { .name = "pc", .cookie = 15, .mode = ARM_MODE_ANY, },
+       { .name = "pc", .cookie = 15, .mode = ARM_MODE_ANY, .gdb_index = 15, },
+       { .name = "r8_fiq", .cookie = 8, .mode = ARM_MODE_FIQ, .gdb_index = 28, },
+       { .name = "r9_fiq", .cookie = 9, .mode = ARM_MODE_FIQ, .gdb_index = 29, },
+       { .name = "r10_fiq", .cookie = 10, .mode = ARM_MODE_FIQ, .gdb_index = 30, },
+       { .name = "r11_fiq", .cookie = 11, .mode = ARM_MODE_FIQ, .gdb_index = 31, },
+       { .name = "r12_fiq", .cookie = 12, .mode = ARM_MODE_FIQ, .gdb_index = 32, },
 
-       { .name = "r8_fiq", .cookie = 8, .mode = ARM_MODE_FIQ, },
-       { .name = "r9_fiq", .cookie = 9, .mode = ARM_MODE_FIQ, },
-       { .name = "r10_fiq", .cookie = 10, .mode = ARM_MODE_FIQ, },
-       { .name = "r11_fiq", .cookie = 11, .mode = ARM_MODE_FIQ, },
-       { .name = "r12_fiq", .cookie = 12, .mode = ARM_MODE_FIQ, },
+       { .name = "sp_fiq", .cookie = 13, .mode = ARM_MODE_FIQ, .gdb_index = 33, },
+       { .name = "lr_fiq", .cookie = 14, .mode = ARM_MODE_FIQ, .gdb_index = 34, },
 
-       { .name = "sp_fiq", .cookie = 13, .mode = ARM_MODE_FIQ, },
-       { .name = "lr_fiq", .cookie = 14, .mode = ARM_MODE_FIQ, },
+       { .name = "sp_irq", .cookie = 13, .mode = ARM_MODE_IRQ, .gdb_index = 35, },
+       { .name = "lr_irq", .cookie = 14, .mode = ARM_MODE_IRQ, .gdb_index = 36, },
 
-       { .name = "sp_irq", .cookie = 13, .mode = ARM_MODE_IRQ, },
-       { .name = "lr_irq", .cookie = 14, .mode = ARM_MODE_IRQ, },
+       { .name = "sp_svc", .cookie = 13, .mode = ARM_MODE_SVC, .gdb_index = 37, },
+       { .name = "lr_svc", .cookie = 14, .mode = ARM_MODE_SVC, .gdb_index = 38, },
 
-       { .name = "sp_svc", .cookie = 13, .mode = ARM_MODE_SVC, },
-       { .name = "lr_svc", .cookie = 14, .mode = ARM_MODE_SVC, },
+       { .name = "sp_abt", .cookie = 13, .mode = ARM_MODE_ABT, .gdb_index = 39, },
+       { .name = "lr_abt", .cookie = 14, .mode = ARM_MODE_ABT, .gdb_index = 40, },
 
-       { .name = "sp_abt", .cookie = 13, .mode = ARM_MODE_ABT, },
-       { .name = "lr_abt", .cookie = 14, .mode = ARM_MODE_ABT, },
+       { .name = "sp_und", .cookie = 13, .mode = ARM_MODE_UND, .gdb_index = 41, },
+       { .name = "lr_und", .cookie = 14, .mode = ARM_MODE_UND, .gdb_index = 42, },
 
-       { .name = "sp_und", .cookie = 13, .mode = ARM_MODE_UND, },
-       { .name = "lr_und", .cookie = 14, .mode = ARM_MODE_UND, },
+       { .name = "cpsr", .cookie = 16, .mode = ARM_MODE_ANY, .gdb_index = 25, },
+       { .name = "spsr_fiq", .cookie = 16, .mode = ARM_MODE_FIQ, .gdb_index = 43, },
+       { .name = "spsr_irq", .cookie = 16, .mode = ARM_MODE_IRQ, .gdb_index = 44, },
+       { .name = "spsr_svc", .cookie = 16, .mode = ARM_MODE_SVC, .gdb_index = 45, },
+       { .name = "spsr_abt", .cookie = 16, .mode = ARM_MODE_ABT, .gdb_index = 46, },
+       { .name = "spsr_und", .cookie = 16, .mode = ARM_MODE_UND, .gdb_index = 47, },
 
-       { .name = "cpsr", .cookie = 16, .mode = ARM_MODE_ANY, },
-       { .name = "spsr_fiq", .cookie = 16, .mode = ARM_MODE_FIQ, },
-       { .name = "spsr_irq", .cookie = 16, .mode = ARM_MODE_IRQ, },
-       { .name = "spsr_svc", .cookie = 16, .mode = ARM_MODE_SVC, },
-       { .name = "spsr_abt", .cookie = 16, .mode = ARM_MODE_ABT, },
-       { .name = "spsr_und", .cookie = 16, .mode = ARM_MODE_UND, },
+       /* These are only used for GDB target description, banked registers are accessed instead */
+       { .name = "sp", .cookie = 13, .mode = ARM_MODE_ANY, .gdb_index = 13, },
+       { .name = "lr", .cookie = 14, .mode = ARM_MODE_ANY, .gdb_index = 14, },
+
+       /* These exist only when the Security Extension (TrustZone) is present */
+       { .name = "sp_mon", .cookie = 13, .mode = ARM_MODE_MON, .gdb_index = 48, },
+       { .name = "lr_mon", .cookie = 14, .mode = ARM_MODE_MON, .gdb_index = 49, },
+       { .name = "spsr_mon", .cookie = 16, .mode = ARM_MODE_MON, .gdb_index = 50, },
 
-       { .name = "sp_mon", .cookie = 13, .mode = ARM_MODE_MON, },
-       { .name = "lr_mon", .cookie = 14, .mode = ARM_MODE_MON, },
-       { .name = "spsr_mon", .cookie = 16, .mode = ARM_MODE_MON, },
 };
 
 /* map core mode (USR, FIQ, ...) and register number to
@@ -414,7 +448,11 @@ struct reg *arm_reg_current(struct arm *arm, unsigned regnum)
        if (regnum > 16)
                return NULL;
 
-       r = arm->core_cache->reg_list + arm->map[regnum];
+       if (!arm->map) {
+               LOG_ERROR("Register map is not available yet, the target is not fully initialised");
+               r = arm->core_cache->reg_list + regnum;
+       } else
+               r = arm->core_cache->reg_list + arm->map[regnum];
 
        /* e.g. invalid CPSR said "secure monitor" mode on a core
         * that doesn't support it...
@@ -429,6 +467,10 @@ struct reg *arm_reg_current(struct arm *arm, unsigned regnum)
 
 static const uint8_t arm_gdb_dummy_fp_value[12];
 
+static struct reg_feature arm_gdb_dummy_fp_features = {
+       .name = "net.sourceforge.openocd.fake_fpa"
+};
+
 /**
  * Dummy FPA registers are required to support GDB on ARM.
  * Register packets require eight obsolete FPA register values.
@@ -440,6 +482,10 @@ struct reg arm_gdb_dummy_fp_reg = {
        .value = (uint8_t *) arm_gdb_dummy_fp_value,
        .valid = 1,
        .size = 96,
+       .exist = false,
+       .number = 16,
+       .feature = &arm_gdb_dummy_fp_features,
+       .group = "fake_fpa",
 };
 
 static const uint8_t arm_gdb_dummy_fps_value[4];
@@ -453,6 +499,10 @@ struct reg arm_gdb_dummy_fps_reg = {
        .value = (uint8_t *) arm_gdb_dummy_fps_value,
        .valid = 1,
        .size = 32,
+       .exist = false,
+       .number = 24,
+       .feature = &arm_gdb_dummy_fp_features,
+       .group = "fake_fpa",
 };
 
 static void arm_gdb_dummy_init(void) __attribute__ ((constructor));
@@ -512,8 +562,10 @@ static int armv4_5_set_core_reg(struct reg *reg, uint8_t *buf)
                        LOG_DEBUG("changing ARM core mode to '%s'",
                                arm_mode_name(value & 0x1f));
                        value &= ~((1 << 24) | (1 << 5));
+                       uint8_t t[4];
+                       buf_set_u32(t, 0, 32, value);
                        armv4_5_target->write_core_reg(target, reg,
-                               16, ARM_MODE_ANY, value);
+                               16, ARM_MODE_ANY, t);
                }
        } else {
                buf_set_u32(reg->value, 0, 32, value);
@@ -562,11 +614,41 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm)
                reg_arch_info[i].target = target;
                reg_arch_info[i].arm = arm;
 
-               reg_list[i].name = (char *) arm_core_regs[i].name;
+               reg_list[i].name = arm_core_regs[i].name;
+               reg_list[i].number = arm_core_regs[i].gdb_index;
                reg_list[i].size = 32;
-               reg_list[i].value = &reg_arch_info[i].value;
+               reg_list[i].value = reg_arch_info[i].value;
                reg_list[i].type = &arm_reg_type;
                reg_list[i].arch_info = &reg_arch_info[i];
+               reg_list[i].exist = true;
+
+               /* This really depends on the calling convention in use */
+               reg_list[i].caller_save = false;
+
+               /* Registers data type, as used by GDB target description */
+               reg_list[i].reg_data_type = malloc(sizeof(struct reg_data_type));
+               switch (arm_core_regs[i].cookie) {
+               case 13:
+                       reg_list[i].reg_data_type->type = REG_TYPE_DATA_PTR;
+                       break;
+               case 14:
+               case 15:
+                       reg_list[i].reg_data_type->type = REG_TYPE_CODE_PTR;
+                   break;
+               default:
+                       reg_list[i].reg_data_type->type = REG_TYPE_UINT32;
+                   break;
+               }
+
+               /* let GDB shows banked registers only in "info all-reg" */
+               reg_list[i].feature = malloc(sizeof(struct reg_feature));
+               if (reg_list[i].number <= 15 || reg_list[i].number == 25) {
+                       reg_list[i].feature->name = "org.gnu.gdb.arm.core";
+                       reg_list[i].group = "general";
+               } else {
+                       reg_list[i].feature->name = "net.sourceforge.openocd.banked";
+                       reg_list[i].group = "banked";
+               }
 
                cache->num_regs++;
        }
@@ -1002,13 +1084,13 @@ static const struct command_registration arm_exec_command_handlers[] = {
                .mode = COMMAND_EXEC,
                .jim_handler = &jim_mcrmrc,
                .help = "write coprocessor register",
-               .usage = "cpnum op1 CRn op2 CRm value",
+               .usage = "cpnum op1 CRn CRm op2 value",
        },
        {
                .name = "mrc",
                .jim_handler = &jim_mcrmrc,
                .help = "read coprocessor register",
-               .usage = "cpnum op1 CRn op2 CRm",
+               .usage = "cpnum op1 CRn CRm op2",
        },
        {
                "semihosting",
@@ -1032,29 +1114,65 @@ const struct command_registration arm_command_handlers[] = {
 };
 
 int arm_get_gdb_reg_list(struct target *target,
-       struct reg **reg_list[], int *reg_list_size)
+       struct reg **reg_list[], int *reg_list_size,
+       enum target_register_class reg_class)
 {
        struct arm *arm = target_to_arm(target);
-       int i;
+       unsigned int i;
 
        if (!is_arm_mode(arm->core_mode)) {
                LOG_ERROR("not a valid arm core mode - communication failure?");
                return ERROR_FAIL;
        }
 
-       *reg_list_size = 26;
-       *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
+       switch (reg_class) {
+       case REG_CLASS_GENERAL:
+               *reg_list_size = 26;
+               *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
 
-       for (i = 0; i < 16; i++)
-               (*reg_list)[i] = arm_reg_current(arm, i);
+               for (i = 0; i < 16; i++)
+                               (*reg_list)[i] = arm_reg_current(arm, i);
 
-       for (i = 16; i < 24; i++)
-               (*reg_list)[i] = &arm_gdb_dummy_fp_reg;
+               /* For GDB compatibility, take FPA registers size into account and zero-fill it*/
+               for (i = 16; i < 24; i++)
+                               (*reg_list)[i] = &arm_gdb_dummy_fp_reg;
+               (*reg_list)[24] = &arm_gdb_dummy_fps_reg;
 
-       (*reg_list)[24] = &arm_gdb_dummy_fps_reg;
-       (*reg_list)[25] = arm->cpsr;
+               (*reg_list)[25] = arm->cpsr;
 
-       return ERROR_OK;
+               return ERROR_OK;
+               break;
+
+       case REG_CLASS_ALL:
+               *reg_list_size = (arm->core_type != ARM_MODE_MON ? 48 : 51);
+               *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
+
+               for (i = 0; i < 16; i++)
+                               (*reg_list)[i] = arm_reg_current(arm, i);
+
+               for (i = 13; i < ARRAY_SIZE(arm_core_regs); i++) {
+                               int reg_index = arm->core_cache->reg_list[i].number;
+                               if (!(arm_core_regs[i].mode == ARM_MODE_MON
+                                               && arm->core_type != ARM_MODE_MON))
+                                       (*reg_list)[reg_index] = &(arm->core_cache->reg_list[i]);
+               }
+
+               /* When we supply the target description, there is no need for fake FPA */
+               for (i = 16; i < 24; i++) {
+                               (*reg_list)[i] = &arm_gdb_dummy_fp_reg;
+                               (*reg_list)[i]->size = 0;
+               }
+               (*reg_list)[24] = &arm_gdb_dummy_fps_reg;
+               (*reg_list)[24]->size = 0;
+
+               return ERROR_OK;
+               break;
+
+       default:
+               LOG_ERROR("not a valid register class type in query.");
+               return ERROR_FAIL;
+               break;
+       }
 }
 
 /* wait for execution to complete and check exit point */
@@ -1300,7 +1418,7 @@ int arm_checksum_memory(struct target *target,
        uint32_t address, uint32_t count, uint32_t *checksum)
 {
        struct working_area *crc_algorithm;
-       struct arm_algorithm armv4_5_info;
+       struct arm_algorithm arm_algo;
        struct arm *arm = target_to_arm(target);
        struct reg_param reg_params[2];
        int retval;
@@ -1352,9 +1470,9 @@ int arm_checksum_memory(struct target *target,
                        return retval;
        }
 
-       armv4_5_info.common_magic = ARM_COMMON_MAGIC;
-       armv4_5_info.core_mode = ARM_MODE_SVC;
-       armv4_5_info.core_state = ARM_STATE_ARM;
+       arm_algo.common_magic = ARM_COMMON_MAGIC;
+       arm_algo.core_mode = ARM_MODE_SVC;
+       arm_algo.core_state = ARM_STATE_ARM;
 
        init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
        init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
@@ -1372,7 +1490,7 @@ int arm_checksum_memory(struct target *target,
        retval = target_run_algorithm(target, 0, NULL, 2, reg_params,
                        crc_algorithm->address,
                        exit_var,
-                       timeout, &armv4_5_info);
+                       timeout, &arm_algo);
        if (retval != ERROR_OK) {
                LOG_ERROR("error executing ARM crc algorithm");
                destroy_reg_param(&reg_params[0]);
@@ -1402,7 +1520,7 @@ int arm_blank_check_memory(struct target *target,
 {
        struct working_area *check_algorithm;
        struct reg_param reg_params[3];
-       struct arm_algorithm armv4_5_info;
+       struct arm_algorithm arm_algo;
        struct arm *arm = target_to_arm(target);
        int retval;
        uint32_t i;
@@ -1433,12 +1551,12 @@ int arm_blank_check_memory(struct target *target,
                                + i * sizeof(uint32_t),
                                check_code[i]);
                if (retval != ERROR_OK)
-                       return retval;
+                       goto cleanup;
        }
 
-       armv4_5_info.common_magic = ARM_COMMON_MAGIC;
-       armv4_5_info.core_mode = ARM_MODE_SVC;
-       armv4_5_info.core_state = ARM_STATE_ARM;
+       arm_algo.common_magic = ARM_COMMON_MAGIC;
+       arm_algo.core_mode = ARM_MODE_SVC;
+       arm_algo.core_state = ARM_STATE_ARM;
 
        init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
        buf_set_u32(reg_params[0].value, 0, 32, address);
@@ -1456,24 +1574,19 @@ int arm_blank_check_memory(struct target *target,
        retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
                        check_algorithm->address,
                        exit_var,
-                       10000, &armv4_5_info);
-       if (retval != ERROR_OK) {
-               destroy_reg_param(&reg_params[0]);
-               destroy_reg_param(&reg_params[1]);
-               destroy_reg_param(&reg_params[2]);
-               target_free_working_area(target, check_algorithm);
-               return retval;
-       }
+                       10000, &arm_algo);
 
-       *blank = buf_get_u32(reg_params[2].value, 0, 32);
+       if (retval == ERROR_OK)
+               *blank = buf_get_u32(reg_params[2].value, 0, 32);
 
        destroy_reg_param(&reg_params[0]);
        destroy_reg_param(&reg_params[1]);
        destroy_reg_param(&reg_params[2]);
 
+cleanup:
        target_free_working_area(target, check_algorithm);
 
-       return ERROR_OK;
+       return retval;
 }
 
 static int arm_full_context(struct target *target)

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)