#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",
"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[] =
{
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)
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];
}
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)
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;
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)
{
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) {
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)
{
- command_t *armv4_5_cmd;
+ 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,
"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;
}
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(®_params[0], "r0", 32, PARAM_IN_OUT);
+ init_reg_param(®_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(®_params[0]);
+ destroy_reg_param(®_params[1]);
+ target_free_working_area(target, crc_algorithm);
+ return retval;
+ }
+
+ *checksum = buf_get_u32(reg_params[0].value, 0, 32);
+
+ destroy_reg_param(®_params[0]);
+ destroy_reg_param(®_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(®_params[0], "r0", 32, PARAM_OUT);
+ buf_set_u32(reg_params[0].value, 0, 32, address);
+
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
+ buf_set_u32(reg_params[1].value, 0, 32, count);
+
+ init_reg_param(®_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(®_params[0]);
+ destroy_reg_param(®_params[1]);
+ destroy_reg_param(®_params[2]);
+ target_free_working_area(target, check_algorithm);
+ return retval;
+ }
+
+ *blank = buf_get_u32(reg_params[2].value, 0, 32);
+
+ destroy_reg_param(®_params[0]);
+ destroy_reg_param(®_params[1]);
+ destroy_reg_param(®_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;