ARM11: register (most) standard ARM commands
[openocd.git] / src / target / armv4_5.c
index 6e3eff68e79b68c96eb48a8d6fe468dff70fc01d..b60b8b275dd0caed6d428198fffed7c21807de73 100644 (file)
 #endif
 
 #include "armv4_5.h"
+#include "arm_jtag.h"
+#include "breakpoints.h"
 #include "arm_disassembler.h"
 #include "binarybuffer.h"
+#include "algorithm.h"
+#include "register.h"
 
 
-struct bitfield_desc armv4_5_psr_bitfield_desc[] =
-{
-       {"M[4:0]", 5},
-       {"T", 1},
-       {"F", 1},
-       {"I", 1},
-       {"reserved", 16},
-       {"J", 1},
-       {"reserved", 2},
-       {"Q", 1},
-       {"V", 1},
-       {"C", 1},
-       {"Z", 1},
-       {"N", 1},
-};
-
 char* armv4_5_core_reg_list[] =
 {
        "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13_usr", "lr_usr", "pc",
@@ -65,13 +53,63 @@ char* armv4_5_core_reg_list[] =
        "cpsr", "spsr_fiq", "spsr_irq", "spsr_svc", "spsr_abt", "spsr_und"
 };
 
-char * armv4_5_mode_strings_list[] =
+static const char *armv4_5_mode_strings_list[] =
 {
        "Illegal mode value", "User", "FIQ", "IRQ", "Supervisor", "Abort", "Undefined", "System"
 };
 
 /* Hack! Yuk! allow -1 index, which simplifies codepaths elsewhere in the code */
