#ifndef __GDB_KDP_PROTOCOL_H__
#define __GDB_KDP_PROTOCOL_H__

#define KDP_MAX_PACKET_SIZE 1200        /* max packet size */
#define KDP_MAX_DATA_SIZE 1024  /* max r/w data per packet */

/* Requests */

typedef enum kdp_req_t
{

  /* connection oriented requests */
  KDP_CONNECT, KDP_DISCONNECT,

  /* obtaining client info */
  KDP_HOSTINFO, KDP_VERSION, KDP_MAXBYTES,

  /* memory access */
  KDP_READMEM, KDP_WRITEMEM,

  /* register access */
  KDP_READREGS, KDP_WRITEREGS,

  /* executable image info */
  KDP_LOAD, KDP_IMAGEPATH,

  /* execution control */
  KDP_SUSPEND, KDP_RESUMECPUS,

  /* exception and termination notification, NOT true requests */
  KDP_EXCEPTION, KDP_TERMINATION,

  /* breakpoint control */
  KDP_BREAKPOINT_SET, KDP_BREAKPOINT_REMOVE,

  /* vm regions */
  KDP_REGIONS,

  /* reattach to a connected host */
  KDP_REATTACH,

  /* remote reboot request */
  KDP_HOSTREBOOT
} kdp_req_t;

/* Common KDP packet header */

typedef struct
{
  kdp_req_t request;            /* request type */
  unsigned char is_reply;       /* 0 => request, 1 => reply */
  unsigned char seq;            /* sequence number within session */
  unsigned int key;             /* session key */
} kdp_hdr_t;

/* KDP errors */

typedef enum
{
  KDP_PROTERR_SUCCESS = 0,
  KDP_PROTERR_ALREADY_CONNECTED,
  KDP_PROTERR_BAD_NBYTES,
  KDP_PROTERR_BADFLAVOR,        /* bad flavor in w/r regs */
} kdp_error_t;

/* KDP requests and reply packet formats */

/* KDP_CONNECT */

typedef struct
{
  kdp_hdr_t hdr;
  unsigned short req_reply_port;        /* udp port which to send replies */
  unsigned short exc_note_port; /* udp port which to send exc notes */
  char greeting[0];             /* "greetings", null-terminated */
} kdp_connect_req_t;

typedef struct
{
  kdp_hdr_t hdr;
  kdp_error_t error;
} kdp_connect_reply_t;

/* KDP_DISCONNECT */

typedef struct
{
  kdp_hdr_t hdr;
} kdp_disconnect_req_t;

typedef struct
{
  kdp_hdr_t hdr;
} kdp_disconnect_reply_t;

/* KDP_REATTACH */

typedef struct
{
  kdp_hdr_t hdr;
  unsigned short req_reply_port;        /* udp port which to send replies */
} kdp_reattach_req_t;

/* KDP_HOSTREBOOT */

typedef struct
{
  kdp_hdr_t hdr;
} kdp_hostreboot_req_t;

/* KDP_HOSTINFO */

typedef struct
{
  kdp_hdr_t hdr;
} kdp_hostinfo_req_t;

typedef struct
{
  kdp_hdr_t hdr;
  unsigned int cpu_mask;
  unsigned int cpu_type;
  unsigned int cpu_subtype;
} kdp_hostinfo_reply_t;

/*
 * KDP_VERSION
 */
typedef struct
{
  kdp_hdr_t hdr;
} kdp_version_req_t;

#define KDP_FEATURE_BP  0x1     /* local breakpoint support */

typedef struct
{
  kdp_hdr_t hdr;
  unsigned version;
  unsigned feature;
  unsigned pad0;
  unsigned pad1;
} kdp_version_reply_t;

/* KDP_REGIONS */

typedef struct
{
  kdp_hdr_t hdr;
} kdp_regions_req_t;

typedef struct
{
  kdp_hdr_t hdr;
  unsigned nregions;
  struct
  {
    unsigned long address;
    size_t nbytes;
    unsigned int protection;
  } regions[0];
} kdp_regions_reply_t;

/* KDP_MAXBYTES */

typedef struct
{
  kdp_hdr_t hdr;
} kdp_maxbytes_req_t;

