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

compliance_dev
Megan Wachs 2017-10-25 15:41:41 -07:00
commit 1672f9a60d
49 changed files with 2500 additions and 1430 deletions

View File

@ -5,6 +5,7 @@ matrix:
include: include:
- os: linux - os: linux
env: BUILD=x86_64-linux-gnu env: BUILD=x86_64-linux-gnu
compiler: gcc
- os: linux - os: linux
env: BUILD=i686-linux-gnu CFLAGS=-m32 env: BUILD=i686-linux-gnu CFLAGS=-m32
@ -12,6 +13,19 @@ matrix:
apt: apt:
packages: packages:
- gcc-multilib - gcc-multilib
compiler: gcc
- os: linux
env: BUILD=x86_64-linux-gnu
compiler: clang
- os: linux
env: BUILD=i686-linux-gnu CFLAGS=-m32
compiler: clang
addons:
apt:
packages:
- gcc-multilib
script: script:
- ./bootstrap && ./configure && make - ./bootstrap && ./configure && make

View File

@ -6,7 +6,7 @@ ARM_OBJCOPY ?= $(ARM_CROSS_COMPILE)objcopy
ARM_AFLAGS = -EL -mthumb ARM_AFLAGS = -EL -mthumb
arm: armv7m_kinetis_wdog.inc arm: armv7m_kinetis_wdog.inc armv7m_kinetis_wdog32.inc
armv7m_%.elf: armv7m_%.s armv7m_%.elf: armv7m_%.s
$(ARM_AS) $(ARM_AFLAGS) $< -o $@ $(ARM_AS) $(ARM_AFLAGS) $< -o $@

View File

@ -1,4 +1,3 @@
/* Autogenerated with ../../../src/helper/bin2char.sh */ /* Autogenerated with ../../../src/helper/bin2char.sh */
0x04,0x4b,0x05,0x4a,0xda,0x81,0x05,0x4a,0xda,0x81,0x01,0x24,0x1a,0x88,0xa2,0x43, 0x04,0x4a,0xc2,0x81,0x04,0x4a,0xc2,0x81,0x01,0x24,0x02,0x88,0xa2,0x43,0x02,0x80,
0x1a,0x80,0x06,0xe0,0x00,0x20,0x05,0x40,0x20,0xc5,0x00,0x00,0x28,0xd9,0x00,0x00, 0x05,0xe0,0x00,0x00,0x20,0xc5,0x00,0x00,0x28,0xd9,0x00,0x00,0x00,0x00,0x00,0xbe,
0x00,0x00,0x00,0xbe,

View File

@ -19,7 +19,9 @@
/* /*
Disable watchdog for Kinetis Kx and KVx Disable watchdog for Kinetis Kx and KVx
Parameters: none Parameters:
r0 ... WDOG base (in)
Used instruction set should work on both Cortex-M4 and M0+ Used instruction set should work on both Cortex-M4 and M0+
*/ */
@ -28,7 +30,6 @@
.cpu cortex-m0 .cpu cortex-m0
.thumb .thumb
WDOG_ADDR = 0x40052000
/* WDOG registers offsets */ /* WDOG registers offsets */
WDOG_STCTRLH = 0 WDOG_STCTRLH = 0
WDOG_UNLOCK = 0x0e WDOG_UNLOCK = 0x0e
@ -39,17 +40,16 @@ WDOG_KEY2 = 0xd928
.thumb_func .thumb_func
start: start:
/* WDOG_UNLOCK = 0xC520 */ /* WDOG_UNLOCK = 0xC520 */
ldr r3, =WDOG_ADDR
ldr r2, =WDOG_KEY1 ldr r2, =WDOG_KEY1
strh r2, [r3, WDOG_UNLOCK] strh r2, [r0, WDOG_UNLOCK]
/* WDOG_UNLOCK = 0xD928 */ /* WDOG_UNLOCK = 0xD928 */
ldr r2, =WDOG_KEY2 ldr r2, =WDOG_KEY2
strh r2, [r3, WDOG_UNLOCK] strh r2, [r0, WDOG_UNLOCK]
/* WDOG_STCTRLH clear bit 0 */ /* WDOG_STCTRLH clear bit 0 */
movs r4, #1 movs r4, #1
ldrh r2, [r3, WDOG_STCTRLH] ldrh r2, [r0, WDOG_STCTRLH]
bics r2, r4 bics r2, r4
strh r2, [r3, WDOG_STCTRLH] strh r2, [r0, WDOG_STCTRLH]
/* OpenOCD checks exit point address. Jump to the very end. */ /* OpenOCD checks exit point address. Jump to the very end. */
b done b done

View File

@ -0,0 +1,5 @@
/* Autogenerated with ../../../src/helper/bin2char.sh */
0x02,0x68,0x08,0x4b,0x1a,0x42,0x08,0x4b,0x01,0xd0,0x43,0x60,0x02,0xe0,0x83,0x80,
0x1b,0x0c,0x83,0x80,0x80,0x24,0xa2,0x43,0x20,0x24,0x22,0x43,0x02,0x60,0x03,0x4b,
0x83,0x60,0x06,0xe0,0x00,0x20,0x00,0x00,0x20,0xc5,0x28,0xd9,0x00,0x04,0x00,0x00,
0x00,0x00,0x00,0xbe,

View File

@ -0,0 +1,81 @@
/***************************************************************************
* Copyright (C) 2017 Tomas Vanek *
* vanekt@fbl.cz *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc. *
***************************************************************************/
/*
Disable watchdog, 32-bit version for newer Kinetis
Parameters:
r0 ... WDOG32 base (in)
Used instruction set should work on both Cortex-M4 and M0+
*/
.text
.syntax unified
.cpu cortex-m0
.thumb
/* WDOG registers offsets */
WDOG_CS = 0
WDOG_CNT = 4
WDOG_TOVAL = 8
WDOG_KEY = 0xd928c520
.thumb_func
start:
/* test WDOG_CS bit CMD32EN */
ldr r2, [r0, WDOG_CS]
ldr r3, =0x2000
tst r2, r3
ldr r3, =WDOG_KEY
beq cmd16
/* WDOG_CNT = key */
str r3, [r0, WDOG_CNT]
b unlocked
cmd16:
/* WDOG_CNT = key, halfword by halfword */
strh r3, [r0, WDOG_CNT]
lsrs r3, r3, #16
strh r3, [r0, WDOG_CNT]
/* WDOG_CS: clear EN bit 7, set UPDATE bit 5 */
unlocked:
movs r4, #0x80
bics r2, r4
movs r4, #0x20
orrs r2, r4
str r2, [r0, WDOG_CS]
/* All active WDOG registers have to be updated, set dummy timeout */
/* WDOG_TOVAL = 0x400 */
ldr r3, =0x400
str r3, [r0, WDOG_TOVAL]
/* OpenOCD checks exit point address. Jump to the very end. */
b done
.pool
/* Avoid padding at .text segment end. Otherwise exit point check fails. */
.skip ( . - start + 2) & 2, 0
done:
bkpt #0
.end

View File

@ -682,7 +682,8 @@ bash$ openocd --help
--version | -v display OpenOCD version --version | -v display OpenOCD version
--file | -f use configuration file <name> --file | -f use configuration file <name>
--search | -s dir to search for config files and scripts --search | -s dir to search for config files and scripts
--debug | -d set debug level <0-3> --debug | -d set debug level to 3
| -d<n> set debug level to <level>
--log_output | -l redirect log output to file <name> --log_output | -l redirect log output to file <name>
--command | -c run <command> --command | -c run <command>
@end verbatim @end verbatim
@ -4715,15 +4716,18 @@ each block, and the specified length must stay within that bank.
@end deffn @end deffn
@comment no current checks for errors if fill blocks touch multiple banks! @comment no current checks for errors if fill blocks touch multiple banks!
@deffn Command {flash write_bank} num filename offset @deffn Command {flash write_bank} num filename [offset]
Write the binary @file{filename} to flash bank @var{num}, Write the binary @file{filename} to flash bank @var{num},
starting at @var{offset} bytes from the beginning of the bank. starting at @var{offset} bytes from the beginning of the bank. If @var{offset}
is omitted, start at the beginning of the flash bank.
The @var{num} parameter is a value shown by @command{flash banks}. The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn @end deffn
@deffn Command {flash read_bank} num filename offset length @deffn Command {flash read_bank} num filename [offset [length]]
Read @var{length} bytes from the flash bank @var{num} starting at @var{offset} Read @var{length} bytes from the flash bank @var{num} starting at @var{offset}
and write the contents to the binary @file{filename}. and write the contents to the binary @file{filename}. If @var{offset} is
omitted, start at the beginning of the flash bank. If @var{length} is omitted,
read the remaining bytes from the flash bank.
The @var{num} parameter is a value shown by @command{flash banks}. The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn @end deffn
@ -5361,15 +5365,28 @@ nor is Chip Erase (only Sector Erase is implemented).}
@deffn {Flash Driver} kinetis @deffn {Flash Driver} kinetis
@cindex kinetis @cindex kinetis
Kx and KLx members of the Kinetis microcontroller family from Freescale include Kx, KLx, KVx and KE1x members of the Kinetis microcontroller family
from NXP (former Freescale) include
internal flash and use ARM Cortex-M0+ or M4 cores. The driver automatically internal flash and use ARM Cortex-M0+ or M4 cores. The driver automatically
recognizes flash size and a number of flash banks (1-4) using the chip recognizes flash size and a number of flash banks (1-4) using the chip
identification register, and autoconfigures itself. identification register, and autoconfigures itself.
Use kinetis_ke driver for KE0x devices.
The @var{kinetis} driver defines option:
@itemize
@item -sim-base @var{addr} ... base of System Integration Module where chip identification resides. Driver tries two known locations if option is omitted.
@end itemize
@example @example
flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME
@end example @end example
@deffn Command {kinetis create_banks}
Configuration command enables automatic creation of additional flash banks
based on real flash layout of device. Banks are created during device probe.
Use 'flash probe 0' to force probe.
@end deffn
@deffn Command {kinetis fcf_source} [protection|write] @deffn Command {kinetis fcf_source} [protection|write]
Select what source is used when writing to a Flash Configuration Field. Select what source is used when writing to a Flash Configuration Field.
@option{protection} mode builds FCF content from protection bits previously @option{protection} mode builds FCF content from protection bits previously
@ -5446,10 +5463,11 @@ Command disables watchdog timer.
@deffn {Flash Driver} kinetis_ke @deffn {Flash Driver} kinetis_ke
@cindex kinetis_ke @cindex kinetis_ke
KE members of the Kinetis microcontroller family from Freescale include KE0x members of the Kinetis microcontroller family from Freescale include
internal flash and use ARM Cortex-M0+. The driver automatically recognizes internal flash and use ARM Cortex-M0+. The driver automatically recognizes
the KE family and sub-family using the chip identification register, and the KE0x sub-family using the chip identification register, and
autoconfigures itself. autoconfigures itself.
Use kinetis (not kinetis_ke) driver for KE1x devices.
@example @example
flash bank $_FLASHNAME kinetis_ke 0 0 0 0 $_TARGETNAME flash bank $_FLASHNAME kinetis_ke 0 0 0 0 $_TARGETNAME
@ -5971,16 +5989,21 @@ The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn @end deffn
@deffn Command {stm32f2x options_read} num @deffn Command {stm32f2x options_read} num
Reads and displays user options and (where implemented) boot_addr0 and boot_addr1. Reads and displays user options and (where implemented) boot_addr0, boot_addr1, optcr2.
The @var{num} parameter is a value shown by @command{flash banks}. The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn @end deffn
@deffn Command {stm32f2x options_write} num user_options boot_addr0 boot_addr1 @deffn Command {stm32f2x options_write} num user_options boot_addr0 boot_addr1
Writes user options and (where implemented) boot_addr0 and boot_addr1 in raw format. Writes user options and (where implemented) boot_addr0 and boot_addr1 in raw format.
Warning: The meaning of the various bits depends on the device, always check datasheet! Warning: The meaning of the various bits depends on the device, always check datasheet!
The @var{num} parameter is a value shown by @command{flash banks}, user_options a The @var{num} parameter is a value shown by @command{flash banks}, @var{user_options} a
12 bit value, consisting of bits 31-28 and 7-0 of FLASH_OPTCR, boot_addr0 and boot_addr1 12 bit value, consisting of bits 31-28 and 7-0 of FLASH_OPTCR, @var{boot_addr0} and
two halfwords (of FLASH_OPTCR1). @var{boot_addr1} two halfwords (of FLASH_OPTCR1).
@end deffn
@deffn Command {stm32f2x optcr2_write} num optcr2
Writes FLASH_OPTCR2 options. Warning: Clearing PCROPi bits requires a full mass erase!
The @var{num} parameter is a value shown by @command{flash banks}, @var{optcr2} a 32-bit word.
@end deffn @end deffn
@end deffn @end deffn
@ -6832,12 +6855,13 @@ non-zero exit code to the parent process.
@deffn Command debug_level [n] @deffn Command debug_level [n]
@cindex message level @cindex message level
Display debug level. Display debug level.
If @var{n} (from 0..3) is provided, then set it to that level. If @var{n} (from 0..4) is provided, then set it to that level.
This affects the kind of messages sent to the server log. This affects the kind of messages sent to the server log.
Level 0 is error messages only; Level 0 is error messages only;
level 1 adds warnings; level 1 adds warnings;
level 2 adds informational messages; level 2 adds informational messages;
and level 3 adds debugging messages. level 3 adds debugging messages;
and level 4 adds verbose low-level debug messages.
The default is level 2, but that can be overridden on The default is level 2, but that can be overridden on
the command line along with the location of that log the command line along with the location of that log
file (which is normally the server's standard output). file (which is normally the server's standard output).

View File

@ -22,8 +22,8 @@ NOR_DRIVERS = \
%D%/dsp5680xx_flash.c \ %D%/dsp5680xx_flash.c \
%D%/efm32.c \ %D%/efm32.c \
%D%/em357.c \ %D%/em357.c \
%D%/fespi.c \
%D%/faux.c \ %D%/faux.c \
%D%/fespi.c \
%D%/fm3.c \ %D%/fm3.c \
%D%/fm4.c \ %D%/fm4.c \
%D%/jtagspi.c \ %D%/jtagspi.c \

