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$"); 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; 61267992ShselaskySYSCTL_INT(_debug, OID_AUTO, gdbcons, CTLFLAG_RWTUN, &gdbcons_enable, 62267992Shselasky 0, "copy console messages to GDB"); 63157059Ssam 64157059Ssamstatic void 65157059Ssamgdb_cnprobe(struct consdev *cp) 66157059Ssam{ 67157059Ssam sprintf(cp->cn_name, "gdb"); 68157059Ssam cp->cn_pri = CN_LOW; /* XXX no way to say "write only" */ 69157059Ssam} 70157059Ssam 71157059Ssamstatic void 72157059Ssamgdb_cninit(struct consdev *cp) 73157059Ssam{ 74157059Ssam struct gdbcons *c = &state; 75157059Ssam 76157059Ssam /* setup tx buffer and callout */ 77157059Ssam if (c->npending == -1) { 78157059Ssam c->npending = 0; 79283291Sjkim callout_init(&c->flush, 1); 80157059Ssam cp->cn_arg = c; 81157059Ssam } 82157059Ssam} 83157059Ssam 84158960Sphkstatic void 85158960Sphkgdb_cnterm(struct consdev *cp) 86158960Sphk{ 87158960Sphk} 88158960Sphk 89228631Savgstatic void 90228631Savggdb_cngrab(struct consdev *cp) 91228631Savg{ 92228631Savg} 93228631Savg 94228631Savgstatic void 95228631Savggdb_cnungrab(struct consdev *cp) 96228631Savg{ 97228631Savg} 98228631Savg 99157059Ssamstatic int 100158960Sphkgdb_cngetc(struct consdev *cp) 101157059Ssam{ 102157059Ssam return -1; 103157059Ssam} 104157059Ssam 105157059Ssamstatic void 106157059Ssamgdb_tx_puthex(int c) 107157059Ssam{ 108157059Ssam const char *hex = "0123456789abcdef"; 109157059Ssam 110157059Ssam gdb_tx_char(hex[(c>>4)&0xf]); 111157059Ssam gdb_tx_char(hex[(c>>0)&0xf]); 112157059Ssam} 113157059Ssam 114157059Ssamstatic void 115157059Ssamgdb_cnflush(void *arg) 116157059Ssam{ 117157059Ssam struct gdbcons *gc = arg; 118157059Ssam int i; 119157059Ssam 120157059Ssam gdb_tx_begin('O'); 121157059Ssam for (i = 0; i < gc->npending; i++) 122157059Ssam gdb_tx_puthex(gc->buf[i]); 123157059Ssam gdb_tx_end(); 124157059Ssam gc->npending = 0; 125157059Ssam} 126157059Ssam 127157059Ssam/* 128157059Ssam * This glop is to figure out when it's safe to use callouts 129157059Ssam * to defer buffer flushing. There's probably a better way 130157059Ssam * and/or an earlier point in the boot process when it's ok. 131157059Ssam */ 132157059Ssamstatic int calloutok = 0; 133157059Ssamstatic void 134157059Ssamoktousecallout(void *data __unused) 135157059Ssam{ 136157059Ssam calloutok = 1; 137157059Ssam} 138253604SavgSYSINIT(gdbhack, SI_SUB_LAST, SI_ORDER_MIDDLE, oktousecallout, NULL); 139157059Ssam 140157059Ssamstatic void 141157059Ssamgdb_cnputc(struct consdev *cp, int c) 142157059Ssam{ 143157059Ssam struct gdbcons *gc; 144157059Ssam 145157059Ssam if (gdbcons_enable && gdb_cur != NULL && gdb_listening) { 146157059Ssam gc = cp->cn_arg; 147157059Ssam if (gc->npending != 0) { 148157059Ssam /* 149157059Ssam * Cancel any pending callout and flush the 150157059Ssam * buffer if there's no space for this byte. 151157059Ssam */ 152157059Ssam if (calloutok) 153157059Ssam callout_stop(&gc->flush); 154157059Ssam if (gc->npending == sizeof(gc->buf)) 155157059Ssam gdb_cnflush(gc); 156157059Ssam } 157157059Ssam gc->buf[gc->npending++] = c; 158157059Ssam /* 159157059Ssam * Flush on end of line; this is especially helpful 160157059Ssam * during boot when we don't have callouts to flush 161157059Ssam * the buffer. Otherwise we defer flushing; a 1/4 162157059Ssam * second is a guess. 163157059Ssam */ 164157059Ssam if (c == '\n') 165157059Ssam gdb_cnflush(gc); 166157059Ssam else if (calloutok) 167157059Ssam callout_reset(&gc->flush, hz/4, gdb_cnflush, gc); 168157059Ssam } 169157059Ssam} 170157059Ssam 171158960SphkCONSOLE_DRIVER(gdb); 172157059Ssam 173157059Ssam/* 174157059Ssam * Our console device only gets attached if the system is booted 175157059Ssam * with RB_MULTIPLE set so gdb_init also calls us to attach the 176157059Ssam * console so we're setup regardless. 177157059Ssam */ 178157059Ssamvoid 179157059Ssamgdb_consinit(void) 180157059Ssam{ 181157059Ssam gdb_cnprobe(&gdb_consdev); 182157059Ssam gdb_cninit(&gdb_consdev); 183157059Ssam cnadd(&gdb_consdev); 184157059Ssam} 185