typedef struct
{
  kdp_hdr_t hdr;
  size_t max_bytes;
} kdp_maxbytes_reply_t;

/* KDP_READMEM */

typedef struct
{
  kdp_hdr_t hdr;
  unsigned long address;
  size_t nbytes;
} kdp_readmem_req_t;

typedef struct
{
  kdp_hdr_t hdr;
  kdp_error_t error;
  size_t nbytes;
  unsigned char data[0];
} kdp_readmem_reply_t;

/* KDP_WRITEMEM */

typedef struct
{
  kdp_hdr_t hdr;
  unsigned long address;
  size_t nbytes;
  unsigned char data[0];
} kdp_writemem_req_t;

typedef struct
{
  kdp_hdr_t hdr;
  kdp_error_t error;
} kdp_writemem_reply_t;

/* KDP_READREGS */

typedef struct
{
  kdp_hdr_t hdr;
  unsigned int cpu;
  unsigned int flavor;
} kdp_readregs_req_t;

typedef struct
{
  kdp_hdr_t hdr;
  kdp_error_t error;
  size_t nbytes;
  unsigned char data[0];
} kdp_readregs_reply_t;

/* KDP_WRITEREGS */

typedef struct
{
  kdp_hdr_t hdr;
  unsigned int cpu;
  unsigned int flavor;
  size_t nbytes;
  unsigned char data[0];
} kdp_writeregs_req_t;

typedef struct
{
  kdp_hdr_t hdr;
  kdp_error_t error;
} kdp_writeregs_reply_t;

/* KDP_LOAD */

typedef struct
{
  kdp_hdr_t hdr;
  char file_args[0];
} kdp_load_req_t;

typedef struct
{
  kdp_hdr_t hdr;
  kdp_error_t error;
} kdp_load_reply_t;

/* KDP_IMAGEPATH */

typedef struct
{
  kdp_hdr_t hdr;
} kdp_imagepath_req_t;

typedef struct
{
  kdp_hdr_t hdr;
  char path[0];
} kdp_imagepath_reply_t;

/* KDP_SUSPEND */

typedef struct
{
  kdp_hdr_t hdr;
} kdp_suspend_req_t;

typedef struct
{
  kdp_hdr_t hdr;
} kdp_suspend_reply_t;

/* KDP_RESUMECPUS */

typedef struct
{
  kdp_hdr_t hdr;
  unsigned int cpu_mask;
} kdp_resumecpus_req_t;

typedef struct
{
  kdp_hdr_t hdr;
} kdp_resumecpus_reply_t;

/* KDP_BREAKPOINT_SET, KDP_BREAKPOINT_REMOVE */
typedef struct
{
  kdp_hdr_t hdr;
  unsigned long address;
#if 0
  unsigned long ccache;
#endif
} kdp_breakpoint_req_t;

typedef struct
{
  kdp_hdr_t hdr;
  kdp_error_t error;
} kdp_breakpoint_reply_t;

/* Exception notifications */

/* (Exception notifications are not requests, and in fact travel from
   the remote debugger to the gdb agent KDB.) */

/* exc. info for one cpu */

typedef struct kdp_exc_info_t
{
  unsigned int cpu;
  unsigned int exception;
  unsigned int code;
  unsigned int subcode;
} kdp_exc_info_t;

typedef struct kdp_exception_t
{
  kdp_hdr_t hdr;
  size_t n_exc_info;
  kdp_exc_info_t exc_info[0];
} kdp_exception_t;

typedef struct kdp_exception_ack_t
{
  kdp_hdr_t hdr;
} kdp_exception_ack_t;

/* Child termination messages */

typedef enum kdp_termination_code_t
{
  KDP_FAULT = 0,                /* child took fault (internal use) */
  KDP_EXIT,                     /* child exited */
  KDP_POWEROFF,                 /* child power-off */
  KDP_REBOOT,                   /* child reboot */
  KDP_COMMAND_MODE,             /* child exit to mon command_mode */
} kdp_termination_code_t;

typedef struct kdp_termination_t
{
  kdp_hdr_t hdr;
  kdp_termination_code_t term_code;
  unsigned int exit_code;
} kdp_termination_t;

typedef struct kdp_termination_ack_t
{
  kdp_hdr_t hdr;
} kdp_termination_ack_t;

