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: stable/10/sys/gdb/gdb_cons.c 314667 2017-03-04 13:03:31Z avg $"); 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; 80314667Savg callout_init(&c->flush, 1); 81157059Ssam cp->cn_arg = c; 82157059Ssam } 83157059Ssam} 84157059Ssam 85158960Sphkstatic void 86158960Sphkgdb_cnterm(struct consdev *cp) 87158960Sphk{ 88158960Sphk} 89158960Sphk 90228631Savgstatic void 91228631Savggdb_cngrab(struct consdev *cp) 92228631Savg{ 93228631Savg} 94228631Savg 95228631Savgstatic void 96228631Savggdb_cnungrab(struct consdev *cp) 97228631Savg{ 98228631Savg} 99228631Savg 100157059Ssamstatic int 101158960Sphkgdb_cngetc(struct consdev *cp) 102157059Ssam{ 103157059Ssam return -1; 104157059Ssam} 105157059Ssam 106157059Ssamstatic void 107157059Ssamgdb_tx_puthex(int c) 108157059Ssam{ 109157059Ssam const char *hex = "0123456789abcdef"; 110157059Ssam 111157059Ssam gdb_tx_char(hex[(c>>4)&0xf]); 112157059Ssam gdb_tx_char(hex[(c>>0)&0xf]); 113157059Ssam} 114157059Ssam 115157059Ssamstatic void 116157059Ssamgdb_cnflush(void *arg) 117157059Ssam{ 118157059Ssam struct gdbcons *gc = arg; 119157059Ssam int i; 120157059Ssam 121157059Ssam gdb_tx_begin('O'); 122157059Ssam for (i = 0; i < gc->npending; i++) 123157059Ssam gdb_tx_puthex(gc->buf[i]); 124157059Ssam gdb_tx_end(); 125157059Ssam gc->npending = 0; 126157059Ssam} 127157059Ssam 128157059Ssam/* 129157059Ssam * This glop is to figure out when it's safe to use callouts 130157059Ssam * to defer buffer flushing. There's probably a better way 131157059Ssam * and/or an earlier point in the boot process when it's ok. 132157059Ssam */ 133157059Ssamstatic int calloutok = 0; 134157059Ssamstatic void 135157059Ssamoktousecallout(void *data __unused) 136157059Ssam{ 137157059Ssam calloutok = 1; 138157059Ssam} 139253604SavgSYSINIT(gdbhack, SI_SUB_LAST, SI_ORDER_MIDDLE, oktousecallout, NULL); 140157059Ssam 141157059Ssamstatic void 142157059Ssamgdb_cnputc(struct consdev *cp, int c) 143157059Ssam{ 144157059Ssam struct gdbcons *gc; 145157059Ssam 146157059Ssam if (gdbcons_enable && gdb_cur != NULL && gdb_listening) { 147157059Ssam gc = cp->cn_arg; 148157059Ssam if (gc->npending != 0) { 149157059Ssam /* 150157059Ssam * Cancel any pending callout and flush the 151157059Ssam * buffer if there's no space for this byte. 152157059Ssam */ 153157059Ssam if (calloutok) 154157059Ssam callout_stop(&gc->flush); 155157059Ssam if (gc->npending == sizeof(gc->buf)) 156157059Ssam gdb_cnflush(gc); 157157059Ssam } 158157059Ssam gc->buf[gc->npending++] = c; 159157059Ssam /* 160157059Ssam * Flush on end of line; this is especially helpful 161157059Ssam * during boot when we don't have callouts to flush 162157059Ssam * the buffer. Otherwise we defer flushing; a 1/4 163157059Ssam * second is a guess. 164157059Ssam */ 165157059Ssam if (c == '\n') 166157059Ssam gdb_cnflush(gc); 167157059Ssam else if (calloutok) 168157059Ssam callout_reset(&gc->flush, hz/4, gdb_cnflush, gc); 169157059Ssam } 170157059Ssam} 171157059Ssam 172158960SphkCONSOLE_DRIVER(gdb); 173157059Ssam 174157059Ssam/* 175157059Ssam * Our console device only gets attached if the system is booted 176157059Ssam * with RB_MULTIPLE set so gdb_init also calls us to attach the 177157059Ssam * console so we're setup regardless. 178157059Ssam */ 179157059Ssamvoid 180157059Ssamgdb_consinit(void) 181157059Ssam{ 182157059Ssam gdb_cnprobe(&gdb_consdev); 183157059Ssam gdb_cninit(&gdb_consdev); 184157059Ssam cnadd(&gdb_consdev); 185157059Ssam} 186