aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2021-04-08 12:53:30 -0700
committerGitHub <noreply@github.com>2021-04-08 12:53:30 -0700
commit737f013ada404fdd620c2c0d4f1cb318a0ff64b2 (patch)
tree70cb46a7050fb037607b1c0f460e089581f5ca95
parent28724d996a9b68e490f6bd90b5537c71631c753d (diff)
downloadriscv-openocd-737f013ada404fdd620c2c0d4f1cb318a0ff64b2.zip
riscv-openocd-737f013ada404fdd620c2c0d4f1cb318a0ff64b2.tar.gz
riscv-openocd-737f013ada404fdd620c2c0d4f1cb318a0ff64b2.tar.bz2
Support RV32/RV64 mainline/metal stackings (#586)
* Support mainline FreeRTOS instead of metal FreeRTOS I'll have to add an option or something before this can be merged. The stack pointer value for suspended threads is computed, and I didn't check that it's right. Can't be written. Does not support accessing gp/tp in suspended threads. Change-Id: Ibe7f5167b970d5990a296e968df2b4480135d673 Signed-off-by: Tim Newsome <tim@sifive.com> * Add riscv_freertos_stacking command. This lets the user describe how registers are stored on the stack. Change-Id: I052188fa9c6cb4f8670fa4b01a8878272ed6fc4d * Redo how we handle offsets in FreeRTOS. Instead of hard-coding them for each "target," hard code the data types in FreeRTOS list structures, and compute the offsets based on size of pointers and ubase_t types. Doesn't work right now. Change-Id: I444cd1ef47121190e2222f19a67edf3c6155a96a * Correctly get thread list. Works on RV32 and RV64. Change-Id: I27768aef698475bef425d6a7e27ea609c9b9a1b6 * Fix SP calculation and RV64 register stacking. Smoketest now passes on spike with both RV32 and RV64. Change-Id: I94b43e041abe5370a833bd3afb4a2a8591538d7a Signed-off-by: Tim Newsome <tim@sifive.com> * Style fixes. Change-Id: I269b5aac8c233022c41ebc8ac8c5aeb437882719 Signed-off-by: Tim Newsome <tim@sifive.com> * Style fix. Change-Id: I18fbff7dcaad9bd35f0942598c05c2a45bdb9f3b Signed-off-by: Tim Newsome <tim@sifive.com>
-rw-r--r--src/rtos/FreeRTOS.c397
-rw-r--r--src/rtos/rtos.c17
-rw-r--r--src/rtos/rtos.h10
-rw-r--r--src/rtos/rtos_riot_stackings.c4
-rw-r--r--src/rtos/rtos_standard_stackings.c183
-rw-r--r--src/rtos/rtos_standard_stackings.h11
6 files changed, 481 insertions, 141 deletions
diff --git a/src/rtos/FreeRTOS.c b/src/rtos/FreeRTOS.c
index ee7faa0..6e829b5 100644
--- a/src/rtos/FreeRTOS.c
+++ b/src/rtos/FreeRTOS.c
@@ -33,26 +33,13 @@
#include "target/cortex_m.h"
#define FREERTOS_MAX_PRIORITIES 63
-
-#define FreeRTOS_STRUCT(int_type, ptr_type, list_prev_offset)
-
-/* FIXME: none of the _width parameters are actually observed properly!
- * you WILL need to edit more if you actually attempt to target a 8/16/64
- * bit target!
- */
+#define FREERTOS_THREAD_NAME_STR_SIZE 200
struct FreeRTOS_params {
const char *target_name;
- const unsigned char thread_count_width;
- const unsigned char pointer_width;
- const unsigned char list_next_offset;
- const unsigned char list_width;
- const unsigned char list_elem_next_offset;
- const unsigned char list_elem_content_offset;
- const unsigned char thread_stack_offset;
- const unsigned char thread_name_offset;
int (*stacking)(struct rtos *rtos, const struct rtos_register_stacking **stacking,
target_addr_t stack_ptr);
+ const struct command_registration *commands;
};
struct FreeRTOS_thread_entry {
@@ -68,6 +55,23 @@ struct FreeRTOS {
gl_map_t entry_by_threadid;
/* Map from tcb to FreeRTOS_thread_entry. */
gl_map_t entry_by_tcb;
+ /* sizeof(UBaseType_t) */
+ unsigned ubasetype_size;
+ /* sizeof(void *) */
+ unsigned pointer_size;
+ unsigned list_width;
+ unsigned list_item_width;
+ unsigned list_elem_next_offset;
+ unsigned list_elem_next_size;
+ unsigned list_elem_content_offset;
+ unsigned list_elem_content_size;
+ unsigned list_uxNumberOfItems_offset;
+ unsigned list_uxNumberOfItems_size;
+ unsigned list_next_offset;
+ unsigned list_next_size;
+ unsigned thread_stack_offset;
+ unsigned thread_stack_size;
+ unsigned thread_name_offset;
};
static int cortex_m_stacking(struct rtos *rtos, const struct rtos_register_stacking **stacking,
@@ -123,61 +127,81 @@ static int nds32_stacking(struct rtos *rtos, const struct rtos_register_stacking
return ERROR_OK;
}
+static enum {
+ STACKING_MAINLINE,
+ STACKING_METAL
+} riscv_freertos_stacking;
+COMMAND_HANDLER(handle_riscv_freertos_stacking)
+{
+ if (CMD_ARGC != 1) {
+ LOG_ERROR("Command takes exactly 1 parameter");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ if (!strcmp(CMD_ARGV[0], "mainline")) {
+ riscv_freertos_stacking = STACKING_MAINLINE;
+ } else if (!strcmp(CMD_ARGV[0], "metal")) {
+ riscv_freertos_stacking = STACKING_METAL;
+ } else {
+ LOG_ERROR("Only two arguments are supported: mainline and metal");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ return ERROR_OK;
+}
+
+static const struct command_registration riscv_commands[] = {
+ {
+ .name = "riscv_freertos_stacking",
+ .handler = handle_riscv_freertos_stacking,
+ .mode = COMMAND_ANY,
+ .usage = "mainline|metal",
+ .help = "Select which FreeRTOS branch is being used. OpenOCD needs to "
+ "know because different branches save thread registers on the stack "
+ "in different orders. It is likely that this order on both branches will "
+ "change in the future, so make sure to seek out the very latest OpenOCD if "
+ "debugging is not working right."
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
static int riscv_stacking(struct rtos *rtos, const struct rtos_register_stacking **stacking,
target_addr_t stack_ptr)
{
- *stacking = &rtos_standard_RV32_stacking;
+ struct FreeRTOS *freertos = (struct FreeRTOS *) rtos->rtos_specific_params;
+ LOG_DEBUG("riscv_freertos_stacking=%d", riscv_freertos_stacking);
+ switch (riscv_freertos_stacking) {
+ case STACKING_MAINLINE:
+ if (freertos->pointer_size == 4)
+ *stacking = &rtos_standard_RV32_stacking;
+ else if (freertos->pointer_size == 8)
+ *stacking = &rtos_standard_RV64_stacking;
+ break;
+ case STACKING_METAL:
+ if (freertos->pointer_size == 4)
+ *stacking = &rtos_metal_RV32_stacking;
+ else if (freertos->pointer_size == 8)
+ *stacking = &rtos_metal_RV64_stacking;
+ break;
+ }
return ERROR_OK;
}
static const struct FreeRTOS_params FreeRTOS_params_list[] = {
{
- "cortex_m", /* target_name */
- 4, /* thread_count_width; */
- 4, /* pointer_width; */
- 16, /* list_next_offset; */
- 20, /* list_width; */
- 8, /* list_elem_next_offset; */
- 12, /* list_elem_content_offset */
- 0, /* thread_stack_offset; */
- 52, /* thread_name_offset; */
- cortex_m_stacking,
+ .target_name = "cortex_m",
+ .stacking = cortex_m_stacking
},
{
- "hla_target", /* target_name */
- 4, /* thread_count_width; */
- 4, /* pointer_width; */
- 16, /* list_next_offset; */
- 20, /* list_width; */
- 8, /* list_elem_next_offset; */
- 12, /* list_elem_content_offset */
- 0, /* thread_stack_offset; */
- 52, /* thread_name_offset; */
- cortex_m_stacking,
+ .target_name = "hla_target",
+ .stacking = cortex_m_stacking
},
{
- "nds32_v3", /* target_name */
- 4, /* thread_count_width; */
- 4, /* pointer_width; */
- 16, /* list_next_offset; */
- 20, /* list_width; */
- 8, /* list_elem_next_offset; */
- 12, /* list_elem_content_offset */
- 0, /* thread_stack_offset; */
- 52, /* thread_name_offset; */
- nds32_stacking,
+ .target_name = "nds32_v3",
+ .stacking = nds32_stacking,
},
{
- "riscv", /* target_name */
- 4, /* thread_count_width; */
- 4, /* pointer_width; */
- 16, /* list_next_offset; */
- 20, /* list_width; */
- 8, /* list_elem_next_offset; */
- 12, /* list_elem_content_offset */
- 0, /* thread_stack_offset; */
- 52, /* thread_name_offset; */
- riscv_stacking,
+ .target_name = "riscv",
+ .stacking = riscv_stacking,
+ .commands = riscv_commands,
},
};
@@ -244,6 +268,83 @@ static const struct symbols FreeRTOS_symbol_list[] = {
/* may be problems reading if sizes are not 32 bit long integers. */
/* test mallocs for failure */
+static int FreeRTOS_read_struct_value(
+ struct target *target, target_addr_t base_address, unsigned offset,
+ unsigned size_bytes, uint64_t *value)
+{
+ uint8_t buf[size_bytes];
+ int retval = target_read_buffer(target, base_address + offset, size_bytes, buf);
+ *value = buf_get_u64(buf, 0, size_bytes * 8);
+ return retval;
+}
+
+typedef struct {
+ enum {
+ TYPE_POINTER,
+ TYPE_UBASE,
+ TYPE_TICKTYPE,
+ TYPE_LIST_ITEM,
+ TYPE_CHAR_ARRAY
+ } type;
+ unsigned offset;
+ unsigned size;
+} type_offset_size_t;
+
+static unsigned populate_offset_size(struct FreeRTOS *freertos,
+ type_offset_size_t *info, unsigned count)
+{
+ unsigned offset = 0;
+ unsigned largest = 0;
+ for (unsigned i = 0; i < count; i++) {
+ unsigned align = 0;
+ switch (info[i].type) {
+ case TYPE_UBASE:
+ info[i].size = freertos->ubasetype_size;
+ align = freertos->ubasetype_size;
+ break;
+ case TYPE_POINTER:
+ info[i].size = freertos->pointer_size;
+ align = freertos->pointer_size;
+ break;
+ case TYPE_TICKTYPE:
+ /* Could be either 16 or 32 bits, depending on configUSE_16_BIT_TICKS. */
+ info[i].size = 4;
+ align = 4;
+ break;
+ case TYPE_LIST_ITEM:
+ info[i].size = freertos->list_item_width;
+ align = MAX(freertos->ubasetype_size, freertos->pointer_size);
+ break;
+ case TYPE_CHAR_ARRAY:
+ /* size is set by the caller. */
+ align = 1;
+ break;
+ }
+
+ assert(info[i].size > 0);
+ assert(align > 0);
+
+ largest = MAX(largest, align);
+
+ if (offset & (align - 1)) {
+ offset = offset & ~(align - 1);
+ offset += align;
+ }
+
+ info[i].offset = offset;
+ offset += info[i].size;
+ }
+
+ /* Now align offset to the largest type used, and return that as the width
+ * of the structure. */
+
+ if (offset & (largest - 1)) {
+ offset = offset & ~(largest - 1);
+ offset += largest;
+ }
+ return offset;
+}
+
static int FreeRTOS_update_threads(struct rtos *rtos)
{
int retval;
@@ -253,7 +354,6 @@ static int FreeRTOS_update_threads(struct rtos *rtos)
return ERROR_FAIL;
struct FreeRTOS *freertos = (struct FreeRTOS *) rtos->rtos_specific_params;
- const struct FreeRTOS_params *param = freertos->param;
if (rtos->symbols == NULL) {
LOG_ERROR("No symbols for FreeRTOS");
@@ -265,11 +365,13 @@ static int FreeRTOS_update_threads(struct rtos *rtos)
return ERROR_FAIL;
}
- uint32_t thread_list_size = 0;
- retval = target_read_u32(rtos->target,
- rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address,
- &thread_list_size);
- LOG_DEBUG("FreeRTOS: Read uxCurrentNumberOfTasks at 0x%" PRIx64 ", value %" PRIu32,
+ uint64_t thread_list_size;
+ retval = FreeRTOS_read_struct_value(rtos->target,
+ rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address,
+ 0,
+ freertos->ubasetype_size,
+ &thread_list_size);
+ LOG_DEBUG("FreeRTOS: Read uxCurrentNumberOfTasks at 0x%" PRIx64 ", value %" PRIu64,
rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address,
thread_list_size);
@@ -282,15 +384,16 @@ static int FreeRTOS_update_threads(struct rtos *rtos)
rtos_free_threadlist(rtos);
/* read the current thread */
- uint32_t pointer_casts_are_bad;
- retval = target_read_u32(rtos->target,
- rtos->symbols[FreeRTOS_VAL_pxCurrentTCB].address,
- &pointer_casts_are_bad);
+ target_addr_t pxCurrentTCB;
+ retval = FreeRTOS_read_struct_value(rtos->target,
+ rtos->symbols[FreeRTOS_VAL_pxCurrentTCB].address,
+ 0,
+ freertos->pointer_size,
+ &pxCurrentTCB);
if (retval != ERROR_OK) {
LOG_ERROR("Error reading current thread in FreeRTOS thread list");
return retval;
}
- target_addr_t pxCurrentTCB = pointer_casts_are_bad;
LOG_DEBUG("FreeRTOS: Read pxCurrentTCB at 0x%" PRIx64 ", value 0x%" PRIx64,
rtos->symbols[FreeRTOS_VAL_pxCurrentTCB].address,
pxCurrentTCB);
@@ -305,7 +408,7 @@ static int FreeRTOS_update_threads(struct rtos *rtos)
rtos->thread_details = malloc(
sizeof(struct thread_detail) * thread_list_size);
if (!rtos->thread_details) {
- LOG_ERROR("Error allocating memory for %d threads", thread_list_size);
+ LOG_ERROR("Error allocating memory for %" PRIu64 " threads", thread_list_size);
return ERROR_FAIL;
}
rtos->thread_details->threadid = 1;
@@ -323,13 +426,13 @@ static int FreeRTOS_update_threads(struct rtos *rtos)
rtos->thread_details = malloc(
sizeof(struct thread_detail) * thread_list_size);
if (!rtos->thread_details) {
- LOG_ERROR("Error allocating memory for %d threads", thread_list_size);
+ LOG_ERROR("Error allocating memory for %" PRId64 " threads", thread_list_size);
return ERROR_FAIL;
}
}
/* Find out how many lists are needed to be read from pxReadyTasksLists, */
- uint32_t top_used_priority = 0;
+ uint64_t top_used_priority = 0;
if (rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address == 0) {
LOG_WARNING("FreeRTOS: uxTopUsedPriority is not defined, consult the OpenOCD manual for a work-around");
/* This is a hack specific to the binary I'm debugging.
@@ -337,17 +440,19 @@ static int FreeRTOS_update_threads(struct rtos *rtos)
* into our FreeRTOS source. */
top_used_priority = 6;
} else {
- retval = target_read_u32(rtos->target,
- rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address,
- &top_used_priority);
+ retval = FreeRTOS_read_struct_value(rtos->target,
+ rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address,
+ 0,
+ freertos->ubasetype_size,
+ &top_used_priority);
if (retval != ERROR_OK)
return retval;
- LOG_DEBUG("FreeRTOS: Read uxTopUsedPriority at 0x%" PRIx64 ", value %" PRIu32,
+ LOG_DEBUG("FreeRTOS: Read uxTopUsedPriority at 0x%" PRIx64 ", value %" PRIu64,
rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address,
top_used_priority);
}
if (top_used_priority > FREERTOS_MAX_PRIORITIES) {
- LOG_ERROR("FreeRTOS top used priority is unreasonably big, not proceeding: %" PRIu32,
+ LOG_ERROR("FreeRTOS top used priority is unreasonably big, not proceeding: %" PRIu64,
top_used_priority);
return ERROR_FAIL;
}
@@ -369,7 +474,7 @@ static int FreeRTOS_update_threads(struct rtos *rtos)
unsigned int num_lists;
for (num_lists = 0; num_lists < config_max_priorities; num_lists++)
list_of_lists[num_lists] = rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address +
- num_lists * param->list_width;
+ num_lists * freertos->list_width;
list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xDelayedTaskList1].address;
list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xDelayedTaskList2].address;
@@ -383,50 +488,56 @@ static int FreeRTOS_update_threads(struct rtos *rtos)
continue;
/* Read the number of threads in this list */
- uint32_t list_thread_count = 0;
- retval = target_read_u32(rtos->target,
- list_of_lists[i],
- &list_thread_count);
+ uint64_t list_thread_count = 0;
+ retval = FreeRTOS_read_struct_value(rtos->target,
+ list_of_lists[i],
+ freertos->list_uxNumberOfItems_offset,
+ freertos->list_uxNumberOfItems_size,
+ &list_thread_count);
if (retval != ERROR_OK) {
LOG_ERROR("Error reading number of threads in FreeRTOS thread list");
free(list_of_lists);
return retval;
}
- LOG_DEBUG("FreeRTOS: Read thread count for list %u at 0x%" PRIx64 ", value %" PRIu32,
+ LOG_DEBUG("FreeRTOS: Read thread count for list %u at 0x%" PRIx64 ", value %" PRIu64,
i, list_of_lists[i], list_thread_count);
if (list_thread_count == 0)
continue;
/* Read the location of first list item */
- uint32_t prev_list_elem_ptr = -1;
- uint32_t list_elem_ptr = 0;
- retval = target_read_u32(rtos->target,
- list_of_lists[i] + param->list_next_offset,
- &list_elem_ptr);
+ target_addr_t prev_list_elem_ptr = -1;
+ target_addr_t list_elem_ptr = 0;
+ retval = FreeRTOS_read_struct_value(rtos->target,
+ list_of_lists[i],
+ freertos->list_next_offset,
+ freertos->list_next_size,
+ &list_elem_ptr);
if (retval != ERROR_OK) {
LOG_ERROR("Error reading first thread item location in FreeRTOS thread list");
free(list_of_lists);
return retval;
}
- LOG_DEBUG("FreeRTOS: Read first item for list %u at 0x%" PRIx64 ", value 0x%" PRIx32,
- i, list_of_lists[i] + param->list_next_offset, list_elem_ptr);
+ LOG_DEBUG("FreeRTOS: Read first item for list %u at 0x%" PRIx64 ", value 0x%" PRIx64,
+ i, list_of_lists[i] + freertos->list_next_offset, list_elem_ptr);
while ((list_thread_count > 0) && (list_elem_ptr != 0) &&
(list_elem_ptr != prev_list_elem_ptr) &&
(tasks_found < thread_list_size)) {
/* Get the location of the thread structure. */
rtos->thread_details[tasks_found].threadid = 0;
- retval = target_read_u32(rtos->target,
- list_elem_ptr + param->list_elem_content_offset,
- &pointer_casts_are_bad);
+ target_addr_t tcb;
+ retval = FreeRTOS_read_struct_value(rtos->target,
+ list_elem_ptr,
+ freertos->list_elem_content_offset,
+ freertos->list_elem_content_size,
+ &tcb);
if (retval != ERROR_OK) {
LOG_ERROR("Error reading thread list item object in FreeRTOS thread list");
free(list_of_lists);
return retval;
}
- target_addr_t tcb = pointer_casts_are_bad;
const struct FreeRTOS_thread_entry *value =
gl_map_get(freertos->entry_by_tcb, &tcb);
@@ -450,18 +561,17 @@ static int FreeRTOS_update_threads(struct rtos *rtos)
rtos->thread_details[tasks_found].threadid = value->threadid;
LOG_DEBUG("FreeRTOS: Thread %" PRId64 " has TCB 0x%" TARGET_PRIxADDR
- "; read from 0x%" PRIx32,
+ "; read from 0x%" PRIx64,
value->threadid, value->tcb,
- list_elem_ptr + param->list_elem_content_offset);
+ list_elem_ptr + freertos->list_elem_content_offset);
/* get thread name */
- #define FREERTOS_THREAD_NAME_STR_SIZE (200)
char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE];
/* Read the thread name */
retval = target_read_buffer(rtos->target,
- value->tcb + param->thread_name_offset,
+ value->tcb + freertos->thread_name_offset,
FREERTOS_THREAD_NAME_STR_SIZE,
(uint8_t *)&tmp_str);
if (retval != ERROR_OK) {
@@ -471,7 +581,7 @@ static int FreeRTOS_update_threads(struct rtos *rtos)
}
tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00';
LOG_DEBUG("FreeRTOS: Read Thread Name at 0x%" PRIx64 ", value '%s'",
- value->tcb + param->thread_name_offset,
+ value->tcb + freertos->thread_name_offset,
tmp_str);
if (tmp_str[0] == '\x00')
@@ -497,17 +607,20 @@ static int FreeRTOS_update_threads(struct rtos *rtos)
prev_list_elem_ptr = list_elem_ptr;
list_elem_ptr = 0;
- retval = target_read_u32(rtos->target,
- prev_list_elem_ptr + param->list_elem_next_offset,
- &list_elem_ptr);
+ retval = FreeRTOS_read_struct_value(rtos->target,
+ prev_list_elem_ptr,
+ freertos->list_elem_next_offset,
+ freertos->list_elem_next_size,
+ &list_elem_ptr);
if (retval != ERROR_OK) {
LOG_ERROR("Error reading next thread item location in FreeRTOS thread list");
free(list_of_lists);
return retval;
}
- LOG_DEBUG("FreeRTOS: Read next thread location at 0x%" PRIx32 ", value 0x%" PRIx32,
- prev_list_elem_ptr + param->list_elem_next_offset,
- list_elem_ptr);
+ LOG_DEBUG("FreeRTOS: Read next thread location at " TARGET_ADDR_FMT
+ ", value " TARGET_ADDR_FMT,
+ prev_list_elem_ptr + freertos->list_elem_next_offset,
+ list_elem_ptr);
}
}
@@ -536,17 +649,17 @@ static int FreeRTOS_get_stacking_info(struct rtos *rtos, threadid_t thread_id,
}
/* Read the stack pointer */
- uint32_t pointer_casts_are_bad;
- int retval = target_read_u32(rtos->target,
- entry->tcb + param->thread_stack_offset,
- &pointer_casts_are_bad);
+ int retval = FreeRTOS_read_struct_value(rtos->target,
+ entry->tcb,
+ freertos->thread_stack_offset,
+ freertos->thread_stack_size,
+ stack_ptr);
if (retval != ERROR_OK) {
LOG_ERROR("Error reading stack frame from FreeRTOS thread %" PRIx64, thread_id);
return retval;
}
- *stack_ptr = pointer_casts_are_bad;
LOG_DEBUG("[%" PRId64 "] FreeRTOS: Read stack pointer at 0x%" PRIx64 ", value 0x%" PRIx64,
- thread_id, entry->tcb + param->thread_stack_offset, *stack_ptr);
+ thread_id, entry->tcb + freertos->thread_stack_offset, *stack_ptr);
if (param->stacking(rtos, stacking_info, *stack_ptr) != ERROR_OK) {
LOG_ERROR("No stacking info found for %s!", param->target_name);
@@ -728,5 +841,71 @@ static int FreeRTOS_create(struct target *target)
}
freertos->param = &FreeRTOS_params_list[i];
+ if (freertos->param->commands) {
+ if (register_commands(target->rtos->cmd_ctx, NULL,
+ freertos->param->commands) != ERROR_OK)
+ return ERROR_FAIL;
+ }
+
+ freertos->pointer_size = DIV_ROUND_UP(target_address_bits(target), 8);
+ freertos->ubasetype_size = DIV_ROUND_UP(target_data_bits(target), 8);
+
+ /*
+ * FreeRTOS can be compiled with configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES
+ * in which case extra data is inserted and OpenOCD won't work right.
+ */
+
+ /* struct xLIST */
+ type_offset_size_t struct_list_info[] = {
+ {TYPE_UBASE, 0, 0}, /* uxNumberOfItems */
+ {TYPE_POINTER, 0, 0}, /* ListItem_t *pxIndex */
+ {TYPE_TICKTYPE, 0, 0}, /* xItemValue */
+ {TYPE_POINTER, 0, 0}, /* ListItem_t *pxNext */
+ {TYPE_POINTER, 0, 0}, /* ListItem_t *pxPrevious */
+ };
+
+ /* struct xLIST_ITEM */
+ type_offset_size_t struct_list_item_info[] = {
+ {TYPE_TICKTYPE, 0, 0}, /* xItemValue */
+ {TYPE_POINTER, 0, 0}, /* ListItem_t *pxNext */
+ {TYPE_POINTER, 0, 0}, /* ListItem_t *pxPrevious */
+ {TYPE_POINTER, 0, 0}, /* void *pvOwner */
+ {TYPE_POINTER, 0, 0}, /* List_t *pvContainer */
+ };
+
+ /* struct tskTaskControlBlock */
+ type_offset_size_t task_control_block_info[] = {
+ {TYPE_POINTER, 0, 0}, /* StackType_t *pxTopOfStack */
+ {TYPE_LIST_ITEM, 0, 0}, /* ListItem_t xStateListItem */
+ {TYPE_LIST_ITEM, 0, 0}, /* ListItem_t xEventListItem */
+ {TYPE_UBASE, 0, 0}, /* uxPriority */
+ {TYPE_POINTER, 0, 0}, /* StackType_t *pxStack */
+ /* configMAX_TASK_NAME_LEN varies a lot between targets, but luckily the
+ * name is NULL_terminated and we don't need to read anything else in
+ * the TCB. */
+ {TYPE_CHAR_ARRAY, 0, FREERTOS_THREAD_NAME_STR_SIZE}, /* char pcTaskName[configMAX_TASK_NAME_LEN] */
+ /* Lots of more optional stuff, but is is irrelevant to us. */
+ };
+
+ freertos->list_width = populate_offset_size(
+ freertos, struct_list_info, ARRAY_SIZE(struct_list_info));
+ freertos->list_uxNumberOfItems_offset = struct_list_info[0].offset;
+ freertos->list_uxNumberOfItems_size = struct_list_info[0].size;
+ freertos->list_next_offset = struct_list_info[3].offset;
+ freertos->list_next_size = struct_list_info[3].size;
+
+ freertos->list_item_width = populate_offset_size(
+ freertos, struct_list_item_info, ARRAY_SIZE(struct_list_item_info));
+ freertos->list_elem_next_offset = struct_list_item_info[1].offset;
+ freertos->list_elem_next_size = struct_list_item_info[1].size;
+ freertos->list_elem_content_offset = struct_list_item_info[3].offset;
+ freertos->list_elem_content_size = struct_list_item_info[3].size;
+
+ populate_offset_size(
+ freertos, task_control_block_info, ARRAY_SIZE(task_control_block_info));
+ freertos->thread_stack_offset = task_control_block_info[0].offset;
+ freertos->thread_stack_size = task_control_block_info[0].size;
+ freertos->thread_name_offset = task_control_block_info[5].offset;
+
return 0;
}
diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c
index 5e83333..9a470c6 100644
--- a/src/rtos/rtos.c
+++ b/src/rtos/rtos.c
@@ -79,7 +79,8 @@ static int rtos_target_for_threadid(struct connection *connection,
return ERROR_OK;
}
-static int os_alloc(struct target *target, struct rtos_type *ostype)
+static int os_alloc(struct target *target, struct rtos_type *ostype,
+ struct command_context *cmd_ctx)
{
struct rtos *os = target->rtos = calloc(1, sizeof(struct rtos));
@@ -96,6 +97,7 @@ static int os_alloc(struct target *target, struct rtos_type *ostype)
os->gdb_thread_packet = rtos_thread_packet;
os->gdb_v_packet = NULL;
os->gdb_target_for_threadid = rtos_target_for_threadid;
+ os->cmd_ctx = cmd_ctx;
return JIM_OK;
}
@@ -110,9 +112,10 @@ static void os_free(struct target *target)
target->rtos = NULL;
}
-static int os_alloc_create(struct target *target, struct rtos_type *ostype)
+static int os_alloc_create(struct target *target, struct rtos_type *ostype,
+ struct command_context *cmd_ctx)
{
- int ret = os_alloc(target, ostype);
+ int ret = os_alloc(target, ostype, cmd_ctx);
if (JIM_OK == ret) {
ret = target->rtos->type->create(target);
@@ -135,6 +138,8 @@ int rtos_create(Jim_GetOptInfo *goi, struct target *target)
return JIM_ERR;
}
+ struct command_context *cmd_ctx = current_command_context(goi->interp);
+
os_free(target);
e = Jim_GetOpt_String(goi, &cp, NULL);
@@ -149,12 +154,12 @@ int rtos_create(Jim_GetOptInfo *goi, struct target *target)
/* rtos_qsymbol() will iterate over all RTOSes. Allocate
* target->rtos here, and set it to the first RTOS type. */
- return os_alloc(target, rtos_types[0]);
+ return os_alloc(target, rtos_types[0], cmd_ctx);
}
for (x = 0; rtos_types[x]; x++)
if (0 == strcmp(cp, rtos_types[x]->name))
- return os_alloc_create(target, rtos_types[x]);
+ return os_alloc_create(target, rtos_types[x], cmd_ctx);
Jim_SetResultFormatted(goi->interp, "Unknown RTOS type %s, try one of: ", cp);
res = Jim_GetResult(goi->interp);
@@ -607,7 +612,7 @@ int rtos_generic_stack_read(struct target *target,
LOG_OUTPUT("\r\n");
#endif
- int64_t new_stack_ptr;
+ target_addr_t new_stack_ptr;
if (stacking->calculate_process_stack != NULL) {
new_stack_ptr = stacking->calculate_process_stack(target,
stack_data, stacking, stack_ptr);
diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h
index 3ea6416..9d8ccfe 100644
--- a/src/rtos/rtos.h
+++ b/src/rtos/rtos.h
@@ -60,6 +60,8 @@ struct rtos {
int (*gdb_v_packet)(struct connection *connection, char const *packet, int packet_size);
int (*gdb_target_for_threadid)(struct connection *connection, threadid_t thread_id, struct target **p_target);
void *rtos_specific_params;
+ /* Populated in rtos.c, so that individual RTOSes can register commands. */
+ struct command_context *cmd_ctx;
};
struct rtos_reg {
@@ -108,8 +110,8 @@ struct stack_register_offset {
};
struct rtos_register_stacking {
- unsigned char stack_registers_size;
- signed char stack_growth_direction;
+ unsigned stack_registers_size;
+ int stack_growth_direction;
/* The number of gdb general registers, in order. */
unsigned char num_output_registers;
/* Some targets require evaluating the stack to determine the
@@ -117,10 +119,10 @@ struct rtos_register_stacking {
* just use stacking->stack_registers_size * stack_growth_direction
* to calculate adjustment.
*/
- int64_t (*calculate_process_stack)(struct target *target,
+ target_addr_t (*calculate_process_stack)(struct target *target,
const uint8_t *stack_data,
const struct rtos_register_stacking *stacking,
- int64_t stack_ptr);
+ target_addr_t stack_ptr);
const struct stack_register_offset *register_offsets;
/* Total number of registers on the stack, including the general ones. This
* may be 0 if there are no additional registers on the stack beyond the
diff --git a/src/rtos/rtos_riot_stackings.c b/src/rtos/rtos_riot_stackings.c
index 6489426..6eddc79 100644
--- a/src/rtos/rtos_riot_stackings.c
+++ b/src/rtos/rtos_riot_stackings.c
@@ -27,9 +27,9 @@
/* This works for the M0 and M34 stackings as xPSR is in a fixed
* location
*/
-static int64_t rtos_riot_cortex_m_stack_align(struct target *target,
+static target_addr_t rtos_riot_cortex_m_stack_align(struct target *target,
const uint8_t *stack_data, const struct rtos_register_stacking *stacking,
- int64_t stack_ptr)
+ target_addr_t stack_ptr)
{
const int XPSR_OFFSET = 0x40;
return rtos_Cortex_M_stack_align(target, stack_data, stacking,
diff --git a/src/rtos/rtos_standard_stackings.c b/src/rtos/rtos_standard_stackings.c
index 7ff5b89..8a833de 100644
--- a/src/rtos/rtos_standard_stackings.c
+++ b/src/rtos/rtos_standard_stackings.c
@@ -153,7 +153,7 @@ static const struct stack_register_offset rtos_standard_NDS32_N1068_stack_offset
{ 35, 0x10, 32 }, /* IFC_LP */
};
-static const struct stack_register_offset rtos_standard_RV32_stack_offsets[] = {
+static const struct stack_register_offset rtos_metal_RV32_stack_offsets[] = {
/* zero isn't on the stack. By making its offset -1 we leave the value at 0
* inside rtos_generic_stack_read(). */
{ GDB_REGNO_ZERO, -1, 32 },
@@ -194,15 +194,139 @@ static const struct stack_register_offset rtos_standard_RV32_stack_offsets[] = {
{ GDB_REGNO_MSTATUS, 0x84, 32 },
};
-static int64_t rtos_generic_stack_align(struct target *target,
+static const struct stack_register_offset rtos_metal_RV64_stack_offsets[] = {
+ /* zero isn't on the stack. By making its offset -1 we leave the value at 0
+ * inside rtos_generic_stack_read(). */
+ { GDB_REGNO_ZERO, -1, 64 },
+ { GDB_REGNO_RA, 2 * 0x04, 64 },
+ { GDB_REGNO_SP, 2 * 0x08, 64 },
+ { GDB_REGNO_GP, 2 * 0x0c, 64 },
+ { GDB_REGNO_TP, 2 * 0x10, 64 },
+ { GDB_REGNO_T0, 2 * 0x14, 64 },
+ { GDB_REGNO_T1, 2 * 0x18, 64 },
+ { GDB_REGNO_T2, 2 * 0x1c, 64 },
+ { GDB_REGNO_FP, 2 * 0x20, 64 },
+ { GDB_REGNO_S1, 2 * 0x24, 64 },
+ { GDB_REGNO_A0, 2 * 0x28, 64 },
+ { GDB_REGNO_A1, 2 * 0x2c, 64 },
+ { GDB_REGNO_A2, 2 * 0x30, 64 },
+ { GDB_REGNO_A3, 2 * 0x34, 64 },
+ { GDB_REGNO_A4, 2 * 0x38, 64 },
+ { GDB_REGNO_A5, 2 * 0x3c, 64 },
+ { GDB_REGNO_A6, 2 * 0x40, 64 },
+ { GDB_REGNO_A7, 2 * 0x44, 64 },
+ { GDB_REGNO_S2, 2 * 0x48, 64 },
+ { GDB_REGNO_S3, 2 * 0x4c, 64 },
+ { GDB_REGNO_S4, 2 * 0x50, 64 },
+ { GDB_REGNO_S5, 2 * 0x54, 64 },
+ { GDB_REGNO_S6, 2 * 0x58, 64 },
+ { GDB_REGNO_S7, 2 * 0x5c, 64 },
+ { GDB_REGNO_S8, 2 * 0x60, 64 },
+ { GDB_REGNO_S9, 2 * 0x64, 64 },
+ { GDB_REGNO_S10, 2 * 0x68, 64 },
+ { GDB_REGNO_S11, 2 * 0x6c, 64 },
+ { GDB_REGNO_T3, 2 * 0x70, 64 },
+ { GDB_REGNO_T4, 2 * 0x74, 64 },
+ { GDB_REGNO_T5, 2 * 0x78, 64 },
+ { GDB_REGNO_T6, 2 * 0x7c, 64 },
+ { GDB_REGNO_PC, 2 * 0x80, 64 },
+ /* Registers below are on the stack, but not what gdb expects to return from
+ * a 'g' packet so are only accessible through get_reg. */
+ { GDB_REGNO_MSTATUS, 2 * 0x84, 64 },
+};
+
+static const struct stack_register_offset rtos_standard_RV32_stack_offsets[] = {
+ /* zero isn't on the stack. By making its offset -1 we leave the value at 0
+ * inside rtos_generic_stack_read(). */
+ { GDB_REGNO_ZERO, -1, 32 },
+ { GDB_REGNO_RA, 0x04, 32 },
+ { GDB_REGNO_SP, -2, 32 },
+ { GDB_REGNO_GP, -2, 32 },
+ { GDB_REGNO_TP, -2, 32 },
+ { GDB_REGNO_T0, 0x08, 32 },
+ { GDB_REGNO_T1, 0x0c, 32 },
+ { GDB_REGNO_T2, 0x10, 32 },
+ { GDB_REGNO_FP, 0x14, 32 },
+ { GDB_REGNO_S1, 0x18, 32 },
+ { GDB_REGNO_A0, 0x1c, 32 },
+ { GDB_REGNO_A1, 0x20, 32 },
+ { GDB_REGNO_A2, 0x24, 32 },
+ { GDB_REGNO_A3, 0x28, 32 },
+ { GDB_REGNO_A4, 0x2c, 32 },
+ { GDB_REGNO_A5, 0x30, 32 },
+ { GDB_REGNO_A6, 0x34, 32 },
+ { GDB_REGNO_A7, 0x38, 32 },
+ { GDB_REGNO_S2, 0x3c, 32 },
+ { GDB_REGNO_S3, 0x40, 32 },
+ { GDB_REGNO_S4, 0x44, 32 },
+ { GDB_REGNO_S5, 0x48, 32 },
+ { GDB_REGNO_S6, 0x4c, 32 },
+ { GDB_REGNO_S7, 0x50, 32 },
+ { GDB_REGNO_S8, 0x54, 32 },
+ { GDB_REGNO_S9, 0x58, 32 },
+ { GDB_REGNO_S10, 0x5c, 32 },
+ { GDB_REGNO_S11, 0x60, 32 },
+ { GDB_REGNO_T3, 0x64, 32 },
+ { GDB_REGNO_T4, 0x68, 32 },
+ { GDB_REGNO_T5, 0x6c, 32 },
+ { GDB_REGNO_T6, 0x70, 32 },
+ { GDB_REGNO_PC, 0, 32 },
+ /* Registers below are on the stack, but not what gdb expects to return from
+ * a 'g' packet so are only accessible through get_reg. */
+ { GDB_REGNO_MSTATUS, 29 * 4, 32 },
+};
+
+static const struct stack_register_offset rtos_standard_RV64_stack_offsets[] = {
+ /* zero isn't on the stack. By making its offset -1 we leave the value at 0
+ * inside rtos_generic_stack_read(). */
+ { GDB_REGNO_ZERO, -1, 64 },
+ { GDB_REGNO_RA, 2 * 0x04, 64 },
+ { GDB_REGNO_SP, -2, 64 },
+ { GDB_REGNO_GP, -2, 64 },
+ { GDB_REGNO_TP, -2, 64 },
+ { GDB_REGNO_T0, 2 * 0x08, 64 },
+ { GDB_REGNO_T1, 2 * 0x0c, 64 },
+ { GDB_REGNO_T2, 2 * 0x10, 64 },
+ { GDB_REGNO_FP, 2 * 0x14, 64 },
+ { GDB_REGNO_S1, 2 * 0x18, 64 },
+ { GDB_REGNO_A0, 2 * 0x1c, 64 },
+ { GDB_REGNO_A1, 2 * 0x20, 64 },
+ { GDB_REGNO_A2, 2 * 0x24, 64 },
+ { GDB_REGNO_A3, 2 * 0x28, 64 },
+ { GDB_REGNO_A4, 2 * 0x2c, 64 },
+ { GDB_REGNO_A5, 2 * 0x30, 64 },
+ { GDB_REGNO_A6, 2 * 0x34, 64 },
+ { GDB_REGNO_A7, 2 * 0x38, 64 },
+ { GDB_REGNO_S2, 2 * 0x3c, 64 },
+ { GDB_REGNO_S3, 2 * 0x40, 64 },
+ { GDB_REGNO_S4, 2 * 0x44, 64 },
+ { GDB_REGNO_S5, 2 * 0x48, 64 },
+ { GDB_REGNO_S6, 2 * 0x4c, 64 },
+ { GDB_REGNO_S7, 2 * 0x50, 64 },
+ { GDB_REGNO_S8, 2 * 0x54, 64 },
+ { GDB_REGNO_S9, 2 * 0x58, 64 },
+ { GDB_REGNO_S10, 2 * 0x5c, 64 },
+ { GDB_REGNO_S11, 2 * 0x60, 64 },
+ { GDB_REGNO_T3, 2 * 0x64, 64 },
+ { GDB_REGNO_T4, 2 * 0x68, 64 },
+ { GDB_REGNO_T5, 2 * 0x6c, 64 },
+ { GDB_REGNO_T6, 2 * 0x70, 64 },
+ { GDB_REGNO_PC, 0, 64 },
+ /* Registers below are on the stack, but not what gdb expects to return from
+ * a 'g' packet so are only accessible through get_reg. */
+ { GDB_REGNO_MSTATUS, 2 * 29 * 4, 64 },
+};
+
+static target_addr_t rtos_generic_stack_align(struct target *target,
const uint8_t *stack_data, const struct rtos_register_stacking *stacking,
- int64_t stack_ptr, int align)
+ target_addr_t stack_ptr, int align)
{
- int64_t new_stack_ptr;
- int64_t aligned_stack_ptr;
- new_stack_ptr = stack_ptr - stacking->stack_growth_direction *
- stacking->stack_registers_size;
- aligned_stack_ptr = new_stack_ptr & ~((int64_t)align - 1);
+ target_addr_t new_stack_ptr = stack_ptr;
+ if (stacking->stack_growth_direction > 0)
+ new_stack_ptr -= stacking->stack_registers_size;
+ else
+ new_stack_ptr += stacking->stack_registers_size;
+ target_addr_t aligned_stack_ptr = new_stack_ptr & ~((int64_t)align - 1);
if (aligned_stack_ptr != new_stack_ptr &&
stacking->stack_growth_direction == -1) {
/* If we have a downward growing stack, the simple alignment code
@@ -214,9 +338,9 @@ static int64_t rtos_generic_stack_align(struct target *target,
return aligned_stack_ptr;
}
-int64_t rtos_generic_stack_align8(struct target *target,
+target_addr_t rtos_generic_stack_align8(struct target *target,
const uint8_t *stack_data, const struct rtos_register_stacking *stacking,
- int64_t stack_ptr)
+ target_addr_t stack_ptr)
{
return rtos_generic_stack_align(target, stack_data,
stacking, stack_ptr, 8);
@@ -262,27 +386,27 @@ int64_t rtos_Cortex_M_stack_align(struct target *target,
return new_stack_ptr;
}
-static int64_t rtos_standard_Cortex_M3_stack_align(struct target *target,
+static target_addr_t rtos_standard_Cortex_M3_stack_align(struct target *target,
const uint8_t *stack_data, const struct rtos_register_stacking *stacking,
- int64_t stack_ptr)
+ target_addr_t stack_ptr)
{
const int XPSR_OFFSET = 0x3c;
return rtos_Cortex_M_stack_align(target, stack_data, stacking,
stack_ptr, XPSR_OFFSET);
}
-static int64_t rtos_standard_Cortex_M4F_stack_align(struct target *target,
+static target_addr_t rtos_standard_Cortex_M4F_stack_align(struct target *target,
const uint8_t *stack_data, const struct rtos_register_stacking *stacking,
- int64_t stack_ptr)
+ target_addr_t stack_ptr)
{
const int XPSR_OFFSET = 0x40;
return rtos_Cortex_M_stack_align(target, stack_data, stacking,
stack_ptr, XPSR_OFFSET);
}
-static int64_t rtos_standard_Cortex_M4F_FPU_stack_align(struct target *target,
+static target_addr_t rtos_standard_Cortex_M4F_FPU_stack_align(struct target *target,
const uint8_t *stack_data, const struct rtos_register_stacking *stacking,
- int64_t stack_ptr)
+ target_addr_t stack_ptr)
{
const int XPSR_OFFSET = 0x80;
return rtos_Cortex_M_stack_align(target, stack_data, stacking,
@@ -330,6 +454,15 @@ const struct rtos_register_stacking rtos_standard_NDS32_N1068_stacking = {
.register_offsets = rtos_standard_NDS32_N1068_stack_offsets
};
+const struct rtos_register_stacking rtos_metal_RV32_stacking = {
+ .stack_registers_size = (32 + 2) * 4,
+ .stack_growth_direction = -1,
+ .num_output_registers = 33,
+ .calculate_process_stack = rtos_generic_stack_align8,
+ .register_offsets = rtos_metal_RV32_stack_offsets,
+ .total_register_count = ARRAY_SIZE(rtos_metal_RV32_stack_offsets)
+};
+
const struct rtos_register_stacking rtos_standard_RV32_stacking = {
.stack_registers_size = (32 + 2) * 4,
.stack_growth_direction = -1,
@@ -338,3 +471,21 @@ const struct rtos_register_stacking rtos_standard_RV32_stacking = {
.register_offsets = rtos_standard_RV32_stack_offsets,
.total_register_count = ARRAY_SIZE(rtos_standard_RV32_stack_offsets)
};
+
+const struct rtos_register_stacking rtos_metal_RV64_stacking = {
+ .stack_registers_size = (32 + 2) * 8,
+ .stack_growth_direction = -1,
+ .num_output_registers = 33,
+ .calculate_process_stack = rtos_generic_stack_align8,
+ .register_offsets = rtos_metal_RV64_stack_offsets,
+ .total_register_count = ARRAY_SIZE(rtos_metal_RV64_stack_offsets)
+};
+
+const struct rtos_register_stacking rtos_standard_RV64_stacking = {
+ .stack_registers_size = (32 + 2) * 8,
+ .stack_growth_direction = -1,
+ .num_output_registers = 33,
+ .calculate_process_stack = rtos_generic_stack_align8,
+ .register_offsets = rtos_standard_RV64_stack_offsets,
+ .total_register_count = ARRAY_SIZE(rtos_standard_RV64_stack_offsets)
+};
diff --git a/src/rtos/rtos_standard_stackings.h b/src/rtos/rtos_standard_stackings.h
index 302ebed..6a10e4b 100644
--- a/src/rtos/rtos_standard_stackings.h
+++ b/src/rtos/rtos_standard_stackings.h
@@ -30,13 +30,16 @@ extern const struct rtos_register_stacking rtos_standard_Cortex_M4F_stacking;
extern const struct rtos_register_stacking rtos_standard_Cortex_M4F_FPU_stacking;
extern const struct rtos_register_stacking rtos_standard_Cortex_R4_stacking;
extern const struct rtos_register_stacking rtos_standard_NDS32_N1068_stacking;
-int64_t rtos_generic_stack_align8(struct target *target,
+target_addr_t rtos_generic_stack_align8(struct target *target,
const uint8_t *stack_data, const struct rtos_register_stacking *stacking,
- int64_t stack_ptr);
-int64_t rtos_Cortex_M_stack_align(struct target *target,
+ target_addr_t stack_ptr);
+target_addr_t rtos_Cortex_M_stack_align(struct target *target,
const uint8_t *stack_data, const struct rtos_register_stacking *stacking,
- int64_t stack_ptr, size_t xpsr_offset);
+ target_addr_t stack_ptr, size_t xpsr_offset);
extern const struct rtos_register_stacking rtos_standard_RV32_stacking;
+extern const struct rtos_register_stacking rtos_standard_RV64_stacking;
+extern const struct rtos_register_stacking rtos_metal_RV32_stacking;
+extern const struct rtos_register_stacking rtos_metal_RV64_stacking;
#endif /* OPENOCD_RTOS_RTOS_STANDARD_STACKINGS_H */