This is an automated email from Gerrit. "Nishanth Menon <n...@ti.com>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/7089
-- gerrit commit 661354f240332a378004812586306b376222258e Author: Jason Peck <jp...@ti.com> Date: Mon Jul 18 13:45:05 2022 -0500 jtag/drivers: dmem: Add Emulated AP mode This emulation mode supports software translation of an AP request into an address mapped transaction that does not rely on physical AP hardware. This is necessary in some hardware such as K3 SoCs since the hardware architecture anticipates a potential race condition between AP doing direct memory access generating transactions back to system bus and firewalls that data path out. This emulation mode allows direct memory driver to emulate CoreSight Access Port(AP) and reuse the SoC configuration meant for JTAG debuggers. Since the address ranges are flat in nature, the requisite memory base and size will need to be provided a-priori to the driver for mapping. The other design alternative would be to map requested memory map for every register operation, but, that would defeat our intent of getting max debug performance. Signed-off-by: Nishanth Menon <n...@ti.com> Signed-off-by: Jason Peck <jp...@ti.com> Change-Id: I2d3c5f7833f1973e90b4f6b247827f62fc2905d0 diff --git a/doc/openocd.texi b/doc/openocd.texi index bd5713f108..e50b7a33ab 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -3719,6 +3719,19 @@ Set the address offset between Access Ports (APs). Set the maximum number of valid access ports on the SoC. @end deffn +@deffn {Config Command} {emu_ap_list list_of_ap_ids} +Set the list of Access Ports(APs) that need to be emulated. This +emulation mode supports software translation of an AP request into an +address mapped transaction that does not rely on physical AP hardware. +This maybe needed if the AP is either denied access via memory map or +protected using other SoC mechanisms. +@end deffn + +@deffn {Config Command} {emu_base_address base_address address_window_size} +Set the emulated address and address window size. Both of these +parameters must be aligned to page size. +@end deffn + @end deffn @section Transport Configuration diff --git a/src/jtag/drivers/dmem.c b/src/jtag/drivers/dmem.c index 1d74b93518..75fe0d8fe0 100644 --- a/src/jtag/drivers/dmem.c +++ b/src/jtag/drivers/dmem.c @@ -24,6 +24,12 @@ #include <target/arm_adi_v5.h> #include <transport/transport.h> +/* + * This bit tells if the transaction is coming in from jtag or not + * we just mask this out to emulate direct address access + */ +#define ARM_APB_PADDR31 (0x1 << 31) + /* Use local variable stub for DP/AP registers. */ static uint32_t dp_ctrl_stat; static uint32_t dp_id_code; @@ -44,6 +50,166 @@ static uint64_t dmem_dap_base_address; static uint8_t dmem_dap_max_aps = 1; static uint32_t dmem_dap_ap_offset = 0x100; +/* AP Emulation Mode */ +static uint64_t dmem_emu_base_address; +static uint64_t dmem_emu_mapped_size; +static void *dmem_emu_virt_base_addr; +#define DMEM_MAX_EMULATE_APS 5 +static uint8_t dmem_emu_ap_count; +static uint64_t dmem_emu_ap_list[DMEM_MAX_EMULATE_APS]; + +/* Emulation mode state variables */ +static uint32_t apbap_tar; +static uint32_t apbap_tar_inc; +static uint32_t apbap_csw; +static uint32_t apbap_cfg; +static uint32_t apbap_base; +static uint32_t apbap_idr; + +/* + * EMULATION MODE: In Emulation MODE, we assume the following: + * TCL still describes as system is operational from the view of AP (ex. jtag) + * However, the hardware does'nt permit direct memory access to these APs + * (only permitted via JTAG). + * + * So, the access to these APs have to be decoded to a memory map + * access which we can directly access. + * + * A few TI processors have this issue. + */ +static int dmem_is_emulated_ap(struct adiv5_ap *ap) +{ + int i; + + for (i = 0; i < dmem_emu_ap_count; i++) { + if (ap->ap_num == dmem_emu_ap_list[i]) + return ERROR_OK; + } + return ERROR_FAIL; +} + +static void dmem_emu_set_ap_reg(uint64_t addr, uint32_t val) +{ + addr &= ~ARM_APB_PADDR31; + + *(volatile uint32_t *)((char *)dmem_emu_virt_base_addr + addr) = val; +} + +static uint32_t dmem_emu_get_ap_reg(uint64_t addr) +{ + uint32_t val; + + addr &= ~ARM_APB_PADDR31; + + val = *(volatile uint32_t *)((char *)dmem_emu_virt_base_addr + addr); + + return val; +} + +static int dmem_emu_ap_q_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *data) +{ + uint64_t addr; + int ret = ERROR_OK; + + switch (reg) { + case ADIV5_MEM_AP_REG_CSW: + *data = apbap_csw; + break; + case ADIV5_MEM_AP_REG_TAR: + *data = apbap_tar; + break; + case ADIV5_MEM_AP_REG_CFG: + *data = 0; + break; + case ADIV5_MEM_AP_REG_BASE: + *data = 0; + break; + case ADIV5_AP_REG_IDR: + *data = 0; + break; + case ADIV5_MEM_AP_REG_BD0: + case ADIV5_MEM_AP_REG_BD1: + case ADIV5_MEM_AP_REG_BD2: + case ADIV5_MEM_AP_REG_BD3: + addr = (apbap_tar & ~0xf) + (reg & 0x0C); + + *data = dmem_emu_get_ap_reg(addr); + + break; + case ADIV5_MEM_AP_REG_DRW: + addr = (apbap_tar & ~0x3) + apbap_tar_inc; + + *data = dmem_emu_get_ap_reg(addr); + + if (apbap_csw & CSW_ADDRINC_MASK) + apbap_tar_inc += (apbap_csw & 0x03) * 2; + break; + default: + LOG_INFO("%s: Unknown reg: 0x%02x\n", __func__, reg); + ret = ERROR_FAIL; + break; + } + + /* Track the last error code. */ + if (ret != ERROR_OK) + dmem_dap_retval = ret; + + return ret; +} + +static int dmem_emu_ap_q_write(struct adiv5_ap *ap, unsigned int reg, uint32_t data) +{ + uint64_t addr; + int ret = ERROR_OK; + + switch (reg) { + case ADIV5_MEM_AP_REG_CSW: + apbap_csw = data; + break; + case ADIV5_MEM_AP_REG_TAR: + apbap_tar = data; + apbap_tar_inc = 0; + break; + + case ADIV5_MEM_AP_REG_CFG: + apbap_cfg = data; + break; + case ADIV5_MEM_AP_REG_BASE: + apbap_base = data; + break; + case ADIV5_AP_REG_IDR: + apbap_idr = data; + break; + + case ADIV5_MEM_AP_REG_BD0: + case ADIV5_MEM_AP_REG_BD1: + case ADIV5_MEM_AP_REG_BD2: + case ADIV5_MEM_AP_REG_BD3: + addr = (apbap_tar & ~0xf) + (reg & 0x0C); + + dmem_emu_set_ap_reg(addr, data); + + break; + case ADIV5_MEM_AP_REG_DRW: + addr = (apbap_tar & ~0x3) + apbap_tar_inc; + dmem_emu_set_ap_reg(addr, data); + + if (apbap_csw & CSW_ADDRINC_MASK) + apbap_tar_inc += (apbap_csw & 0x03) * 2; + break; + default: + LOG_INFO("%s: Unknown reg: 0x%02x\n", __func__, reg); + ret = EINVAL; + break; + } + + /* Track the last error code. */ + if (ret != ERROR_OK) + dmem_dap_retval = ret; + + return ret; +} + /* AP MODE */ static uint32_t dmem_get_ap_reg_offset(struct adiv5_ap *ap, unsigned int reg) { @@ -111,6 +277,9 @@ static int dmem_ap_q_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *data) return ERROR_FAIL; } + if (dmem_is_emulated_ap(ap) == ERROR_OK) + return dmem_emu_ap_q_read(ap, reg, data); + *data = dmem_get_ap_reg(ap, reg); return ERROR_OK; @@ -134,6 +303,9 @@ static int dmem_ap_q_write(struct adiv5_ap *ap, unsigned int reg, uint32_t data) return ERROR_FAIL; } + if (dmem_is_emulated_ap(ap) == ERROR_OK) + return dmem_emu_ap_q_write(ap, reg, data); + dmem_set_ap_reg(ap, reg, data); return ERROR_OK; @@ -166,6 +338,11 @@ static int dmem_connect(struct adiv5_dap *dap) return ERROR_FAIL; } + if (dmem_emu_ap_count && (!dmem_emu_base_address || !dmem_emu_mapped_size)) { + LOG_ERROR("dmem EMU Base address NOT set? value is 0\n"); + return ERROR_FAIL; + } + dmem_fd = open(path, O_RDWR | O_SYNC); if (dmem_fd == -1) { LOG_ERROR("Unable to open %s\n", path); @@ -202,6 +379,26 @@ static int dmem_connect(struct adiv5_dap *dap) dmem_virt_base_addr = (char *)dmem_map_base + start_delta; + /* Lets Map the emulated address if necessary */ + if (dmem_emu_ap_count) { + if ((dmem_emu_base_address % page_size) || + (dmem_emu_mapped_size % page_size)) { + LOG_ERROR ("Please align emulated base and size to pagesize 0x%lx\n", page_size); + return ERROR_FAIL; + } + dmem_emu_virt_base_addr = mmap(NULL, + dmem_emu_mapped_size, + (PROT_READ | PROT_WRITE), + MAP_SHARED, dmem_fd, + dmem_emu_base_address & ~(off_t) (page_size + - 1)); + if (dmem_emu_virt_base_addr == MAP_FAILED) { + LOG_ERROR("Mapping EMU address 0x%lx for 0x%lx bytes failed!\n", + dmem_emu_base_address, dmem_emu_mapped_size); + return ERROR_FAIL; + } + } + return ERROR_OK; } @@ -209,6 +406,9 @@ static void dmem_disconnect(struct adiv5_dap *dap) { if (munmap(dmem_map_base, dmem_mapped_size) == -1) LOG_ERROR("%s: Failed to unmap mapped memory!\n", __func__); + if (dmem_emu_ap_count + && munmap(dmem_emu_virt_base_addr, dmem_emu_mapped_size) == -1) + LOG_ERROR("%s: Failed to unmap emu mapped memory!\n", __func__); if (dmem_fd != -1) { close(dmem_fd); dmem_fd = -1; @@ -257,6 +457,39 @@ COMMAND_HANDLER(dmem_dap_ap_offset_command) return ERROR_OK; } +COMMAND_HANDLER(dmem_emu_base_address_command) +{ + if (CMD_ARGC != 2) { + command_print(CMD, "Need address and Size"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], dmem_emu_base_address); + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], dmem_emu_mapped_size); + + return ERROR_OK; +} + +COMMAND_HANDLER(dmem_emu_ap_list_command) +{ + int i; + int argc = CMD_ARGC; + uint64_t em_ap; + + if (argc > DMEM_MAX_EMULATE_APS) { + command_print(CMD, "Max emulated APs can be upto %d", + DMEM_MAX_EMULATE_APS); + return ERROR_COMMAND_SYNTAX_ERROR; + } + for (i = 0; i < argc; i++) { + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[i], em_ap); + dmem_emu_ap_list[i] = em_ap; + } + + dmem_emu_ap_count = CMD_ARGC; + + return ERROR_OK; +} + COMMAND_HANDLER(dmem_dap_config_info_command) { if (CMD_ARGC != 0) { @@ -269,7 +502,18 @@ COMMAND_HANDLER(dmem_dap_config_info_command) command_print(CMD, " Base Address : 0x%lx", dmem_dap_base_address); command_print(CMD, " Max APs : %d", dmem_dap_max_aps); command_print(CMD, " AP offset : 0x%08x", dmem_dap_ap_offset); + command_print(CMD, " Emulated AP Count : %d", dmem_emu_ap_count); + if (dmem_emu_ap_count) { + int i; + + command_print(CMD, " Emulated AP details:"); + command_print(CMD, " Emulated address : 0x%lx", dmem_emu_base_address); + command_print(CMD, " Emulated size : 0x%lx", dmem_emu_mapped_size); + for (i = 0; i < dmem_emu_ap_count; i++) + command_print(CMD, " Emulated AP [%d] : %ld", i, + dmem_emu_ap_list[i]); + } return ERROR_OK; } @@ -302,6 +546,20 @@ static const struct command_registration dmem_dap_subcommand_handlers[] = { .help = "set the offsets of each ap index", .usage = "<0x100>", }, + { + .name = "emu_base_address", + .handler = dmem_emu_base_address_command, + .mode = COMMAND_CONFIG, + .help = "set the base address and size of emulated AP range (all emulated APs access this range)", + .usage = "<0x100 0x100>", + }, + { + .name = "emu_ap_list", + .handler = dmem_emu_ap_list_command, + .mode = COMMAND_CONFIG, + .help = "set the list of AP indices to be emulated (upto max)", + .usage = "<1 5>", + }, { .name = "info", .handler = dmem_dap_config_info_command, --