View File

@ -464,7 +464,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0, .bank_number = 0,
.base_address = FLASH_BANK_BASE_S, .base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00, .controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */ .flash_wait_states = 5,
.present = 1, .present = 1,
.size_bytes = 1024 * 1024, .size_bytes = 1024 * 1024,
.nsectors = 128, .nsectors = 128,
@ -499,7 +499,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0, .bank_number = 0,
.base_address = FLASH_BANK_BASE_S, .base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00, .controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */ .flash_wait_states = 5,
.present = 1, .present = 1,
.size_bytes = 512 * 1024, .size_bytes = 512 * 1024,
.nsectors = 64, .nsectors = 64,
@ -532,7 +532,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0, .bank_number = 0,
.base_address = FLASH_BANK_BASE_S, .base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00, .controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */ .flash_wait_states = 5,
.present = 1, .present = 1,
.size_bytes = 512 * 1024, .size_bytes = 512 * 1024,
.nsectors = 64, .nsectors = 64,
@ -565,7 +565,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0, .bank_number = 0,
.base_address = FLASH_BANK_BASE_S, .base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00, .controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */ .flash_wait_states = 5,
.present = 1, .present = 1,
.size_bytes = 512 * 1024, .size_bytes = 512 * 1024,
.nsectors = 64, .nsectors = 64,
@ -598,7 +598,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0, .bank_number = 0,
.base_address = FLASH_BANK_BASE_S, .base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00, .controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */ .flash_wait_states = 5,
.present = 1, .present = 1,
.size_bytes = 1024 * 1024, .size_bytes = 1024 * 1024,
.nsectors = 128, .nsectors = 128,
@ -631,7 +631,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0, .bank_number = 0,
.base_address = FLASH_BANK_BASE_S, .base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00, .controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */ .flash_wait_states = 5,
.present = 1, .present = 1,
.size_bytes = 1024 * 1024, .size_bytes = 1024 * 1024,
.nsectors = 128, .nsectors = 128,
@ -1279,7 +1279,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0, .bank_number = 0,
.base_address = FLASH_BANK0_BASE_SD, .base_address = FLASH_BANK0_BASE_SD,
.controller_address = 0x400e0a00, .controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */ .flash_wait_states = 5,
.present = 1, .present = 1,
.size_bytes = 512 * 1024, .size_bytes = 512 * 1024,
.nsectors = 64, .nsectors = 64,
@ -1295,7 +1295,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 1, .bank_number = 1,
.base_address = FLASH_BANK1_BASE_1024K_SD, .base_address = FLASH_BANK1_BASE_1024K_SD,
.controller_address = 0x400e0c00, .controller_address = 0x400e0c00,
.flash_wait_states = 6, /* workaround silicon bug */ .flash_wait_states = 5,
.present = 1, .present = 1,
.size_bytes = 512 * 1024, .size_bytes = 512 * 1024,
.nsectors = 64, .nsectors = 64,
@ -1305,10 +1305,10 @@ static const struct sam4_chip_details all_sam4_details[] = {
}, },
}, },
/* at91samg53n19 */ /* atsamg53n19 */
{ {
.chipid_cidr = 0x247e0ae0, .chipid_cidr = 0x247e0ae0,
.name = "at91samg53n19", .name = "atsamg53n19",
.total_flash_size = 512 * 1024, .total_flash_size = 512 * 1024,
.total_sram_size = 96 * 1024, .total_sram_size = 96 * 1024,
.n_gpnvms = 2, .n_gpnvms = 2,
@ -1323,7 +1323,7 @@ static const struct sam4_chip_details all_sam4_details[] = {
.bank_number = 0, .bank_number = 0,
.base_address = FLASH_BANK_BASE_S, .base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00, .controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */ .flash_wait_states = 5,
.present = 1, .present = 1,
.size_bytes = 512 * 1024, .size_bytes = 512 * 1024,
.nsectors = 64, .nsectors = 64,

View File

@ -25,7 +25,7 @@
#include <target/cortex_m.h> #include <target/cortex_m.h>
#define SAMD_NUM_SECTORS 16 #define SAMD_NUM_PROT_BLOCKS 16
#define SAMD_PAGE_SIZE_MAX 1024 #define SAMD_PAGE_SIZE_MAX 1024
#define SAMD_FLASH ((uint32_t)0x00000000) /* physical Flash memory */ #define SAMD_FLASH ((uint32_t)0x00000000) /* physical Flash memory */
@ -286,6 +286,7 @@ struct samd_info {
uint32_t page_size; uint32_t page_size;
int num_pages; int num_pages;
int sector_size; int sector_size;
int prot_block_size;
bool probed; bool probed;
struct target *target; 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) static int samd_protect_check(struct flash_bank *bank)
{ {
int res; int res, prot_block;
uint16_t lock; uint16_t lock;
res = target_read_u16(bank->target, res = target_read_u16(bank->target,
@ -328,8 +329,8 @@ static int samd_protect_check(struct flash_bank *bank)
return res; return res;
/* Lock bits are active-low */ /* Lock bits are active-low */
for (int i = 0; i < bank->num_sectors; i++) for (prot_block = 0; prot_block < bank->num_prot_blocks; prot_block++)
bank->sectors[i].is_protected = !(lock & (1<<i)); bank->prot_blocks[prot_block].is_protected = !(lock & (1u<<prot_block));
return ERROR_OK; return ERROR_OK;
} }
@ -380,8 +381,6 @@ static int samd_probe(struct flash_bank *bank)
bank->size = part->flash_kb * 1024; 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, res = samd_get_flash_page_info(bank->target, &chip->page_size,
&chip->num_pages); &chip->num_pages);
if (res != ERROR_OK) { 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); 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 */ /* Allocate the sector table */
bank->num_sectors = SAMD_NUM_SECTORS; bank->num_sectors = chip->num_pages / 4;
bank->sectors = calloc(bank->num_sectors, sizeof((bank->sectors)[0])); bank->sectors = alloc_block_array(0, chip->sector_size, bank->num_sectors);
if (!bank->sectors) if (!bank->sectors)
return ERROR_FAIL; return ERROR_FAIL;
/* Fill out the sector information: all SAMD sectors are the same size and /* 16 protection blocks per device */
* there is always a fixed number of them. */ chip->prot_block_size = bank->size / SAMD_NUM_PROT_BLOCKS;
for (int i = 0; i < bank->num_sectors; i++) {
bank->sectors[i].size = chip->sector_size; /* Allocate the table of protection blocks */
bank->sectors[i].offset = i * chip->sector_size; bank->num_prot_blocks = SAMD_NUM_PROT_BLOCKS;
/* mark as unknown */ bank->prot_blocks = alloc_block_array(0, chip->prot_block_size, bank->num_prot_blocks);
bank->sectors[i].is_erased = -1; if (!bank->prot_blocks)
bank->sectors[i].is_protected = -1; return ERROR_FAIL;
}
samd_protect_check(bank); samd_protect_check(bank);
@ -606,9 +607,10 @@ out_user_row:
return res; 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 /* 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 * 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; return ERROR_TARGET_NOT_HALTED;
} }
int res = ERROR_OK; for (prot_block = first_prot_bl; prot_block <= last_prot_bl; prot_block++) {
if (set != bank->prot_blocks[prot_block].is_protected) {
for (int s = first; s <= last; s++) { /* Load an address that is within this protection block (we use offset 0) */
if (set != bank->sectors[s].is_protected) {
/* Load an address that is within this sector (we use offset 0) */
res = target_write_u32(bank->target, res = target_write_u32(bank->target,
SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR, SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR,
((s * chip->sector_size) >> 1)); bank->prot_blocks[prot_block].offset >> 1);
if (res != ERROR_OK) if (res != ERROR_OK)
goto exit; goto exit;
/* Tell the controller to lock that sector */ /* Tell the controller to lock that block */
res = samd_issue_nvmctrl_command(bank->target, res = samd_issue_nvmctrl_command(bank->target,
set ? SAMD_NVM_CMD_LR : SAMD_NVM_CMD_UR); set ? SAMD_NVM_CMD_LR : SAMD_NVM_CMD_UR);
if (res != ERROR_OK) 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. */ * locked. See Table 9-3 in the SAMD20 datasheet for more details. */
res = samd_modify_user_row(bank->target, set ? 0x0000 : 0xFFFF, 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) if (res != ERROR_OK)
LOG_WARNING("SAMD: protect settings were not made persistent!"); LOG_WARNING("SAMD: protect settings were not made persistent!");
@ -656,10 +656,9 @@ exit:
return res; 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 res, s;
int rows_in_sector;
struct samd_info *chip = (struct samd_info *)bank->driver_priv; struct samd_info *chip = (struct samd_info *)bank->driver_priv;
if (bank->target->state != TARGET_HALTED) { 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; 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 each sector to be erased */
for (int s = first; s <= last; s++) { for (s = first_sect; s <= last_sect; s++) {
if (bank->sectors[s].is_protected) { res = samd_erase_row(bank->target, bank->sectors[s].offset);
LOG_ERROR("SAMD: failed to erase sector %d. That sector is write-protected", s); if (res != ERROR_OK) {
return ERROR_FLASH_OPERATION_FAILED; LOG_ERROR("SAMD: failed to erase sector %d at 0x%08" PRIx32, s, bank->sectors[s].offset);
} return res;
/* 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;
}
} }
} }

View File

@ -48,6 +48,7 @@
#define EFM_FAMILY_ID_HAPPY_GECKO 77 #define EFM_FAMILY_ID_HAPPY_GECKO 77
#define EZR_FAMILY_ID_WONDER_GECKO 120 #define EZR_FAMILY_ID_WONDER_GECKO 120
#define EZR_FAMILY_ID_LEOPARD_GECKO 121 #define EZR_FAMILY_ID_LEOPARD_GECKO 121
#define EZR_FAMILY_ID_HAPPY_GECKO 122
#define EFM32_FLASH_ERASE_TMO 100 #define EFM32_FLASH_ERASE_TMO 100
#define EFM32_FLASH_WDATAREADY_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) EFM_FAMILY_ID_TINY_GECKO == efm32_info->part_family)
efm32_info->page_size = 512; efm32_info->page_size = 512;
else if (EFM_FAMILY_ID_ZERO_GECKO == efm32_info->part_family || 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; efm32_info->page_size = 1024;
else if (EFM_FAMILY_ID_GIANT_GECKO == efm32_info->part_family || else if (EFM_FAMILY_ID_GIANT_GECKO == efm32_info->part_family ||
EFM_FAMILY_ID_LEOPARD_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) { switch (info->part_family) {
case EZR_FAMILY_ID_WONDER_GECKO: case EZR_FAMILY_ID_WONDER_GECKO:
case EZR_FAMILY_ID_LEOPARD_GECKO: case EZR_FAMILY_ID_LEOPARD_GECKO:
case EZR_FAMILY_ID_HAPPY_GECKO:
printed = snprintf(buf, buf_size, "EZR32 "); printed = snprintf(buf, buf_size, "EZR32 ");
break; break;
default: 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"); printed = snprintf(buf, buf_size, "Zero Gecko");
break; break;
case EFM_FAMILY_ID_HAPPY_GECKO: case EFM_FAMILY_ID_HAPPY_GECKO:
case EZR_FAMILY_ID_HAPPY_GECKO:
printed = snprintf(buf, buf_size, "Happy Gecko"); printed = snprintf(buf, buf_size, "Happy Gecko");
break; break;
} }

File diff suppressed because it is too large Load Diff

View File

@ -59,10 +59,14 @@
* *
* Sector sizes in kiBytes: * Sector sizes in kiBytes:
* 1 MiByte part with 4 x 16, 1 x 64, 7 x 128. * 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. * 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: * 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. * 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] * STM32F7[4|5]
* 1 MiByte part with 4 x 32, 1 x 128, 3 x 256. * 1 MiByte part with 4 x 32, 1 x 128, 3 x 256.
* *
@ -93,6 +97,12 @@
* RM0410 * RM0410
* http://www.st.com/resource/en/reference_manual/dm00224583.pdf * 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 * STM32F1x series - notice that this code was copy, pasted and knocked
* into a stm32f2x driver, so in case something has been converted or * into a stm32f2x driver, so in case something has been converted or
* bugs haven't been fixed, here are the original manuals: * bugs haven't been fixed, here are the original manuals:
@ -121,6 +131,7 @@
#define STM32_FLASH_CR 0x40023c10 #define STM32_FLASH_CR 0x40023c10
#define STM32_FLASH_OPTCR 0x40023c14 #define STM32_FLASH_OPTCR 0x40023c14
#define STM32_FLASH_OPTCR1 0x40023c18 #define STM32_FLASH_OPTCR1 0x40023c18
#define STM32_FLASH_OPTCR2 0x40023c1c
/* FLASH_CR register bits */ /* FLASH_CR register bits */
#define FLASH_PG (1 << 0) #define FLASH_PG (1 << 0)
@ -152,6 +163,10 @@
#define OPTCR_START (1 << 1) #define OPTCR_START (1 << 1)
#define OPTCR_NDBANK (1 << 29) /* not dual bank mode */ #define OPTCR_NDBANK (1 << 29) /* not dual bank mode */
#define OPTCR_DB1M (1 << 30) /* 1 MiB devices dual flash bank option */ #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 */ /* register unlock keys */
#define KEY1 0x45670123 #define KEY1 0x45670123
@ -166,14 +181,17 @@ struct stm32x_options {
uint16_t user_options; /* bit 0-7 usual options, bit 8-11 extra options */ uint16_t user_options; /* bit 0-7 usual options, bit 8-11 extra options */
uint32_t protection; uint32_t protection;
uint32_t boot_addr; uint32_t boot_addr;
uint32_t optcr2_pcrop;
}; };
struct stm32x_flash_bank { struct stm32x_flash_bank {
struct stm32x_options option_bytes; struct stm32x_options option_bytes;
int probed; int probed;
bool has_large_mem; /* F42x/43x/469/479/7xx in dual bank mode */ 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_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; 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 */ * whereas F7 6 bits (IWDG_SW and WWDG_SW) in user_options */
stm32x_info->option_bytes.user_options = optiondata & 0xfc; stm32x_info->option_bytes.user_options = optiondata & 0xfc;
stm32x_info->option_bytes.RDP = (optiondata >> 8) & 0xff; 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) { if (stm32x_info->has_extra_options) {
/* F42x/43x/469/479 and 7xx have up to 4 bits of 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) { 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) if (stm32x_info->option_bytes.RDP != 0xAA)
LOG_INFO("Device Security Bit Set"); LOG_INFO("Device Security Bit Set");
@ -371,11 +405,13 @@ static int stm32x_write_options(struct flash_bank *bank)
/* rebuild option data */ /* rebuild option data */
optiondata = stm32x_info->option_bytes.user_options & 0xfc; optiondata = stm32x_info->option_bytes.user_options & 0xfc;
optiondata |= stm32x_info->option_bytes.RDP << 8; 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) { if (stm32x_info->has_extra_options) {
/* F42x/43x/469/479 and 7xx have up to 4 bits of 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) { 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; 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 */ /* program options */
retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata); retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata);
if (retval != ERROR_OK) 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) static int stm32x_protect_check(struct flash_bank *bank)
{ {
struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
struct flash_sector *prot_blocks;
int num_prot_blocks;
/* read write protection settings */ /* read write protection settings */
int retval = stm32x_read_options(bank); int retval = stm32x_read_options(bank);
@ -426,27 +472,18 @@ static int stm32x_protect_check(struct flash_bank *bank)
return retval; return retval;
} }
if (stm32x_info->has_boot_addr && stm32x_info->has_large_mem) { if (bank->prot_blocks) {
/* F76x/77x: bit k protects sectors 2*k and 2*k+1 */ num_prot_blocks = bank->num_prot_blocks;
for (int i = 0; i < (bank->num_sectors >> 1); i++) { prot_blocks = bank->prot_blocks;
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;
}
}
} else { } else {
/* one protection bit per sector */ num_prot_blocks = bank->num_sectors;
for (int i = 0; i < bank->num_sectors; i++) { prot_blocks = bank->sectors;
if (stm32x_info->option_bytes.protection & (1 << i))
bank->sectors[i].is_protected = 0;
else
bank->sectors[i].is_protected = 1;
}
} }
for (int i = 0; i < num_prot_blocks; i++)
prot_blocks[i].is_protected =
~(stm32x_info->option_bytes.protection >> i) & 1;
return ERROR_OK; return ERROR_OK;
} }
@ -515,17 +552,6 @@ static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
return retval; 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++) { for (int i = first; i <= last; i++) {
if (set) if (set)
stm32x_info->option_bytes.protection &= ~(1 << i); 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 target *target = bank->target;
struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
int i; int i, num_prot_blocks;
uint16_t flash_size_in_kb; uint16_t flash_size_in_kb;
uint32_t flash_size_reg = 0x1FFF7A22; uint32_t flash_size_reg = 0x1FFF7A22;
uint16_t max_sector_size_in_kb = 128; 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_large_mem = false;
stm32x_info->has_boot_addr = false; stm32x_info->has_boot_addr = false;
stm32x_info->has_extra_options = 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 */ /* read stm32 device id register */
int retval = stm32x_get_device_id(bank, &device_id); int retval = stm32x_get_device_id(bank, &device_id);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
LOG_INFO("device id = 0x%08" PRIx32 "", device_id); 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 */ /* set max flash size depending on family, id taken from AN2606 */
switch (device_id & 0xfff) { switch (device_id) {
case 0x411: /* F20x/21x */ case 0x411: /* F20x/21x */
case 0x413: /* F40x/41x */ case 0x413: /* F40x/41x */
max_flash_size_in_kb = 1024; max_flash_size_in_kb = 1024;
@ -892,6 +934,21 @@ static int stm32x_probe(struct flash_bank *bank)
stm32x_info->has_boot_addr = true; stm32x_info->has_boot_addr = true;
break; 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: default:
LOG_WARNING("Cannot identify target as a STM32 family."); LOG_WARNING("Cannot identify target as a STM32 family.");
return ERROR_FAIL; return ERROR_FAIL;
@ -920,12 +977,8 @@ static int stm32x_probe(struct flash_bank *bank)
/* did we assign flash size? */ /* did we assign flash size? */
assert(flash_size_in_kb != 0xffff); 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 */ /* 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; uint32_t optiondata;
retval = target_read_u32(target, STM32_FLASH_OPTCR, &optiondata); retval = target_read_u32(target, STM32_FLASH_OPTCR, &optiondata);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
@ -942,7 +995,7 @@ static int stm32x_probe(struct flash_bank *bank)
} }
/* F76x/77x devices have a dual bank option */ /* F76x/77x devices have a dual bank option */
if ((device_id & 0xfff) == 0x451) { if (device_id == 0x451) {
uint32_t optiondata; uint32_t optiondata;
retval = target_read_u32(target, STM32_FLASH_OPTCR, &optiondata); retval = target_read_u32(target, STM32_FLASH_OPTCR, &optiondata);
if (retval != ERROR_OK) { 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 int num_pages = flash_size_in_kb / max_sector_size_in_kb
+ (stm32x_info->has_large_mem ? 8 : 4); + (stm32x_info->has_large_mem ? 8 : 4);
if (bank->sectors) {
free(bank->sectors);
bank->sectors = NULL;
}
bank->base = base_address; bank->base = base_address;
bank->num_sectors = num_pages; bank->num_sectors = num_pages;
bank->sectors = malloc(sizeof(struct flash_sector) * 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; bank->size = 0;
LOG_DEBUG("allocated %d sectors", num_pages); 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) { if (stm32x_info->has_large_mem) {
/* dual-bank */ /* dual-bank */
setup_bank(bank, 0, flash_size_in_kb >> 1, max_sector_size_in_kb); 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, setup_bank(bank, num_pages >> 1, flash_size_in_kb >> 1,
max_sector_size_in_kb); 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 { } else {
/* single-bank */ /* single-bank */
setup_bank(bank, 0, flash_size_in_kb, max_sector_size_in_kb); 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); assert((bank->size >> 10) == flash_size_in_kb);
stm32x_info->probed = 1; stm32x_info->probed = 1;
@ -1107,6 +1184,14 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
case 0x1001: case 0x1001:
rev_str = "Z"; rev_str = "Z";
break; break;
case 0x2000:
rev_str = "B";
break;
case 0x3000:
rev_str = "C";
break;
} }
break; break;
@ -1134,6 +1219,26 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
} }
break; 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: default:
snprintf(buf, buf_size, "Cannot identify target as a STM32F2/4/7\n"); snprintf(buf, buf_size, "Cannot identify target as a STM32F2/4/7\n");
return ERROR_FAIL; return ERROR_FAIL;
@ -1164,8 +1269,8 @@ COMMAND_HANDLER(stm32x_handle_lock_command)
target = bank->target; target = bank->target;
if (target->state != TARGET_HALTED) { if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted"); LOG_INFO("Target not halted");
return ERROR_TARGET_NOT_HALTED; /* return ERROR_TARGET_NOT_HALTED; */
} }
if (stm32x_read_options(bank) != ERROR_OK) { if (stm32x_read_options(bank) != ERROR_OK) {
@ -1203,8 +1308,8 @@ COMMAND_HANDLER(stm32x_handle_unlock_command)
target = bank->target; target = bank->target;
if (target->state != TARGET_HALTED) { if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted"); LOG_INFO("Target not halted");
return ERROR_TARGET_NOT_HALTED; /* return ERROR_TARGET_NOT_HALTED; */
} }
if (stm32x_read_options(bank) != ERROR_OK) { if (stm32x_read_options(bank) != ERROR_OK) {
@ -1215,6 +1320,9 @@ COMMAND_HANDLER(stm32x_handle_unlock_command)
/* clear readout protection and complementary option bytes /* clear readout protection and complementary option bytes
* this will also force a device unlock if set */ * this will also force a device unlock if set */
stm32x_info->option_bytes.RDP = 0xAA; 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) { if (stm32x_write_options(bank) != ERROR_OK) {
command_print(CMD_CTX, "%s failed to unlock device", bank->driver->name); 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", " boot_add0 0x%04X, boot_add1 0x%04X",
stm32x_info->option_bytes.user_options, stm32x_info->option_bytes.user_options,
boot_addr & 0xffff, (boot_addr & 0xffff0000) >> 16); 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 { } 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); stm32x_info->option_bytes.user_options);
} }
} else { } else {
@ -1345,7 +1457,7 @@ COMMAND_HANDLER(stm32f2x_handle_options_write_command)
int retval; int retval;
struct flash_bank *bank; struct flash_bank *bank;
struct stm32x_flash_bank *stm32x_info = NULL; 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) { if (CMD_ARGC < 1) {
command_print(CMD_CTX, "stm32f2x options_write <bank> ..."); 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); 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"); 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; stm32x_info->option_bytes.user_options = user_options;
@ -1400,6 +1514,48 @@ COMMAND_HANDLER(stm32f2x_handle_options_write_command)
return retval; 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[] = { static const struct command_registration stm32x_exec_command_handlers[] = {
{ {
.name = "lock", .name = "lock",
@ -1433,9 +1589,17 @@ static const struct command_registration stm32x_exec_command_handlers[] = {
.name = "options_write", .name = "options_write",
.handler = stm32f2x_handle_options_write_command, .handler = stm32f2x_handle_options_write_command,
.mode = COMMAND_EXEC, .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", .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 COMMAND_REGISTRATION_DONE
}; };

View File

@ -790,6 +790,11 @@ static int stm32lx_probe(struct flash_bank *bank)
flash_size_in_kb = 256; 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), /* Failed reading flash size or flash size invalid (early silicon),
* default to max target family */ * default to max target family */
if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) { if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) {

View File

@ -583,9 +583,10 @@ COMMAND_HANDLER(handle_flash_write_bank_command)
{ {
uint32_t offset; uint32_t offset;
uint8_t *buffer; uint8_t *buffer;
size_t length;
struct fileio *fileio; struct fileio *fileio;
if (CMD_ARGC != 3) if (CMD_ARGC < 2 || CMD_ARGC > 3)
return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_COMMAND_SYNTAX_ERROR;
struct duration bench; struct duration bench;
@ -596,7 +597,16 @@ COMMAND_HANDLER(handle_flash_write_bank_command)
if (ERROR_OK != retval) if (ERROR_OK != retval)
return 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) if (fileio_open(&fileio, CMD_ARGV[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
@ -608,20 +618,38 @@ COMMAND_HANDLER(handle_flash_write_bank_command)
return retval; 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) { if (buffer == NULL) {
fileio_close(fileio); fileio_close(fileio);
LOG_ERROR("Out of memory"); LOG_ERROR("Out of memory");
return ERROR_FAIL; return ERROR_FAIL;
} }
size_t buf_cnt; 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); free(buffer);
fileio_close(fileio); fileio_close(fileio);
return ERROR_FAIL; 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); free(buffer);
buffer = NULL; buffer = NULL;
@ -629,8 +657,8 @@ COMMAND_HANDLER(handle_flash_write_bank_command)
if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
command_print(CMD_CTX, "wrote %zu bytes from file %s to flash bank %u" 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)", " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
filesize, CMD_ARGV[1], p->bank_number, offset, length, CMD_ARGV[1], p->bank_number, offset,
duration_elapsed(&bench), duration_kbps(&bench, filesize)); duration_elapsed(&bench), duration_kbps(&bench, length));
} }
fileio_close(fileio); fileio_close(fileio);
@ -646,7 +674,7 @@ COMMAND_HANDLER(handle_flash_read_bank_command)
uint32_t length; uint32_t length;
size_t written; size_t written;
if (CMD_ARGC != 4) if (CMD_ARGC < 2 || CMD_ARGC > 4)
return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_COMMAND_SYNTAX_ERROR;
struct duration bench; struct duration bench;
@ -654,11 +682,31 @@ COMMAND_HANDLER(handle_flash_read_bank_command)
struct flash_bank *p; struct flash_bank *p;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
if (ERROR_OK != retval) if (ERROR_OK != retval)
return retval; return retval;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset); offset = 0;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], length);
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); buffer = malloc(length);
if (buffer == NULL) { if (buffer == NULL) {
@ -705,6 +753,7 @@ COMMAND_HANDLER(handle_flash_verify_bank_command)
struct fileio *fileio; struct fileio *fileio;
size_t read_cnt; size_t read_cnt;
size_t filesize; size_t filesize;
size_t length;
int differ; int differ;
if (CMD_ARGC < 2 || CMD_ARGC > 3) if (CMD_ARGC < 2 || CMD_ARGC > 3)
@ -741,14 +790,26 @@ COMMAND_HANDLER(handle_flash_verify_bank_command)
return retval; 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) { if (buffer_file == NULL) {
LOG_ERROR("Out of memory"); LOG_ERROR("Out of memory");
fileio_close(fileio); fileio_close(fileio);
return ERROR_FAIL; return ERROR_FAIL;
} }
retval = fileio_read(fileio, filesize, buffer_file, &read_cnt); retval = fileio_read(fileio, length, buffer_file, &read_cnt);
fileio_close(fileio); fileio_close(fileio);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("File read failure"); LOG_ERROR("File read failure");
@ -756,20 +817,20 @@ COMMAND_HANDLER(handle_flash_verify_bank_command)
return retval; return retval;
} }
if (read_cnt != filesize) { if (read_cnt != length) {
LOG_ERROR("Short read"); LOG_ERROR("Short read");
free(buffer_file); free(buffer_file);
return ERROR_FAIL; return ERROR_FAIL;
} }
buffer_flash = malloc(filesize); buffer_flash = malloc(length);
if (buffer_flash == NULL) { if (buffer_flash == NULL) {
LOG_ERROR("Out of memory"); LOG_ERROR("Out of memory");
free(buffer_file); free(buffer_file);
return ERROR_FAIL; 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) { if (retval != ERROR_OK) {
LOG_ERROR("Flash read error"); LOG_ERROR("Flash read error");
free(buffer_flash); free(buffer_flash);
@ -780,15 +841,15 @@ COMMAND_HANDLER(handle_flash_verify_bank_command)
if (duration_measure(&bench) == ERROR_OK) if (duration_measure(&bench) == ERROR_OK)
command_print(CMD_CTX, "read %zd bytes from file %s and flash bank %u" 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)", " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
read_cnt, CMD_ARGV[1], p->bank_number, offset, length, CMD_ARGV[1], p->bank_number, offset,
duration_elapsed(&bench), duration_kbps(&bench, read_cnt)); 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"); command_print(CMD_CTX, "contents %s", differ ? "differ" : "match");
if (differ) { if (differ) {
uint32_t t; uint32_t t;
int diffs = 0; int diffs = 0;
for (t = 0; t < read_cnt; t++) { for (t = 0; t < length; t++) {
if (buffer_flash[t] == buffer_file[t]) if (buffer_flash[t] == buffer_file[t])
continue; continue;
command_print(CMD_CTX, "diff %d address 0x%08x. Was 0x%02x instead of 0x%02x", 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", .name = "write_bank",
.handler = handle_flash_write_bank_command, .handler = handle_flash_write_bank_command,
.mode = COMMAND_EXEC, .mode = COMMAND_EXEC,
.usage = "bank_id filename offset", .usage = "bank_id filename [offset]",
.help = "Write binary data from file to flash bank, " .help = "Write binary data from file to flash bank. Allow optional "
"starting at specified byte offset from the " "offset from beginning of the bank (defaults to zero).",
"beginning of the bank.",
}, },
{ {
.name = "write_image", .name = "write_image",
@ -926,10 +986,9 @@ static const struct command_registration flash_exec_command_handlers[] = {
.name = "read_bank", .name = "read_bank",
.handler = handle_flash_read_bank_command, .handler = handle_flash_read_bank_command,
.mode = COMMAND_EXEC, .mode = COMMAND_EXEC,
.usage = "bank_id filename offset length", .usage = "bank_id filename [offset [length]]",
.help = "Read binary data from flash bank to file, " .help = "Read binary data from flash bank to file. Allow optional "
"starting at specified byte offset from the " "offset from beginning of the bank (defaults to zero).",
"beginning of the bank.",
}, },
{ {
.name = "verify_bank", .name = "verify_bank",

View File

@ -50,11 +50,12 @@ static int64_t current_time;
static int64_t start; static int64_t start;
static const char * const log_strings[5] = { static const char * const log_strings[6] = {
"User : ", "User : ",
"Error: ", "Error: ",
"Warn : ", /* want a space after each colon, all same width, colons aligned */ "Warn : ", /* want a space after each colon, all same width, colons aligned */
"Info : ", "Info : ",
"Debug: ",
"Debug: " "Debug: "
}; };
@ -234,8 +235,8 @@ COMMAND_HANDLER(handle_debug_level_command)
if (CMD_ARGC == 1) { if (CMD_ARGC == 1) {
int new_level; int new_level;
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], new_level); COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], new_level);
if ((new_level > LOG_LVL_DEBUG) || (new_level < LOG_LVL_SILENT)) { 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); LOG_ERROR("level must be between %d and %d", LOG_LVL_SILENT, LOG_LVL_DEBUG_IO);
return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_COMMAND_SYNTAX_ERROR;
} }
debug_level = new_level; debug_level = new_level;
@ -279,7 +280,8 @@ static struct command_registration log_command_handlers[] = {
.mode = COMMAND_ANY, .mode = COMMAND_ANY,
.help = "Sets the verbosity level of debugging output. " .help = "Sets the verbosity level of debugging output. "
"0 shows errors only; 1 adds warnings; " "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", .usage = "number",
}, },
COMMAND_REGISTRATION_DONE COMMAND_REGISTRATION_DONE
@ -303,7 +305,7 @@ void log_init(void)
int retval = parse_int(debug_env, &value); int retval = parse_int(debug_env, &value);
if (ERROR_OK == retval && if (ERROR_OK == retval &&
debug_level >= LOG_LVL_SILENT && debug_level >= LOG_LVL_SILENT &&
debug_level <= LOG_LVL_DEBUG) debug_level <= LOG_LVL_DEBUG_IO)
debug_level = value; debug_level = value;
} }

View File

@ -46,6 +46,7 @@
* LOG_LVL_WARNING - non-fatal errors, that may be resolved later * LOG_LVL_WARNING - non-fatal errors, that may be resolved later
* LOG_LVL_INFO - state information, etc. * LOG_LVL_INFO - state information, etc.
* LOG_LVL_DEBUG - debug statements, execution trace * LOG_LVL_DEBUG - debug statements, execution trace
* LOG_LVL_DEBUG_IO - verbose debug, low-level I/O trace
*/ */
enum log_levels { enum log_levels {
LOG_LVL_SILENT = -3, LOG_LVL_SILENT = -3,
@ -54,7 +55,8 @@ enum log_levels {
LOG_LVL_ERROR = 0, LOG_LVL_ERROR = 0,
LOG_LVL_WARNING = 1, LOG_LVL_WARNING = 1,
LOG_LVL_INFO = 2, 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, 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_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 ...) \ #define LOG_DEBUG(expr ...) \
do { \ do { \
if (debug_level >= LOG_LVL_DEBUG) \ if (debug_level >= LOG_LVL_DEBUG) \

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(); tap_state_t saved_end_state = tap_get_end_state();
int bit_cnt; unsigned bit_cnt;
if (!((!ir_scan && if (!((!ir_scan &&
(tap_get_state() == TAP_DRSHIFT)) || (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); bitbang_end_state(saved_end_state);
} }
size_t buffered = 0;
for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) { for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) {
int val = 0;
int tms = (bit_cnt == scan_size-1) ? 1 : 0; int tms = (bit_cnt == scan_size-1) ? 1 : 0;
int tdi; int tdi;
int bytec = bit_cnt/8; 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); bitbang_interface->write(0, tms, tdi);
if (type != SCAN_OUT) if (type != SCAN_OUT) {
val = bitbang_interface->read(); 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); bitbang_interface->write(1, tms, tdi);
if (type != SCAN_OUT) { if (type != SCAN_OUT && bitbang_interface->buf_size &&
if (val) (buffered == bitbang_interface->buf_size ||
buffer[bytec] |= bcval; bit_cnt == scan_size - 1)) {
else for (unsigned i = bit_cnt + 1 - buffered; i <= bit_cnt; i++) {
buffer[bytec] &= ~bcval; 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); bitbang_path_move(cmd->cmd.pathmove);
break; break;
case JTAG_SCAN: 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); bitbang_end_state(cmd->cmd.scan->end_state);
scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); 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); type = jtag_scan_type(cmd->cmd.scan);
bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)

View File

@ -27,7 +27,24 @@
struct bitbang_interface { struct bitbang_interface {
/* low level callbacks (for bitbang) /* low level callbacks (for bitbang)
*/ */
/* Either read() or sample()/read_sample() must be implemented. */
/* Sample TDO and return 0 or 1. */
int (*read)(void); 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 (*write)(int tck, int tms, int tdi);
void (*reset)(int trst, int srst); void (*reset)(int trst, int srst);
void (*blink)(int on); void (*blink)(int on);

View File

@ -596,7 +596,7 @@ static int cmsis_dap_swd_run_queue(void)
{ {
uint8_t *buffer = cmsis_dap_handle->packet_buffer; 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) { if (queued_retval != ERROR_OK) {
LOG_DEBUG("Skipping due to previous errors: %d", queued_retval); 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; uint8_t cmd = pending_transfers[i].cmd;
uint32_t data = pending_transfers[i].data; 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_APnDP ? "AP" : "DP",
cmd & SWD_CMD_RnW ? "read" : "write", cmd & SWD_CMD_RnW ? "read" : "write",
(cmd & SWD_CMD_A32) >> 1, data); (cmd & SWD_CMD_A32) >> 1, data);
@ -674,7 +674,7 @@ static int cmsis_dap_swd_run_queue(void)
uint32_t tmp = data; uint32_t tmp = data;
idx += 4; idx += 4;
LOG_DEBUG("Read result: %"PRIx32, data); LOG_DEBUG_IO("Read result: %"PRIx32, data);
/* Imitate posted AP reads */ /* Imitate posted AP reads */
if ((pending_transfers[i].cmd & SWD_CMD_APnDP) || if ((pending_transfers[i].cmd & SWD_CMD_APnDP) ||

View File

@ -430,40 +430,10 @@ static void ftdi_execute_pathmove(struct jtag_command *cmd)
tap_set_end_state(tap_get_state()); 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) static void ftdi_execute_scan(struct jtag_command *cmd)
{ {
DEBUG_JTAG_IO("%s type:%d", cmd->cmd.scan->ir_scan ? "IRSCAN" : "DRSCAN", DEBUG_JTAG_IO("%s type:%d", cmd->cmd.scan->ir_scan ? "IRSCAN" : "DRSCAN",
jtag_scan_type(cmd->cmd.scan)); 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. */ /* Make sure there are no trailing fields with num_bits == 0, or the logic below will fail. */
while (cmd->cmd.scan->num_fields > 0 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", DEBUG_JTAG_IO("%s scan, %i bits, end in %s",
(cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size, (cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size,
tap_state_name(tap_get_end_state())); 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) 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) 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; int retval;
struct signal *led = find_signal_by_name("LED"); struct signal *led = find_signal_by_name("LED");
if (queued_retval != ERROR_OK) { 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; goto skip;
} }
@ -1135,7 +1100,7 @@ static int ftdi_swd_run_queue(void)
for (size_t i = 0; i < swd_cmd_queue_length; i++) { 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); 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", 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_APnDP ? "AP" : "DP",
swd_cmd_queue[i].cmd & SWD_CMD_RnW ? "read" : "write", swd_cmd_queue[i].cmd & SWD_CMD_RnW ? "read" : "write",

View File

@ -40,8 +40,58 @@
static char *remote_bitbang_host; static char *remote_bitbang_host;
static char *remote_bitbang_port; static char *remote_bitbang_port;
FILE *remote_bitbang_in; static FILE *remote_bitbang_in;
FILE *remote_bitbang_out; 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) static void remote_bitbang_putc(int c)
{ {
@ -75,15 +125,8 @@ static int remote_bitbang_quit(void)
return ERROR_OK; return ERROR_OK;
} }
/* Get the next read response. */ static int char_to_int(int c)
static int remote_bitbang_rread(void)
{ {
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) { switch (c) {
case '0': case '0':
return 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'); 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(); return remote_bitbang_rread();
} }
@ -121,7 +197,9 @@ static void remote_bitbang_blink(int on)
} }
static struct bitbang_interface remote_bitbang_bitbang = { 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, .write = &remote_bitbang_write,
.reset = &remote_bitbang_reset, .reset = &remote_bitbang_reset,
.blink = &remote_bitbang_blink, .blink = &remote_bitbang_blink,
@ -199,26 +277,28 @@ static int remote_bitbang_init_unix(void)
static int remote_bitbang_init(void) static int remote_bitbang_init(void)
{ {
int fd;
bitbang_interface = &remote_bitbang_bitbang; bitbang_interface = &remote_bitbang_bitbang;
remote_bitbang_start = 0;
remote_bitbang_end = 0;
LOG_INFO("Initializing remote_bitbang driver"); LOG_INFO("Initializing remote_bitbang driver");
if (remote_bitbang_port == NULL) if (remote_bitbang_port == NULL)
fd = remote_bitbang_init_unix(); remote_bitbang_fd = remote_bitbang_init_unix();
else else
fd = remote_bitbang_init_tcp(); remote_bitbang_fd = remote_bitbang_init_tcp();
if (fd < 0) if (remote_bitbang_fd < 0)
return fd; return remote_bitbang_fd;
remote_bitbang_in = fdopen(fd, "r"); remote_bitbang_in = fdopen(remote_bitbang_fd, "r");
if (remote_bitbang_in == NULL) { if (remote_bitbang_in == NULL) {
LOG_ERROR("fdopen: failed to open read stream"); LOG_ERROR("fdopen: failed to open read stream");
close(fd); close(remote_bitbang_fd);
return ERROR_FAIL; return ERROR_FAIL;
} }
remote_bitbang_out = fdopen(fd, "w"); remote_bitbang_out = fdopen(remote_bitbang_fd, "w");
if (remote_bitbang_out == NULL) { if (remote_bitbang_out == NULL) {
LOG_ERROR("fdopen: failed to open write stream"); LOG_ERROR("fdopen: failed to open write stream");
fclose(remote_bitbang_in); fclose(remote_bitbang_in);

View File

@ -30,7 +30,6 @@ static int riscv_create_rtos(struct target *target)
target->rtos->current_threadid = 1; target->rtos->current_threadid = 1;
target->rtos->current_thread = 1; target->rtos->current_thread = 1;
riscv_update_threads(target->rtos);
target->rtos->gdb_thread_packet = riscv_gdb_thread_packet; target->rtos->gdb_thread_packet = riscv_gdb_thread_packet;
target->rtos->gdb_v_packet = riscv_gdb_v_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"); LOG_DEBUG("Updating the RISC-V Hart List");
struct target *target = rtos->target;
/* Figures out how many harts there are on the system. */ /* Figures out how many harts there are on the system. */
int hart_count = riscv_count_harts(rtos->target); int hart_count = riscv_count_harts(rtos->target);
if (rtos->thread_count != hart_count) { if (rtos->thread_count != hart_count) {
@ -54,7 +55,8 @@ int riscv_update_threads(struct rtos *rtos)
rtos->thread_details[i].exists = true; rtos->thread_details[i].exists = true;
if (asprintf(&rtos->thread_details[i].thread_name_str, "Hart %d", i) < 0) if (asprintf(&rtos->thread_details[i].thread_name_str, "Hart %d", i) < 0)
LOG_ERROR("riscv_update_threads() failed asprintf"); 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"); LOG_ERROR("riscv_update_threads() failed asprintf");
} }
} }

View File

@ -434,7 +434,7 @@ int rtos_get_gdb_reg_list(struct connection *connection)
(target->smp))) { /* in smp several current thread are possible */ (target->smp))) { /* in smp several current thread are possible */
char *hex_reg_list; 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", ", target->rtos->current_thread=0x%" PRIx64 "\r\n",
current_threadid, current_threadid,
target->rtos->current_thread); target->rtos->current_thread);

View File

@ -1,5 +1,5 @@
/*************************************************************************** /***************************************************************************
* Copyright (C) 2016 by Square, Inc. * * Copyright (C) 2017 by Square, Inc. *
* Steven Stallion <stallion@squareup.com> * * Steven Stallion <stallion@squareup.com> *
* * * *
* This program is free software; you can redistribute it and/or modify * * This program is free software; you can redistribute it and/or modify *
@ -20,34 +20,35 @@
#include "config.h" #include "config.h"
#endif #endif
#include "rtos.h" #include <helper/types.h>
#include "rtos_standard_stackings.h" #include <rtos/rtos.h>
#include "target/armv7m.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] = { static const struct stack_register_offset rtos_uCOS_III_Cortex_M_stack_offsets[] = {
{ 0x20, 32 }, /* r0 */ { 0x20, 32 }, /* r0 */
{ 0x24, 32 }, /* r1 */ { 0x24, 32 }, /* r1 */
{ 0x28, 32 }, /* r2 */ { 0x28, 32 }, /* r2 */
{ 0x2c, 32 }, /* r3 */ { 0x2c, 32 }, /* r3 */
{ 0x00, 32 }, /* r4 */ { 0x00, 32 }, /* r4 */
{ 0x04, 32 }, /* r5 */ { 0x04, 32 }, /* r5 */
{ 0x08, 32 }, /* r6 */ { 0x08, 32 }, /* r6 */
{ 0x0c, 32 }, /* r7 */ { 0x0c, 32 }, /* r7 */
{ 0x10, 32 }, /* r8 */ { 0x10, 32 }, /* r8 */
{ 0x14, 32 }, /* r9 */ { 0x14, 32 }, /* r9 */
{ 0x18, 32 }, /* r10 */ { 0x18, 32 }, /* r10 */
{ 0x1c, 32 }, /* r11 */ { 0x1c, 32 }, /* r11 */
{ 0x30, 32 }, /* r12 */ { 0x30, 32 }, /* r12 */
{ -2, 32 }, /* sp */ { -2, 32 }, /* sp */
{ 0x34, 32 }, /* lr */ { 0x34, 32 }, /* lr */
{ 0x38, 32 }, /* pc */ { 0x38, 32 }, /* pc */
{ 0x3c, 32 }, /* xPSR */ { 0x3c, 32 }, /* xPSR */
}; };
const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking = { const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking = {
0x40, /* stack_registers_size */ 0x40, /* stack_registers_size */
-1, /* stack_growth_direction */ -1, /* stack_growth_direction */
ARMV7M_NUM_CORE_REGS, /* num_output_registers */ ARRAY_SIZE(rtos_uCOS_III_Cortex_M_stack_offsets), /* num_output_registers */
rtos_generic_stack_align8, /* stack_alignment */ rtos_generic_stack_align8, /* stack_alignment */
rtos_uCOS_III_Cortex_M_stack_offsets /* register_offsets */ rtos_uCOS_III_Cortex_M_stack_offsets /* register_offsets */
}; };

View File

@ -1,5 +1,5 @@
/*************************************************************************** /***************************************************************************
* Copyright (C) 2016 by Square, Inc. * * Copyright (C) 2017 by Square, Inc. *
* Steven Stallion <stallion@squareup.com> * * Steven Stallion <stallion@squareup.com> *
* * * *
* This program is free software; you can redistribute it and/or modify * * This program is free software; you can redistribute it and/or modify *
@ -23,7 +23,7 @@
#include "config.h" #include "config.h"
#endif #endif
#include "rtos.h" #include <rtos/rtos.h>
extern const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking; extern const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking;

View File

@ -1,5 +1,5 @@
/*************************************************************************** /***************************************************************************
* Copyright (C) 2016 by Square, Inc. * * Copyright (C) 2017 by Square, Inc. *
* Steven Stallion <stallion@squareup.com> * * Steven Stallion <stallion@squareup.com> *
* * * *
* This program is free software; you can redistribute it and/or modify * * This program is free software; you can redistribute it and/or modify *
@ -20,14 +20,14 @@
#include "config.h" #include "config.h"
#endif #endif
#include <helper/log.h>
#include <helper/time_support.h> #include <helper/time_support.h>
#include <jtag/jtag.h> #include <helper/types.h>
#include "target/target.h" #include <rtos/rtos.h>
#include "target/target_type.h" #include <target/target.h>
#include "rtos.h" #include <target/target_type.h>
#include "helper/log.h"
#include "helper/types.h" #include "rtos_ucos_iii_stackings.h"
#include "rtos/rtos_ucos_iii_stackings.h"
#ifndef UCOS_III_MAX_STRLEN #ifndef UCOS_III_MAX_STRLEN
#define UCOS_III_MAX_STRLEN 64 #define UCOS_III_MAX_STRLEN 64
@ -55,18 +55,18 @@ struct uCOS_III_params {
static const struct uCOS_III_params uCOS_III_params_list[] = { static const struct uCOS_III_params uCOS_III_params_list[] = {
{ {
"cortex_m", /* target_name */ "cortex_m", /* target_name */
sizeof(uint32_t), /* pointer_width */ sizeof(uint32_t), /* pointer_width */
0, /* thread_stack_offset */ 0, /* thread_stack_offset */
0, /* thread_name_offset */ 0, /* thread_name_offset */
0, /* thread_state_offset */ 0, /* thread_state_offset */
0, /* thread_priority_offset */ 0, /* thread_priority_offset */
0, /* thread_prev_offset */ 0, /* thread_prev_offset */
0, /* thread_next_offset */ 0, /* thread_next_offset */
false, /* thread_offsets_updated */ false, /* thread_offsets_updated */
1, /* threadid_start */ 1, /* threadid_start */
&rtos_uCOS_III_Cortex_M_stacking, /* stacking_info */ &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; symbol_address_t thread_list_address = 0;
retval = target_read_memory(rtos->target, retval = target_read_memory(rtos->target,
rtos->symbols[uCOS_III_VAL_OSTaskDbgListPtr].address, rtos->symbols[uCOS_III_VAL_OSTaskDbgListPtr].address,
params->pointer_width, params->pointer_width,
1, 1,
(void *)&thread_list_address); (void *)&thread_list_address);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read thread list address"); LOG_ERROR("uCOS-III: failed to read thread list address");
return retval; 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; *thread_address = thread_list_address;
retval = target_read_memory(rtos->target, retval = target_read_memory(rtos->target,
thread_list_address + params->thread_next_offset, thread_list_address + params->thread_next_offset,
params->pointer_width, params->pointer_width,
1, 1,
(void *)&thread_list_address); (void *)&thread_list_address);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read next thread address"); LOG_ERROR("uCOS-III: failed to read next thread address");
return retval; 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]; const struct thread_offset_map *thread_offset_map = &thread_offset_maps[i];
int retval = target_read_memory(rtos->target, int retval = target_read_memory(rtos->target,
rtos->symbols[thread_offset_map->symbol_value].address, rtos->symbols[thread_offset_map->symbol_value].address,
params->pointer_width, params->pointer_width,
1, 1,
(void *)thread_offset_map->thread_offset); (void *)thread_offset_map->thread_offset);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read thread offset"); LOG_ERROR("uCOS-III: failed to read thread offset");
return retval; 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) static int uCOS_III_detect_rtos(struct target *target)
{ {
return target->rtos->symbols != NULL && 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) 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++) 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) { if (strcmp(uCOS_III_params_list[i].target_name, target->type->name) == 0) {
params = malloc(sizeof(*params) + params = malloc(sizeof(*params) + (UCOS_III_MAX_THREADS * sizeof(*params->threads)));
UCOS_III_MAX_THREADS * sizeof(*params->threads));
if (params == NULL) { if (params == NULL) {
LOG_ERROR("uCOS-III: out of memory"); LOG_ERROR("uCOS-III: out of memory");
return ERROR_FAIL; return ERROR_FAIL;
@ -294,13 +293,18 @@ static int uCOS_III_update_threads(struct rtos *rtos)
uint8_t rtos_running; uint8_t rtos_running;
retval = target_read_u8(rtos->target, retval = target_read_u8(rtos->target,
rtos->symbols[uCOS_III_VAL_OSRunning].address, rtos->symbols[uCOS_III_VAL_OSRunning].address,
&rtos_running); &rtos_running);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read RTOS running"); LOG_ERROR("uCOS-III: failed to read RTOS running");
return retval; return retval;
} }
if (rtos_running != 1 && rtos_running != 0) {
LOG_ERROR("uCOS-III: invalid RTOS running value");
return ERROR_FAIL;
}
if (!rtos_running) { if (!rtos_running) {
rtos->thread_details = calloc(1, sizeof(struct thread_detail)); rtos->thread_details = calloc(1, sizeof(struct thread_detail));
if (rtos->thread_details == NULL) { 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; symbol_address_t current_thread_address = 0;
retval = target_read_memory(rtos->target, retval = target_read_memory(rtos->target,
rtos->symbols[uCOS_III_VAL_OSTCBCurPtr].address, rtos->symbols[uCOS_III_VAL_OSTCBCurPtr].address,
params->pointer_width, params->pointer_width,
1, 1,
(void *)&current_thread_address); (void *)&current_thread_address);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read current thread address"); LOG_ERROR("uCOS-III: failed to read current thread address");
return retval; return retval;
@ -338,8 +342,8 @@ static int uCOS_III_update_threads(struct rtos *rtos)
/* read number of tasks */ /* read number of tasks */
retval = target_read_u16(rtos->target, retval = target_read_u16(rtos->target,
rtos->symbols[uCOS_III_VAL_OSTaskQty].address, rtos->symbols[uCOS_III_VAL_OSTaskQty].address,
(void *)&rtos->thread_count); (void *)&rtos->thread_count);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read thread count"); LOG_ERROR("uCOS-III: failed to read thread count");
return retval; return retval;
@ -368,9 +372,7 @@ static int uCOS_III_update_threads(struct rtos *rtos)
char thread_str_buffer[UCOS_III_MAX_STRLEN + 1]; char thread_str_buffer[UCOS_III_MAX_STRLEN + 1];
/* find or create new threadid */ /* find or create new threadid */
retval = uCOS_III_find_or_create_thread(rtos, retval = uCOS_III_find_or_create_thread(rtos, thread_address, &thread_detail->threadid);
thread_address,
&thread_detail->threadid);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to find or create thread"); LOG_ERROR("uCOS-III: failed to find or create thread");
return retval; return retval;
@ -385,19 +387,19 @@ static int uCOS_III_update_threads(struct rtos *rtos)
symbol_address_t thread_name_address = 0; symbol_address_t thread_name_address = 0;
retval = target_read_memory(rtos->target, retval = target_read_memory(rtos->target,
thread_address + params->thread_name_offset, thread_address + params->thread_name_offset,
params->pointer_width, params->pointer_width,
1, 1,
(void *)&thread_name_address); (void *)&thread_name_address);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to name address"); LOG_ERROR("uCOS-III: failed to name address");
return retval; return retval;
} }
retval = target_read_buffer(rtos->target, retval = target_read_buffer(rtos->target,
thread_name_address, thread_name_address,
sizeof(thread_str_buffer), sizeof(thread_str_buffer),
(void *)thread_str_buffer); (void *)thread_str_buffer);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read thread name"); LOG_ERROR("uCOS-III: failed to read thread name");
return retval; return retval;
@ -411,16 +413,16 @@ static int uCOS_III_update_threads(struct rtos *rtos)
uint8_t thread_priority; uint8_t thread_priority;
retval = target_read_u8(rtos->target, retval = target_read_u8(rtos->target,
thread_address + params->thread_state_offset, thread_address + params->thread_state_offset,
&thread_state); &thread_state);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read thread state"); LOG_ERROR("uCOS-III: failed to read thread state");
return retval; return retval;
} }
retval = target_read_u8(rtos->target, retval = target_read_u8(rtos->target,
thread_address + params->thread_priority_offset, thread_address + params->thread_priority_offset,
&thread_priority); &thread_priority);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read thread priority"); LOG_ERROR("uCOS-III: failed to read thread priority");
return retval; return retval;
@ -434,15 +436,15 @@ static int uCOS_III_update_threads(struct rtos *rtos)
thread_state_str = "Unknown"; thread_state_str = "Unknown";
snprintf(thread_str_buffer, sizeof(thread_str_buffer), "State: %s, Priority: %d", 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); thread_detail->extra_info_str = strdup(thread_str_buffer);
/* read previous thread address */ /* read previous thread address */
retval = target_read_memory(rtos->target, retval = target_read_memory(rtos->target,
thread_address + params->thread_prev_offset, thread_address + params->thread_prev_offset,
params->pointer_width, params->pointer_width,
1, 1,
(void *)&thread_address); (void *)&thread_address);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read previous thread address"); LOG_ERROR("uCOS-III: failed to read previous thread address");
return retval; 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; symbol_address_t stack_address = 0;
retval = target_read_memory(rtos->target, retval = target_read_memory(rtos->target,
thread_address + params->thread_stack_offset, thread_address + params->thread_stack_offset,
params->pointer_width, params->pointer_width,
1, 1,
(void *)&stack_address); (void *)&stack_address);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("uCOS-III: failed to read stack address"); LOG_ERROR("uCOS-III: failed to read stack address");
return retval; return retval;
} }
return rtos_generic_stack_read(rtos->target, return rtos_generic_stack_read(rtos->target,
params->stacking_info, params->stacking_info,
stack_address, stack_address,
hex_reg_list); hex_reg_list);
} }
static int uCOS_III_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) static int uCOS_III_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])

