Merge commit '5cd430647ecfb6dab4a2ed858fb98567723de699' into stable
This commit is contained in:
commit
8fc7a559b2
@ -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);
|
||||
}
|
||||
|
||||
|
238
src/gdb_main.c
238
src/gdb_main.c
@ -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);
|
||||
|
@ -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, ...)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user