]> git.sur5r.net Git - openocd/blobdiff - src/target/armv4_5.c
ARM: only use one set of dummy FPA registers
[openocd] / src / target / armv4_5.c
index 9fa1ac09a5a1982436a55e828d5c0653d5844e0a..aba44319694955caf41fed9b7e7e649066ee99b3 100644 (file)
@@ -28,6 +28,7 @@
 #endif
 
 #include "armv4_5.h"
+#include "arm_jtag.h"
 #include "breakpoints.h"
 #include "arm_disassembler.h"
 #include "binarybuffer.h"
@@ -52,21 +53,69 @@ 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[] =
 {
        "ARM", "Thumb", "Jazelle"
 };
 
-int armv4_5_core_reg_arch_type = -1;
-
 struct armv4_5_core_reg armv4_5_core_reg_list_arch_info[] =
 {
        {0, ARMV4_5_MODE_ANY, NULL, NULL},
@@ -140,32 +189,44 @@ int armv4_5_core_reg_map[7][17] =
        }
 };
 
-uint8_t armv4_5_gdb_dummy_fp_value[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const uint8_t arm_gdb_dummy_fp_value[12];
 
-struct reg armv4_5_gdb_dummy_fp_reg =
+/**
+ * Dummy FPA registers are required to support GDB on ARM.
+ * Register packets require eight obsolete FPA register values.
+ * Modern ARM cores use Vector Floating Point (VFP), if they
+ * have any floating point support.  VFP is not FPA-compatible.
+ */
+struct reg arm_gdb_dummy_fp_reg =
 {
-       .name = "GDB dummy floating-point register",
-       .value = armv4_5_gdb_dummy_fp_value,
-       .dirty = 0,
+       .name = "GDB dummy FPA register",
+       .value = (uint8_t *) arm_gdb_dummy_fp_value,
        .valid = 1,
        .size = 96,
-       .arch_info = NULL,
-       .arch_type = 0,
 };
 
-uint8_t armv4_5_gdb_dummy_fps_value[] = {0, 0, 0, 0};
+static const uint8_t arm_gdb_dummy_fps_value[4];
 
-struct reg armv4_5_gdb_dummy_fps_reg =
+/**
+ * Dummy FPA status registers are required to support GDB on ARM.
+ * Register packets require an obsolete FPA status register.
+ */
+struct reg arm_gdb_dummy_fps_reg =
 {
-       .name = "GDB dummy floating-point status register",
-       .value = armv4_5_gdb_dummy_fps_value,
-       .dirty = 0,
+       .name = "GDB dummy FPA status register",
+       .value = (uint8_t *) arm_gdb_dummy_fps_value,
        .valid = 1,
        .size = 32,
-       .arch_info = NULL,
-       .arch_type = 0,
 };
 
+static void arm_gdb_dummy_init(void) __attribute__ ((constructor));
+
+static void arm_gdb_dummy_init(void)
+{
+       register_init_dummy(&arm_gdb_dummy_fp_reg);
+       register_init_dummy(&arm_gdb_dummy_fps_reg);
+}
+
 int armv4_5_get_core_reg(struct reg *reg)
 {
        int retval;
@@ -234,6 +295,11 @@ int armv4_5_set_core_reg(struct reg *reg, uint8_t *buf)
        return ERROR_OK;
 }
 
+static const struct reg_arch_type arm_reg_type = {
+       .get = armv4_5_get_core_reg,
+       .set = armv4_5_set_core_reg,
+};
+
 int armv4_5_invalidate_core_regs(struct target *target)
 {
        struct armv4_5_common_s *armv4_5 = target_to_armv4_5(target);
@@ -261,12 +327,6 @@ struct reg_cache* armv4_5_build_reg_cache(struct target *target, struct arm *arm
        cache->reg_list = reg_list;
        cache->num_regs = num_regs;
 
-       if (armv4_5_core_reg_arch_type == -1)
-               armv4_5_core_reg_arch_type = register_reg_arch_type(armv4_5_get_core_reg, armv4_5_set_core_reg);
-
-       register_init_dummy(&armv4_5_gdb_dummy_fp_reg);
-       register_init_dummy(&armv4_5_gdb_dummy_fps_reg);
-
        for (i = 0; i < 37; i++)
        {
                arch_info[i] = armv4_5_core_reg_list_arch_info[i];
@@ -277,7 +337,7 @@ 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].arch_type = armv4_5_core_reg_arch_type;
+               reg_list[i].type = &arm_reg_type;
                reg_list[i].arch_info = &arch_info[i];
        }
 
@@ -291,7 +351,7 @@ int armv4_5_arch_state(struct target *target)
        if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
        {
                LOG_ERROR("BUG: called for a non-ARMv4/5 target");
-               exit(-1);
+               return ERROR_FAIL;
        }
 
        LOG_USER("target halted in %s state due to %s, current mode: %s\ncpsr: 0x%8.8" PRIx32 " pc: 0x%8.8" PRIx32 "",
@@ -309,24 +369,30 @@ COMMAND_HANDLER(handle_armv4_5_reg_command)
        char output[128];
        int output_len;
        int mode, num;
-       struct target *target = get_current_target(cmd_ctx);
+       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)
        {
-               command_print(cmd_ctx, "error: target must be halted for register accesses");
+               command_print(CMD_CTX, "error: target must be halted for register accesses");
                return ERROR_OK;
        }
 
        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;
@@ -342,9 +408,9 @@ COMMAND_HANDLER(handle_armv4_5_reg_command)
                                               ARMV4_5_CORE_REG_MODENUM(armv4_5->core_cache, mode, num).name,
                                               buf_get_u32(ARMV4_5_CORE_REG_MODENUM(armv4_5->core_cache, mode, num).value, 0, 32));
                }
