Line 65... |
Line 65... |
int hwp_server_running = 0;
|
int hwp_server_running = 0;
|
int hwp_target_is_running = 0;
|
int hwp_target_is_running = 0;
|
int use_cached_dmr2 = 0;
|
int use_cached_dmr2 = 0;
|
uint32_t cached_dmr2 = 0;
|
uint32_t cached_dmr2 = 0;
|
|
|
|
/* To track which watchpoints are in use by an external program,
|
|
* so that the RSP server can have the unused ones for GDB
|
|
*/
|
|
#define HWP_MAX_WP 8
|
|
unsigned char hwp_in_use[HWP_MAX_WP];
|
|
|
/*! String to map hex digits to chars */
|
/*! String to map hex digits to chars */
|
static const char hexchars[]="0123456789abcdef";
|
static const char hexchars[]="0123456789abcdef";
|
|
|
pthread_t hwp_server_thread;
|
pthread_t hwp_server_thread;
|
void *hwp_server(void *arg);
|
void *hwp_server(void *arg);
|
Line 87... |
Line 93... |
unsigned long int hwp_hex2reg (char *buf);
|
unsigned long int hwp_hex2reg (char *buf);
|
void hwp_reg2hex (unsigned long int val, char *buf);
|
void hwp_reg2hex (unsigned long int val, char *buf);
|
int hwp_hex(int c);
|
int hwp_hex(int c);
|
void hwp_report_run(void);
|
void hwp_report_run(void);
|
void hwp_report_stop(void);
|
void hwp_report_stop(void);
|
|
void hwp_set_in_use(unsigned int wp, unsigned char inuse);
|
|
|
/*----------------------------------------------------------*/
|
/*----------------------------------------------------------*/
|
/* Public API */
|
/* Public API */
|
/*----------------------------------------------------------*/
|
/*----------------------------------------------------------*/
|
|
|
Line 100... |
Line 107... |
struct addrinfo hints;
|
struct addrinfo hints;
|
struct addrinfo *servinfo; // will point to the results of getaddrinfo
|
struct addrinfo *servinfo; // will point to the results of getaddrinfo
|
int optval; /* Socket options */
|
int optval; /* Socket options */
|
char portnum[6]; /* portNum as a string */
|
char portnum[6]; /* portNum as a string */
|
void *addr;
|
void *addr;
|
|
int i, errcode;
|
|
uint32_t regaddr, tmp;
|
|
|
debug("HWP Server initializing\n");
|
debug("HWP Server initializing\n");
|
|
|
|
/* First thing's first: Check if there are any HWP.
|
|
* Read all DCR, mark which are present.*/
|
|
status = 0;
|
|
for(i = 0; i < HWP_MAX_WP; i++)
|
|
{
|
|
regaddr = SPR_DCR(i);
|
|
errcode = dbg_cpu0_read(regaddr, &tmp);
|
|
if(errcode != APP_ERR_NONE)
|
|
{
|
|
fprintf(stderr, "ERROR reading DCR %i at startup! %s\n", i, get_err_string(errcode));
|
|
hwp_set_in_use(i, 1);
|
|
}
|
|
else
|
|
{
|
|
if(tmp & 0x1) /* HWP present */
|
|
{
|
|
hwp_set_in_use(i, 0);
|
|
status++;
|
|
}
|
|
else /* HWP not implemented */
|
|
{
|
|
hwp_set_in_use(i, 1);
|
|
}
|
|
}
|
|
debug("HWP %i is %s\n", i, hwp_in_use[i] ? "absent":"present");
|
|
}
|
|
|
|
if(status > 0)
|
|
{
|
|
fprintf(stderr, "HWP server initializing with %i watchpoints available\n", status);
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "No watchpoint hardware found, HWP server not starting\n");
|
|
}
|
|
|
|
/* We have watchpoint hardware. Initialize the server. */
|
hwp_server_fd = -1;
|
hwp_server_fd = -1;
|
hwp_client_fd = -1;
|
hwp_client_fd = -1;
|
hwp_portnum = portNum;
|
hwp_portnum = portNum;
|
|
|
memset(portnum, '\0', sizeof(portnum));
|
memset(portnum, '\0', sizeof(portnum));
|
Line 722... |
Line 768... |
void hwp_write_reg (struct rsp_buf *buf)
|
void hwp_write_reg (struct rsp_buf *buf)
|
{
|
{
|
unsigned int regnum;
|
unsigned int regnum;
|
char valstr[9]; /* Allow for EOS on the string */
|
char valstr[9]; /* Allow for EOS on the string */
|
unsigned int errcode = APP_ERR_NONE;
|
unsigned int errcode = APP_ERR_NONE;
|
|
int dcridx;
|
|
uint32_t val, cc, ct;
|
|
|
/* Break out the fields from the data */
|
/* Break out the fields from the data */
|
if (2 != sscanf (buf->data, "P%x=%8s", ®num, valstr))
|
if (2 != sscanf (buf->data, "P%x=%8s", ®num, valstr))
|
{
|
{
|
fprintf (stderr, "Warning: Failed to recognize RSP write register command: %s\n", buf->data);
|
fprintf (stderr, "Warning: Failed to recognize RSP write register command: %s\n", buf->data);
|
Line 733... |
Line 781... |
return;
|
return;
|
}
|
}
|
|
|
/* Set the relevant register. We assume that the client is not
|
/* Set the relevant register. We assume that the client is not
|
* GDB, and no register number translation is needed. */
|
* GDB, and no register number translation is needed. */
|
errcode = dbg_cpu0_write(regnum, hwp_hex2reg(valstr));
|
val = hwp_hex2reg(valstr);
|
|
errcode = dbg_cpu0_write(regnum, val);
|
|
|
if(errcode == APP_ERR_NONE) {
|
if(errcode == APP_ERR_NONE) {
|
debug("Wrote reg 0x%X with val 0x%X (%s)\n", regnum, hwp_hex2reg(valstr), valstr);
|
debug("Wrote reg 0x%X with val 0x%X (%s)\n", regnum, hwp_hex2reg(valstr), valstr);
|
hwp_put_str_packet (hwp_client_fd, "OK");
|
hwp_put_str_packet (hwp_client_fd, "OK");
|
}
|
}
|
else {
|
else {
|
fprintf(stderr, "Error writing register: %s\n", get_err_string(errcode));
|
fprintf(stderr, "Error writing register: %s\n", get_err_string(errcode));
|
hwp_put_str_packet(hwp_client_fd, "E01");
|
hwp_put_str_packet(hwp_client_fd, "E01");
|
}
|
}
|
|
|
|
/* A bit of hackery: Determine if this write enables a comparison on a DCR.
|
|
* If so, then we mark this HWP as in use, so that GDB/RSP cannot use it.
|
|
* Note that there's no point making the HWP client check which watchpoints are in
|
|
* use - GDB only sets HWP as it is starting the CPU, and clears them
|
|
* immediately after a stop. So as far as the HWP client would see, GDB/RSP
|
|
* never uses any watchpoints.
|
|
*/
|
|
|
|
if((regnum >= SPR_DCR(0)) && (regnum <= SPR_DCR(7)))
|
|
{
|
|
dcridx = regnum - SPR_DCR(0);
|
|
/* If the 'compare condition' (cc) or 'compare to' (ct) are 0,
|
|
* then matching is disabled and we can mark this HWP not in use.
|
|
*/
|
|
cc = val & 0x0E;
|
|
ct = val & 0xE0;
|
|
if ((cc == 0) || (ct == 0))
|
|
hwp_set_in_use(dcridx, 0);
|
|
else
|
|
hwp_set_in_use(dcridx, 1);
|
|
}
|
|
|
} /* hwp_write_reg() */
|
} /* hwp_write_reg() */
|
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
/*!Convenience to put a constant string packet
|
/*!Convenience to put a constant string packet
|
|
|
Line 922... |
Line 993... |
|
|
hwp_put_packet(hwp_client_fd, &buf);
|
hwp_put_packet(hwp_client_fd, &buf);
|
|
|
} /* hwp_report_run() */
|
} /* hwp_report_run() */
|
|
|
|
/* Used by the HWP server to indicate which HWP are
|
|
* in long-term use by an external client
|
|
*/
|
|
void hwp_set_in_use(unsigned int wp, unsigned char inuse)
|
|
{
|
|
if(wp < HWP_MAX_WP)
|
|
{
|
|
hwp_in_use[wp] = inuse;
|
|
debug("HWP setting wp %i status to %i\n", wp, inuse);
|
|
}
|
|
else
|
|
fprintf(stderr, "ERROR! value %i out of range when setting HWP in use!\n", wp);
|
|
}
|
|
|
|
/* Called by the RSP server to get any one unused HWP.
|
|
* This will only be called immediately before a 'step'
|
|
* or 'continue,' and the HWP will be disabled as soon
|
|
* as the CPU returns control to the RSP server.
|
|
* Returns -1 if no HWP available.
|
|
*/
|
|
int hwp_get_available_watchpoint(void)
|
|
{
|
|
int i;
|
|
int ret = -1;
|
|
|
|
for(i = 0; i < HWP_MAX_WP; i++)
|
|
{
|
|
if(hwp_in_use[i] == 0)
|
|
{
|
|
ret = i;
|
|
hwp_in_use[i] = 1;
|
|
|
|
break;
|
|
}
|
|
}
|
|
debug("HWP granting wp %i to GDB/RSP\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Called by the RSP server to indicate it is no longer
|
|
* using a watchpoint previously granted by
|
|
* hwp_get_available_watchpoint()
|
|
*/
|
|
void hwp_return_watchpoint(int wp)
|
|
{
|
|
if(wp >= HWP_MAX_WP)
|
|
{
|
|
fprintf(stderr, "ERROR! WP value %i out of range in hwp_return_watchpoint()!\n", wp);
|
|
}
|
|
else
|
|
{
|
|
if(hwp_in_use[wp] != 0)
|
|
{
|
|
hwp_in_use[wp] = 0;
|
|
debug("HWP got wp %i back from GDB/RSP\n", wp);
|
|
}
|
|
else
|
|
fprintf(stderr, "ERROR! hwp_return_watchpoint() returning wp %i, not in use!\n", wp);
|
|
}
|
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|