- Add an option to change escape character.

- Use CTRL macro.
- Make target reset work on telnet port.
- Add a key bind to invoke kgdb on the terminal. (experimental)
This commit is contained in:
Hidetoshi Shimokawa 2007-06-15 12:09:16 +00:00
parent e19249f7a7
commit 8bd6994930
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=170775
2 changed files with 122 additions and 33 deletions

View File

@ -35,6 +35,7 @@
.Sh SYNOPSIS
.Nm
.Op Fl brvwRT1
.Op Fl e Ar escape-char
.Op Fl h Ar hz
.Op Fl C Ar console_port
.Op Fl G Ar gdb_port
@ -107,13 +108,15 @@ acts as a master device with
.Pp
Typed characters are normally transmitted directly to
.Xr dcons 4 .
A tilde
.Pq Ql ~
appearing as the first character of a line is an escape signal; the
A escape character (the default is
.Ql ~
) appearing as the first character of a line is an escape signal; the
following are recognized:
.Bl -tag -width ident
.It Ic ~.
Drop the connection and exit.
.It Ic ~^G
Invoke kgdb on the terminal on which dconschat is running.
.It Ic ~^R
Reset the target over FireWire if a reset address is registered in Configuration ROM.
.It Ic ~^Z
@ -156,6 +159,9 @@ Read available buffer, then exit.
This implies the
.Fl r
option.
.It Fl e Ar escape-char
Specify escape character.
The default is '~'.
.It Fl h Ar hz
Specify polling rate.
The default value is 100.

View File

