17d0c6c9fSSam Leffler /*- 27d0c6c9fSSam Leffler * Copyright (c) 2006 Sam Leffler 37d0c6c9fSSam Leffler * All rights reserved. 47d0c6c9fSSam Leffler * 57d0c6c9fSSam Leffler * Redistribution and use in source and binary forms, with or without 67d0c6c9fSSam Leffler * modification, are permitted provided that the following conditions 77d0c6c9fSSam Leffler * are met: 87d0c6c9fSSam Leffler * 97d0c6c9fSSam Leffler * 1. Redistributions of source code must retain the above copyright 107d0c6c9fSSam Leffler * notice, this list of conditions and the following disclaimer. 117d0c6c9fSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 127d0c6c9fSSam Leffler * notice, this list of conditions and the following disclaimer in the 137d0c6c9fSSam Leffler * documentation and/or other materials provided with the distribution. 147d0c6c9fSSam Leffler * 157d0c6c9fSSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 167d0c6c9fSSam Leffler * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 177d0c6c9fSSam Leffler * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 187d0c6c9fSSam Leffler * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 197d0c6c9fSSam Leffler * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 207d0c6c9fSSam Leffler * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 217d0c6c9fSSam Leffler * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 227d0c6c9fSSam Leffler * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 237d0c6c9fSSam Leffler * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 247d0c6c9fSSam Leffler * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 257d0c6c9fSSam Leffler */ 267d0c6c9fSSam Leffler 277d0c6c9fSSam Leffler /* 287d0c6c9fSSam Leffler * Support for redirecting console msgs to gdb. We register 297d0c6c9fSSam Leffler * a pseudo console to hook cnputc and send stuff to the gdb 307d0c6c9fSSam Leffler * port. The only trickiness here is buffering output so this 317d0c6c9fSSam Leffler * isn't dog slow. 327d0c6c9fSSam Leffler */ 337d0c6c9fSSam Leffler 347d0c6c9fSSam Leffler #include <sys/cdefs.h> 357d0c6c9fSSam Leffler __FBSDID("$FreeBSD$"); 367d0c6c9fSSam Leffler 377d0c6c9fSSam Leffler #include <sys/param.h> 387d0c6c9fSSam Leffler #include <sys/systm.h> 397d0c6c9fSSam Leffler #include <sys/cons.h> 407d0c6c9fSSam Leffler #include <sys/kdb.h> 417d0c6c9fSSam Leffler #include <sys/kernel.h> 427d0c6c9fSSam Leffler #include <sys/malloc.h> 437d0c6c9fSSam Leffler #include <sys/reboot.h> 447d0c6c9fSSam Leffler #include <sys/sysctl.h> 457d0c6c9fSSam Leffler 467d0c6c9fSSam Leffler #include <machine/gdb_machdep.h> 477d0c6c9fSSam Leffler #include <machine/kdb.h> 487d0c6c9fSSam Leffler 497d0c6c9fSSam Leffler #include <gdb/gdb.h> 507d0c6c9fSSam Leffler #include <gdb/gdb_int.h> 517d0c6c9fSSam Leffler 527d0c6c9fSSam Leffler struct gdbcons { 537d0c6c9fSSam Leffler int npending; 547d0c6c9fSSam Leffler /* /2 for hex conversion, -6 for protocol glue */ 557d0c6c9fSSam Leffler char buf[GDB_BUFSZ/2 - 6]; 567d0c6c9fSSam Leffler struct callout flush; 577d0c6c9fSSam Leffler }; 587d0c6c9fSSam Leffler static struct gdbcons state = { -1 }; 597d0c6c9fSSam Leffler 607d0c6c9fSSam Leffler static int gdbcons_enable = 0; 617d0c6c9fSSam Leffler SYSCTL_INT(_debug, OID_AUTO, gdbcons, CTLFLAG_RW, &gdbcons_enable, 627d0c6c9fSSam Leffler 0, "copy console messages to gdb"); 637d0c6c9fSSam Leffler TUNABLE_INT("debug.gdbcons", &gdbcons_enable); 647d0c6c9fSSam Leffler 657d0c6c9fSSam Leffler static void 667d0c6c9fSSam Leffler gdb_cnprobe(struct consdev *cp) 677d0c6c9fSSam Leffler { 687d0c6c9fSSam Leffler sprintf(cp->cn_name, "gdb"); 697d0c6c9fSSam Leffler cp->cn_pri = CN_LOW; /* XXX no way to say "write only" */ 707d0c6c9fSSam Leffler } 717d0c6c9fSSam Leffler 727d0c6c9fSSam Leffler static void 737d0c6c9fSSam Leffler gdb_cninit(struct consdev *cp) 747d0c6c9fSSam Leffler { 757d0c6c9fSSam Leffler struct gdbcons *c = &state; 767d0c6c9fSSam Leffler 777d0c6c9fSSam Leffler /* setup tx buffer and callout */ 787d0c6c9fSSam Leffler if (c->npending == -1) { 797d0c6c9fSSam Leffler c->npending = 0; 807d0c6c9fSSam Leffler callout_init(&c->flush, CALLOUT_MPSAFE); 817d0c6c9fSSam Leffler cp->cn_arg = c; 827d0c6c9fSSam Leffler } 837d0c6c9fSSam Leffler } 847d0c6c9fSSam Leffler 857672c959SPoul-Henning Kamp static void 867672c959SPoul-Henning Kamp gdb_cnterm(struct consdev *cp) 877672c959SPoul-Henning Kamp { 887672c959SPoul-Henning Kamp } 897672c959SPoul-Henning Kamp 90*9976156fSAndriy Gapon static void 91*9976156fSAndriy Gapon gdb_cngrab(struct consdev *cp) 92*9976156fSAndriy Gapon { 93*9976156fSAndriy Gapon } 94*9976156fSAndriy Gapon 95*9976156fSAndriy Gapon static void 96*9976156fSAndriy Gapon gdb_cnungrab(struct consdev *cp) 97*9976156fSAndriy Gapon { 98*9976156fSAndriy Gapon } 99*9976156fSAndriy Gapon 1007d0c6c9fSSam Leffler static int 1017672c959SPoul-Henning Kamp gdb_cngetc(struct consdev *cp) 1027d0c6c9fSSam Leffler { 1037d0c6c9fSSam Leffler return -1; 1047d0c6c9fSSam Leffler } 1057d0c6c9fSSam Leffler 1067d0c6c9fSSam Leffler static void 1077d0c6c9fSSam Leffler gdb_tx_puthex(int c) 1087d0c6c9fSSam Leffler { 1097d0c6c9fSSam Leffler const char *hex = "0123456789abcdef"; 1107d0c6c9fSSam Leffler 1117d0c6c9fSSam Leffler gdb_tx_char(hex[(c>>4)&0xf]); 1127d0c6c9fSSam Leffler gdb_tx_char(hex[(c>>0)&0xf]); 1137d0c6c9fSSam Leffler } 1147d0c6c9fSSam Leffler 1157d0c6c9fSSam Leffler static void 1167d0c6c9fSSam Leffler gdb_cnflush(void *arg) 1177d0c6c9fSSam Leffler { 1187d0c6c9fSSam Leffler struct gdbcons *gc = arg; 1197d0c6c9fSSam Leffler int i; 1207d0c6c9fSSam Leffler 1217d0c6c9fSSam Leffler gdb_tx_begin('O'); 1227d0c6c9fSSam Leffler for (i = 0; i < gc->npending; i++) 1237d0c6c9fSSam Leffler gdb_tx_puthex(gc->buf[i]); 1247d0c6c9fSSam Leffler gdb_tx_end(); 1257d0c6c9fSSam Leffler gc->npending = 0; 1267d0c6c9fSSam Leffler } 1277d0c6c9fSSam Leffler 1287d0c6c9fSSam Leffler /* 1297d0c6c9fSSam Leffler * This glop is to figure out when it's safe to use callouts 1307d0c6c9fSSam Leffler * to defer buffer flushing. There's probably a better way 1317d0c6c9fSSam Leffler * and/or an earlier point in the boot process when it's ok. 1327d0c6c9fSSam Leffler */ 1337d0c6c9fSSam Leffler static int calloutok = 0; 1347d0c6c9fSSam Leffler static void 1357d0c6c9fSSam Leffler oktousecallout(void *data __unused) 1367d0c6c9fSSam Leffler { 1377d0c6c9fSSam Leffler calloutok = 1; 1387d0c6c9fSSam Leffler } 1397b9df13bSAndriy Gapon SYSINIT(gdbhack, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, oktousecallout, NULL); 1407d0c6c9fSSam Leffler 1417d0c6c9fSSam Leffler static void 1427d0c6c9fSSam Leffler gdb_cnputc(struct consdev *cp, int c) 1437d0c6c9fSSam Leffler { 1447d0c6c9fSSam Leffler struct gdbcons *gc; 1457d0c6c9fSSam Leffler 1467d0c6c9fSSam Leffler if (gdbcons_enable && gdb_cur != NULL && gdb_listening) { 1477d0c6c9fSSam Leffler gc = cp->cn_arg; 1487d0c6c9fSSam Leffler if (gc->npending != 0) { 1497d0c6c9fSSam Leffler /* 1507d0c6c9fSSam Leffler * Cancel any pending callout and flush the 1517d0c6c9fSSam Leffler * buffer if there's no space for this byte. 1527d0c6c9fSSam Leffler */ 1537d0c6c9fSSam Leffler if (calloutok) 1547d0c6c9fSSam Leffler callout_stop(&gc->flush); 1557d0c6c9fSSam Leffler if (gc->npending == sizeof(gc->buf)) 1567d0c6c9fSSam Leffler gdb_cnflush(gc); 1577d0c6c9fSSam Leffler } 1587d0c6c9fSSam Leffler gc->buf[gc->npending++] = c; 1597d0c6c9fSSam Leffler /* 1607d0c6c9fSSam Leffler * Flush on end of line; this is especially helpful 1617d0c6c9fSSam Leffler * during boot when we don't have callouts to flush 1627d0c6c9fSSam Leffler * the buffer. Otherwise we defer flushing; a 1/4 1637d0c6c9fSSam Leffler * second is a guess. 1647d0c6c9fSSam Leffler */ 1657d0c6c9fSSam Leffler if (c == '\n') 1667d0c6c9fSSam Leffler gdb_cnflush(gc); 1677d0c6c9fSSam Leffler else if (calloutok) 1687d0c6c9fSSam Leffler callout_reset(&gc->flush, hz/4, gdb_cnflush, gc); 1697d0c6c9fSSam Leffler } 1707d0c6c9fSSam Leffler } 1717d0c6c9fSSam Leffler 1727672c959SPoul-Henning Kamp CONSOLE_DRIVER(gdb); 1737d0c6c9fSSam Leffler 1747d0c6c9fSSam Leffler /* 1757d0c6c9fSSam Leffler * Our console device only gets attached if the system is booted 1767d0c6c9fSSam Leffler * with RB_MULTIPLE set so gdb_init also calls us to attach the 1777d0c6c9fSSam Leffler * console so we're setup regardless. 1787d0c6c9fSSam Leffler */ 1797d0c6c9fSSam Leffler void 1807d0c6c9fSSam Leffler gdb_consinit(void) 1817d0c6c9fSSam Leffler { 1827d0c6c9fSSam Leffler gdb_cnprobe(&gdb_consdev); 1837d0c6c9fSSam Leffler gdb_cninit(&gdb_consdev); 1847d0c6c9fSSam Leffler cnadd(&gdb_consdev); 1857d0c6c9fSSam Leffler } 186