typedef union kdp_pkt_t
{
  kdp_hdr_t hdr;
  kdp_connect_req_t connect_req;
  kdp_connect_reply_t connect_reply;
  kdp_disconnect_req_t disconnect_req;
  kdp_disconnect_reply_t disconnect_reply;
  kdp_hostinfo_req_t hostinfo_req;
  kdp_hostinfo_reply_t hostinfo_reply;
  kdp_version_req_t version_req;
  kdp_version_reply_t version_reply;
  kdp_maxbytes_req_t maxbytes_req;
  kdp_maxbytes_reply_t maxbytes_reply;
  kdp_readmem_req_t readmem_req;
  kdp_readmem_reply_t readmem_reply;
  kdp_writemem_req_t writemem_req;
  kdp_writemem_reply_t writemem_reply;
  kdp_readregs_req_t readregs_req;
  kdp_readregs_reply_t readregs_reply;
  kdp_writeregs_req_t writeregs_req;
  kdp_writeregs_reply_t writeregs_reply;
  kdp_load_req_t load_req;
  kdp_load_reply_t load_reply;
  kdp_imagepath_req_t imagepath_req;
  kdp_imagepath_reply_t imagepath_reply;
  kdp_suspend_req_t suspend_req;
  kdp_suspend_reply_t suspend_reply;
  kdp_resumecpus_req_t resumecpus_req;
  kdp_resumecpus_reply_t resumecpus_reply;
  kdp_exception_t exception;
  kdp_exception_ack_t exception_ack;
  kdp_termination_t termination;
  kdp_termination_ack_t termination_ack;
  kdp_breakpoint_req_t breakpoint_req;
  kdp_breakpoint_reply_t breakpoint_reply;
  kdp_regions_req_t regions_req;
  kdp_regions_reply_t regions_reply;
  kdp_reattach_req_t reattach_req;
  kdp_hostreboot_req_t hostreboot_req;
} kdp_pkt_t;

typedef enum
{
  KDP_LOG_ERROR = 1,
  KDP_LOG_WARNING = 2,
  KDP_LOG_INFO = 3,
  KDP_LOG_DEBUG = 4,
  KDP_LOG_PACKET = 5
} kdp_log_level;

typedef enum
{
  RR_SUCCESS = 0,
  RR_ALREADY_CONNECTED = KDP_PROTERR_ALREADY_CONNECTED,
  RR_BAD_NBYTES = KDP_PROTERR_BAD_NBYTES,
  RR_BADFLAVOR = KDP_PROTERR_BADFLAVOR,
  RR_SEND_TIMEOUT,
  RR_RECV_TIMEOUT,
  RR_IP_ERROR,                  /* misc. network error */
  RR_BAD_ACK,                   /* bad packet_type on ack */
  RR_BYTE_COUNT,                /* unexpected byte count */
  RR_BAD_SEQ,                   /* unexpected sequence number */
  RR_RESOURCE,                  /* resource shortage */
  RR_LOOKUP,                    /* can't find target */
  RR_INTERNAL,                  /* internal error */
  RR_CONNECT,                   /* connection failure */
  RR_INVALID_ADDRESS,           /* bad memory address */
  RR_EXCEPTION,                 /* exception is new */
  RR_RECV_INTR,
} kdp_return_t;

typedef void (kdp_log_function) (kdp_log_level l, const char *s, ...);

const char *kdp_req_string (kdp_req_t req);
const char *kdp_error_string (kdp_error_t error);
const char *kdp_return_string (kdp_return_t error);

struct kdp_connection;

void kdp_log_data
  (kdp_log_function * f, kdp_log_level l, const unsigned char *data,
   unsigned int nbytes);

void kdp_log_packet
  (kdp_log_function * f, kdp_log_level l, const kdp_pkt_t * p);

kdp_return_t kdp_marshal
  (struct kdp_connection *c, kdp_pkt_t * p, unsigned char *s, size_t maxlen,
   size_t * plen);

kdp_return_t kdp_unmarshal
  (struct kdp_connection *c, kdp_pkt_t * p, const unsigned char *s,
   size_t rlen);

#endif /* __GDB_KDP_PROTOCOL_H__ */
