Line 36... |
Line 36... |
#include <fcntl.h>
|
#include <fcntl.h>
|
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
#include <poll.h>
|
#include <poll.h>
|
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
#include <string.h>
|
#include <string.h>
|
#include <pthread.h>
|
|
|
|
/* Package includes */
|
/* Package includes */
|
#include "except.h"
|
#include "except.h"
|
#include "spr-defs.h"
|
#include "spr-defs.h"
|
#include "dbg_api.h"
|
#include "dbg_api.h"
|
#include "errcodes.h"
|
#include "errcodes.h"
|
|
#include "hardware_monitor.h"
|
|
|
/* Define to log each packet */
|
/* Define to log each packet */
|
#define RSP_TRACE 0
|
#define RSP_TRACE 0
|
|
|
/*! Name of the RSP service */
|
/*! Name of the RSP service */
|
Line 77... |
Line 77... |
TARGET_SIGNAL_ALRM = 14,
|
TARGET_SIGNAL_ALRM = 14,
|
TARGET_SIGNAL_USR2 = 31,
|
TARGET_SIGNAL_USR2 = 31,
|
TARGET_SIGNAL_PWR = 32
|
TARGET_SIGNAL_PWR = 32
|
};
|
};
|
|
|
/*! The maximum number of characters in inbound/outbound buffers. The largest
|
/*! The maximum number of characters in inbound/outbound buffers.
|
packets are the 'G' packet, which must hold the 'G' and all the registers
|
* The max is 16kB, and larger buffers make for faster
|
with two hex digits per byte and the 'g' reply, which must hold all the
|
* transfer times, so use the max. If your setup is prone
|
registers, and (in our implementation) an end-of-string (0)
|
* to JTAG communication errors, you may want to use a smaller
|
character. Adding the EOS allows us to print out the packet as a
|
* size.
|
string. So at least NUMREGBYTES*2 + 1 (for the 'G' or the EOS) are needed
|
*/
|
for register packets */
|
#define GDB_BUF_MAX (16*1024) // ((NUM_REGS) * 8 + 1)
|
#define GDB_BUF_MAX ((NUM_REGS) * 8 + 1)
|
|
|
|
/*! Size of the matchpoint hash table. Largest prime < 2^10 */
|
/*! Size of the matchpoint hash table. Largest prime < 2^10 */
|
#define MP_HASH_SIZE 1021
|
#define MP_HASH_SIZE 1021
|
|
|
/*! String to map hex digits to chars */
|
/*! String to map hex digits to chars */
|
Line 120... |
Line 119... |
unsigned long int instr; /*!< Substituted instruction */
|
unsigned long int instr; /*!< Substituted instruction */
|
struct mp_entry *next; /*!< Next entry with this hash */
|
struct mp_entry *next; /*!< Next entry with this hash */
|
};
|
};
|
|
|
/* Data to interface the GDB handler thread with the target handler thread */
|
/* Data to interface the GDB handler thread with the target handler thread */
|
pthread_mutex_t rsp_mutex = PTHREAD_MUTEX_INITIALIZER; /*!< Mutex to protect the "target_running" member of the rsp struct */
|
|
pthread_mutex_t target_handler_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
pthread_cond_t target_handler_cond = PTHREAD_COND_INITIALIZER;
|
|
|
|
int target_handler_state = 0;
|
|
pthread_t target_handler_thread;
|
|
void *target_handler(void *arg);
|
|
|
|
int pipe_fds[2]; // Descriptors for the pipe from the poller thread to the GDB interface thread
|
int pipe_fds[2]; // Descriptors for the pipe from the poller thread to the GDB interface thread
|
|
|
// Work-around for the current OR1200 implementation; After setting the NPC,
|
// Work-around for the current OR1200 implementation; After setting the NPC,
|
// it always reads back 0 until the next instruction is executed. This
|
// it always reads back 0 until the next instruction is executed. This
|
// is a problem with the way we handle memory breakpoints (resetting the NPC),
|
// is a problem with the way we handle memory breakpoints (resetting the NPC),
|
Line 228... |
Line 219... |
struct sockaddr_in sock_addr; /* Socket address */
|
struct sockaddr_in sock_addr; /* Socket address */
|
|
|
int optval; /* Socket options */
|
int optval; /* Socket options */
|
int flags; /* Socket flags */
|
int flags; /* Socket flags */
|
char name[256]; /* Our name */
|
char name[256]; /* Our name */
|
unsigned long tmp;
|
|
|
|
|
|
/* Clear out the central data structure */
|
/* Clear out the central data structure */
|
rsp.client_waiting = 0; /* GDB client is not waiting for us */
|
rsp.client_waiting = 0; /* GDB client is not waiting for us */
|
rsp.proto_num = -1; /* i.e. invalid */
|
rsp.proto_num = -1; /* i.e. invalid */
|
Line 355... |
Line 345... |
"%d to %d: %s\n", rsp.server_fd, 1, strerror (errno));
|
"%d to %d: %s\n", rsp.server_fd, 1, strerror (errno));
|
rsp_server_close();
|
rsp_server_close();
|
return;
|
return;
|
}
|
}
|
|
|
// Stall the CPU...it starts off running.
|
|
set_stall_state(1);
|
|
rsp.target_running = 0;
|
|
target_handler_state = 0; // Don't start the polling thread until we have a client
|
|
rsp.single_step_mode = 0;
|
|
|
|
// Set up the CPU to break to the debug unit on exceptions.
|
|
dbg_cpu0_read(SPR_DSR, &tmp);
|
|
dbg_cpu0_write(SPR_DSR, tmp|SPR_DSR_TE|SPR_DSR_FPE|SPR_DSR_RE|SPR_DSR_IIE|SPR_DSR_AE|SPR_DSR_BUSEE);
|
|
|
|
// Enable TRAP exception, but don't otherwise change the SR
|
|
dbg_cpu0_read(SPR_SR, &tmp);
|
|
dbg_cpu0_write(SPR_SR, tmp|SPR_SR_SM); // We set 'supervisor mode', which also enables TRAP exceptions
|
|
|
|
if(0 > pipe(pipe_fds)) { // pipe_fds[0] is for reading, [1] is for writing
|
|
perror("Error creating sockets: ");
|
|
rsp_server_close();
|
|
return;
|
|
}
|
|
|
|
// Create the harware target polling thread
|
|
if(pthread_create(&target_handler_thread, NULL, target_handler, NULL))
|
|
{
|
|
fprintf(stderr, "Failed to create target handler thread!\n");
|
|
rsp_server_close();
|
|
return;
|
|
}
|
|
|
|
} /* rsp_init () */
|
} /* rsp_init () */
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
/*!Look for action on RSP
|
/*!Look for action on RSP
|
Line 413... |
Line 375... |
Polling is always blocking (i.e. timeout -1). */
|
Polling is always blocking (i.e. timeout -1). */
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
int handle_rsp (void)
|
int handle_rsp (void)
|
{
|
{
|
struct pollfd fds[2]; /* The FD to poll for */
|
struct pollfd fds[2]; /* The FD to poll for */
|
char bitbucket;
|
char monitor_status;
|
|
unsigned long drrval;
|
|
|
/* Give up if no RSP server port (this should not occur) */
|
/* Give up if no RSP server port (this should not occur) */
|
if (-1 == rsp.server_fd)
|
if (-1 == rsp.server_fd)
|
{
|
{
|
fprintf (stderr, "Warning: No RSP server port open\n");
|
fprintf (stderr, "Warning: No RSP server port open\n");
|
Line 479... |
Line 442... |
of using a pipe? */
|
of using a pipe? */
|
|
|
fds[0].fd = rsp.client_fd; /* FD for the client socket */
|
fds[0].fd = rsp.client_fd; /* FD for the client socket */
|
fds[0].events = POLLIN; /* Poll for input activity */
|
fds[0].events = POLLIN; /* Poll for input activity */
|
|
|
fds[1].fd = pipe_fds[0];
|
fds[1].fd = pipe_fds[1];
|
fds[1].events = POLLIN;
|
fds[1].events = POLLIN;
|
|
|
/* Poll is always blocking. We can't do anything more until something
|
/* Poll is always blocking. We can't do anything more until something
|
happens here. */
|
happens here. */
|
//fprintf(stderr, "Polling...\n");
|
//fprintf(stderr, "Polling...\n");
|
Line 514... |
Line 477... |
rsp_client_request ();
|
rsp_client_request ();
|
}
|
}
|
else if(POLLIN == (fds[1].revents & POLLIN))
|
else if(POLLIN == (fds[1].revents & POLLIN))
|
{
|
{
|
//fprintf(stderr, "Got pipe event from monitor thread\n");
|
//fprintf(stderr, "Got pipe event from monitor thread\n");
|
bitbucket = read(pipe_fds[0], &bitbucket, 1); // Clear the byte out and discard
|
read(pipe_fds[1], &monitor_status, 1); // Read the monitor status
|
|
// *** TODO: Check return value of read()
|
|
if(monitor_status == 'H')
|
|
{
|
|
if(rsp.target_running) // ignore if a duplicate event
|
|
{
|
|
rsp.target_running = 0;
|
|
// Log the exception so it can be sent back to GDB
|
|
dbg_cpu0_read(SPR_DRR, &drrval); // Read the DRR, find out why we stopped
|
|
rsp_exception(drrval); // Send it to be translated and stored
|
|
|
/* If we have an unacknowledged exception and a client is available, tell
|
/* If we have an unacknowledged exception and a client is available, tell
|
GDB. If this exception was a trap due to a memory breakpoint, then
|
GDB. If this exception was a trap due to a memory breakpoint, then
|
adjust the NPC. */
|
adjust the NPC. */
|
if (rsp.client_waiting)
|
if (rsp.client_waiting)
|
{
|
{
|
Line 534... |
Line 507... |
|
|
rsp_report_exception();
|
rsp_report_exception();
|
rsp.client_waiting = 0; /* No longer waiting */
|
rsp.client_waiting = 0; /* No longer waiting */
|
}
|
}
|
}
|
}
|
|
}
|
|
else if(monitor_status == 'R')
|
|
{
|
|
rsp.target_running = 1;
|
|
// If things are added here, be sure to ignore if this event is a duplicate
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "RSP server got unknown status \'%c\' (0x%X) from target monitor!\n", monitor_status, monitor_status);
|
|
}
|
|
}
|
else
|
else
|
{
|
{
|
/* Error leads to closing the client, but not the server. */
|
/* Error leads to closing the client, but not the server. */
|
fprintf (stderr, "Warning: RSP client received flags "
|
fprintf (stderr, "Warning: RSP client received flags "
|
"0x%08x: closing client connection\n", fds[0].revents);
|
"0x%08x: closing client connection\n", fds[0].revents);
|
Line 616... |
Line 600... |
struct sockaddr_in sock_addr; /* The socket address */
|
struct sockaddr_in sock_addr; /* The socket address */
|
socklen_t len; /* Size of the socket address */
|
socklen_t len; /* Size of the socket address */
|
int fd; /* The client FD */
|
int fd; /* The client FD */
|
int flags; /* fcntl () flags */
|
int flags; /* fcntl () flags */
|
int optval; /* Option value for setsockopt () */
|
int optval; /* Option value for setsockopt () */
|
|
unsigned long tmp;
|
|
|
/* Get the client FD */
|
/* Get the client FD */
|
len = sizeof (sock_addr);
|
len = sizeof (sock_addr);
|
fd = accept (rsp.server_fd, (struct sockaddr *)&sock_addr, &len);
|
fd = accept (rsp.server_fd, (struct sockaddr *)&sock_addr, &len);
|
if (fd < 0)
|
if (fd < 0)
|
Line 680... |
Line 665... |
"RSP client socket %d: %s\n", fd, strerror (errno));
|
"RSP client socket %d: %s\n", fd, strerror (errno));
|
close (fd);
|
close (fd);
|
return;
|
return;
|
}
|
}
|
|
|
|
/* Register for stall/unstall events from the target monitor thread. Also creates pipe
|
|
* for sending stall/unstall command to the target monitor. */
|
|
if(0 > register_with_monitor_thread(pipe_fds)) { // pipe_fds[0] is for writing to monitor, [1] is to read from it
|
|
fprintf(stderr, "RSP server failed to register with monitor thread, exiting");
|
|
rsp_server_close();
|
|
close (fd);
|
|
return;
|
|
}
|
|
|
/* We have a new client socket */
|
/* We have a new client socket */
|
rsp.client_fd = fd;
|
rsp.client_fd = fd;
|
|
|
// Set the hardware polling thread to run
|
/* Now that we have a valid client connection, set up the CPU for GDB
|
// This will cause the poll() to be interrupted next time
|
* Stall the CPU...it starts off running. */
|
pthread_mutex_lock(&target_handler_mutex);
|
set_stall_state(1);
|
target_handler_state = 1;
|
rsp.target_running = 0; // This prevents an initial exception report to GDB (which it's not expecting)
|
pthread_mutex_unlock(&target_handler_mutex);
|
rsp.single_step_mode = 0;
|
|
|
|
/* Set up the CPU to break to the debug unit on exceptions. */
|
|
dbg_cpu0_read(SPR_DSR, &tmp);
|
|
dbg_cpu0_write(SPR_DSR, tmp|SPR_DSR_TE|SPR_DSR_FPE|SPR_DSR_RE|SPR_DSR_IIE|SPR_DSR_AE|SPR_DSR_BUSEE);
|
|
|
|
/* Enable TRAP exception, but don't otherwise change the SR */
|
|
dbg_cpu0_read(SPR_SR, &tmp);
|
|
dbg_cpu0_write(SPR_SR, tmp|SPR_SR_SM); // We set 'supervisor mode', which also enables TRAP exceptions
|
|
|
} /* rsp_server_request () */
|
} /* rsp_server_request () */
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
Line 717... |
Line 719... |
printf ("Packet received %s: %d chars\n", buf->data, buf->len );
|
printf ("Packet received %s: %d chars\n", buf->data, buf->len );
|
fflush (stdout);
|
fflush (stdout);
|
#endif
|
#endif
|
|
|
// Check if target is running.
|
// Check if target is running.
|
int running = 0;
|
|
pthread_mutex_lock(&rsp_mutex);
|
|
running = rsp.target_running;
|
|
pthread_mutex_unlock(&rsp_mutex);
|
|
|
|
// If running, only process async BREAK command
|
// If running, only process async BREAK command
|
if(running)
|
if(rsp.target_running)
|
{
|
{
|
if(buf->data[0] == 0x03) // 0x03 is the ctrl-C "break" command from GDB
|
if(buf->data[0] == 0x03) // 0x03 is the ctrl-C "break" command from GDB
|
{
|
{
|
// Send the STALL command to the target
|
// Send the STALL command to the target
|
set_stall_state (1);
|
set_stall_state (1);
|
Line 932... |
Line 929... |
/*!Close the server if it is open */
|
/*!Close the server if it is open */
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
static void
|
static void
|
rsp_server_close ()
|
rsp_server_close ()
|
{
|
{
|
// Stop the target handler thread
|
|
pthread_mutex_lock(&target_handler_mutex);
|
|
target_handler_state = 2;
|
|
pthread_mutex_unlock(&target_handler_mutex);
|
|
|
|
if (-1 != rsp.server_fd)
|
if (-1 != rsp.server_fd)
|
{
|
{
|
close (rsp.server_fd);
|
close (rsp.server_fd);
|
rsp.server_fd = -1;
|
rsp.server_fd = -1;
|
}
|
}
|
Line 951... |
Line 943... |
/*!Close the client if it is open */
|
/*!Close the client if it is open */
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
static void
|
static void
|
rsp_client_close ()
|
rsp_client_close ()
|
{
|
{
|
unsigned char was_running = 0;
|
|
|
|
// If target is running, stop it so we can modify SPRs
|
// If target is running, stop it so we can modify SPRs
|
pthread_mutex_lock(&rsp_mutex);
|
if(rsp.target_running) {
|
was_running = rsp.target_running;
|
|
pthread_mutex_unlock(&rsp_mutex);
|
|
if(was_running) {
|
|
set_stall_state(1);
|
set_stall_state(1);
|
}
|
}
|
|
|
// Clear the DSR: don't transfer control to the debug unit for any reason
|
// Clear the DSR: don't transfer control to the debug unit for any reason
|
dbg_cpu0_write(SPR_DSR, 0);
|
dbg_cpu0_write(SPR_DSR, 0);
|
|
|
// If target was running, restart it.
|
// If target was running, restart it.
|
if(was_running) {
|
// rsp.target_running is changed in this thread, so it won't have changed due to the above stall command.
|
|
if(rsp.target_running) {
|
set_stall_state(0);
|
set_stall_state(0);
|
}
|
}
|
|
|
// Stop the target handler thread. MUST BE DONE AFTER THE LAST set_stall_state()!
|
// Unregister with the target handler thread. MUST BE DONE AFTER THE LAST set_stall_state()!
|
pthread_mutex_lock(&target_handler_mutex);
|
unregister_with_monitor_thread(pipe_fds);
|
target_handler_state = 0;
|
|
pthread_mutex_unlock(&target_handler_mutex);
|
|
|
|
if (-1 != rsp.client_fd)
|
if (-1 != rsp.client_fd)
|
{
|
{
|
close (rsp.client_fd);
|
close (rsp.client_fd);
|
rsp.client_fd = -1;
|
rsp.client_fd = -1;
|
Line 2819... |
Line 2805... |
} /* rsp_insert_matchpoint () */
|
} /* rsp_insert_matchpoint () */
|
|
|
|
|
// Additions from this point on were added solely to handle hardware,
|
// Additions from this point on were added solely to handle hardware,
|
// and did not come from simulator interface code.
|
// and did not come from simulator interface code.
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Thread to poll for break on remote processor.
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
void *target_handler(void *arg)
|
|
{
|
|
unsigned char target_status = 0;
|
|
int retval = APP_ERR_NONE;
|
|
char string[] = "a"; // We send this through the pipe. Content is unimportant.
|
|
unsigned int local_state = 0;
|
|
|
|
while(1)
|
void set_stall_state(int stall)
|
{
|
|
// Block on condition for GO or DETACH signal
|
|
pthread_mutex_lock(&target_handler_mutex);
|
|
if(target_handler_state == 0)
|
|
{
|
{
|
pthread_cond_wait(&target_handler_cond, &target_handler_mutex);
|
int ret;
|
}
|
|
|
|
// if detach, exit thread
|
if(stall == 0)
|
if(target_handler_state == 2) // 2 = DETACH
|
|
{
|
{
|
target_handler_state = 0;
|
use_cached_npc = 0;
|
pthread_mutex_unlock(&target_handler_mutex);
|
|
return arg;
|
|
}
|
}
|
|
|
local_state = target_handler_state;
|
//fprintf(stderr, "RSP server sending stall command 0x%X\n", stall);
|
pthread_mutex_unlock(&target_handler_mutex);
|
|
|
|
|
|
|
// Actually start or stop the CPU hardware
|
|
if(stall) ret = write(pipe_fds[0], "S", 1);
|
|
else ret = write(pipe_fds[0], "U", 1);
|
|
|
if(local_state == 1) // Then start target polling loop, but keep checking for DETACH. State 1 == GO
|
|
{
|
|
while(1)
|
|
{
|
|
// non-blocking check for DETACH signal
|
|
pthread_mutex_lock(&target_handler_mutex);
|
|
if(target_handler_state == 2) // state 2 == DETACH
|
|
{
|
|
pthread_mutex_unlock(&target_handler_mutex);
|
|
return arg;
|
|
}
|
|
pthread_mutex_unlock(&target_handler_mutex);
|
|
|
|
// Poll target hardware
|
|
retval = dbg_cpu0_read_ctrl(0, &target_status);
|
|
if(retval != APP_ERR_NONE)
|
|
fprintf(stderr, "ERROR 0x%X while polling target CPU status\n", retval);
|
|
else {
|
|
if(target_status & 0x01) // Did we get the stall bit? Bit 0 is STALL bit.
|
|
{
|
|
// clear the RUNNING flag
|
|
pthread_mutex_lock(&rsp_mutex);
|
|
rsp.target_running = 0;
|
|
pthread_mutex_unlock(&rsp_mutex);
|
|
|
|
// Log the exception so it can be sent back to GDB
|
|
unsigned long drrval;
|
|
dbg_cpu0_read(SPR_DRR, &drrval); // Read the DRR, find out why we stopped
|
|
rsp_exception(drrval); // Send it to be translated and stored
|
|
|
|
// Send message to GDB handler thread via socket (so it can break out of its poll())
|
|
int ret = write(pipe_fds[1], string, 1);
|
|
if(!ret) {
|
if(!ret) {
|
fprintf(stderr, "Warning: target monitor write() to pipe returned 0\n");
|
fprintf(stderr, "Warning: target monitor write() to pipe returned 0\n");
|
}
|
}
|
else if(ret < 0) {
|
else if(ret < 0) {
|
perror("Error in target monitor write to pipe: ");
|
perror("Error in target monitor write to pipe");
|
}
|
|
|
|
// Set our own state back to STOP
|
|
pthread_mutex_lock(&target_handler_mutex);
|
|
target_handler_state = 0;
|
|
pthread_mutex_unlock(&target_handler_mutex);
|
|
|
|
break; // Stop polling, block on the next GO/DETACH
|
|
}
|
|
}
|
|
|
|
usleep(250000); // wait 1/4 second before polling again.
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
fprintf(stderr, "Unknown command 0x%X received by target handler thread\n", local_state);
|
|
pthread_mutex_lock(&target_handler_mutex); // Set our own state back to STOP
|
|
target_handler_state = 0;
|
|
pthread_mutex_unlock(&target_handler_mutex);
|
|
}
|
|
}
|
|
|
|
return arg;
|
|
}
|
|
|
|
|
|
|
|
|
|
void set_stall_state(int stall)
|
|
{
|
|
int retval = 0;
|
|
unsigned char data = (stall>0)? 1:0;
|
|
unsigned char stalled = 0;
|
|
|
|
// Set the 'running' variable, if necessary. Do this before actually starting the CPU.
|
|
// The 'running' variable prevents us from responding to most GDB requests while the
|
|
// CPU is running.
|
|
// We don't ever set the 'running' bit to 0 here. Instead, we stall the CPU hardware, and let
|
|
// the target handler thread detect the stall, then signal us to send a message up to
|
|
// GDB and clear the 'running' bit.
|
|
if(stall == 0)
|
|
{
|
|
use_cached_npc = 0;
|
|
pthread_mutex_lock(&rsp_mutex);
|
|
rsp.target_running = 1;
|
|
pthread_mutex_unlock(&rsp_mutex);
|
|
}
|
|
|
|
// Actually start or stop the CPU hardware
|
|
retval = dbg_cpu0_write_ctrl(0, data); // 0x01 is the STALL command bit
|
|
if(retval != APP_ERR_NONE)
|
|
fprintf(stderr, "ERROR 0x%X sending async STALL to target.\n", retval);
|
|
|
|
dbg_cpu0_read_ctrl(0, &stalled);
|
|
/*
|
|
if (!(stalled & 0x1)) {
|
|
printf("or1k is not stalled!\n");
|
|
}
|
|
|
|
fprintf(stderr, "Set STALL to %i\n", data);
|
|
*/
|
|
|
|
// Wake up the target handler thread to poll for a new STALL
|
|
if(stall == 0)
|
|
{
|
|
pthread_mutex_lock(&target_handler_mutex);
|
|
target_handler_state = 1;
|
|
pthread_cond_signal(&target_handler_cond);
|
|
pthread_mutex_unlock(&target_handler_mutex);
|
|
}
|
}
|
|
|
return;
|
return;
|
}
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|