diff options
author | Tim Newsome <tim@sifive.com> | 2021-04-08 12:53:30 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-08 12:53:30 -0700 |
commit | 737f013ada404fdd620c2c0d4f1cb318a0ff64b2 (patch) | |
tree | 70cb46a7050fb037607b1c0f460e089581f5ca95 | |
parent | 28724d996a9b68e490f6bd90b5537c71631c753d (diff) | |
download | riscv-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.c | 397 | ||||
-rw-r--r-- | src/rtos/rtos.c | 17 | ||||
-rw-r--r-- | src/rtos/rtos.h | 10 | ||||
-rw-r--r-- | src/rtos/rtos_riot_stackings.c | 4 | ||||
-rw-r--r-- | src/rtos/rtos_standard_stackings.c | 183 | ||||
-rw-r--r-- | src/rtos/rtos_standard_stackings.h | 11 |
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 */ |