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>
This commit is contained in:
parent
28724d996a
commit
737f013ada
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue