gdb_cons.c revision 157059
1157059Ssam/*- 2157059Ssam * Copyright (c) 2006 Sam Leffler 3157059Ssam * All rights reserved. 4157059Ssam * 5157059Ssam * Redistribution and use in source and binary forms, with or without 6157059Ssam * modification, are permitted provided that the following conditions 7157059Ssam * are met: 8157059Ssam * 9157059Ssam * 1. Redistributions of source code must retain the above copyright 10157059Ssam * notice, this list of conditions and the following disclaimer. 11157059Ssam * 2. Redistributions in binary form must reproduce the above copyright 12157059Ssam * notice, this list of conditions and the following disclaimer in the 13157059Ssam * documentation and/or other materials provided with the distribution. 14157059Ssam * 15157059Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 16157059Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17157059Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18157059Ssam * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 19157059Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20157059Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21157059Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22157059Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23157059Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24157059Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25157059Ssam */ 26157059Ssam 27157059Ssam/* 28157059Ssam * Support for redirecting console msgs to gdb. We register 29157059Ssam * a pseudo console to hook cnputc and send stuff to the gdb 30157059Ssam * port. The only trickiness here is buffering output so this 31157059Ssam * isn't dog slow. 32157059Ssam */ 33157059Ssam 34157059Ssam#include <sys/cdefs.h> 35157059Ssam__FBSDID("$FreeBSD: head/sys/gdb/gdb_cons.c 157059 2006-03-23 23:06:14Z sam $"); 36157059Ssam 37157059Ssam#include <sys/param.h> 38157059Ssam#include <sys/systm.h> 39157059Ssam#include <sys/cons.h> 40157059Ssam#include <sys/kdb.h> 41157059Ssam#include <sys/kernel.h> 42157059Ssam#include <sys/malloc.h> 43157059Ssam#include <sys/reboot.h> 44157059Ssam#include <sys/sysctl.h> 45157059Ssam 46157059Ssam#include <machine/gdb_machdep.h> 47157059Ssam#include <machine/kdb.h> 48157059Ssam 49157059Ssam#include <gdb/gdb.h> 50157059Ssam#include <gdb/gdb_int.h> 51157059Ssam 52157059Ssamstruct gdbcons { 53157059Ssam int npending; 54157059Ssam /* /2 for hex conversion, -6 for protocol glue */ 55157059Ssam char buf[GDB_BUFSZ/2 - 6]; 56157059Ssam struct callout flush; 57157059Ssam}; 58157059Ssamstatic struct gdbcons state = { -1 }; 59157059Ssam 60157059Ssamstatic int gdbcons_enable = 0; 61157059SsamSYSCTL_INT(_debug, OID_AUTO, gdbcons, CTLFLAG_RW, &gdbcons_enable, 62157059Ssam 0, "copy console messages to gdb"); 63157059SsamTUNABLE_INT("debug.gdbcons", &gdbcons_enable); 64157059Ssam 65157059Ssamstatic void 66157059Ssamgdb_cnprobe(struct consdev *cp) 67157059Ssam{ 68157059Ssam sprintf(cp->cn_name, "gdb"); 69157059Ssam cp->cn_pri = CN_LOW; /* XXX no way to say "write only" */ 70157059Ssam} 71157059Ssam 72157059Ssamstatic void 73157059Ssamgdb_cninit(struct consdev *cp) 74157059Ssam{ 75157059Ssam struct gdbcons *c = &state; 76157059Ssam 77157059Ssam /* setup tx buffer and callout */ 78157059Ssam if (c->npending == -1) { 79157059Ssam c->npending = 0; 80157059Ssam callout_init(&c->flush, CALLOUT_MPSAFE); 81157059Ssam cp->cn_arg = c; 82157059Ssam } 83157059Ssam} 84157059Ssam 85157059Ssamstatic int 86157059Ssamgdb_nogetc(struct consdev *cp) 87157059Ssam{ 88157059Ssam return -1; 89157059Ssam} 90157059Ssam 91157059Ssamstatic void 92157059Ssamgdb_tx_puthex(int c) 93157059Ssam{ 94157059Ssam const char *hex = "0123456789abcdef"; 95157059Ssam 96157059Ssam gdb_tx_char(hex[(c>>4)&0xf]); 97157059Ssam gdb_tx_char(hex[(c>>0)&0xf]); 98157059Ssam} 99157059Ssam 100157059Ssamstatic void 101157059Ssamgdb_cnflush(void *arg) 102157059Ssam{ 103157059Ssam struct gdbcons *gc = arg; 104157059Ssam int i; 105157059Ssam 106157059Ssam gdb_tx_begin('O'); 107157059Ssam for (i = 0; i < gc->npending; i++) 108157059Ssam gdb_tx_puthex(gc->buf[i]); 109157059Ssam gdb_tx_end(); 110157059Ssam gc->npending = 0; 111157059Ssam} 112157059Ssam 113157059Ssam/* 114157059Ssam * This glop is to figure out when it's safe to use callouts 115157059Ssam * to defer buffer flushing. There's probably a better way 116157059Ssam * and/or an earlier point in the boot process when it's ok. 117157059Ssam */ 118157059Ssamstatic int calloutok = 0; 119157059Ssamstatic void 120157059Ssamoktousecallout(void *data __unused) 121157059Ssam{ 122157059Ssam calloutok = 1; 123157059Ssam} 124157059SsamSYSINIT(gdbhack, SI_SUB_RUN_SCHEDULER, SI_ORDER_ANY, oktousecallout, NULL) 125157059Ssam 126157059Ssamstatic void 127157059Ssamgdb_cnputc(struct consdev *cp, int c) 128157059Ssam{ 129157059Ssam struct gdbcons *gc; 130157059Ssam 131157059Ssam if (gdbcons_enable && gdb_cur != NULL && gdb_listening) { 132157059Ssam gc = cp->cn_arg; 133157059Ssam if (gc->npending != 0) { 134157059Ssam /* 135157059Ssam * Cancel any pending callout and flush the 136157059Ssam * buffer if there's no space for this byte. 137157059Ssam */ 138157059Ssam if (calloutok) 139157059Ssam callout_stop(&gc->flush); 140157059Ssam if (gc->npending == sizeof(gc->buf)) 141157059Ssam gdb_cnflush(gc); 142157059Ssam } 143157059Ssam gc->buf[gc->npending++] = c; 144157059Ssam /* 145157059Ssam * Flush on end of line; this is especially helpful 146157059Ssam * during boot when we don't have callouts to flush 147157059Ssam * the buffer. Otherwise we defer flushing; a 1/4 148157059Ssam * second is a guess. 149157059Ssam */ 150157059Ssam if (c == '\n') 151157059Ssam gdb_cnflush(gc); 152157059Ssam else if (calloutok) 153157059Ssam callout_reset(&gc->flush, hz/4, gdb_cnflush, gc); 154157059Ssam } 155157059Ssam} 156157059Ssam 157157059Ssam/* NB: no get interface, we supply nogetc for checkc too */ 158157059SsamCONS_DRIVER(gdb, gdb_cnprobe, gdb_cninit, NULL, gdb_nogetc, gdb_nogetc, 159157059Ssam gdb_cnputc, NULL); 160157059Ssam 161157059Ssam/* 162157059Ssam * Our console device only gets attached if the system is booted 163157059Ssam * with RB_MULTIPLE set so gdb_init also calls us to attach the 164157059Ssam * console so we're setup regardless. 165157059Ssam */ 166157059Ssamvoid 167157059Ssamgdb_consinit(void) 168157059Ssam{ 169157059Ssam gdb_cnprobe(&gdb_consdev); 170157059Ssam gdb_cninit(&gdb_consdev); 171157059Ssam cnadd(&gdb_consdev); 172157059Ssam} 173