1 /* 2 * Mach Operating System 3 * Copyright (c) 1991,1990 Carnegie Mellon University 4 * All Rights Reserved. 5 * 6 * Permission to use, copy, modify and distribute this software and its 7 * documentation is hereby granted, provided that both the copyright 8 * notice and this permission notice appear in all copies of the 9 * software, derivative works or modified versions, and any portions 10 * thereof, and that both notices appear in supporting documentation. 11 * 12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 15 * 16 * Carnegie Mellon requests users of this software to return to 17 * 18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 19 * School of Computer Science 20 * Carnegie Mellon University 21 * Pittsburgh PA 15213-3890 22 * 23 * any improvements or extensions that they make and grant Carnegie the 24 * rights to redistribute these changes. 25 * 26 * $FreeBSD: src/sys/ddb/db_output.c,v 1.26 1999/08/28 00:41:09 peter Exp $ 27 */ 28 29 /* 30 * Author: David B. Golub, Carnegie Mellon University 31 * Date: 7/90 32 */ 33 34 /* 35 * Printf and character output for debugger. 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/cons.h> 41 #include <sys/ctype.h> 42 #include <sys/thread2.h> 43 #include <sys/spinlock2.h> 44 45 #include <machine/stdarg.h> 46 47 #include <ddb/ddb.h> 48 #include <ddb/db_output.h> 49 50 /* 51 * Character output - tracks position in line. 52 * To do this correctly, we should know how wide 53 * the output device is - then we could zero 54 * the line position when the output device wraps 55 * around to the start of the next line. 56 * 57 * Instead, we count the number of spaces printed 58 * since the last printing character so that we 59 * don't print trailing spaces. This avoids most 60 * of the wraparounds. 61 */ 62 static int db_output_position = 0; /* output column */ 63 static int db_last_non_space = 0; /* last non-space character */ 64 db_expr_t db_tab_stop_width = 8; /* how wide are tab stops? */ 65 #define NEXT_TAB(i) rounddown((i) + db_tab_stop_width, db_tab_stop_width) 66 db_expr_t db_max_width = 79; /* output line width */ 67 68 static void db_putchar (int c, void *arg); 69 70 /* 71 * Force pending whitespace. 72 */ 73 void 74 db_force_whitespace(void) 75 { 76 int last_print, next_tab; 77 78 last_print = db_last_non_space; 79 while (last_print < db_output_position) { 80 next_tab = NEXT_TAB(last_print); 81 if (next_tab <= db_output_position) { 82 while (last_print < next_tab) { /* DON'T send a tab!!! */ 83 cnputc(' '); 84 last_print++; 85 } 86 } 87 else { 88 cnputc(' '); 89 last_print++; 90 } 91 } 92 db_last_non_space = db_output_position; 93 } 94 95 /* 96 * Output character. Buffer whitespace. 97 * 98 * Parameters: 99 * arg: character to output 100 */ 101 static void 102 db_putchar(int c, void *arg) 103 { 104 /* 105 * If not in the debugger, output data to both the console and 106 * the message buffer. 107 */ 108 if (!db_active) { 109 if (c == '\r' || c == '\n' || c == '\t' || 110 isprint(c)) { 111 kprintf("%c", c); 112 } else { 113 kprintf("?"); 114 } 115 if (!db_active) 116 return; 117 if (c == '\r' || c == '\n') 118 db_check_interrupt(); 119 return; 120 } 121 122 crit_enter_hard(); 123 124 if (c > ' ' && c <= '~') { 125 /* 126 * Printing character. 127 * If we have spaces to print, print them first. 128 * Use tabs if possible. 129 */ 130 db_force_whitespace(); 131 cnputc(c); 132 db_output_position++; 133 db_last_non_space = db_output_position; 134 } 135 else if (c == '\n') { 136 /* Newline */ 137 cnputc(c); 138 db_output_position = 0; 139 db_last_non_space = 0; 140 db_check_interrupt(); 141 } 142 else if (c == '\r') { 143 /* Return */ 144 cnputc(c); 145 db_output_position = 0; 146 db_last_non_space = 0; 147 db_check_interrupt(); 148 } 149 else if (c == '\t') { 150 /* assume tabs every 8 positions */ 151 db_output_position = NEXT_TAB(db_output_position); 152 } 153 else if (c == ' ') { 154 /* space */ 155 db_output_position++; 156 } 157 else if (c == '\007') { 158 /* bell */ 159 cnputc(c); 160 } 161 /* other characters are assumed non-printing */ 162 crit_exit_hard(); 163 } 164 165 /* 166 * Return output position 167 */ 168 int 169 db_print_position(void) 170 { 171 return (db_output_position); 172 } 173 174 /* 175 * Printing 176 * 177 * NOTE: We bypass subr_prf's cons_spin here by using our own putchar 178 * function. 179 */ 180 void 181 db_printf(const char *fmt, ...) 182 { 183 __va_list listp; 184 185 __va_start(listp, fmt); 186 kvcprintf (fmt, db_putchar, NULL, listp); 187 __va_end(listp); 188 /* DELAY(100000);*/ 189 } 190 191 void 192 db_vprintf(const char *fmt, __va_list va) 193 { 194 kvcprintf (fmt, db_putchar, NULL, va); 195 /* DELAY(100000);*/ 196 } 197 198 int db_indent; 199 200 void 201 db_iprintf(const char *fmt,...) 202 { 203 int i; 204 __va_list listp; 205 206 for (i = db_indent; i >= 8; i -= 8) 207 db_printf("\t"); 208 while (--i >= 0) 209 db_printf(" "); 210 __va_start(listp, fmt); 211 kvcprintf (fmt, db_putchar, NULL, listp); 212 __va_end(listp); 213 } 214 215 /* 216 * End line if too long. 217 */ 218 void 219 db_end_line(int field_width) 220 { 221 if (db_output_position + field_width > db_max_width) 222 db_printf("\n"); 223 } 224 225 /* 226 * Simple pager 227 */ 228 int 229 db_more(int *nl) 230 { 231 ++*nl; 232 if (*nl == 20) { 233 int c; 234 235 db_printf("--More--"); 236 c = cngetc(); 237 db_printf("\r"); 238 /* 239 * A whole screenfull or just one line? 240 */ 241 switch (c) { 242 case '\n': /* just one line */ 243 *nl = 19; 244 break; 245 case ' ': 246 *nl = 0; /* another screenfull */ 247 break; 248 default: /* exit */ 249 db_printf("\n"); 250 return(-1); 251 } 252 } 253 return(0); 254 } 255 256 /* 257 * Replacement for old '%r' kprintf format. 258 */ 259 void 260 db_format_radix(char *buf, size_t bufsiz, quad_t val, int altflag) 261 { 262 const char *fmt; 263 264 if (db_radix == 16) { 265 db_format_hex(buf, bufsiz, val, altflag); 266 return; 267 } 268 269 if (db_radix == 8) 270 fmt = altflag ? "-%#qo" : "-%qo"; 271 else 272 fmt = altflag ? "-%#qu" : "-%qu"; 273 274 if (val < 0) 275 val = -val; 276 else 277 ++fmt; 278 279 ksnprintf(buf, bufsiz, fmt, val); 280 } 281 282 /* 283 * Replacement for old '%z' kprintf format. 284 */ 285 void 286 db_format_hex(char *buf, size_t bufsiz, quad_t val, int altflag) 287 { 288 /* Only use alternate form if val is nonzero. */ 289 const char *fmt = (altflag && val) ? "-%#qx" : "-%qx"; 290 291 if (val < 0) 292 val = -val; 293 else 294 ++fmt; 295 296 ksnprintf(buf, bufsiz, fmt, val); 297 } 298 299 /* #define TEMPORARY_DEBUGGING */ 300 #ifdef TEMPORARY_DEBUGGING 301 302 /* 303 * Temporary Debugging, only turned on manually by kernel hackers trying 304 * to debug extremely low level code. Adjust PCHAR_ as required. 305 */ 306 static void PCHAR_(int, void * __unused); 307 308 void 309 kprintf0(const char *fmt, ...) 310 { 311 __va_list ap; 312 313 __va_start(ap, fmt); 314 kvcprintf(fmt, PCHAR_, NULL, ap); 315 __va_end(ap); 316 } 317 318 static void 319 PCHAR_(int c, void *dummy __unused) 320 { 321 const int COMC_TXWAIT = 0x40000; 322 const int COMPORT = 0x2f8; /* 0x3f8 COM1, 0x2f8 COM2 */ 323 const int LSR_TXRDY = 0x20; 324 const int BAUD = 115200; 325 const int com_lsr = 5; 326 const int com_data = 0; 327 int wait; 328 static int setbaud; 329 330 if (setbaud == 0) { 331 setbaud = 1; 332 outb(COMPORT+3, 0x83); /* DLAB + 8N1 */ 333 outb(COMPORT+0, (115200 / BAUD) & 0xFF); 334 outb(COMPORT+1, (115200 / BAUD) >> 8); 335 outb(COMPORT+3, 0x03); /* 8N1 */ 336 outb(COMPORT+4, 0x03); /* RTS+DTR */ 337 outb(COMPORT+2, 0x01); /* FIFO_ENABLE */ 338 } 339 340 for (wait = COMC_TXWAIT; wait > 0; wait--) { 341 if (inb(COMPORT + com_lsr) & LSR_TXRDY) { 342 outb(COMPORT + com_data, (u_char)c); 343 break; 344 } 345 } 346 } 347 348 #endif 349