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:
Tim Newsome 2021-04-08 12:53:30 -07:00 committed by GitHub
parent 28724d996a
commit 737f013ada
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 481 additions and 141 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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,

View File

@ -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)
};

View File

@ -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 */