-char** armv4_5_mode_strings = armv4_5_mode_strings_list + 1;
+const char **armv4_5_mode_strings = armv4_5_mode_strings_list + 1;
+
+/** Map PSR mode bits to linear number */
+int armv4_5_mode_to_number(enum armv4_5_mode mode)
+{
+       switch (mode) {
+       case ARMV4_5_MODE_ANY:
+               /* map MODE_ANY to user mode */
+       case ARMV4_5_MODE_USR:
+               return 0;
+       case ARMV4_5_MODE_FIQ:
+               return 1;
+       case ARMV4_5_MODE_IRQ:
+               return 2;
+       case ARMV4_5_MODE_SVC:
+               return 3;
+       case ARMV4_5_MODE_ABT:
+               return 4;
+       case ARMV4_5_MODE_UND:
+               return 5;
+       case ARMV4_5_MODE_SYS:
+               return 6;
+       default:
+               LOG_ERROR("invalid mode value encountered %d", mode);
+               return -1;
+       }
+}
+
+/** Map linear number to PSR mode bits. */
+enum armv4_5_mode armv4_5_number_to_mode(int number)
+{
+       switch (number) {
+       case 0:
+               return ARMV4_5_MODE_USR;
+       case 1:
+               return ARMV4_5_MODE_FIQ;
+       case 2:
+               return ARMV4_5_MODE_IRQ;
+       case 3:
+               return ARMV4_5_MODE_SVC;
+       case 4:
+               return ARMV4_5_MODE_ABT;
+       case 5:
+               return ARMV4_5_MODE_UND;
+       case 6:
+               return ARMV4_5_MODE_SYS;
+       default:
+               LOG_ERROR("mode index out of bounds %d", number);
+               return ARMV4_5_MODE_ANY;
+       }
+}
 
 char* armv4_5_state_strings[] =
 {
@@ -157,14 +195,26 @@ uint8_t armv4_5_gdb_dummy_fp_value[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
 struct reg armv4_5_gdb_dummy_fp_reg =
 {
-       "GDB dummy floating-point register", armv4_5_gdb_dummy_fp_value, 0, 1, 96, NULL, 0, NULL, 0
+       .name = "GDB dummy floating-point register",
+       .value = armv4_5_gdb_dummy_fp_value,
+       .dirty = 0,
+       .valid = 1,
+       .size = 96,
+       .arch_info = NULL,
+       .arch_type = 0,
 };
 
 uint8_t armv4_5_gdb_dummy_fps_value[] = {0, 0, 0, 0};
 
 struct reg armv4_5_gdb_dummy_fps_reg =
 {
-       "GDB dummy floating-point status register", armv4_5_gdb_dummy_fps_value, 0, 1, 32, NULL, 0, NULL, 0
+       .name = "GDB dummy floating-point status register",
+       .value = armv4_5_gdb_dummy_fps_value,
+       .dirty = 0,
+       .valid = 1,
+       .size = 32,
+       .arch_info = NULL,
+       .arch_type = 0,
 };
 
 int armv4_5_get_core_reg(struct reg *reg)
@@ -278,8 +328,6 @@ struct reg_cache* armv4_5_build_reg_cache(struct target *target, struct arm *arm
                reg_list[i].value = calloc(1, 4);
                reg_list[i].dirty = 0;
                reg_list[i].valid = 0;
-               reg_list[i].bitfield_desc = NULL;
-               reg_list[i].num_bitfields = 0;
                reg_list[i].arch_type = armv4_5_core_reg_arch_type;
                reg_list[i].arch_info = &arch_info[i];
        }
@@ -315,10 +363,10 @@ COMMAND_HANDLER(handle_armv4_5_reg_command)
        struct target *target = get_current_target(cmd_ctx);
        struct armv4_5_common_s *armv4_5 = target_to_armv4_5(target);
 
-       if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
+       if (!is_arm(armv4_5))
        {
-               command_print(cmd_ctx, "current target isn't an ARMV4/5 target");
-               return ERROR_OK;
+               command_print(cmd_ctx, "current target isn't an ARM");
+               return ERROR_FAIL;
        }
 
        if (target->state != TARGET_HALTED)
@@ -330,6 +378,12 @@ COMMAND_HANDLER(handle_armv4_5_reg_command)
        if (armv4_5_mode_to_number(armv4_5->core_mode)==-1)
                return ERROR_FAIL;
 
+       if (!armv4_5->full_context) {
+               command_print(cmd_ctx, "error: target doesn't support %s",
+                               CMD_NAME);
+               return ERROR_FAIL;
+       }
+
        for (num = 0; num <= 15; num++)
        {
                output_len = 0;
@@ -364,10 +418,10 @@ COMMAND_HANDLER(handle_armv4_5_core_state_command)
        struct target *target = get_current_target(cmd_ctx);
        struct armv4_5_common_s *armv4_5 = target_to_armv4_5(target);
 
-       if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
+       if (!is_arm(armv4_5))
        {
-               command_print(cmd_ctx, "current target isn't an ARMV4/5 target");
-               return ERROR_OK;
+               command_print(cmd_ctx, "current target isn't an ARM");
+               return ERROR_FAIL;
        }
 
        if (argc > 0)
@@ -391,19 +445,14 @@ COMMAND_HANDLER(handle_armv4_5_disassemble_command)
 {
        int retval = ERROR_OK;
        struct target *target = get_current_target(cmd_ctx);
-       struct armv4_5_common_s *armv4_5 = target_to_armv4_5(target);
+       struct arm *arm = target ? target_to_arm(target) : NULL;
        uint32_t address;
        int count = 1;
-       int i;
-       struct arm_instruction cur_instruction;
-       uint32_t opcode;
-       uint16_t thumb_opcode;
        int thumb = 0;
 
-       if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
-       {
-               command_print(cmd_ctx, "current target isn't an ARMV4/5 target");
-               return ERROR_OK;
+       if (!is_arm(arm)) {
+               command_print(cmd_ctx, "current target isn't an ARM");
+               return ERROR_FAIL;
        }
 
        switch (argc) {
@@ -428,47 +477,48 @@ COMMAND_HANDLER(handle_armv4_5_disassemble_command)
        default:
 usage:
                command_print(cmd_ctx,
-                       "usage: armv4_5 disassemble <address> [<count> ['thumb']]");
-               return ERROR_OK;
-       }
-
-       for (i = 0; i < count; i++)
-       {
-               if (thumb)
-               {
-                       if ((retval = target_read_u16(target, address, &thumb_opcode)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-                       if ((retval = thumb_evaluate_opcode(thumb_opcode, address, &cur_instruction)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-               }
-               else {
-                       if ((retval = target_read_u32(target, address, &opcode)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-                       if ((retval = arm_evaluate_opcode(opcode, address, &cur_instruction)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
+                       "usage: arm disassemble <address> [<count> ['thumb']]");
+               count = 0;
+               retval = ERROR_FAIL;
+       }
+
+       while (count-- > 0) {
+               struct arm_instruction cur_instruction;
+
+               if (thumb) {
+                       /* Always use Thumb2 disassembly for best handling
+                        * of 32-bit BL/BLX, and to work with newer cores
+                        * (some ARMv6, all ARMv7) that use Thumb2.
+                        */
+                       retval = thumb2_opcode(target, address,
+                                       &cur_instruction);
+                       if (retval != ERROR_OK)
+                               break;
+               } else {
+                       uint32_t opcode;
+
+                       retval = target_read_u32(target, address, &opcode);
+                       if (retval != ERROR_OK)
+                               break;
+                       retval = arm_evaluate_opcode(opcode, address,
+                                       &cur_instruction) != ERROR_OK;
+                       if (retval != ERROR_OK)
+                               break;
                }
                command_print(cmd_ctx, "%s", cur_instruction.text);
-               address += (thumb) ? 2 : 4;
+               address += cur_instruction.instruction_size;
        }
 
-       return ERROR_OK;
+       return retval;
 }
 
 int armv4_5_register_commands(struct command_context *cmd_ctx)
 {
        struct command *armv4_5_cmd;
 
-       armv4_5_cmd = register_command(cmd_ctx, NULL, "armv4_5",
+       armv4_5_cmd = register_command(cmd_ctx, NULL, "arm",
                        NULL, COMMAND_ANY,
-                       "armv4/5 specific commands");
+                       "generic ARM commands");
 
        register_command(cmd_ctx, armv4_5_cmd, "reg",
                        handle_armv4_5_reg_command, COMMAND_EXEC,
@@ -478,7 +528,8 @@ int armv4_5_register_commands(struct command_context *cmd_ctx)
                        "display/change ARM core state <arm | thumb>");
        register_command(cmd_ctx, armv4_5_cmd, "disassemble",
                        handle_armv4_5_disassemble_command, COMMAND_EXEC,
-                       "disassemble instructions <address> [<count> ['thumb']]");
+                       "disassemble instructions "
+                               "<address> [<count> ['thumb']]");
 
        return ERROR_OK;
 }
@@ -713,6 +764,176 @@ int armv4_5_run_algorithm(struct target *target, int num_mem_params, struct mem_
        return armv4_5_run_algorithm_inner(target, num_mem_params, mem_params, num_reg_params, reg_params, entry_point, exit_point, timeout_ms, arch_info, armv4_5_run_algorithm_completion);
 }
 
+/**
+ * Runs ARM code in the target to calculate a CRC32 checksum.
+ *
+ * \todo On ARMv5+, rely on BKPT termination for reduced overhead.
+ */
+int arm_checksum_memory(struct target *target,
+               uint32_t address, uint32_t count, uint32_t *checksum)
+{
+       struct working_area *crc_algorithm;
+       struct armv4_5_algorithm armv4_5_info;
+       struct reg_param reg_params[2];
+       int retval;
+       uint32_t i;
+
+       static const uint32_t arm_crc_code[] = {
+               0xE1A02000,             /* mov          r2, r0 */
+               0xE3E00000,             /* mov          r0, #0xffffffff */
+               0xE1A03001,             /* mov          r3, r1 */
+               0xE3A04000,             /* mov          r4, #0 */
+               0xEA00000B,             /* b            ncomp */
+               /* nbyte: */
+               0xE7D21004,             /* ldrb r1, [r2, r4] */
+               0xE59F7030,             /* ldr          r7, CRC32XOR */
+               0xE0200C01,             /* eor          r0, r0, r1, asl 24 */
+               0xE3A05000,             /* mov          r5, #0 */
+               /* loop: */
+               0xE3500000,             /* cmp          r0, #0 */
+               0xE1A06080,             /* mov          r6, r0, asl #1 */
+               0xE2855001,             /* add          r5, r5, #1 */
+               0xE1A00006,             /* mov          r0, r6 */
+               0xB0260007,             /* eorlt        r0, r6, r7 */
+               0xE3550008,             /* cmp          r5, #8 */
+               0x1AFFFFF8,             /* bne          loop */
+               0xE2844001,             /* add          r4, r4, #1 */
+               /* ncomp: */
+               0xE1540003,             /* cmp          r4, r3 */
+               0x1AFFFFF1,             /* bne          nbyte */
+               /* end: */
+               0xEAFFFFFE,             /* b            end */
+               /* CRC32XOR: */
+               0x04C11DB7              /* .word 0x04C11DB7 */
+       };
+
+       retval = target_alloc_working_area(target,
+                       sizeof(arm_crc_code), &crc_algorithm);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* convert code into a buffer in target endianness */
+       for (i = 0; i < ARRAY_SIZE(arm_crc_code); i++) {
+               retval = target_write_u32(target,
+                               crc_algorithm->address + i * sizeof(uint32_t),
+                               arm_crc_code[i]);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
+       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
+       armv4_5_info.core_state = ARMV4_5_STATE_ARM;
+
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+
+       buf_set_u32(reg_params[0].value, 0, 32, address);
+       buf_set_u32(reg_params[1].value, 0, 32, count);
+
+       /* 20 second timeout/megabyte */
+       int timeout = 20000 * (1 + (count / (1024 * 1024)));
+
+       retval = target_run_algorithm(target, 0, NULL, 2, reg_params,
+                       crc_algorithm->address,
+                       crc_algorithm->address + sizeof(arm_crc_code) - 8,
+                       timeout, &armv4_5_info);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("error executing ARM crc algorithm");
+               destroy_reg_param(&reg_params[0]);
+               destroy_reg_param(&reg_params[1]);
+               target_free_working_area(target, crc_algorithm);
+               return retval;
+       }
+
+       *checksum = buf_get_u32(reg_params[0].value, 0, 32);
+
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+
+       target_free_working_area(target, crc_algorithm);
+
+       return ERROR_OK;
+}
+
+/**
+ * Runs ARM code in the target to check whether a memory block holds
+ * all ones.  NOR flash which has been erased, and thus may be written,
+ * holds all ones.
+ *
+ * \todo On ARMv5+, rely on BKPT termination for reduced overhead.
+ */
+int arm_blank_check_memory(struct target *target,
+               uint32_t address, uint32_t count, uint32_t *blank)
+{
+       struct working_area *check_algorithm;
+       struct reg_param reg_params[3];
+       struct armv4_5_algorithm armv4_5_info;
+       int retval;
+       uint32_t i;
+
+       static const uint32_t check_code[] = {
+               /* loop: */
+               0xe4d03001,             /* ldrb r3, [r0], #1 */
+               0xe0022003,             /* and r2, r2, r3    */
+               0xe2511001,             /* subs r1, r1, #1   */
+               0x1afffffb,             /* bne loop          */
+               /* end: */
+               0xeafffffe              /* b end             */
+       };
+
+       /* make sure we have a working area */
+       retval = target_alloc_working_area(target,
+                       sizeof(check_code), &check_algorithm);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* convert code into a buffer in target endianness */
+       for (i = 0; i < ARRAY_SIZE(check_code); i++) {
+               retval = target_write_u32(target,
+                               check_algorithm->address
+                                               + i * sizeof(uint32_t),
+                               check_code[i]);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
+       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
+       armv4_5_info.core_state = ARMV4_5_STATE_ARM;
+
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+       buf_set_u32(reg_params[0].value, 0, 32, address);
+
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+       buf_set_u32(reg_params[1].value, 0, 32, count);
+
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
+       buf_set_u32(reg_params[2].value, 0, 32, 0xff);
+
+       retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
+                       check_algorithm->address,
+                       check_algorithm->address + sizeof(check_code) - 4,
+                       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;
+       }
+
+       *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]);
+
+       target_free_working_area(target, check_algorithm);
+
+       return ERROR_OK;
+}
+
 int armv4_5_init_arch_info(struct target *target, struct arm *armv4_5)
 {
        target->arch_info = armv4_5;

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)