View File

@ -302,7 +302,7 @@ int add_service(char *name,
struct sockaddr_in addr_in; struct sockaddr_in addr_in;
socklen_t addr_in_size = sizeof(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", LOG_INFO("Listening on port %d for %s connections",
ntohs(addr_in.sin_port), name); ntohs(addr_in.sin_port), name);
} else if (c->type == CONNECTION_STDINOUT) { } else if (c->type == CONNECTION_STDINOUT) {

View File

@ -17,6 +17,7 @@ static uint32_t load(const struct target *target, unsigned int rd,
return ld(rd, base, offset); return ld(rd, base, offset);
} }
assert(0); assert(0);
return 0; // Silence -Werror=return-type
} }
static uint32_t store(const struct target *target, unsigned int src, 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); return sd(src, base, offset);
} }
assert(0); assert(0);
return 0; // Silence -Werror=return-type
} }
#endif #endif

View File

@ -44,6 +44,13 @@ bool riscv_batch_full(struct riscv_batch *batch)
void riscv_batch_run(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); LOG_DEBUG("running a batch of %ld scans", (long)batch->used_scans);
riscv_batch_add_nop(batch); 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; batch->read_keys[batch->read_keys_used] = batch->used_scans - 1;
LOG_DEBUG("read key %u for batch 0x%p is %u (0x%p)", LOG_DEBUG("read key %u for batch 0x%p is %u (0x%p)",
(unsigned) batch->read_keys_used, batch, (unsigned) (batch->used_scans - 1), (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++; 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); assert(key < batch->read_keys_used);
size_t index = batch->read_keys[key]; size_t index = batch->read_keys[key];
assert(index <= batch->used_scans); assert(index <= batch->used_scans);
uint64_t *addr = ((uint64_t *)(batch->data_in) + index); uint8_t *base = batch->data_in + 8 * index;
return *addr; 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) void riscv_batch_add_nop(struct riscv_batch *batch)

View File

@ -23,8 +23,8 @@ struct riscv_batch {
size_t idle_count; size_t idle_count;
char *data_out; uint8_t *data_out;
char *data_in; uint8_t *data_in;
struct scan_field *fields; struct scan_field *fields;
/* In JTAG we scan out the previous value's output when performing a /* In JTAG we scan out the previous value's output when performing a

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,8 @@
#ifndef TARGET__RISCV__GDB_REGS_H #ifndef TARGET__RISCV__GDB_REGS_H
#define 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 { enum gdb_regno {
GDB_REGNO_XPR0 = 0, GDB_REGNO_XPR0 = 0,
GDB_REGNO_X0 = GDB_REGNO_XPR0 + 0, GDB_REGNO_X0 = GDB_REGNO_XPR0 + 0,

View File

@ -3,6 +3,7 @@
#endif #endif
#include "target/target.h" #include "target/target.h"
#include "target/register.h"
#include "riscv.h" #include "riscv.h"
#include "program.h" #include "program.h"
#include "helper/log.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) int riscv_program_exec(struct riscv_program *p, struct target *t)
{ {
keep_alive();
if (riscv_debug_buffer_leave(t, p) != ERROR_OK) { if (riscv_debug_buffer_leave(t, p) != ERROR_OK) {
LOG_ERROR("unable to write program buffer exit code"); LOG_ERROR("unable to write program buffer exit code");
return ERROR_FAIL; 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)); 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_FPR0);
assert(d <= GDB_REGNO_FPR31); 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); : riscv_program_gettemp(p);
if (riscv_program_lah(p, t, addr) != ERROR_OK) if (riscv_program_lah(p, t, addr) != ERROR_OK)
return ERROR_FAIL; 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; return ERROR_FAIL;
riscv_program_puttemp(p, t); riscv_program_puttemp(p, t);
p->writes_memory = true; p->writes_memory = true;
return ERROR_OK; 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_FPR0);
assert(d <= GDB_REGNO_FPR31); assert(d <= GDB_REGNO_FPR31);
enum gdb_regno t = riscv_program_gah(p, addr) == 0 ? GDB_REGNO_X0 : d; enum gdb_regno t = riscv_program_gah(p, addr) == 0 ? GDB_REGNO_X0 : d;
if (riscv_program_lah(p, t, addr) != ERROR_OK) if (riscv_program_lah(p, t, addr) != ERROR_OK)
return ERROR_FAIL; 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_FAIL;
return ERROR_OK; 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) 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) int riscv_program_lah(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)

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_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_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_fsx(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_flx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr);
/* Assembler macros. */ /* Assembler macros. */
int riscv_program_li(struct riscv_program *p, enum gdb_regno d, riscv_reg_t c); int riscv_program_li(struct riscv_program *p, enum gdb_regno d, riscv_reg_t c);

View File

@ -21,6 +21,7 @@
#include "helper/time_support.h" #include "helper/time_support.h"
#include "riscv.h" #include "riscv.h"
#include "asm.h" #include "asm.h"
#include "gdb_regs.h"
/** /**
* Since almost everything can be accomplish by scanning the dbus register, all * Since almost everything can be accomplish by scanning the dbus register, all
@ -155,21 +156,6 @@ typedef enum slot {
#define DBUS_ADDRESS_UNKNOWN 0xffff #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 #define DRAM_CACHE_SIZE 16
struct trigger { 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", LOG_ERROR("slot_offset called with xlen=%d, slot=%d",
riscv_xlen(target), slot); riscv_xlen(target), slot);
assert(0); assert(0);
return 0; // Silence -Werror=return-type
} }
static uint32_t load_slot(const struct target *target, unsigned int dest, 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; 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) { if (mstatus_reg->valid) {
uint64_t mstatus_user = buf_get_u64(mstatus_reg->value, 0, riscv_xlen(target)); uint64_t mstatus_user = buf_get_u64(mstatus_reg->value, 0, riscv_xlen(target));
if (mstatus_user != info->mstatus_actual) { if (mstatus_user != info->mstatus_actual) {
@ -1201,15 +1188,15 @@ static void update_reg_list(struct target *target)
if (info->reg_values) { if (info->reg_values) {
free(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]; struct reg *r = &target->reg_cache->reg_list[i];
r->value = info->reg_values + i * riscv_xlen(target) / 4; r->value = info->reg_values + i * riscv_xlen(target) / 4;
if (r->dirty) { if (r->dirty) {
LOG_ERROR("Register %d was dirty. Its value is lost.", i); LOG_ERROR("Register %d was dirty. Its value is lost.", i);
} }
if (i == REG_PRIV) { if (i == GDB_REGNO_PRIV) {
r->size = 8; r->size = 8;
} else { } else {
r->size = riscv_xlen(target); 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) 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) { if (mstatus_reg->valid) {
// We previously made it valid. // We previously made it valid.
return ERROR_OK; 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 // Force reading the register. In that process mstatus_actual will be
// updated. // 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. ***/ /*** 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) static int register_read(struct target *target, riscv_reg_t *value, int regnum)
{ {
riscv011_info_t *info = get_info(target); riscv011_info_t *info = get_info(target);
if (regnum >= REG_CSR0 && regnum <= REG_CSR4095) { if (regnum >= GDB_REGNO_CSR0 && regnum <= GDB_REGNO_CSR4095) {
cache_set32(target, 0, csrr(S0, regnum - REG_CSR0)); cache_set32(target, 0, csrr(S0, regnum - GDB_REGNO_CSR0));
cache_set_store(target, 1, S0, SLOT0); cache_set_store(target, 1, S0, SLOT0);
cache_set_jump(target, 2); cache_set_jump(target, 2);
} else { } else {
@ -1281,7 +1268,7 @@ static int register_read(struct target *target, riscv_reg_t *value, int regnum)
*value = cache_get(target, SLOT0); *value = cache_get(target, SLOT0);
LOG_DEBUG("reg[%d]=0x%" PRIx64, regnum, *value); LOG_DEBUG("reg[%d]=0x%" PRIx64, regnum, *value);
if (regnum == REG_MSTATUS) { if (regnum == GDB_REGNO_MSTATUS) {
info->mstatus_actual = *value; info->mstatus_actual = *value;
} }
@ -1296,13 +1283,13 @@ static int register_get(struct reg *reg)
maybe_write_tselect(target); maybe_write_tselect(target);
riscv_reg_t value = ~0; riscv_reg_t value = ~0;
if (reg->number <= REG_XPR31) { if (reg->number <= GDB_REGNO_XPR31) {
value = reg_cache_get(target, reg->number); value = reg_cache_get(target, reg->number);
LOG_DEBUG("%s=0x%" PRIx64, reg->name, 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; value = info->dpc;
LOG_DEBUG("%s=0x%" PRIx64 " (cached)", reg->name, 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); int result = update_mstatus_actual(target);
if (result != ERROR_OK) { if (result != ERROR_OK) {
return result; return result;
@ -1316,22 +1303,24 @@ static int register_get(struct reg *reg)
} }
if (riscv_xlen(target) == 32) { 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 { } 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++); cache_set_jump(target, i++);
if (cache_write(target, 4, true) != ERROR_OK) { if (cache_write(target, 4, true) != ERROR_OK) {
return ERROR_FAIL; return ERROR_FAIL;
} }
} else if (reg->number == GDB_REGNO_PRIV) {
value = get_field(info->dcsr, DCSR_PRV);
} else { } else {
if (register_read(target, &value, reg->number) != ERROR_OK) if (register_read(target, &value, reg->number) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
} }
buf_set_u64(reg->value, 0, riscv_xlen(target), value); buf_set_u64(reg->value, 0, riscv_xlen(target), value);
if (reg->number == REG_MSTATUS) { if (reg->number == GDB_REGNO_MSTATUS) {
reg->valid = true; 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_load(target, 0, S0, SLOT0);
cache_set_store(target, 1, S0, SLOT_LAST); cache_set_store(target, 1, S0, SLOT_LAST);
cache_set_jump(target, 2); cache_set_jump(target, 2);
} else if (number <= REG_XPR31) { } else if (number <= GDB_REGNO_XPR31) {
cache_set_load(target, 0, number - REG_XPR0, SLOT0); cache_set_load(target, 0, number - GDB_REGNO_XPR0, SLOT0);
cache_set_jump(target, 1); cache_set_jump(target, 1);
} else if (number == REG_PC) { } else if (number == GDB_REGNO_PC) {
info->dpc = value; info->dpc = value;
return ERROR_OK; 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); int result = update_mstatus_actual(target);
if (result != ERROR_OK) { if (result != ERROR_OK) {
return result; return result;
@ -1374,20 +1363,20 @@ static int register_write(struct target *target, unsigned int number,
} }
if (riscv_xlen(target) == 32) { 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 { } 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++); 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_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); cache_set_jump(target, 2);
if (number == REG_MSTATUS) { if (number == GDB_REGNO_MSTATUS) {
info->mstatus_actual = value; info->mstatus_actual = value;
} }
} else if (number == REG_PRIV) { } else if (number == GDB_REGNO_PRIV) {
info->dcsr = set_field(info->dcsr, DCSR_PRV, value); info->dcsr = set_field(info->dcsr, DCSR_PRV, value);
return ERROR_OK; return ERROR_OK;
} else { } 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 = calloc(1, sizeof(*target->reg_cache));
target->reg_cache->name = "RISC-V registers"; 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; 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; char *reg_name = info->reg_names;
info->reg_values = NULL; 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]; struct reg *r = &target->reg_cache->reg_list[i];
r->number = i; r->number = i;
r->caller_save = true; r->caller_save = true;
@ -1499,22 +1488,22 @@ static int init_target(struct command_context *cmd_ctx,
r->exist = true; r->exist = true;
r->type = &riscv_reg_arch_type; r->type = &riscv_reg_arch_type;
r->arch_info = target; r->arch_info = target;
if (i <= REG_XPR31) { if (i <= GDB_REGNO_XPR31) {
sprintf(reg_name, "x%d", i); sprintf(reg_name, "x%d", i);
} else if (i == REG_PC) { } else if (i == GDB_REGNO_PC) {
sprintf(reg_name, "pc"); sprintf(reg_name, "pc");
} else if (i >= REG_FPR0 && i <= REG_FPR31) { } else if (i >= GDB_REGNO_FPR0 && i <= GDB_REGNO_FPR31) {
sprintf(reg_name, "f%d", i - REG_FPR0); sprintf(reg_name, "f%d", i - GDB_REGNO_FPR0);
} else if (i >= REG_CSR0 && i <= REG_CSR4095) { } else if (i >= GDB_REGNO_CSR0 && i <= GDB_REGNO_CSR4095) {
sprintf(reg_name, "csr%d", i - REG_CSR0); sprintf(reg_name, "csr%d", i - GDB_REGNO_CSR0);
} else if (i == REG_PRIV) { } else if (i == GDB_REGNO_PRIV) {
sprintf(reg_name, "priv"); sprintf(reg_name, "priv");
} }
if (reg_name[0]) { if (reg_name[0]) {
r->name = reg_name; r->name = reg_name;
} }
reg_name += strlen(reg_name) + 1; 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; 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.", LOG_WARNING("Asked to resume at 32-bit PC on %d-bit target.",
riscv_xlen(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) if (result != ERROR_OK)
return result; 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.", LOG_WARNING("Asked to resume at 32-bit PC on %d-bit target.",
riscv_xlen(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) if (result != ERROR_OK)
return result; return result;
} }
@ -2091,7 +2080,7 @@ static int read_memory(struct target *target, target_addr_t address,
cache_write(target, CACHE_NO_READ, false); cache_write(target, CACHE_NO_READ, false);
riscv011_info_t *info = get_info(target); 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); scans_t *scans = scans_new(target, max_batch_size);
uint32_t result_value = 0x777; uint32_t result_value = 0x777;
@ -2252,7 +2241,7 @@ static int write_memory(struct target *target, target_addr_t address,
return ERROR_FAIL; return ERROR_FAIL;
} }
const int max_batch_size = 256; const unsigned max_batch_size = 256;
scans_t *scans = scans_new(target, max_batch_size); scans_t *scans = scans_new(target, max_batch_size);
uint32_t result_value = 0x777; uint32_t result_value = 0x777;

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 void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a);
static int riscv013_dmi_write_u64_bits(struct target *target); 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_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); 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_ANYHALTED, "anyhalted" },
{ DMI_DMSTATUS, DMI_DMSTATUS_AUTHENTICATED, "authenticated" }, { DMI_DMSTATUS, DMI_DMSTATUS_AUTHENTICATED, "authenticated" },
{ DMI_DMSTATUS, DMI_DMSTATUS_AUTHBUSY, "authbusy" }, { 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_DMSTATUS, DMI_DMSTATUS_VERSION, "version" },
{ DMI_ABSTRACTCS, DMI_ABSTRACTCS_PROGSIZE, "progsize" }, { 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); 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 * exec: If this is set, assume the scan results in an execution, so more
* run-test/idle cycles may be required. * 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); select_dmi(target);
uint64_t value;
dmi_status_t status; dmi_status_t status;
uint16_t address_in; 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 // This first loop ensures that the read request was actually sent
// to the target. Note that if for some reason this stays busy, // 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++) { for (i = 0; i < 256; i++) {
status = dmi_scan(target, NULL, NULL, DMI_OP_READ, address, 0, status = dmi_scan(target, NULL, NULL, DMI_OP_READ, address, 0,
false); false);
@ -456,14 +443,14 @@ static uint64_t dmi_read(struct target *target, uint16_t address)
} }
if (status != DMI_STATUS_SUCCESS) { if (status != DMI_STATUS_SUCCESS) {
LOG_ERROR("Failed read from 0x%x" PRIx64 ", status=%d", LOG_ERROR("Failed read from 0x%x; status=%d", address, status);
address, status);
abort(); abort();
} }
// This second loop ensures that we got the read // This second loop ensures that we got the read
// data back. Note that NOP can result in a 'busy' result as well, but // 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. // that would be noticed on the next DMI access we do.
uint64_t value;
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
status = dmi_scan(target, &address_in, &value, DMI_OP_NOP, address, 0, status = dmi_scan(target, &address_in, &value, DMI_OP_NOP, address, 0,
false); false);
@ -472,7 +459,7 @@ static uint64_t dmi_read(struct target *target, uint16_t address)
} else if (status == DMI_STATUS_SUCCESS) { } else if (status == DMI_STATUS_SUCCESS) {
break; break;
} else { } 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; break;
} }
} }
@ -501,13 +488,13 @@ static void dmi_write(struct target *target, uint16_t address, uint64_t value)
} else if (status == DMI_STATUS_SUCCESS) { } else if (status == DMI_STATUS_SUCCESS) {
break; break;
} else { } 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; break;
} }
} }
if (status != DMI_STATUS_SUCCESS) { 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); address, status);
abort(); abort();
} }
@ -522,16 +509,25 @@ static void dmi_write(struct target *target, uint16_t address, uint64_t value)
} else if (status == DMI_STATUS_SUCCESS) { } else if (status == DMI_STATUS_SUCCESS) {
break; break;
} else { } 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; break;
} }
} }
if (status != DMI_STATUS_SUCCESS) { 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(); 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) uint32_t abstract_register_size(unsigned width)
{ {
switch (width) { switch (width) {
@ -577,7 +573,7 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs)
errors[info->cmderr], *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.", "Increase the timeout with riscv set_command_timeout_sec.",
riscv_command_timeout_sec, riscv_command_timeout_sec,
*abstractcs); *abstractcs);
@ -783,7 +779,7 @@ static int register_write_direct(struct target *target, unsigned number,
if (number <= GDB_REGNO_XPR31) { if (number <= GDB_REGNO_XPR31) {
riscv_program_lx(&program, number, input); riscv_program_lx(&program, number, input);
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { } 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) { } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
enum gdb_regno temp = riscv_program_gettemp(&program); enum gdb_regno temp = riscv_program_gettemp(&program);
riscv_program_lx(&program, temp, input); 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) { if (number <= GDB_REGNO_XPR31) {
riscv_program_sx(&program, number, output); riscv_program_sx(&program, number, output);
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { } 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) { } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
LOG_DEBUG("reading CSR index=0x%03x", number - GDB_REGNO_CSR0); LOG_DEBUG("reading CSR index=0x%03x", number - GDB_REGNO_CSR0);
enum gdb_regno temp = riscv_program_gettemp(&program); 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_read_u64 = &riscv013_fill_dmi_read_u64;
generic_info->fill_dmi_nop_u64 = &riscv013_fill_dmi_nop_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->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->test_compliance = &riscv013_test_compliance;
generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); generic_info->version_specific = calloc(1, sizeof(riscv013_info_t));
if (!generic_info->version_specific) if (!generic_info->version_specific)
@ -1148,7 +1143,7 @@ static int examine(struct target *target)
r->xlen[i], r->debug_buffer_addr[i]); r->xlen[i], r->debug_buffer_addr[i]);
if (riscv_program_gah(&program64, 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]); (long)r->debug_buffer_addr[i]);
abort(); abort();
} }
@ -1179,32 +1174,67 @@ static int examine(struct target *target)
LOG_INFO("Examined RISC-V core; found %d harts", LOG_INFO("Examined RISC-V core; found %d harts",
riscv_count_harts(target)); riscv_count_harts(target));
for (int i = 0; i < riscv_count_harts(target); ++i) { for (int i = 0; i < riscv_count_harts(target); ++i) {
LOG_INFO(" hart %d: XLEN=%d, program buffer at 0x%" PRIx64 if (riscv_hart_enabled(target, i)) {
", %d triggers", i, r->xlen[i], r->debug_buffer_addr[i], LOG_INFO(" hart %d: XLEN=%d, program buffer at 0x%" PRIx64
r->trigger_count[i]); ", %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; return ERROR_OK;
} }
static int assert_reset(struct target *target) static int assert_reset(struct target *target)
{ {
/*FIXME -- this only works for single-hart.*/
RISCV_INFO(r); RISCV_INFO(r);
assert(r->current_hartid == 0);
select_dmi(target); select_dmi(target);
LOG_DEBUG("ASSERTING NDRESET");
uint32_t control = dmi_read(target, DMI_DMCONTROL); uint32_t control_base = set_field(0, DMI_DMCONTROL_DMACTIVE, 1);
control = set_field(control, DMI_DMCONTROL_NDMRESET, 1);
if (target->reset_halt) { if (target->rtos) {
LOG_DEBUG("TARGET RESET HALT SET, ensuring halt is set during reset."); // There's only one target, and OpenOCD thinks each hart is a thread.
control |= DMI_DMCONTROL_HALTREQ; // 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 { } else {
LOG_DEBUG("TARGET RESET HALT NOT SET"); // Reset just this hart.
control &= ~DMI_DMCONTROL_HALTREQ; 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; return ERROR_OK;
} }
@ -1215,43 +1245,85 @@ static int deassert_reset(struct target *target)
RISCV013_INFO(info); RISCV013_INFO(info);
select_dmi(target); select_dmi(target);
/*FIXME -- this only works for Single Hart*/ LOG_DEBUG("%d", r->current_hartid);
assert(r->current_hartid == 0);
/*FIXME -- is there bookkeeping we need to do here*/
uint32_t control = dmi_read(target, DMI_DMCONTROL);
// Clear the reset, but make sure haltreq is still set // Clear the reset, but make sure haltreq is still set
if (target->reset_halt) { uint32_t control = 0;
control |= DMI_DMCONTROL_HALTREQ; 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);
control = set_field(control, DMI_DMCONTROL_NDMRESET, 0);
dmi_write(target, DMI_DMCONTROL, control); dmi_write(target, DMI_DMCONTROL, control);
uint32_t status; uint32_t dmstatus;
int dmi_busy_delay = info->dmi_busy_delay; int dmi_busy_delay = info->dmi_busy_delay;
time_t start = time(NULL);
if (target->reset_halt) { if (target->reset_halt) {
LOG_DEBUG("DEASSERTING RESET, waiting for hart to be halted."); LOG_DEBUG("Waiting for hart to be halted.");
do { do {
status = dmi_read(target, DMI_DMSTATUS); dmstatus = dmi_read(target, DMI_DMSTATUS);
} while (get_field(status, DMI_DMSTATUS_ALLHALTED) == 0); if (time(NULL) - start > riscv_reset_timeout_sec) {
} else { LOG_ERROR("Hart didn't halt coming out of reset in %ds; "
LOG_DEBUG("DEASSERTING RESET, waiting for hart to be running."); "dmstatus=0x%x; "
do { "Increase the timeout with riscv set_reset_timeout_sec.",
status = dmi_read(target, DMI_DMSTATUS); riscv_reset_timeout_sec, dmstatus);
if (get_field(status, DMI_DMSTATUS_ANYHALTED) || return ERROR_FAIL;
get_field(status, DMI_DMSTATUS_ANYUNAVAIL)) {
LOG_ERROR("Unexpected hart status during reset.");
abort();
} }
} 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; info->dmi_busy_delay = dmi_busy_delay;
return ERROR_OK; 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, static int read_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, uint8_t *buffer) 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_addr_t r_addr = riscv_program_alloc_x(&program);
riscv_program_fence(&program); riscv_program_fence(&program);
riscv_program_lx(&program, GDB_REGNO_S0, r_addr); riscv_program_lx(&program, GDB_REGNO_S0, r_addr);
riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size);
switch (size) { switch (size) {
case 1: case 1:
riscv_program_lbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); 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); LOG_ERROR("Unsupported size: %d", size);
return ERROR_FAIL; 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_sw(&program, GDB_REGNO_S1, r_data);
riscv_program_sx(&program, GDB_REGNO_S0, r_addr); 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. */ * program execution mechanism. */
switch (riscv_xlen(target)) { switch (riscv_xlen(target)) {
case 64: 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: 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; break;
default: default:
LOG_ERROR("unknown XLEN %d", riscv_xlen(target)); 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; return ERROR_FAIL;
} }
uint32_t value = riscv_program_read_ram(&program, r_data); // Program has been executed once. d_addr contains address+size, and d_data
LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", address, value); // contains *address.
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;
}
/* The rest of this program is designed to be fast so it reads various /* The rest of this program is designed to be fast so it reads various
* DMI registers directly. */ * 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 * 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 * termination conditions to this loop: a non-BUSY error message, or
* the data was all copied. */ * 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 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); LOG_DEBUG("reading until final address 0x%" PRIx64, fin_addr);
while (count > 1 && !this_is_last_read) { while (cur_addr < fin_addr) {
cur_addr = riscv_read_debug_buffer_x(target, d_addr); // Invariant:
LOG_DEBUG("transferring burst starting at address 0x%" TARGET_PRIxADDR // d_data contains *addr
" (previous burst was 0x%" TARGET_PRIxADDR ")", cur_addr, // d_addr contains addr + size
prev_addr);
assert(first || prev_addr < cur_addr); unsigned start = (cur_addr - address) / size;
first = false; LOG_DEBUG("creating burst to read address 0x%" TARGET_PRIxADDR
prev_addr = cur_addr; " up to 0x%" TARGET_PRIxADDR "; start=0x%d", cur_addr, fin_addr, start);
riscv_addr_t start = (cur_addr - address) / size; assert(cur_addr >= address && cur_addr < fin_addr);
assert (cur_addr >= address);
struct riscv_batch *batch = riscv_batch_alloc( struct riscv_batch *batch = riscv_batch_alloc(
target, target,
32, 32,
info->dmi_busy_delay + info->ac_busy_delay); info->dmi_busy_delay + info->ac_busy_delay);
size_t reads = 0; size_t reads = 0;
size_t rereads = reads; for (riscv_addr_t addr = cur_addr; addr < fin_addr; addr += size) {
for (riscv_addr_t i = start; i < count; ++i) { size_t const index =
if (i == count - 1) { riscv_batch_add_dmi_read(
// 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(
batch, batch,
riscv013_debug_buffer_register(target, r_data)); riscv013_debug_buffer_register(target, r_data));
assert(index == reads); assert(index == reads);
}
reads++; reads++;
if (riscv_batch_full(batch)) if (riscv_batch_full(batch))
@ -1397,26 +1436,21 @@ static int read_memory(struct target *target, target_addr_t address,
riscv_batch_run(batch); riscv_batch_run(batch);
// Note that if the scan resulted in a Busy DMI response, it // Wait for the target to finish performing the last abstract command,
// is this read to abstractcs that will cause the dmi_busy_delay // and update our copy of cmderr.
// to be incremented if necessary. The loop condition above
// catches the case where no writes went through at all.
bool retry_batch_transaction = false;
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY))
abstractcs = dmi_read(target, DMI_ABSTRACTCS); abstractcs = dmi_read(target, DMI_ABSTRACTCS);
info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR);
switch (info->cmderr) { switch (info->cmderr) {
case CMDERR_NONE: case CMDERR_NONE:
LOG_DEBUG("successful (partial?) memory write"); LOG_DEBUG("successful (partial?) memory read");
break; break;
case CMDERR_BUSY: case CMDERR_BUSY:
LOG_DEBUG("memory write resulted in busy response"); LOG_DEBUG("memory read resulted in busy response");
riscv013_clear_abstract_error(target);
increase_ac_busy_delay(target); increase_ac_busy_delay(target);
retry_batch_transaction = true; riscv013_clear_abstract_error(target);
riscv_batch_free(batch);
break; break;
default: default:
LOG_ERROR("error when reading memory, abstractcs=0x%08lx", (long)abstractcs); 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); riscv_batch_free(batch);
return ERROR_FAIL; return ERROR_FAIL;
} }
if (retry_batch_transaction) continue;
for (size_t i = start; i < start + reads; ++i) { // Figure out how far we managed to read.
riscv_addr_t offset = size*i; riscv_addr_t next_addr = riscv_read_debug_buffer_x(target, d_addr);
riscv_addr_t t_addr = address + offset; LOG_DEBUG("Batch read [0x%" TARGET_PRIxADDR ", 0x%" TARGET_PRIxADDR
uint8_t *t_buffer = buffer + offset; "); 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) { // Now read whatever we got out of the batch.
riscv013_set_autoexec(target, d_data, 0); unsigned rereads = 0;
for (riscv_addr_t addr = cur_addr - size; addr < next_addr - size;
addr += size) {
riscv_addr_t offset = addr - address;
// access debug buffer without executing a program - this address logic was taken from program.c uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads);
int const off = (r_data - riscv_debug_buffer_addr(program.target)) / sizeof(program.debug_buffer[0]); uint32_t value = get_field(dmi_out, DTM_DMI_DATA);
value = riscv_read_debug_buffer(target, off); write_to_buf(buffer + offset, value, size);
} else {
uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads);
value = get_field(dmi_out, DTM_DMI_DATA);
}
rereads++; rereads++;
switch (size) { LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", addr, value);
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);
} }
riscv_batch_free(batch); riscv_batch_free(batch);
cur_addr = next_addr;
} }
riscv013_set_autoexec(target, d_data, 0); 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_S0, s0);
riscv_set_register(target, GDB_REGNO_S1, s1); riscv_set_register(target, GDB_REGNO_S1, s1);
return ERROR_OK; return ERROR_OK;
@ -1692,7 +1720,7 @@ struct target_type riscv013_target =
/*** 0.13-specific implementations of various RISC-V helper functions. ***/ /*** 0.13-specific implementations of various RISC-V helper functions. ***/
static riscv_reg_t riscv013_get_register(struct target *target, int hid, int rid) 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); 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); LOG_DEBUG("read PC from DPC: 0x%016" PRIx64, out);
} else if (rid == GDB_REGNO_PRIV) { } else if (rid == GDB_REGNO_PRIV) {
uint64_t dcsr; 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)); buf_set_u64((unsigned char *)&out, 0, 8, get_field(dcsr, CSR_DCSR_PRV));
} else { } else {
int result = register_read_direct(target, &out, rid); 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) 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); 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); assert(value == actual_value);
} else if (rid == GDB_REGNO_PRIV) { } else if (rid == GDB_REGNO_PRIV) {
uint64_t dcsr; 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); dcsr = set_field(dcsr, CSR_DCSR_PRV, value);
register_write_direct(target, CSR_DCSR, dcsr); register_write_direct(target, GDB_REGNO_DCSR, dcsr);
} else { } else {
register_write_direct(target, rid, value); 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; 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. */ /* Helper Functions. */
static void riscv013_on_step_or_resume(struct target *target, bool step) 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) void riscv013_clear_abstract_error(struct target *target)
{ {
uint32_t acs = dmi_read(target, DMI_ABSTRACTCS); // Wait for busy to go away.
dmi_write(target, DMI_ABSTRACTCS, acs); 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) { \ #define COMPLIANCE_TEST(b, message) { \

View File

@ -394,31 +394,43 @@ static int add_trigger(struct target *target, struct trigger *trigger)
{ {
RISCV_INFO(r); 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]; riscv_reg_t tselect[RISCV_MAX_HARTS];
int first_hart = -1;
for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) { for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) {
if (!riscv_hart_enabled(target, hartid)) if (!riscv_hart_enabled(target, hartid))
continue; continue;
if (first_hart < 0)
first_hart = hartid;
tselect[hartid] = riscv_get_register_on_hart(target, hartid, tselect[hartid] = riscv_get_register_on_hart(target, hartid,
GDB_REGNO_TSELECT); GDB_REGNO_TSELECT);
} }
assert(first_hart >= 0);
unsigned int i; 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) { if (r->trigger_unique_id[i] != -1) {
continue; 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 type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target)));
int result = ERROR_OK; 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)) if (!riscv_hart_enabled(target, hartid))
continue; continue;
if (hartid > 0) { if (hartid > first_hart) {
riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, i); riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, i);
} }
switch (type) { switch (type) {
@ -448,14 +460,14 @@ static int add_trigger(struct target *target, struct trigger *trigger)
break; 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)) if (!riscv_hart_enabled(target, hartid))
continue; continue;
riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT,
tselect[hartid]); tselect[hartid]);
} }
if (i >= r->trigger_count[0]) { if (i >= r->trigger_count[first_hart]) {
LOG_ERROR("Couldn't find an available hardware trigger."); LOG_ERROR("Couldn't find an available hardware trigger.");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
} }
@ -507,19 +519,30 @@ static int remove_trigger(struct target *target, struct trigger *trigger)
{ {
RISCV_INFO(r); 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; 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) { if (r->trigger_unique_id[i] == trigger->unique_id) {
break; 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 " LOG_ERROR("Couldn't find the hardware resources used by hardware "
"trigger."); "trigger.");
return ERROR_FAIL; return ERROR_FAIL;
} }
LOG_DEBUG("Stop using resource %d for bp %d", i, trigger->unique_id); 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)) if (!riscv_hart_enabled(target, hartid))
continue; continue;
riscv_reg_t tselect = riscv_get_register_on_hart(target, hartid, GDB_REGNO_TSELECT); 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()"); LOG_DEBUG("riscv_examine()");
if (target_was_examined(target)) { if (target_was_examined(target)) {
LOG_DEBUG("Target was already examined.\n"); LOG_DEBUG("Target was already examined.");
return ERROR_OK; return ERROR_OK;
} }
@ -676,14 +699,13 @@ static int old_or_new_riscv_halt(struct target *target)
return riscv_openocd_halt(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); struct target_type *tt = get_target_type(target);
return tt->assert_reset(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"); LOG_DEBUG("RISCV DEASSERT RESET");
struct target_type *tt = get_target_type(target); 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, static int oldriscv_resume(struct target *target, int current, uint32_t address,
int handle_breakpoints, int debug_execution) int handle_breakpoints, int debug_execution)
{ {
@ -1115,28 +1119,6 @@ int riscv_openocd_step(
return out; 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 Handlers */
COMMAND_HANDLER(riscv_set_command_timeout_sec) { COMMAND_HANDLER(riscv_set_command_timeout_sec) {
@ -1243,8 +1225,8 @@ struct target_type riscv_target =
.resume = old_or_new_riscv_resume, .resume = old_or_new_riscv_resume,
.step = old_or_new_riscv_step, .step = old_or_new_riscv_step,
.assert_reset = old_or_new_riscv_assert_reset, .assert_reset = riscv_assert_reset,
.deassert_reset = old_or_new_riscv_deassert_reset, .deassert_reset = riscv_deassert_reset,
.read_memory = riscv_read_memory, .read_memory = riscv_read_memory,
.write_memory = riscv_write_memory, .write_memory = riscv_write_memory,
@ -1341,33 +1323,6 @@ int riscv_resume_one_hart(struct target *target, int hartid)
return ERROR_OK; 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) int riscv_step_rtos_hart(struct target *target)
{ {
RISCV_INFO(r); RISCV_INFO(r);
@ -1741,6 +1696,8 @@ const char *gdb_regno_name(enum gdb_regno regno)
sprintf(buf, "x%d", regno - GDB_REGNO_XPR0); sprintf(buf, "x%d", regno - GDB_REGNO_XPR0);
} else if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) { } else if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) {
sprintf(buf, "csr%d", regno - GDB_REGNO_CSR0); 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 { } else {
sprintf(buf, "gdb_regno_%d", regno); sprintf(buf, "gdb_regno_%d", regno);
} }

View File

@ -67,7 +67,9 @@ typedef struct {
unsigned trigger_count[RISCV_MAX_HARTS]; unsigned trigger_count[RISCV_MAX_HARTS];
/* For each physical trigger, contains -1 if the hwbp is available, or the /* 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]; int trigger_unique_id[RISCV_MAX_HWBPS];
/* The address of the debug RAM buffer. */ /* 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_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_read_u64)(struct target *target, char *buf, int a);
void (*fill_dmi_nop_u64)(struct target *target, char *buf); 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; } riscv_info_t;
/* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/ /* 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_halt_one_hart(struct target *target, int hartid);
int riscv_resume_all_harts(struct target *target); int riscv_resume_all_harts(struct target *target);
int riscv_resume_one_hart(struct target *target, int hartid); 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 /* Steps the hart that's currently selected in the RTOS, or if there is no RTOS
* then the only hart. */ * then the only hart. */

View File

@ -3037,16 +3037,16 @@ static void handle_md_output(struct command_context *cmd_ctx,
const char *value_fmt; const char *value_fmt;
switch (size) { switch (size) {
case 8: case 8:
value_fmt = "%16.16llx "; value_fmt = "%16.16"PRIx64" ";
break; break;
case 4: case 4:
value_fmt = "%8.8x "; value_fmt = "%8.8"PRIx64" ";
break; break;
case 2: case 2:
value_fmt = "%4.4x "; value_fmt = "%4.4"PRIx64" ";
break; break;
case 1: case 1:
value_fmt = "%2.2x "; value_fmt = "%2.2"PRIx64" ";
break; break;
default: default:
/* "can't happen", caller checked */ /* "can't happen", caller checked */

View File

@ -1,6 +0,0 @@
#
# Freescale Kinetis KE02 devices
#
set CHIPNAME ke02
source [find target/kex.cfg]

View File

@ -1,6 +0,0 @@
#
# Freescale Kinetis KE04 devices
#
set CHIPNAME ke04
source [find target/kex.cfg]

View File

@ -1,6 +0,0 @@
#
# Freescale Kinetis KE06 devices
#
set CHIPNAME ke06
source [find target/kex.cfg]

View File

@ -1,5 +1,5 @@
# #
# Freescale Kinetis KE series devices # Freescale Kinetis KE0x series devices
# #
source [find target/swj-dp.tcl] source [find target/swj-dp.tcl]
@ -21,11 +21,7 @@ if { [info exists WORKAREASIZE] } {
if { [info exists CPUTAPID] } { if { [info exists CPUTAPID] } {
set _CPUTAPID $CPUTAPID set _CPUTAPID $CPUTAPID
} else { } else {
if { [using_jtag] } { set _CPUTAPID 0x0bc11477
set _CPUTAPID 0x4ba00477
} {
set _CPUTAPID 0x2ba01477
}
} }
swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID

7
tcl/target/ke1xf.cfg Normal file
View File

@ -0,0 +1,7 @@
#
# NXP (Freescale) Kinetis KE1xF devices
#
set CHIPNAME ke
source [find target/kx.cfg]

7
tcl/target/ke1xz.cfg Normal file
View File

@ -0,0 +1,7 @@
#
# NXP (Freescale) Kinetis KE1xZ devices
#
set CHIPNAME ke
source [find target/klx.cfg]

View File

@ -1,5 +1,6 @@
# #
# Freescale Kinetis KL series devices # NXP (former Freescale) Kinetis KL series devices
# Also used for Cortex-M0+ equipped members of KVx and KE1xZ series
# #
source [find target/swj-dp.tcl] source [find target/swj-dp.tcl]
@ -31,11 +32,13 @@ target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
set _FLASHNAME $_CHIPNAME.flash set _FLASHNAME $_CHIPNAME.pflash
flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME
kinetis create_banks
# Table 5-1. Clock Summary of KL25 Sub-Family Reference Manual # Table 5-1. Clock Summary of KL25 Sub-Family Reference Manual
# specifies up to 1MHz for VLPR mode. # specifies up to 1MHz for VLPR mode and up to 24MHz for run mode;
# Table 17 of Sub-Family Data Sheet rev4 lists 25MHz as the maximum frequency.
adapter_khz 1000 adapter_khz 1000
reset_config srst_nogate reset_config srst_nogate
@ -51,10 +54,9 @@ if {![using_hla]} {
cortex_m reset_config sysresetreq cortex_m reset_config sysresetreq
} }
# Table 5-1. Clock Summary of KL25 Sub-Family Reference Manual # Disable watchdog not to disturb OpenOCD algorithms running on MCU
# specifies up to 24MHz for run mode; Table 17 of Sub-Family Data # (e.g. armv7m_checksum_memory() in verify_image)
# Sheet rev4 lists 25MHz as the maximum frequency. # Flash driver also disables watchdog before FTFA flash programming.
# Uncoment only if VLPR mode is not used $_TARGETNAME configure -event reset-init {
#$_TARGETNAME configure -event reset-init { kinetis disable_wdog
# adapter_khz 24000 }
#}

View File

@ -1,5 +1,6 @@
# #
# Freescale Kinetis Kx series devices # NXP (former Freescale) Kinetis Kx series devices
# Also used for Cortex-M4 equipped members of KVx and KE1xF series
# #
source [find target/swj-dp.tcl] source [find target/swj-dp.tcl]
@ -35,8 +36,9 @@ target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
set _FLASHNAME $_CHIPNAME.flash set _FLASHNAME $_CHIPNAME.pflash
flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME
kinetis create_banks
adapter_khz 1000 adapter_khz 1000
@ -52,3 +54,11 @@ if {![using_hla]} {
# perform a soft reset # perform a soft reset
cortex_m reset_config sysresetreq cortex_m reset_config sysresetreq
} }
# Disable watchdog not to disturb OpenOCD algorithms running on MCU
# (e.g. armv7m_checksum_memory() in verify_image)
# Flash driver also disables watchdog before FTFA flash programming.
$_TARGETNAME configure -event reset-init {
kinetis disable_wdog
}

View File

@ -10,7 +10,8 @@ set _TARGETNAME $_CHIPNAME.cpu
jtag newtap zynq_pl bs -irlen 6 -ircapture 0x1 -irmask 0x03 \ jtag newtap zynq_pl bs -irlen 6 -ircapture 0x1 -irmask 0x03 \
-expected-id 0x23727093 \ -expected-id 0x23727093 \
-expected-id 0x13722093 \ -expected-id 0x13722093 \
-expected-id 0x03727093 -expected-id 0x03727093 \
-expected-id 0x03736093
jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0x4ba00477 jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0x4ba00477