1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2006 Sam Leffler 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Support for redirecting console msgs to gdb. We register 31 * a pseudo console to hook cnputc and send stuff to the gdb 32 * port. The only trickiness here is buffering output so this 33 * isn't dog slow. 34 */ 35 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD$"); 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/cons.h> 42 #include <sys/kdb.h> 43 #include <sys/kernel.h> 44 #include <sys/malloc.h> 45 #include <sys/reboot.h> 46 #include <sys/sysctl.h> 47 48 #include <machine/gdb_machdep.h> 49 #include <machine/kdb.h> 50 51 #include <gdb/gdb.h> 52 #include <gdb/gdb_int.h> 53 54 struct gdbcons { 55 int npending; 56 /* /2 for hex conversion, -6 for protocol glue */ 57 char buf[GDB_BUFSZ/2 - 6]; 58 struct callout flush; 59 }; 60 static struct gdbcons state = { -1 }; 61 62 static int gdbcons_enable = 0; 63 SYSCTL_INT(_debug_gdb, OID_AUTO, cons, CTLFLAG_RWTUN, &gdbcons_enable, 0, 64 "copy console messages to GDB"); 65 /* Legacy sysctl alias */ 66 SYSCTL_INT(_debug, OID_AUTO, gdbcons, CTLFLAG_RWTUN, &gdbcons_enable, 67 0, "copy console messages to GDB"); 68 69 static void 70 gdb_cnprobe(struct consdev *cp) 71 { 72 sprintf(cp->cn_name, "gdb"); 73 cp->cn_pri = CN_LOW; /* XXX no way to say "write only" */ 74 } 75 76 static void 77 gdb_cninit(struct consdev *cp) 78 { 79 struct gdbcons *c = &state; 80 81 /* setup tx buffer and callout */ 82 if (c->npending == -1) { 83 c->npending = 0; 84 callout_init(&c->flush, 1); 85 cp->cn_arg = c; 86 } 87 } 88 89 static void 90 gdb_cnterm(struct consdev *cp) 91 { 92 } 93 94 static void 95 gdb_cngrab(struct consdev *cp) 96 { 97 } 98 99 static void 100 gdb_cnungrab(struct consdev *cp) 101 { 102 } 103 104 static int 105 gdb_cngetc(struct consdev *cp) 106 { 107 return -1; 108 } 109 110 static void 111 gdb_tx_puthex(int c) 112 { 113 const char *hex = "0123456789abcdef"; 114 115 gdb_tx_char(hex[(c>>4)&0xf]); 116 gdb_tx_char(hex[(c>>0)&0xf]); 117 } 118 119 static void 120 gdb_cnflush(void *arg) 121 { 122 struct gdbcons *gc = arg; 123 int i; 124 125 gdb_tx_begin('O'); 126 for (i = 0; i < gc->npending; i++) 127 gdb_tx_puthex(gc->buf[i]); 128 gdb_tx_end(); 129 gc->npending = 0; 130 } 131 132 /* 133 * This glop is to figure out when it's safe to use callouts 134 * to defer buffer flushing. There's probably a better way 135 * and/or an earlier point in the boot process when it's ok. 136 */ 137 static int calloutok = 0; 138 static void 139 oktousecallout(void *data __unused) 140 { 141 calloutok = 1; 142 } 143 SYSINIT(gdbhack, SI_SUB_LAST, SI_ORDER_MIDDLE, oktousecallout, NULL); 144 145 static void 146 gdb_cnputc(struct consdev *cp, int c) 147 { 148 struct gdbcons *gc; 149 150 if (gdbcons_enable && gdb_cur != NULL && gdb_listening) { 151 gc = cp->cn_arg; 152 if (gc->npending != 0) { 153 /* 154 * Cancel any pending callout and flush the 155 * buffer if there's no space for this byte. 156 */ 157 if (calloutok) 158 callout_stop(&gc->flush); 159 if (gc->npending == sizeof(gc->buf)) 160 gdb_cnflush(gc); 161 } 162 gc->buf[gc->npending++] = c; 163 /* 164 * Flush on end of line; this is especially helpful 165 * during boot when we don't have callouts to flush 166 * the buffer. Otherwise we defer flushing; a 1/4 167 * second is a guess. 168 */ 169 if (c == '\n') 170 gdb_cnflush(gc); 171 else if (calloutok) 172 callout_reset(&gc->flush, hz/4, gdb_cnflush, gc); 173 } 174 } 175 176 CONSOLE_DRIVER(gdb); 177 178 /* 179 * Our console device only gets attached if the system is booted 180 * with RB_MULTIPLE set so gdb_init also calls us to attach the 181 * console so we're setup regardless. 182 */ 183 void 184 gdb_consinit(void) 185 { 186 gdb_cnprobe(&gdb_consdev); 187 gdb_cninit(&gdb_consdev); 188 cnadd(&gdb_consdev); 189 } 190