Move semihosting support to cortexm.c.
Try to implement more syscalls.
This commit is contained in:
parent
aca421d0bb
commit
5020d1f05d
159
src/cortexm.c
159
src/cortexm.c
|
@ -204,6 +204,9 @@ static int cortexm_check_hw_wp(struct target_s *target, uint32_t *addr);
|
||||||
#define CORTEXM_MAX_WATCHPOINTS 4 /* architecture says up to 15, no implementation has > 4 */
|
#define CORTEXM_MAX_WATCHPOINTS 4 /* architecture says up to 15, no implementation has > 4 */
|
||||||
#define CORTEXM_MAX_BREAKPOINTS 6 /* architecture says up to 127, no implementation has > 6 */
|
#define CORTEXM_MAX_BREAKPOINTS 6 /* architecture says up to 127, no implementation has > 6 */
|
||||||
|
|
||||||
|
static int cortexm_hostio_request(target *t);
|
||||||
|
static void cortexm_hostio_reply(target *t, int32_t retcode, uint32_t errcode);
|
||||||
|
|
||||||
struct cortexm_priv {
|
struct cortexm_priv {
|
||||||
bool stepping;
|
bool stepping;
|
||||||
bool on_bkpt;
|
bool on_bkpt;
|
||||||
|
@ -219,6 +222,10 @@ struct cortexm_priv {
|
||||||
unsigned hw_breakpoint_max;
|
unsigned hw_breakpoint_max;
|
||||||
/* Copy of DEMCR for vector-catch */
|
/* Copy of DEMCR for vector-catch */
|
||||||
uint32_t demcr;
|
uint32_t demcr;
|
||||||
|
/* Semihosting state */
|
||||||
|
uint32_t syscall;
|
||||||
|
uint32_t errno;
|
||||||
|
uint32_t byte_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Register number tables */
|
/* Register number tables */
|
||||||
|
@ -335,6 +342,8 @@ cortexm_probe(struct target_s *target)
|
||||||
target->halt_resume = cortexm_halt_resume;
|
target->halt_resume = cortexm_halt_resume;
|
||||||
target->regs_size = sizeof(regnum_cortex_m);
|
target->regs_size = sizeof(regnum_cortex_m);
|
||||||
|
|
||||||
|
target->hostio_reply = cortexm_hostio_reply;
|
||||||
|
|
||||||
target_add_commands(target, cortexm_cmd_list, cortexm_driver_str);
|
target_add_commands(target, cortexm_cmd_list, cortexm_driver_str);
|
||||||
|
|
||||||
/* Probe for FP extension */
|
/* Probe for FP extension */
|
||||||
|
@ -595,6 +604,23 @@ cortexm_halt_wait(struct target_s *target)
|
||||||
|
|
||||||
/* Remember if we stopped on a breakpoint */
|
/* Remember if we stopped on a breakpoint */
|
||||||
priv->on_bkpt = dfsr & (CORTEXM_DFSR_BKPT);
|
priv->on_bkpt = dfsr & (CORTEXM_DFSR_BKPT);
|
||||||
|
if (priv->on_bkpt) {
|
||||||
|
/* If we've hit a programmed breakpoint, check for semihosting
|
||||||
|
* call. */
|
||||||
|
uint32_t pc = cortexm_pc_read(target);
|
||||||
|
uint16_t bkpt_instr;
|
||||||
|
target_mem_read_bytes(target, (uint8_t *)&bkpt_instr, pc, 2);
|
||||||
|
if (bkpt_instr == 0xBEAB) {
|
||||||
|
int n = cortexm_hostio_request(target);
|
||||||
|
if (n > 0) {
|
||||||
|
target_halt_resume(target, priv->stepping);
|
||||||
|
return 0;
|
||||||
|
} else if (n < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (dfsr & (CORTEXM_DFSR_BKPT | CORTEXM_DFSR_DWTTRAP))
|
if (dfsr & (CORTEXM_DFSR_BKPT | CORTEXM_DFSR_DWTTRAP))
|
||||||
return SIGTRAP;
|
return SIGTRAP;
|
||||||
|
|
||||||
|
@ -861,3 +887,136 @@ static bool cortexm_vector_catch(target *t, int argc, char *argv[])
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Semihosting support */
|
||||||
|
/* ARM Semihosting syscall numbers, from ARM doc DUI0471C, Chapter 8 */
|
||||||
|
#define SYS_CLOSE 0x02
|
||||||
|
#define SYS_CLOCK 0x10
|
||||||
|
#define SYS_ELAPSED 0x30
|
||||||
|
#define SYS_ERRNO 0x13
|
||||||
|
#define SYS_FLEN 0x0C
|
||||||
|
#define SYS_GET_CMDLINE 0x15
|
||||||
|
#define SYS_HEAPINFO 0x16
|
||||||
|
#define SYS_ISERROR 0x08
|
||||||
|
#define SYS_ISTTY 0x09
|
||||||
|
#define SYS_OPEN 0x01
|
||||||
|
#define SYS_READ 0x06
|
||||||
|
#define SYS_READC 0x07
|
||||||
|
#define SYS_REMOVE 0x0E
|
||||||
|
#define SYS_RENAME 0x0F
|
||||||
|
#define SYS_SEEK 0x0A
|
||||||
|
#define SYS_SYSTEM 0x12
|
||||||
|
#define SYS_TICKFREQ 0x31
|
||||||
|
#define SYS_TIME 0x11
|
||||||
|
#define SYS_TMPNAM 0x0D
|
||||||
|
#define SYS_WRITE 0x05
|
||||||
|
#define SYS_WRITEC 0x03
|
||||||
|
#define SYS_WRITE0 0x04
|
||||||
|
|
||||||
|
#define FILEIO_O_RDONLY 0
|
||||||
|
#define FILEIO_O_WRONLY 1
|
||||||
|
#define FILEIO_O_RDWR 2
|
||||||
|
#define FILEIO_O_APPEND 0x008
|
||||||
|
#define FILEIO_O_CREAT 0x200
|
||||||
|
#define FILEIO_O_TRUNC 0x400
|
||||||
|
|
||||||
|
#define FILEIO_SEEK_SET 0
|
||||||
|
#define FILEIO_SEEK_CUR 1
|
||||||
|
#define FILEIO_SEEK_END 2
|
||||||
|
|
||||||
|
static int cortexm_hostio_request(target *t)
|
||||||
|
{
|
||||||
|
ADIv5_AP_t *ap = adiv5_target_ap(t);
|
||||||
|
struct cortexm_priv *priv = ap->priv;
|
||||||
|
uint32_t arm_regs[t->regs_size];
|
||||||
|
uint32_t params[4];
|
||||||
|
|
||||||
|
target_regs_read(t, arm_regs);
|
||||||
|
target_mem_read_words(t, params, arm_regs[1], sizeof(params));
|
||||||
|
priv->syscall = arm_regs[0];
|
||||||
|
|
||||||
|
DEBUG("syscall 0x%x (%x %x %x %x)\n", priv->syscall,
|
||||||
|
params[0], params[1], params[2], params[3]);
|
||||||
|
switch (priv->syscall) {
|
||||||
|
case SYS_OPEN:{ /* open */
|
||||||
|
/* Translate stupid fopen modes to open flags.
|
||||||
|
* See DUI0471C, Table 8-3 */
|
||||||
|
const uint32_t flags[] = {
|
||||||
|
FILEIO_O_RDONLY, /* r, rb */
|
||||||
|
FILEIO_O_RDWR, /* r+, r+b */
|
||||||
|
FILEIO_O_WRONLY | FILEIO_O_CREAT | FILEIO_O_TRUNC,/*w*/
|
||||||
|
FILEIO_O_RDWR | FILEIO_O_CREAT | FILEIO_O_TRUNC,/*w+*/
|
||||||
|
FILEIO_O_WRONLY | FILEIO_O_CREAT | FILEIO_O_APPEND,/*a*/
|
||||||
|
FILEIO_O_RDWR | FILEIO_O_CREAT | FILEIO_O_APPEND,/*a+*/
|
||||||
|
};
|
||||||
|
gdb_putpacket_f("Fopen,%08X/%X,%08X,%08X",
|
||||||
|
params[0], params[2] + 1,
|
||||||
|
flags[params[1] >> 1], 0644);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SYS_CLOSE: /* close */
|
||||||
|
gdb_putpacket_f("Fclose,%08X", params[0]);
|
||||||
|
break;
|
||||||
|
case SYS_READ: /* read */
|
||||||
|
priv->byte_count = params[2];
|
||||||
|
gdb_putpacket_f("Fread,%08X,%08X,%08X",
|
||||||
|
params[0], params[1], params[2]);
|
||||||
|
break;
|
||||||
|
case SYS_WRITE: /* write */
|
||||||
|
priv->byte_count = params[2];
|
||||||
|
gdb_putpacket_f("Fwrite,%08X,%08X,%08X",
|
||||||
|
params[0], params[1], params[2]);
|
||||||
|
break;
|
||||||
|
case SYS_ISTTY: /* isatty */
|
||||||
|
gdb_putpacket_f("Fisatty,%08X", params[0]);
|
||||||
|
break;
|
||||||
|
case SYS_SEEK: /* lseek */
|
||||||
|
gdb_putpacket_f("Flseek,%08X,%08X,%08X",
|
||||||
|
params[0], params[1], FILEIO_SEEK_SET);
|
||||||
|
break;
|
||||||
|
case SYS_RENAME:/* rename */
|
||||||
|
gdb_putpacket_f("Frename,%08X/%X,%08X/%X",
|
||||||
|
params[0], params[1] + 1,
|
||||||
|
params[2], params[3] + 1);
|
||||||
|
break;
|
||||||
|
case SYS_REMOVE:/* unlink */
|
||||||
|
gdb_putpacket_f("Funlink,%08X/%X", params[0], params[1] + 1);
|
||||||
|
break;
|
||||||
|
case SYS_SYSTEM:/* system */
|
||||||
|
gdb_putpacket_f("Fsystem,%08X/%X", params[0], params[1] + 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SYS_FLEN: /* Not supported, fake success */
|
||||||
|
priv->errno = 0;
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case SYS_ERRNO: /* Return last errno from GDB */
|
||||||
|
arm_regs[0] = priv->errno;
|
||||||
|
target_regs_write(t, arm_regs);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case SYS_TIME: /* gettimeofday */
|
||||||
|
/* FIXME How do we use gdb's gettimeofday? */
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cortexm_hostio_reply(target *t, int32_t retcode, uint32_t errcode)
|
||||||
|
{
|
||||||
|
ADIv5_AP_t *ap = adiv5_target_ap(t);
|
||||||
|
struct cortexm_priv *priv = ap->priv;
|
||||||
|
uint32_t arm_regs[t->regs_size];
|
||||||
|
|
||||||
|
DEBUG("syscall return ret=%d errno=%d\n", retcode, errcode);
|
||||||
|
target_regs_read(t, arm_regs);
|
||||||
|
if (((priv->syscall == SYS_READ) || (priv->syscall == SYS_WRITE)) &&
|
||||||
|
(retcode > 0))
|
||||||
|
retcode = priv->byte_count - retcode;
|
||||||
|
arm_regs[0] = retcode;
|
||||||
|
target_regs_write(t, arm_regs);
|
||||||
|
priv->errno = errcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,6 @@ gdb_main(void)
|
||||||
int size;
|
int size;
|
||||||
bool single_step = false;
|
bool single_step = false;
|
||||||
char last_activity = 0;
|
char last_activity = 0;
|
||||||
uint32_t semihost_read_bytes = 0;
|
|
||||||
|
|
||||||
DEBUG("Entring GDB protocol main loop\n");
|
DEBUG("Entring GDB protocol main loop\n");
|
||||||
/* GDB protocol main loop */
|
/* GDB protocol main loop */
|
||||||
|
@ -161,6 +160,7 @@ gdb_main(void)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
last_activity = pbuf[0];
|
||||||
/* Wait for target halt */
|
/* Wait for target halt */
|
||||||
while(!(sig = target_halt_wait(cur_target))) {
|
while(!(sig = target_halt_wait(cur_target))) {
|
||||||
unsigned char c = gdb_if_getchar_to(0);
|
unsigned char c = gdb_if_getchar_to(0);
|
||||||
|
@ -171,42 +171,9 @@ gdb_main(void)
|
||||||
}
|
}
|
||||||
SET_RUN_STATE(0);
|
SET_RUN_STATE(0);
|
||||||
|
|
||||||
uint32_t arm_regs[cur_target->regs_size];
|
/* Negative signal indicates we're in a syscall */
|
||||||
uint32_t semihost_buf[4];
|
if (sig < 0)
|
||||||
target_regs_read(cur_target, arm_regs);
|
break;
|
||||||
target_mem_read_bytes(cur_target, (uint8_t *)semihost_buf, arm_regs[15], 2);
|
|
||||||
/* Is this a semihosting breakpoint? */
|
|
||||||
if ((semihost_buf[0] & 0xFFFF) == 0xBEAB) {
|
|
||||||
last_activity = pbuf[0];
|
|
||||||
semihost_read_bytes = 0;
|
|
||||||
target_mem_read_words(cur_target, semihost_buf, arm_regs[1], sizeof(semihost_buf));
|
|
||||||
|
|
||||||
switch (arm_regs[0]) {
|
|
||||||
case 0x09: /* SYS_ISTTY */
|
|
||||||
arm_regs[0] = 1; /* it's a tty */
|
|
||||||
target_regs_write(cur_target, arm_regs);
|
|
||||||
/* fall-through */
|
|
||||||
case 0x01: /* SYS_OPEN */
|
|
||||||
case 0x0C: /* SYS_FLEN */
|
|
||||||
/* pretend it's successful, r0 is non-zero already */
|
|
||||||
goto continue_activity;
|
|
||||||
case 0x13: /* SYS_ERRNO */
|
|
||||||
arm_regs[0] = 4; /* EINTR */
|
|
||||||
target_regs_write(cur_target, arm_regs);
|
|
||||||
goto continue_activity;
|
|
||||||
case 0x05: /* SYS_WRITE */
|
|
||||||
gdb_putpacket_f("Fwrite,1,%08X,%08X",
|
|
||||||
semihost_buf[1], semihost_buf[2]);
|
|
||||||
arm_regs[0] = 0; /* pretend it's always successful */
|
|
||||||
target_regs_write(cur_target, arm_regs);
|
|
||||||
continue;
|
|
||||||
case 0x06: /* SYS_READ */
|
|
||||||
gdb_putpacket_f("Fread,0,%08X,%08X",
|
|
||||||
semihost_buf[1], semihost_buf[2]);
|
|
||||||
semihost_read_bytes = semihost_buf[2];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Report reason for halt */
|
/* Report reason for halt */
|
||||||
if(target_check_hw_wp(cur_target, &watch_addr)) {
|
if(target_check_hw_wp(cur_target, &watch_addr)) {
|
||||||
|
@ -218,23 +185,17 @@ gdb_main(void)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'F': { /* Semihosting call finished */
|
case 'F': { /* Semihosting call finished */
|
||||||
int bytes, errcode, items;
|
int retcode, errcode, items;
|
||||||
char c, *p;
|
char c, *p;
|
||||||
if (pbuf[1] == '-')
|
if (pbuf[1] == '-')
|
||||||
p = &pbuf[2];
|
p = &pbuf[2];
|
||||||
else
|
else
|
||||||
p = &pbuf[1];
|
p = &pbuf[1];
|
||||||
items = sscanf(p, "%x,%x,%c", &bytes, &errcode, &c);
|
items = sscanf(p, "%x,%x,%c", &retcode, &errcode, &c);
|
||||||
|
if (pbuf[1] == '-')
|
||||||
|
retcode = -retcode;
|
||||||
|
|
||||||
if (semihost_read_bytes) {
|
target_hostio_reply(cur_target, retcode, errcode);
|
||||||
uint32_t arm_regs[cur_target->regs_size];
|
|
||||||
target_regs_read(cur_target, arm_regs);
|
|
||||||
if (items == 3 && c == 'C')
|
|
||||||
arm_regs[0] = -1;
|
|
||||||
else
|
|
||||||
arm_regs[0] = semihost_read_bytes - bytes;
|
|
||||||
target_regs_write(cur_target, arm_regs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if break is requested */
|
/* if break is requested */
|
||||||
if (items == 3 && c == 'C') {
|
if (items == 3 && c == 'C') {
|
||||||
|
|
|
@ -116,6 +116,10 @@ target *target_attach(target *t, target_destroy_callback destroy_cb);
|
||||||
#define target_flash_write(target, dest, src, len) \
|
#define target_flash_write(target, dest, src, len) \
|
||||||
(target)->flash_write((target), (dest), (src), (len))
|
(target)->flash_write((target), (dest), (src), (len))
|
||||||
|
|
||||||
|
/* Host I/O */
|
||||||
|
#define target_hostio_reply(target, recode, errcode) \
|
||||||
|
(target)->hostio_reply((target), (retcode), (errcode))
|
||||||
|
|
||||||
|
|
||||||
struct target_s {
|
struct target_s {
|
||||||
/* Notify controlling debugger if target is lost */
|
/* Notify controlling debugger if target is lost */
|
||||||
|
@ -171,6 +175,9 @@ struct target_s {
|
||||||
int (*flash_write)(struct target_s *target, uint32_t dest,
|
int (*flash_write)(struct target_s *target, uint32_t dest,
|
||||||
const uint8_t *src, int len);
|
const uint8_t *src, int len);
|
||||||
|
|
||||||
|
/* Host I/O support */
|
||||||
|
void (*hostio_reply)(target *t, int32_t retcode, uint32_t errcode);
|
||||||
|
|
||||||
const char *driver;
|
const char *driver;
|
||||||
struct target_command_s *commands;
|
struct target_command_s *commands;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue