3793 lines
106 KiB
C
3793 lines
106 KiB
C
/*
|
|
******************************************************************************
|
|
******************************************************************************
|
|
*
|
|
* COPYRIGHT (C) by EMC Corporation, 1997 All rights reserved.
|
|
* $Id$
|
|
* DESCRIPTION: This module has been provided for the purpose of testing GDB.
|
|
*
|
|
* NOTES:
|
|
*
|
|
******************************************************************************
|
|
*****************************************************************************/
|
|
|
|
/*=============================================================================
|
|
* INCLUDE FILES
|
|
*===========================================================================*/
|
|
|
|
|
|
#ifdef DO_IT_BY_THE_BOOK
|
|
|
|
|
|
#include "symtypes_defs.h"
|
|
#include "printp.h"
|
|
|
|
#include "adbg_expression.h"
|
|
#include "common_hw_ds.h"
|
|
#include "common_hw_defs.h"
|
|
#include "evnttrac.h"
|
|
#include "sym_scratch_ds.h"
|
|
#include "symglob_ds.h"
|
|
#include "sym_protglob_ds.h"
|
|
|
|
#include "ether.h"
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
#else
|
|
|
|
#include "adbg_dtc.h"
|
|
|
|
#define YES 1
|
|
#define NO 0
|
|
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
|
|
#define ENABLED 1
|
|
#define DISABLED 0
|
|
|
|
#define CONTROL_C 3 /* ASCII 'ETX' */
|
|
|
|
|
|
/*
|
|
* Faked after ctype.h
|
|
*/
|
|
|
|
#define isxdigit(X) (((X) >= '0' && (X) <= '9') || \
|
|
((X) >= 'A' && (X) <= 'F') || \
|
|
((X) >= 'a' && (X) <= 'f'))
|
|
/*
|
|
* Borrowed from string.h
|
|
*/
|
|
|
|
extern unsigned int strlen ( const char * );
|
|
|
|
/*
|
|
* Extracted from symtypes.h:
|
|
*/
|
|
|
|
typedef char BOOL; /* 8 Bits */
|
|
typedef unsigned char UCHAR; /* 8 Bits */
|
|
typedef unsigned short USHORT; /* 16 Bits */
|
|
typedef unsigned long ULONG; /* 32 Bits */
|
|
|
|
/*
|
|
* for struct t_expr_tag and
|
|
* decl of build_and_add_expression
|
|
*/
|
|
#include "adbg_expression.h"
|
|
#define NULL 0
|
|
|
|
/*
|
|
* Extracted from printp.h:
|
|
*/
|
|
|
|
extern void printp ( const char * fptr, ... );
|
|
extern void sprintp ( const char * fptr, ... );
|
|
|
|
/*
|
|
* Extracted from ether.h:
|
|
*/
|
|
|
|
extern long eth_to_gdb ( UCHAR *buf, long length );
|
|
|
|
|
|
/*
|
|
* Derived from hwequs.s:
|
|
*/
|
|
|
|
#define CS_CODE_START 0x100000
|
|
#define CS_CODE_SIZE 0x200000
|
|
#define LAST_CS_WORD (CS_CODE_START + CS_CODE_SIZE - 2)
|
|
|
|
#define sh_genstat1 (*((volatile ULONG *) 0xFFFFFE54))
|
|
|
|
#define rs232_mode1 0 /* rs-232 mode 1 reg. */
|
|
#define rs232_mode2 rs232_mode1 /* rs-232 mode 2 reg. */
|
|
#define rs232_stat 4 /* rs-232 status reg. */
|
|
#define rs232_clk rs232_stat /* rs-232 clock select reg. */
|
|
#define rs232_cmd 8 /* rs-232 command reg */
|
|
#define rs232_transmit 12 /* rs-232 transmit reg. */
|
|
#define rs232_receive rs232_transmit /* rs-232 transmit reg. */
|
|
#define rs232_aux 16 /* rs-232 aux control reg. */
|
|
#define rs232_isr 20 /* rs-232 interrupt status reg. */
|
|
#define rs232_imr rs232_isr /* rs-232 interrupt mask reg. */
|
|
#define rs232_tc_high 24 /* rs-232 timer/counter high reg. */
|
|
#define rs232_tc_low 28 /* rs-232 timer/counter low reg. */
|
|
|
|
|
|
#endif
|
|
|
|
|
|
/*============================================================================
|
|
* MODULE DEFINES
|
|
*===========================================================================*/
|
|
|
|
#define P_RST_LAN_UART_REG ((volatile UCHAR *) 0xFFFFFE45)
|
|
#define M_RST_LAN_UART 0x80 /* Bit 7 */
|
|
|
|
#define P_LAN0TR_REG P_RST_LAN_UART_REG
|
|
#define M_LAN0TR 0x20 /* Bit 5 */
|
|
|
|
#define M_SH_GENCON_LAN0TR 0x00200000 /* Bit 21 */
|
|
|
|
#define MAX_RS232_CHARS 512
|
|
|
|
#define LAN_Q_MOD(X) ((X) % MAX_RS232_CHARS)
|
|
|
|
/*---------------------------------------*
|
|
* LAN UART Registers *
|
|
*---------------------------------------*/
|
|
|
|
#define LAN_UART_BASE ((ULONG) 0xfffffc22)
|
|
|
|
/* Write-Read */
|
|
|
|
#define P_LAN_MR1 ((volatile UCHAR *) (LAN_UART_BASE + ((ULONG) rs232_mode1 )))
|
|
#define P_LAN_MR2 ((volatile UCHAR *) (LAN_UART_BASE + ((ULONG) rs232_mode2 )))
|
|
|
|
/* Write-Only */
|
|
|
|
#define P_LAN_ACR ((volatile UCHAR *) (LAN_UART_BASE + ((ULONG) rs232_aux )))
|
|
#define P_LAN_CR ((volatile UCHAR *) (LAN_UART_BASE + ((ULONG) rs232_cmd )))
|
|
#define P_LAN_CSR ((volatile UCHAR *) (LAN_UART_BASE + ((ULONG) rs232_clk )))
|
|
#define P_LAN_CTLR ((volatile UCHAR *) (LAN_UART_BASE + ((ULONG) rs232_tc_low )))
|
|
#define P_LAN_CTUR ((volatile UCHAR *) (LAN_UART_BASE + ((ULONG) rs232_tc_high )))
|
|
#define P_LAN_IMR ((volatile UCHAR *) (LAN_UART_BASE + ((ULONG) rs232_imr )))
|
|
|
|
/* Read-Only */
|
|
|
|
#define P_LAN_SR ((volatile UCHAR *) (LAN_UART_BASE + ((ULONG) rs232_stat )))
|
|
#define P_LAN_ISR ((volatile UCHAR *) (LAN_UART_BASE + ((ULONG) rs232_isr )))
|
|
#define P_LAN_XMT ((volatile UCHAR *) (LAN_UART_BASE + ((ULONG) rs232_transmit)))
|
|
#define P_LAN_RCV ((volatile UCHAR *) (LAN_UART_BASE + ((ULONG) rs232_receive )))
|
|
|
|
/*
|
|
* Bit Values for Write-Read and Write-Only Registers
|
|
*/
|
|
|
|
#define DEFAULT_LAN_MR1 ((UCHAR) 0x13)
|
|
#define DEFAULT_LAN_MR2 ((UCHAR) 0x07)
|
|
#define DEFAULT_LAN_CSR ((UCHAR) 0xcc)
|
|
#define DEFAULT_LAN_ACR ((UCHAR) 0x38)
|
|
#define DEFAULT_LAN_CTUR ((UCHAR) 0xff)
|
|
#define DEFAULT_LAN_CTLR ((UCHAR) 0xff)
|
|
|
|
#define LAN_ACR_SELECT_BRG_0 DEFAULT_LAN_ACR
|
|
#define LAN_ACR_SELECT_BRG_1 (DEFAULT_LAN_ACR | 0x80)
|
|
|
|
#define UART_CR_RESET_MR_PTR ((UCHAR) 0x10) /* Reset MR pointer (points to MR1). */
|
|
#define UART_CR_RESET_RVCR ((UCHAR) 0x20) /* Reset receiver (disabled). */
|
|
#define UART_CR_RESET_XMTR ((UCHAR) 0x30) /* Reset transmitter (disabled). */
|
|
#define UART_CR_RESET_ERROR_STATUS ((UCHAR) 0x40) /* Reset error status. */
|
|
#define UART_CR_RESET_BRK_CHG_INT ((UCHAR) 0x50) /* Reset break change interrupt. */
|
|
#define UART_CR_START_CNTR_TIMER ((UCHAR) 0x80) /* Start counter/timer. */
|
|
#define UART_CR_STOP_CNTR ((UCHAR) 0x90) /* Stop counter. */
|
|
|
|
#define UART_CR_DISABLE_XMTR ((UCHAR) 0x08) /* Disable transmitter. */
|
|
#define UART_CR_ENABLE_XMTR ((UCHAR) 0x04) /* Enable transmitter. */
|
|
#define UART_CR_DISABLE_RCVR ((UCHAR) 0x02) /* Disable receiver. */
|
|
#define UART_CR_ENABLE_RCVR ((UCHAR) 0x01) /* Enable receiver. */
|
|
|
|
#define UART_CSR_BR_4800 ((UCHAR) 0x99) /* With either BRG Set selected (via ACR). */
|
|
#define UART_CSR_BR_9600 ((UCHAR) 0xbb) /* With either BRG Set selected (via ACR). */
|
|
#define UART_CSR_BR_19200 ((UCHAR) 0xcc) /* With BRG Set '1' selected (via ACR). */
|
|
#define UART_CSR_BR_38400 ((UCHAR) 0xcc) /* With BRG Set '0' selected (via ACR). */
|
|
|
|
#define UART_IMR_RxRDY ((UCHAR) 0x04) /* Enable 'RxRDY' interrupt. */
|
|
#define UART_IMR_TxEMT ((UCHAR) 0x02) /* Enable 'TxEMT' interrupt. */
|
|
#define UART_IMR_TxRDY ((UCHAR) 0x01) /* Enable 'TxRDY' interrupt. */
|
|
|
|
/*
|
|
* Bit Masks for Read-Only Registers
|
|
*/
|
|
|
|
#define M_UART_SR_RCVD_BRK 0x80 /* Bit 7 */
|
|
#define M_UART_SR_FE 0x40 /* Bit 6 */
|
|
#define M_UART_SR_PE 0x20 /* Bit 5 */
|
|
#define M_UART_SR_OE 0x10 /* Bit 4 */
|
|
#define M_UART_SR_TxEMT 0x08 /* Bit 3 */
|
|
#define M_UART_SR_TxRDY 0x04 /* Bit 2 */
|
|
#define M_UART_SR_FFULL 0x02 /* Bit 1 */
|
|
#define M_UART_SR_RxRDY 0x01 /* Bit 0 */
|
|
|
|
#define M_UART_ISR_RxRDY 0x04 /* Bit 2 */
|
|
#define M_UART_ISR_TxEMT 0x02 /* Bit 1 */
|
|
#define M_UART_ISR_TxRDY 0x01 /* Bit 0 */
|
|
|
|
/*---------------------------------------*
|
|
* Support for 'Utility 83'. *
|
|
*---------------------------------------*/
|
|
|
|
#define LAN_UTIL_CODE 0x83
|
|
|
|
#define LAN_INIT ((ULONG) (('I' << 24) | ('N' << 16) | ('I' << 8) | 'T'))
|
|
#define LAN_BAUD ((ULONG) (('B' << 24) | ('A' << 16) | ('U' << 8) | 'D'))
|
|
#define LAN_INTR ((ULONG) (('I' << 24) | ('N' << 16) | ('T' << 8) | 'R'))
|
|
#define LAN_XMT ((ULONG) (('X' << 16) | ('M' << 8) | 'T'))
|
|
#define LAN_ECHO ((ULONG) (('E' << 24) | ('C' << 16) | ('H' << 8) | 'O'))
|
|
#define LAN_STAT ((ULONG) (('S' << 24) | ('T' << 16) | ('A' << 8) | 'T'))
|
|
#define LAN_IN ((ULONG) (('I' << 8) | 'N'))
|
|
#define LAN_OUT ((ULONG) (('O' << 16) | ('U' << 8) | 'T'))
|
|
|
|
#define LAN_PUTC ((ULONG) (('P' << 24) | ('U' << 16) | ('T' << 8) | 'C'))
|
|
#define LAN_WPM ((ULONG) (('W' << 16) | ('P' << 8) | 'M'))
|
|
|
|
#define STATUS(X) ( ( ( X ) == 0 ) ? "disabled" : "enabled" )
|
|
|
|
#define XMT_VIA_BP_ENABLED() ( *P_LAN0TR_REG & M_LAN0TR ? 1 : 0 )
|
|
|
|
#define TRAP_1_INST 0x4E41
|
|
|
|
/*
|
|
* Bit #13 of shared genstat 1 indicates
|
|
* which processor we are as follows.
|
|
*
|
|
* 0 => X (side A)
|
|
* 1 => Y (side B)
|
|
*/
|
|
|
|
#define M_PROC_ID 0x00002000
|
|
|
|
#define IS_SIDE_A() ( ( (sh_genstat1) & M_PROC_ID ) == 0 )
|
|
#define IS_SIDE_B() ( (sh_genstat1) & M_PROC_ID )
|
|
|
|
|
|
#ifdef STANDALONE /* Compile this module stand-alone for debugging */
|
|
#define LAN_PUT_CHAR(X) printf("%c", X)
|
|
#else
|
|
#define LAN_PUT_CHAR(X) while ( lan_put_char( X ) )
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#define VIA_RS232 0
|
|
#define VIA_ETHERNET 1
|
|
|
|
#define MAX_IO_BUF_SIZE 400
|
|
|
|
#define MAX_BYTE_CODES 200 /* maximum length for bytecode string */
|
|
|
|
|
|
static ULONG gdb_host_comm;
|
|
|
|
static ULONG gdb_cat_ack;
|
|
|
|
static char eth_outbuffer[ MAX_IO_BUF_SIZE + 1 ];
|
|
|
|
|
|
#ifdef STANDALONE
|
|
|
|
#define ACK_PKT() LAN_PUT_CHAR( '+' )
|
|
#define NACK_PKT() LAN_PUT_CHAR( '-' )
|
|
|
|
#else
|
|
|
|
#define ACK_PKT() { \
|
|
if ( VIA_ETHERNET == gdb_host_comm ) \
|
|
{ \
|
|
gdb_cat_ack = YES; \
|
|
} \
|
|
else \
|
|
{ \
|
|
LAN_PUT_CHAR( '+' ); \
|
|
} \
|
|
}
|
|
|
|
|
|
|
|
#define NACK_PKT() { \
|
|
if ( VIA_ETHERNET == gdb_host_comm ) \
|
|
{ \
|
|
eth_outbuffer[ 0 ] = '-'; \
|
|
eth_to_gdb( (UCHAR *) eth_outbuffer, 1 ); \
|
|
} \
|
|
else \
|
|
{ \
|
|
LAN_PUT_CHAR( '-' ); \
|
|
} \
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*============================================================================
|
|
* MODULE TYPEDEFS
|
|
*===========================================================================*/
|
|
|
|
typedef struct rs232_queue {
|
|
|
|
long head_index;
|
|
|
|
long tail_index;
|
|
|
|
ULONG overflows;
|
|
|
|
long gdb_packet_start;
|
|
long gdb_packet_end;
|
|
long gdb_packet_csum1;
|
|
long gdb_packet_csum2;
|
|
|
|
UCHAR buf[ MAX_RS232_CHARS ];
|
|
|
|
} T_RS232_QUEUE;
|
|
|
|
|
|
|
|
|
|
/*=============================================================================
|
|
* EXTERNAL GLOBAL VARIABLES
|
|
*===========================================================================*/
|
|
|
|
extern volatile UCHAR sss_trace_flag;
|
|
|
|
|
|
/*=============================================================================
|
|
* STATIC MODULE DECLARATIONS
|
|
*===========================================================================*/
|
|
|
|
static T_RS232_QUEUE lan_input_queue,
|
|
lan_output_queue;
|
|
|
|
static BOOL test_echo;
|
|
|
|
#if 0
|
|
/* The stub no longer seems to use this. */
|
|
static BOOL write_access_enabled;
|
|
#endif
|
|
|
|
static int baud_rate_idx;
|
|
|
|
static ULONG tx_by_intr,
|
|
tx_by_poll;
|
|
|
|
static UCHAR lan_shadow_imr;
|
|
|
|
|
|
/*=============================================================================
|
|
* EXTERNAL FUNCTION PROTOTYPES
|
|
*===========================================================================*/
|
|
|
|
extern long write_to_protected_mem( void *address, unsigned short value );
|
|
|
|
|
|
/*=============================================================================
|
|
* MODULE GLOBAL FUNCTIONS PROTOTYPES
|
|
*===========================================================================*/
|
|
|
|
ULONG gdb_c_test( ULONG *parm );
|
|
|
|
|
|
void lan_init( void );
|
|
|
|
void lan_isr( void );
|
|
|
|
long lan_get_char( void );
|
|
|
|
long lan_put_char( UCHAR c );
|
|
|
|
ULONG lan_util( ULONG *parm );
|
|
|
|
|
|
/*=============================================================================
|
|
* MODULE LOCAL FUNCTION PROTOTYPES
|
|
*===========================================================================*/
|
|
|
|
static void lan_reset( void );
|
|
|
|
static void lan_configure( void );
|
|
|
|
static void lan_init_queue( T_RS232_QUEUE *p_queue );
|
|
|
|
static void lan_add_to_queue( long c, T_RS232_QUEUE *p_queue );
|
|
|
|
static UCHAR lan_next_queue_char( T_RS232_QUEUE *p_queue );
|
|
|
|
static void lan_util_menu( void );
|
|
|
|
static long get_gdb_input( long c, T_RS232_QUEUE *p_input_q );
|
|
|
|
|
|
/*=============================================================================
|
|
* GDB STUB FUNCTION PROTOTYPES
|
|
*===========================================================================*/
|
|
|
|
void gdb_trap_1_handler( void );
|
|
void gdb_trace_handler ( void );
|
|
|
|
void gdb_get_eth_input( unsigned char *buf, long length );
|
|
|
|
static void getpacket ( void );
|
|
static void putpacket ( char * );
|
|
static void discard_packet ( void );
|
|
|
|
#ifdef STANDALONE /* Compile this module stand-alone for debugging */
|
|
#include <stdio.h>
|
|
#define printp printf /* easier than declaring a local varargs stub func. */
|
|
#endif /* STANDALONE */
|
|
|
|
|
|
/*=============================================================================
|
|
* MODULE BODY
|
|
*===========================================================================*/
|
|
|
|
/* ------------------- Things that belong in a header file --------------- */
|
|
extern char *memset (char *, int, int);
|
|
|
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*
|
|
* *
|
|
* Global Module Functions *
|
|
* *
|
|
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
|
|
|
|
static char gdb_char_test;
|
|
static short gdb_short_test;
|
|
static long gdb_long_test;
|
|
static char gdb_arr_test[25];
|
|
static struct GDB_STRUCT_TEST
|
|
{
|
|
char c;
|
|
short s;
|
|
long l;
|
|
int bfield : 11; /* collect bitfield */
|
|
char arr[25];
|
|
struct GDB_STRUCT_TEST *next;
|
|
} gdb_struct1_test, gdb_struct2_test, *gdb_structp_test, **gdb_structpp_test;
|
|
|
|
static union GDB_UNION_TEST
|
|
{
|
|
char c;
|
|
short s;
|
|
long l;
|
|
int bfield : 11; /* collect bitfield */
|
|
char arr[4];
|
|
union GDB_UNION_TEST *next;
|
|
} gdb_union1_test;
|
|
|
|
void gdb_recursion_test (int, int, int, int, int, int, int);
|
|
|
|
void gdb_recursion_test (int depth,
|
|
int q1,
|
|
int q2,
|
|
int q3,
|
|
int q4,
|
|
int q5,
|
|
int q6)
|
|
{ /* gdb_recursion_test line 0 */
|
|
int q = q1; /* gdbtestline 1 */
|
|
|
|
q1 = q2; /* gdbtestline 2 */
|
|
q2 = q3; /* gdbtestline 3 */
|
|
q3 = q4; /* gdbtestline 4 */
|
|
q4 = q5; /* gdbtestline 5 */
|
|
q5 = q6; /* gdbtestline 6 */
|
|
q6 = q; /* gdbtestline 7 */
|
|
if (depth--) /* gdbtestline 8 */
|
|
gdb_recursion_test (depth, q1, q2, q3, q4, q5, q6); /* gdbtestline 9 */
|
|
}
|
|
|
|
|
|
ULONG gdb_c_test( ULONG *parm )
|
|
|
|
{
|
|
char *p = "gdb_c_test";
|
|
char *ridiculously_long_variable_name_with_equally_long_string_assignment;
|
|
register long local_reg = 7;
|
|
static unsigned long local_static, local_static_sizeof;
|
|
long local_long;
|
|
unsigned long *stack_ptr;
|
|
unsigned long end_of_stack;
|
|
|
|
ridiculously_long_variable_name_with_equally_long_string_assignment =
|
|
"ridiculously long variable name with equally long string assignment";
|
|
local_static = 9;
|
|
local_static_sizeof = sizeof (struct GDB_STRUCT_TEST);
|
|
local_long = local_reg + 1;
|
|
stack_ptr = (unsigned long *) &local_long;
|
|
end_of_stack =
|
|
(unsigned long) &stack_ptr + sizeof(stack_ptr) + sizeof(end_of_stack) - 1;
|
|
|
|
printp ("\n$Id$\n");
|
|
|
|
printp( "%s: arguments = %X, %X, %X, %X, %X, %X\n",
|
|
p, parm[ 1 ], parm[ 2 ], parm[ 3 ], parm[ 4 ], parm[ 5 ], parm[ 6 ] );
|
|
|
|
gdb_char_test = gdb_struct1_test.c = (char) ((long) parm[1] & 0xff);
|
|
gdb_short_test = gdb_struct1_test.s = (short) ((long) parm[2] & 0xffff);
|
|
gdb_long_test = gdb_struct1_test.l = (long) ((long) parm[3] & 0xffffffff);
|
|
gdb_union1_test.l = (long) parm[4];
|
|
gdb_arr_test[0] = gdb_struct1_test.arr[0] = (char) ((long) parm[1] & 0xff);
|
|
gdb_arr_test[1] = gdb_struct1_test.arr[1] = (char) ((long) parm[2] & 0xff);
|
|
gdb_arr_test[2] = gdb_struct1_test.arr[2] = (char) ((long) parm[3] & 0xff);
|
|
gdb_arr_test[3] = gdb_struct1_test.arr[3] = (char) ((long) parm[4] & 0xff);
|
|
gdb_arr_test[4] = gdb_struct1_test.arr[4] = (char) ((long) parm[5] & 0xff);
|
|
gdb_arr_test[5] = gdb_struct1_test.arr[5] = (char) ((long) parm[6] & 0xff);
|
|
gdb_struct1_test.bfield = 144;
|
|
gdb_struct1_test.next = &gdb_struct2_test;
|
|
gdb_structp_test = &gdb_struct1_test;
|
|
gdb_structpp_test = &gdb_structp_test;
|
|
|
|
gdb_recursion_test (3, (long) parm[1], (long) parm[2], (long) parm[3],
|
|
(long) parm[4], (long) parm[5], (long) parm[6]);
|
|
|
|
gdb_char_test = gdb_short_test = gdb_long_test = 0;
|
|
gdb_structp_test = (void *) 0;
|
|
gdb_structpp_test = (void *) 0;
|
|
memset ((char *) &gdb_struct1_test, 0, sizeof (gdb_struct1_test));
|
|
memset ((char *) &gdb_struct2_test, 0, sizeof (gdb_struct2_test));
|
|
local_static_sizeof = 0;
|
|
local_static = 0;
|
|
return ( (ULONG) 0 );
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* FUNCTION NAME: lan_init
|
|
*
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
*
|
|
* RETURN VALUE:
|
|
*
|
|
*
|
|
* USED GLOBAL VARIABLES:
|
|
*
|
|
*
|
|
* AFFECTED GLOBAL VARIABLES/SIDE EFFECTS:
|
|
*
|
|
*
|
|
* NOTES:
|
|
*
|
|
*
|
|
*
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
void lan_init( void )
|
|
|
|
{
|
|
|
|
if ( IS_SIDE_A( ) )
|
|
{
|
|
|
|
lan_reset( );
|
|
|
|
lan_init_queue( &lan_input_queue );
|
|
|
|
lan_init_queue( &lan_output_queue );
|
|
|
|
lan_configure( );
|
|
}
|
|
|
|
return;
|
|
}
|
|
/* end of 'lan_init'
|
|
*===========================================================================*/
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* FUNCTION NAME: lan_isr
|
|
*
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
*
|
|
* RETURN VALUE: None.
|
|
*
|
|
*
|
|
* USED GLOBAL VARIABLES:
|
|
*
|
|
*
|
|
* AFFECTED GLOBAL VARIABLES/SIDE EFFECTS:
|
|
*
|
|
*
|
|
* NOTES:
|
|
*
|
|
*
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
void lan_isr( void )
|
|
|
|
{
|
|
UCHAR c;
|
|
|
|
|
|
lan_shadow_imr = 0; /* Disable all UART interrupts. */
|
|
*P_LAN_IMR = lan_shadow_imr;
|
|
|
|
|
|
if ( *P_LAN_ISR & M_UART_ISR_RxRDY )
|
|
{
|
|
|
|
gdb_host_comm = VIA_RS232;
|
|
|
|
c = *P_LAN_RCV;
|
|
|
|
if ( test_echo )
|
|
{
|
|
/* ????? */
|
|
}
|
|
|
|
if ( c == CONTROL_C )
|
|
{
|
|
/* can't stop the target, but we can tell gdb to stop waiting... */
|
|
discard_packet( );
|
|
putpacket( "S03" ); /* send back SIGINT to the debugger */
|
|
}
|
|
|
|
else
|
|
{
|
|
lan_add_to_queue( (long) c, &lan_input_queue );
|
|
get_gdb_input( (long) c, &lan_input_queue );
|
|
}
|
|
|
|
}
|
|
|
|
if ( XMT_VIA_BP_ENABLED( ) )
|
|
{
|
|
|
|
c = 0;
|
|
|
|
while ( (*P_LAN_ISR & M_UART_ISR_TxRDY) && (c = lan_next_queue_char( &lan_output_queue )) )
|
|
{
|
|
*P_LAN_XMT = c;
|
|
++tx_by_intr;
|
|
}
|
|
|
|
if ( c )
|
|
{
|
|
lan_shadow_imr |= UART_IMR_TxRDY; /* (Re-)Enable 'TxRDY' interrupt from UART. */
|
|
}
|
|
|
|
}
|
|
|
|
|
|
lan_shadow_imr |= UART_IMR_RxRDY; /* Re-Enable 'RxRDY' interrupt from UART. */
|
|
*P_LAN_IMR = lan_shadow_imr;
|
|
|
|
|
|
|
|
return;
|
|
}
|
|
/* end of 'lan_isr'
|
|
*===========================================================================*/
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* FUNCTION NAME: lan_get_char
|
|
*
|
|
*
|
|
* DESCRIPTION: Fetches a character from the UART.
|
|
*
|
|
*
|
|
* RETURN VALUE: 0 on success, -1 on failure.
|
|
*
|
|
*
|
|
* USED GLOBAL VARIABLES:
|
|
*
|
|
*
|
|
* AFFECTED GLOBAL VARIABLES/SIDE EFFECTS:
|
|
*
|
|
*
|
|
* NOTES:
|
|
*
|
|
*
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
long lan_get_char( void )
|
|
|
|
{
|
|
long status = -2; /* AGD: nothing found in rcv buffer */
|
|
|
|
if ( *P_LAN_SR & M_UART_SR_RxRDY )
|
|
{
|
|
char c = (char) *P_LAN_RCV;
|
|
|
|
if ( test_echo )
|
|
{
|
|
LAN_PUT_CHAR ( c );
|
|
}
|
|
|
|
if ( c == CONTROL_C )
|
|
{
|
|
/* can't stop the target, but we can tell gdb to stop waiting... */
|
|
discard_packet( );
|
|
putpacket( "S03" ); /* send back SIGINT to the debugger */
|
|
status = 0; /* success */
|
|
}
|
|
|
|
else
|
|
{
|
|
lan_add_to_queue( (long) c, &lan_input_queue );
|
|
status = get_gdb_input( (long) c, &lan_input_queue );
|
|
}
|
|
|
|
}
|
|
|
|
return( status );
|
|
}
|
|
/* end of 'lan_get_char'
|
|
*===========================================================================*/
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* FUNCTION NAME: lan_put_char
|
|
*
|
|
* DESCRIPTION: Puts a character out via the UART.
|
|
*
|
|
* RETURN VALUE: 0 on success, -1 on failure.
|
|
*
|
|
* USED GLOBAL VARIABLES: none.
|
|
*
|
|
* AFFECTED GLOBAL VARIABLES/SIDE EFFECTS:
|
|
*
|
|
* NOTES: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
* !! !!
|
|
* !! If 'XMT_VIA_BP_ENABLED()' is FALSE then output is THROWN AWAY. !!
|
|
* !! This prevents anyone infinite-looping on this function. !!
|
|
* !! !!
|
|
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
*
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
long lan_put_char( UCHAR c )
|
|
|
|
{
|
|
long status = -1;
|
|
|
|
if ( XMT_VIA_BP_ENABLED( ) )
|
|
{
|
|
|
|
if ( *P_LAN_SR & M_UART_SR_TxRDY )
|
|
{
|
|
lan_add_to_queue( (long) c, &lan_output_queue );
|
|
|
|
c = lan_next_queue_char( &lan_output_queue );
|
|
|
|
*P_LAN_XMT = c;
|
|
++tx_by_poll;
|
|
status = 0;
|
|
}
|
|
#if 0
|
|
else
|
|
{
|
|
status = 0;
|
|
lan_shadow_imr |= UART_IMR_TxRDY; /* Enable 'TxRDY' interrupt from UART. */
|
|
*P_LAN_IMR = lan_shadow_imr;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
else
|
|
{
|
|
status = 0; /* You lose: input character goes to the bit bucket. */
|
|
}
|
|
|
|
return( status );
|
|
}
|
|
/* end of 'lan_put_char'
|
|
*===========================================================================*/
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* FUNCTION NAME: lan_util
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* RETURN VALUE:
|
|
*
|
|
* USED GLOBAL VARIABLES:
|
|
*
|
|
* AFFECTED GLOBAL VARIABLES/SIDE EFFECTS:
|
|
*
|
|
* NOTES:
|
|
*
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
ULONG lan_util( ULONG *parm )
|
|
|
|
{
|
|
|
|
|
|
static const struct {
|
|
|
|
ULONG rate_code;
|
|
UCHAR acr_setting;
|
|
UCHAR csr_setting;
|
|
|
|
} baud_rate_setting [] = {
|
|
|
|
{ 0x38400, LAN_ACR_SELECT_BRG_0, UART_CSR_BR_38400 },
|
|
{ 0x19200, LAN_ACR_SELECT_BRG_1, UART_CSR_BR_19200 },
|
|
{ 0x9600, LAN_ACR_SELECT_BRG_0, UART_CSR_BR_9600 },
|
|
{ 0x4800, LAN_ACR_SELECT_BRG_0, UART_CSR_BR_4800 }
|
|
};
|
|
|
|
|
|
#define BOGUS_P1 0xE1
|
|
#define BOGUS_P2 0xE2
|
|
|
|
ULONG not_done_code;
|
|
|
|
|
|
ULONG opcode;
|
|
ULONG parm_1;
|
|
ULONG parm_2;
|
|
|
|
int i;
|
|
UCHAR c;
|
|
|
|
|
|
not_done_code = 0;
|
|
|
|
opcode = parm[ 1 ];
|
|
parm_1 = parm[ 2 ];
|
|
parm_2 = parm[ 3 ];
|
|
|
|
|
|
switch ( opcode )
|
|
{
|
|
|
|
case LAN_INIT:
|
|
{
|
|
|
|
lan_init( );
|
|
printp( "\n\n Interface (Re)Initialized ...\n\n" );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case LAN_BAUD:
|
|
{
|
|
|
|
for ( i = 0; i < (int)(sizeof(baud_rate_setting) / sizeof(baud_rate_setting[0])); i ++ )
|
|
{
|
|
if ( baud_rate_setting[i].rate_code == parm_1 )
|
|
{
|
|
baud_rate_idx = i;
|
|
*P_LAN_ACR = baud_rate_setting[i].acr_setting;
|
|
*P_LAN_CSR = baud_rate_setting[i].csr_setting;
|
|
printp ( "Baud rate set to %X!\n", baud_rate_setting[i].rate_code );
|
|
return( not_done_code );
|
|
}
|
|
}
|
|
|
|
printp( "\n\n *** SYNTAX Error - Invalid baudrate (P2)\n\n" );
|
|
not_done_code = BOGUS_P2;
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case LAN_INTR:
|
|
{
|
|
|
|
switch ( parm_1 )
|
|
{
|
|
|
|
case 0x0D: /* Disable 'RxRDY' Interrupts */
|
|
{
|
|
lan_shadow_imr &= ~UART_IMR_RxRDY;
|
|
*P_LAN_IMR = lan_shadow_imr;
|
|
printp( "\n\n Receive Ready Interrupts DISABLED ...\n\n" );
|
|
break;
|
|
}
|
|
|
|
case 0x0E: /* Enable 'RxRDY' Interrupts */
|
|
{
|
|
lan_shadow_imr |= UART_IMR_RxRDY;
|
|
*P_LAN_IMR = lan_shadow_imr;
|
|
printp( "\n\n Receive Ready Interrupts ENABLED ...\n\n" );
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
printp( "\n\n *** SYNTAX Error - Invalid P2 (use D or E)\n\n" );
|
|
not_done_code = BOGUS_P2;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case LAN_XMT:
|
|
{
|
|
|
|
switch ( parm_1 )
|
|
{
|
|
|
|
case 0x0E: /* Enable Transmission-via-Backplane */
|
|
{
|
|
if ( !(*P_LAN0TR_REG & M_LAN0TR) )
|
|
{
|
|
*P_LAN0TR_REG |= M_LAN0TR; /* 0 -> 1 */
|
|
}
|
|
|
|
printp( "\n\n Transmit-via-Backplane ENABLED ...\n\n" );
|
|
break;
|
|
}
|
|
|
|
case 0x0D: /* Disable Transmission-via-Backplane */
|
|
{
|
|
if ( *P_LAN0TR_REG & M_LAN0TR )
|
|
{
|
|
*P_LAN0TR_REG &= ~M_LAN0TR; /* 1 -> 0 */
|
|
}
|
|
|
|
printp( "\n\n Transmit-via-Backplane DISABLED ...\n\n" );
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
printp( "\n\n *** SYNTAX Error - Invalid P2 (use D or E)\n\n" );
|
|
not_done_code = BOGUS_P2;
|
|
lan_util_menu( );
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case LAN_STAT:
|
|
{
|
|
|
|
printp( "\n -- Status --\n\n" );
|
|
|
|
printp( " Baud Rate: %X *\n", baud_rate_setting[ baud_rate_idx ].rate_code );
|
|
printp( " Xmt-via-BP: %s *\n", STATUS( XMT_VIA_BP_ENABLED( ) ) );
|
|
printp( " RxRdy Intr: %s *\n", STATUS( (lan_shadow_imr & M_UART_ISR_RxRDY) ) );
|
|
/*** printp( " TxRdy Intr: %s\n", STATUS( (lan_shadow_imr & M_UART_ISR_TxRDY) ) ); ***/
|
|
printp( " Echo: %s *\n\n", STATUS( test_echo ) );
|
|
|
|
printp( " IMR: %02X\n", (ULONG) lan_shadow_imr );
|
|
printp( " ISR: %02X\n", (ULONG) *P_LAN_ISR );
|
|
printp( " SR: %02X\n\n", (ULONG) *P_LAN_SR );
|
|
|
|
printp( " Input Overflows: %d\n\n", lan_input_queue.overflows );
|
|
|
|
printp( " Tx by Intr: %d\n", tx_by_intr );
|
|
printp( " Tx by Poll: %d\n\n", tx_by_poll );
|
|
|
|
printp( " * Can be set or toggled via Utility %2X.\n\n", (ULONG) LAN_UTIL_CODE );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case LAN_IN:
|
|
{
|
|
|
|
switch ( parm_1 )
|
|
{
|
|
|
|
case 0x0C: /* Clear and Reset Queue */
|
|
{
|
|
lan_init_queue( &lan_input_queue );
|
|
printp( "\n\n Queue CLEARED/RESET ...\n\n" );
|
|
break;
|
|
}
|
|
|
|
case 0x0D: /* Display Queue */
|
|
{
|
|
printp( "\n -- Input Queue --\n" );
|
|
printp( "\n Head Index: %8X Tail Index: %8X\n\n ",
|
|
(ULONG) lan_input_queue.head_index, (ULONG) lan_input_queue.tail_index );
|
|
|
|
for ( i = 0; i < MAX_RS232_CHARS; ++i )
|
|
{
|
|
printp( " %02X", (ULONG) lan_input_queue.buf[ i ] );
|
|
|
|
if ( 15 == (i % 16) )
|
|
{
|
|
int j;
|
|
|
|
printp ( " " );
|
|
for ( j = i - 15; j <= i; j++ )
|
|
{
|
|
if ( lan_input_queue.buf[ j ] >= ' ' &&
|
|
lan_input_queue.buf[ j ] < 127 )
|
|
printp ( "%c", lan_input_queue.buf[ j ] );
|
|
else
|
|
printp ( "." );
|
|
}
|
|
printp( "\n " );
|
|
}
|
|
|
|
else if ( 7 == (i % 8) )
|
|
{
|
|
printp( " " );
|
|
}
|
|
|
|
}
|
|
|
|
printp( "\n" );
|
|
|
|
break;
|
|
}
|
|
|
|
case 0x0F: /* Fetch next character in Queue */
|
|
{
|
|
c = lan_next_queue_char( &lan_input_queue );
|
|
|
|
if ( c )
|
|
{
|
|
printp( "\n\n Next Character: " );
|
|
if ( 0x21 <= c && c <= 0x7F )
|
|
{
|
|
printp( "%c\n\n", (ULONG) c );
|
|
}
|
|
|
|
else if ( 0x20 == ((UCHAR) c) )
|
|
{
|
|
printp( "<space>\n\n" );
|
|
}
|
|
|
|
else
|
|
{
|
|
printp( "%02X\n\n", (ULONG) c );
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
printp( "\n\n Input Queue EMPTY ...\n\n" );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
printp( "\n\n *** SYNTAX Error - Invalid P2 ...\n\n" );
|
|
not_done_code = BOGUS_P2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case LAN_OUT:
|
|
{
|
|
|
|
switch ( parm_1 )
|
|
{
|
|
|
|
case 0x0C: /* Clear and Reset Queue */
|
|
{
|
|
lan_init_queue( &lan_output_queue );
|
|
printp( "\n\n Queue CLEARED/RESET ...\n\n" );
|
|
break;
|
|
}
|
|
|
|
case 0x0D: /* Display Queue */
|
|
{
|
|
printp( "\n -- Output Queue --\n" );
|
|
printp( "\n Head Index: %8X Tail Index: %8X\n\n ",
|
|
(ULONG) lan_output_queue.head_index, (ULONG) lan_output_queue.tail_index );
|
|
|
|
for ( i = 0; i < MAX_RS232_CHARS; ++i )
|
|
{
|
|
printp( " %02X", (ULONG) lan_output_queue.buf[ i ] );
|
|
|
|
if ( 15 == (i % 16) )
|
|
{
|
|
int j;
|
|
|
|
printp ( " " );
|
|
for ( j = i - 15; j <= i; j++ )
|
|
{
|
|
if ( lan_output_queue.buf[ j ] >= ' ' &&
|
|
lan_output_queue.buf[ j ] < 127 )
|
|
printp ( "%c", lan_output_queue.buf[ j ] );
|
|
else
|
|
printp ( "." );
|
|
}
|
|
printp( "\n " );
|
|
}
|
|
|
|
else if ( 7 == (i % 8) )
|
|
{
|
|
printp( " " );
|
|
}
|
|
|
|
}
|
|
|
|
printp( "\n" );
|
|
|
|
break;
|
|
}
|
|
|
|
case 0x0F: /* Fetch next character in Queue */
|
|
{
|
|
c = lan_next_queue_char( &lan_output_queue );
|
|
|
|
if ( c )
|
|
{
|
|
printp( "\n\n Next Character: " );
|
|
if ( 0x21 <= c && c <= 0x7F )
|
|
{
|
|
printp( "%c\n\n", (ULONG) c );
|
|
}
|
|
|
|
else if ( 0x20 == c )
|
|
{
|
|
printp( "<space>\n\n" );
|
|
}
|
|
|
|
else
|
|
{
|
|
printp( "%02X\n\n", (ULONG) c );
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
printp( "\n\n Input Queue EMPTY ...\n\n" );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
printp( "\n\n *** SYNTAX Error - Invalid P2 ...\n\n" );
|
|
not_done_code = BOGUS_P2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case LAN_ECHO:
|
|
{
|
|
|
|
switch ( parm_1 )
|
|
{
|
|
|
|
case 0x0E:
|
|
{
|
|
test_echo = ENABLED;
|
|
printp( "\n\n Test echo ENABLED ...\n\n" );
|
|
break;
|
|
}
|
|
|
|
case 0x0D:
|
|
{
|
|
test_echo = DISABLED;
|
|
printp( "\n\n Test echo DISABLED ...\n\n" );
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
printp( "\n\n *** SYNTAX Error - Invalid P2 ...\n\n" );
|
|
not_done_code = BOGUS_P2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case LAN_PUTC:
|
|
{
|
|
|
|
if ( 0x20 < parm_1 && parm_1 < 0x7F )
|
|
{
|
|
if ( lan_put_char( (UCHAR) parm_1 ) )
|
|
{
|
|
printp( "\n\n *** 'lan_put_char' Error ...\n" );
|
|
}
|
|
|
|
else
|
|
{
|
|
printp( "\n\n O.K. ...\n" );
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
printp( "\n\n *** Error - character must be in the 0x21-0x7E range ...\n" );
|
|
not_done_code = BOGUS_P2;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
/***
|
|
case LAN_WPM:
|
|
{
|
|
|
|
if ( write_to_protected_mem( (void *) parm_1, (unsigned short) parm_2 ) )
|
|
{
|
|
printp( "\n Write to protected memory FAILED ...\n" );
|
|
}
|
|
|
|
break;
|
|
}
|
|
***/
|
|
|
|
case 0: /* no argument -- print menu */
|
|
{
|
|
lan_util_menu( );
|
|
break;
|
|
}
|
|
|
|
|
|
default:
|
|
{
|
|
parm_2 = 0; /* to supress compiler warning with 'LAN_WPM' case disabled */
|
|
|
|
printp( "\n\n *** SYNTAX Error - Invalid P1 ...\n\n" );
|
|
not_done_code = BOGUS_P1;
|
|
break;
|
|
}
|
|
|
|
|
|
} /* End of 'switch ( opcode )'. */
|
|
|
|
|
|
return( not_done_code );
|
|
}
|
|
/* end of 'lan_util'
|
|
*===========================================================================*/
|
|
|
|
|
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*
|
|
* *
|
|
* Local Module Functions *
|
|
* *
|
|
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* FUNCTION NAME: lan_reset
|
|
*
|
|
* DESCRIPTION: Resets the LAN UART by strobing the 'RST_LAN_UART' bit in the
|
|
* Shared Control 1 area.
|
|
*
|
|
* 1 _| ______
|
|
* | | |
|
|
* Bit | | |
|
|
* | | |
|
|
* 0 _|______| |______
|
|
* |---------------------> t
|
|
*
|
|
* RETURN VALUE: None.
|
|
*
|
|
* USED GLOBAL VARIABLES:
|
|
*
|
|
* AFFECTED GLOBAL VARIABLES/SIDE EFFECTS:
|
|
*
|
|
* NOTES: H/W configuration requires that a byte in the shared
|
|
* control 1 area must be read before being written.
|
|
*
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
static void lan_reset( void )
|
|
|
|
{
|
|
|
|
while ( *P_RST_LAN_UART_REG & M_RST_LAN_UART )
|
|
{
|
|
*P_RST_LAN_UART_REG &= ~M_RST_LAN_UART; /* 0 */
|
|
}
|
|
|
|
while ( !(*P_RST_LAN_UART_REG & M_RST_LAN_UART) )
|
|
{
|
|
*P_RST_LAN_UART_REG |= M_RST_LAN_UART; /* 1 */
|
|
}
|
|
|
|
while ( *P_RST_LAN_UART_REG & M_RST_LAN_UART )
|
|
{
|
|
*P_RST_LAN_UART_REG &= ~M_RST_LAN_UART; /* 0 */
|
|
}
|
|
|
|
}
|
|
/* end of 'lan_reset'
|
|
*===========================================================================*/
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* FUNCTION NAME: lan_configure
|
|
*
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
*
|
|
* RETURN VALUE:
|
|
*
|
|
*
|
|
* USED GLOBAL VARIABLES:
|
|
*
|
|
*
|
|
* AFFECTED GLOBAL VARIABLES/SIDE EFFECTS:
|
|
*
|
|
*
|
|
* NOTES:
|
|
*
|
|
*
|
|
*
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
static void lan_configure( void )
|
|
|
|
{
|
|
|
|
*P_LAN_CR = UART_CR_RESET_MR_PTR; /* Points to MR1. */
|
|
*P_LAN_CR = UART_CR_RESET_RVCR; /* Receiver disabled. */
|
|
*P_LAN_CR = UART_CR_RESET_XMTR; /* Transmitter disabled. */
|
|
*P_LAN_CR = UART_CR_RESET_ERROR_STATUS;
|
|
*P_LAN_CR = UART_CR_RESET_BRK_CHG_INT;
|
|
|
|
*P_LAN_MR1 = DEFAULT_LAN_MR1;
|
|
*P_LAN_MR2 = DEFAULT_LAN_MR2;
|
|
|
|
*P_LAN_ACR = DEFAULT_LAN_ACR;
|
|
|
|
*P_LAN_CSR = UART_CSR_BR_9600;
|
|
baud_rate_idx = 2;
|
|
|
|
*P_LAN_CTUR = DEFAULT_LAN_CTUR;
|
|
*P_LAN_CTLR = DEFAULT_LAN_CTLR;
|
|
|
|
*P_LAN_CR = (UART_CR_START_CNTR_TIMER | UART_CR_ENABLE_XMTR | UART_CR_ENABLE_RCVR);
|
|
|
|
lan_shadow_imr = UART_IMR_RxRDY; /* Enable only 'RxRDY' interrupt from UART. */
|
|
*P_LAN_IMR = lan_shadow_imr;
|
|
|
|
tx_by_intr = 0;
|
|
tx_by_poll = 0;
|
|
|
|
return;
|
|
}
|
|
/* end of 'lan_configure'
|
|
*===========================================================================*/
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* FUNCTION NAME: lan_init_queue
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* RETURN VALUE: None.
|
|
*
|
|
* USED GLOBAL VARIABLES:
|
|
*
|
|
* AFFECTED GLOBAL VARIABLES/SIDE EFFECTS:
|
|
*
|
|
* NOTES:
|
|
*
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
static void lan_init_queue( T_RS232_QUEUE *p_queue )
|
|
|
|
{
|
|
long i;
|
|
|
|
/*
|
|
* We set "head" equal to "tail" implying the queue is empty,
|
|
* BUT the "head" and "tail" should each point to valid queue
|
|
* positions.
|
|
*/
|
|
|
|
p_queue->head_index = 0;
|
|
p_queue->tail_index = 0;
|
|
|
|
p_queue->overflows = 0;
|
|
|
|
p_queue->gdb_packet_start = -1;
|
|
p_queue->gdb_packet_end = -1;
|
|
|
|
p_queue->gdb_packet_csum1 = -1;
|
|
p_queue->gdb_packet_csum2 = -1;
|
|
|
|
for ( i = 0; i < MAX_RS232_CHARS; ++i )
|
|
{
|
|
p_queue->buf[ i ] = 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
/* end of 'lan_init_queue'
|
|
*===========================================================================*/
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* FUNCTION NAME: lan_add_to_queue
|
|
*
|
|
*
|
|
* DESCRIPTION: Adds the specified character to the tail of the
|
|
* specified queue. Observes "oldest thrown on floor"
|
|
* rule (i.e. the queue is allowed to "wrap" and the
|
|
* input character is unconditionally placed at the
|
|
* tail of the queue.
|
|
*
|
|
*
|
|
* RETURN VALUE: None.
|
|
*
|
|
*
|
|
* USED GLOBAL VARIABLES:
|
|
*
|
|
*
|
|
* AFFECTED GLOBAL VARIABLES/SIDE EFFECTS:
|
|
*
|
|
*
|
|
* NOTES:
|
|
*
|
|
*
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
static void lan_add_to_queue( long c, T_RS232_QUEUE *p_queue )
|
|
|
|
{
|
|
|
|
if ( p_queue ) /* Sanity check. */
|
|
{
|
|
|
|
if ( c & 0x000000FF ) /* We don't allow NULL characters to be added to a queue. */
|
|
{
|
|
/* Insert the new character at the tail of the queue. */
|
|
|
|
p_queue->buf[ p_queue->tail_index ] = (UCHAR) (c & 0x000000FF);
|
|
|
|
/* Increment the tail index. */
|
|
|
|
if ( MAX_RS232_CHARS <= ++(p_queue->tail_index) )
|
|
{
|
|
p_queue->tail_index = 0;
|
|
}
|
|
|
|
/* Check for wrapping (i.e. overflow). */
|
|
|
|
if ( p_queue->head_index == p_queue->tail_index )
|
|
{
|
|
/* If the tail has caught up to the head record the overflow . . . */
|
|
|
|
++(p_queue->overflows);
|
|
|
|
/* . . . then increment the head index. */
|
|
|
|
if ( MAX_RS232_CHARS <= ++(p_queue->head_index) )
|
|
{
|
|
p_queue->head_index = 0;
|
|
}
|
|
|
|
}
|
|
|
|
} /* End of 'if ( c & 0x000000FF )'. */
|
|
|
|
} /* End of 'if ( p_queue )'. */
|
|
|
|
|
|
return;
|
|
}
|
|
/* end of 'lan_add_to_queue'
|
|
*===========================================================================*/
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* FUNCTION NAME: lan_next_queue_char
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* RETURN VALUE:
|
|
*
|
|
* USED GLOBAL VARIABLES:
|
|
*
|
|
* AFFECTED GLOBAL VARIABLES/SIDE EFFECTS:
|
|
*
|
|
* NOTES:
|
|
*
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
static UCHAR lan_next_queue_char( T_RS232_QUEUE *p_queue )
|
|
|
|
{
|
|
UCHAR c;
|
|
|
|
|
|
c = 0;
|
|
|
|
if ( p_queue )
|
|
{
|
|
|
|
if ( p_queue->head_index != p_queue->tail_index )
|
|
{
|
|
/* Return the 'oldest' character in the queue. */
|
|
|
|
c = p_queue->buf[ p_queue->head_index ];
|
|
|
|
/* Increment the head index. */
|
|
|
|
if ( MAX_RS232_CHARS <= ++(p_queue->head_index) )
|
|
{
|
|
p_queue->head_index = 0;
|
|
}
|
|
|
|
}
|
|
|
|
} /* End of 'if ( p_queue )'. */
|
|
|
|
|
|
return( c );
|
|
}
|
|
|
|
/* end of 'lan_next_queue_char'
|
|
*===========================================================================*/
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* FUNCTION NAME: lan_util_menu
|
|
*
|
|
* DESCRIPTION: Prints out a brief help on the LAN UART control utility.
|
|
*
|
|
* RETURN VALUE: None.
|
|
*
|
|
* USED GLOBAL VARIABLES: None.
|
|
*
|
|
* AFFECTED GLOBAL VARIABLES/SIDE EFFECTS: None.
|
|
*
|
|
* NOTES: None.
|
|
*
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
static void lan_util_menu( void )
|
|
|
|
{
|
|
|
|
/*
|
|
* Multiply calling printp() below is made due to the limitations
|
|
* of printp(), incapable of handling long formatting constants:
|
|
*/
|
|
|
|
printp( "\n -- Options --\n\n" );
|
|
|
|
printp( " %2X,'INIT' ............... Reset & (Re)INITIALIZE Interface.\n", (ULONG) LAN_UTIL_CODE );
|
|
printp( " %2X,'BAUD',<rate> ........ Set BAUD Rate.\n", (ULONG) LAN_UTIL_CODE );
|
|
printp( " %2X,'INTR',<mode> ........ Toggle 'RxRDY' Interrupts.\n", (ULONG) LAN_UTIL_CODE );
|
|
printp( " %2X,'XMT',<mode> ......... Toggle TRANSMIT-via-backplane.\n", (ULONG) LAN_UTIL_CODE );
|
|
printp( " %2X,'STAT' ............... Display STATUS.\n", (ULONG) LAN_UTIL_CODE );
|
|
printp( " %2X,'ECHO',<mode> ........ Enable/Disable Test ECHO.\n", (ULONG) LAN_UTIL_CODE );
|
|
printp( " %2X,'IN',<action> ........ Access INPUT Queue.\n", (ULONG) LAN_UTIL_CODE );
|
|
printp( " %2X,'OUT',<action> ....... Access OUTPUT Queue.\n\n", (ULONG) LAN_UTIL_CODE );
|
|
|
|
printp( " %2X,'PUTC',<char> ........ Output a Character (i.e. <char>).\n\n", (ULONG) LAN_UTIL_CODE );
|
|
|
|
/***
|
|
printp( " %2X,'WPM',address,word ... Write Protected Memory Test.\n\n", (ULONG) LAN_UTIL_CODE );
|
|
***/
|
|
|
|
printp( " <rate>: 4800 <mode>: E - enable <action>: C - clear/reset\n" );
|
|
printp( " 9600 D - disable D - display\n" );
|
|
printp( " 19200 F - fetch next char\n" );
|
|
printp( " 38400\n" );
|
|
}
|
|
/* end of 'lan_util_menu'
|
|
*===========================================================================*/
|
|
|
|
|
|
/* Thu Feb 5 17:14:41 EST 1998 CYGNUS...CYGNUS...CYGNUS...CYGNUS...CYGNUS...CYGNUS...CYGNUS...CYGNUS */
|
|
|
|
|
|
static long get_gdb_input( long c, T_RS232_QUEUE * p_input_q )
|
|
|
|
{
|
|
|
|
/* Now to detect when we've got a gdb packet... */
|
|
|
|
if ( '$' == c ) { /* char marks beginning of a packet */
|
|
|
|
if ( -1 != p_input_q->gdb_packet_start ||
|
|
-1 != p_input_q->gdb_packet_end ||
|
|
-1 != p_input_q->gdb_packet_csum1 ||
|
|
-1 != p_input_q->gdb_packet_csum2 ) { /* PROTOCOL ERROR */
|
|
|
|
/* NEW: Actually, this probably means that we muffed a packet,
|
|
and GDB has already resent it. The thing to do now is to
|
|
throw away the one we WERE working on, but immediately start
|
|
accepting the new one. Don't NAK, or GDB will have to try
|
|
and send it yet a third time! */
|
|
|
|
/*NACK_PKT( );*/ /*<ETHERNET>*/
|
|
discard_packet( ); /* throw away old packet */
|
|
lan_add_to_queue ('$', p_input_q); /* put the new "$" back in */
|
|
return 0;
|
|
} else { /* match new "$" */
|
|
p_input_q->gdb_packet_start = p_input_q->tail_index;
|
|
p_input_q->gdb_packet_end =
|
|
p_input_q->gdb_packet_csum1 =
|
|
p_input_q->gdb_packet_csum2 = -1;
|
|
}
|
|
} else if ( '#' == c ) { /* # marks end of packet (except for checksum) */
|
|
|
|
if ( -1 == p_input_q->gdb_packet_start ||
|
|
-1 != p_input_q->gdb_packet_end ||
|
|
-1 != p_input_q->gdb_packet_csum1 ||
|
|
-1 != p_input_q->gdb_packet_csum2 ) { /* PROTOCOL ERROR */
|
|
|
|
/* Garbled packet. Discard, but do not NAK. */
|
|
|
|
/*NACK_PKT( );*/ /*<ETHERNET>*/
|
|
discard_packet( );
|
|
return -1;
|
|
}
|
|
p_input_q->gdb_packet_end = p_input_q->tail_index;
|
|
p_input_q->gdb_packet_csum1 = p_input_q->gdb_packet_csum2 = -1;
|
|
|
|
} else if ( -1 != p_input_q->gdb_packet_start &&
|
|
-1 != p_input_q->gdb_packet_end) {
|
|
|
|
if ( isxdigit( c ) ) { /* char is one of two checksum digits for packet */
|
|
|
|
if ( -1 == p_input_q->gdb_packet_csum1 &&
|
|
LAN_Q_MOD( p_input_q->gdb_packet_end + 1 ) ==
|
|
p_input_q->tail_index ) {
|
|
|
|
/* first checksum digit */
|
|
|
|
p_input_q->gdb_packet_csum1 = p_input_q->tail_index;
|
|
p_input_q->gdb_packet_csum2 = -1;
|
|
|
|
} else if ( -1 == p_input_q->gdb_packet_csum2 &&
|
|
LAN_Q_MOD( p_input_q->gdb_packet_end + 2 ) ==
|
|
p_input_q->tail_index ) {
|
|
|
|
/* second checksum digit: packet is complete! */
|
|
|
|
p_input_q->gdb_packet_csum2 = p_input_q->tail_index;
|
|
getpacket(); /* got a packet -- extract it */
|
|
|
|
} else { /* probably can't happen (um... three hex digits?) */
|
|
|
|
/* PROTOCOL ERROR */
|
|
/* Not sure how this can happen, but ...
|
|
discard it, but do not NAK it. */
|
|
/*NACK_PKT( );*/ /*<ETHERNET>*/
|
|
discard_packet( );
|
|
return -1;
|
|
}
|
|
|
|
} else { /* '#' followed by non-hex char */
|
|
|
|
/* PROTOCOL ERROR */
|
|
/* Bad packet -- discard but do not NAK */
|
|
/*NACK_PKT( );*/ /*<ETHERNET>*/
|
|
discard_packet( );
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef STANDALONE
|
|
|
|
/* stand-alone stand-alone stand-alone stand-alone stand-alone stand-alone
|
|
stand-alone stand-alone
|
|
stand-alone Enable stand-alone build, for ease of debugging stand-alone
|
|
stand-alone stand-alone
|
|
stand-alone stand-alone stand-alone stand-alone stand-alone stand-alone */
|
|
|
|
long write_to_protected_mem (addr, word)
|
|
void *addr;
|
|
unsigned short word;
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
char dummy_memory[0x4000];
|
|
|
|
int main ( void )
|
|
{
|
|
long c;
|
|
|
|
lan_init_queue( &lan_input_queue );
|
|
printf( "Stand-alone EMC 'stub', pid = %d\n", getpid( ) );
|
|
printf( "Start of simulated 'memory': 0x%08x\n", &dummy_memory);
|
|
while ( (c = getc( stdin ) ) != EOF )
|
|
{
|
|
if ( c == '\\' ) /* escape char */
|
|
break;
|
|
|
|
lan_add_to_queue( c, &lan_input_queue );
|
|
get_gdb_input (c, &lan_input_queue);
|
|
fflush( stdout );
|
|
}
|
|
|
|
printf( "Goodbye!\n" );
|
|
exit( 0 );
|
|
}
|
|
|
|
#define SRAM_START ((void *) (&dummy_memory[0] + 0x00000000))
|
|
#define SRAM_END ((void *) (&dummy_memory[0] + 0x00000400))
|
|
|
|
#define RO_AREA_START ((void *) (&dummy_memory[0] + 0x00000100))
|
|
#define RO_AREA_END ((void *) (&dummy_memory[0] + 0x00000300))
|
|
|
|
#define NVD_START ((void *) (&dummy_memory[0] + 0x00003000))
|
|
#define NVD_END ((void *) (&dummy_memory[0] + 0x00003100))
|
|
|
|
#else /* normal stub (not stand-alone) */
|
|
|
|
#define SRAM_START ((void *) 0x00000000)
|
|
#define SRAM_END ((void *) 0x00400000)
|
|
|
|
#define RO_AREA_START ((void *) 0x00100000)
|
|
#define RO_AREA_END ((void *) 0x00300000)
|
|
|
|
#define NVD_START ((void *) 0x03000000)
|
|
#define NVD_END ((void *) 0x03100000)
|
|
|
|
#endif /* STANDALONE */
|
|
|
|
|
|
|
|
|
|
/* gdb gdb gdb gdb gdb gdb gdb gdb gdb gdb gdb gdb gdb gdb gdb gdb gdb gdb
|
|
gdb gdb
|
|
gdb Here begins the gdb stub section. gdb
|
|
gdb The following functions were added by Cygnus, gdb
|
|
gdb to make this thing act like a gdb stub. gdb
|
|
gdb gdb
|
|
gdb gdb gdb gdb gdb gdb gdb gdb gdb gdb gdb gdb gdb gdb gdb gdb gdb gdb */
|
|
|
|
|
|
/* ------------------- global defines and data decl's -------------------- */
|
|
|
|
#define hexchars "0123456789abcdef"
|
|
|
|
/* there are 180 bytes of registers on a 68020 w/68881 */
|
|
/* many of the fpa registers are 12 byte (96 bit) registers */
|
|
#define NUMREGBYTES 180
|
|
#define NUMREGS 29
|
|
#define REGISTER_BYTE(regno) regno
|
|
|
|
enum regnames { D0, D1, D2, D3, D4, D5, D6, D7,
|
|
A0, A1, A2, A3, A4, A5, A6, A7,
|
|
PS, PC,
|
|
FP0, FP1,
|
|
FP2, FP3,
|
|
FP4, FP5,
|
|
FP6, FP7,
|
|
FPCONTROL, FPSTATUS, FPIADDR
|
|
};
|
|
|
|
unsigned long registers[NUMREGBYTES/4];
|
|
|
|
static long remote_debug;
|
|
|
|
#define BUFMAX MAX_IO_BUF_SIZE
|
|
static char inbuffer[BUFMAX], outbuffer[BUFMAX];
|
|
static char spare_buffer[BUFMAX];
|
|
|
|
|
|
struct stub_trace_frame
|
|
{
|
|
int valid;
|
|
unsigned long frame_id;
|
|
unsigned long tdp_id;
|
|
FRAME_DEF *frame_data;
|
|
COLLECTION_FORMAT_DEF *format;
|
|
unsigned long traceregs[NUMREGBYTES/4];
|
|
unsigned char *stack_data;
|
|
unsigned char *memrange_data;
|
|
} curframe;
|
|
|
|
/* ------------------- function prototypes -------------------- */
|
|
|
|
void handle_request ( char * );
|
|
|
|
/* ------------------- Implementation -------------------- */
|
|
|
|
static void
|
|
discard_packet( void )
|
|
{
|
|
lan_input_queue.head_index = lan_input_queue.tail_index;
|
|
|
|
lan_input_queue.gdb_packet_start =
|
|
lan_input_queue.gdb_packet_end =
|
|
lan_input_queue.gdb_packet_csum1 =
|
|
lan_input_queue.gdb_packet_csum2 = -1;
|
|
}
|
|
|
|
/* Utility function: convert an ASCII isxdigit to a hex nybble */
|
|
|
|
static long
|
|
hex( char ch )
|
|
{
|
|
if ( (ch >= 'A') && (ch <= 'F') )
|
|
return ch - 'A' + 10;
|
|
if ( (ch >= 'a') && (ch <= 'f') )
|
|
return ch - 'a' + 10;
|
|
if ( (ch >= '0') && (ch <= '9') )
|
|
return ch - '0';
|
|
return -1;
|
|
}
|
|
|
|
static void
|
|
getpacket( void )
|
|
{
|
|
unsigned char our_checksum, their_checksum;
|
|
char *copy = inbuffer;
|
|
unsigned char c;
|
|
|
|
our_checksum = 0;
|
|
|
|
/* first find the '$' */
|
|
while ((c = lan_next_queue_char ( &lan_input_queue )) != '$')
|
|
if (c == 0) /* ??? Protocol error? (paranoia) */
|
|
{
|
|
/* PROTOCOL ERROR (missing '$') */
|
|
/*NACK_PKT( );*/ /*<ETHERNET>*/
|
|
return;
|
|
}
|
|
|
|
/* Now copy the message (up to the '#') */
|
|
for (c = lan_next_queue_char ( &lan_input_queue ); /* skip the '$' */
|
|
c != 0 && c != '#'; /* stop at the '#' */
|
|
c = lan_next_queue_char ( &lan_input_queue ))
|
|
{
|
|
*copy++ = c;
|
|
our_checksum += c;
|
|
}
|
|
*copy++ = '\0'; /* terminate the copy */
|
|
|
|
if (c == 0) /* ??? Protocol error? (paranoia) */
|
|
{
|
|
/* PROTOCOL ERROR (missing '#') */
|
|
/*NACK_PKT( );*/ /*<ETHERNET>*/
|
|
return;
|
|
}
|
|
their_checksum = hex( lan_next_queue_char ( &lan_input_queue ) ) << 4;
|
|
their_checksum += hex( lan_next_queue_char ( &lan_input_queue ) );
|
|
|
|
/* Now reset the queue packet-recognition bits */
|
|
discard_packet( );
|
|
|
|
if ( remote_debug ||
|
|
our_checksum == their_checksum )
|
|
{
|
|
ACK_PKT( ); /* good packet */
|
|
/* Parse and process the packet */
|
|
handle_request( inbuffer );
|
|
}
|
|
else
|
|
/* PROTOCOL ERROR (bad check sum) */
|
|
NACK_PKT( );
|
|
}
|
|
|
|
/* EMC will provide a better implementation
|
|
(perhaps just of LAN_PUT_CHAR) that does not block.
|
|
For now, this works. */
|
|
|
|
|
|
static void
|
|
putpacket( char *str )
|
|
{
|
|
unsigned char checksum;
|
|
|
|
/* '$'<packet>'#'<checksum> */
|
|
|
|
if ( VIA_ETHERNET == gdb_host_comm )
|
|
{
|
|
char *p_out;
|
|
long length;
|
|
|
|
p_out = eth_outbuffer;
|
|
length = 0;
|
|
|
|
|
|
if ( YES == gdb_cat_ack )
|
|
{
|
|
*p_out++ = '+';
|
|
++length;
|
|
}
|
|
|
|
gdb_cat_ack = NO;
|
|
|
|
|
|
*p_out++ = '$';
|
|
++length;
|
|
|
|
checksum = 0;
|
|
|
|
while ( *str )
|
|
{
|
|
*p_out++ = *str;
|
|
++length;
|
|
checksum += *str++;
|
|
}
|
|
|
|
*p_out++ = '#';
|
|
*p_out++ = hexchars[checksum >> 4];
|
|
*p_out = hexchars[checksum % 16];
|
|
length += 3;
|
|
|
|
eth_to_gdb( (UCHAR *) eth_outbuffer, length );
|
|
}
|
|
|
|
else
|
|
{
|
|
|
|
/* via RS-232 */
|
|
do {
|
|
LAN_PUT_CHAR( '$' );
|
|
checksum = 0;
|
|
|
|
while ( *str )
|
|
{
|
|
LAN_PUT_CHAR( *str );
|
|
checksum += *str++;
|
|
}
|
|
|
|
LAN_PUT_CHAR( '#' );
|
|
LAN_PUT_CHAR( hexchars[checksum >> 4] );
|
|
LAN_PUT_CHAR( hexchars[checksum % 16] );
|
|
} while ( 0 /* get_debug_char( ) != '+' */ );
|
|
/* XXX FIXME: not waiting for the ack. */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* FUNCTION NAME: gdb_get_eth_input
|
|
*
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
*
|
|
* RETURN VALUE: None.
|
|
*
|
|
*
|
|
* USED GLOBAL VARIABLES:
|
|
*
|
|
*
|
|
* AFFECTED GLOBAL VARIABLES/SIDE EFFECTS:
|
|
*
|
|
*
|
|
* NOTES:
|
|
*
|
|
*
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
void gdb_get_eth_input( unsigned char *buf, long length )
|
|
|
|
{
|
|
|
|
gdb_host_comm = VIA_ETHERNET;
|
|
|
|
for ( ; 0 < length; ++buf, --length)
|
|
{
|
|
|
|
if ( *buf == CONTROL_C )
|
|
{
|
|
/* can't stop the target, but we can tell gdb to stop waiting... */
|
|
discard_packet( );
|
|
putpacket( "S03" ); /* send back SIGINT to the debugger */
|
|
}
|
|
|
|
else
|
|
{
|
|
lan_add_to_queue( (long) *buf, &lan_input_queue );
|
|
get_gdb_input( (long) *buf, &lan_input_queue );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
}
|
|
/* end of 'gdb_get_eth_input'
|
|
*===========================================================================*/
|
|
|
|
|
|
|
|
|
|
/* STDOUT STDOUT STDOUT STDOUT STDOUT STDOUT STDOUT STDOUT STDOUT STDOUT
|
|
Stuff pertaining to simulating stdout by sending chars to gdb to be echoed.
|
|
|
|
Dear reader:
|
|
This code is based on the premise that if GDB receives a packet
|
|
from the stub that begins with the character CAPITAL-OH, GDB will
|
|
echo the rest of the packet to GDB's console / stdout. This gives
|
|
the stub a way to send a message directly to the user. In practice,
|
|
(as currently implemented), GDB will only accept such a packet when
|
|
it believes the target to be running (ie. when you say STEP or
|
|
CONTINUE); at other times it does not expect it. This will probably
|
|
change as a side effect of the "asynchronous" behavior.
|
|
|
|
Functions: gdb_putchar(char ch)
|
|
gdb_write(char *str, int len)
|
|
gdb_puts(char *str)
|
|
gdb_error(char *format, char *parm)
|
|
*/
|
|
|
|
#if 0 /* avoid compiler warning while this is not used */
|
|
|
|
/* Function: gdb_putchar(int)
|
|
Make gdb write a char to stdout.
|
|
Returns: the char */
|
|
|
|
static int
|
|
gdb_putchar( long ch )
|
|
{
|
|
char buf[4];
|
|
|
|
buf[0] = 'O';
|
|
buf[1] = hexchars[ch >> 4];
|
|
buf[2] = hexchars[ch & 0x0F];
|
|
buf[3] = 0;
|
|
putpacket( buf );
|
|
return ch;
|
|
}
|
|
#endif
|
|
|
|
/* Function: gdb_write(char *, int)
|
|
Make gdb write n bytes to stdout (not assumed to be null-terminated).
|
|
Returns: number of bytes written */
|
|
|
|
static int
|
|
gdb_write( char *data, long len )
|
|
{
|
|
char *buf, *cpy;
|
|
long i;
|
|
|
|
buf = outbuffer;
|
|
buf[0] = 'O';
|
|
i = 0;
|
|
while ( i < len )
|
|
{
|
|
for ( cpy = buf+1;
|
|
i < len && cpy < buf + BUFMAX - 3;
|
|
i++ )
|
|
{
|
|
*cpy++ = hexchars[data[i] >> 4];
|
|
*cpy++ = hexchars[data[i] & 0x0F];
|
|
}
|
|
*cpy = 0;
|
|
putpacket( buf );
|
|
}
|
|
return len;
|
|
}
|
|
|
|
/* Function: gdb_puts(char *)
|
|
Make gdb write a null-terminated string to stdout.
|
|
Returns: the length of the string */
|
|
|
|
static int
|
|
gdb_puts( char *str )
|
|
{
|
|
return gdb_write( str, strlen( str ) );
|
|
}
|
|
|
|
/* Function: gdb_error(char *, char *)
|
|
Send an error message to gdb's stdout.
|
|
First string may have 1 (one) optional "%s" in it, which
|
|
will cause the optional second string to be inserted. */
|
|
|
|
#if 0
|
|
static void
|
|
gdb_error( char *format, char *parm )
|
|
{
|
|
static char buf[400];
|
|
char *cpy;
|
|
long len;
|
|
|
|
if ( remote_debug )
|
|
{
|
|
if ( format && *format )
|
|
len = strlen( format );
|
|
else
|
|
return; /* empty input */
|
|
|
|
if ( parm && *parm )
|
|
len += strlen( parm );
|
|
|
|
for ( cpy = buf; *format; )
|
|
{
|
|
if ( format[0] == '%' && format[1] == 's' ) /* include 2nd string */
|
|
{
|
|
format += 2; /* advance two chars instead of just one */
|
|
while ( parm && *parm )
|
|
*cpy++ = *parm++;
|
|
}
|
|
else
|
|
*cpy++ = *format++;
|
|
}
|
|
*cpy = '\0';
|
|
gdb_puts( buf );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void gdb_note (char *, int);
|
|
static int error_ret (int, char *, int);
|
|
|
|
static unsigned long
|
|
elinum_to_index (unsigned long elinum)
|
|
{
|
|
if ((elinum & 0xf0) == 0xd0)
|
|
return (elinum & 0x0f);
|
|
else if ((elinum & 0xf0) == 0xa0)
|
|
return (elinum & 0x0f) + 8;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
static long
|
|
index_to_elinum (unsigned long index)
|
|
{
|
|
if (index <= 7)
|
|
return index + 0xd0;
|
|
else if (index <= 15)
|
|
return (index - 8) + 0xa0;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
|
|
/*
|
|
READMEM READMEM READMEM READMEM READMEM READMEM READMEM READMEM READMEM
|
|
|
|
The following code pertains to reading memory from the target.
|
|
Some sort of exception handling should be added to make it safe.
|
|
|
|
READMEM READMEM READMEM READMEM READMEM READMEM READMEM READMEM READMEM
|
|
|
|
Safe Memory Access:
|
|
|
|
All reads and writes into the application's memory will pass thru
|
|
get_uchar() or set_uchar(), which check whether accessing their
|
|
argument is legal before actual access (thus avoiding a bus error).
|
|
|
|
*/
|
|
|
|
enum { SUCCESS = 0, FAIL = -1 };
|
|
|
|
#if 0
|
|
static long get_uchar ( const unsigned char * );
|
|
#endif
|
|
static long set_uchar ( unsigned char *, unsigned char );
|
|
static long read_access_violation ( const void * );
|
|
static long write_access_violation ( const void * );
|
|
static long read_access_range(const void *, long);
|
|
static DTC_RESPONSE find_memory(unsigned char *,long,unsigned char **,long *);
|
|
|
|
static int
|
|
dtc_error_ret (int ret, char *src, DTC_RESPONSE code)
|
|
{
|
|
if (src)
|
|
sprintp (spare_buffer,
|
|
"'%s' returned DTC error '%s'.\n", src, get_err_text (code));
|
|
else
|
|
sprintp (spare_buffer, "DTC error '%s'.\n", get_err_text (code));
|
|
|
|
gdb_puts (spare_buffer);
|
|
return ret;
|
|
}
|
|
|
|
|
|
#if 0
|
|
/* I think this function is unnecessary since the introduction of
|
|
adbg_find_memory_addr_in_frame. */
|
|
|
|
/* Return the number of expressions in the format associated with a
|
|
given trace frame. */
|
|
static int
|
|
count_frame_exprs (FRAME_DEF *frame)
|
|
{
|
|
CFD *format;
|
|
T_EXPR *expr;
|
|
int num_exprs;
|
|
|
|
/* Get the format from the frame. */
|
|
get_frame_format_pointer (frame, &format);
|
|
|
|
/* Walk the linked list of expressions, and count the number of
|
|
expressions we find there. */
|
|
num_exprs = 0;
|
|
for (expr = format->p_cfd_expr; expr; expr = expr->next)
|
|
num_exprs++;
|
|
|
|
return num_exprs;
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
/* Function: get_frame_addr
|
|
*
|
|
* Description: If the input memory address was collected in the
|
|
* current trace frame, then lookup and return the address
|
|
* from within the trace buffer from which the collected byte
|
|
* may be retrieved. Else return -1. */
|
|
|
|
unsigned char *
|
|
get_frame_addr ( const unsigned char *addr )
|
|
{
|
|
unsigned char *base, *regs, *stack, *mem;
|
|
CFD *dummy;
|
|
DTC_RESPONSE ret;
|
|
|
|
/* first, see if addr is on the saved piece of stack for curframe */
|
|
if (curframe.format->stack_size > 0 &&
|
|
(base = (unsigned char *) curframe.traceregs[A7]) <= addr &&
|
|
addr < base + curframe.format->stack_size)
|
|
{
|
|
gdb_puts("STUB: get_frame_addr: call get_addr_to_frame_regs_stack_mem\n");
|
|
if ((ret = get_addr_to_frame_regs_stack_mem (curframe.frame_data,
|
|
&dummy,
|
|
(void *) ®s,
|
|
(void *) &stack,
|
|
(void *) &mem))
|
|
!= OK_TARGET_RESPONSE)
|
|
return (void *) dtc_error_ret (-1,
|
|
"get_addr_to_frame_regs_stack_mem",
|
|
ret);
|
|
else
|
|
return stack + (addr - base);
|
|
}
|
|
|
|
/* Next, try to find addr in the current frame's expression-
|
|
collected memory blocks. I'm sure this is at least quadradic in
|
|
time. */
|
|
{
|
|
int num_exprs = count_frame_exprs (curframe.frame_data);
|
|
int expr, block;
|
|
|
|
/* Try each expression in turn. */
|
|
for (expr = 0; expr < num_exprs; expr++)
|
|
{
|
|
for (block = 0; ; block++)
|
|
{
|
|
T_EXPR_DATA *data;
|
|
if (adbg_get_expr_data (curframe.frame_data,
|
|
'x', expr, block,
|
|
&data)
|
|
!= OK_TARGET_RESPONSE)
|
|
break;
|
|
else if ((unsigned char *) data->address <= addr
|
|
&& addr < ((unsigned char *) data->address + data->size))
|
|
{
|
|
/* We have found the right block; is it valid data?
|
|
Upper-case stamps mean bad data. */
|
|
if ('A' <= data->stamp && data->stamp <= 'Z')
|
|
{
|
|
gdb_puts("STUB: get_frame_addr: adbg_get_expr_data INVALID\n");
|
|
return (unsigned char *) -1;
|
|
}
|
|
else
|
|
{
|
|
if (remote_debug > 1)
|
|
{
|
|
sprintp(spare_buffer,
|
|
"STUB: get_frame_addr: got it [%x,%x)\n",
|
|
data->address, data->address + data->size);
|
|
gdb_puts(spare_buffer);
|
|
}
|
|
|
|
return (((unsigned char *) &data->data)
|
|
+ (addr - (unsigned char *) data->address));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* not found, return error */
|
|
return (unsigned char *) -1;
|
|
}
|
|
|
|
/*============================================================*/
|
|
|
|
static long get_uchar ( const unsigned char * addr )
|
|
{
|
|
unsigned char *frame_addr;
|
|
|
|
if ( read_access_violation ( addr ) )
|
|
return ( -1 ); /* Access error */
|
|
|
|
if (curframe.valid) /* if debugging a trace frame? */
|
|
{
|
|
/* If the requested address was collected in the current frame,
|
|
* then fetch and return the data from the trace buffer.
|
|
*/
|
|
if ((frame_addr = get_frame_addr (addr)) != (unsigned char *) -1)
|
|
return ( *frame_addr );
|
|
/* If the requested address is in the Code Section,
|
|
* let's be magnanimous and read it anyway (else we shall
|
|
* not be able to disassemble, find function prologues, etc.)
|
|
*/
|
|
else if (CS_CODE_START <= (unsigned long) addr &&
|
|
(unsigned long) addr < CS_CODE_START + CS_CODE_SIZE)
|
|
return (*addr);
|
|
else
|
|
return ( -1 ); /* "Access error" (the data was not collected) */
|
|
}
|
|
else
|
|
/* Not debugging a trace frame, read the data from live memory. */
|
|
return ( *addr ); /* Meaningful result >= 0 */
|
|
}
|
|
#endif
|
|
|
|
/*============================================================*/
|
|
|
|
static long set_uchar ( unsigned char * addr, unsigned char val )
|
|
{
|
|
long check_result = write_access_violation ( addr );
|
|
|
|
if ( check_result != 0L )
|
|
return ( check_result ); /* Access error */
|
|
|
|
return ( *addr = val ); /* Successful writing */
|
|
}
|
|
|
|
/*============================================================*/
|
|
|
|
/*
|
|
* Function read_access_violation() below returns TRUE if dereferencing
|
|
* its argument for reading would cause a bus error - and FALSE otherwise:
|
|
*/
|
|
|
|
static long read_access_violation ( const void * addr )
|
|
{
|
|
return ( ( ( addr < SRAM_START ) || ( addr >= SRAM_END ) ) &&
|
|
( ( addr < NVD_START ) || ( addr >= NVD_END ) ) );
|
|
}
|
|
|
|
/*============================================================*/
|
|
|
|
/*
|
|
* Function write_access_violation() below returns zero if dereferencing
|
|
* its argument for writing is safe, -1 on a soft error (the argument
|
|
* falls into the write-protected area), -2 on a hard error (the argument
|
|
* points to a non-existent memory location). In other words, it returns
|
|
* FALSE when no bus error is expected - and an error code otherwise:
|
|
*/
|
|
|
|
static long write_access_violation ( const void * addr )
|
|
{
|
|
/*
|
|
* The boundaries of the write-protected area have to be received via
|
|
* an API provided in the Symmetrix core code. For now, these limits
|
|
* are hard-coded:
|
|
*/
|
|
|
|
if ( ( addr >= RO_AREA_START ) && ( addr < RO_AREA_END ) )
|
|
return ( -1 ); /* soft error */
|
|
|
|
if ( ( ( addr < SRAM_START ) || ( addr >= SRAM_END ) ) &&
|
|
( ( addr < NVD_START ) || ( addr >= NVD_END ) ) )
|
|
return ( -2 ); /* hard error */
|
|
|
|
return ( 0 );
|
|
}
|
|
|
|
|
|
/* read_access_range is like read_access_violation,
|
|
but returns the number of bytes we can read w/o faulting.
|
|
that is, it checks an address range and tells us what portion
|
|
(if any) of the prefix is safe to read without a bus error */
|
|
static long
|
|
read_access_range(const void *addr, long count)
|
|
{
|
|
if ((addr >= SRAM_START) && (addr < SRAM_END))
|
|
{
|
|
if ((char *)addr + count < (char *)SRAM_END)
|
|
return (count);
|
|
else
|
|
return ((char *)SRAM_END - (char *)addr);
|
|
}
|
|
else if (((char *)addr >= (char *)NVD_START) &&
|
|
((char *)addr < (char *)NVD_END))
|
|
{
|
|
if ((char *)addr + count < (char *)NVD_END)
|
|
return (count);
|
|
else
|
|
return ((char *)NVD_END - (char *)addr);
|
|
}
|
|
else
|
|
return (0);
|
|
}
|
|
|
|
/* Convert the memory pointed to by mem into hex, placing result in buf.
|
|
Return SUCCESS or FAIL.
|
|
If MAY_FAULT is non-zero, then we should return FAIL in response to
|
|
a fault; if zero treat a fault like any other fault in the stub. */
|
|
|
|
static long
|
|
mem2hex(unsigned char *mem, char *buf, long count, long may_fault)
|
|
{
|
|
long ndx;
|
|
long ndx2;
|
|
long ch;
|
|
long incr;
|
|
unsigned char *location;
|
|
DTC_RESPONSE status;
|
|
|
|
if (may_fault)
|
|
{
|
|
for (ndx = 0, incr = 1; (ndx < count) && (incr > 0); ndx += incr)
|
|
{
|
|
status = find_memory(mem, count - ndx, &location, &incr);
|
|
|
|
if (status == OK_TARGET_RESPONSE)
|
|
{
|
|
if (incr > 0)
|
|
{
|
|
for (ndx2 = 0; ndx2 < incr; ndx2++)
|
|
{
|
|
ch = *location++;
|
|
*buf++ = hexchars[ch >> 4];
|
|
*buf++ = hexchars[ch & 0xf];
|
|
}
|
|
mem += incr;
|
|
}
|
|
else if (incr <= 0) /* should never happen */
|
|
{
|
|
*buf = 0;
|
|
return (0);
|
|
}
|
|
}
|
|
else if (status == NOT_FOUND_TARGET_RESPONSE)
|
|
{
|
|
*buf = 0;
|
|
return (ndx); /* return amount copied */
|
|
}
|
|
else
|
|
{
|
|
*buf = 0;
|
|
return (0); /* XXX: how do we tell the user the status? */
|
|
}
|
|
}
|
|
*buf = 0;
|
|
return (count);
|
|
}
|
|
else
|
|
{
|
|
for (ndx = 0; ndx < count; ndx++)
|
|
{
|
|
ch = *mem++;
|
|
*buf++ = hexchars[ch >> 4];
|
|
*buf++ = hexchars[ch & 0xf];
|
|
}
|
|
*buf = 0;
|
|
return (count); /* we copied everything */
|
|
}
|
|
}
|
|
|
|
static DTC_RESPONSE
|
|
find_memory(unsigned char *mem, long count,
|
|
unsigned char **location, long *incr)
|
|
{
|
|
DTC_RESPONSE retval;
|
|
long length;
|
|
|
|
/* figure out how much of the memory range we can read w/o faulting */
|
|
count = read_access_range(mem, count);
|
|
if (count == 0)
|
|
return (NOT_FOUND_TARGET_RESPONSE);
|
|
|
|
if (curframe.valid)
|
|
{
|
|
unsigned char *mem_block;
|
|
unsigned char *mem_addr;
|
|
unsigned long mem_size;
|
|
unsigned long mem_stamp;
|
|
|
|
retval = adbg_find_memory_addr_in_frame(curframe.frame_data, mem,
|
|
(unsigned long **)&mem_block,
|
|
(unsigned long **)&mem_addr,
|
|
&mem_size, &mem_stamp);
|
|
|
|
switch (retval)
|
|
{
|
|
case OK_TARGET_RESPONSE:
|
|
#if 0
|
|
printp("FOUND: mem %x block %x addr %x size %d stamp %x\n",
|
|
mem, mem_block, mem_addr, mem_size, mem_stamp);
|
|
#endif
|
|
*location = mem_block + (mem - mem_addr);
|
|
length = mem_size - (mem - mem_addr);
|
|
|
|
if (length < count)
|
|
*incr = length;
|
|
else
|
|
*incr = count;
|
|
|
|
break;
|
|
|
|
case NOT_FOUND_TARGET_RESPONSE:
|
|
case NEAR_FOUND_TARGET_RESPONSE:
|
|
#if 0
|
|
printp("NOT FOUND: mem %x, checking code region\n", mem);
|
|
#endif
|
|
/* check to see if it's in the code region */
|
|
if ((CS_CODE_START <= (long)mem) &&
|
|
((long)mem < CS_CODE_START + CS_CODE_SIZE))
|
|
{
|
|
/* some or all of the address range is in the code */
|
|
*location = mem;
|
|
if ((long)mem + count <= CS_CODE_START + CS_CODE_SIZE)
|
|
*incr = count; /* it's totally in the code */
|
|
else
|
|
/* how much is in the code? */
|
|
*incr = CS_CODE_START + CS_CODE_SIZE - (long)mem;
|
|
#if 0
|
|
printp("FOUND in code region: %x\n", mem);
|
|
#endif
|
|
retval = OK_TARGET_RESPONSE;
|
|
}
|
|
else
|
|
retval = NOT_FOUND_TARGET_RESPONSE;
|
|
|
|
break;
|
|
|
|
default:
|
|
#if 0
|
|
printp("BAD RETURN: %d\n", retval);
|
|
#endif
|
|
retval = NOT_FOUND_TARGET_RESPONSE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*location = mem;
|
|
*incr = count;
|
|
retval = OK_TARGET_RESPONSE;
|
|
}
|
|
|
|
return (retval);
|
|
}
|
|
|
|
/* Convert the hex array pointed to by buf into binary to be placed in mem.
|
|
Return SUCCESS or FAIL. */
|
|
|
|
static long
|
|
hex2mem( char *buf, unsigned char *mem, long count, long may_fault )
|
|
{
|
|
long i, ch;
|
|
|
|
for ( i=0; i<count; i++ )
|
|
{
|
|
ch = hex( *buf++ ) << 4;
|
|
ch = ch + hex( *buf++ );
|
|
if ( may_fault )
|
|
{
|
|
ch = set_uchar( mem++, ch );
|
|
if ( ch < 0 ) /* negative return indicates error */
|
|
return FAIL;
|
|
}
|
|
else
|
|
*mem++ = ch;
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
|
|
/**********************************************/
|
|
/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
|
|
/* RETURN NUMBER OF CHARS PROCESSED */
|
|
/**********************************************/
|
|
|
|
static int
|
|
hexToInt( char **ptr, unsigned long *intValue )
|
|
{
|
|
long numChars = 0;
|
|
long hexValue;
|
|
|
|
*intValue = 0;
|
|
while ( **ptr )
|
|
{
|
|
hexValue = hex( **ptr );
|
|
if ( hexValue >=0 )
|
|
{
|
|
*intValue = (*intValue << 4) | hexValue;
|
|
numChars ++;
|
|
}
|
|
else
|
|
break;
|
|
(*ptr)++;
|
|
}
|
|
return numChars;
|
|
}
|
|
|
|
static volatile long gdb_handling_trap1;
|
|
static volatile long gdb_handling_sstrace;
|
|
static volatile long gdb_signo;
|
|
|
|
/*
|
|
Here is the "callable" stub entry point.
|
|
Call this function with a GDB request as an argument,
|
|
and it will service the request and return.
|
|
|
|
May be further broken up as we go along, with individual requests
|
|
broken out as separate functions.
|
|
*/
|
|
|
|
static char * handle_trace_query (char *);
|
|
static char * handle_trace_set (char *);
|
|
static int handle_format (char **request, CFD *format);
|
|
static unsigned long crc32 (unsigned char *buf, int len, unsigned long crc);
|
|
static char * crc_query (char *);
|
|
static char * handle_test (char *);
|
|
|
|
void
|
|
handle_request( char *request )
|
|
{
|
|
#if 0
|
|
remote_debug = 2;
|
|
#endif
|
|
switch( *request++ )
|
|
{
|
|
case 'k': /* "kill" */
|
|
curframe.valid = FALSE;
|
|
putpacket ("");
|
|
break;
|
|
case 'D': /* "detach" */
|
|
curframe.valid = FALSE;
|
|
putpacket ("");
|
|
break;
|
|
default: /* Unknown code. Return an empty reply message. */
|
|
putpacket( "" ); /* return empty packet */
|
|
break;
|
|
|
|
case 'H': /* Set thread for subsequent operations.
|
|
Hct... c = 'c' for thread used in step and continue;
|
|
t... can be -1 for all threads.
|
|
c = 'g' for thread used in other operations.
|
|
If zero, pick a thread, any thread. */
|
|
|
|
putpacket( "OK" );
|
|
break;
|
|
|
|
case 'g': /* Read registers.
|
|
Each byte of register data is described by
|
|
two hex digits. registers are in the
|
|
internal order for GDB, and the bytes in a
|
|
register are in the same order the machine
|
|
uses. */
|
|
{
|
|
/* Return the values in (one of) the registers cache(s).
|
|
Several situations may pertain:
|
|
1) We're synchronous, in which case the "registers" array
|
|
should actually be current.
|
|
2) We're asynchronous, in which case the "registers" array
|
|
holds whatever was cached most recently.
|
|
3) We're looking at a trace frame that was collected earlier:
|
|
we will return those earlier registers.
|
|
*/
|
|
|
|
/* all registers default to zero */
|
|
memset (outbuffer, '0', NUMREGBYTES);
|
|
outbuffer[NUMREGBYTES] = '\0';
|
|
|
|
if (curframe.valid) /* debugging a trace frame */
|
|
mem2hex( (unsigned char*) curframe.traceregs,
|
|
outbuffer, NUMREGBYTES, 0 );
|
|
else
|
|
mem2hex( (unsigned char*) registers, outbuffer, NUMREGBYTES, 0 );
|
|
|
|
putpacket( outbuffer );
|
|
}
|
|
break;
|
|
case 'G': /* Write registers.
|
|
Gxxxxxxxx Each byte of register data is described by
|
|
two hex digits. */
|
|
if (curframe.valid) /* debugging a trace frame */
|
|
putpacket ("E03"); /* can't write regs into a trace frame! */
|
|
else
|
|
{
|
|
/* Write the values into the local registers cache...
|
|
Note that no actual registers are being changed. */
|
|
|
|
hex2mem( request,
|
|
(unsigned char *) registers, NUMREGBYTES, 0 );
|
|
putpacket( "OK" );
|
|
}
|
|
break;
|
|
case 'P': /* Write (single) register.
|
|
Pnn=xxxxxxxx register nn gets value xxxxxxxx;
|
|
two hex digits for each byte in the register
|
|
(target byte order). */
|
|
|
|
if (curframe.valid)
|
|
putpacket ("E03"); /* can't write regs into a trace frame! */
|
|
else
|
|
{
|
|
unsigned long regno;
|
|
|
|
if ( hexToInt( &request, ®no ) && *(request++) == '=' )
|
|
{
|
|
if ( regno < NUMREGS )
|
|
{
|
|
hexToInt( &request,
|
|
(unsigned long *) ®isters[REGISTER_BYTE(regno)]);
|
|
|
|
putpacket( "OK" );
|
|
}
|
|
else
|
|
putpacket( "E01" ); /* bad packet or regno */
|
|
}
|
|
}
|
|
break;
|
|
case 'm': /* Read memory.
|
|
mAAAAAAAA,LLLL AAAAAAAA is address, LLLL is length.
|
|
Reply can be fewer bytes than requested
|
|
if able to read only part of the data. */
|
|
{
|
|
unsigned long addr, len;
|
|
|
|
if ( hexToInt( &request, &addr ) &&
|
|
*(request++) == ',' &&
|
|
hexToInt( &request, &len ) )
|
|
{
|
|
/* better not overwrite outbuffer! */
|
|
if ( len > (BUFMAX / 2) - 5 )
|
|
len = (BUFMAX / 2) - 5;
|
|
if (mem2hex((unsigned char *) addr, outbuffer, len, 1) == 0) /* XXX: eventually use returned value */
|
|
putpacket( "E03" ); /* read fault (access denied) */
|
|
else
|
|
putpacket( outbuffer ); /* read succeeded */
|
|
}
|
|
else
|
|
putpacket( "E01" ); /* badly formed read request */
|
|
|
|
}
|
|
break;
|
|
case 'M': /* Write memory.
|
|
Maaaaaaaa,llll:xxxx aaaaaaaa is address, llll is length;
|
|
xxxx is data to write. */
|
|
|
|
{
|
|
unsigned long addr, len;
|
|
|
|
if (curframe.valid) /* can't write memory into a trace frame! */
|
|
putpacket ("E03"); /* "access denied" */
|
|
else /*** if ( write_access_enabled ) ***/
|
|
{
|
|
if ( hexToInt( &request, &addr ) &&
|
|
*(request++) == ',' &&
|
|
hexToInt( &request, &len ) &&
|
|
*(request++) == ':' )
|
|
{
|
|
if (len == 2 &&
|
|
addr >= CS_CODE_START &&
|
|
addr <= LAST_CS_WORD)
|
|
{
|
|
unsigned long val;
|
|
|
|
if ( !hexToInt( &request, &val ) ||
|
|
write_to_protected_mem( (void *)addr, val ) )
|
|
putpacket( "E03" ); /* write fault (access denied) */
|
|
else
|
|
putpacket( "OK" ); /* write succeeded */
|
|
}
|
|
else
|
|
{
|
|
if ( hex2mem( request, (unsigned char*) addr, len, 1 ) )
|
|
putpacket( "E03" ); /* write fault (access denied) */
|
|
else
|
|
putpacket( "OK" ); /* write succeeded */
|
|
}
|
|
}
|
|
else
|
|
putpacket( "E02" ); /* badly formed write request */
|
|
}
|
|
}
|
|
break;
|
|
case 'c': /* Continue.
|
|
cAAAAAAAA AAAAAAAA is address from which to resume.
|
|
If omitted, resume at current PC. */
|
|
|
|
{
|
|
unsigned long addr;
|
|
|
|
if (curframe.valid)
|
|
{
|
|
/* Don't continue if debugging a trace frame! */
|
|
gdb_puts ("Error: can't continue!\n");
|
|
putpacket ("S03");
|
|
}
|
|
else
|
|
{
|
|
gdb_signo = 3;
|
|
if (isxdigit(request[0]))
|
|
{
|
|
hexToInt(&request, &addr);
|
|
registers[REGISTER_BYTE(PC)] = addr;
|
|
}
|
|
|
|
gdb_handling_trap1 = FALSE;
|
|
gdb_handling_sstrace = FALSE;
|
|
sss_trace_flag = '\0';
|
|
}
|
|
}
|
|
break;
|
|
case 's': /* Step.
|
|
sAAAAAAAA AAAAAAAA is address from which to begin stepping.
|
|
If omitted, begin stepping at current PC. */
|
|
{
|
|
unsigned long addr;
|
|
|
|
if (curframe.valid)
|
|
{
|
|
/* Don't step if debugging a trace frame! */
|
|
gdb_puts ("Error: can't step!\n");
|
|
putpacket ("S03");
|
|
}
|
|
else
|
|
{
|
|
gdb_signo = 3;
|
|
if (isxdigit(request[0]))
|
|
{
|
|
hexToInt(&request, &addr);
|
|
registers[REGISTER_BYTE(PC)] = addr;
|
|
}
|
|
|
|
gdb_handling_trap1 = FALSE;
|
|
gdb_handling_sstrace = FALSE;
|
|
sss_trace_flag = 't';
|
|
}
|
|
}
|
|
break;
|
|
case 'C': /* Continue with signal.
|
|
Cxx;AAAAAAAA xx is signal number in hex;
|
|
AAAAAAAA is adddress from which to resume.
|
|
If ;AAAAAAAA omitted, continue from PC. */
|
|
|
|
{
|
|
unsigned long addr = 0;
|
|
|
|
if (!gdb_handling_trap1 || curframe.valid)
|
|
{
|
|
/* Don't continue if not currently in synchronous mode,
|
|
or if currently debugging a trace frame! */
|
|
gdb_puts( "Error: can't continue!\n" );
|
|
putpacket( "S03" ); /* "sigquit" (better idea?) */
|
|
}
|
|
else
|
|
{
|
|
gdb_signo = 3;
|
|
if ( isxdigit( *request ) )
|
|
{
|
|
hex2mem( request, (unsigned char *) &gdb_signo, 2, 0 );
|
|
request += 2;
|
|
if ( *request == ';' && isxdigit( *++request ) )
|
|
{
|
|
hexToInt( &request, &addr );
|
|
registers[REGISTER_BYTE(PC)] = addr;
|
|
}
|
|
}
|
|
gdb_handling_trap1 = FALSE;
|
|
gdb_handling_sstrace = FALSE;
|
|
sss_trace_flag = '\0';
|
|
}
|
|
}
|
|
break;
|
|
case 'S': /* Step with signal.
|
|
Sxx;AAAAAAAA xx is signal number in hex;
|
|
AAAAAAAA is adddress from which to begin stepping.
|
|
If ;AAAAAAAA omitted, begin stepping from PC. */
|
|
{
|
|
unsigned long addr = 0;
|
|
|
|
if (!gdb_handling_trap1 || curframe.valid)
|
|
{
|
|
/* Don't step if not currently in synchronous mode,
|
|
or if currently debugging a trace frame! */
|
|
gdb_puts( "Error: can't step!\n" );
|
|
putpacket( "S03" ); /* "sigquit" (better idea?) */
|
|
}
|
|
else
|
|
{
|
|
gdb_signo = 3;
|
|
if ( isxdigit( *request ) )
|
|
{
|
|
hex2mem( request, (unsigned char *) &gdb_signo, 2, 0 );
|
|
request += 2;
|
|
if ( *request == ';' && isxdigit( *++request ) )
|
|
{
|
|
hexToInt( &request, &addr );
|
|
registers[REGISTER_BYTE(PC)] = addr;
|
|
}
|
|
}
|
|
gdb_handling_trap1 = FALSE;
|
|
gdb_handling_sstrace = FALSE;
|
|
sss_trace_flag = 't';
|
|
}
|
|
}
|
|
break;
|
|
case '?': /* Query the latest reason for stopping.
|
|
Should be same reply as was last generated
|
|
for step or continue. */
|
|
|
|
if ( gdb_signo == 0 )
|
|
gdb_signo = 3; /* default to SIGQUIT */
|
|
outbuffer[ 0 ] = 'S';
|
|
outbuffer[ 1 ] = hexchars[ gdb_signo >> 4 ];
|
|
outbuffer[ 2 ] = hexchars[ gdb_signo & 0xf ];
|
|
outbuffer[ 3 ] = 0;
|
|
putpacket( outbuffer );
|
|
break;
|
|
|
|
case 'd': /* Toggle debug mode
|
|
I'm sure we can think of something interesting. */
|
|
|
|
remote_debug = !remote_debug;
|
|
putpacket( "" ); /* return empty packet */
|
|
break;
|
|
|
|
case 'q': /* general query */
|
|
switch (*request++)
|
|
{
|
|
default:
|
|
putpacket (""); /* nak a request which we don't handle */
|
|
break;
|
|
case 'T': /* trace query */
|
|
putpacket (handle_trace_query (request));
|
|
break;
|
|
case 'C': /* crc query (?) */
|
|
if (*request++ == 'R' &&
|
|
*request++ == 'C' &&
|
|
*request++ == ':')
|
|
putpacket (crc_query (request));
|
|
else
|
|
putpacket (""); /* unknown query */
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 'Q': /* general set */
|
|
switch (*request++)
|
|
{
|
|
default:
|
|
putpacket (""); /* nak a request which we don't handle */
|
|
break;
|
|
case 'T': /* trace */
|
|
putpacket (handle_trace_set (request));
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 'T':
|
|
/* call test function: TAAA,BBB,CCC
|
|
A, B, and C are arguments to pass to gdb_c_test. Reply is
|
|
"E01" (bad arguments) or "OK" (test function called). */
|
|
putpacket (handle_test (request));
|
|
break;
|
|
}
|
|
}
|
|
|
|
static TDP_SETUP_INFO tdp_temp;
|
|
static int trace_running;
|
|
|
|
/*
|
|
* Function msgcmp:
|
|
*
|
|
* If second argument (str) is matched in first argument,
|
|
* then advance first argument past end of str and return "SAME"
|
|
* else return "DIFFERENT" without changing first argument.
|
|
*
|
|
* Return: zero for DIFFERENT, non-zero for SUCCESS
|
|
*/
|
|
|
|
static int
|
|
msgcmp (char **msgp, char *str)
|
|
{
|
|
char *next;
|
|
|
|
if (msgp != 0 && str != 0) /* input validation */
|
|
if ((next = *msgp) != 0)
|
|
{
|
|
for (;
|
|
*next && *str && *next == *str;
|
|
next++, str++)
|
|
;
|
|
|
|
if (*str == 0) /* matched all of str in msg */
|
|
return (int) (*msgp = next); /* advance msg ptr past str */
|
|
}
|
|
return 0; /* failure */
|
|
}
|
|
|
|
static char *
|
|
handle_trace_query (char *request)
|
|
{
|
|
if (msgcmp (&request, "Status"))
|
|
{
|
|
if (adbg_check_if_active ())
|
|
{
|
|
gdb_puts ("Target trace is running.\n");
|
|
return "T1";
|
|
}
|
|
else
|
|
{
|
|
gdb_puts ("Target trace not running.\n");
|
|
trace_running = 0;
|
|
return "T0";
|
|
}
|
|
}
|
|
else /* unknown trace query */
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
|
|
static void
|
|
gdb_note (char *fmt, int arg1)
|
|
{
|
|
if (remote_debug > 1)
|
|
{
|
|
sprintp (spare_buffer, fmt, arg1);
|
|
gdb_puts (spare_buffer);
|
|
}
|
|
}
|
|
|
|
static int
|
|
error_ret (int ret, char *fmt, int arg1)
|
|
{
|
|
if (remote_debug > 0)
|
|
{
|
|
sprintp (spare_buffer, fmt, arg1);
|
|
gdb_puts (spare_buffer);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
handle_format (char **request, COLLECTION_FORMAT_DEF *format)
|
|
{
|
|
MEMRANGE_DEF m;
|
|
DTC_RESPONSE ret;
|
|
int elinum;
|
|
unsigned long regnum;
|
|
long bytecodes[(MAX_BYTE_CODES + sizeof (struct t_expr_tag))/ 4];
|
|
struct t_expr_tag *t_expr = (struct t_expr_tag *)bytecodes;
|
|
|
|
if (format->id == 0)
|
|
{
|
|
if ((ret = get_unused_format_id (&format->id)) != OK_TARGET_RESPONSE)
|
|
return dtc_error_ret (-1, "get_unused_format_id", ret);
|
|
|
|
if (**request == 'R')
|
|
{
|
|
(*request)++;
|
|
hexToInt (request, &format->regs_mask);
|
|
}
|
|
gdb_note ("STUB: call define_format (id = %d, ", format->id);
|
|
gdb_note ("regs_mask = 0x%X);\n", format->regs_mask);
|
|
|
|
if ((ret = define_format (format)) != OK_TARGET_RESPONSE)
|
|
{
|
|
sprintp (spare_buffer,
|
|
"'define_format': DTC error '%s' for format id %d.\n",
|
|
get_err_text (ret),
|
|
format->id);
|
|
gdb_puts (spare_buffer);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
while ((**request == 'M') || (**request == 'X'))
|
|
{
|
|
switch (**request)
|
|
{
|
|
case 'M': /* M<regnum>,<offset>,<size> */
|
|
(*request)++;
|
|
hexToInt(request, ®num);
|
|
|
|
if (regnum == 0 || regnum == (unsigned long) -1)
|
|
m.typecode = -1;
|
|
else if ((elinum = index_to_elinum (regnum)) > 0)
|
|
m.typecode = elinum;
|
|
else
|
|
return error_ret (-1,
|
|
"Memrange register %d is not between 0 and 15\n",
|
|
regnum);
|
|
|
|
if (*(*request)++ != ',')
|
|
return error_ret (-1,"Malformed memrange (comma #%d missing)\n",1);
|
|
hexToInt(request, &m.offset);
|
|
if (*(*request)++ != ',')
|
|
return error_ret (-1,"Malformed memrange (comma #%d missing)\n",2);
|
|
hexToInt(request, &m.size);
|
|
|
|
gdb_note ("STUB: call add_format_mem_range (typecode = 0x%x, ",
|
|
m.typecode);
|
|
gdb_note ("offset = 0x%X, ", m.offset);
|
|
gdb_note ("size = %d);\n", m.size);
|
|
if ((ret = add_format_mem_ranges (format->id, &m)) !=
|
|
OK_TARGET_RESPONSE)
|
|
{
|
|
dtc_error_ret (-1, "add_format_mem_ranges", ret);
|
|
sprintp (spare_buffer,
|
|
"format id %d: memrange (0x%x, 0x%x, 0x%x).\n",
|
|
format->id, m.typecode, m.offset, m.size);
|
|
gdb_puts (spare_buffer);
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
case 'X': /* X<length>,<bytecodes> */
|
|
{
|
|
unsigned long length;
|
|
|
|
(*request)++;
|
|
hexToInt(request, &length);
|
|
|
|
if ((length <= 0) || (length > MAX_BYTE_CODES))
|
|
return error_ret (-1,
|
|
"Bytecode expression length (%d) too large\n",
|
|
length);
|
|
|
|
if (*(*request)++ != ',')
|
|
return error_ret (-1,
|
|
"Malformed bytecode expr (comma#%d missing)\n",
|
|
1);
|
|
t_expr->next = NULL;
|
|
/* subtract one to account for expr[0] in header */
|
|
t_expr->size = sizeof(struct t_expr_tag) + length - 1;
|
|
t_expr->expr_size = length;
|
|
|
|
hex2mem(*request, &t_expr->expr[0], length, 0);
|
|
*request += 2 * length;
|
|
build_and_add_expression(format->id, t_expr);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static char *
|
|
handle_trace_set (char *request)
|
|
{
|
|
long n_frame;
|
|
unsigned long frameno, tdp, pc, start, stop;
|
|
DTC_RESPONSE ret = -1;
|
|
static COLLECTION_FORMAT_DEF tempfmt1;
|
|
static char enable;
|
|
static char retbuf[20];
|
|
|
|
if (msgcmp (&request, "init"))
|
|
{
|
|
gdb_note ("STUB: call clear_trace_state();\n", 0);
|
|
curframe.valid = 0; /* all old frames become invalid now */
|
|
if ((ret = clear_trace_state ()) == OK_TARGET_RESPONSE)
|
|
return "OK";
|
|
else
|
|
{
|
|
sprintp (retbuf, "E2%x", ret);
|
|
return (char *) dtc_error_ret ((int) &retbuf,
|
|
"clear_trace_state",
|
|
ret);
|
|
}
|
|
}
|
|
else if (msgcmp (&request, "Start"))
|
|
{
|
|
trace_running = 1;
|
|
curframe.valid = 0; /* all old frames become invalid now */
|
|
gdb_note ("STUB: call start_trace_experiment();\n", 0);
|
|
adbg_save_trace_in_nvd ();
|
|
if ((ret = start_trace_experiment ()) == OK_TARGET_RESPONSE)
|
|
return "OK";
|
|
else
|
|
{
|
|
sprintp (retbuf, "E2%x", ret);
|
|
return (char *) dtc_error_ret ((int) &retbuf,
|
|
"start_trace_experiment",
|
|
ret);
|
|
}
|
|
}
|
|
else if (msgcmp (&request, "Stop"))
|
|
{
|
|
trace_running = 0;
|
|
if (adbg_check_if_active ())
|
|
{
|
|
gdb_note ("STUB: call end_trace_experiment();\n", 0);
|
|
if ((ret = end_trace_experiment ()) == OK_TARGET_RESPONSE)
|
|
return "OK";
|
|
else
|
|
{
|
|
sprintp (retbuf, "E2%x", ret);
|
|
return (char *) dtc_error_ret ((int) &retbuf,
|
|
"end_trace_experiment",
|
|
ret);
|
|
}
|
|
}
|
|
else return "OK";
|
|
}
|
|
/* "TDP:" (The 'T' was consumed in handle_request.) */
|
|
else if (msgcmp (&request, "DP:"))
|
|
{
|
|
/* TDP:<id>:<addr>:{D,E}:<stepcount>:<pass_limit>{R[M,X]+}<tdp-format>
|
|
{S{R[M,X]+}}<tp-format>
|
|
|
|
D -- disable tracepoint (illegal from EMC's point of view)
|
|
E -- enable tracepoint?
|
|
|
|
R -- regs format: R<regs-mask>
|
|
M -- memory format: M<regnum>,<offset>,<size>
|
|
X -- expr format: X<size>,<bytecodes>
|
|
S -- fencepost between trap formats and stepping formats.
|
|
*/
|
|
|
|
/* state variable, required for splitting TDP packets. */
|
|
static int doing_step_formats;
|
|
|
|
/*
|
|
* TDP: packets may now be split into multiple packets.
|
|
* If a TDP packet is to be continued in another packet, it
|
|
* must end in a "-" character. The subsequent continuation
|
|
* packet will then begin with a "-" character, between the
|
|
* token "TDP:" and the tdp_id field. The ID and address
|
|
* will be repeated in each sub-packet. The step_count,
|
|
* pass_count, and 'enabled' field must appear in the first
|
|
* packet. The boundary between sub-packets may not appear
|
|
* between the "S" that denotes the start of stepping "formats",
|
|
* and the regs_mask that follows it. The split may also not
|
|
* occur in the middle of either a memrange description or a
|
|
* bytecode string. -- MVS
|
|
*/
|
|
|
|
if (*request == '-') /* this is a continuation of a
|
|
trace definition in progress */
|
|
{
|
|
unsigned long temp_id, temp_addr;
|
|
|
|
request++;
|
|
if (!(hexToInt (&request, &temp_id) &&
|
|
*request++ == ':'))
|
|
return "E11"; /* badly formed packet, field 1 */
|
|
|
|
if (!(hexToInt (&request, (unsigned long *) &temp_addr) &&
|
|
*request++ == ':'))
|
|
return "E12"; /* badly formed packet, field 2 */
|
|
|
|
if (temp_id != tdp_temp.id)
|
|
return "E11"; /* something wrong: field 1 doesn't match */
|
|
if (temp_addr != (unsigned long) tdp_temp.addr)
|
|
return "E12"; /* something wrong: field 2 doesn't match */
|
|
}
|
|
else /* This is a new TDP definition */
|
|
{
|
|
memset ((char *) &tdp_temp, 0, sizeof (tdp_temp));
|
|
memset ((char *) &tempfmt1, 0, sizeof (tempfmt1));
|
|
doing_step_formats = FALSE;
|
|
|
|
if (!(hexToInt (&request, &tdp_temp.id) &&
|
|
*request++ == ':'))
|
|
return "E11"; /* badly formed packet, field 1 */
|
|
|
|
if (!(hexToInt (&request, (unsigned long *) &tdp_temp.addr) &&
|
|
*request++ == ':'))
|
|
return "E12"; /* badly formed packet, field 2 */
|
|
|
|
if (!(((enable = *request++) == 'D' || enable == 'E') &&
|
|
*request++ == ':'))
|
|
return "E13"; /* badly formed packet, field 3 */
|
|
#if 0
|
|
if (enable == 'D')
|
|
{
|
|
gdb_puts ("Disabling of tracepoints not supported by EMC target\n");
|
|
return "E20";
|
|
}
|
|
#endif
|
|
if (!(hexToInt (&request, &tdp_temp.stepcount) &&
|
|
*request++ == ':'))
|
|
return "E14"; /* badly formed packet, field 4 */
|
|
|
|
if (!hexToInt (&request, &tdp_temp.pass_limit))
|
|
return "E15"; /* badly formed packet, field 5 */
|
|
|
|
}
|
|
|
|
/* Typically, the first group of collection descriptors
|
|
refers to the trap collection. There is an "S" token
|
|
to act as a fencepost between collection descriptors for
|
|
the trap, and those for the single-stepping.
|
|
|
|
However, when the packet is split up into several packets,
|
|
this "S" token may already have been seen in a previous
|
|
sub-packet; so we have to remember it in a state variable. */
|
|
|
|
if (*request == 'R' || *request == 'M' || *request == 'X')
|
|
{
|
|
if (handle_format (&request, &tempfmt1))
|
|
return "E16";
|
|
if (doing_step_formats)
|
|
tdp_temp.tp_format_p = tempfmt1.id;
|
|
else
|
|
tdp_temp.tdp_format_p = tempfmt1.id;
|
|
}
|
|
|
|
/* When we see the "S" token, we remember it in a state variable
|
|
(in case the packet is split up and continued in another message),
|
|
and discard all current state from the collection "format". */
|
|
if (*request == 'S')
|
|
{
|
|
doing_step_formats = TRUE;
|
|
/* discard prev format and start a new one */
|
|
memset ((char *) &tempfmt1, 0, sizeof (tempfmt1));
|
|
request++;
|
|
|
|
/* Having seen the "S" fencepost, it is now possible that
|
|
we will see some more collection descriptors pertaining
|
|
to the stepping collection. */
|
|
if (*request == 'R' || *request == 'M' || *request == 'X')
|
|
{
|
|
if (handle_format (&request, &tempfmt1))
|
|
return "E17";
|
|
/* new format ID is tp_format */
|
|
tdp_temp.tp_format_p = tempfmt1.id;
|
|
}
|
|
}
|
|
|
|
if (*request == '-') /* this TDP definition will be continued. */
|
|
sprintp (retbuf, "OK");
|
|
else if (enable == 'E') /* end of TDP definition: pass to ADBG (if enabled!) */
|
|
{
|
|
gdb_note ("STUB: call define_tdp (id %d, ", tdp_temp.id);
|
|
gdb_note ("addr 0x%X, ", (int) tdp_temp.addr);
|
|
gdb_note ("passc %d, ", tdp_temp.pass_limit);
|
|
gdb_note ("stepc %d, ", tdp_temp.stepcount);
|
|
gdb_note ("TDP fmt #%d, ", tdp_temp.tdp_format_p);
|
|
gdb_note ("TP fmt #%d);\n", tdp_temp.tp_format_p);
|
|
|
|
ret = define_tdp (tdp_temp.id, &tdp_temp, 0);
|
|
|
|
if (ret == OK_TARGET_RESPONSE)
|
|
{
|
|
sprintp (retbuf, "OK");
|
|
}
|
|
else
|
|
{
|
|
sprintp (spare_buffer,
|
|
"'define_tdp' returned DTC error '%s' for tracepoint %d.\n",
|
|
get_err_text (ret),
|
|
tdp_temp.id);
|
|
gdb_puts (spare_buffer);
|
|
sprintp (retbuf, "E2%x", ret);
|
|
}
|
|
/* Redundant, but let's try to make sure this state gets discarded. */
|
|
{
|
|
memset ((char *) &tdp_temp, 0, sizeof (tdp_temp));
|
|
memset ((char *) &tempfmt1, 0, sizeof (tempfmt1));
|
|
}
|
|
}
|
|
else /* ADBG_DTC does not support disabled tracepoints -- ignore it. */
|
|
gdb_note ("STUB: ignoring disabled tracepoint %d.\n", tdp_temp.id);
|
|
|
|
return retbuf;
|
|
}
|
|
else if (msgcmp (&request, "Frame:"))
|
|
{
|
|
ret = OK_TARGET_RESPONSE;
|
|
|
|
if (msgcmp (&request, "pc:"))
|
|
{
|
|
if (!hexToInt (&request, &pc))
|
|
return "E10"; /* badly formed packet */
|
|
n_frame = curframe.valid ? curframe.frame_id + 1 : 0;
|
|
gdb_note ("STUB: call fetch_trace_frame_pc (id %d, ", n_frame);
|
|
gdb_note ("pc 0x%X);\n", pc);
|
|
ret = fetch_trace_frame_with_pc (&n_frame,
|
|
(void *) pc,
|
|
&curframe.format,
|
|
&curframe.frame_data);
|
|
}
|
|
else if (msgcmp (&request, "tdp:"))
|
|
{
|
|
if (!hexToInt (&request, &tdp))
|
|
return "E10"; /* badly formed packet */
|
|
n_frame = curframe.valid ? curframe.frame_id + 1: 0;
|
|
gdb_note ("STUB: call fetch_trace_frame_tdp (id %d, ", n_frame);
|
|
gdb_note ("tdp 0x%X);\n", tdp);
|
|
ret = fetch_trace_frame_with_tdp (&n_frame,
|
|
tdp,
|
|
&curframe.format,
|
|
&curframe.frame_data);
|
|
}
|
|
else if (msgcmp (&request, "range:"))
|
|
{
|
|
if (!(hexToInt (&request, &start) &&
|
|
*request++ == ':'))
|
|
return "E11"; /* badly formed packet, field 1 */
|
|
else if (!hexToInt (&request, &stop))
|
|
return "E12"; /* badly formed packet, field 2 */
|
|
n_frame = curframe.valid ? curframe.frame_id + 1: 0;
|
|
gdb_note ("STUB: call fetch_trace_frame_range (id %d, ", n_frame);
|
|
gdb_note ("start 0x%X, ", start);
|
|
gdb_note ("stop 0x%X);\n", stop);
|
|
ret = fetch_trace_frame_with_pc_in_range (&n_frame,
|
|
(void *) start,
|
|
(void *) stop,
|
|
&curframe.format,
|
|
&curframe.frame_data);
|
|
}
|
|
else if (msgcmp (&request, "outside:"))
|
|
{
|
|
if (!(hexToInt (&request, &start) &&
|
|
*request++ == ':'))
|
|
return "E11"; /* badly formed packet, field 1 */
|
|
else if (!hexToInt (&request, &stop))
|
|
return "E12"; /* badly formed packet, field 2 */
|
|
n_frame = curframe.valid ? curframe.frame_id + 1: 0;
|
|
gdb_note ("STUB: call fetch_trace_frame_outside (id %d, ", n_frame);
|
|
gdb_note ("start 0x%X, ", start);
|
|
gdb_note ("stop 0x%X);\n", stop);
|
|
ret = fetch_trace_frame_with_pc_outside (&n_frame,
|
|
(void *) start,
|
|
(void *) stop,
|
|
&curframe.format,
|
|
&curframe.frame_data);
|
|
}
|
|
else /* simple TFind by frame number: */
|
|
{
|
|
if (!hexToInt (&request, &frameno))
|
|
return "E10"; /* badly formed packet */
|
|
if (frameno != (unsigned long) -1)
|
|
{
|
|
gdb_note ("STUB: call fetch_trace_frame (id %d);\n", frameno);
|
|
ret = fetch_trace_frame (n_frame = frameno,
|
|
&curframe.format,
|
|
&curframe.frame_data);
|
|
#if 0
|
|
printp("STUB: fetch_trace_frame: return %d\n", ret);
|
|
#endif
|
|
}
|
|
else /* discard any trace frame, debug "the real world" */
|
|
{
|
|
if (curframe.valid)
|
|
gdb_note ("STUB: discard current trace frame #%d.\n",
|
|
curframe.frame_id);
|
|
curframe.valid = 0;
|
|
return "OK";
|
|
}
|
|
}
|
|
if (ret == OK_TARGET_RESPONSE) /* fetch_trace_frame succeeded */
|
|
{ /* setup for debugging the trace frame */
|
|
curframe.valid = 1;
|
|
curframe.frame_id = n_frame;
|
|
curframe.tdp_id = curframe.frame_data->id;
|
|
|
|
memset ((char *) &curframe.traceregs, 0,
|
|
sizeof (curframe.traceregs));
|
|
curframe.traceregs[PC] = (unsigned long)
|
|
curframe.frame_data->program_counter;
|
|
|
|
if (curframe.format)
|
|
{
|
|
unsigned long regs_mask = curframe.format->regs_mask;
|
|
unsigned long *regs, *stack, *mem;
|
|
unsigned long regno, index = 0;
|
|
CFD *dummy;
|
|
|
|
if ((ret = get_addr_to_frame_regs_stack_mem
|
|
(curframe.frame_data, &dummy, ®s, &stack, &mem))
|
|
!= OK_TARGET_RESPONSE)
|
|
{
|
|
curframe.valid = 0;
|
|
sprintp (retbuf, "E2%x", ret);
|
|
return (char *)
|
|
dtc_error_ret ((int) &retbuf,
|
|
"get_addr_to_frame_regs_stack_mem",
|
|
ret);
|
|
}
|
|
|
|
if (remote_debug > 1)
|
|
{ /* echo what we've found to gdb console */
|
|
sprintp (spare_buffer,
|
|
"STUB: Found frame %d, TDP %d, format %d (%s):\n",
|
|
curframe.frame_id,
|
|
curframe.tdp_id & 0x7fffffff,
|
|
curframe.format->id,
|
|
curframe.tdp_id & 0x80000000 ?
|
|
"trap frame" : "stepping frame");
|
|
gdb_puts (spare_buffer);
|
|
}
|
|
/* copy trace frame regs into stub's data format */
|
|
for (regno = 0, index = 0;
|
|
regno < 16;
|
|
regno++, regs_mask >>= 1)
|
|
if (regs_mask & 1) /* got a collected register */
|
|
{
|
|
curframe.traceregs[regno] = regs[index++];
|
|
if (remote_debug > 1)
|
|
{
|
|
sprintp (spare_buffer,
|
|
" Collected 0x%08x for register %d.\n",
|
|
curframe.traceregs[regno], regno);
|
|
gdb_puts (spare_buffer);
|
|
}
|
|
}
|
|
if (remote_debug > 1)
|
|
{
|
|
long midx, ridx, len;
|
|
MEMRANGE_DEF *mrange;
|
|
unsigned char *data, *base;
|
|
|
|
if (curframe.format->stack_size > 0)
|
|
{
|
|
len = curframe.format->stack_size;
|
|
sprintp (spare_buffer,
|
|
" Collected %d bytes of stack at 0x%x:\n",
|
|
len, curframe.traceregs[A7]);
|
|
gdb_puts (spare_buffer);
|
|
|
|
/* print stack data, but stay under msg len */
|
|
if (len >= (NUMREGBYTES/2 - 2))
|
|
len = (NUMREGBYTES/2 - 3);
|
|
mem2hex ((unsigned char *) stack,
|
|
spare_buffer, len, 0);
|
|
spare_buffer [len * 2] = '\n';
|
|
spare_buffer [len * 2 + 1] = '\0'; /* EOS */
|
|
gdb_puts (spare_buffer);
|
|
}
|
|
else
|
|
gdb_puts ("Stack not collected\n");
|
|
|
|
for (midx = 0;
|
|
get_addr_to_a_mem_range (curframe.frame_data,
|
|
midx,
|
|
&mrange,
|
|
(void **) &data)
|
|
== OK_TARGET_RESPONSE;
|
|
midx++)
|
|
{
|
|
if ((mrange->typecode == 0) ||
|
|
(mrange->typecode == (unsigned long) -1))
|
|
{
|
|
sprintp (spare_buffer,
|
|
" Collected %d bytes at MEM: 0x%x:\n",
|
|
mrange->size, mrange->offset);
|
|
base = (unsigned char *) mrange->offset;
|
|
}
|
|
else
|
|
{
|
|
if ((ridx = elinum_to_index (mrange->typecode)) > 0)
|
|
base = (unsigned char *) curframe.traceregs[ridx]
|
|
+ (long) mrange->offset;
|
|
else
|
|
{
|
|
sprintp (spare_buffer,
|
|
"STUB: bad typecode in memrange #%d: (0x%x,0x%x,0x%x).\n",
|
|
midx,
|
|
mrange->typecode,
|
|
mrange->offset,
|
|
mrange->size);
|
|
gdb_puts (spare_buffer);
|
|
continue;
|
|
}
|
|
sprintp (spare_buffer,
|
|
" Collected %d bytes at 0x%x (REG %X + %d):\n",
|
|
mrange->size,
|
|
base,
|
|
mrange->typecode,
|
|
mrange->offset);
|
|
}
|
|
gdb_puts (spare_buffer);
|
|
len = mrange->size;
|
|
if (len >= (NUMREGBYTES/2 - 2))
|
|
len = (NUMREGBYTES/2 - 3);
|
|
mem2hex (data, spare_buffer, len, 0);
|
|
spare_buffer [len * 2] = '\n';
|
|
spare_buffer [len * 2 + 1] = '\0'; /* EOS */
|
|
gdb_puts (spare_buffer);
|
|
}
|
|
}
|
|
}
|
|
sprintp (retbuf, "F%xT%x", n_frame, curframe.tdp_id & 0x7fffffff);
|
|
return retbuf;
|
|
}
|
|
else if (ret == NOT_FOUND_TARGET_RESPONSE)
|
|
{
|
|
/* Here's a question: if the fetch_trace_frame call failed
|
|
(which probably means a bad "TFIND" command from GDB),
|
|
should we remain focused on the previous frame (if any),
|
|
or should we revert to "no current frame"?
|
|
*/
|
|
return "F-1";
|
|
}
|
|
else
|
|
{
|
|
sprintp (retbuf, "E2%x", ret);
|
|
return (char *) dtc_error_ret ((int) &retbuf,
|
|
"fetch_trace_frame[...]",
|
|
ret);
|
|
}
|
|
}
|
|
else /* unknown trace command */
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
|
|
/* Table used by the crc32 function to calcuate the checksum. */
|
|
static unsigned long crc32_table[256];
|
|
|
|
static int crc_mem_err;
|
|
|
|
static unsigned long
|
|
crc32 (buf, len, crc)
|
|
unsigned char *buf;
|
|
int len;
|
|
unsigned long crc;
|
|
{
|
|
crc_mem_err = FALSE;
|
|
|
|
if (! crc32_table[1])
|
|
{
|
|
/* Initialize the CRC table and the decoding table. */
|
|
int i, j;
|
|
unsigned int c;
|
|
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
for (c = i << 24, j = 8; j > 0; --j)
|
|
c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1);
|
|
crc32_table[i] = c;
|
|
}
|
|
}
|
|
|
|
while (len--)
|
|
{
|
|
if (read_access_violation (buf))
|
|
{
|
|
crc_mem_err = TRUE;
|
|
return -1;
|
|
}
|
|
crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf++) & 255];
|
|
}
|
|
return crc;
|
|
}
|
|
|
|
static char *
|
|
crc_query (cmd)
|
|
char *cmd;
|
|
{
|
|
unsigned long startmem, len, crc;
|
|
static char buf[32];
|
|
|
|
if (hexToInt (&cmd, &startmem) &&
|
|
*cmd++ == ',' &&
|
|
hexToInt (&cmd, &len))
|
|
{
|
|
crc = crc32 ((unsigned char *) startmem, len, 0xffffffff);
|
|
if (!crc_mem_err)
|
|
{
|
|
sprintp (buf, "C%08x", crc);
|
|
return buf;
|
|
}
|
|
/* else error, fall thru */
|
|
}
|
|
sprintp (buf, "E01");
|
|
return buf;
|
|
}
|
|
|
|
|
|
static char *
|
|
handle_test (request)
|
|
char *request;
|
|
{
|
|
ULONG args[7];
|
|
int i;
|
|
|
|
/* Parse the arguments, a comma-separated list of hex numbers, into
|
|
ARGS. Parse at most six arguments. */
|
|
i = 1;
|
|
if (*request != '\0')
|
|
while (i < 7)
|
|
{
|
|
if (! hexToInt (&request, &args[i++]))
|
|
return "E01";
|
|
if (*request == '\0')
|
|
break;
|
|
if (*request++ != ',')
|
|
return "E01";
|
|
}
|
|
|
|
/* Fill the rest of the args array with zeros. This is what the
|
|
INLINES command processor does with omitted arguments. */
|
|
for (; i < 7; i++)
|
|
args[i] = 0;
|
|
|
|
gdb_c_test (args);
|
|
|
|
return "OK";
|
|
}
|
|
|
|
|
|
/* GDB_TRAP_1_HANDLER
|
|
|
|
By the time this is called, the registers have been saved in "registers",
|
|
and the interrupt priority has been set to permit serial UART interrupts.
|
|
|
|
However, since no gdb request has yet been received, and there is no
|
|
equivalent of getpacket for us to wait on, we can't sit here waiting
|
|
for packets and processing them.
|
|
|
|
In fact, the ONLY thing for us to do here is sit and wait.
|
|
As gdb sends packet requests, they will handle themselves at the
|
|
interrupt level. When gdb decides we can continue, it will reset
|
|
the global variable "gdb_handling_trap1", and we will return
|
|
(whereupon registers will be restored etc.) */
|
|
|
|
void gdb_trap_1_handler( void )
|
|
{
|
|
gdb_handling_trap1 = TRUE;
|
|
sss_trace_flag = '\0'; /* shut off "trace bit" (indirectly) */
|
|
gdb_signo = 5;
|
|
putpacket( "S05" );
|
|
while ( gdb_handling_trap1 )
|
|
;
|
|
return;
|
|
}
|
|
|
|
void gdb_trace_handler( void )
|
|
{
|
|
sss_trace_flag = '\0'; /* shut off "trace bit" (indirectly) */
|
|
gdb_handling_trap1 = TRUE;
|
|
gdb_handling_sstrace = TRUE;
|
|
gdb_signo = 5;
|
|
putpacket( "S05" );
|
|
while ( gdb_handling_trap1 )
|
|
;
|
|
return;
|
|
}
|