Merge remote-tracking branch 'origin/riscv' into riscv-compliance

This commit is contained in:
Megan Wachs
2017-10-25 15:41:41 -07:00
49 changed files with 2500 additions and 1430 deletions
+1 -1
View File
@@ -22,8 +22,8 @@ NOR_DRIVERS = \
%D%/dsp5680xx_flash.c \
%D%/efm32.c \
%D%/em357.c \
%D%/fespi.c \
%D%/faux.c \
%D%/fespi.c \
%D%/fm3.c \
%D%/fm4.c \
%D%/jtagspi.c \
+11 -11
View File
@@ -464,7 +464,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0,
.base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */
.flash_wait_states = 5,
.present = 1,
.size_bytes = 1024 * 1024,
.nsectors = 128,
@@ -499,7 +499,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0,
.base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */
.flash_wait_states = 5,
.present = 1,
.size_bytes = 512 * 1024,
.nsectors = 64,
@@ -532,7 +532,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0,
.base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */
.flash_wait_states = 5,
.present = 1,
.size_bytes = 512 * 1024,
.nsectors = 64,
@@ -565,7 +565,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0,
.base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */
.flash_wait_states = 5,
.present = 1,
.size_bytes = 512 * 1024,
.nsectors = 64,
@@ -598,7 +598,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0,
.base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */
.flash_wait_states = 5,
.present = 1,
.size_bytes = 1024 * 1024,
.nsectors = 128,
@@ -631,7 +631,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0,
.base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */
.flash_wait_states = 5,
.present = 1,
.size_bytes = 1024 * 1024,
.nsectors = 128,
@@ -1279,7 +1279,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0,
.base_address = FLASH_BANK0_BASE_SD,
.controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */
.flash_wait_states = 5,
.present = 1,
.size_bytes = 512 * 1024,
.nsectors = 64,
@@ -1295,7 +1295,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 1,
.base_address = FLASH_BANK1_BASE_1024K_SD,
.controller_address = 0x400e0c00,
.flash_wait_states = 6, /* workaround silicon bug */
.flash_wait_states = 5,
.present = 1,
.size_bytes = 512 * 1024,
.nsectors = 64,
@@ -1305,10 +1305,10 @@ static const struct sam4_chip_details all_sam4_details[] = {
},
},
/* at91samg53n19 */
/* atsamg53n19 */
{
.chipid_cidr = 0x247e0ae0,
.name = "at91samg53n19",
.name = "atsamg53n19",
.total_flash_size = 512 * 1024,
.total_sram_size = 96 * 1024,
.n_gpnvms = 2,
@@ -1323,7 +1323,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0,
.base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */
.flash_wait_states = 5,
.present = 1,
.size_bytes = 512 * 1024,
.nsectors = 64,
+34 -49
View File
@@ -25,7 +25,7 @@
#include <target/cortex_m.h>
#define SAMD_NUM_SECTORS 16
#define SAMD_NUM_PROT_BLOCKS 16
#define SAMD_PAGE_SIZE_MAX 1024
#define SAMD_FLASH ((uint32_t)0x00000000) /* physical Flash memory */
@@ -286,6 +286,7 @@ struct samd_info {
uint32_t page_size;
int num_pages;
int sector_size;
int prot_block_size;
bool probed;
struct target *target;
@@ -319,7 +320,7 @@ static const struct samd_part *samd_find_part(uint32_t id)
static int samd_protect_check(struct flash_bank *bank)
{
int res;
int res, prot_block;
uint16_t lock;
res = target_read_u16(bank->target,
@@ -328,8 +329,8 @@ static int samd_protect_check(struct flash_bank *bank)
return res;
/* Lock bits are active-low */
for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_protected = !(lock & (1<<i));
for (prot_block = 0; prot_block < bank->num_prot_blocks; prot_block++)
bank->prot_blocks[prot_block].is_protected = !(lock & (1u<<prot_block));
return ERROR_OK;
}
@@ -380,8 +381,6 @@ static int samd_probe(struct flash_bank *bank)
bank->size = part->flash_kb * 1024;
chip->sector_size = bank->size / SAMD_NUM_SECTORS;
res = samd_get_flash_page_info(bank->target, &chip->page_size,
&chip->num_pages);
if (res != ERROR_OK) {
@@ -397,21 +396,23 @@ static int samd_probe(struct flash_bank *bank)
part->flash_kb, chip->num_pages, chip->page_size);
}
/* Erase granularity = 1 row = 4 pages */
chip->sector_size = chip->page_size * 4;
/* Allocate the sector table */
bank->num_sectors = SAMD_NUM_SECTORS;
bank->sectors = calloc(bank->num_sectors, sizeof((bank->sectors)[0]));
bank->num_sectors = chip->num_pages / 4;
bank->sectors = alloc_block_array(0, chip->sector_size, bank->num_sectors);
if (!bank->sectors)
return ERROR_FAIL;
/* Fill out the sector information: all SAMD sectors are the same size and
* there is always a fixed number of them. */
for (int i = 0; i < bank->num_sectors; i++) {
bank->sectors[i].size = chip->sector_size;
bank->sectors[i].offset = i * chip->sector_size;
/* mark as unknown */
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = -1;
}
/* 16 protection blocks per device */
chip->prot_block_size = bank->size / SAMD_NUM_PROT_BLOCKS;
/* Allocate the table of protection blocks */
bank->num_prot_blocks = SAMD_NUM_PROT_BLOCKS;
bank->prot_blocks = alloc_block_array(0, chip->prot_block_size, bank->num_prot_blocks);
if (!bank->prot_blocks)
return ERROR_FAIL;
samd_protect_check(bank);
@@ -606,9 +607,10 @@ out_user_row:
return res;
}
static int samd_protect(struct flash_bank *bank, int set, int first, int last)
static int samd_protect(struct flash_bank *bank, int set, int first_prot_bl, int last_prot_bl)
{
struct samd_info *chip = (struct samd_info *)bank->driver_priv;
int res = ERROR_OK;
int prot_block;
/* We can issue lock/unlock region commands with the target running but
* the settings won't persist unless we're able to modify the LOCK regions
@@ -618,18 +620,16 @@ static int samd_protect(struct flash_bank *bank, int set, int first, int last)
return ERROR_TARGET_NOT_HALTED;
}
int res = ERROR_OK;
for (int s = first; s <= last; s++) {
if (set != bank->sectors[s].is_protected) {
/* Load an address that is within this sector (we use offset 0) */
for (prot_block = first_prot_bl; prot_block <= last_prot_bl; prot_block++) {
if (set != bank->prot_blocks[prot_block].is_protected) {
/* Load an address that is within this protection block (we use offset 0) */
res = target_write_u32(bank->target,
SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR,
((s * chip->sector_size) >> 1));
bank->prot_blocks[prot_block].offset >> 1);
if (res != ERROR_OK)
goto exit;
/* Tell the controller to lock that sector */
/* Tell the controller to lock that block */
res = samd_issue_nvmctrl_command(bank->target,
set ? SAMD_NVM_CMD_LR : SAMD_NVM_CMD_UR);
if (res != ERROR_OK)
@@ -644,7 +644,7 @@ static int samd_protect(struct flash_bank *bank, int set, int first, int last)
* locked. See Table 9-3 in the SAMD20 datasheet for more details. */
res = samd_modify_user_row(bank->target, set ? 0x0000 : 0xFFFF,
48 + first, 48 + last);
48 + first_prot_bl, 48 + last_prot_bl);
if (res != ERROR_OK)
LOG_WARNING("SAMD: protect settings were not made persistent!");
@@ -656,10 +656,9 @@ exit:
return res;
}
static int samd_erase(struct flash_bank *bank, int first, int last)
static int samd_erase(struct flash_bank *bank, int first_sect, int last_sect)
{
int res;
int rows_in_sector;
int res, s;
struct samd_info *chip = (struct samd_info *)bank->driver_priv;
if (bank->target->state != TARGET_HALTED) {
@@ -673,26 +672,12 @@ static int samd_erase(struct flash_bank *bank, int first, int last)
return ERROR_FLASH_BANK_NOT_PROBED;
}
/* The SAMD NVM has row erase granularity. There are four pages in a row
* and the number of rows in a sector depends on the sector size, which in
* turn depends on the Flash capacity as there is a fixed number of
* sectors. */
rows_in_sector = chip->sector_size / (chip->page_size * 4);
/* For each sector to be erased */
for (int s = first; s <= last; s++) {
if (bank->sectors[s].is_protected) {
LOG_ERROR("SAMD: failed to erase sector %d. That sector is write-protected", s);
return ERROR_FLASH_OPERATION_FAILED;
}
/* For each row in that sector */
for (int r = s * rows_in_sector; r < (s + 1) * rows_in_sector; r++) {
res = samd_erase_row(bank->target, r * chip->page_size * 4);
if (res != ERROR_OK) {
LOG_ERROR("SAMD: failed to erase sector %d", s);
return res;
}
for (s = first_sect; s <= last_sect; s++) {
res = samd_erase_row(bank->target, bank->sectors[s].offset);
if (res != ERROR_OK) {
LOG_ERROR("SAMD: failed to erase sector %d at 0x%08" PRIx32, s, bank->sectors[s].offset);
return res;
}
}
+5 -1
View File
@@ -48,6 +48,7 @@
#define EFM_FAMILY_ID_HAPPY_GECKO 77
#define EZR_FAMILY_ID_WONDER_GECKO 120
#define EZR_FAMILY_ID_LEOPARD_GECKO 121
#define EZR_FAMILY_ID_HAPPY_GECKO 122
#define EFM32_FLASH_ERASE_TMO 100
#define EFM32_FLASH_WDATAREADY_TMO 100
@@ -178,7 +179,8 @@ static int efm32x_read_info(struct flash_bank *bank,
EFM_FAMILY_ID_TINY_GECKO == efm32_info->part_family)
efm32_info->page_size = 512;
else if (EFM_FAMILY_ID_ZERO_GECKO == efm32_info->part_family ||
EFM_FAMILY_ID_HAPPY_GECKO == efm32_info->part_family)
EFM_FAMILY_ID_HAPPY_GECKO == efm32_info->part_family ||
EZR_FAMILY_ID_HAPPY_GECKO == efm32_info->part_family)
efm32_info->page_size = 1024;
else if (EFM_FAMILY_ID_GIANT_GECKO == efm32_info->part_family ||
EFM_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family) {
@@ -236,6 +238,7 @@ static int efm32x_decode_info(struct efm32_info *info, char *buf, int buf_size)
switch (info->part_family) {
case EZR_FAMILY_ID_WONDER_GECKO:
case EZR_FAMILY_ID_LEOPARD_GECKO:
case EZR_FAMILY_ID_HAPPY_GECKO:
printed = snprintf(buf, buf_size, "EZR32 ");
break;
default:
@@ -270,6 +273,7 @@ static int efm32x_decode_info(struct efm32_info *info, char *buf, int buf_size)
printed = snprintf(buf, buf_size, "Zero Gecko");
break;
case EFM_FAMILY_ID_HAPPY_GECKO:
case EZR_FAMILY_ID_HAPPY_GECKO:
printed = snprintf(buf, buf_size, "Happy Gecko");
break;
}
+1016 -311
View File
File diff suppressed because it is too large Load Diff
+220 -56
View File
@@ -59,10 +59,14 @@
*
* Sector sizes in kiBytes:
* 1 MiByte part with 4 x 16, 1 x 64, 7 x 128.
* 1.5 MiByte part with 4 x 16, 1 x 64, 11 x 128.
* 2 MiByte part with 4 x 16, 1 x 64, 7 x 128, 4 x 16, 1 x 64, 7 x 128.
* 1 MiByte STM32F42x/43x part with DB1M Option set:
* 4 x 16, 1 x 64, 3 x 128, 4 x 16, 1 x 64, 3 x 128.
*
* STM32F7[2|3]
* 512 kiByte part with 4 x 16, 1 x 64, 3 x 128.
*
* STM32F7[4|5]
* 1 MiByte part with 4 x 32, 1 x 128, 3 x 256.
*
@@ -93,6 +97,12 @@
* RM0410
* http://www.st.com/resource/en/reference_manual/dm00224583.pdf
*
* RM0430
* http://www.st.com/resource/en/reference_manual/dm00305666.pdf
*
* RM0431
* http://www.st.com/resource/en/reference_manual/dm00305990.pdf
*
* STM32F1x series - notice that this code was copy, pasted and knocked
* into a stm32f2x driver, so in case something has been converted or
* bugs haven't been fixed, here are the original manuals:
@@ -121,6 +131,7 @@
#define STM32_FLASH_CR 0x40023c10
#define STM32_FLASH_OPTCR 0x40023c14
#define STM32_FLASH_OPTCR1 0x40023c18
#define STM32_FLASH_OPTCR2 0x40023c1c
/* FLASH_CR register bits */
#define FLASH_PG (1 << 0)
@@ -152,6 +163,10 @@
#define OPTCR_START (1 << 1)
#define OPTCR_NDBANK (1 << 29) /* not dual bank mode */
#define OPTCR_DB1M (1 << 30) /* 1 MiB devices dual flash bank option */
#define OPTCR_SPRMOD (1 << 31) /* switches PCROPi/nWPRi interpretation */
/* STM32_FLASH_OPTCR2 register bits */
#define OPTCR2_PCROP_RDP (1 << 31) /* erase PCROP zone when decreasing RDP */
/* register unlock keys */
#define KEY1 0x45670123
@@ -166,14 +181,17 @@ struct stm32x_options {
uint16_t user_options; /* bit 0-7 usual options, bit 8-11 extra options */
uint32_t protection;
uint32_t boot_addr;
uint32_t optcr2_pcrop;
};
struct stm32x_flash_bank {
struct stm32x_options option_bytes;
int probed;
bool has_large_mem; /* F42x/43x/469/479/7xx in dual bank mode */
bool has_boot_addr; /* F7xx */
bool has_extra_options; /* F42x/43x/469/479/7xx */
bool has_boot_addr; /* F7xx */
bool has_optcr2_pcrop; /* F72x/73x */
int protection_bits; /* F413/423 */
uint32_t user_bank_size;
};
@@ -328,11 +346,13 @@ static int stm32x_read_options(struct flash_bank *bank)
* whereas F7 6 bits (IWDG_SW and WWDG_SW) in user_options */
stm32x_info->option_bytes.user_options = optiondata & 0xfc;
stm32x_info->option_bytes.RDP = (optiondata >> 8) & 0xff;
stm32x_info->option_bytes.protection = (optiondata >> 16) & 0xfff;
stm32x_info->option_bytes.protection =
(optiondata >> 16) & (~(0xffff << stm32x_info->protection_bits) & 0xffff);
if (stm32x_info->has_extra_options) {
/* F42x/43x/469/479 and 7xx have up to 4 bits of extra options */
stm32x_info->option_bytes.user_options |= (optiondata >> 20) & 0xf00;
stm32x_info->option_bytes.user_options |= (optiondata >> 20) &
((0xf00 << (stm32x_info->protection_bits - 12)) & 0xf00);
}
if (stm32x_info->has_large_mem || stm32x_info->has_boot_addr) {
@@ -350,6 +370,20 @@ static int stm32x_read_options(struct flash_bank *bank)
}
}
if (stm32x_info->has_optcr2_pcrop) {
retval = target_read_u32(target, STM32_FLASH_OPTCR2, &optiondata);
if (retval != ERROR_OK)
return retval;
stm32x_info->option_bytes.optcr2_pcrop = optiondata;
if (stm32x_info->has_optcr2_pcrop &&
(stm32x_info->option_bytes.optcr2_pcrop & ~OPTCR2_PCROP_RDP)) {
LOG_INFO("PCROP Engaged");
}
} else {
stm32x_info->option_bytes.optcr2_pcrop = 0x0;
}
if (stm32x_info->option_bytes.RDP != 0xAA)
LOG_INFO("Device Security Bit Set");
@@ -371,11 +405,13 @@ static int stm32x_write_options(struct flash_bank *bank)
/* rebuild option data */
optiondata = stm32x_info->option_bytes.user_options & 0xfc;
optiondata |= stm32x_info->option_bytes.RDP << 8;
optiondata |= (stm32x_info->option_bytes.protection & 0x0fff) << 16;
optiondata |= (stm32x_info->option_bytes.protection &
(~(0xffff << stm32x_info->protection_bits))) << 16;
if (stm32x_info->has_extra_options) {
/* F42x/43x/469/479 and 7xx have up to 4 bits of extra options */
optiondata |= (stm32x_info->option_bytes.user_options & 0xf00) << 20;
optiondata |= (stm32x_info->option_bytes.user_options &
((0xf00 << (stm32x_info->protection_bits - 12)) & 0xf00)) << 20;
}
if (stm32x_info->has_large_mem || stm32x_info->has_boot_addr) {
@@ -392,6 +428,14 @@ static int stm32x_write_options(struct flash_bank *bank)
return retval;
}
/* program extra pcrop register */
if (stm32x_info->has_optcr2_pcrop) {
retval = target_write_u32(target, STM32_FLASH_OPTCR2,
stm32x_info->option_bytes.optcr2_pcrop);
if (retval != ERROR_OK)
return retval;
}
/* program options */
retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata);
if (retval != ERROR_OK)
@@ -418,6 +462,8 @@ static int stm32x_write_options(struct flash_bank *bank)
static int stm32x_protect_check(struct flash_bank *bank)
{
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
struct flash_sector *prot_blocks;
int num_prot_blocks;
/* read write protection settings */
int retval = stm32x_read_options(bank);
@@ -426,27 +472,18 @@ static int stm32x_protect_check(struct flash_bank *bank)
return retval;
}
if (stm32x_info->has_boot_addr && stm32x_info->has_large_mem) {
/* F76x/77x: bit k protects sectors 2*k and 2*k+1 */
for (int i = 0; i < (bank->num_sectors >> 1); i++) {
if (stm32x_info->option_bytes.protection & (1 << i)) {
bank->sectors[i << 1].is_protected = 0;
bank->sectors[(i << 1) + 1].is_protected = 0;
} else {
bank->sectors[i << 1].is_protected = 1;
bank->sectors[(i << 1) + 1].is_protected = 1;
}
}
if (bank->prot_blocks) {
num_prot_blocks = bank->num_prot_blocks;
prot_blocks = bank->prot_blocks;
} else {
/* one protection bit per sector */
for (int i = 0; i < bank->num_sectors; i++) {
if (stm32x_info->option_bytes.protection & (1 << i))
bank->sectors[i].is_protected = 0;
else
bank->sectors[i].is_protected = 1;
}
num_prot_blocks = bank->num_sectors;
prot_blocks = bank->sectors;
}
for (int i = 0; i < num_prot_blocks; i++)
prot_blocks[i].is_protected =
~(stm32x_info->option_bytes.protection >> i) & 1;
return ERROR_OK;
}
@@ -515,17 +552,6 @@ static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
return retval;
}
if (stm32x_info->has_boot_addr && stm32x_info->has_large_mem) {
/* F76x/77x: bit k protects sectors 2*k and 2*k+1 */
if ((first & 1) != 0 || (last & 1) != 1) {
LOG_ERROR("sector protection must be double sector aligned");
return ERROR_FAIL;
} else {
first >>= 1;
last >>= 1;
}
}
for (int i = first; i <= last; i++) {
if (set)
stm32x_info->option_bytes.protection &= ~(1 << i);
@@ -829,7 +855,7 @@ static int stm32x_probe(struct flash_bank *bank)
{
struct target *target = bank->target;
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
int i;
int i, num_prot_blocks;
uint16_t flash_size_in_kb;
uint32_t flash_size_reg = 0x1FFF7A22;
uint16_t max_sector_size_in_kb = 128;
@@ -841,15 +867,31 @@ static int stm32x_probe(struct flash_bank *bank)
stm32x_info->has_large_mem = false;
stm32x_info->has_boot_addr = false;
stm32x_info->has_extra_options = false;
stm32x_info->has_optcr2_pcrop = false;
stm32x_info->protection_bits = 12; /* max. number of nWRPi bits (in FLASH_OPTCR !!!) */
num_prot_blocks = 0;
if (bank->sectors) {
free(bank->sectors);
bank->num_sectors = 0;
bank->sectors = NULL;
}
if (bank->prot_blocks) {
free(bank->prot_blocks);
bank->num_prot_blocks = 0;
bank->prot_blocks = NULL;
}
/* read stm32 device id register */
int retval = stm32x_get_device_id(bank, &device_id);
if (retval != ERROR_OK)
return retval;
LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
device_id &= 0xfff; /* only bits 0-11 are used further on */
/* set max flash size depending on family, id taken from AN2606 */
switch (device_id & 0xfff) {
switch (device_id) {
case 0x411: /* F20x/21x */
case 0x413: /* F40x/41x */
max_flash_size_in_kb = 1024;
@@ -892,6 +934,21 @@ static int stm32x_probe(struct flash_bank *bank)
stm32x_info->has_boot_addr = true;
break;
case 0x452: /* F72x/73x */
max_flash_size_in_kb = 512;
flash_size_reg = 0x1FF07A22; /* yes, 0x1FF*0*7A22, not 0x1FF*F*7A22 */
stm32x_info->has_extra_options = true;
stm32x_info->has_boot_addr = true;
stm32x_info->has_optcr2_pcrop = true;
break;
case 0x463: /* F413x/423x */
max_flash_size_in_kb = 1536;
stm32x_info->has_extra_options = true;
stm32x_info->protection_bits = 15;
num_prot_blocks = 15;
break;
default:
LOG_WARNING("Cannot identify target as a STM32 family.");
return ERROR_FAIL;
@@ -920,12 +977,8 @@ static int stm32x_probe(struct flash_bank *bank)
/* did we assign flash size? */
assert(flash_size_in_kb != 0xffff);
/* Devices with > 1024 kiByte always are dual-banked */
if (flash_size_in_kb > 1024)
stm32x_info->has_large_mem = true;
/* F42x/43x/469/479 1024 kiByte devices have a dual bank option */
if ((device_id & 0xfff) == 0x419 || (device_id & 0xfff) == 0x434) {
if ((device_id == 0x419) || (device_id == 0x434)) {
uint32_t optiondata;
retval = target_read_u32(target, STM32_FLASH_OPTCR, &optiondata);
if (retval != ERROR_OK) {
@@ -942,7 +995,7 @@ static int stm32x_probe(struct flash_bank *bank)
}
/* F76x/77x devices have a dual bank option */
if ((device_id & 0xfff) == 0x451) {
if (device_id == 0x451) {
uint32_t optiondata;
retval = target_read_u32(target, STM32_FLASH_OPTCR, &optiondata);
if (retval != ERROR_OK) {
@@ -963,11 +1016,6 @@ static int stm32x_probe(struct flash_bank *bank)
int num_pages = flash_size_in_kb / max_sector_size_in_kb
+ (stm32x_info->has_large_mem ? 8 : 4);
if (bank->sectors) {
free(bank->sectors);
bank->sectors = NULL;
}
bank->base = base_address;
bank->num_sectors = num_pages;
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
@@ -978,15 +1026,44 @@ static int stm32x_probe(struct flash_bank *bank)
bank->size = 0;
LOG_DEBUG("allocated %d sectors", num_pages);
/* F76x/77x in dual bank mode */
if ((device_id == 0x451) && stm32x_info->has_large_mem)
num_prot_blocks = num_pages >> 1;
if (num_prot_blocks) {
bank->prot_blocks = malloc(sizeof(struct flash_sector) * num_prot_blocks);
for (i = 0; i < num_prot_blocks; i++)
bank->prot_blocks[i].is_protected = 0;
LOG_DEBUG("allocated %d prot blocks", num_prot_blocks);
}
if (stm32x_info->has_large_mem) {
/* dual-bank */
setup_bank(bank, 0, flash_size_in_kb >> 1, max_sector_size_in_kb);
setup_bank(bank, num_pages >> 1, flash_size_in_kb >> 1,
max_sector_size_in_kb);
/* F767x/F77x in dual mode, one protection bit refers to two adjacent sectors */
if (device_id == 0x451) {
for (i = 0; i < num_prot_blocks; i++) {
bank->prot_blocks[i].offset = bank->sectors[i << 1].offset;
bank->prot_blocks[i].size = bank->sectors[i << 1].size << 1;
}
}
} else {
/* single-bank */
setup_bank(bank, 0, flash_size_in_kb, max_sector_size_in_kb);
/* F413/F423, sectors 14 and 15 share one common protection bit */
if (device_id == 0x463) {
for (i = 0; i < num_prot_blocks; i++) {
bank->prot_blocks[i].offset = bank->sectors[i].offset;
bank->prot_blocks[i].size = bank->sectors[i].size;
}
bank->prot_blocks[num_prot_blocks - 1].size <<= 1;
}
}
bank->num_prot_blocks = num_prot_blocks;
assert((bank->size >> 10) == flash_size_in_kb);
stm32x_info->probed = 1;
@@ -1107,6 +1184,14 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
case 0x1001:
rev_str = "Z";
break;
case 0x2000:
rev_str = "B";
break;
case 0x3000:
rev_str = "C";
break;
}
break;
@@ -1134,6 +1219,26 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
}
break;
case 0x452:
device_str = "STM32F7[2|3]x";
switch (rev_id) {
case 0x1000:
rev_str = "A";
break;
}
break;
case 0x463:
device_str = "STM32F4[1|2]3";
switch (rev_id) {
case 0x1000:
rev_str = "A";
break;
}
break;
default:
snprintf(buf, buf_size, "Cannot identify target as a STM32F2/4/7\n");
return ERROR_FAIL;
@@ -1164,8 +1269,8 @@ COMMAND_HANDLER(stm32x_handle_lock_command)
target = bank->target;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
LOG_INFO("Target not halted");
/* return ERROR_TARGET_NOT_HALTED; */
}
if (stm32x_read_options(bank) != ERROR_OK) {
@@ -1203,8 +1308,8 @@ COMMAND_HANDLER(stm32x_handle_unlock_command)
target = bank->target;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
LOG_INFO("Target not halted");
/* return ERROR_TARGET_NOT_HALTED; */
}
if (stm32x_read_options(bank) != ERROR_OK) {
@@ -1215,6 +1320,9 @@ COMMAND_HANDLER(stm32x_handle_unlock_command)
/* clear readout protection and complementary option bytes
* this will also force a device unlock if set */
stm32x_info->option_bytes.RDP = 0xAA;
if (stm32x_info->has_optcr2_pcrop) {
stm32x_info->option_bytes.optcr2_pcrop = OPTCR2_PCROP_RDP | (~1 << bank->num_sectors);
}
if (stm32x_write_options(bank) != ERROR_OK) {
command_print(CMD_CTX, "%s failed to unlock device", bank->driver->name);
@@ -1327,8 +1435,12 @@ COMMAND_HANDLER(stm32f2x_handle_options_read_command)
" boot_add0 0x%04X, boot_add1 0x%04X",
stm32x_info->option_bytes.user_options,
boot_addr & 0xffff, (boot_addr & 0xffff0000) >> 16);
if (stm32x_info->has_optcr2_pcrop) {
command_print(CMD_CTX, "stm32f2x optcr2_pcrop 0x%08X",
stm32x_info->option_bytes.optcr2_pcrop);
}
} else {
command_print(CMD_CTX, "stm32f2x user_options 0x%03X,",
command_print(CMD_CTX, "stm32f2x user_options 0x%03X",
stm32x_info->option_bytes.user_options);
}
} else {
@@ -1345,7 +1457,7 @@ COMMAND_HANDLER(stm32f2x_handle_options_write_command)
int retval;
struct flash_bank *bank;
struct stm32x_flash_bank *stm32x_info = NULL;
uint16_t user_options, boot_addr0, boot_addr1;
uint16_t user_options, boot_addr0, boot_addr1, options_mask;
if (CMD_ARGC < 1) {
command_print(CMD_CTX, "stm32f2x options_write <bank> ...");
@@ -1378,9 +1490,11 @@ COMMAND_HANDLER(stm32f2x_handle_options_write_command)
}
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], user_options);
if (user_options & (stm32x_info->has_extra_options ? ~0xffc : ~0xfc)) {
options_mask = !stm32x_info->has_extra_options ? ~0xfc :
~(((0xf00 << (stm32x_info->protection_bits - 12)) | 0xff) & 0xffc);
if (user_options & options_mask) {
command_print(CMD_CTX, "stm32f2x invalid user_options");
return ERROR_COMMAND_SYNTAX_ERROR;
return ERROR_COMMAND_ARGUMENT_INVALID;
}
stm32x_info->option_bytes.user_options = user_options;
@@ -1400,6 +1514,48 @@ COMMAND_HANDLER(stm32f2x_handle_options_write_command)
return retval;
}
COMMAND_HANDLER(stm32f2x_handle_optcr2_write_command)
{
int retval;
struct flash_bank *bank;
struct stm32x_flash_bank *stm32x_info = NULL;
uint32_t optcr2_pcrop;
if (CMD_ARGC != 2) {
command_print(CMD_CTX, "stm32f2x optcr2_write <bank> <optcr2_value>");
return ERROR_COMMAND_SYNTAX_ERROR;
}
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
stm32x_info = bank->driver_priv;
if (!stm32x_info->has_optcr2_pcrop) {
command_print(CMD_CTX, "no optcr2 register");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
command_print(CMD_CTX, "INFO: To disable PCROP, set PCROP_RDP"
" with PCROPi bits STILL SET, then\nlock device and"
" finally unlock it. Clears PCROP and mass erases flash.");
retval = stm32x_read_options(bank);
if (ERROR_OK != retval)
return retval;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], optcr2_pcrop);
stm32x_info->option_bytes.optcr2_pcrop = optcr2_pcrop;
if (stm32x_write_options(bank) != ERROR_OK) {
command_print(CMD_CTX, "stm32f2x failed to write options");
return ERROR_OK;
}
command_print(CMD_CTX, "stm32f2x optcr2_write complete.");
return retval;
}
static const struct command_registration stm32x_exec_command_handlers[] = {
{
.name = "lock",
@@ -1433,9 +1589,17 @@ static const struct command_registration stm32x_exec_command_handlers[] = {
.name = "options_write",
.handler = stm32f2x_handle_options_write_command,
.mode = COMMAND_EXEC,
.usage = "bank_id user_options [ boot_add0 boot_add1]",
.usage = "bank_id user_options [ boot_add0 boot_add1 ]",
.help = "Write option bytes",
},
{
.name = "optcr2_write",
.handler = stm32f2x_handle_optcr2_write_command,
.mode = COMMAND_EXEC,
.usage = "bank_id optcr2",
.help = "Write optcr2 word",
},
COMMAND_REGISTRATION_DONE
};
+5
View File
@@ -790,6 +790,11 @@ static int stm32lx_probe(struct flash_bank *bank)
flash_size_in_kb = 256;
}
/* 0x429 devices only use the lowest 8 bits of the flash size register */
if (retval == ERROR_OK && (device_id & 0xfff) == 0x429) {
flash_size_in_kb &= 0xff;
}
/* Failed reading flash size or flash size invalid (early silicon),
* default to max target family */
if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) {
+86 -27
View File
@@ -583,9 +583,10 @@ COMMAND_HANDLER(handle_flash_write_bank_command)
{
uint32_t offset;
uint8_t *buffer;
size_t length;
struct fileio *fileio;
if (CMD_ARGC != 3)
if (CMD_ARGC < 2 || CMD_ARGC > 3)
return ERROR_COMMAND_SYNTAX_ERROR;
struct duration bench;
@@ -596,7 +597,16 @@ COMMAND_HANDLER(handle_flash_write_bank_command)
if (ERROR_OK != retval)
return retval;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset);
offset = 0;
if (CMD_ARGC > 2)
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset);
if (offset > p->size) {
LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank",
offset);
return ERROR_COMMAND_ARGUMENT_INVALID;
}
if (fileio_open(&fileio, CMD_ARGV[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
return ERROR_FAIL;
@@ -608,20 +618,38 @@ COMMAND_HANDLER(handle_flash_write_bank_command)
return retval;
}
buffer = malloc(filesize);
length = MIN(filesize, p->size - offset);
if (!length) {
LOG_INFO("Nothing to write to flash bank");
fileio_close(fileio);
return ERROR_OK;
}
if (length != filesize)
LOG_INFO("File content exceeds flash bank size. Only writing the "
"first %zu bytes of the file", length);
buffer = malloc(length);
if (buffer == NULL) {
fileio_close(fileio);
LOG_ERROR("Out of memory");
return ERROR_FAIL;
}
size_t buf_cnt;
if (fileio_read(fileio, filesize, buffer, &buf_cnt) != ERROR_OK) {
if (fileio_read(fileio, length, buffer, &buf_cnt) != ERROR_OK) {
free(buffer);
fileio_close(fileio);
return ERROR_FAIL;
}
retval = flash_driver_write(p, buffer, offset, buf_cnt);
if (buf_cnt != length) {
LOG_ERROR("Short read");
free(buffer);
return ERROR_FAIL;
}
retval = flash_driver_write(p, buffer, offset, length);
free(buffer);
buffer = NULL;
@@ -629,8 +657,8 @@ COMMAND_HANDLER(handle_flash_write_bank_command)
if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
command_print(CMD_CTX, "wrote %zu bytes from file %s to flash bank %u"
" at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
filesize, CMD_ARGV[1], p->bank_number, offset,
duration_elapsed(&bench), duration_kbps(&bench, filesize));
length, CMD_ARGV[1], p->bank_number, offset,
duration_elapsed(&bench), duration_kbps(&bench, length));
}
fileio_close(fileio);
@@ -646,7 +674,7 @@ COMMAND_HANDLER(handle_flash_read_bank_command)
uint32_t length;
size_t written;
if (CMD_ARGC != 4)
if (CMD_ARGC < 2 || CMD_ARGC > 4)
return ERROR_COMMAND_SYNTAX_ERROR;
struct duration bench;
@@ -654,11 +682,31 @@ COMMAND_HANDLER(handle_flash_read_bank_command)
struct flash_bank *p;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
if (ERROR_OK != retval)
return retval;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], length);
offset = 0;
if (CMD_ARGC > 2)
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset);
if (offset > p->size) {
LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank",
offset);
return ERROR_COMMAND_ARGUMENT_INVALID;
}
length = p->size - offset;
if (CMD_ARGC > 3)
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], length);
if (offset + length > p->size) {
LOG_ERROR("Length of %" PRIu32 " bytes with offset 0x%8.8" PRIx32
" is out of range of the flash bank", length, offset);
return ERROR_COMMAND_ARGUMENT_INVALID;
}
buffer = malloc(length);
if (buffer == NULL) {
@@ -705,6 +753,7 @@ COMMAND_HANDLER(handle_flash_verify_bank_command)
struct fileio *fileio;
size_t read_cnt;
size_t filesize;
size_t length;
int differ;
if (CMD_ARGC < 2 || CMD_ARGC > 3)
@@ -741,14 +790,26 @@ COMMAND_HANDLER(handle_flash_verify_bank_command)
return retval;
}
buffer_file = malloc(filesize);
length = MIN(filesize, p->size - offset);
if (!length) {
LOG_INFO("Nothing to compare with flash bank");
fileio_close(fileio);
return ERROR_OK;
}
if (length != filesize)
LOG_INFO("File content exceeds flash bank size. Only comparing the "
"first %zu bytes of the file", length);
buffer_file = malloc(length);
if (buffer_file == NULL) {
LOG_ERROR("Out of memory");
fileio_close(fileio);
return ERROR_FAIL;
}
retval = fileio_read(fileio, filesize, buffer_file, &read_cnt);
retval = fileio_read(fileio, length, buffer_file, &read_cnt);
fileio_close(fileio);
if (retval != ERROR_OK) {
LOG_ERROR("File read failure");
@@ -756,20 +817,20 @@ COMMAND_HANDLER(handle_flash_verify_bank_command)
return retval;
}
if (read_cnt != filesize) {
if (read_cnt != length) {
LOG_ERROR("Short read");
free(buffer_file);
return ERROR_FAIL;
}
buffer_flash = malloc(filesize);
buffer_flash = malloc(length);
if (buffer_flash == NULL) {
LOG_ERROR("Out of memory");
free(buffer_file);
return ERROR_FAIL;
}
retval = flash_driver_read(p, buffer_flash, offset, read_cnt);
retval = flash_driver_read(p, buffer_flash, offset, length);
if (retval != ERROR_OK) {
LOG_ERROR("Flash read error");
free(buffer_flash);
@@ -780,15 +841,15 @@ COMMAND_HANDLER(handle_flash_verify_bank_command)
if (duration_measure(&bench) == ERROR_OK)
command_print(CMD_CTX, "read %zd bytes from file %s and flash bank %u"
" at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
read_cnt, CMD_ARGV[1], p->bank_number, offset,
duration_elapsed(&bench), duration_kbps(&bench, read_cnt));
length, CMD_ARGV[1], p->bank_number, offset,
duration_elapsed(&bench), duration_kbps(&bench, length));
differ = memcmp(buffer_file, buffer_flash, read_cnt);
differ = memcmp(buffer_file, buffer_flash, length);
command_print(CMD_CTX, "contents %s", differ ? "differ" : "match");
if (differ) {
uint32_t t;
int diffs = 0;
for (t = 0; t < read_cnt; t++) {
for (t = 0; t < length; t++) {
if (buffer_flash[t] == buffer_file[t])
continue;
command_print(CMD_CTX, "diff %d address 0x%08x. Was 0x%02x instead of 0x%02x",
@@ -908,10 +969,9 @@ static const struct command_registration flash_exec_command_handlers[] = {
.name = "write_bank",
.handler = handle_flash_write_bank_command,
.mode = COMMAND_EXEC,
.usage = "bank_id filename offset",
.help = "Write binary data from file to flash bank, "
"starting at specified byte offset from the "
"beginning of the bank.",
.usage = "bank_id filename [offset]",
.help = "Write binary data from file to flash bank. Allow optional "
"offset from beginning of the bank (defaults to zero).",
},
{
.name = "write_image",
@@ -926,10 +986,9 @@ static const struct command_registration flash_exec_command_handlers[] = {
.name = "read_bank",
.handler = handle_flash_read_bank_command,
.mode = COMMAND_EXEC,
.usage = "bank_id filename offset length",
.help = "Read binary data from flash bank to file, "
"starting at specified byte offset from the "
"beginning of the bank.",
.usage = "bank_id filename [offset [length]]",
.help = "Read binary data from flash bank to file. Allow optional "
"offset from beginning of the bank (defaults to zero).",
},
{
.name = "verify_bank",
+7 -5
View File
@@ -50,11 +50,12 @@ static int64_t current_time;
static int64_t start;
static const char * const log_strings[5] = {
static const char * const log_strings[6] = {
"User : ",
"Error: ",
"Warn : ", /* want a space after each colon, all same width, colons aligned */
"Info : ",
"Debug: ",
"Debug: "
};
@@ -234,8 +235,8 @@ COMMAND_HANDLER(handle_debug_level_command)
if (CMD_ARGC == 1) {
int new_level;
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], new_level);
if ((new_level > LOG_LVL_DEBUG) || (new_level < LOG_LVL_SILENT)) {
LOG_ERROR("level must be between %d and %d", LOG_LVL_SILENT, LOG_LVL_DEBUG);
if ((new_level > LOG_LVL_DEBUG_IO) || (new_level < LOG_LVL_SILENT)) {
LOG_ERROR("level must be between %d and %d", LOG_LVL_SILENT, LOG_LVL_DEBUG_IO);
return ERROR_COMMAND_SYNTAX_ERROR;
}
debug_level = new_level;
@@ -279,7 +280,8 @@ static struct command_registration log_command_handlers[] = {
.mode = COMMAND_ANY,
.help = "Sets the verbosity level of debugging output. "
"0 shows errors only; 1 adds warnings; "
"2 (default) adds other info; 3 adds debugging.",
"2 (default) adds other info; 3 adds debugging; "
"4 adds extra verbose debugging.",
.usage = "number",
},
COMMAND_REGISTRATION_DONE
@@ -303,7 +305,7 @@ void log_init(void)
int retval = parse_int(debug_env, &value);
if (ERROR_OK == retval &&
debug_level >= LOG_LVL_SILENT &&
debug_level <= LOG_LVL_DEBUG)
debug_level <= LOG_LVL_DEBUG_IO)
debug_level = value;
}
+11 -1
View File
@@ -46,6 +46,7 @@
* LOG_LVL_WARNING - non-fatal errors, that may be resolved later
* LOG_LVL_INFO - state information, etc.
* LOG_LVL_DEBUG - debug statements, execution trace
* LOG_LVL_DEBUG_IO - verbose debug, low-level I/O trace
*/
enum log_levels {
LOG_LVL_SILENT = -3,
@@ -54,7 +55,8 @@ enum log_levels {
LOG_LVL_ERROR = 0,
LOG_LVL_WARNING = 1,
LOG_LVL_INFO = 2,
LOG_LVL_DEBUG = 3
LOG_LVL_DEBUG = 3,
LOG_LVL_DEBUG_IO = 4,
};
void log_printf(enum log_levels level, const char *file, unsigned line,
@@ -102,6 +104,14 @@ extern int debug_level;
#define LOG_LEVEL_IS(FOO) ((debug_level) >= (FOO))
#define LOG_DEBUG_IO(expr ...) \
do { \
if (debug_level >= LOG_LVL_DEBUG_IO) \
log_printf_lf(LOG_LVL_DEBUG, \
__FILE__, __LINE__, __func__, \
expr); \
} while (0)
#define LOG_DEBUG(expr ...) \
do { \
if (debug_level >= LOG_LVL_DEBUG) \
+32 -15
View File
@@ -185,10 +185,11 @@ static void bitbang_stableclocks(int num_cycles)
}
}
static void bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size)
static void bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer,
unsigned scan_size)
{
tap_state_t saved_end_state = tap_get_end_state();
int bit_cnt;
unsigned bit_cnt;
if (!((!ir_scan &&
(tap_get_state() == TAP_DRSHIFT)) ||
@@ -202,8 +203,8 @@ static void bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int
bitbang_end_state(saved_end_state);
}
size_t buffered = 0;
for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) {
int val = 0;
int tms = (bit_cnt == scan_size-1) ? 1 : 0;
int tdi;
int bytec = bit_cnt/8;
@@ -219,16 +220,31 @@ static void bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int
bitbang_interface->write(0, tms, tdi);
if (type != SCAN_OUT)
val = bitbang_interface->read();
if (type != SCAN_OUT) {
if (bitbang_interface->buf_size) {
bitbang_interface->sample();
buffered++;
} else {
int val = bitbang_interface->read();
if (val)
buffer[bytec] |= bcval;
else
buffer[bytec] &= ~bcval;
}
}
bitbang_interface->write(1, tms, tdi);
if (type != SCAN_OUT) {
if (val)
buffer[bytec] |= bcval;
else
buffer[bytec] &= ~bcval;
if (type != SCAN_OUT && bitbang_interface->buf_size &&
(buffered == bitbang_interface->buf_size ||
bit_cnt == scan_size - 1)) {
for (unsigned i = bit_cnt + 1 - buffered; i <= bit_cnt; i++) {
if (bitbang_interface->read_sample())
buffer[i/8] |= 1 << (i % 8);
else
buffer[i/8] &= ~(1 << (i % 8));
}
buffered = 0;
}
}
@@ -309,13 +325,14 @@ int bitbang_execute_queue(void)
bitbang_path_move(cmd->cmd.pathmove);
break;
case JTAG_SCAN:
#ifdef _DEBUG_JTAG_IO_
LOG_DEBUG("%s scan end in %s",
(cmd->cmd.scan->ir_scan) ? "IR" : "DR",
tap_state_name(cmd->cmd.scan->end_state));
#endif
bitbang_end_state(cmd->cmd.scan->end_state);
scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
#ifdef _DEBUG_JTAG_IO_
LOG_DEBUG("%s scan %d bits; end in %s",
(cmd->cmd.scan->ir_scan) ? "IR" : "DR",
scan_size,
tap_state_name(cmd->cmd.scan->end_state));
#endif
type = jtag_scan_type(cmd->cmd.scan);
bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
+17
View File
@@ -27,7 +27,24 @@
struct bitbang_interface {
/* low level callbacks (for bitbang)
*/
/* Either read() or sample()/read_sample() must be implemented. */
/* Sample TDO and return 0 or 1. */
int (*read)(void);
/* The sample functions allow an interface to batch a number of writes and
* sample requests together. Not waiting for a value to come back can
* greatly increase throughput. */
/* The number of TDO samples that can be buffered up before the caller has
* to call read_sample. */
size_t buf_size;
/* Sample TDO and put the result in a buffer. */
void (*sample)(void);
/* Return the next unread value from the buffer. */
int (*read_sample)(void);
/* Set TCK, TMS, and TDI to the given values. */
void (*write)(int tck, int tms, int tdi);
void (*reset)(int trst, int srst);
void (*blink)(int on);
+3 -3
View File
@@ -596,7 +596,7 @@ static int cmsis_dap_swd_run_queue(void)
{
uint8_t *buffer = cmsis_dap_handle->packet_buffer;
LOG_DEBUG("Executing %d queued transactions", pending_transfer_count);
LOG_DEBUG_IO("Executing %d queued transactions", pending_transfer_count);
if (queued_retval != ERROR_OK) {
LOG_DEBUG("Skipping due to previous errors: %d", queued_retval);
@@ -616,7 +616,7 @@ static int cmsis_dap_swd_run_queue(void)
uint8_t cmd = pending_transfers[i].cmd;
uint32_t data = pending_transfers[i].data;
LOG_DEBUG("%s %s reg %x %"PRIx32,
LOG_DEBUG_IO("%s %s reg %x %"PRIx32,
cmd & SWD_CMD_APnDP ? "AP" : "DP",
cmd & SWD_CMD_RnW ? "read" : "write",
(cmd & SWD_CMD_A32) >> 1, data);
@@ -674,7 +674,7 @@ static int cmsis_dap_swd_run_queue(void)
uint32_t tmp = data;
idx += 4;
LOG_DEBUG("Read result: %"PRIx32, data);
LOG_DEBUG_IO("Read result: %"PRIx32, data);
/* Imitate posted AP reads */
if ((pending_transfers[i].cmd & SWD_CMD_APnDP) ||
+3 -38
View File
@@ -430,40 +430,10 @@ static void ftdi_execute_pathmove(struct jtag_command *cmd)
tap_set_end_state(tap_get_state());
}
#ifdef _DEBUG_JTAG_IO_
static void debug_jtag_io_value(const char *prefix, const uint8_t *value,
unsigned int num_bits)
{
if (!value) {
return;
}
char buf[33];
char *bufp = buf;
unsigned int chars = (num_bits + 3) / 4;
for (unsigned int i = 0; i < chars; i++) {
if (i && (i % 32) == 0) {
DEBUG_JTAG_IO(" %s%s", prefix, buf);
bufp = buf;
}
int start_bit = 4 * (chars - i - 1);
sprintf(bufp, "%01x", buf_get_u32(value, start_bit, 4));
bufp++;
}
if (bufp != buf) {
DEBUG_JTAG_IO(" %s%s", prefix, buf);
}
}
#endif
static void ftdi_execute_scan(struct jtag_command *cmd)
{
DEBUG_JTAG_IO("%s type:%d", cmd->cmd.scan->ir_scan ? "IRSCAN" : "DRSCAN",
jtag_scan_type(cmd->cmd.scan));
#ifdef _DEBUG_JTAG_IO_
debug_jtag_io_value(" out=", cmd->cmd.scan->fields->out_value,
cmd->cmd.scan->fields->num_bits);
#endif
/* Make sure there are no trailing fields with num_bits == 0, or the logic below will fail. */
while (cmd->cmd.scan->num_fields > 0
@@ -545,11 +515,6 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
DEBUG_JTAG_IO("%s scan, %i bits, end in %s",
(cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size,
tap_state_name(tap_get_end_state()));
#ifdef _DEBUG_JTAG_IO_
debug_jtag_io_value(" in=", cmd->cmd.scan->fields->in_value,
cmd->cmd.scan->fields->num_bits);
#endif
}
static void ftdi_execute_reset(struct jtag_command *cmd)
@@ -1109,12 +1074,12 @@ static void ftdi_swd_swdio_en(bool enable)
*/
static int ftdi_swd_run_queue(void)
{
LOG_DEBUG("Executing %zu queued transactions", swd_cmd_queue_length);
LOG_DEBUG_IO("Executing %zu queued transactions", swd_cmd_queue_length);
int retval;
struct signal *led = find_signal_by_name("LED");
if (queued_retval != ERROR_OK) {
LOG_DEBUG("Skipping due to previous errors: %d", queued_retval);
LOG_DEBUG_IO("Skipping due to previous errors: %d", queued_retval);
goto skip;
}
@@ -1135,7 +1100,7 @@ static int ftdi_swd_run_queue(void)
for (size_t i = 0; i < swd_cmd_queue_length; i++) {
int ack = buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1, 3);
LOG_DEBUG("%s %s %s reg %X = %08"PRIx32,
LOG_DEBUG_IO("%s %s %s reg %X = %08"PRIx32,
ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
swd_cmd_queue[i].cmd & SWD_CMD_APnDP ? "AP" : "DP",
swd_cmd_queue[i].cmd & SWD_CMD_RnW ? "read" : "write",
+100 -20
View File
@@ -40,8 +40,58 @@
static char *remote_bitbang_host;
static char *remote_bitbang_port;
FILE *remote_bitbang_in;
FILE *remote_bitbang_out;
static FILE *remote_bitbang_in;
static FILE *remote_bitbang_out;
static int remote_bitbang_fd;
/* Circular buffer. When start == end, the buffer is empty. */
static char remote_bitbang_buf[64];
static unsigned remote_bitbang_start;
static unsigned remote_bitbang_end;
static int remote_bitbang_buf_full(void)
{
return remote_bitbang_end ==
((remote_bitbang_start + sizeof(remote_bitbang_buf) - 1) %
sizeof(remote_bitbang_buf));
}
/* Read any incoming data, placing it into the buffer. */
static void remote_bitbang_fill_buf(void)
{
fcntl(remote_bitbang_fd, F_SETFL, O_NONBLOCK);
while (!remote_bitbang_buf_full()) {
unsigned contiguous_available_space;
if (remote_bitbang_end >= remote_bitbang_start) {
contiguous_available_space = sizeof(remote_bitbang_buf) -
remote_bitbang_end;
if (remote_bitbang_start == 0)
contiguous_available_space -= 1;
} else {
contiguous_available_space = remote_bitbang_start -
remote_bitbang_end - 1;
}
ssize_t count = read(remote_bitbang_fd,
remote_bitbang_buf + remote_bitbang_end,
contiguous_available_space);
if (count > 0) {
remote_bitbang_end += count;
// TODO: check for overflow.
if (remote_bitbang_end == sizeof(remote_bitbang_buf)) {
remote_bitbang_end = 0;
}
} else if (count == 0) {
return;
} else if (count < 0) {
if (errno == EAGAIN) {
return;
} else {
REMOTE_BITBANG_RAISE_ERROR("remote_bitbang_fill_buf: %s (%d)",
strerror(errno), errno);
}
}
}
}
static void remote_bitbang_putc(int c)
{
@@ -75,15 +125,8 @@ static int remote_bitbang_quit(void)
return ERROR_OK;
}
/* Get the next read response. */
static int remote_bitbang_rread(void)
static int char_to_int(int c)
{
if (EOF == fflush(remote_bitbang_out)) {
remote_bitbang_quit();
REMOTE_BITBANG_RAISE_ERROR("fflush: %s", strerror(errno));
}
int c = fgetc(remote_bitbang_in);
switch (c) {
case '0':
return 0;
@@ -96,9 +139,42 @@ static int remote_bitbang_rread(void)
}
}
static int remote_bitbang_read(void)
/* Get the next read response. */
static int remote_bitbang_rread(void)
{
if (EOF == fflush(remote_bitbang_out)) {
remote_bitbang_quit();
REMOTE_BITBANG_RAISE_ERROR("fflush: %s", strerror(errno));
}
/* Enable blocking access. */
fcntl(remote_bitbang_fd, F_SETFL, 0);
char c;
ssize_t count = read(remote_bitbang_fd, &c, 1);
if (count == 1) {
return char_to_int(c);
} else {
remote_bitbang_quit();
REMOTE_BITBANG_RAISE_ERROR("read: count=%d, error=%s", (int) count,
strerror(errno));
}
}
static void remote_bitbang_sample(void)
{
remote_bitbang_fill_buf();
assert(!remote_bitbang_buf_full());
remote_bitbang_putc('R');
}
static int remote_bitbang_read_sample(void)
{
if (remote_bitbang_start != remote_bitbang_end) {
int c = remote_bitbang_buf[remote_bitbang_start];
remote_bitbang_start =
(remote_bitbang_start + 1) % sizeof(remote_bitbang_buf);
return char_to_int(c);
}
return remote_bitbang_rread();
}
@@ -121,7 +197,9 @@ static void remote_bitbang_blink(int on)
}
static struct bitbang_interface remote_bitbang_bitbang = {
.read = &remote_bitbang_read,
.buf_size = sizeof(remote_bitbang_buf) - 1,
.sample = &remote_bitbang_sample,
.read_sample = &remote_bitbang_read_sample,
.write = &remote_bitbang_write,
.reset = &remote_bitbang_reset,
.blink = &remote_bitbang_blink,
@@ -199,26 +277,28 @@ static int remote_bitbang_init_unix(void)
static int remote_bitbang_init(void)
{
int fd;
bitbang_interface = &remote_bitbang_bitbang;
remote_bitbang_start = 0;
remote_bitbang_end = 0;
LOG_INFO("Initializing remote_bitbang driver");
if (remote_bitbang_port == NULL)
fd = remote_bitbang_init_unix();
remote_bitbang_fd = remote_bitbang_init_unix();
else
fd = remote_bitbang_init_tcp();
remote_bitbang_fd = remote_bitbang_init_tcp();
if (fd < 0)
return fd;
if (remote_bitbang_fd < 0)
return remote_bitbang_fd;
remote_bitbang_in = fdopen(fd, "r");
remote_bitbang_in = fdopen(remote_bitbang_fd, "r");
if (remote_bitbang_in == NULL) {
LOG_ERROR("fdopen: failed to open read stream");
close(fd);
close(remote_bitbang_fd);
return ERROR_FAIL;
}
remote_bitbang_out = fdopen(fd, "w");
remote_bitbang_out = fdopen(remote_bitbang_fd, "w");
if (remote_bitbang_out == NULL) {
LOG_ERROR("fdopen: failed to open write stream");
fclose(remote_bitbang_in);
+4 -2
View File
@@ -30,7 +30,6 @@ static int riscv_create_rtos(struct target *target)
target->rtos->current_threadid = 1;
target->rtos->current_thread = 1;
riscv_update_threads(target->rtos);
target->rtos->gdb_thread_packet = riscv_gdb_thread_packet;
target->rtos->gdb_v_packet = riscv_gdb_v_packet;
@@ -42,6 +41,8 @@ int riscv_update_threads(struct rtos *rtos)
{
LOG_DEBUG("Updating the RISC-V Hart List");
struct target *target = rtos->target;
/* Figures out how many harts there are on the system. */
int hart_count = riscv_count_harts(rtos->target);
if (rtos->thread_count != hart_count) {
@@ -54,7 +55,8 @@ int riscv_update_threads(struct rtos *rtos)
rtos->thread_details[i].exists = true;
if (asprintf(&rtos->thread_details[i].thread_name_str, "Hart %d", i) < 0)
LOG_ERROR("riscv_update_threads() failed asprintf");
if (asprintf(&rtos->thread_details[i].extra_info_str, "RV64") < 0)
if (asprintf(&rtos->thread_details[i].extra_info_str, "RV%d",
riscv_xlen_of_hart(target, i)) < 0)
LOG_ERROR("riscv_update_threads() failed asprintf");
}
}
+1 -1
View File
@@ -434,7 +434,7 @@ int rtos_get_gdb_reg_list(struct connection *connection)
(target->smp))) { /* in smp several current thread are possible */
char *hex_reg_list;
LOG_INFO("RTOS: getting register list for thread 0x%" PRIx64
LOG_DEBUG("RTOS: getting register list for thread 0x%" PRIx64
", target->rtos->current_thread=0x%" PRIx64 "\r\n",
current_threadid,
target->rtos->current_thread);
+28 -27
View File
@@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2016 by Square, Inc. *
* Copyright (C) 2017 by Square, Inc. *
* Steven Stallion <stallion@squareup.com> *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -20,34 +20,35 @@
#include "config.h"
#endif
#include "rtos.h"
#include "rtos_standard_stackings.h"
#include "target/armv7m.h"
#include <helper/types.h>
#include <rtos/rtos.h>
#include <rtos/rtos_standard_stackings.h>
#include <target/armv7m.h>
static const struct stack_register_offset rtos_uCOS_III_Cortex_M_stack_offsets[ARMV7M_NUM_CORE_REGS] = {
{ 0x20, 32 }, /* r0 */
{ 0x24, 32 }, /* r1 */
{ 0x28, 32 }, /* r2 */
{ 0x2c, 32 }, /* r3 */
{ 0x00, 32 }, /* r4 */
{ 0x04, 32 }, /* r5 */
{ 0x08, 32 }, /* r6 */
{ 0x0c, 32 }, /* r7 */
{ 0x10, 32 }, /* r8 */
{ 0x14, 32 }, /* r9 */
{ 0x18, 32 }, /* r10 */
{ 0x1c, 32 }, /* r11 */
{ 0x30, 32 }, /* r12 */
{ -2, 32 }, /* sp */
{ 0x34, 32 }, /* lr */
{ 0x38, 32 }, /* pc */
{ 0x3c, 32 }, /* xPSR */
static const struct stack_register_offset rtos_uCOS_III_Cortex_M_stack_offsets[] = {
{ 0x20, 32 }, /* r0 */
{ 0x24, 32 }, /* r1 */
{ 0x28, 32 }, /* r2 */
{ 0x2c, 32 }, /* r3 */
{ 0x00, 32 }, /* r4 */
{ 0x04, 32 }, /* r5 */
{ 0x08, 32 }, /* r6 */
{ 0x0c, 32 }, /* r7 */
{ 0x10, 32 }, /* r8 */
{ 0x14, 32 }, /* r9 */
{ 0x18, 32 }, /* r10 */
{ 0x1c, 32 }, /* r11 */
{ 0x30, 32 }, /* r12 */
{ -2, 32 }, /* sp */
{ 0x34, 32 }, /* lr */
{ 0x38, 32 }, /* pc */
{ 0x3c, 32 }, /* xPSR */
};
const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking = {
0x40, /* stack_registers_size */
-1, /* stack_growth_direction */
ARMV7M_NUM_CORE_REGS, /* num_output_registers */
rtos_generic_stack_align8, /* stack_alignment */
rtos_uCOS_III_Cortex_M_stack_offsets /* register_offsets */
0x40, /* stack_registers_size */
-1, /* stack_growth_direction */
ARRAY_SIZE(rtos_uCOS_III_Cortex_M_stack_offsets), /* num_output_registers */
rtos_generic_stack_align8, /* stack_alignment */
rtos_uCOS_III_Cortex_M_stack_offsets /* register_offsets */
};
+2 -2
View File
@@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2016 by Square, Inc. *
* Copyright (C) 2017 by Square, Inc. *
* Steven Stallion <stallion@squareup.com> *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -23,7 +23,7 @@
#include "config.h"
#endif
#include "rtos.h"
#include <rtos/rtos.h>
extern const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking;
+70 -68
View File
@@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2016 by Square, Inc. *
* Copyright (C) 2017 by Square, Inc. *
* Steven Stallion <stallion@squareup.com> *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -20,14 +20,14 @@
#include "config.h"
#endif
#include <helper/log.h>
#include <helper/time_support.h>
#include <jtag/jtag.h>
#include "target/target.h"
#include "target/target_type.h"
#include "rtos.h"
#include "helper/log.h"
#include "helper/types.h"
#include "rtos/rtos_ucos_iii_stackings.h"
#include <helper/types.h>
#include <rtos/rtos.h>
#include <target/target.h>
#include <target/target_type.h>
#include "rtos_ucos_iii_stackings.h"
#ifndef UCOS_III_MAX_STRLEN
#define UCOS_III_MAX_STRLEN 64
@@ -55,18 +55,18 @@ struct uCOS_III_params {
static const struct uCOS_III_params uCOS_III_params_list[] = {
{
"cortex_m", /* target_name */
sizeof(uint32_t), /* pointer_width */
0, /* thread_stack_offset */
0, /* thread_name_offset */
0, /* thread_state_offset */
0, /* thread_priority_offset */
0, /* thread_prev_offset */
0, /* thread_next_offset */
false, /* thread_offsets_updated */
1, /* threadid_start */
"cortex_m", /* target_name */
sizeof(uint32_t), /* pointer_width */
0, /* thread_stack_offset */
0, /* thread_name_offset */
0, /* thread_state_offset */
0, /* thread_priority_offset */
0, /* thread_prev_offset */
0, /* thread_next_offset */
false, /* thread_offsets_updated */
1, /* threadid_start */
&rtos_uCOS_III_Cortex_M_stacking, /* stacking_info */
0, /* num_threads */
0, /* num_threads */
},
};
@@ -159,10 +159,10 @@ static int uCOS_III_find_last_thread_address(struct rtos *rtos, symbol_address_t
symbol_address_t thread_list_address = 0;
retval = target_read_memory(rtos->target,
rtos->symbols[uCOS_III_VAL_OSTaskDbgListPtr].address,
params->pointer_width,
1,
(void *)&thread_list_address);
rtos->symbols[uCOS_III_VAL_OSTaskDbgListPtr].address,
params->pointer_width,
1,
(void *)&thread_list_address);
if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read thread list address");
return retval;
@@ -173,10 +173,10 @@ static int uCOS_III_find_last_thread_address(struct rtos *rtos, symbol_address_t
*thread_address = thread_list_address;
retval = target_read_memory(rtos->target,
thread_list_address + params->thread_next_offset,
params->pointer_width,
1,
(void *)&thread_list_address);
thread_list_address + params->thread_next_offset,
params->pointer_width,
1,
(void *)&thread_list_address);
if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read next thread address");
return retval;
@@ -227,10 +227,10 @@ static int uCOS_III_update_thread_offsets(struct rtos *rtos)
const struct thread_offset_map *thread_offset_map = &thread_offset_maps[i];
int retval = target_read_memory(rtos->target,
rtos->symbols[thread_offset_map->symbol_value].address,
params->pointer_width,
1,
(void *)thread_offset_map->thread_offset);
rtos->symbols[thread_offset_map->symbol_value].address,
params->pointer_width,
1,
(void *)thread_offset_map->thread_offset);
if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read thread offset");
return retval;
@@ -244,7 +244,7 @@ static int uCOS_III_update_thread_offsets(struct rtos *rtos)
static int uCOS_III_detect_rtos(struct target *target)
{
return target->rtos->symbols != NULL &&
target->rtos->symbols[uCOS_III_VAL_OSRunning].address != 0;
target->rtos->symbols[uCOS_III_VAL_OSRunning].address != 0;
}
static int uCOS_III_reset_handler(struct target *target, enum target_reset_mode reset_mode, void *priv)
@@ -263,8 +263,7 @@ static int uCOS_III_create(struct target *target)
for (size_t i = 0; i < ARRAY_SIZE(uCOS_III_params_list); i++)
if (strcmp(uCOS_III_params_list[i].target_name, target->type->name) == 0) {
params = malloc(sizeof(*params) +
UCOS_III_MAX_THREADS * sizeof(*params->threads));
params = malloc(sizeof(*params) + (UCOS_III_MAX_THREADS * sizeof(*params->threads)));
if (params == NULL) {
LOG_ERROR("uCOS-III: out of memory");
return ERROR_FAIL;
@@ -294,13 +293,18 @@ static int uCOS_III_update_threads(struct rtos *rtos)
uint8_t rtos_running;
retval = target_read_u8(rtos->target,
rtos->symbols[uCOS_III_VAL_OSRunning].address,
&rtos_running);
rtos->symbols[uCOS_III_VAL_OSRunning].address,
&rtos_running);
if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read RTOS running");
return retval;
}
if (rtos_running != 1 && rtos_running != 0) {
LOG_ERROR("uCOS-III: invalid RTOS running value");
return ERROR_FAIL;
}
if (!rtos_running) {
rtos->thread_details = calloc(1, sizeof(struct thread_detail));
if (rtos->thread_details == NULL) {
@@ -327,10 +331,10 @@ static int uCOS_III_update_threads(struct rtos *rtos)
symbol_address_t current_thread_address = 0;
retval = target_read_memory(rtos->target,
rtos->symbols[uCOS_III_VAL_OSTCBCurPtr].address,
params->pointer_width,
1,
(void *)&current_thread_address);
rtos->symbols[uCOS_III_VAL_OSTCBCurPtr].address,
params->pointer_width,
1,
(void *)&current_thread_address);
if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read current thread address");
return retval;
@@ -338,8 +342,8 @@ static int uCOS_III_update_threads(struct rtos *rtos)
/* read number of tasks */
retval = target_read_u16(rtos->target,
rtos->symbols[uCOS_III_VAL_OSTaskQty].address,
(void *)&rtos->thread_count);
rtos->symbols[uCOS_III_VAL_OSTaskQty].address,
(void *)&rtos->thread_count);
if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read thread count");
return retval;
@@ -368,9 +372,7 @@ static int uCOS_III_update_threads(struct rtos *rtos)
char thread_str_buffer[UCOS_III_MAX_STRLEN + 1];
/* find or create new threadid */
retval = uCOS_III_find_or_create_thread(rtos,
thread_address,
&thread_detail->threadid);
retval = uCOS_III_find_or_create_thread(rtos, thread_address, &thread_detail->threadid);
if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to find or create thread");
return retval;
@@ -385,19 +387,19 @@ static int uCOS_III_update_threads(struct rtos *rtos)
symbol_address_t thread_name_address = 0;
retval = target_read_memory(rtos->target,
thread_address + params->thread_name_offset,
params->pointer_width,
1,
(void *)&thread_name_address);
thread_address + params->thread_name_offset,
params->pointer_width,
1,
(void *)&thread_name_address);
if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to name address");
return retval;
}
retval = target_read_buffer(rtos->target,
thread_name_address,
sizeof(thread_str_buffer),
(void *)thread_str_buffer);
thread_name_address,
sizeof(thread_str_buffer),
(void *)thread_str_buffer);
if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read thread name");
return retval;
@@ -411,16 +413,16 @@ static int uCOS_III_update_threads(struct rtos *rtos)
uint8_t thread_priority;
retval = target_read_u8(rtos->target,
thread_address + params->thread_state_offset,
&thread_state);
thread_address + params->thread_state_offset,
&thread_state);
if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read thread state");
return retval;
}
retval = target_read_u8(rtos->target,
thread_address + params->thread_priority_offset,
&thread_priority);
thread_address + params->thread_priority_offset,
&thread_priority);
if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read thread priority");
return retval;
@@ -434,15 +436,15 @@ static int uCOS_III_update_threads(struct rtos *rtos)
thread_state_str = "Unknown";
snprintf(thread_str_buffer, sizeof(thread_str_buffer), "State: %s, Priority: %d",
thread_state_str, thread_priority);
thread_state_str, thread_priority);
thread_detail->extra_info_str = strdup(thread_str_buffer);
/* read previous thread address */
retval = target_read_memory(rtos->target,
thread_address + params->thread_prev_offset,
params->pointer_width,
1,
(void *)&thread_address);
thread_address + params->thread_prev_offset,
params->pointer_width,
1,
(void *)&thread_address);
if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read previous thread address");
return retval;
@@ -470,19 +472,19 @@ static int uCOS_III_get_thread_reg_list(struct rtos *rtos, threadid_t threadid,
symbol_address_t stack_address = 0;
retval = target_read_memory(rtos->target,
thread_address + params->thread_stack_offset,
params->pointer_width,
1,
(void *)&stack_address);
thread_address + params->thread_stack_offset,
params->pointer_width,
1,
(void *)&stack_address);
if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read stack address");
return retval;
}
return rtos_generic_stack_read(rtos->target,
params->stacking_info,
stack_address,
hex_reg_list);
params->stacking_info,
stack_address,
hex_reg_list);
}
static int uCOS_III_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+1 -1
View File
@@ -302,7 +302,7 @@ int add_service(char *name,
struct sockaddr_in addr_in;
socklen_t addr_in_size = sizeof(addr_in);
getsockname(c->fd, &addr_in, &addr_in_size);
getsockname(c->fd, (struct sockaddr *)&addr_in, &addr_in_size);
LOG_INFO("Listening on port %d for %s connections",
ntohs(addr_in.sin_port), name);
} else if (c->type == CONNECTION_STDINOUT) {
+2
View File
@@ -17,6 +17,7 @@ static uint32_t load(const struct target *target, unsigned int rd,
return ld(rd, base, offset);
}
assert(0);
return 0; // Silence -Werror=return-type
}
static uint32_t store(const struct target *target, unsigned int src,
@@ -31,6 +32,7 @@ static uint32_t store(const struct target *target, unsigned int src,
return sd(src, base, offset);
}
assert(0);
return 0; // Silence -Werror=return-type
}
#endif
+17 -3
View File
@@ -44,6 +44,13 @@ bool riscv_batch_full(struct riscv_batch *batch)
void riscv_batch_run(struct riscv_batch *batch)
{
if (batch->used_scans == 0) {
LOG_DEBUG("Ignoring empty batch.");
return;
}
keep_alive();
LOG_DEBUG("running a batch of %ld scans", (long)batch->used_scans);
riscv_batch_add_nop(batch);
@@ -96,7 +103,7 @@ size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address)
batch->read_keys[batch->read_keys_used] = batch->used_scans - 1;
LOG_DEBUG("read key %u for batch 0x%p is %u (0x%p)",
(unsigned) batch->read_keys_used, batch, (unsigned) (batch->used_scans - 1),
(uint64_t*)batch->data_in + (batch->used_scans + 1));
batch->data_in + sizeof(uint64_t) * (batch->used_scans + 1));
return batch->read_keys_used++;
}
@@ -105,8 +112,15 @@ uint64_t riscv_batch_get_dmi_read(struct riscv_batch *batch, size_t key)
assert(key < batch->read_keys_used);
size_t index = batch->read_keys[key];
assert(index <= batch->used_scans);
uint64_t *addr = ((uint64_t *)(batch->data_in) + index);
return *addr;
uint8_t *base = batch->data_in + 8 * index;
return base[0] |
((uint64_t) base[1]) << 8 |
((uint64_t) base[2]) << 16 |
((uint64_t) base[3]) << 24 |
((uint64_t) base[4]) << 32 |
((uint64_t) base[5]) << 40 |
((uint64_t) base[6]) << 48 |
((uint64_t) base[7]) << 56;
}
void riscv_batch_add_nop(struct riscv_batch *batch)
+2 -2
View File
@@ -23,8 +23,8 @@ struct riscv_batch {
size_t idle_count;
char *data_out;
char *data_in;
uint8_t *data_out;
uint8_t *data_in;
struct scan_field *fields;
/* In JTAG we scan out the previous value's output when performing a
File diff suppressed because it is too large Load Diff
+2
View File
@@ -1,6 +1,8 @@
#ifndef TARGET__RISCV__GDB_REGS_H
#define TARGET__RISCV__GDB_REGS_H
// gdb's register list is defined in riscv_gdb_reg_names gdb/riscv-tdep.c in
// its source tree. We must interpret the numbers the same here.
enum gdb_regno {
GDB_REGNO_XPR0 = 0,
GDB_REGNO_X0 = GDB_REGNO_XPR0 + 0,
+34 -5
View File
@@ -3,6 +3,7 @@
#endif
#include "target/target.h"
#include "target/register.h"
#include "riscv.h"
#include "program.h"
#include "helper/log.h"
@@ -41,6 +42,8 @@ int riscv_program_init(struct riscv_program *p, struct target *target)
int riscv_program_exec(struct riscv_program *p, struct target *t)
{
keep_alive();
if (riscv_debug_buffer_leave(t, p) != ERROR_OK) {
LOG_ERROR("unable to write program buffer exit code");
return ERROR_FAIL;
@@ -367,7 +370,7 @@ int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno
return riscv_program_insert(p, addi(d, s, u));
}
int riscv_program_fsd(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
int riscv_program_fsx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
{
assert(d >= GDB_REGNO_FPR0);
assert(d <= GDB_REGNO_FPR31);
@@ -376,21 +379,43 @@ int riscv_program_fsd(struct riscv_program *p, enum gdb_regno d, riscv_addr_t ad
: riscv_program_gettemp(p);
if (riscv_program_lah(p, t, addr) != ERROR_OK)
return ERROR_FAIL;
if (riscv_program_insert(p, fsd(d - GDB_REGNO_FPR0, t, riscv_program_gal(p, addr))) != ERROR_OK)
uint32_t instruction;
switch (p->target->reg_cache->reg_list[GDB_REGNO_FPR0].size) {
case 64:
instruction = fsd(d - GDB_REGNO_FPR0, t, riscv_program_gal(p, addr));
break;
case 32:
instruction = fsw(d - GDB_REGNO_FPR0, t, riscv_program_gal(p, addr));
break;
default:
return ERROR_FAIL;
}
if (riscv_program_insert(p, instruction) != ERROR_OK)
return ERROR_FAIL;
riscv_program_puttemp(p, t);
p->writes_memory = true;
return ERROR_OK;
}
int riscv_program_fld(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
int riscv_program_flx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
{
assert(d >= GDB_REGNO_FPR0);
assert(d <= GDB_REGNO_FPR31);
enum gdb_regno t = riscv_program_gah(p, addr) == 0 ? GDB_REGNO_X0 : d;
if (riscv_program_lah(p, t, addr) != ERROR_OK)
return ERROR_FAIL;
if (riscv_program_insert(p, fld(d - GDB_REGNO_FPR0, t, riscv_program_gal(p, addr))) != ERROR_OK)
uint32_t instruction;
switch (p->target->reg_cache->reg_list[GDB_REGNO_FPR0].size) {
case 64:
instruction = fld(d - GDB_REGNO_FPR0, t, riscv_program_gal(p, addr));
break;
case 32:
instruction = flw(d - GDB_REGNO_FPR0, t, riscv_program_gal(p, addr));
break;
default:
return ERROR_FAIL;
}
if (riscv_program_insert(p, instruction) != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK;
}
@@ -453,7 +478,11 @@ riscv_addr_t riscv_program_gah(struct riscv_program *p, riscv_addr_t addr)
riscv_addr_t riscv_program_gal(struct riscv_program *p, riscv_addr_t addr)
{
return ((addr > 0) ? 1 : 0) * (abs(addr) & 0x7FF);
if (addr > 0) {
return (addr & 0x7FF);
} else {
return 0;
}
}
int riscv_program_lah(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
+2 -2
View File
@@ -114,8 +114,8 @@ int riscv_program_ebreak(struct riscv_program *p);
int riscv_program_lui(struct riscv_program *p, enum gdb_regno d, int32_t u);
int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t i);
int riscv_program_fsd(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr);
int riscv_program_fld(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr);
int riscv_program_fsx(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr);
int riscv_program_flx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr);
/* Assembler macros. */
int riscv_program_li(struct riscv_program *p, enum gdb_regno d, riscv_reg_t c);
+45 -56
View File
@@ -21,6 +21,7 @@
#include "helper/time_support.h"
#include "riscv.h"
#include "asm.h"
#include "gdb_regs.h"
/**
* Since almost everything can be accomplish by scanning the dbus register, all
@@ -155,21 +156,6 @@ typedef enum slot {
#define DBUS_ADDRESS_UNKNOWN 0xffff
// gdb's register list is defined in riscv_gdb_reg_names gdb/riscv-tdep.c in
// its source tree. We must interpret the numbers the same here.
enum {
REG_XPR0 = 0,
REG_XPR31 = 31,
REG_PC = 32,
REG_FPR0 = 33,
REG_FPR31 = 64,
REG_CSR0 = 65,
REG_MSTATUS = CSR_MSTATUS + REG_CSR0,
REG_CSR4095 = 4160,
REG_PRIV = 4161,
REG_COUNT
};
#define DRAM_CACHE_SIZE 16
struct trigger {
@@ -269,6 +255,7 @@ static unsigned int slot_offset(const struct target *target, slot_t slot)
LOG_ERROR("slot_offset called with xlen=%d, slot=%d",
riscv_xlen(target), slot);
assert(0);
return 0; // Silence -Werror=return-type
}
static uint32_t load_slot(const struct target *target, unsigned int dest,
@@ -1117,7 +1104,7 @@ static int execute_resume(struct target *target, bool step)
return ERROR_FAIL;
}
struct reg *mstatus_reg = &target->reg_cache->reg_list[REG_MSTATUS];
struct reg *mstatus_reg = &target->reg_cache->reg_list[GDB_REGNO_MSTATUS];
if (mstatus_reg->valid) {
uint64_t mstatus_user = buf_get_u64(mstatus_reg->value, 0, riscv_xlen(target));
if (mstatus_user != info->mstatus_actual) {
@@ -1201,15 +1188,15 @@ static void update_reg_list(struct target *target)
if (info->reg_values) {
free(info->reg_values);
}
info->reg_values = malloc(REG_COUNT * riscv_xlen(target) / 4);
info->reg_values = malloc(GDB_REGNO_COUNT * riscv_xlen(target) / 4);
for (unsigned int i = 0; i < REG_COUNT; i++) {
for (unsigned int i = 0; i < GDB_REGNO_COUNT; i++) {
struct reg *r = &target->reg_cache->reg_list[i];
r->value = info->reg_values + i * riscv_xlen(target) / 4;
if (r->dirty) {
LOG_ERROR("Register %d was dirty. Its value is lost.", i);
}
if (i == REG_PRIV) {
if (i == GDB_REGNO_PRIV) {
r->size = 8;
} else {
r->size = riscv_xlen(target);
@@ -1241,7 +1228,7 @@ static void reg_cache_set(struct target *target, unsigned int number,
static int update_mstatus_actual(struct target *target)
{
struct reg *mstatus_reg = &target->reg_cache->reg_list[REG_MSTATUS];
struct reg *mstatus_reg = &target->reg_cache->reg_list[GDB_REGNO_MSTATUS];
if (mstatus_reg->valid) {
// We previously made it valid.
return ERROR_OK;
@@ -1249,7 +1236,7 @@ static int update_mstatus_actual(struct target *target)
// Force reading the register. In that process mstatus_actual will be
// updated.
return register_get(&target->reg_cache->reg_list[REG_MSTATUS]);
return register_get(&target->reg_cache->reg_list[GDB_REGNO_MSTATUS]);
}
/*** OpenOCD target functions. ***/
@@ -1257,8 +1244,8 @@ static int update_mstatus_actual(struct target *target)
static int register_read(struct target *target, riscv_reg_t *value, int regnum)
{
riscv011_info_t *info = get_info(target);
if (regnum >= REG_CSR0 && regnum <= REG_CSR4095) {
cache_set32(target, 0, csrr(S0, regnum - REG_CSR0));
if (regnum >= GDB_REGNO_CSR0 && regnum <= GDB_REGNO_CSR4095) {
cache_set32(target, 0, csrr(S0, regnum - GDB_REGNO_CSR0));
cache_set_store(target, 1, S0, SLOT0);
cache_set_jump(target, 2);
} else {
@@ -1281,7 +1268,7 @@ static int register_read(struct target *target, riscv_reg_t *value, int regnum)
*value = cache_get(target, SLOT0);
LOG_DEBUG("reg[%d]=0x%" PRIx64, regnum, *value);
if (regnum == REG_MSTATUS) {
if (regnum == GDB_REGNO_MSTATUS) {
info->mstatus_actual = *value;
}
@@ -1296,13 +1283,13 @@ static int register_get(struct reg *reg)
maybe_write_tselect(target);
riscv_reg_t value = ~0;
if (reg->number <= REG_XPR31) {
if (reg->number <= GDB_REGNO_XPR31) {
value = reg_cache_get(target, reg->number);
LOG_DEBUG("%s=0x%" PRIx64, reg->name, reg_cache_get(target, reg->number));
} else if (reg->number == REG_PC) {
} else if (reg->number == GDB_REGNO_PC) {
value = info->dpc;
LOG_DEBUG("%s=0x%" PRIx64 " (cached)", reg->name, info->dpc);
} else if (reg->number >= REG_FPR0 && reg->number <= REG_FPR31) {
} else if (reg->number >= GDB_REGNO_FPR0 && reg->number <= GDB_REGNO_FPR31) {
int result = update_mstatus_actual(target);
if (result != ERROR_OK) {
return result;
@@ -1316,22 +1303,24 @@ static int register_get(struct reg *reg)
}
if (riscv_xlen(target) == 32) {
cache_set32(target, i++, fsw(reg->number - REG_FPR0, 0, DEBUG_RAM_START + 16));
cache_set32(target, i++, fsw(reg->number - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16));
} else {
cache_set32(target, i++, fsd(reg->number - REG_FPR0, 0, DEBUG_RAM_START + 16));
cache_set32(target, i++, fsd(reg->number - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16));
}
cache_set_jump(target, i++);
if (cache_write(target, 4, true) != ERROR_OK) {
return ERROR_FAIL;
}
} else if (reg->number == GDB_REGNO_PRIV) {
value = get_field(info->dcsr, DCSR_PRV);
} else {
if (register_read(target, &value, reg->number) != ERROR_OK)
return ERROR_FAIL;
}
buf_set_u64(reg->value, 0, riscv_xlen(target), value);
if (reg->number == REG_MSTATUS) {
if (reg->number == GDB_REGNO_MSTATUS) {
reg->valid = true;
}
@@ -1354,13 +1343,13 @@ static int register_write(struct target *target, unsigned int number,
cache_set_load(target, 0, S0, SLOT0);
cache_set_store(target, 1, S0, SLOT_LAST);
cache_set_jump(target, 2);
} else if (number <= REG_XPR31) {
cache_set_load(target, 0, number - REG_XPR0, SLOT0);
} else if (number <= GDB_REGNO_XPR31) {
cache_set_load(target, 0, number - GDB_REGNO_XPR0, SLOT0);
cache_set_jump(target, 1);
} else if (number == REG_PC) {
} else if (number == GDB_REGNO_PC) {
info->dpc = value;
return ERROR_OK;
} else if (number >= REG_FPR0 && number <= REG_FPR31) {
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
int result = update_mstatus_actual(target);
if (result != ERROR_OK) {
return result;
@@ -1374,20 +1363,20 @@ static int register_write(struct target *target, unsigned int number,
}
if (riscv_xlen(target) == 32) {
cache_set32(target, i++, flw(number - REG_FPR0, 0, DEBUG_RAM_START + 16));
cache_set32(target, i++, flw(number - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16));
} else {
cache_set32(target, i++, fld(number - REG_FPR0, 0, DEBUG_RAM_START + 16));
cache_set32(target, i++, fld(number - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16));
}
cache_set_jump(target, i++);
} else if (number >= REG_CSR0 && number <= REG_CSR4095) {
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
cache_set_load(target, 0, S0, SLOT0);
cache_set32(target, 1, csrw(S0, number - REG_CSR0));
cache_set32(target, 1, csrw(S0, number - GDB_REGNO_CSR0));
cache_set_jump(target, 2);
if (number == REG_MSTATUS) {
if (number == GDB_REGNO_MSTATUS) {
info->mstatus_actual = value;
}
} else if (number == REG_PRIV) {
} else if (number == GDB_REGNO_PRIV) {
info->dcsr = set_field(info->dcsr, DCSR_PRV, value);
return ERROR_OK;
} else {
@@ -1481,16 +1470,16 @@ static int init_target(struct command_context *cmd_ctx,
target->reg_cache = calloc(1, sizeof(*target->reg_cache));
target->reg_cache->name = "RISC-V registers";
target->reg_cache->num_regs = REG_COUNT;
target->reg_cache->num_regs = GDB_REGNO_COUNT;
target->reg_cache->reg_list = calloc(REG_COUNT, sizeof(struct reg));
target->reg_cache->reg_list = calloc(GDB_REGNO_COUNT, sizeof(struct reg));
const unsigned int max_reg_name_len = 12;
info->reg_names = calloc(1, REG_COUNT * max_reg_name_len);
info->reg_names = calloc(1, GDB_REGNO_COUNT * max_reg_name_len);
char *reg_name = info->reg_names;
info->reg_values = NULL;
for (unsigned int i = 0; i < REG_COUNT; i++) {
for (unsigned int i = 0; i < GDB_REGNO_COUNT; i++) {
struct reg *r = &target->reg_cache->reg_list[i];
r->number = i;
r->caller_save = true;
@@ -1499,22 +1488,22 @@ static int init_target(struct command_context *cmd_ctx,
r->exist = true;
r->type = &riscv_reg_arch_type;
r->arch_info = target;
if (i <= REG_XPR31) {
if (i <= GDB_REGNO_XPR31) {
sprintf(reg_name, "x%d", i);
} else if (i == REG_PC) {
} else if (i == GDB_REGNO_PC) {
sprintf(reg_name, "pc");
} else if (i >= REG_FPR0 && i <= REG_FPR31) {
sprintf(reg_name, "f%d", i - REG_FPR0);
} else if (i >= REG_CSR0 && i <= REG_CSR4095) {
sprintf(reg_name, "csr%d", i - REG_CSR0);
} else if (i == REG_PRIV) {
} else if (i >= GDB_REGNO_FPR0 && i <= GDB_REGNO_FPR31) {
sprintf(reg_name, "f%d", i - GDB_REGNO_FPR0);
} else if (i >= GDB_REGNO_CSR0 && i <= GDB_REGNO_CSR4095) {
sprintf(reg_name, "csr%d", i - GDB_REGNO_CSR0);
} else if (i == GDB_REGNO_PRIV) {
sprintf(reg_name, "priv");
}
if (reg_name[0]) {
r->name = reg_name;
}
reg_name += strlen(reg_name) + 1;
assert(reg_name < info->reg_names + REG_COUNT * max_reg_name_len);
assert(reg_name < info->reg_names + GDB_REGNO_COUNT * max_reg_name_len);
}
return ERROR_OK;
@@ -1579,7 +1568,7 @@ static int step(struct target *target, int current, target_addr_t address,
LOG_WARNING("Asked to resume at 32-bit PC on %d-bit target.",
riscv_xlen(target));
}
int result = register_write(target, REG_PC, address);
int result = register_write(target, GDB_REGNO_PC, address);
if (result != ERROR_OK)
return result;
}
@@ -2006,7 +1995,7 @@ static int riscv011_resume(struct target *target, int current,
LOG_WARNING("Asked to resume at 32-bit PC on %d-bit target.",
riscv_xlen(target));
}
int result = register_write(target, REG_PC, address);
int result = register_write(target, GDB_REGNO_PC, address);
if (result != ERROR_OK)
return result;
}
@@ -2091,7 +2080,7 @@ static int read_memory(struct target *target, target_addr_t address,
cache_write(target, CACHE_NO_READ, false);
riscv011_info_t *info = get_info(target);
const int max_batch_size = 256;
const unsigned max_batch_size = 256;
scans_t *scans = scans_new(target, max_batch_size);
uint32_t result_value = 0x777;
@@ -2252,7 +2241,7 @@ static int write_memory(struct target *target, target_addr_t address,
return ERROR_FAIL;
}
const int max_batch_size = 256;
const unsigned max_batch_size = 256;
scans_t *scans = scans_new(target, max_batch_size);
uint32_t result_value = 0x777;
+214 -200
View File
@@ -63,7 +63,6 @@ static void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a,
static void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a);
static int riscv013_dmi_write_u64_bits(struct target *target);
static void riscv013_fill_dmi_nop_u64(struct target *target, char *buf);
static void riscv013_reset_current_hart(struct target *target);
static int riscv013_test_compliance(struct target *target);
/**
@@ -218,7 +217,7 @@ static void decode_dmi(char *text, unsigned address, unsigned data)
{ DMI_DMSTATUS, DMI_DMSTATUS_ANYHALTED, "anyhalted" },
{ DMI_DMSTATUS, DMI_DMSTATUS_AUTHENTICATED, "authenticated" },
{ DMI_DMSTATUS, DMI_DMSTATUS_AUTHBUSY, "authbusy" },
{ DMI_DMSTATUS, DMI_DMSTATUS_CFGSTRVALID, "cfgstrvalid" },
{ DMI_DMSTATUS, DMI_DMSTATUS_DEVTREEVALID, "devtreevalid" },
{ DMI_DMSTATUS, DMI_DMSTATUS_VERSION, "version" },
{ DMI_ABSTRACTCS, DMI_ABSTRACTCS_PROGSIZE, "progsize" },
@@ -365,17 +364,6 @@ static void increase_dmi_busy_delay(struct target *target)
dtmcontrol_scan(target, DTM_DTMCS_DMIRESET);
}
static void increase_ac_busy_delay(struct target *target)
{
riscv013_info_t *info = get_info(target);
info->ac_busy_delay += info->ac_busy_delay / 10 + 1;
LOG_INFO("dtmcontrol_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d",
info->dtmcontrol_idle, info->dmi_busy_delay,
info->ac_busy_delay);
dtmcontrol_scan(target, DTM_DTMCS_DMIRESET);
}
/**
* exec: If this is set, assume the scan results in an execution, so more
* run-test/idle cycles may be required.
@@ -433,7 +421,6 @@ static uint64_t dmi_read(struct target *target, uint16_t address)
{
select_dmi(target);
uint64_t value;
dmi_status_t status;
uint16_t address_in;
@@ -441,7 +428,7 @@ static uint64_t dmi_read(struct target *target, uint16_t address)
// This first loop ensures that the read request was actually sent
// to the target. Note that if for some reason this stays busy,
// it is actually due to the Previous dmi_read or dmi_write.
// it is actually due to the previous dmi_read or dmi_write.
for (i = 0; i < 256; i++) {
status = dmi_scan(target, NULL, NULL, DMI_OP_READ, address, 0,
false);
@@ -456,14 +443,14 @@ static uint64_t dmi_read(struct target *target, uint16_t address)
}
if (status != DMI_STATUS_SUCCESS) {
LOG_ERROR("Failed read from 0x%x" PRIx64 ", status=%d",
address, status);
LOG_ERROR("Failed read from 0x%x; status=%d", address, status);
abort();
}
// This second loop ensures that we got the read
// data back. Note that NOP can result in a 'busy' result as well, but
// that would be noticed on the next DMI access we do.
uint64_t value;
for (i = 0; i < 256; i++) {
status = dmi_scan(target, &address_in, &value, DMI_OP_NOP, address, 0,
false);
@@ -472,7 +459,7 @@ static uint64_t dmi_read(struct target *target, uint16_t address)
} else if (status == DMI_STATUS_SUCCESS) {
break;
} else {
LOG_ERROR("failed read (NOP) at 0x%x, status=%d\n", address, status);
LOG_ERROR("failed read (NOP) at 0x%x, status=%d", address, status);
break;
}
}
@@ -501,13 +488,13 @@ static void dmi_write(struct target *target, uint16_t address, uint64_t value)
} else if (status == DMI_STATUS_SUCCESS) {
break;
} else {
LOG_ERROR("failed write to 0x%x, status=%d\n", address, status);
LOG_ERROR("failed write to 0x%x, status=%d", address, status);
break;
}
}
if (status != DMI_STATUS_SUCCESS) {
LOG_ERROR("Failed write to 0x%x;, status=%d\n",
LOG_ERROR("Failed write to 0x%x;, status=%d",
address, status);
abort();
}
@@ -522,16 +509,25 @@ static void dmi_write(struct target *target, uint16_t address, uint64_t value)
} else if (status == DMI_STATUS_SUCCESS) {
break;
} else {
LOG_ERROR("failed write (NOP) at 0x%x, status=%d\n", address, status);
LOG_ERROR("failed write (NOP) at 0x%x, status=%d", address, status);
break;
}
}
if (status != DMI_STATUS_SUCCESS) {
LOG_ERROR("failed to write (NOP) 0x%" PRIx64 " to 0x%x; status=%d\n", value, address, status);
LOG_ERROR("failed to write (NOP) 0x%" PRIx64 " to 0x%x; status=%d", value, address, status);
abort();
}
}
static void increase_ac_busy_delay(struct target *target)
{
riscv013_info_t *info = get_info(target);
info->ac_busy_delay += info->ac_busy_delay / 10 + 1;
LOG_INFO("dtmcontrol_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d",
info->dtmcontrol_idle, info->dmi_busy_delay,
info->ac_busy_delay);
}
uint32_t abstract_register_size(unsigned width)
{
switch (width) {
@@ -577,7 +573,7 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs)
errors[info->cmderr], *abstractcs);
}
LOG_ERROR("Timed out after %ds waiting for busy to go low. (abstractcs=0x%x)"
LOG_ERROR("Timed out after %ds waiting for busy to go low (abstractcs=0x%x). "
"Increase the timeout with riscv set_command_timeout_sec.",
riscv_command_timeout_sec,
*abstractcs);
@@ -783,7 +779,7 @@ static int register_write_direct(struct target *target, unsigned number,
if (number <= GDB_REGNO_XPR31) {
riscv_program_lx(&program, number, input);
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
riscv_program_fld(&program, number, input);
riscv_program_flx(&program, number, input);
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
enum gdb_regno temp = riscv_program_gettemp(&program);
riscv_program_lx(&program, temp, input);
@@ -819,7 +815,7 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t
if (number <= GDB_REGNO_XPR31) {
riscv_program_sx(&program, number, output);
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
riscv_program_fsd(&program, number, output);
riscv_program_fsx(&program, number, output);
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
LOG_DEBUG("reading CSR index=0x%03x", number - GDB_REGNO_CSR0);
enum gdb_regno temp = riscv_program_gettemp(&program);
@@ -908,7 +904,6 @@ static int init_target(struct command_context *cmd_ctx,
generic_info->fill_dmi_read_u64 = &riscv013_fill_dmi_read_u64;
generic_info->fill_dmi_nop_u64 = &riscv013_fill_dmi_nop_u64;
generic_info->dmi_write_u64_bits = &riscv013_dmi_write_u64_bits;
generic_info->reset_current_hart = &riscv013_reset_current_hart;
generic_info->test_compliance = &riscv013_test_compliance;
generic_info->version_specific = calloc(1, sizeof(riscv013_info_t));
if (!generic_info->version_specific)
@@ -1148,7 +1143,7 @@ static int examine(struct target *target)
r->xlen[i], r->debug_buffer_addr[i]);
if (riscv_program_gah(&program64, r->debug_buffer_addr[i])) {
LOG_ERROR("This implementation will not work with hart %d with debug_buffer_addr of 0x%lx\n", i,
LOG_ERROR("This implementation will not work with hart %d with debug_buffer_addr of 0x%lx", i,
(long)r->debug_buffer_addr[i]);
abort();
}
@@ -1179,32 +1174,67 @@ static int examine(struct target *target)
LOG_INFO("Examined RISC-V core; found %d harts",
riscv_count_harts(target));
for (int i = 0; i < riscv_count_harts(target); ++i) {
LOG_INFO(" hart %d: XLEN=%d, program buffer at 0x%" PRIx64
", %d triggers", i, r->xlen[i], r->debug_buffer_addr[i],
r->trigger_count[i]);
if (riscv_hart_enabled(target, i)) {
LOG_INFO(" hart %d: XLEN=%d, program buffer at 0x%" PRIx64
", %d triggers", i, r->xlen[i], r->debug_buffer_addr[i],
r->trigger_count[i]);
} else {
LOG_INFO(" hart %d: currently disabled", i);
}
}
return ERROR_OK;
}
static int assert_reset(struct target *target)
{
/*FIXME -- this only works for single-hart.*/
RISCV_INFO(r);
assert(r->current_hartid == 0);
select_dmi(target);
LOG_DEBUG("ASSERTING NDRESET");
uint32_t control = dmi_read(target, DMI_DMCONTROL);
control = set_field(control, DMI_DMCONTROL_NDMRESET, 1);
if (target->reset_halt) {
LOG_DEBUG("TARGET RESET HALT SET, ensuring halt is set during reset.");
control |= DMI_DMCONTROL_HALTREQ;
uint32_t control_base = set_field(0, DMI_DMCONTROL_DMACTIVE, 1);
if (target->rtos) {
// There's only one target, and OpenOCD thinks each hart is a thread.
// We must reset them all.
// TODO: Try to use hasel in dmcontrol
// Set haltreq/resumereq for each hart.
uint32_t control = control_base;
for (int i = 0; i < riscv_count_harts(target); ++i) {
if (!riscv_hart_enabled(target, i))
continue;
control = set_field(control_base, DMI_DMCONTROL_HARTSEL, i);
control = set_field(control, DMI_DMCONTROL_HALTREQ,
target->reset_halt ? 1 : 0);
dmi_write(target, DMI_DMCONTROL, control);
}
// Assert ndmreset
control = set_field(control, DMI_DMCONTROL_NDMRESET, 1);
dmi_write(target, DMI_DMCONTROL, control);
} else {
LOG_DEBUG("TARGET RESET HALT NOT SET");
control &= ~DMI_DMCONTROL_HALTREQ;
// Reset just this hart.
uint32_t control = set_field(control_base, DMI_DMCONTROL_HARTSEL,
r->current_hartid);
control = set_field(control, DMI_DMCONTROL_HALTREQ,
target->reset_halt ? 1 : 0);
control = set_field(control, DMI_DMCONTROL_HARTRESET, 1);
dmi_write(target, DMI_DMCONTROL, control);
// Read back to check if hartreset is supported.
uint32_t rb = dmi_read(target, DMI_DMCONTROL);
if (!get_field(rb, DMI_DMCONTROL_HARTRESET)) {
// Use ndmreset instead. That will reset the entire device, but
// that's probably what OpenOCD wants anyway.
control = set_field(control, DMI_DMCONTROL_HARTRESET, 0);
control = set_field(control, DMI_DMCONTROL_NDMRESET, 1);
dmi_write(target, DMI_DMCONTROL, control);
}
}
dmi_write(target, DMI_DMCONTROL, control);
target->state = TARGET_RESET;
return ERROR_OK;
}
@@ -1215,43 +1245,85 @@ static int deassert_reset(struct target *target)
RISCV013_INFO(info);
select_dmi(target);
/*FIXME -- this only works for Single Hart*/
assert(r->current_hartid == 0);
/*FIXME -- is there bookkeeping we need to do here*/
uint32_t control = dmi_read(target, DMI_DMCONTROL);
LOG_DEBUG("%d", r->current_hartid);
// Clear the reset, but make sure haltreq is still set
if (target->reset_halt) {
control |= DMI_DMCONTROL_HALTREQ;
}
control = set_field(control, DMI_DMCONTROL_NDMRESET, 0);
uint32_t control = 0;
control = set_field(control, DMI_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0);
control = set_field(control, DMI_DMCONTROL_HARTSEL, r->current_hartid);
control = set_field(control, DMI_DMCONTROL_DMACTIVE, 1);
dmi_write(target, DMI_DMCONTROL, control);
uint32_t status;
uint32_t dmstatus;
int dmi_busy_delay = info->dmi_busy_delay;
time_t start = time(NULL);
if (target->reset_halt) {
LOG_DEBUG("DEASSERTING RESET, waiting for hart to be halted.");
LOG_DEBUG("Waiting for hart to be halted.");
do {
status = dmi_read(target, DMI_DMSTATUS);
} while (get_field(status, DMI_DMSTATUS_ALLHALTED) == 0);
} else {
LOG_DEBUG("DEASSERTING RESET, waiting for hart to be running.");
do {
status = dmi_read(target, DMI_DMSTATUS);
if (get_field(status, DMI_DMSTATUS_ANYHALTED) ||
get_field(status, DMI_DMSTATUS_ANYUNAVAIL)) {
LOG_ERROR("Unexpected hart status during reset.");
abort();
dmstatus = dmi_read(target, DMI_DMSTATUS);
if (time(NULL) - start > riscv_reset_timeout_sec) {
LOG_ERROR("Hart didn't halt coming out of reset in %ds; "
"dmstatus=0x%x; "
"Increase the timeout with riscv set_reset_timeout_sec.",
riscv_reset_timeout_sec, dmstatus);
return ERROR_FAIL;
}
} while (get_field(status, DMI_DMSTATUS_ALLRUNNING) == 0);
target->state = TARGET_HALTED;
} while (get_field(dmstatus, DMI_DMSTATUS_ALLHALTED) == 0);
control = set_field(control, DMI_DMCONTROL_HALTREQ, 0);
dmi_write(target, DMI_DMCONTROL, control);
} else {
LOG_DEBUG("Waiting for hart to be running.");
do {
dmstatus = dmi_read(target, DMI_DMSTATUS);
if (get_field(dmstatus, DMI_DMSTATUS_ANYHALTED) ||
get_field(dmstatus, DMI_DMSTATUS_ANYUNAVAIL)) {
LOG_ERROR("Unexpected hart status during reset. dmstatus=0x%x",
dmstatus);
return ERROR_FAIL;
}
if (time(NULL) - start > riscv_reset_timeout_sec) {
LOG_ERROR("Hart didn't run coming out of reset in %ds; "
"dmstatus=0x%x; "
"Increase the timeout with riscv set_reset_timeout_sec.",
riscv_reset_timeout_sec, dmstatus);
return ERROR_FAIL;
}
} while (get_field(dmstatus, DMI_DMSTATUS_ALLRUNNING) == 0);
target->state = TARGET_RUNNING;
}
info->dmi_busy_delay = dmi_busy_delay;
return ERROR_OK;
}
static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size)
{
switch (size) {
case 8:
buffer[7] = value >> 56;
buffer[6] = value >> 48;
buffer[5] = value >> 40;
buffer[4] = value >> 32;
case 4:
buffer[3] = value >> 24;
buffer[2] = value >> 16;
case 2:
buffer[1] = value >> 8;
case 1:
buffer[0] = value;
break;
default:
assert(false);
}
}
/**
* Read the requested memory, taking care to execute every read exactly once,
* even if cmderr=busy is encountered.
*/
static int read_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, uint8_t *buffer)
{
@@ -1277,7 +1349,6 @@ static int read_memory(struct target *target, target_addr_t address,
riscv_addr_t r_addr = riscv_program_alloc_x(&program);
riscv_program_fence(&program);
riscv_program_lx(&program, GDB_REGNO_S0, r_addr);
riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size);
switch (size) {
case 1:
riscv_program_lbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0);
@@ -1292,6 +1363,7 @@ static int read_memory(struct target *target, target_addr_t address,
LOG_ERROR("Unsupported size: %d", size);
return ERROR_FAIL;
}
riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size);
riscv_program_sw(&program, GDB_REGNO_S1, r_data);
riscv_program_sx(&program, GDB_REGNO_S0, r_addr);
@@ -1299,9 +1371,9 @@ static int read_memory(struct target *target, target_addr_t address,
* program execution mechanism. */
switch (riscv_xlen(target)) {
case 64:
riscv_program_write_ram(&program, r_addr + 4, (((riscv_addr_t) address) - size) >> 32);
riscv_program_write_ram(&program, r_addr + 4, ((riscv_addr_t) address) >> 32);
case 32:
riscv_program_write_ram(&program, r_addr, ((riscv_addr_t) address) - size);
riscv_program_write_ram(&program, r_addr, (riscv_addr_t) address);
break;
default:
LOG_ERROR("unknown XLEN %d", riscv_xlen(target));
@@ -1318,26 +1390,8 @@ static int read_memory(struct target *target, target_addr_t address,
return ERROR_FAIL;
}
uint32_t value = riscv_program_read_ram(&program, r_data);
LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", address, value);
switch (size) {
case 1:
buffer[0] = value;
break;
case 2:
buffer[0] = value;
buffer[1] = value >> 8;
break;
case 4:
buffer[0] = value;
buffer[1] = value >> 8;
buffer[2] = value >> 16;
buffer[3] = value >> 24;
break;
default:
LOG_ERROR("unsupported access size: %d", size);
return ERROR_FAIL;
}
// Program has been executed once. d_addr contains address+size, and d_data
// contains *address.
/* The rest of this program is designed to be fast so it reads various
* DMI registers directly. */
@@ -1350,45 +1404,30 @@ static int read_memory(struct target *target, target_addr_t address,
* case we need to back off a bit and try again. There's two
* termination conditions to this loop: a non-BUSY error message, or
* the data was all copied. */
riscv_addr_t cur_addr = 0xbadbeef;
riscv_addr_t cur_addr = riscv_read_debug_buffer_x(target, d_addr);
riscv_addr_t fin_addr = address + (count * size);
riscv_addr_t prev_addr = ((riscv_addr_t) address) - size;
bool first = true;
bool this_is_last_read = false;
LOG_DEBUG("reading until final address 0x%" PRIx64, fin_addr);
while (count > 1 && !this_is_last_read) {
cur_addr = riscv_read_debug_buffer_x(target, d_addr);
LOG_DEBUG("transferring burst starting at address 0x%" TARGET_PRIxADDR
" (previous burst was 0x%" TARGET_PRIxADDR ")", cur_addr,
prev_addr);
assert(first || prev_addr < cur_addr);
first = false;
prev_addr = cur_addr;
riscv_addr_t start = (cur_addr - address) / size;
assert (cur_addr >= address);
while (cur_addr < fin_addr) {
// Invariant:
// d_data contains *addr
// d_addr contains addr + size
unsigned start = (cur_addr - address) / size;
LOG_DEBUG("creating burst to read address 0x%" TARGET_PRIxADDR
" up to 0x%" TARGET_PRIxADDR "; start=0x%d", cur_addr, fin_addr, start);
assert(cur_addr >= address && cur_addr < fin_addr);
struct riscv_batch *batch = riscv_batch_alloc(
target,
32,
info->dmi_busy_delay + info->ac_busy_delay);
size_t reads = 0;
size_t rereads = reads;
for (riscv_addr_t i = start; i < count; ++i) {
if (i == count - 1) {
// don't do actual read in this batch,
// we will do it later after we disable autoexec
//
// this is done to avoid reading more memory than requested
// which in some special cases(like reading stack located
// at the very top of RAM) may cause an exception
this_is_last_read = true;
} else {
size_t const index =
riscv_batch_add_dmi_read(
for (riscv_addr_t addr = cur_addr; addr < fin_addr; addr += size) {
size_t const index =
riscv_batch_add_dmi_read(
batch,
riscv013_debug_buffer_register(target, r_data));
assert(index == reads);
}
assert(index == reads);
reads++;
if (riscv_batch_full(batch))
@@ -1397,26 +1436,21 @@ static int read_memory(struct target *target, target_addr_t address,
riscv_batch_run(batch);
// Note that if the scan resulted in a Busy DMI response, it
// is this read to abstractcs that will cause the dmi_busy_delay
// to be incremented if necessary. The loop condition above
// catches the case where no writes went through at all.
bool retry_batch_transaction = false;
// Wait for the target to finish performing the last abstract command,
// and update our copy of cmderr.
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY))
abstractcs = dmi_read(target, DMI_ABSTRACTCS);
info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR);
switch (info->cmderr) {
case CMDERR_NONE:
LOG_DEBUG("successful (partial?) memory write");
LOG_DEBUG("successful (partial?) memory read");
break;
case CMDERR_BUSY:
LOG_DEBUG("memory write resulted in busy response");
riscv013_clear_abstract_error(target);
LOG_DEBUG("memory read resulted in busy response");
increase_ac_busy_delay(target);
retry_batch_transaction = true;
riscv_batch_free(batch);
riscv013_clear_abstract_error(target);
break;
default:
LOG_ERROR("error when reading memory, abstractcs=0x%08lx", (long)abstractcs);
@@ -1427,51 +1461,45 @@ static int read_memory(struct target *target, target_addr_t address,
riscv_batch_free(batch);
return ERROR_FAIL;
}
if (retry_batch_transaction) continue;
for (size_t i = start; i < start + reads; ++i) {
riscv_addr_t offset = size*i;
riscv_addr_t t_addr = address + offset;
uint8_t *t_buffer = buffer + offset;
// Figure out how far we managed to read.
riscv_addr_t next_addr = riscv_read_debug_buffer_x(target, d_addr);
LOG_DEBUG("Batch read [0x%" TARGET_PRIxADDR ", 0x%" TARGET_PRIxADDR
"); reads=%d", cur_addr, next_addr, (unsigned) reads);
assert(next_addr >= address && next_addr <= fin_addr);
assert(info->cmderr != CMDERR_NONE ||
next_addr == cur_addr + reads * size);
if (this_is_last_read && i == start + reads - 1) {
riscv013_set_autoexec(target, d_data, 0);
// Now read whatever we got out of the batch.
unsigned rereads = 0;
for (riscv_addr_t addr = cur_addr - size; addr < next_addr - size;
addr += size) {
riscv_addr_t offset = addr - address;
uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads);
uint32_t value = get_field(dmi_out, DTM_DMI_DATA);
write_to_buf(buffer + offset, value, size);
// access debug buffer without executing a program - this address logic was taken from program.c
int const off = (r_data - riscv_debug_buffer_addr(program.target)) / sizeof(program.debug_buffer[0]);
value = riscv_read_debug_buffer(target, off);
} else {
uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads);
value = get_field(dmi_out, DTM_DMI_DATA);
}
rereads++;
switch (size) {
case 1:
t_buffer[0] = value;
break;
case 2:
t_buffer[0] = value;
t_buffer[1] = value >> 8;
break;
case 4:
t_buffer[0] = value;
t_buffer[1] = value >> 8;
t_buffer[2] = value >> 16;
t_buffer[3] = value >> 24;
break;
default:
LOG_ERROR("unsupported access size: %d", size);
return ERROR_FAIL;
}
LOG_DEBUG("M[0x%08lx] reads 0x%08x", (long)t_addr, value);
LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", addr, value);
}
riscv_batch_free(batch);
cur_addr = next_addr;
}
riscv013_set_autoexec(target, d_data, 0);
// Read the last word.
// Access debug buffer without executing a program. This
// address logic was taken from program.c.
uint32_t value = riscv013_read_debug_buffer(target, d_data);
riscv_addr_t addr = cur_addr - size;
write_to_buf(buffer + addr - address, value, size);
LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", addr, value);
riscv_set_register(target, GDB_REGNO_S0, s0);
riscv_set_register(target, GDB_REGNO_S1, s1);
return ERROR_OK;
@@ -1692,7 +1720,7 @@ struct target_type riscv013_target =
/*** 0.13-specific implementations of various RISC-V helper functions. ***/
static riscv_reg_t riscv013_get_register(struct target *target, int hid, int rid)
{
LOG_DEBUG("reading register 0x%08x on hart %d", rid, hid);
LOG_DEBUG("reading register %s on hart %d", gdb_regno_name(rid), hid);
riscv_set_current_hartid(target, hid);
@@ -1706,7 +1734,7 @@ static riscv_reg_t riscv013_get_register(struct target *target, int hid, int rid
LOG_DEBUG("read PC from DPC: 0x%016" PRIx64, out);
} else if (rid == GDB_REGNO_PRIV) {
uint64_t dcsr;
register_read_direct(target, &dcsr, CSR_DCSR);
register_read_direct(target, &dcsr, GDB_REGNO_DCSR);
buf_set_u64((unsigned char *)&out, 0, 8, get_field(dcsr, CSR_DCSR_PRV));
} else {
int result = register_read_direct(target, &out, rid);
@@ -1724,7 +1752,8 @@ static riscv_reg_t riscv013_get_register(struct target *target, int hid, int rid
static void riscv013_set_register(struct target *target, int hid, int rid, uint64_t value)
{
LOG_DEBUG("writing register 0x%08x on hart %d", rid, hid);
LOG_DEBUG("writing 0x%" PRIx64 " to register %s on hart %d", value,
gdb_regno_name(rid), hid);
riscv_set_current_hartid(target, hid);
@@ -1739,9 +1768,9 @@ static void riscv013_set_register(struct target *target, int hid, int rid, uint6
assert(value == actual_value);
} else if (rid == GDB_REGNO_PRIV) {
uint64_t dcsr;
register_read_direct(target, &dcsr, CSR_DCSR);
register_read_direct(target, &dcsr, GDB_REGNO_DCSR);
dcsr = set_field(dcsr, CSR_DCSR_PRV, value);
register_write_direct(target, CSR_DCSR, dcsr);
register_write_direct(target, GDB_REGNO_DCSR, dcsr);
} else {
register_write_direct(target, rid, value);
}
@@ -1900,36 +1929,6 @@ int riscv013_dmi_write_u64_bits(struct target *target)
return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH;
}
void riscv013_reset_current_hart(struct target *target)
{
select_dmi(target);
uint32_t control = dmi_read(target, DMI_DMCONTROL);
control = set_field(control, DMI_DMCONTROL_NDMRESET, 1);
control |= DMI_DMCONTROL_HALTREQ;
dmi_write(target, DMI_DMCONTROL, control);
control = set_field(control, DMI_DMCONTROL_NDMRESET, 0);
dmi_write(target, DMI_DMCONTROL, control);
time_t start = time(NULL);
while (1) {
uint32_t dmstatus = dmi_read(target, DMI_DMSTATUS);
if (get_field(dmstatus, DMI_DMSTATUS_ALLHALTED)) {
break;
}
if (time(NULL) - start > riscv_reset_timeout_sec) {
LOG_ERROR("Hart didn't halt coming out of reset in %ds; "
"dmstatus=0x%x"
"Increase the timeout with riscv set_reset_timeout_sec.",
riscv_reset_timeout_sec, dmstatus);
return;
}
}
control &= ~DMI_DMCONTROL_HALTREQ;
dmi_write(target, DMI_DMCONTROL, control);
}
/* Helper Functions. */
static void riscv013_on_step_or_resume(struct target *target, bool step)
@@ -2063,8 +2062,23 @@ int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr)
void riscv013_clear_abstract_error(struct target *target)
{
uint32_t acs = dmi_read(target, DMI_ABSTRACTCS);
dmi_write(target, DMI_ABSTRACTCS, acs);
// Wait for busy to go away.
time_t start = time(NULL);
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) {
abstractcs = dmi_read(target, DMI_ABSTRACTCS);
if (time(NULL) - start > riscv_command_timeout_sec) {
LOG_ERROR("abstractcs.busy is not going low after %d seconds "
"(abstractcs=0x%x). The target is either really slow or "
"broken. You could increase the timeout with riscv "
"set_reset_timeout_sec.",
riscv_command_timeout_sec, abstractcs);
break;
}
}
// Clear the error status.
dmi_write(target, DMI_ABSTRACTCS, abstractcs & DMI_ABSTRACTCS_CMDERR);
}
#define COMPLIANCE_TEST(b, message) { \
+40 -83
View File
@@ -394,31 +394,43 @@ static int add_trigger(struct target *target, struct trigger *trigger)
{
RISCV_INFO(r);
// In RTOS mode, we need to set the same trigger in the same slot on every
// hart, to keep up the illusion that each hart is a thread running on the
// same core.
// Otherwise, we just set the trigger on the one hart this target deals
// with.
riscv_reg_t tselect[RISCV_MAX_HARTS];
int first_hart = -1;
for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) {
if (!riscv_hart_enabled(target, hartid))
continue;
if (first_hart < 0)
first_hart = hartid;
tselect[hartid] = riscv_get_register_on_hart(target, hartid,
GDB_REGNO_TSELECT);
}
assert(first_hart >= 0);
unsigned int i;
for (i = 0; i < r->trigger_count[0]; i++) {
for (i = 0; i < r->trigger_count[first_hart]; i++) {
if (r->trigger_unique_id[i] != -1) {
continue;
}
riscv_set_register_on_hart(target, 0, GDB_REGNO_TSELECT, i);
riscv_set_register_on_hart(target, first_hart, GDB_REGNO_TSELECT, i);
uint64_t tdata1 = riscv_get_register_on_hart(target, 0, GDB_REGNO_TDATA1);
uint64_t tdata1 = riscv_get_register_on_hart(target, first_hart, GDB_REGNO_TDATA1);
int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target)));
int result = ERROR_OK;
for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) {
for (int hartid = first_hart; hartid < riscv_count_harts(target); ++hartid) {
LOG_DEBUG(">>> hartid=%d", hartid);
if (!riscv_hart_enabled(target, hartid))
continue;
if (hartid > 0) {
if (hartid > first_hart) {
riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, i);
}
switch (type) {
@@ -448,14 +460,14 @@ static int add_trigger(struct target *target, struct trigger *trigger)
break;
}
for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) {
for (int hartid = first_hart; hartid < riscv_count_harts(target); ++hartid) {
if (!riscv_hart_enabled(target, hartid))
continue;
riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT,
tselect[hartid]);
}
if (i >= r->trigger_count[0]) {
if (i >= r->trigger_count[first_hart]) {
LOG_ERROR("Couldn't find an available hardware trigger.");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
@@ -507,19 +519,30 @@ static int remove_trigger(struct target *target, struct trigger *trigger)
{
RISCV_INFO(r);
int first_hart = -1;
for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) {
if (!riscv_hart_enabled(target, hartid))
continue;
if (first_hart < 0) {
first_hart = hartid;
break;
}
}
assert(first_hart >= 0);
unsigned int i;
for (i = 0; i < r->trigger_count[0]; i++) {
for (i = 0; i < r->trigger_count[first_hart]; i++) {
if (r->trigger_unique_id[i] == trigger->unique_id) {
break;
}
}
if (i >= r->trigger_count[0]) {
if (i >= r->trigger_count[first_hart]) {
LOG_ERROR("Couldn't find the hardware resources used by hardware "
"trigger.");
return ERROR_FAIL;
}
LOG_DEBUG("Stop using resource %d for bp %d", i, trigger->unique_id);
for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) {
for (int hartid = first_hart; hartid < riscv_count_harts(target); ++hartid) {
if (!riscv_hart_enabled(target, hartid))
continue;
riscv_reg_t tselect = riscv_get_register_on_hart(target, hartid, GDB_REGNO_TSELECT);
@@ -629,7 +652,7 @@ static int riscv_examine(struct target *target)
{
LOG_DEBUG("riscv_examine()");
if (target_was_examined(target)) {
LOG_DEBUG("Target was already examined.\n");
LOG_DEBUG("Target was already examined.");
return ERROR_OK;
}
@@ -676,14 +699,13 @@ static int old_or_new_riscv_halt(struct target *target)
return riscv_openocd_halt(target);
}
static int oldriscv_assert_reset(struct target *target)
static int riscv_assert_reset(struct target *target)
{
LOG_DEBUG("RISCV ASSERT RESET");
struct target_type *tt = get_target_type(target);
return tt->assert_reset(target);
}
static int oldriscv_deassert_reset(struct target *target)
static int riscv_deassert_reset(struct target *target)
{
LOG_DEBUG("RISCV DEASSERT RESET");
struct target_type *tt = get_target_type(target);
@@ -691,24 +713,6 @@ static int oldriscv_deassert_reset(struct target *target)
}
static int old_or_new_riscv_assert_reset(struct target *target)
{
RISCV_INFO(r);
if (r->is_halted == NULL)
return oldriscv_assert_reset(target);
else
return riscv_openocd_assert_reset(target);
}
static int old_or_new_riscv_deassert_reset(struct target *target)
{
RISCV_INFO(r);
if (r->is_halted == NULL)
return oldriscv_deassert_reset(target);
else
return riscv_openocd_deassert_reset(target);
}
static int oldriscv_resume(struct target *target, int current, uint32_t address,
int handle_breakpoints, int debug_execution)
{
@@ -1115,28 +1119,6 @@ int riscv_openocd_step(
return out;
}
int riscv_openocd_assert_reset(struct target *target)
{
LOG_DEBUG("asserting reset for all harts");
int out = riscv_reset_all_harts(target);
if (out != ERROR_OK) {
LOG_ERROR("unable to reset all harts");
return out;
}
return out;
}
int riscv_openocd_deassert_reset(struct target *target)
{
LOG_DEBUG("deasserting reset for all harts");
if (target->reset_halt)
riscv_halt_all_harts(target);
else
riscv_resume_all_harts(target);
return ERROR_OK;
}
/* Command Handlers */
COMMAND_HANDLER(riscv_set_command_timeout_sec) {
@@ -1243,8 +1225,8 @@ struct target_type riscv_target =
.resume = old_or_new_riscv_resume,
.step = old_or_new_riscv_step,
.assert_reset = old_or_new_riscv_assert_reset,
.deassert_reset = old_or_new_riscv_deassert_reset,
.assert_reset = riscv_assert_reset,
.deassert_reset = riscv_deassert_reset,
.read_memory = riscv_read_memory,
.write_memory = riscv_write_memory,
@@ -1341,33 +1323,6 @@ int riscv_resume_one_hart(struct target *target, int hartid)
return ERROR_OK;
}
int riscv_reset_all_harts(struct target *target)
{
for (int i = 0; i < riscv_count_harts(target); ++i) {
if (!riscv_hart_enabled(target, i))
continue;
riscv_reset_one_hart(target, i);
}
riscv_invalidate_register_cache(target);
return ERROR_OK;
}
int riscv_reset_one_hart(struct target *target, int hartid)
{
RISCV_INFO(r);
LOG_DEBUG("resetting hart %d", hartid);
riscv_halt_one_hart(target, hartid);
riscv_set_current_hartid(target, hartid);
r->reset_current_hart(target);
/* At this point the hart must be halted. On platforms that support
* "reset halt" exactly we expect the hart to have been halted before
* executing any instructions, while on older cores it'll just have
* halted quickly. */
return ERROR_OK;
}
int riscv_step_rtos_hart(struct target *target)
{
RISCV_INFO(r);
@@ -1741,6 +1696,8 @@ const char *gdb_regno_name(enum gdb_regno regno)
sprintf(buf, "x%d", regno - GDB_REGNO_XPR0);
} else if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) {
sprintf(buf, "csr%d", regno - GDB_REGNO_CSR0);
} else if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) {
sprintf(buf, "f%d", regno - GDB_REGNO_FPR0);
} else {
sprintf(buf, "gdb_regno_%d", regno);
}
+5 -5
View File
@@ -67,7 +67,9 @@ typedef struct {
unsigned trigger_count[RISCV_MAX_HARTS];
/* For each physical trigger, contains -1 if the hwbp is available, or the
* unique_id of the breakpoint/watchpoint that is using it. */
* unique_id of the breakpoint/watchpoint that is using it.
* Note that in RTOS mode the triggers are the same across all harts the
* target controls, while otherwise only a single hart is controlled. */
int trigger_unique_id[RISCV_MAX_HWBPS];
/* The address of the debug RAM buffer. */
@@ -103,8 +105,8 @@ typedef struct {
void (*fill_dmi_write_u64)(struct target *target, char *buf, int a, uint64_t d);
void (*fill_dmi_read_u64)(struct target *target, char *buf, int a);
void (*fill_dmi_nop_u64)(struct target *target, char *buf);
void (*reset_current_hart)(struct target *target);
int (*test_compliance)(struct target *target);
int (*test_compliance)(struct target *target);
} riscv_info_t;
/* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/
@@ -162,8 +164,6 @@ int riscv_halt_all_harts(struct target *target);
int riscv_halt_one_hart(struct target *target, int hartid);
int riscv_resume_all_harts(struct target *target);
int riscv_resume_one_hart(struct target *target, int hartid);
int riscv_reset_all_harts(struct target *target);
int riscv_reset_one_hart(struct target *target, int hartid);
/* Steps the hart that's currently selected in the RTOS, or if there is no RTOS
* then the only hart. */
+4 -4
View File
@@ -3037,16 +3037,16 @@ static void handle_md_output(struct command_context *cmd_ctx,
const char *value_fmt;
switch (size) {
case 8:
value_fmt = "%16.16llx ";
value_fmt = "%16.16"PRIx64" ";
break;
case 4:
value_fmt = "%8.8x ";
value_fmt = "%8.8"PRIx64" ";
break;
case 2:
value_fmt = "%4.4x ";
value_fmt = "%4.4"PRIx64" ";
break;
case 1:
value_fmt = "%2.2x ";
value_fmt = "%2.2"PRIx64" ";
break;
default:
/* "can't happen", caller checked */