-               command_print(cmd_ctx, "%s", output);
+               command_print(CMD_CTX, "%s", output);
        }
-       command_print(cmd_ctx,
+       command_print(CMD_CTX,
                      "    cpsr: %8.8" PRIx32 " spsr_fiq: %8.8" PRIx32 " spsr_irq: %8.8" PRIx32 " spsr_svc: %8.8" PRIx32 " spsr_abt: %8.8" PRIx32 " spsr_und: %8.8" PRIx32 "",
                          buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32),
                          buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_SPSR_FIQ].value, 0, 32),
@@ -358,28 +424,28 @@ COMMAND_HANDLER(handle_armv4_5_reg_command)
 
 COMMAND_HANDLER(handle_armv4_5_core_state_command)
 {
-       struct target *target = get_current_target(cmd_ctx);
+       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)
+       if (CMD_ARGC > 0)
        {
-               if (strcmp(args[0], "arm") == 0)
+               if (strcmp(CMD_ARGV[0], "arm") == 0)
                {
                        armv4_5->core_state = ARMV4_5_STATE_ARM;
                }
-               if (strcmp(args[0], "thumb") == 0)
+               if (strcmp(CMD_ARGV[0], "thumb") == 0)
                {
                        armv4_5->core_state = ARMV4_5_STATE_THUMB;
                }
        }
 
-       command_print(cmd_ctx, "core state: %s", armv4_5_state_strings[armv4_5->core_state]);
+       command_print(CMD_CTX, "core state: %s", armv4_5_state_strings[armv4_5->core_state]);
 
        return ERROR_OK;
 }
@@ -387,36 +453,31 @@ COMMAND_HANDLER(handle_armv4_5_core_state_command)
 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 target *target = get_current_target(CMD_CTX);
+       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) {
+       switch (CMD_ARGC) {
        case 3:
-               if (strcmp(args[2], "thumb") != 0)
+               if (strcmp(CMD_ARGV[2], "thumb") != 0)
                        goto usage;
                thumb = 1;
                /* FALL THROUGH */
        case 2:
-               COMMAND_PARSE_NUMBER(int, args[1], count);
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], count);
                /* FALL THROUGH */
        case 1:
-               COMMAND_PARSE_NUMBER(u32, args[0], address);
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
                if (address & 0x01) {
                        if (!thumb) {
-                               command_print(cmd_ctx, "Disassemble as Thumb");
+                               command_print(CMD_CTX, "Disassemble as Thumb");
                                thumb = 1;
                        }
                        address &= ~1;
@@ -424,48 +485,49 @@ COMMAND_HANDLER(handle_armv4_5_disassemble_command)
                break;
        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;
-                       }
+               command_print(CMD_CTX,
+                       "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;
                }
-               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;
-                       }
-               }
-               command_print(cmd_ctx, "%s", cur_instruction.text);
-               address += (thumb) ? 2 : 4;
+               command_print(CMD_CTX, "%s", cur_instruction.text);
+               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,
@@ -475,7 +537,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;
 }
@@ -498,10 +561,10 @@ int armv4_5_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int
 
        for (i = 16; i < 24; i++)
        {
-               (*reg_list)[i] = &armv4_5_gdb_dummy_fp_reg;
+               (*reg_list)[i] = &arm_gdb_dummy_fp_reg;
        }
 
-       (*reg_list)[24] = &armv4_5_gdb_dummy_fps_reg;
+       (*reg_list)[24] = &arm_gdb_dummy_fps_reg;
        (*reg_list)[25] = &armv4_5->core_cache->reg_list[ARMV4_5_CPSR];
 
        return ERROR_OK;
@@ -597,13 +660,13 @@ int armv4_5_run_algorithm_inner(struct target *target, int num_mem_params, struc
                if (!reg)
                {
                        LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
-                       exit(-1);
+                       return ERROR_INVALID_ARGUMENTS;
                }
 
                if (reg->size != reg_params[i].size)
                {
                        LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name);
-                       exit(-1);
+                       return ERROR_INVALID_ARGUMENTS;
                }
 
                if ((retval = armv4_5_set_core_reg(reg, reg_params[i].value)) != ERROR_OK)
@@ -620,7 +683,7 @@ int armv4_5_run_algorithm_inner(struct target *target, int num_mem_params, struc
        else
        {
                LOG_ERROR("BUG: can't execute algorithms when not in ARM or Thumb state");
-               exit(-1);
+               return ERROR_INVALID_ARGUMENTS;
        }
 
        if (armv4_5_algorithm_info->core_mode != ARMV4_5_MODE_ANY)
@@ -670,13 +733,15 @@ int armv4_5_run_algorithm_inner(struct target *target, int num_mem_params, struc
                        if (!reg)
                        {
                                LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
-                               exit(-1);
+                               retval = ERROR_INVALID_ARGUMENTS;
+                               continue;
                        }
 
                        if (reg->size != reg_params[i].size)
                        {
                                LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name);
-                               exit(-1);
+                               retval = ERROR_INVALID_ARGUMENTS;
+                               continue;
                        }
 
                        buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32));