// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: remote.cc
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
// The above named program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
// ========== Copyright Header End ============================================
/////////////////////////////////////////////////////////////////////
// Copyright (C) 2005 Sun Microsystems, Inc.
// Frontend socket interface for the debugger
#include <string.h> /* for memset in FD_ZERO */
#include "cpu_interface.h"
// output debug log messages
#define DEBUG(s) if(g_debug_on){s}
#define SWAP_BIT_5_0(I) ((( (I) & 0x01e ) | ( ((I) & 0x020) >> 5 )) & 0x1f)
const char START_CHR
= '$';
const char END_CHR
= '#';
const int MAX_BUF_SIZE
= 8192;
// external routines called from this module
extern int cpu_set_breakpoint ( int cpu_id
, VCPU_BpType type
, uint64_t addr
);
extern int cpu_remove_breakpoint ( int cpu_id
, VCPU_BpType type
, uint64_t addr
);
extern void UI_exec_cmd ( char *cmd
);
// Convert number NIB to a hex digit.
static int tohex (int nib
)
// Convert hex digit A to a number.
static int fromhex (uint8_t a
)
if (a
>= '0' && a
<= '9')
else if (a
>= 'a' && a
<= 'f')
else if (a
>= 'A' && a
<= 'F')
printf ("Reply contains invalid hex digit %d", a
);
// read next parameter from the command string;
// set string pointer to the next param
static uint64_t read_next_param ( uint8_t **p
)
for (int i
=0; i
<100; i
++)
if (c
== '#' || c
== '\0')
else if (c
== ',' || c
== ':' || c
== ' ')
value
= (value
<<4) | fromhex(c
);
static uint64_t get_value
uint8_t **buf
, // buffer to get value from
int size
// size of the value
for (int offset
= size
* 8 - 4; offset
>=0; offset
-= 4)
value
= value
| fromhex ( (*buf
)[i
++] ) << offset
;
*buf
+= i
; // update buffer pointer
uint8_t **buf
, // buffer to put a hex string value
int size
// number of bytes ( should less or equal 8 )
for (int offset
= size
* 8 - 4; offset
>=0; offset
-= 4)
(*buf
)[i
++] = uint8_t( tohex (int(val
>> offset
)&0xf ));
*buf
+= i
; // update the buffer pointer
int cpu_id
; // current cpu id
uint8_t send_buffer
[MAX_BUF_SIZE
];
uint8_t recv_buffer
[MAX_BUF_SIZE
];
~SocketInterface () { close(socket
); }
// send an ack - command was recieved
uint8_t ack
[4] = {'+',0};
DEBUG( printf("send an ack : + ; "); );
uint8_t nack
[4] = {'-',0};
DEBUG( printf("send a nack : -\n"); );
void reply_not_implemented ()
// send error number in hex
void reply_error ( uint32_t error_number
)
send_buffer
[2] = tohex ((error_number
>> 4) & 0xf);
send_buffer
[3] = tohex (error_number
& 0xf);
// send target stop reason in hex
void reply_target_stopped (uint32_t reason
)
send_buffer
[2] = tohex ((reason
>> 4) & 0xf);
send_buffer
[3] = tohex (reason
& 0xf);
// send a data from the send_buffer;
// add first, last control symbols and a checksum
send_buffer
[n
++] = START_CHR
;
if ( n
> MAX_BUF_SIZE
-3 )
uint8_t c
= send_buffer
[n
];
// insert end control char
send_buffer
[n
++] = END_CHR
;
send_buffer
[n
++] = tohex ((check_sum
>> 4) & 0xf);
send_buffer
[n
++] = tohex (check_sum
& 0xf);
send_buffer
[n
] = 0; // null terminate
DEBUG( printf("\n intf %d send a reply :%s \n", id
, send_buffer
); );
uint64_t res
= write( socket
, send_buffer
, n
);
return (res
!= n
) ? -1 : 0;
// read a command into recieve buffer;
// overwrite a previous command if it was there;
// return the number of bytes read,-1 if error
while ( n
< MAX_BUF_SIZE
)
if ( read (socket
, &c
, 1) == 1 )
// one character recieved
// last character in the command
recv_buffer
[n
] = 0; // null terminated
// accumulate the characters
return (-1); // data is incomplete
// read one register value from the recieve buffer
uint8_t *args
= recv_buffer
+1;
int reg_idx
= (int)read_next_param ( &args
);
uint8_t *sbuf
= send_buffer
+1; // skip first control char
g_vcpu
[cpu_id
]->get_reg(VCPU_IRF_0
+ reg_idx
, &value
);
put_value( &sbuf
, value
, 8);
else if (reg_idx
< 64) // read 4 byte fpr value
g_vcpu
[cpu_id
]->get_reg(VCPU_FRF_0
+ reg_idx
- 32, &value
);
put_value( &sbuf
, value
, 4);
else if (reg_idx
< 80) // read 8 byte fpr value
g_vcpu
[cpu_id
]->get_reg(VCPU_DRF_0
+ reg_idx
- 64 + 16, &value
);
put_value( &sbuf
, value
, 8);
else if (reg_idx
< 90) // read control reg value
case 80: g_vcpu
[cpu_id
]->get_reg(VCPU_ASR_PC
, &value
); break;
case 81: g_vcpu
[cpu_id
]->get_reg(VCPU_ASR_NPC
, &value
); break;
case 82: g_vcpu
[cpu_id
]->get_reg(VCPU_PR_PSTATE
, &value
); break;
case 83: g_vcpu
[cpu_id
]->get_reg(VCPU_ASR_FSR
, &value
); break;
case 84: g_vcpu
[cpu_id
]->get_reg(VCPU_ASR_FPRS
, &value
); break;
case 85: g_vcpu
[cpu_id
]->get_reg(VCPU_ASR_Y
, &value
); break;
case 86: g_vcpu
[cpu_id
]->get_reg(VCPU_PR_CWP
, &value
); break;
case 87: g_vcpu
[cpu_id
]->get_reg(VCPU_PR_PSTATE
, &value
); break;
case 88: g_vcpu
[cpu_id
]->get_reg(VCPU_ASR_ASI
, &value
); break;
case 89: g_vcpu
[cpu_id
]->get_reg(VCPU_ASR_CCR
, &value
); break;
put_value( &sbuf
, value
, 8);
else if (reg_idx
< 122) // read 8 byte fpr value
g_vcpu
[cpu_id
]->get_reg(VCPU_DRF_0
+ reg_idx
- 90, &value
);
put_value( &sbuf
, value
, 8);
else if (reg_idx
< 138) // read 16 byte fpr value
int regnum
= (reg_idx
- 122) * 2;
g_vcpu
[cpu_id
]->get_reg(VCPU_DRF_0
+ regnum
, &value
);
put_value( &sbuf
, value
, 8);
g_vcpu
[cpu_id
]->get_reg(VCPU_DRF_0
+ regnum
+ 1, &value
);
put_value( &sbuf
, value
, 8);
int msg_size
= int(sbuf
- send_buffer
);
uint8_t *sbuf
= send_buffer
+1; // skip first control char
g_vcpu
[cpu_id
]->get_reg(VCPU_IRF_0
+ i
, &gpr
);
put_value( &sbuf
, gpr
, 8);
// read all 32 bit fp regs
g_vcpu
[cpu_id
]->get_reg(VCPU_FRF_0
+ i
, &fpr
);
put_value( &sbuf
, fpr
, 4);
// read all 64 bit fp regs
for (int i
=32; i
<64; i
+=2)
g_vcpu
[cpu_id
]->get_reg(VCPU_DRF_0
+ (i
/ 2), &dfpr
);
put_value( &sbuf
, dfpr
, 8);
// read control registers
g_vcpu
[cpu_id
]->get_reg(VCPU_ASR_PC
, ®
);
put_value( &sbuf
, reg
, 8);
g_vcpu
[cpu_id
]->get_reg(VCPU_ASR_NPC
, ®
);
put_value( &sbuf
, reg
, 8);
g_vcpu
[cpu_id
]->get_reg(VCPU_PR_PSTATE
, ®
);
put_value( &sbuf
, reg
, 8);
g_vcpu
[cpu_id
]->get_reg(VCPU_ASR_FSR
, ®
);
put_value( &sbuf
, reg
, 8);
g_vcpu
[cpu_id
]->get_reg(VCPU_ASR_FPRS
, ®
);
put_value( &sbuf
, reg
, 8);
g_vcpu
[cpu_id
]->get_reg(VCPU_ASR_Y
, ®
);
put_value( &sbuf
, reg
, 8);
int msg_size
= int(sbuf
- send_buffer
);
uint8_t *buf
= recv_buffer
;
reg
= get_value( &buf
, 8);
g_vcpu
[cpu_id
]->set_reg(VCPU_IRF_0
+ i
, reg
);
// write all 32 bit fp regs
reg
= get_value( &buf
, 4);
g_vcpu
[cpu_id
]->set_reg(VCPU_FRF_0
+ i
, reg
);
// write all 64 bit fp regs
for (int i
=32; i
<64; i
+=2)
reg
= get_value( &buf
, 8);
g_vcpu
[cpu_id
]->set_reg(VCPU_DRF_0
+ (i
/ 2), reg
);
// write control registers
reg
= get_value( &buf
, 8);
g_vcpu
[cpu_id
]->set_reg(VCPU_ASR_PC
, reg
);
reg
= get_value( &buf
, 8);
g_vcpu
[cpu_id
]->set_reg(VCPU_ASR_NPC
, reg
);
reg
= get_value( &buf
, 8);
g_vcpu
[cpu_id
]->set_reg(VCPU_PR_PSTATE
, reg
);
reg
= get_value( &buf
, 8);
g_vcpu
[cpu_id
]->set_reg(VCPU_ASR_FSR
, reg
);
reg
= get_value( &buf
, 8);
g_vcpu
[cpu_id
]->set_reg(VCPU_ASR_FPRS
, reg
);
reg
= get_value( &buf
, 8);
g_vcpu
[cpu_id
]->set_reg(VCPU_ASR_Y
, reg
);
uint8_t *args
= recv_buffer
+1;
uint64_t addr
= read_next_param ( &args
);
int size
= (int)read_next_param ( &args
);
if (size
> MAX_BUF_SIZE
-3)
uint8_t *sbuf
= send_buffer
+1;
// read from the double word aligned address
uint64_t addr8
= addr
& ~uint64_t(7);
if ( g_vcpu
[cpu_id
]->read_mem(addr8
, &value
, 8) != 0 )
DEBUG( printf(" read dword %llx from address %llx \n", value
, addr8
); );
// alignement for the very first byte
int start_byte_idx
= int(addr
& 0x7);
int end_byte_idx
= start_byte_idx
+ size
-1;
int chunck_size
= end_byte_idx
- start_byte_idx
+ 1;
value
>>= ((7-end_byte_idx
)*8);
value
&= ((uint64_t(1)<<(chunck_size
*8))-1);
put_value( &sbuf
, value
, chunck_size
);
int msg_size
= int(sbuf
- send_buffer
);
uint8_t *args
= recv_buffer
+1;
uint64_t addr
= read_next_param ( &args
);
int size
= (int)read_next_param ( &args
);
// allow only double word aligned addresses
if ((size
<= 0) || ( addr
& 0x7 ) )
for (int i
=0; i
<size
/8; i
++)
// double word aligned address
addr
= ( addr
+ i
*8 ) & ~uint64_t(7);
uint64_t value
= get_value ( &args
,size
);
if (g_vcpu
[cpu_id
]->write_mem(addr
, value
, 8) != 0)
uint8_t *args
= recv_buffer
+1;
int type
= (int)read_next_param ( &args
);
uint64_t addr
= read_next_param ( &args
);
int size
= (int)read_next_param ( &args
);
if (cpu_set_breakpoint(cpu_id
, VCPU_BP_INSTR_ADDR
, addr
) != 0)
case 2: // write watchpoint
if (cpu_set_breakpoint(cpu_id
, VCPU_BP_DATA_WRITE_ADDR
, addr
) != 0)
case 3: // read watchpoint
if (cpu_set_breakpoint(cpu_id
, VCPU_BP_DATA_READ_ADDR
, addr
) != 0)
uint8_t *args
= recv_buffer
+1;
int type
= (int)read_next_param ( &args
);
uint64_t addr
= read_next_param ( &args
);
int size
= (int)read_next_param ( &args
);
if (cpu_remove_breakpoint(cpu_id
, VCPU_BP_INSTR_ADDR
, addr
) != 0)
case 2: // write watchpoint
if (cpu_remove_breakpoint(cpu_id
, VCPU_BP_DATA_WRITE_ADDR
, addr
) != 0)
case 3: // read watchpoint
if (cpu_remove_breakpoint(cpu_id
, VCPU_BP_DATA_READ_ADDR
, addr
) != 0)
// head of linked list of interface objects
SocketInterface
* gpIntf
;
// This routine is called when target is stoped.
// Inform the debugger about the reason of stopping.
int target_stopped ( int reason
)
SocketInterface
*in
= gpIntf
;
// for all attached remote interfaces
in
->reply_target_stopped (reason
);
// This new thread is invoked once contact with a debugger is
// been established. This thread exits once that debugger
// Any one debugger can stop the simulation, all are required
// to be active to continue simulation.
void * in_worker_thread (void * argp
)
SocketInterface
*in
= (SocketInterface
*)argp
;
// run the command interface until we get the
// command to termnate this session
// get the command packet
printf ("failed in communication");
in
->reply_nack(); // send a nack
DEBUG( printf(" remote interface %d got a command %s: ", in
->id
, in
->recv_buffer
); );
char command
= in
->recv_buffer
[0];
DEBUG( printf("get the the reason why stoped \n"); );
in
->reply_target_stopped (0);
case 'p': // read register
DEBUG( printf("read register :%s \n", in
->recv_buffer
+1); );
//in->reply_not_implemented(); // not implemented
case 'g': // read all registers
DEBUG( printf("read all register \n" ); );
case 'G': // write registers
DEBUG( printf("write registers: %s\n", in
->recv_buffer
+1); );
DEBUG( printf("read memory : %s \n", in
->recv_buffer
+1); );
case 'M': // write memory
DEBUG( printf("write memory :%s \n", in
->recv_buffer
+1); );
case 'c': // continue from address
DEBUG( printf("continue %s \n", in
->recv_buffer
+1); );
case 's': // step from address
DEBUG( printf("step :%s \n", in
->recv_buffer
+1); );
UI_exec_cmd("stepi 1\n");
case 'z': // remove a breakpoint
DEBUG( printf("remove a breakpoint :%s \n", in
->recv_buffer
+1); );
case 'Z': // set a breakpoint
DEBUG( printf("set a breakpoint :%s \n", in
->recv_buffer
+1); );
case 'D': // detach the session
DEBUG( printf("\n unimplemented command %s \n", in
->recv_buffer
); );
in
->reply_not_implemented(); // not implemented
// remove interface structure from the list
SocketInterface
*prev
=NULL
;
for ( SocketInterface
*p
= gpIntf
;
// to wait for user interface connections.
void *wait_connection (void *param
)
static fd_set comm_channels
;
int tcp_attach_socket
, res
;
struct sockaddr_in tcp_server
;
thr_sigsetmask(SIG_BLOCK
, &sigs
, NULL
);
skt
= socket(AF_INET
, SOCK_STREAM
, 0);
printf ("ERROR: cannot opening stream socket\n");
// enable the reuse of this socket if this process dies
if (setsockopt(skt
,SOL_SOCKET
,SO_REUSEADDR
,(char*)&on
,int(sizeof(on
)))<0)
printf ("ERROR: turning on REUSEADDR \n");
RemoteConfig
*config
= (RemoteConfig
*)param
;
g_debug_on
= config
->debug_on
;
retry
: // bind the connection
tcp_server
.sin_family
= AF_INET
;
tcp_server
.sin_addr
.s_addr
= INADDR_ANY
;
tcp_server
.sin_port
= config
->port
;
printf("- trying port:%d", config
->port
);
if (bind(skt
, (struct sockaddr
*)&tcp_server
, int(sizeof(tcp_server
))) < 0)
printf("\nPort %d already in use ", config
->port
);
printf("ERROR: binding tcp stream socket");
length
= int(sizeof(tcp_server
));
if (getsockname(skt
, (struct sockaddr
*) &tcp_server
, &length
)==-1)
printf("ERROR:getting socket name");
// start waiting for the connection
printf("\nWaiting for connection on port # %d\n",ntohs(tcp_server
.sin_port
));
listen(skt
, config
->max_connections
);
max_channel
= tcp_attach_socket
;
FD_SET(tcp_attach_socket
, &comm_channels
);
// Wait for a control connection
if (next_connection
> config
->max_connections
- 1)
res
= select(max_channel
+1, &comm_channels
, (fd_set
*)0, (fd_set
*)0, (struct timeval
*)0 /* stall */);
fromlen
= int(sizeof(from
));
fh
= accept(tcp_attach_socket
,(struct sockaddr
*)&from
, (int*)&fromlen
);
hp
= gethostbyaddr((char *)&from
.sin_addr
, 4, AF_INET
);
if (hp
== (struct hostent
*)0)
froms
= inet_ntoa(from
.sin_addr
);
fprintf(stderr
,"cant resolve hostname for %s\n", froms
);;
printf("got remote connection from %s : port %d\n", froms
, from
.sin_port
);
// Create the thread to handle this debugger
// connection. It cleans up after itself
// if anything goes wrong
SocketInterface
*in
= new SocketInterface ();
in
->id
= next_connection
;
DEBUG( printf("connection %d on socket_id=%d\n", in
->id
, in
->socket
); );
thr_create(NULL
, NULL
, in_worker_thread
, (void*)in
, THR_BOUND
, &in
->thread_id
);
int start_connection ( RemoteConfig
*config
)
// start thread waiting for a remote connection
thr_create(NULL
, NULL
, wait_connection
, (void *)config
, THR_BOUND
, &thread_id
);
printf ( "remote debug server started...\n");
int destroy_connection ()
SocketInterface
*in
= gpIntf
;
// for all attached remote interfaces
in
->reply_target_stopped (SIGNAL_HUP
);
////////////////////////////////////////////////////////
// Get exported interface from the Remote shared library.
// Assign function pointers in the interface structure.
// return: 0 - success; 1 - fail;
int get_ex_remote_interface
RemoteExInterface
*intf
// pointer to the interface structure
intf
->create
= start_connection
;
intf
->destroy
= destroy_connection
;
intf
->update_status
= target_stopped
;