@ -78,9 +78,10 @@
int verbose = 0;
int tc_set = 0;
int poll_hz = DCONS_POLL_HZ;
static u_char abreak[3] = {13 /* CR */, 126 /* ~ */, 2 /* ^B */};
#define IS_CONSOLE(p) ((p)->port == 0)
#define IS_GDB(p) ((p)->port == 1)
#define IS_CONSOLE(p) ((p)->port == DCONS_CON)
#define IS_GDB(p) ((p)->port == DCONS_GDB)
static struct dcons_state {
int fd;
@ -103,6 +104,7 @@ static struct dcons_state {
int escape_state;
struct dcons_port {
int port;
int sport;
struct dcons_ch o;
struct dcons_ch i;
u_int32_t optr;
@ -117,8 +119,11 @@ static struct dcons_state {
struct timespec zero;
struct termios tsave;
struct termios traw;
char escape;
} sc;
static int dconschat_write_dcons(struct dcons_state *, int, char *, int);
static int
dread(struct dcons_state *dc, void *buf, size_t n, off_t offset)
{
@ -147,21 +152,25 @@ dwrite(struct dcons_state *dc, void *buf, size_t n, off_t offset)
}
static void
dconschat_reset_target(struct dcons_state *dc)
dconschat_reset_target(struct dcons_state *dc, struct dcons_port *p)
{
char zeros[PAGE_SIZE];
char buf[PAGE_SIZE];
if (dc->reset == 0)
return;
bzero(&zeros[0], PAGE_SIZE);
printf("\r\n[dconschat reset target(addr=0x%zx)...]\r\n", dc->reset);
dwrite(dc, (void *)zeros, PAGE_SIZE, dc->reset);
snprintf(buf, PAGE_SIZE, "\r\n[dconschat reset target(addr=0x%zx)...]\r\n", dc->reset);
write(p->outfd, buf, strlen(buf));
bzero(&buf[0], PAGE_SIZE);
dwrite(dc, (void *)buf, PAGE_SIZE, dc->reset);
}
static void
dconschat_suspend(struct dcons_state *dc)
dconschat_suspend(struct dcons_state *dc, struct dcons_port *p)
{
if (p->sport != 0)
return;
if (tc_set)
tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->tsave);
@ -172,10 +181,71 @@ dconschat_suspend(struct dcons_state *dc)
tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->traw);
}
static void
dconschat_sigchld(int s)
{
struct kevent kev;
struct dcons_port *p;
char buf[256];
p = &sc.port[DCONS_CON];
snprintf(buf, 256, "\r\n[child exit]\r\n");
write(p->outfd, buf, strlen(buf));
if (tc_set)
tcsetattr(STDIN_FILENO, TCSADRAIN, &sc.traw);
EV_SET(&kev, p->infd, EVFILT_READ, EV_ADD, NOTE_LOWAT, 1, (void *)p);
kevent(sc.kq, &kev, 1, NULL, 0, &sc.zero);
}
static void
dconschat_fork_gdb(struct dcons_state *dc, struct dcons_port *p)
{
pid_t pid;
char buf[256], com[256];
struct kevent kev;
pid = fork();
if (pid < 0) {
snprintf(buf, 256, "\r\n[%s: fork failed]\r\n", __FUNCTION__);
write(p->outfd, buf, strlen(buf));
}
if (pid == 0) {
/* child */
if (tc_set)
tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->tsave);
snprintf(com, sizeof(buf), "kgdb -r :%d kernel",
dc->port[DCONS_GDB].sport);
snprintf(buf, 256, "\n[fork %s]\n", com);
write(p->outfd, buf, strlen(buf));
execl("/bin/sh", "/bin/sh", "-c", com, 0);
snprintf(buf, 256, "\n[fork failed]\n");
write(p->outfd, buf, strlen(buf));
if (tc_set)
tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->traw);
exit(0);
} else {
signal(SIGCHLD, dconschat_sigchld);
EV_SET(&kev, p->infd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
kevent(sc.kq, &kev, 1, NULL, 0, &sc.zero);
}
}
static void
dconschat_cleanup(int sig)
{
struct dcons_state *dc;
int status;
dc = &sc;
if (tc_set != 0)
@ -185,6 +255,7 @@ dconschat_cleanup(int sig)
printf("\n[dconschat exiting with signal %d ...]\n", sig);
else
printf("\n[dconschat exiting...]\n");
wait(&status);
exit(0);
}
@ -451,7 +522,7 @@ dconschat_read_dcons(struct dcons_state *dc, int port, char *buf, int len)
rlen = len;
#if 1
if (verbose)
if (verbose == 1)
printf("[%d]", rlen); fflush(stdout);
#endif
@ -532,13 +603,14 @@ dconschat_write_dcons(struct dcons_state *dc, int port, char *buf, int blen)
return(0);
}
static int
dconschat_write_socket(int fd, char *buf, int len)
{
write(fd, buf, len);
if (verbose > 1) {
buf[len] = 0;
printf("[%s]", buf);
printf("<- %s\n", buf);
}
return (0);
}
@ -554,6 +626,7 @@ dconschat_init_socket(struct dcons_state *dc, int port, char *host, int sport)
p = &dc->port[port];
p->port = port;
p->sport = sport;
p->infd = p->outfd = -1;
if (sport < 0)
@ -666,8 +739,8 @@ static int
dconschat_read_filter(struct dcons_state *dc, struct dcons_port *p,
u_char *sp, int slen, u_char *dp, int *dlen)
{
static u_char abreak[3] = {13 /* CR */, 126 /* ~ */, 2 /* ^B */};
int skip;
char *buf;
while (slen > 0) {
skip = 0;
@ -697,7 +770,7 @@ dconschat_read_filter(struct dcons_state *dc, struct dcons_port *p,
}
switch (dc->escape_state) {
case STATE1:
if (*sp == KEY_TILDE) {
if (*sp == dc->escape) {
skip = 1;
dc->escape_state = STATE2;
} else
@ -705,20 +778,26 @@ dconschat_read_filter(struct dcons_state *dc, struct dcons_port *p,
break;
case STATE2:
dc->escape_state = STATE0;
skip = 1;
if (*sp == '.')
dconschat_cleanup(0);
else if ((*sp == 0x12 /*'^R'*/)
else if (*sp == CTRL('B')) {
bcopy(abreak, dp, 3);
dp += 3;
*dlen += 3;
}
else if (*sp == CTRL('G'))
dconschat_fork_gdb(dc, p);
else if ((*sp == CTRL('R'))
&& (dc->reset != 0)) {
dc->escape_state = STATE3;
skip = 1;
printf("\r\n[Are you sure to "
"reset target? (y/N)]");
fflush(stdout);
} else if (*sp == 0x1a /*'^Z'*/) {
skip = 1;
dconschat_suspend(dc);
} else {
*dp++ = '~';
buf = "\r\n[Are you sure to reset target? (y/N)]";
write(p->outfd, buf, strlen(buf));
} else if (*sp == CTRL('Z'))
dconschat_suspend(dc, p);
else {
skip = 0;
*dp++ = dc->escape;
(*dlen) ++;
}
break;
@ -726,16 +805,18 @@ dconschat_read_filter(struct dcons_state *dc, struct dcons_port *p,
dc->escape_state = STATE0;
skip = 1;
if (*sp == 'y')
dconschat_reset_target(dc);
else
printf("\r\n");
dconschat_reset_target(dc, p);
else {
write(p->outfd, sp, 1);
write(p->outfd, "\r\n", 2);
}
break;
}
if (*sp == KEY_CR)
dc->escape_state = STATE1;
} else if (IS_GDB(p)) {
/* GDB: ^C -> CR+~+^B */
if (*sp == 0x3 && (dc->flags & F_ALT_BREAK) != 0) {
if (*sp == CTRL('C') && (dc->flags & F_ALT_BREAK) != 0) {
bcopy(abreak, dp, 3);
dp += 3;
sp ++;
@ -771,9 +852,8 @@ dconschat_read_socket(struct dcons_state *dc, struct dcons_port *p)
dconschat_write_dcons(dc, p->port, wbuf, wlen);
if (verbose > 1) {
wbuf[wlen] = 0;
printf("(%s)\n", wbuf);
}
if (verbose) {
printf("-> %s\n", wbuf);
} else if (verbose == 1) {
printf("(%d)", wlen);
fflush(stdout);
}
@ -926,7 +1006,7 @@ main(int argc, char **argv)
port[0] = 0; /* stdin/out for console */
port[1] = -1; /* disable gdb port */
while ((ch = getopt(argc, argv, "a:bh:rt:u:vwC:G:M:N:RT1")) != -1) {
while ((ch = getopt(argc, argv, "a:be:h:rt:u:vwC:G:M:N:RT1")) != -1) {
switch(ch) {
case 'a':
dc->paddr = strtoull(optarg, NULL, 0);
@ -935,6 +1015,9 @@ main(int argc, char **argv)
case 'b':
dc->flags |= F_ALT_BREAK;
break;
case 'e':
dc->escape |= optarg[0];
break;
case 'h':
poll_hz = strtoul(optarg, NULL, 0);
if (poll_hz == 0)