Merge commit '5cd430647ecfb6dab4a2ed858fb98567723de699' into stable

This commit is contained in:
Jason Kotzin 2022-08-11 19:15:01 -07:00
commit 8fc7a559b2
12 changed files with 680 additions and 589 deletions

View File

@ -130,4 +130,3 @@ int hostio_system(struct target_controller *tc,
gdb_putpacket_f("Fsystem,%08X/%X", cmd, cmd_len);
return gdb_main_loop(tc, true);
}

View File

@ -43,7 +43,7 @@ enum gdb_signal {
GDB_SIGLOST = 29,
};
#define BUF_SIZE 1024
#define BUF_SIZE 1024U
#define ERROR_IF_NO_TARGET() \
if(!cur_target) { gdb_putpacketz("EFF"); break; }
@ -51,23 +51,29 @@ enum gdb_signal {
typedef struct
{
const char *cmd_prefix;
void (*func)(const char *packet, int len);
void (*func)(const char *packet, size_t len);
} cmd_executer;
static char pbuf[BUF_SIZE + 1];
static char pbuf[BUF_SIZE + 1U];
static target *cur_target;
static target *last_target;
static bool gdb_needs_detach_notify = false;
static void handle_q_packet(char *packet, int len);
static void handle_v_packet(char *packet, int len);
static void handle_z_packet(char *packet, int len);
static void handle_q_packet(char *packet, size_t len);
static void handle_v_packet(char *packet, size_t len);
static void handle_z_packet(char *packet, size_t len);
static void handle_kill_target(void);
static void gdb_target_destroy_callback(struct target_controller *tc, target *t)
{
(void)tc;
if (cur_target == t)
if (cur_target == t) {
gdb_put_notificationz("%Stop:W00");
gdb_out("You are now detached from the previous target.\n");
cur_target = NULL;
gdb_needs_detach_notify = true;
}
if (last_target == t)
last_target = NULL;
@ -100,22 +106,20 @@ static struct target_controller gdb_controller = {
int gdb_main_loop(struct target_controller *tc, bool in_syscall)
{
int size;
bool single_step = false;
/* GDB protocol main loop */
while(1) {
while (1) {
SET_IDLE_STATE(1);
size = gdb_getpacket(pbuf, BUF_SIZE);
size_t size = gdb_getpacket(pbuf, BUF_SIZE);
SET_IDLE_STATE(0);
switch(pbuf[0]) {
switch (pbuf[0]) {
/* Implementation of these is mandatory! */
case 'g': { /* 'g': Read general registers */
ERROR_IF_NO_TARGET();
uint8_t arm_regs[target_regs_size(cur_target)];
target_regs_read(cur_target, arm_regs);
gdb_putpacket(hexify(pbuf, arm_regs, sizeof(arm_regs)),
sizeof(arm_regs) * 2);
uint8_t gp_regs[target_regs_size(cur_target)];
target_regs_read(cur_target, gp_regs);
gdb_putpacket(hexify(pbuf, gp_regs, sizeof(gp_regs)), sizeof(gp_regs) * 2U);
break;
}
case 'm': { /* 'm addr,len': Read len bytes from addr */
@ -132,19 +136,20 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
if (target_mem_read(cur_target, mem, addr, len))
gdb_putpacketz("E01");
else
gdb_putpacket(hexify(pbuf, mem, len), len * 2);
gdb_putpacket(hexify(pbuf, mem, len), len * 2U);
break;
}
case 'G': { /* 'G XX': Write general registers */
ERROR_IF_NO_TARGET();
uint8_t arm_regs[target_regs_size(cur_target)];
unhexify(arm_regs, &pbuf[1], sizeof(arm_regs));
target_regs_write(cur_target, arm_regs);
uint8_t gp_regs[target_regs_size(cur_target)];
unhexify(gp_regs, &pbuf[1], sizeof(gp_regs));
target_regs_write(cur_target, gp_regs);
gdb_putpacketz("OK");
break;
}
case 'M': { /* 'M addr,len:XX': Write len bytes to addr */
uint32_t addr, len;
uint32_t addr = 0;
uint32_t len = 0;
int hex;
ERROR_IF_NO_TARGET();
sscanf(pbuf, "M%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &hex);
@ -162,11 +167,24 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
gdb_putpacketz("OK");
break;
}
/* '[m|M|g|G|c][thread-id]' : Set the thread ID for the given subsequent operation
* (we don't actually care which as we only care about the TID for whether to send OK or an error)
*/
case 'H': {
char operation = 0;
uint32_t thread_id = 0;
sscanf(pbuf, "H%c%" SCNx32, &operation, &thread_id);
if (thread_id <= 1)
gdb_putpacketz("OK");
else
gdb_putpacketz("E01");
break;
}
case 's': /* 's [addr]': Single step [start at addr] */
single_step = true;
/* fall through */
case 'c': /* 'c [addr]': Continue [at addr] */
if(!cur_target) {
if (!cur_target) {
gdb_putpacketz("X1D");
break;
}
@ -181,7 +199,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
target_addr watch;
enum target_halt_reason reason;
if(!cur_target) {
if (!cur_target) {
/* Report "target exited" if no target */
gdb_putpacketz("W00");
break;
@ -189,10 +207,9 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
/* Wait for target halt */
while(!(reason = target_halt_poll(cur_target, &watch))) {
unsigned char c = gdb_if_getchar_to(0);
if((c == '\x03') || (c == '\x04')) {
char c = (char)gdb_if_getchar_to(0);
if(c == '\x03' || c == '\x04')
target_halt_request(cur_target);
}
}
SET_RUN_STATE(0);
@ -274,12 +291,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
break;
case 'k': /* Kill the target */
if(cur_target) {
target_reset(cur_target);
target_detach(cur_target);
last_target = cur_target;
cur_target = NULL;
}
handle_kill_target();
break;
case 'r': /* Reset the target system */
@ -317,7 +329,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
handle_q_packet(pbuf, size);
break;
case 'v': /* General query packet */
case 'v': /* Verbose command packet */
handle_v_packet(pbuf, size);
break;
@ -335,12 +347,12 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
}
}
static bool exec_command(char *packet, int len, const cmd_executer *exec)
static bool exec_command(char *packet, const size_t length, const cmd_executer *exec)
{
while (exec->cmd_prefix) {
const int l = strlen(exec->cmd_prefix);
if (!strncmp(packet, exec->cmd_prefix, l)) {
exec->func(packet + l, len - l);
const size_t prefix_length = strlen(exec->cmd_prefix);
if (!strncmp(packet, exec->cmd_prefix, prefix_length)) {
exec->func(packet + prefix_length, length - prefix_length);
return true;
}
++exec;
@ -348,19 +360,16 @@ static bool exec_command(char *packet, int len, const cmd_executer *exec)
return false;
}
static void exec_q_rcmd(const char *packet,int len)
static void exec_q_rcmd(const char *packet, const size_t length)
{
char *data;
int datalen;
/* calculate size and allocate buffer for command */
datalen = len / 2;
data = alloca(datalen + 1);
const size_t datalen = length / 2U;
char *data = alloca(datalen + 1);
/* dehexify command */
unhexify(data, packet, datalen);
data[datalen] = 0; /* add terminating null */
int c = command_process(cur_target, data);
const int c = command_process(cur_target, data);
if (c < 0)
gdb_putpacketz("");
else if (c == 0)
@ -370,41 +379,41 @@ static void exec_q_rcmd(const char *packet,int len)
2 * strlen("Failed\n"));
}
static void
handle_q_string_reply(const char *str, const char *param)
static void handle_q_string_reply(const char *reply, const char *param)
{
unsigned long addr, len;
const size_t str_len = strlen(str);
const size_t reply_length = strlen(reply);
uint32_t addr = 0;
uint32_t len = 0;
if (sscanf(param, "%08lx,%08lx", &addr, &len) != 2) {
if (sscanf(param, "%08" PRIx32 ",%08" PRIx32, &addr, &len) != 2) {
gdb_putpacketz("E01");
return;
}
else if (addr > str_len) {
if (addr > reply_length) {
gdb_putpacketz("E01");
return;
}
else if (addr == str_len) {
if (addr == reply_length) {
gdb_putpacketz("l");
return;
}
unsigned long output_len = str_len - addr;
size_t output_len = reply_length - addr;
if (output_len > len)
output_len = len;
gdb_putpacket2("m", 1, str + addr, output_len);
gdb_putpacket2("m", 1U, reply + addr, output_len);
}
static void exec_q_supported(const char *packet, int len)
static void exec_q_supported(const char *packet, const size_t length)
{
(void)packet;
(void)len;
(void)length;
gdb_putpacket_f("PacketSize=%X;qXfer:memory-map:read+;qXfer:features:read+", BUF_SIZE);
}
static void exec_q_memory_map(const char *packet, int len)
static void exec_q_memory_map(const char *packet, const size_t length)
{
(void)packet;
(void)len;
(void)length;
/* Read target XML memory map */
if ((!cur_target) && last_target) {
/* Attach to last target if detached. */
@ -420,9 +429,9 @@ static void exec_q_memory_map(const char *packet, int len)
handle_q_string_reply(buf, packet);
}
static void exec_q_feature_read(const char *packet, int len)
static void exec_q_feature_read(const char *packet, const size_t length)
{
(void)len;
(void)length;
/* Read target description */
if ((!cur_target) && last_target) {
/* Attach to last target if detached. */
@ -435,24 +444,51 @@ static void exec_q_feature_read(const char *packet, int len)
handle_q_string_reply(target_tdesc(cur_target), packet);
}
static void exec_q_crc(const char *packet, int len)
static void exec_q_crc(const char *packet, const size_t length)
{
(void)len;
uint32_t addr, alen;
if (sscanf(packet, "%" PRIx32 ",%" PRIx32, &addr, &alen) == 2) {
(void)length;
uint32_t addr;
uint32_t addr_length;
if (sscanf(packet, "%" PRIx32 ",%" PRIx32, &addr, &addr_length) == 2) {
if (!cur_target) {
gdb_putpacketz("E01");
return;
}
uint32_t crc;
int res = generic_crc32(cur_target, &crc, addr, alen);
if (res)
if (generic_crc32(cur_target, &crc, addr, addr_length))
gdb_putpacketz("E03");
else
gdb_putpacket_f("C%lx", crc);
}
}
/*
* qC queries are for the current thread. We don't support threads but GDB 11 and 12 require this,
* so we always answer that the current thread is thread 1.
*/
static void exec_q_c(const char *packet, const size_t length)
{
(void)packet;
(void)length;
gdb_putpacketz("QC1");
}
/*
* qfThreadInfo queries are required in GDB 11 and 12 as these GDBs require the server to support
* threading even when there's only the possiblity for one thread to exist. In this instance,
* we have to tell GDB that there is a single active thread so it doesn't think the "thread" died.
* qsThreadInfo will always follow qfThreadInfo when we reply as we have to specify 'l' at the
* end to terminate the list.. GDB doesn't like this not happening.
*/
static void exec_q_thread_info(const char *packet, const size_t length)
{
(void)length;
if (packet[-11] == 'f')
gdb_putpacketz("m1");
else
gdb_putpacketz("l");
}
static const cmd_executer q_commands[]=
{
{"qRcmd,", exec_q_rcmd},
@ -460,34 +496,60 @@ static const cmd_executer q_commands[]=
{"qXfer:memory-map:read::", exec_q_memory_map},
{"qXfer:features:read:target.xml:",exec_q_feature_read},
{"qCRC:", exec_q_crc},
{"qC", exec_q_c},
{"qfThreadInfo", exec_q_thread_info},
{"qsThreadInfo", exec_q_thread_info},
{NULL, NULL},
};
static void
handle_q_packet(char *packet, int len)
static void handle_kill_target(void)
{
if (exec_command(packet, len, q_commands))
if (cur_target) {
target_reset(cur_target);
target_detach(cur_target);
last_target = cur_target;
cur_target = NULL;
}
}
static void handle_q_packet(char *packet, const size_t length)
{
if (exec_command(packet, length, q_commands))
return;
DEBUG_GDB("*** Unsupported packet: %s\n", packet);
gdb_putpacket("", 0);
}
static void
handle_v_packet(char *packet, int plen)
static void handle_v_packet(char *packet, const size_t plen)
{
unsigned long addr, len;
uint32_t addr = 0;
uint32_t len = 0;
int bin;
static uint8_t flash_mode = 0;
if (sscanf(packet, "vAttach;%08lx", &addr) == 1) {
if (sscanf(packet, "vAttach;%08" PRIx32, &addr) == 1) {
/* Attach to remote target processor */
cur_target = target_attach_n(addr, &gdb_controller);
if(cur_target) {
morse(NULL, false);
gdb_putpacketz("T05");
/*
* We don't actually support threads, but GDB 11 and 12 can't work without
* us saying we attached to thread 1.. see the following for the low-down of this:
* https://sourceware.org/bugzilla/show_bug.cgi?id=28405
* https://sourceware.org/bugzilla/show_bug.cgi?id=28874
* https://sourceware.org/pipermail/gdb-patches/2021-December/184171.html
* https://sourceware.org/pipermail/gdb-patches/2022-April/188058.html
* https://sourceware.org/pipermail/gdb-patches/2022-July/190869.html
*/
gdb_putpacketz("T05thread:1;");
} else
gdb_putpacketz("E01");
} else if (!strncmp(packet, "vKill;", 6)) {
/* Kill the target - we don't actually care about the PID that follows "vKill;" */
handle_kill_target();
gdb_putpacketz("OK");
} else if (!strncmp(packet, "vRun", 4)) {
/* Parse command line for get_cmdline semihosting call */
char cmdline[83];
@ -539,9 +601,9 @@ handle_v_packet(char *packet, int plen)
} else
gdb_putpacketz("E01");
} else if (sscanf(packet, "vFlashErase:%08lx,%08lx", &addr, &len) == 2) {
} else if (sscanf(packet, "vFlashErase:%08" PRIx32 ",%08" PRIx32, &addr, &len) == 2) {
/* Erase Flash Memory */
DEBUG_GDB("Flash Erase %08lX %08lX\n", addr, len);
DEBUG_GDB("Flash Erase %08" PRIX32 " %08" PRIX32 "\n", addr, len);
if (!cur_target) {
gdb_putpacketz("EFF");
return;
@ -560,11 +622,11 @@ handle_v_packet(char *packet, int plen)
gdb_putpacketz("EFF");
}
} else if (sscanf(packet, "vFlashWrite:%08lx:%n", &addr, &bin) == 1) {
} else if (sscanf(packet, "vFlashWrite:%08" PRIx32 ":%n", &addr, &bin) == 1) {
/* Write Flash Memory */
len = plen - bin;
DEBUG_GDB("Flash Write %08lX %08lX\n", addr, len);
if (cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, len) == 0)
const uint32_t count = plen - bin;
DEBUG_GDB("Flash Write %08" PRIX32 " %08" PRIX32 "\n", addr, count);
if (cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, count) == 0)
gdb_putpacketz("OK");
else {
flash_mode = 0;
@ -576,24 +638,30 @@ handle_v_packet(char *packet, int plen)
gdb_putpacketz(target_flash_done(cur_target) ? "EFF" : "OK");
flash_mode = 0;
} else if (!strcmp(packet, "vStopped")) {
if (gdb_needs_detach_notify) {
gdb_putpacketz("W00");
gdb_needs_detach_notify = false;
} else
gdb_putpacketz("OK");
} else {
DEBUG_GDB("*** Unsupported packet: %s\n", packet);
gdb_putpacket("", 0);
}
}
static void
handle_z_packet(char *packet, int plen)
static void handle_z_packet(char *packet, const size_t plen)
{
(void)plen;
uint8_t set = (packet[0] == 'Z') ? 1 : 0;
int type, len;
uint32_t type;
uint32_t len;
uint32_t addr;
int ret;
sscanf(packet, "%*[zZ]%" PRIu32 ",%08" PRIx32 ",%" PRIu32, &type, &addr, &len);
sscanf(packet, "%*[zZ]%d,%08" PRIX32 ",%d", &type, &addr, &len);
if(set)
int ret = 0;
if (packet[0] == 'Z')
ret = target_breakwatch_set(cur_target, type, addr, len);
else
ret = target_breakwatch_clear(cur_target, type, addr, len);

View File

@ -30,12 +30,11 @@
#include <stdarg.h>
int gdb_getpacket(char *packet, int size)
size_t gdb_getpacket(char *packet, size_t size)
{
unsigned char c;
unsigned char csum;
char recv_csum[3];
int i;
size_t offset = 0;
while (1) {
/* Wait for packet start */
@ -44,7 +43,8 @@ int gdb_getpacket(char *packet, int size)
* start ('$') or a BMP remote packet start ('!').
*/
do {
packet[0] = gdb_if_getchar();
/* Smells like bad code */
packet[0] = (char)gdb_if_getchar();
if (packet[0] == 0x04)
return 1;
} while ((packet[0] != '$') && (packet[0] != REMOTE_SOM));
@ -52,18 +52,19 @@ int gdb_getpacket(char *packet, int size)
if (packet[0] == REMOTE_SOM) {
/* This is probably a remote control packet
* - get and handle it */
i = 0;
offset = 0;
bool gettingRemotePacket = true;
while (gettingRemotePacket) {
c = gdb_if_getchar();
/* Smells like bad code */
const char c = (char)gdb_if_getchar();
switch (c) {
case REMOTE_SOM: /* Oh dear, packet restarts */
i = 0;
offset = 0;
break;
case REMOTE_EOM: /* Complete packet for processing */
packet[i] = 0;
remotePacketProcess(i, packet);
packet[offset] = 0;
remotePacketProcess(offset, packet);
gettingRemotePacket = false;
break;
@ -73,8 +74,8 @@ int gdb_getpacket(char *packet, int size)
break;
default:
if (i < size) {
packet[i++] = c;
if (offset < size) {
packet[offset++] = c;
} else {
/* Who knows what is going on...return to normality */
gettingRemotePacket = false;
@ -92,30 +93,32 @@ int gdb_getpacket(char *packet, int size)
#endif
} while (packet[0] != '$');
i = 0;
offset = 0;
csum = 0;
char c;
/* Capture packet data into buffer */
while ((c = gdb_if_getchar()) != '#') {
while ((c = (char)gdb_if_getchar()) != '#') {
if (i == size) /* Oh shit */
/* If we run out of buffer space, exit early */
if (offset == size)
break;
if (c == '$') { /* Restart capture */
i = 0;
offset = 0;
csum = 0;
continue;
}
if (c == '}') { /* escaped char */
c = gdb_if_getchar();
csum += c + '}';
packet[i++] = c ^ 0x20;
packet[offset++] = c ^ 0x20;
continue;
}
csum += c;
packet[i++] = c;
packet[offset++] = c;
}
recv_csum[0] = gdb_if_getchar();
recv_csum[1] = gdb_if_getchar();
recv_csum[0] = (char)gdb_if_getchar();
recv_csum[1] = (char)gdb_if_getchar();
recv_csum[2] = 0;
/* return packet if checksum matches */
@ -126,20 +129,20 @@ int gdb_getpacket(char *packet, int size)
gdb_if_putchar('-', 1); /* send nack */
}
gdb_if_putchar('+', 1); /* send ack */
packet[i] = 0;
packet[offset] = 0;
#if PC_HOSTED == 1
DEBUG_GDB_WIRE("%s : ", __func__);
for(int j = 0; j < i; j++) {
c = packet[j];
if ((c >= 32) && (c < 127))
for (size_t j = 0; j < offset; j++) {
const char c = packet[j];
if (c >= ' ' && c < 0x7F)
DEBUG_GDB_WIRE("%c", c);
else
DEBUG_GDB_WIRE("\\x%02X", c);
}
DEBUG_GDB_WIRE("\n");
#endif
return i;
return offset;
}
static void gdb_next_char(char c, unsigned char *csum)
@ -161,21 +164,19 @@ static void gdb_next_char(char c, unsigned char *csum)
}
}
void gdb_putpacket2(const char *packet1, int size1, const char *packet2, int size2)
void gdb_putpacket2(const char *packet1, size_t size1, const char *packet2, size_t size2)
{
int i;
unsigned char csum;
char xmit_csum[3];
int tries = 0;
size_t tries = 0;
do {
DEBUG_GDB_WIRE("%s : ", __func__);
csum = 0;
DEBUG_GDB_WIRE("%s: ", __func__);
unsigned char csum = 0;
gdb_if_putchar('$', 0);
for (i = 0; i < size1; ++i)
for (size_t i = 0; i < size1; ++i)
gdb_next_char(packet1[i], &csum);
for (i = 0; i < size2; ++i)
for (size_t i = 0; i < size2; ++i)
gdb_next_char(packet2[i], &csum);
gdb_if_putchar('#', 0);
@ -183,28 +184,42 @@ void gdb_putpacket2(const char *packet1, int size1, const char *packet2, int siz
gdb_if_putchar(xmit_csum[0], 0);
gdb_if_putchar(xmit_csum[1], 1);
DEBUG_GDB_WIRE("\n");
} while ((gdb_if_getchar_to(2000) != '+') && (tries++ < 3));
} while (gdb_if_getchar_to(2000) != '+' && tries++ < 3);
}
void gdb_putpacket(const char *packet, int size)
void gdb_putpacket(const char *packet, size_t size)
{
int i;
unsigned char csum;
char xmit_csum[3];
int tries = 0;
size_t tries = 0;
do {
DEBUG_GDB_WIRE("%s : ", __func__);
csum = 0;
DEBUG_GDB_WIRE("%s: ", __func__);
unsigned char csum = 0;
gdb_if_putchar('$', 0);
for (i = 0; i < size; ++i)
for (size_t i = 0; i < size; ++i)
gdb_next_char(packet[i], &csum);
gdb_if_putchar('#', 0);
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum);
gdb_if_putchar(xmit_csum[0], 0);
gdb_if_putchar(xmit_csum[1], 1);
DEBUG_GDB_WIRE("\n");
} while ((gdb_if_getchar_to(2000) != '+') && (tries++ < 3));
} while (gdb_if_getchar_to(2000) != '+' && tries++ < 3);
}
void gdb_put_notification(const char *const packet, const size_t size)
{
char xmit_csum[3];
DEBUG_GDB_WIRE("%s: ", __func__);
uint8_t csum = 0;
gdb_if_putchar('%', 0);
for (size_t i = 0; i < size; ++i)
gdb_next_char(packet[i], &csum);
gdb_if_putchar('#', 0);
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum);
gdb_if_putchar(xmit_csum[0], 0);
gdb_if_putchar(xmit_csum[1], 1);
DEBUG_GDB_WIRE("\n");
}
void gdb_putpacket_f(const char *fmt, ...)

View File

@ -26,16 +26,16 @@
static const char hexdigits[] = "0123456789abcdef";
char * hexify(char *hex, const void *buf, size_t size)
char *hexify(char *hex, const void *buf, const size_t size)
{
char *tmp = hex;
const uint8_t *b = buf;
char *dst = hex;
const uint8_t *const src = buf;
while (size--) {
*tmp++ = hexdigits[*b >> 4];
*tmp++ = hexdigits[*b++ & 0xF];
for (size_t idx = 0; idx < size; ++idx) {
*dst++ = hexdigits[src[idx] >> 4];
*dst++ = hexdigits[src[idx] & 0xF];
}
*tmp++ = 0;
*dst++ = 0;
return hex;
}
@ -43,20 +43,18 @@ char * hexify(char *hex, const void *buf, size_t size)
static uint8_t unhex_digit(char hex)
{
uint8_t tmp = hex - '0';
if(tmp > 9)
if (tmp > 9)
tmp -= 'A' - '0' - 10;
if(tmp > 16)
if (tmp > 16)
tmp -= 'a' - 'A';
return tmp;
}
char * unhexify(void *buf, const char *hex, size_t size)
char *unhexify(void *buf, const char *hex, const size_t size)
{
uint8_t *b = buf;
while (size--) {
*b = unhex_digit(*hex++) << 4;
*b++ |= unhex_digit(*hex++);
uint8_t *const dst = buf;
for (size_t idx = 0; idx < size; ++idx, hex += 2) {
dst[idx] = (unhex_digit(hex[0]) << 4) | unhex_digit(hex[1]);
}
return buf;
}

View File

@ -21,18 +21,19 @@
#ifndef __GDB_PACKET_H
#define __GDB_PACKET_H
#include <stddef.h>
#include <stdarg.h>
int gdb_getpacket(char *packet, int size);
void gdb_putpacket(const char *packet, int size);
void gdb_putpacket2(const char *packet1, int size1, const char *packet2, int size2);
size_t gdb_getpacket(char *packet, size_t size);
void gdb_putpacket(const char *packet, size_t size);
void gdb_putpacket2(const char *packet1, size_t size1, const char *packet2, size_t size2);
#define gdb_putpacketz(packet) gdb_putpacket((packet), strlen(packet))
void gdb_putpacket_f(const char *packet, ...);
void gdb_put_notification(const char *packet, size_t size);
#define gdb_put_notificationz(packet) gdb_put_notification((packet), strlen(packet))
void gdb_out(const char *buf);
void gdb_voutf(const char *fmt, va_list);
void gdb_outf(const char *fmt, ...);
#endif

View File

@ -233,7 +233,9 @@ int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
struct dirent *dp;
int i = 0;
while ((dp = readdir(dir)) != NULL) {
if ((strstr(dp->d_name, BMP_IDSTRING)) &&
if ((strstr(dp->d_name, BMP_IDSTRING_BLACKMAGIC) ||
strstr(dp->d_name, BMP_IDSTRING_BLACKSPHERE) ||
strstr(dp->d_name, BMP_IDSTRING_1BITSQUARED)) &&
(strstr(dp->d_name, "-if00"))) {
i++;
char type[256], version[256], serial[256];
@ -266,7 +268,9 @@ int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
dir = opendir(DEVICE_BY_ID);
i = 0;
while ((dp = readdir(dir)) != NULL) {
if ((strstr(dp->d_name, BMP_IDSTRING)) &&
if ((strstr(dp->d_name, BMP_IDSTRING_BLACKMAGIC) ||
strstr(dp->d_name, BMP_IDSTRING_BLACKSPHERE) ||
strstr(dp->d_name, BMP_IDSTRING_1BITSQUARED)) &&
(strstr(dp->d_name, "-if00"))) {
i++;
char type[256], version[256], serial[256];

View File

@ -285,7 +285,7 @@ static void adc_init(void)
adc_set_single_conversion_mode(ADC1);
adc_disable_external_trigger_regular(ADC1);
adc_set_right_aligned(ADC1);
adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_28DOT5CYC);
adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_239DOT5CYC);
adc_power_on(ADC1);
@ -316,6 +316,8 @@ uint32_t platform_target_voltage_sense(void)
while (!adc_eoc(ADC1));
uint32_t val = adc_read_regular(ADC1); /* 0-4095 */
/* Clear EOC bit. The GD32F103 does not automatically reset it on ADC read. */
ADC_SR(ADC1) &= ~ADC_SR_EOC;
return (val * 99) / 8191;
}

View File

@ -18,12 +18,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* This file implements CH32F1xx target specific functions.
/* This file implements CH32F1xx target specific functions.
The ch32 flash is rather slow so this code is using the so called fast mode (ch32 specific).
128 bytes are copied to a write buffer, then the write buffer is committed to flash
/!\ There is some sort of bus stall/bus arbitration going on that does NOT work when
programmed through SWD/jtag
The workaround is to wait a few cycles before filling the write buffer. This is performed by reading the flash a few times
The workaround is to wait a few cycles before filling the write buffer. This is performed by reading the flash a few times
*/
@ -32,29 +32,20 @@
#include "target_internal.h"
#include "cortexm.h"
#if PC_HOSTED == 1
#define DEBUG_CH DEBUG_INFO
#define ERROR_CH DEBUG_WARN
#else
#define DEBUG_CH(...) {} //DEBUG_WARN //(...) {}
#define ERROR_CH DEBUG_WARN //DEBUG_WARN
#endif
extern const struct command_s stm32f1_cmd_list[]; // Reuse stm32f1 stuff
static int ch32f1_flash_erase(struct target_flash *f,
target_addr addr, size_t len);
static int ch32f1_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len);
static int ch32f1_flash_erase(struct target_flash *f,
target_addr addr, size_t len);
static int ch32f1_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len);
// these are common with stm32f1/gd32f1/...
#define FPEC_BASE 0x40022000
#define FLASH_ACR (FPEC_BASE+0x00)
#define FLASH_KEYR (FPEC_BASE+0x04)
#define FLASH_SR (FPEC_BASE+0x0C)
#define FLASH_CR (FPEC_BASE+0x10)
#define FLASH_AR (FPEC_BASE+0x14)
#define FLASH_ACR (FPEC_BASE + 0x00)
#define FLASH_KEYR (FPEC_BASE + 0x04)
#define FLASH_SR (FPEC_BASE + 0x0C)
#define FLASH_CR (FPEC_BASE + 0x10)
#define FLASH_AR (FPEC_BASE + 0x14)
#define FLASH_CR_LOCK (1 << 7)
#define FLASH_CR_STRT (1 << 6)
#define FLASH_SR_BSY (1 << 0)
@ -66,19 +57,16 @@ extern const struct command_s stm32f1_cmd_list[]; // Reuse stm32f1 stuff
#define FLASHSIZE 0x1FFFF7E0
// these are specific to ch32f1
#define FLASH_MAGIC (FPEC_BASE+0x34)
#define FLASH_MODEKEYR_CH32 (FPEC_BASE+0x24) // Fast mode for CH32F10x
#define FLASH_CR_FLOCK_CH32 (1<<15) // fast unlock
#define FLASH_CR_FTPG_CH32 (1<<16) // fast page program
#define FLASH_CR_FTER_CH32 (1<<17) // fast page erase
#define FLASH_CR_BUF_LOAD_CH32 (1<<18) // Buffer load
#define FLASH_CR_BUF_RESET_CH32 (1<<19) // Buffer reset
#define FLASH_SR_EOP (1<<5) // End of programming
#define FLASH_MAGIC (FPEC_BASE + 0x34)
#define FLASH_MODEKEYR_CH32 (FPEC_BASE + 0x24) // Fast mode for CH32F10x
#define FLASH_CR_FLOCK_CH32 (1 << 15) // fast unlock
#define FLASH_CR_FTPG_CH32 (1 << 16) // fast page program
#define FLASH_CR_FTER_CH32 (1 << 17) // fast page erase
#define FLASH_CR_BUF_LOAD_CH32 (1 << 18) // Buffer load
#define FLASH_CR_BUF_RESET_CH32 (1 << 19) // Buffer reset
#define FLASH_SR_EOP (1 << 5) // End of programming
#define FLASH_BEGIN_ADDRESS_CH32 0x8000000
/**
\fn ch32f1_add_flash
\brief "fast" flash driver for CH32F10x chips
@ -101,38 +89,41 @@ static void ch32f1_add_flash(target *t, uint32_t addr, size_t length, size_t era
target_add_flash(t, f);
}
#define WAIT_BUSY() do { \
sr = target_mem_read32(t, FLASH_SR); \
if(target_check_error(t)) { \
ERROR_CH("ch32f1 flash write: comm error\n"); \
return -1; \
} \
} while (sr & FLASH_SR_BSY);
#define WAIT_BUSY() do { \
sr = target_mem_read32(t, FLASH_SR); \
if (target_check_error(t)) { \
DEBUG_WARN("ch32f1 flash write: comm error\n"); \
return -1; \
} \
} while (sr & FLASH_SR_BSY);
#define WAIT_EOP() do { \
sr = target_mem_read32(t, FLASH_SR); \
if(target_check_error(t)) { \
ERROR_CH("ch32f1 flash write: comm error\n"); \
return -1; \
} \
} while (!(sr & FLASH_SR_EOP));
#define WAIT_EOP() do { \
sr = target_mem_read32(t, FLASH_SR); \
if (target_check_error(t)) { \
DEBUG_WARN("ch32f1 flash write: comm error\n"); \
return -1; \
} \
} while (!(sr & FLASH_SR_EOP));
#define CLEAR_EOP() target_mem_write32(t, FLASH_SR,FLASH_SR_EOP)
#define CLEAR_EOP() target_mem_write32(t, FLASH_SR,FLASH_SR_EOP)
#define SET_CR(bit) { ct = target_mem_read32(t, FLASH_CR); \
ct|=(bit); \
target_mem_write32(t, FLASH_CR, ct);}
#define SET_CR(bit) do { \
const uint32_t cr = target_mem_read32(t, FLASH_CR) | (bit); \
target_mem_write32(t, FLASH_CR, cr); \
} while(0)
#define CLEAR_CR(bit) {ct = target_mem_read32(t, FLASH_CR); \
ct&=~(bit); \
target_mem_write32(t, FLASH_CR, ct);}
#define CLEAR_CR(bit) do { \
const uint32_t cr = target_mem_read32(t, FLASH_CR) & (~(bit)); \
target_mem_write32(t, FLASH_CR, cr); \
} while(0)
// Which one is the right value ?
#define MAGIC_WORD 0x100
// #define MAGIC_WORD 0x1000
#define MAGIC(adr) { magic=target_mem_read32(t,(adr) ^ MAGIC_WORD); \
target_mem_write32(t, FLASH_MAGIC , magic); }
#define MAGIC(addr) do { \
magic = target_mem_read32(t, (addr) ^ MAGIC_WORD); \
target_mem_write32(t, FLASH_MAGIC , magic); \
} while(0)
/**
\fn ch32f1_flash_unlock
@ -140,24 +131,24 @@ static void ch32f1_add_flash(target *t, uint32_t addr, size_t length, size_t era
*/
static int ch32f1_flash_unlock(target *t)
{
DEBUG_CH("CH32: flash unlock \n");
DEBUG_INFO("CH32: flash unlock \n");
target_mem_write32(t, FLASH_KEYR , KEY1);
target_mem_write32(t, FLASH_KEYR , KEY2);
target_mem_write32(t, FLASH_KEYR, KEY1);
target_mem_write32(t, FLASH_KEYR, KEY2);
// fast mode
target_mem_write32(t, FLASH_MODEKEYR_CH32 , KEY1);
target_mem_write32(t, FLASH_MODEKEYR_CH32 , KEY2);
target_mem_write32(t, FLASH_MODEKEYR_CH32, KEY1);
target_mem_write32(t, FLASH_MODEKEYR_CH32, KEY2);
uint32_t cr = target_mem_read32(t, FLASH_CR);
if (cr & FLASH_CR_FLOCK_CH32){
ERROR_CH("Fast unlock failed, cr: 0x%08" PRIx32 "\n", cr);
if (cr & FLASH_CR_FLOCK_CH32) {
DEBUG_WARN("Fast unlock failed, cr: 0x%08" PRIx32 "\n", cr);
return -1;
}
return 0;
}
static int ch32f1_flash_lock(target *t)
{
volatile uint32_t ct;
DEBUG_CH("CH32: flash lock \n");
DEBUG_INFO("CH32: flash lock \n");
SET_CR(FLASH_CR_LOCK);
return 0;
}
@ -166,56 +157,55 @@ static int ch32f1_flash_lock(target *t)
\brief identify the ch32f1 chip
Actually grab all cortex m3 with designer = arm not caught earlier...
*/
bool ch32f1_probe(target *t)
{
t->idcode = target_mem_read32(t, DBGMCU_IDCODE) & 0xfff;
if ((t->cpuid & CPUID_PARTNO_MASK) != CORTEX_M3)
return false;
if(t->idcode !=0x410) { // only ch32f103
const uint32_t idcode = target_mem_read32(t, DBGMCU_IDCODE) & 0x00000fffU;
if (idcode != 0x410) // only ch32f103
return false;
}
// try to flock
ch32f1_flash_lock(t);
// if this fails it is not a CH32 chip
if(ch32f1_flash_unlock(t)) {
if (ch32f1_flash_unlock(t))
return false;
}
t->idcode = idcode;
uint32_t signature = target_mem_read32(t, FLASHSIZE);
uint32_t flashSize = signature & 0xFFFF;
target_add_ram(t, 0x20000000, 0x5000);
ch32f1_add_flash(t, FLASH_BEGIN_ADDRESS_CH32, flashSize*1024, 128);
ch32f1_add_flash(t, FLASH_BEGIN_ADDRESS_CH32, flashSize * 1024, 128);
target_add_commands(t, stm32f1_cmd_list, "STM32 LD/MD/VL-LD/VL-MD");
t->driver = "CH32F1 medium density (stm32f1 clone)";
return true;
}
/**
\fn ch32f1_flash_erase
\brief fast erase of CH32
*/
int ch32f1_flash_erase (struct target_flash *f, target_addr addr, size_t len)
int ch32f1_flash_erase(struct target_flash *f, target_addr addr, size_t len)
{
volatile uint32_t ct, sr, magic;
volatile uint32_t sr, magic;
target *t = f->t;
DEBUG_CH("CH32: flash erase \n");
DEBUG_INFO("CH32: flash erase \n");
if (ch32f1_flash_unlock(t)) {
ERROR_CH("CH32: Unlock failed\n");
DEBUG_WARN("CH32: Unlock failed\n");
return -1;
}
// Fast Erase 128 bytes pages (ch32 mode)
while(len) {
while (len) {
SET_CR(FLASH_CR_FTER_CH32);// CH32 PAGE_ER
/* write address to FMA */
target_mem_write32(t, FLASH_AR , addr);
target_mem_write32(t, FLASH_AR, addr);
/* Flash page erase start instruction */
SET_CR( FLASH_CR_STRT );
SET_CR(FLASH_CR_STRT);
WAIT_EOP();
CLEAR_EOP();
CLEAR_CR( FLASH_CR_STRT );
CLEAR_CR(FLASH_CR_STRT);
// Magic
MAGIC(addr);
if (len > 128)
@ -226,8 +216,8 @@ int ch32f1_flash_erase (struct target_flash *f, target_addr addr, size_t len)
}
sr = target_mem_read32(t, FLASH_SR);
ch32f1_flash_lock(t);
if ((sr & SR_ERROR_MASK)) {
ERROR_CH("ch32f1 flash erase error 0x%" PRIx32 "\n", sr);
if (sr & SR_ERROR_MASK) {
DEBUG_WARN("ch32f1 flash erase error 0x%" PRIx32 "\n", sr);
return -1;
}
return 0;
@ -241,39 +231,38 @@ int ch32f1_flash_erase (struct target_flash *f, target_addr addr, size_t len)
NB: Just reading fff is not enough as it could be a transient previous operation value
*/
static bool ch32f1_wait_flash_ready(target *t,uint32_t adr)
static bool ch32f1_wait_flash_ready(target *t, uint32_t addr)
{
uint32_t ff;
for(int i = 0; i < 32; i++) {
ff = target_mem_read32(t,adr);
}
if(ff != 0xffffffffUL) {
ERROR_CH("ch32f1 Not erased properly at %x or flash access issue\n",adr);
return false;
}
return true;
uint32_t ff = 0;
for (size_t i = 0; i < 32; i++)
ff = target_mem_read32(t, addr);
if (ff != 0xffffffffUL) {
DEBUG_WARN("ch32f1 Not erased properly at %" PRIx32 " or flash access issue\n", addr);
return false;
}
return true;
}
/**
\fn ch32f1_flash_write
\brief fast flash for ch32. Load 128 bytes chunk and then flash them
*/
static int ch32f1_upload(target *t, uint32_t dest, const void *src, uint32_t offset)
static int ch32f1_upload(target *t, uint32_t dest, const void *src, uint32_t offset)
{
volatile uint32_t ct, sr, magic;
volatile uint32_t sr, magic;
const uint32_t *ss = (const uint32_t *)(src+offset);
uint32_t dd = dest+offset;
uint32_t dd = dest + offset;
SET_CR(FLASH_CR_FTPG_CH32);
target_mem_write32(t, dd+0,ss[0]);
target_mem_write32(t, dd+4,ss[1]);
target_mem_write32(t, dd+8,ss[2]);
target_mem_write32(t, dd+12,ss[3]);
target_mem_write32(t, dd + 0, ss[0]);
target_mem_write32(t, dd + 4, ss[1]);
target_mem_write32(t, dd + 8, ss[2]);
target_mem_write32(t, dd + 12, ss[3]);
SET_CR(FLASH_CR_BUF_LOAD_CH32); /* BUF LOAD */
WAIT_EOP();
CLEAR_EOP();
CLEAR_CR(FLASH_CR_FTPG_CH32);
MAGIC((dest+offset));
MAGIC(dest + offset);
return 0;
}
/**
@ -282,12 +271,12 @@ static int ch32f1_upload(target *t, uint32_t dest, const void *src, uint32_t of
*/
int ch32f1_buffer_clear(target *t)
{
volatile uint32_t ct,sr;
SET_CR(FLASH_CR_FTPG_CH32); // Fast page program 4-
SET_CR(FLASH_CR_BUF_RESET_CH32); // BUF_RESET 5-
WAIT_BUSY(); // 6-
CLEAR_CR(FLASH_CR_FTPG_CH32); // Fast page program 4-
return 0;
volatile uint32_t sr;
SET_CR(FLASH_CR_FTPG_CH32); // Fast page program 4-
SET_CR(FLASH_CR_BUF_RESET_CH32); // BUF_RESET 5-
WAIT_BUSY(); // 6-
CLEAR_CR(FLASH_CR_FTPG_CH32); // Fast page program 4-
return 0;
}
//#define CH32_VERIFY
@ -295,21 +284,21 @@ int ch32f1_buffer_clear(target *t)
*/
static int ch32f1_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len)
target_addr dest, const void *src, size_t len)
{
volatile uint32_t ct, sr, magic;
volatile uint32_t sr, magic;
target *t = f->t;
size_t length = len;
#ifdef CH32_VERIFY
target_addr orgDest=dest;
const void *orgSrc=src;
target_addr org_dest = dest;
const void *org_src = src;
#endif
DEBUG_CH("CH32: flash write 0x%x ,size=%d\n",dest,len);
DEBUG_INFO("CH32: flash write 0x%" PRIx32 " ,size=%zu\n", dest, len);
while(length > 0)
while (length > 0)
{
if(ch32f1_flash_unlock(t)) {
ERROR_CH("ch32f1 cannot fast unlock\n");
if (ch32f1_flash_unlock(t)) {
DEBUG_WARN("ch32f1 cannot fast unlock\n");
return -1;
}
WAIT_BUSY();
@ -317,12 +306,12 @@ static int ch32f1_flash_write(struct target_flash *f,
// Buffer reset...
ch32f1_buffer_clear(t);
// Load 128 bytes to buffer
if(!ch32f1_wait_flash_ready(t,dest)) {
if (!ch32f1_wait_flash_ready(t,dest))
return -1;
}
for(int i = 0; i < 8; i++) {
if(ch32f1_upload(t,dest,src, 16*i)) {
ERROR_CH("Cannot upload to buffer\n");
for (size_t i = 0; i < 8; i++) {
if (ch32f1_upload(t, dest, src, i * 16U)) {
DEBUG_WARN("Cannot upload to buffer\n");
return -1;
}
}
@ -334,11 +323,11 @@ static int ch32f1_flash_write(struct target_flash *f,
CLEAR_EOP();
CLEAR_CR(FLASH_CR_FTPG_CH32);
MAGIC((dest));
MAGIC(dest);
// next
if(length > 128)
length -=128;
if (length > 128)
length -=128;
else
length = 0;
dest += 128;
@ -346,24 +335,23 @@ static int ch32f1_flash_write(struct target_flash *f,
sr = target_mem_read32(t, FLASH_SR); // 13
ch32f1_flash_lock(t);
if ((sr & SR_ERROR_MASK) ) {
ERROR_CH("ch32f1 flash write error 0x%" PRIx32 "\n", sr);
if (sr & SR_ERROR_MASK) {
DEBUG_WARN("ch32f1 flash write error 0x%" PRIx32 "\n", sr);
return -1;
}
}
#ifdef CH32_VERIFY
DEBUG_CH("Verifying\n");
size_t i = 0;
for(i = 0; i < len; i+= 4)
DEBUG_INFO("Verifying\n");
for (size_t i = 0; i < len; i += 4)
{
uint32_t mem=target_mem_read32(t, orgDest+i);
uint32_t mem2=*(uint32_t *)(orgSrc+i);
if(mem!=mem2)
const uint32_t expected = *(uint32_t *)(org_src + i);
const uint32_t actual = target_mem_read32(t, org_dest + i);
if (expected != actual)
{
ERROR_CH(">>>>write mistmatch at address 0x%x\n",orgDest+i);
ERROR_CH(">>>>expected 0x%x\n",mem2);
ERROR_CH(">>>>flash 0x%x\n",mem);
DEBUG_WARN(">>>>write mistmatch at address 0x%x\n", org_dest + i);
DEBUG_WARN(">>>>expected: 0x%x\n", expected);
DEBUG_WARN(">>>> actual: 0x%x\n", actual);
return -1;
}
}
@ -371,4 +359,3 @@ static int ch32f1_flash_write(struct target_flash *f,
return 0;
}
// EOF

View File

@ -378,8 +378,25 @@ bool cortexm_probe(ADIv5_AP_t *ap)
} else {
target_check_error(t);
}
#if PC_HOSTED
#define STRINGIFY(x) #x
#define PROBE(x) \
do { if ((x)(t)) {return true;} else target_check_error(t); } while (0)
do { \
DEBUG_INFO("Calling " STRINGIFY(x) "\n"); \
if ((x)(t)) \
return true; \
else \
target_check_error(t); \
} while (0)
#else
#define PROBE(x) \
do { \
if ((x)(t)) \
return true; \
else \
target_check_error(t); \
} while (0)
#endif
switch (ap->ap_designer) {
case AP_DESIGNER_FREESCALE:
@ -502,7 +519,7 @@ bool cortexm_attach(target *t)
priv->flash_patch_revision = (r >> 28);
priv->hw_watchpoint_max = CORTEXM_MAX_WATCHPOINTS;
r = target_mem_read32(t, CORTEXM_DWT_CTRL);
if ((r >> 28) > priv->hw_watchpoint_max)
if ((r >> 28) < priv->hw_watchpoint_max)
priv->hw_watchpoint_max = r >> 28;
/* Clear any stale breakpoints */
@ -675,7 +692,7 @@ static int dcrsr_regnum(target *t, unsigned reg)
return regnum_cortex_m[reg];
} else if ((t->target_options & TOPT_FLAVOUR_V7MF) &&
(reg < (sizeof(regnum_cortex_m) +
sizeof(regnum_cortex_mf) / 4))) {
sizeof(regnum_cortex_mf)) / 4)) {
return regnum_cortex_mf[reg - sizeof(regnum_cortex_m)/4];
} else {
return -1;

View File

@ -37,77 +37,96 @@
#include "general.h"
#include "target.h"
#include "target_internal.h"
#include "adiv5.h"
#define SIM_SDID 0x40048024
#define SIM_FCFG1 0x4004804C
#define KINETIS_MDM_IDR_K22F 0x1c0000
#define KINETIS_MDM_IDR_KZ03 0x1c0020
#define FTFA_BASE 0x40020000
#define FTFA_FSTAT (FTFA_BASE + 0x00)
#define FTFA_FCNFG (FTFA_BASE + 0x01)
#define FTFA_FSEC (FTFA_BASE + 0x02)
#define FTFA_FOPT (FTFA_BASE + 0x03)
#define FTFA_FCCOB_0 (FTFA_BASE + 0x04)
#define FTFA_FCCOB_1 (FTFA_BASE + 0x08)
#define FTFA_FCCOB_2 (FTFA_BASE + 0x0C)
#define MDM_STATUS ADIV5_AP_REG(0x00)
#define MDM_CONTROL ADIV5_AP_REG(0x04)
#define FTFA_FSTAT_CCIF (1 << 7)
#define FTFA_FSTAT_RDCOLERR (1 << 6)
#define FTFA_FSTAT_ACCERR (1 << 5)
#define FTFA_FSTAT_FPVIOL (1 << 4)
#define FTFA_FSTAT_MGSTAT0 (1 << 0)
#define MDM_STATUS_MASS_ERASE_ACK (1 << 0)
#define MDM_STATUS_FLASH_READY (1 << 1)
#define MDM_STATUS_MASS_ERASE_ENABLED (1 << 5)
#define MDM_STATUS_BACK_KEY_ENABLED (1 << 6)
#define FTFA_CMD_CHECK_ERASE 0x01
#define FTFA_CMD_PROGRAM_CHECK 0x02
#define FTFA_CMD_READ_RESOURCE 0x03
#define FTFA_CMD_PROGRAM_LONGWORD 0x06
#define MDM_CONTROL_MASS_ERASE (1 << 0)
#define MDM_CONTROL_SYS_RESET (1 << 3)
#define SIM_SDID 0x40048024
#define SIM_FCFG1 0x4004804C
#define FLASH_SECURITY_BYTE_ADDRESS 0x40C
#define FLASH_SECURITY_BYTE_UNSECURED 0xFE
#define FTFx_BASE 0x40020000
#define FTFx_FSTAT (FTFx_BASE + 0x00)
#define FTFx_FCNFG (FTFx_BASE + 0x01)
#define FTFx_FSEC (FTFx_BASE + 0x02)
#define FTFx_FOPT (FTFx_BASE + 0x03)
#define FTFx_FCCOB0 (FTFx_BASE + 0x04)
#define FTFx_FCCOB4 (FTFx_BASE + 0x08)
#define FTFx_FCCOB8 (FTFx_BASE + 0x0C)
#define FTFx_FSTAT_CCIF (1 << 7)
#define FTFx_FSTAT_RDCOLERR (1 << 6)
#define FTFx_FSTAT_ACCERR (1 << 5)
#define FTFx_FSTAT_FPVIOL (1 << 4)
#define FTFx_FSTAT_MGSTAT0 (1 << 0)
#define FTFx_FSEC_KEYEN_MSK (0b11 << 6)
#define FTFx_FSEC_KEYEN (0b10 << 6)
#define FTFx_CMD_CHECK_ERASE 0x01
#define FTFx_CMD_PROGRAM_CHECK 0x02
#define FTFx_CMD_READ_RESOURCE 0x03
#define FTFx_CMD_PROGRAM_LONGWORD 0x06
/* Part of the FTFE module for K64 */
#define FTFE_CMD_PROGRAM_PHRASE 0x07
#define FTFA_CMD_ERASE_SECTOR 0x09
#define FTFA_CMD_CHECK_ERASE_ALL 0x40
#define FTFA_CMD_READ_ONCE 0x41
#define FTFA_CMD_PROGRAM_ONCE 0x43
#define FTFA_CMD_ERASE_ALL 0x44
#define FTFA_CMD_BACKDOOR_ACCESS 0x45
#define FTFx_CMD_PROGRAM_PHRASE 0x07
#define FTFx_CMD_ERASE_SECTOR 0x09
#define FTFx_CMD_CHECK_ERASE_ALL 0x40
#define FTFx_CMD_READ_ONCE 0x41
#define FTFx_CMD_PROGRAM_ONCE 0x43
#define FTFx_CMD_ERASE_ALL 0x44
#define FTFx_CMD_BACKDOOR_ACCESS 0x45
#define KL_WRITE_LEN 4
/* 8 byte phrases need to be written to the k64 flash */
#define K64_WRITE_LEN 8
static bool kinetis_cmd_unsafe(target *t, int argc, char *argv[]);
static bool kinetis_cmd_unsafe(target *t, int argc, char **argv);
const struct command_s kinetis_cmd_list[] = {
{"unsafe", (cmd_handler)kinetis_cmd_unsafe, "Allow programming security byte (enable|disable)"},
{NULL, NULL, NULL}
{NULL, NULL, NULL},
};
static bool kinetis_cmd_unsafe(target *t, int argc, char *argv[])
static bool kinetis_cmd_unsafe(target *t, int argc, char **argv)
{
if (argc == 1) {
tc_printf(t, "Allow programming security byte: %s\n",
t->unsafe_enabled ? "enabled" : "disabled");
tc_printf(t, "Allow programming security byte: %s\n", t->unsafe_enabled ? "enabled" : "disabled");
} else {
parse_enable_or_disable(argv[1], &t->unsafe_enabled);
}
return true;
}
static int kl_gen_flash_erase(struct target_flash *f, target_addr addr, size_t len);
static int kl_gen_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len);
static int kl_gen_flash_done(struct target_flash *f);
static int kinetis_flash_cmd_erase(struct target_flash *f, target_addr addr, size_t len);
static int kinetis_flash_cmd_write(struct target_flash *f, target_addr dest, const void *src, size_t len);
static int kinetis_flash_done(struct target_flash *f);
struct kinetis_flash {
struct target_flash f;
uint8_t write_len;
};
static void kl_gen_add_flash(target *t, uint32_t addr, size_t length,
size_t erasesize, size_t write_len)
static void kinetis_add_flash(
target *const t, const uint32_t addr, const size_t length, const size_t erasesize, const size_t write_len)
{
struct kinetis_flash *kf = calloc(1, sizeof(*kf));
struct target_flash *f;
if (!kf) { /* calloc failed: heap exhaustion */
if (!kf) { /* calloc failed: heap exhaustion */
DEBUG_WARN("calloc: failed in %s\n", __func__);
return;
}
@ -116,15 +135,26 @@ static void kl_gen_add_flash(target *t, uint32_t addr, size_t length,
f->start = addr;
f->length = length;
f->blocksize = erasesize;
f->erase = kl_gen_flash_erase;
f->write = kl_gen_flash_write;
f->done = kl_gen_flash_done;
f->erase = kinetis_flash_cmd_erase;
f->write = kinetis_flash_cmd_write;
f->done = kinetis_flash_done;
f->erased = 0xff;
kf->write_len = write_len;
target_add_flash(t, f);
}
bool kinetis_probe(target *t)
static void kl_s32k14_setup(
target *const t, const uint32_t sram_l, const uint32_t sram_h, const size_t flash_size, const size_t flexmem_size)
{
t->driver = "S32K14x";
target_add_ram(t, sram_l, 0x20000000 - sram_l);
target_add_ram(t, 0x20000000, sram_h);
kinetis_add_flash(t, 0x00000000, flash_size, 0x1000, K64_WRITE_LEN); /* P-Flash, 4 KB Sectors */
kinetis_add_flash(t, 0x10000000, flexmem_size, 0x1000, K64_WRITE_LEN); /* FlexNVM, 4 KB Sectors */
}
bool kinetis_probe(target *const t)
{
uint32_t sdid = target_mem_read32(t, SIM_SDID);
uint32_t fcfg1 = target_mem_read32(t, SIM_FCFG1);
@ -132,52 +162,52 @@ bool kinetis_probe(target *t)
switch (sdid >> 20) {
case 0x161:
/* sram memory size */
switch((sdid >> 16) & 0x0f) {
case 0x03:/* 4 KB */
target_add_ram(t, 0x1ffffc00, 0x0400);
target_add_ram(t, 0x20000000, 0x0C00);
break;
case 0x04:/* 8 KB */
target_add_ram(t, 0x1ffff800, 0x0800);
target_add_ram(t, 0x20000000, 0x1800);
break;
case 0x05:/* 16 KB */
target_add_ram(t, 0x1ffff000, 0x1000);
target_add_ram(t, 0x20000000, 0x3000);
break;
case 0x06:/* 32 KB */
target_add_ram(t, 0x1fffe000, 0x2000);
target_add_ram(t, 0x20000000, 0x6000);
break;
default:
return false;
break;
switch ((sdid >> 16) & 0x0f) {
case 0x03: /* 4 KB */
target_add_ram(t, 0x1ffffc00, 0x0400);
target_add_ram(t, 0x20000000, 0x0C00);
break;
case 0x04: /* 8 KB */
target_add_ram(t, 0x1ffff800, 0x0800);
target_add_ram(t, 0x20000000, 0x1800);
break;
case 0x05: /* 16 KB */
target_add_ram(t, 0x1ffff000, 0x1000);
target_add_ram(t, 0x20000000, 0x3000);
break;
case 0x06: /* 32 KB */
target_add_ram(t, 0x1fffe000, 0x2000);
target_add_ram(t, 0x20000000, 0x6000);
break;
default:
return false;
break;
}
/* flash memory size */
switch((fcfg1 >> 24) & 0x0f) {
case 0x03: /* 32 KB */
t->driver = "KL16Z32Vxxx";
kl_gen_add_flash(t, 0x00000000, 0x08000, 0x400, KL_WRITE_LEN);
break;
switch ((fcfg1 >> 24) & 0x0f) {
case 0x03: /* 32 KB */
t->driver = "KL16Z32Vxxx";
kinetis_add_flash(t, 0x00000000, 0x08000, 0x400, KL_WRITE_LEN);
break;
case 0x05: /* 64 KB */
t->driver = "KL16Z64Vxxx";
kl_gen_add_flash(t, 0x00000000, 0x10000, 0x400, KL_WRITE_LEN);
break;
case 0x05: /* 64 KB */
t->driver = "KL16Z64Vxxx";
kinetis_add_flash(t, 0x00000000, 0x10000, 0x400, KL_WRITE_LEN);
break;
case 0x07: /* 128 KB */
t->driver = "KL16Z128Vxxx";
kl_gen_add_flash(t, 0x00000000, 0x20000, 0x400, KL_WRITE_LEN);
break;
case 0x07: /* 128 KB */
t->driver = "KL16Z128Vxxx";
kinetis_add_flash(t, 0x00000000, 0x20000, 0x400, KL_WRITE_LEN);
break;
case 0x09: /* 256 KB */
t->driver = "KL16Z256Vxxx";
kl_gen_add_flash(t, 0x00000000, 0x40000, 0x400, KL_WRITE_LEN);
break;
default:
return false;
break;
case 0x09: /* 256 KB */
t->driver = "KL16Z256Vxxx";
kinetis_add_flash(t, 0x00000000, 0x40000, 0x400, KL_WRITE_LEN);
break;
default:
return false;
break;
}
break;
@ -186,68 +216,68 @@ bool kinetis_probe(target *t)
t->driver = "KL25";
target_add_ram(t, 0x1ffff000, 0x1000);
target_add_ram(t, 0x20000000, 0x3000);
kl_gen_add_flash(t, 0x00000000, 0x20000, 0x400, KL_WRITE_LEN);
kinetis_add_flash(t, 0x00000000, 0x20000, 0x400, KL_WRITE_LEN);
break;
case 0x231:
t->driver = "KL27x128"; // MKL27 >=128kb
target_add_ram(t, 0x1fffe000, 0x2000);
target_add_ram(t, 0x20000000, 0x6000);
kl_gen_add_flash(t, 0x00000000, 0x40000, 0x400, KL_WRITE_LEN);
kinetis_add_flash(t, 0x00000000, 0x40000, 0x400, KL_WRITE_LEN);
break;
case 0x271:
switch((sdid >> 16) & 0x0f) {
case 4:
t->driver = "KL27x32";
target_add_ram(t, 0x1ffff800, 0x0800);
target_add_ram(t, 0x20000000, 0x1800);
kl_gen_add_flash(t, 0x00000000, 0x8000, 0x400, KL_WRITE_LEN);
break;
case 5:
t->driver = "KL27x64";
target_add_ram(t, 0x1ffff000, 0x1000);
target_add_ram(t, 0x20000000, 0x3000);
kl_gen_add_flash(t, 0x00000000, 0x10000, 0x400, KL_WRITE_LEN);
break;
default:
return false;
switch ((sdid >> 16) & 0x0f) {
case 4:
t->driver = "KL27x32";
target_add_ram(t, 0x1ffff800, 0x0800);
target_add_ram(t, 0x20000000, 0x1800);
kinetis_add_flash(t, 0x00000000, 0x8000, 0x400, KL_WRITE_LEN);
break;
case 5:
t->driver = "KL27x64";
target_add_ram(t, 0x1ffff000, 0x1000);
target_add_ram(t, 0x20000000, 0x3000);
kinetis_add_flash(t, 0x00000000, 0x10000, 0x400, KL_WRITE_LEN);
break;
default:
return false;
}
break;
case 0x021: /* KL02 family */
switch((sdid >> 16) & 0x0f) {
case 3:
t->driver = "KL02x32";
target_add_ram(t, 0x1FFFFC00, 0x400);
target_add_ram(t, 0x20000000, 0xc00);
kl_gen_add_flash(t, 0x00000000, 0x7FFF, 0x400, KL_WRITE_LEN);
break;
case 2:
t->driver = "KL02x16";
target_add_ram(t, 0x1FFFFE00, 0x200);
target_add_ram(t, 0x20000000, 0x600);
kl_gen_add_flash(t, 0x00000000, 0x3FFF, 0x400, KL_WRITE_LEN);
break;
case 1:
t->driver = "KL02x8";
target_add_ram(t, 0x1FFFFF00, 0x100);
target_add_ram(t, 0x20000000, 0x300);
kl_gen_add_flash(t, 0x00000000, 0x1FFF, 0x400, KL_WRITE_LEN);
break;
default:
return false;
switch ((sdid >> 16) & 0x0f) {
case 3:
t->driver = "KL02x32";
target_add_ram(t, 0x1FFFFC00, 0x400);
target_add_ram(t, 0x20000000, 0xc00);
kinetis_add_flash(t, 0x00000000, 0x7FFF, 0x400, KL_WRITE_LEN);
break;
case 2:
t->driver = "KL02x16";
target_add_ram(t, 0x1FFFFE00, 0x200);
target_add_ram(t, 0x20000000, 0x600);
kinetis_add_flash(t, 0x00000000, 0x3FFF, 0x400, KL_WRITE_LEN);
break;
case 1:
t->driver = "KL02x8";
target_add_ram(t, 0x1FFFFF00, 0x100);
target_add_ram(t, 0x20000000, 0x300);
kinetis_add_flash(t, 0x00000000, 0x1FFF, 0x400, KL_WRITE_LEN);
break;
default:
return false;
}
break;
case 0x031: /* KL03 family */
t->driver = "KL03";
target_add_ram(t, 0x1ffffe00, 0x200);
target_add_ram(t, 0x20000000, 0x600);
kl_gen_add_flash(t, 0, 0x8000, 0x400, KL_WRITE_LEN);
kinetis_add_flash(t, 0, 0x8000, 0x400, KL_WRITE_LEN);
break;
case 0x220: /* K22F family */
t->driver = "K22F";
target_add_ram(t, 0x1c000000, 0x4000000);
target_add_ram(t, 0x20000000, 0x100000);
kl_gen_add_flash(t, 0, 0x40000, 0x800, KL_WRITE_LEN);
kl_gen_add_flash(t, 0x40000, 0x40000, 0x800, KL_WRITE_LEN);
kinetis_add_flash(t, 0, 0x40000, 0x800, KL_WRITE_LEN);
kinetis_add_flash(t, 0x40000, 0x40000, 0x800, KL_WRITE_LEN);
break;
case 0x620: /* K64F family. */
/* This should be 0x640, but according to the errata sheet
@ -255,115 +285,107 @@ bool kinetis_probe(target *t)
* subfamily nibble as 2
*/
t->driver = "K64";
target_add_ram(t, 0x1FFF0000, 0x10000);
target_add_ram(t, 0x20000000, 0x30000);
kl_gen_add_flash(t, 0, 0x80000, 0x1000, K64_WRITE_LEN);
kl_gen_add_flash(t, 0x80000, 0x80000, 0x1000, K64_WRITE_LEN);
target_add_ram(t, 0x1FFF0000, 0x10000);
target_add_ram(t, 0x20000000, 0x30000);
kinetis_add_flash(t, 0, 0x80000, 0x1000, K64_WRITE_LEN);
kinetis_add_flash(t, 0x80000, 0x80000, 0x1000, K64_WRITE_LEN);
break;
case 0x000: /* Older K-series */
switch(sdid & 0xff0) {
case 0x000: /* K10 Family, DIEID=0x0 */
case 0x080: /* K10 Family, DIEID=0x1 */
case 0x100: /* K10 Family, DIEID=0x2 */
case 0x180: /* K10 Family, DIEID=0x3 */
case 0x220: /* K11 Family, DIEID=0x4 */
return false;
case 0x200: /* K12 Family, DIEID=0x4 */
switch((fcfg1 >> 24) & 0x0f) {
/* K12 Sub-Family Reference Manual, K12P80M50SF4RM, Rev. 4, February 2013 */
case 0x7:
t->driver = "MK12DX128Vxx5";
target_add_ram(t, 0x1fffc000, 0x00004000); /* SRAM_L, 16 KB */
target_add_ram(t, 0x20000000, 0x00004000); /* SRAM_H, 16 KB */
kl_gen_add_flash(t, 0x00000000, 0x00020000, 0x800, KL_WRITE_LEN); /* P-Flash, 128 KB, 2 KB Sectors */
kl_gen_add_flash(t, 0x10000000, 0x00010000, 0x800, KL_WRITE_LEN); /* FlexNVM, 64 KB, 2 KB Sectors */
break;
case 0x9:
t->driver = "MK12DX256Vxx5";
target_add_ram(t, 0x1fffc000, 0x00004000); /* SRAM_L, 16 KB */
target_add_ram(t, 0x20000000, 0x00004000); /* SRAM_H, 16 KB */
kl_gen_add_flash(t, 0x00000000, 0x00040000, 0x800, KL_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
kl_gen_add_flash(t, 0x10000000, 0x00010000, 0x800, KL_WRITE_LEN); /* FlexNVM, 64 KB, 2 KB Sectors */
break;
case 0xb:
t->driver = "MK12DN512Vxx5";
target_add_ram(t, 0x1fff8000, 0x00008000); /* SRAM_L, 32 KB */
target_add_ram(t, 0x20000000, 0x00008000); /* SRAM_H, 32 KB */
kl_gen_add_flash(t, 0x00000000, 0x00040000, 0x800, KL_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
kl_gen_add_flash(t, 0x00040000, 0x00040000, 0x800, KL_WRITE_LEN); /* FlexNVM, 256 KB, 2 KB Sectors */
break;
default:
return false;
}
switch (sdid & 0xff0) {
case 0x000: /* K10 Family, DIEID=0x0 */
case 0x080: /* K10 Family, DIEID=0x1 */
case 0x100: /* K10 Family, DIEID=0x2 */
case 0x180: /* K10 Family, DIEID=0x3 */
case 0x220: /* K11 Family, DIEID=0x4 */
return false;
case 0x200: /* K12 Family, DIEID=0x4 */
switch ((fcfg1 >> 24) & 0x0f) {
/* K12 Sub-Family Reference Manual, K12P80M50SF4RM, Rev. 4, February 2013 */
case 0x7:
t->driver = "MK12DX128Vxx5";
target_add_ram(t, 0x1fffc000, 0x00004000); /* SRAM_L, 16 KB */
target_add_ram(t, 0x20000000, 0x00004000); /* SRAM_H, 16 KB */
kinetis_add_flash(t, 0x00000000, 0x00020000, 0x800, KL_WRITE_LEN); /* P-Flash, 128 KB, 2 KB Sectors */
kinetis_add_flash(t, 0x10000000, 0x00010000, 0x800, KL_WRITE_LEN); /* FlexNVM, 64 KB, 2 KB Sectors */
break;
case 0x9:
t->driver = "MK12DX256Vxx5";
target_add_ram(t, 0x1fffc000, 0x00004000); /* SRAM_L, 16 KB */
target_add_ram(t, 0x20000000, 0x00004000); /* SRAM_H, 16 KB */
kinetis_add_flash(t, 0x00000000, 0x00040000, 0x800, KL_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
kinetis_add_flash(t, 0x10000000, 0x00010000, 0x800, KL_WRITE_LEN); /* FlexNVM, 64 KB, 2 KB Sectors */
break;
case 0xb:
t->driver = "MK12DN512Vxx5";
target_add_ram(t, 0x1fff8000, 0x00008000); /* SRAM_L, 32 KB */
target_add_ram(t, 0x20000000, 0x00008000); /* SRAM_H, 32 KB */
kinetis_add_flash(t, 0x00000000, 0x00040000, 0x800, KL_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
kinetis_add_flash(t, 0x00040000, 0x00040000, 0x800, KL_WRITE_LEN); /* FlexNVM, 256 KB, 2 KB Sectors */
break;
case 0x010: /* K20 Family, DIEID=0x0 */
case 0x090: /* K20 Family, DIEID=0x1 */
case 0x110: /* K20 Family, DIEID=0x2 */
case 0x190: /* K20 Family, DIEID=0x3 */
case 0x230: /* K21 Family, DIEID=0x4 */
case 0x330: /* K21 Family, DIEID=0x6 */
case 0x210: /* K22 Family, DIEID=0x4 */
case 0x310: /* K22 Family, DIEID=0x6 */
case 0x0a0: /* K30 Family, DIEID=0x1 */
case 0x120: /* K30 Family, DIEID=0x2 */
case 0x0b0: /* K40 Family, DIEID=0x1 */
case 0x130: /* K40 Family, DIEID=0x2 */
case 0x0e0: /* K50 Family, DIEID=0x1 */
case 0x0f0: /* K51 Family, DIEID=0x1 */
case 0x170: /* K53 Family, DIEID=0x2 */
case 0x140: /* K60 Family, DIEID=0x2 */
case 0x1c0: /* K60 Family, DIEID=0x3 */
case 0x1d0: /* K70 Family, DIEID=0x3 */
default:
return false;
}
break;
case 0x010: /* K20 Family, DIEID=0x0 */
case 0x090: /* K20 Family, DIEID=0x1 */
case 0x110: /* K20 Family, DIEID=0x2 */
case 0x190: /* K20 Family, DIEID=0x3 */
case 0x230: /* K21 Family, DIEID=0x4 */
case 0x330: /* K21 Family, DIEID=0x6 */
case 0x210: /* K22 Family, DIEID=0x4 */
case 0x310: /* K22 Family, DIEID=0x6 */
case 0x0a0: /* K30 Family, DIEID=0x1 */
case 0x120: /* K30 Family, DIEID=0x2 */
case 0x0b0: /* K40 Family, DIEID=0x1 */
case 0x130: /* K40 Family, DIEID=0x2 */
case 0x0e0: /* K50 Family, DIEID=0x1 */
case 0x0f0: /* K51 Family, DIEID=0x1 */
case 0x170: /* K53 Family, DIEID=0x2 */
case 0x140: /* K60 Family, DIEID=0x2 */
case 0x1c0: /* K60 Family, DIEID=0x3 */
case 0x1d0: /* K70 Family, DIEID=0x3 */
default:
return false;
}
break;
case 0x118: /* S32K118 */
t->driver = "S32K118";
target_add_ram(t, 0x1ffffc00, 0x00000400); /* SRAM_L, 1 KB */
target_add_ram(t, 0x20000000, 0x00005800); /* SRAM_H, 22 KB */
kl_gen_add_flash(t, 0x00000000, 0x00040000, 0x800, K64_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
kl_gen_add_flash(t, 0x10000000, 0x00008000, 0x800, K64_WRITE_LEN); /* FlexNVM, 32 KB, 2 KB Sectors */
target_add_ram(t, 0x1ffffc00, 0x00000400); /* SRAM_L, 1 KB */
target_add_ram(t, 0x20000000, 0x00005800); /* SRAM_H, 22 KB */
kinetis_add_flash(t, 0x00000000, 0x00040000, 0x800, K64_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
kinetis_add_flash(t, 0x10000000, 0x00008000, 0x800, K64_WRITE_LEN); /* FlexNVM, 32 KB, 2 KB Sectors */
break;
/* gen1 s32k14x */
case 0x142: /* S32K142 */
case 0x143: /* S32K142W */
/* SRAM_L = 16KiB */
/* SRAM_H = 12KiB */
/* Flash = 256 KiB */
/* FlexNVM = 64 KiB */
kl_s32k14_setup(t, 0x1FFFC000, 0x03000, 0x00040000, 0x10000);
break;
case 0x144: /* S32K144 */
case 0x145: /* S32K144W */
/* SRAM_L = 32KiB */
/* SRAM_H = 28KiB */
/* Flash = 512 KiB */
/* FlexNVM = 64 KiB */
kl_s32k14_setup(t, 0x1FFF8000, 0x07000, 0x00080000, 0x10000);
break;
case 0x146: /* S32K146 */
/* SRAM_L = 64KiB */
/* SRAM_H = 60KiB */
/* Flash = 1024 KiB */
/* FlexNVM = 64 KiB */
kl_s32k14_setup(t, 0x1fff0000, 0x0f000, 0x00100000, 0x10000);
break;
/* gen1 s32k14x */
{
uint32_t sram_l, sram_h;
uint32_t flash, flexmem;
case 0x142: /* s32k142 */
case 0x143: /* s32k142w */
sram_l = 0x1FFFC000; /* SRAM_L, 16k */
sram_h = 0x03000; /* SRAM_H, 12k */
flash = 0x00040000; /* flash 256 KB */
flexmem = 0x10000; /* FlexNVM 64 KB */
goto do_common_s32k14x;
case 0x144: /* s32k144 */
case 0x145: /* s32k144w */
sram_l = 0x1FFF8000; /* SRAM_L, 32k */
sram_h = 0x07000; /* SRAM_H, 28k */
flash = 0x00080000; /* flash 512 KB */
flexmem = 0x10000; /* FlexNVM 64 KB */
goto do_common_s32k14x;
case 0x146: /* s32k146 */
sram_l = 0x1fff0000; /* SRAM_L, 64k */
sram_h = 0x0f000; /* SRAM_H, 60k */
flash = 0x00100000; /* flash 1024 KB */
flexmem = 0x10000; /* FlexNVM 64 KB */
goto do_common_s32k14x;
case 0x148: /* S32K148 */
sram_l = 0x1ffe0000; /* SRAM_L, 128 KB */
sram_h = 0x1f000; /* SRAM_H, 124 KB */
flash = 0x00180000; /* flash 1536 KB */
flexmem = 0x80000; /* FlexNVM 512 KB */
goto do_common_s32k14x;
do_common_s32k14x:
t->driver = "S32K14x";
target_add_ram(t, sram_l, 0x20000000 - sram_l);
target_add_ram(t, 0x20000000, sram_h);
kl_gen_add_flash(t, 0x00000000, flash, 0x1000, K64_WRITE_LEN); /* P-Flash, 4 KB Sectors */
kl_gen_add_flash(t, 0x10000000, flexmem, 0x1000, K64_WRITE_LEN); /* FlexNVM, 4 KB Sectors */
/* SRAM_L = 128 KiB */
/* SRAM_H = 124 KiB */
/* Flash = 1536 KiB */
/* FlexNVM = 512 KiB */
kl_s32k14_setup(t, 0x1ffe0000, 0x1f000, 0x00180000, 0x80000);
break;
}
default:
return false;
}
@ -372,47 +394,48 @@ do_common_s32k14x:
return true;
}
static bool
kl_gen_command(target *t, uint8_t cmd, uint32_t addr, const uint32_t *data, int n_items)
static bool kinetis_fccob_cmd(target *t, uint8_t cmd, uint32_t addr, const uint32_t *data, int n_items)
{
uint8_t fstat;
/* clear errors unconditionally, so we can start a new operation */
target_mem_write8(t,FTFA_FSTAT,(FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL));
target_mem_write8(t, FTFx_FSTAT, (FTFx_FSTAT_ACCERR | FTFx_FSTAT_FPVIOL));
/* Wait for CCIF to be high */
do {
fstat = target_mem_read8(t, FTFA_FSTAT);
} while (!(fstat & FTFA_FSTAT_CCIF));
fstat = target_mem_read8(t, FTFx_FSTAT);
} while (!(fstat & FTFx_FSTAT_CCIF));
/* Write command to FCCOB */
addr &= 0xffffff;
addr |= (uint32_t)cmd << 24;
target_mem_write32(t, FTFA_FCCOB_0, addr);
if (data) {
target_mem_write32(t, FTFA_FCCOB_1, data[0]);
addr &= 0x00ffffffU;
addr |= cmd << 24U;
target_mem_write32(t, FTFx_FCCOB0, addr);
if (data && n_items) {
target_mem_write32(t, FTFx_FCCOB4, data[0]);
if (n_items > 1)
target_mem_write32(t, FTFA_FCCOB_2, data[1]);
target_mem_write32(t, FTFx_FCCOB8, data[1]);
else
target_mem_write32(t, FTFx_FCCOB8, 0);
}
/* Enable execution by clearing CCIF */
target_mem_write8(t, FTFA_FSTAT, FTFA_FSTAT_CCIF);
target_mem_write8(t, FTFx_FSTAT, FTFx_FSTAT_CCIF);
/* Wait for execution to complete */
do {
fstat = target_mem_read8(t, FTFA_FSTAT);
fstat = target_mem_read8(t, FTFx_FSTAT);
/* Check ACCERR and FPVIOL are zero in FSTAT */
if (fstat & (FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL))
if (fstat & (FTFx_FSTAT_ACCERR | FTFx_FSTAT_FPVIOL))
return false;
} while (!(fstat & FTFA_FSTAT_CCIF));
} while (!(fstat & FTFx_FSTAT_CCIF));
return true;
}
static int kl_gen_flash_erase(struct target_flash *f, target_addr addr, size_t len)
static int kinetis_flash_cmd_erase(struct target_flash *const f, target_addr addr, size_t len)
{
while (len) {
if (kl_gen_command(f->t, FTFA_CMD_ERASE_SECTOR, addr, NULL, 0)) {
if (kinetis_fccob_cmd(f->t, FTFx_CMD_ERASE_SECTOR, addr, NULL, 0)) {
/* Different targets have different flash erase sizes */
if (len > f->blocksize)
len -= f->blocksize;
@ -426,72 +449,60 @@ static int kl_gen_flash_erase(struct target_flash *f, target_addr addr, size_t l
return 0;
}
#define FLASH_SECURITY_BYTE_ADDRESS 0x40C
#define FLASH_SECURITY_BYTE_UNSECURED 0xFE
static int kl_gen_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len)
static int kinetis_flash_cmd_write(struct target_flash *f, target_addr dest, const void *src, size_t len)
{
struct kinetis_flash *kf = (struct kinetis_flash *)f;
struct kinetis_flash *const kf = (struct kinetis_flash *)f;
/* Ensure we don't write something horrible over the security byte */
if (!f->t->unsafe_enabled &&
(dest <= FLASH_SECURITY_BYTE_ADDRESS) &&
((dest + len) > FLASH_SECURITY_BYTE_ADDRESS)) {
((uint8_t*)src)[FLASH_SECURITY_BYTE_ADDRESS - dest] =
FLASH_SECURITY_BYTE_UNSECURED;
if (!f->t->unsafe_enabled && dest <= FLASH_SECURITY_BYTE_ADDRESS && dest + len > FLASH_SECURITY_BYTE_ADDRESS) {
((uint8_t *)src)[FLASH_SECURITY_BYTE_ADDRESS - dest] = FLASH_SECURITY_BYTE_UNSECURED;
}
/* Determine write command based on the alignment. */
uint8_t write_cmd;
if (kf->write_len == K64_WRITE_LEN) {
write_cmd = FTFE_CMD_PROGRAM_PHRASE;
} else {
write_cmd = FTFA_CMD_PROGRAM_LONGWORD;
}
if (kf->write_len == K64_WRITE_LEN)
write_cmd = FTFx_CMD_PROGRAM_PHRASE;
else
write_cmd = FTFx_CMD_PROGRAM_LONGWORD;
while (len) {
if (kl_gen_command(f->t, write_cmd, dest, src, 1)) {
if (kinetis_fccob_cmd(f->t, write_cmd, dest, src, kf->write_len >> 2U)) {
if (len > kf->write_len)
len -= kf->write_len;
else
len = 0;
dest += kf->write_len;
src += kf->write_len;
} else {
} else
return 1;
}
}
return 0;
}
static int kl_gen_flash_done(struct target_flash *f)
static int kinetis_flash_done(struct target_flash *const f)
{
struct kinetis_flash *kf = (struct kinetis_flash *)f;
struct kinetis_flash *const kf = (struct kinetis_flash *)f;
if (f->t->unsafe_enabled)
return 0;
if (target_mem_read8(f->t, FLASH_SECURITY_BYTE_ADDRESS) ==
FLASH_SECURITY_BYTE_UNSECURED)
if (target_mem_read8(f->t, FLASH_SECURITY_BYTE_ADDRESS) == FLASH_SECURITY_BYTE_UNSECURED)
return 0;
/* Load the security byte based on the alignment (determine 8 byte phrases
* vs 4 byte phrases).
*/
if (kf->write_len == 8) {
uint32_t vals[2];
vals[0] = target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS-4);
vals[1] = target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS);
vals[1] = (vals[1] & 0xffffff00) | FLASH_SECURITY_BYTE_UNSECURED;
kl_gen_command(f->t, FTFE_CMD_PROGRAM_PHRASE,
FLASH_SECURITY_BYTE_ADDRESS - 4, vals, 2);
if (kf->write_len == K64_WRITE_LEN) {
uint32_t vals[2] = {
target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS - 4),
target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS)
};
vals[1] = (vals[1] & 0xffffff00U) | FLASH_SECURITY_BYTE_UNSECURED;
kinetis_fccob_cmd(f->t, FTFx_CMD_PROGRAM_PHRASE, FLASH_SECURITY_BYTE_ADDRESS - 4, vals, 2);
} else {
uint32_t vals[1];
vals[0] = target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS);
vals[0] = (vals[0] & 0xffffff00) | FLASH_SECURITY_BYTE_UNSECURED;
kl_gen_command(f->t, FTFA_CMD_PROGRAM_LONGWORD,
FLASH_SECURITY_BYTE_ADDRESS, vals, 1);
uint32_t val = target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS);
val = (val & 0xffffff00U) | FLASH_SECURITY_BYTE_UNSECURED;
kinetis_fccob_cmd(f->t, FTFx_CMD_PROGRAM_LONGWORD, FLASH_SECURITY_BYTE_ADDRESS, &val, 1);
}
return 0;
@ -504,10 +515,6 @@ static int kl_gen_flash_done(struct target_flash *f)
* a backdoor AP is provided which may allow a mass erase to recover the
* device. This provides a fake target to allow a monitor command interface
*/
#include "adiv5.h"
#define KINETIS_MDM_IDR_K22F 0x1c0000
#define KINETIS_MDM_IDR_KZ03 0x1c0020
static bool kinetis_mdm_cmd_erase_mass(target *t, int argc, const char **argv);
static bool kinetis_mdm_cmd_ke04_mode(target *t, int argc, const char **argv);
@ -515,18 +522,19 @@ static bool kinetis_mdm_cmd_ke04_mode(target *t, int argc, const char **argv);
const struct command_s kinetis_mdm_cmd_list[] = {
{"erase_mass", (cmd_handler)kinetis_mdm_cmd_erase_mass, "Erase entire flash memory"},
{"ke04_mode", (cmd_handler)kinetis_mdm_cmd_ke04_mode, "Allow erase for KE04"},
{NULL, NULL, NULL}
{NULL, NULL, NULL},
};
enum target_halt_reason mdm_halt_poll(target *t, target_addr *watch)
enum target_halt_reason mdm_halt_poll(target *t, const target_addr *const watch)
{
(void)t; (void)watch;
(void)t;
(void)watch;
return TARGET_HALT_REQUEST;
}
void kinetis_mdm_probe(ADIv5_AP_t *ap)
{
switch(ap->idr) {
switch (ap->idr) {
case KINETIS_MDM_IDR_KZ03: /* Also valid for KE04, no way to check! */
case KINETIS_MDM_IDR_K22F:
break;
@ -541,23 +549,13 @@ void kinetis_mdm_probe(ADIv5_AP_t *ap)
adiv5_ap_ref(ap);
t->priv = ap;
t->priv_free = (void*)adiv5_ap_unref;
t->priv_free = (void *)adiv5_ap_unref;
t->driver = "Kinetis Recovery (MDM-AP)";
t->regs_size = 4;
target_add_commands(t, kinetis_mdm_cmd_list, t->driver);
}
#define MDM_STATUS ADIV5_AP_REG(0x00)
#define MDM_CONTROL ADIV5_AP_REG(0x04)
#define MDM_STATUS_MASS_ERASE_ACK (1 << 0)
#define MDM_STATUS_FLASH_READY (1 << 1)
#define MDM_STATUS_MASS_ERASE_ENABLED (1 << 5)
#define MDM_CONTROL_MASS_ERASE (1 << 0)
#define MDM_CONTROL_SYS_RESET (1 << 3)
/* This is needed as a separate command, as there's no way to *
* tell a KE04 from other kinetis in kinetis_mdm_probe() */
static bool kinetis_mdm_cmd_ke04_mode(target *t, int argc, const char **argv)
@ -569,6 +567,7 @@ static bool kinetis_mdm_cmd_ke04_mode(target *t, int argc, const char **argv)
tc_printf(t, "Mass erase for KE04 now allowed\n");
return true;
}
static bool kinetis_mdm_cmd_erase_mass(target *t, int argc, const char **argv)
{
(void)argc;
@ -576,13 +575,12 @@ static bool kinetis_mdm_cmd_erase_mass(target *t, int argc, const char **argv)
ADIv5_AP_t *ap = t->priv;
/* Keep the MCU in reset as stated in KL25PxxM48SF0RM */
if(t->ke04_mode)
if (t->ke04_mode)
adiv5_ap_write(ap, MDM_CONTROL, MDM_CONTROL_SYS_RESET);
uint32_t status, control;
status = adiv5_ap_read(ap, MDM_STATUS);
control = adiv5_ap_read(ap, MDM_CONTROL);
tc_printf(t, "Requesting mass erase (status = 0x%"PRIx32")\n", status);
uint32_t status = adiv5_ap_read(ap, MDM_STATUS);
uint32_t control = adiv5_ap_read(ap, MDM_CONTROL);
tc_printf(t, "Requesting mass erase (status = 0x%" PRIx32 ")\n", status);
/* This flag does not exist on KE04 */
if (!(status & MDM_STATUS_MASS_ERASE_ENABLED) && !t->ke04_mode) {

View File

@ -56,7 +56,7 @@ static int stm32f4_flash_erase(struct target_flash *f, target_addr addr,
static int stm32f4_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len);
/* Flash Program ad Erase Controller Register Map */
/* Flash Program and Erase Controller Register Map */
#define FPEC_BASE 0x40023C00
#define FLASH_ACR (FPEC_BASE+0x00)
#define FLASH_KEYR (FPEC_BASE+0x04)
@ -503,11 +503,8 @@ static bool stm32f4_cmd_erase_mass(target *t, int argc, const char **argv)
tc_printf(t, "\n");
/* Check for error */
uint32_t sr = target_mem_read32(t, FLASH_SR);
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP))
return false;
return true;
const uint32_t result = target_mem_read32(t, FLASH_SR);
return !(result & SR_ERROR_MASK);
}
/* Dev | DOC |Rev|ID |OPTCR |OPTCR |OPTCR1 |OPTCR1 | OPTCR2

View File

@ -271,6 +271,11 @@ int target_flash_write(target *t,
dest += tmplen;
src += tmplen;
len -= tmplen;
/* If the current chunk of Flash is now full from this operation
* then finish operations on the Flash chunk and free the internal buffer.
*/
if (dest == f->start + f->length)
ret |= target_flash_done_buffered(f);
}
return ret;
}