1 /* 2 * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)subr_prf.c 7.17 (Berkeley) 05/15/90 7 */ 8 9 #include "param.h" 10 #include "systm.h" 11 #include "seg.h" 12 #include "buf.h" 13 #include "conf.h" 14 #include "reboot.h" 15 #include "vm.h" 16 #include "msgbuf.h" 17 #include "user.h" 18 #include "proc.h" 19 #include "ioctl.h" 20 #include "vnode.h" 21 #include "file.h" 22 #include "tty.h" 23 #include "syslog.h" 24 25 #include "machine/mtpr.h" 26 #ifdef KADB 27 #include "machine/kdbparam.h" 28 #endif 29 30 #define TOCONS 0x1 31 #define TOTTY 0x2 32 #define TOLOG 0x4 33 34 /* 35 * In case console is off, 36 * panicstr contains argument to last 37 * call to panic. 38 */ 39 char *panicstr; 40 41 extern cnputc(); /* standard console putc */ 42 int (*v_putc)() = cnputc; /* routine to putc on virtual console */ 43 extern struct tty cons; /* standard console tty */ 44 struct tty *constty; /* pointer to console "window" tty */ 45 46 #ifdef KADB 47 extern cngetc(); /* standard console getc */ 48 extern cnpoll(); 49 int (*v_getc)() = cngetc; /* "" getc from virtual console */ 50 int (*v_poll)() = cnpoll; /* kdb hook to enable input polling */ 51 #endif 52 53 /* 54 * Scaled down version of C Library printf. 55 * Used to print diagnostic information directly on console tty. 56 * Since it is not interrupt driven, all system activities are 57 * suspended. Printf should not be used for chit-chat. 58 * 59 * One additional format: %b is supported to decode error registers. 60 * Usage is: 61 * printf("reg=%b\n", regval, "<base><arg>*"); 62 * Where <base> is the output base expressed as a control character, 63 * e.g. \10 gives octal; \20 gives hex. Each arg is a sequence of 64 * characters, the first of which gives the bit number to be inspected 65 * (origin 1), and the next characters (up to a control character, i.e. 66 * a character <= 32), give the name of the register. Thus 67 * printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 68 * would produce output: 69 * reg=3<BITTWO,BITONE> 70 * 71 * Another additional format: %r is used to pass an additional format string 72 * and argument list recursively. Usage is typically: 73 * 74 * fn(otherstuff, fmt [, arg1, ... ] ) 75 * char *fmt; 76 * u_int arg1, ...; 77 * 78 * printf("prefix: %r, other stuff\n", fmt, &arg1); 79 */ 80 #if defined(tahoe) 81 int consintr; 82 #endif 83 84 /*VARARGS1*/ 85 printf(fmt, x1) 86 char *fmt; 87 unsigned x1; 88 { 89 #if defined(tahoe) 90 register int savintr; 91 92 savintr = consintr, consintr = 0; /* disable interrupts */ 93 #endif 94 prf(fmt, &x1, TOCONS | TOLOG, (caddr_t)0); 95 if (!panicstr) 96 logwakeup(); 97 #if defined(tahoe) 98 consintr = savintr; /* reenable interrupts */ 99 #endif 100 } 101 102 /* 103 * Uprintf prints to the controlling terminal for the current process. 104 * It may block if the tty queue is overfull. 105 * No message is printed if the queue does not clear 106 * in a reasonable time. 107 */ 108 /*VARARGS1*/ 109 uprintf(fmt, x1) 110 char *fmt; 111 unsigned x1; 112 { 113 register struct tty *tp = u.u_procp->p_session->s_ttyp; 114 115 if (tp != NULL && tp->t_session == u.u_procp->p_session) 116 prf(fmt, &x1, TOTTY, (caddr_t)tp); 117 } 118 119 /* 120 * tprintf prints on the specified terminal (console if none) 121 * and logs the message. It is designed for error messages from 122 * single-open devices, and may be called from interrupt level 123 * (does not sleep). 124 */ 125 /*VARARGS2*/ 126 tprintf(vp, fmt, x1) 127 register caddr_t vp; 128 char *fmt; 129 unsigned x1; 130 { 131 #ifdef notyet 132 int flags = TOTTY | TOLOG; 133 134 logpri(LOG_INFO); 135 136 if (vp == NULL || 137 VOP_IOCTL(vp, TIOCCHECKOUTQ, &val, FWRITE, NOCRED) != 0 || 138 val == 0) 139 flags = TOLOG; 140 prf(fmt, &x1, flags, vp); 141 logwakeup(); 142 #else 143 printf("tprintf called\n"); 144 #endif 145 } 146 147 /* 148 * Log writes to the log buffer, 149 * and guarantees not to sleep (so can be called by interrupt routines). 150 * If there is no process reading the log yet, it writes to the console also. 151 */ 152 /*VARARGS2*/ 153 log(level, fmt, x1) 154 char *fmt; 155 unsigned x1; 156 { 157 register s = splhigh(); 158 extern int log_open; 159 160 logpri(level); 161 prf(fmt, &x1, TOLOG, (caddr_t)0); 162 splx(s); 163 if (!log_open) 164 prf(fmt, &x1, TOCONS, (caddr_t)0); 165 logwakeup(); 166 } 167 168 logpri(level) 169 int level; 170 { 171 172 putchar('<', TOLOG, (caddr_t)0); 173 printn((u_long)level, 10, TOLOG, (caddr_t)0); 174 putchar('>', TOLOG, (caddr_t)0); 175 } 176 177 /*VARARGS1*/ 178 addlog(fmt, x1) 179 char *fmt; 180 unsigned x1; 181 { 182 register s = splhigh(); 183 184 prf(fmt, &x1, TOLOG, (caddr_t)0); 185 splx(s); 186 if (!log_open) 187 prf(fmt, &x1, TOCONS, (caddr_t)0); 188 logwakeup(); 189 } 190 191 prf(fmt, adx, flags, where) 192 register char *fmt; 193 register u_int *adx; 194 caddr_t where; 195 { 196 register int b, c, i; 197 char *s; 198 int any; 199 200 loop: 201 while ((c = *fmt++) != '%') { 202 if (c == '\0') 203 return; 204 putchar(c, flags, where); 205 } 206 again: 207 c = *fmt++; 208 /* THIS CODE IS MACHINE DEPENDENT IN HANDLING %l? AND %c */ 209 switch (c) { 210 211 case 'l': 212 goto again; 213 case 'x': case 'X': 214 b = 16; 215 goto number; 216 case 'd': case 'D': 217 b = -10; 218 goto number; 219 case 'u': 220 b = 10; 221 goto number; 222 case 'o': case 'O': 223 b = 8; 224 number: 225 printn((u_long)*adx, b, flags, where); 226 break; 227 case 'c': 228 b = *adx; 229 #if BYTE_ORDER == LITTLE_ENDIAN 230 for (i = 24; i >= 0; i -= 8) 231 if (c = (b >> i) & 0x7f) 232 putchar(c, flags, where); 233 #endif 234 #if BYTE_ORDER == BIG_ENDIAN 235 if (c = (b & 0x7f)) 236 putchar(c, flags, where); 237 #endif 238 break; 239 case 'b': 240 b = *adx++; 241 s = (char *)*adx; 242 printn((u_long)b, *s++, flags, where); 243 any = 0; 244 if (b) { 245 while (i = *s++) { 246 if (b & (1 << (i-1))) { 247 putchar(any ? ',' : '<', flags, where); 248 any = 1; 249 for (; (c = *s) > 32; s++) 250 putchar(c, flags, where); 251 } else 252 for (; *s > 32; s++) 253 ; 254 } 255 if (any) 256 putchar('>', flags, where); 257 } 258 break; 259 260 case 's': 261 s = (char *)*adx; 262 while (c = *s++) 263 putchar(c, flags, where); 264 break; 265 266 case 'r': 267 s = (char *)*adx++; 268 prf(s, (u_int *)*adx, flags, where); 269 break; 270 271 case '%': 272 putchar('%', flags, where); 273 break; 274 } 275 adx++; 276 goto loop; 277 } 278 279 /* 280 * Printn prints a number n in base b. 281 * We don't use recursion to avoid deep kernel stacks. 282 */ 283 printn(n, b, flags, where) 284 u_long n; 285 caddr_t where; 286 { 287 char prbuf[11]; 288 register char *cp; 289 290 if (b == -10) { 291 if ((int)n < 0) { 292 putchar('-', flags, where); 293 n = (unsigned)(-(int)n); 294 } 295 b = -b; 296 } 297 cp = prbuf; 298 do { 299 *cp++ = "0123456789abcdef"[n%b]; 300 n /= b; 301 } while (n); 302 do 303 putchar(*--cp, flags, where); 304 while (cp > prbuf); 305 } 306 307 /* 308 * Panic is called on unresolvable fatal errors. 309 * It prints "panic: mesg", and then reboots. 310 * If we are called twice, then we avoid trying to 311 * sync the disks as this often leads to recursive panics. 312 */ 313 panic(s) 314 char *s; 315 { 316 int bootopt = RB_AUTOBOOT | RB_DUMP; 317 318 if (panicstr) 319 bootopt |= RB_NOSYNC; 320 else { 321 panicstr = s; 322 } 323 printf("panic: %s\n", s); 324 #ifdef KADB 325 if (boothowto & RB_KDB) { 326 int x = splnet(); /* below kdb pri */ 327 328 setsoftkdb(); 329 splx(x); 330 } 331 #endif 332 boot(bootopt); 333 } 334 335 /* 336 * Warn that a system table is full. 337 */ 338 tablefull(tab) 339 char *tab; 340 { 341 342 log(LOG_ERR, "%s: table is full\n", tab); 343 } 344 345 /* 346 * Print a character on console or users terminal. 347 * If destination is console then the last MSGBUFS characters 348 * are saved in msgbuf for inspection later. 349 */ 350 /*ARGSUSED*/ 351 putchar(c, flags, where) 352 register int c; 353 caddr_t where; 354 { 355 extern int msgbufmapped; 356 357 if (panicstr) 358 constty = 0; 359 if ((flags & TOCONS) && where == 0 && constty) { 360 where = (caddr_t)constty; 361 flags |= TOTTY; 362 } 363 if ((flags & TOTTY) && where && tputchar(c, (struct tty *)where) < 0 && 364 (flags & TOCONS) && (struct tty *)where == constty) 365 constty = 0; 366 if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177 && 367 msgbufmapped) { 368 if (msgbuf.msg_magic != MSG_MAGIC) { 369 register int i; 370 371 msgbuf.msg_magic = MSG_MAGIC; 372 msgbuf.msg_bufx = msgbuf.msg_bufr = 0; 373 for (i=0; i < MSG_BSIZE; i++) 374 msgbuf.msg_bufc[i] = 0; 375 } 376 msgbuf.msg_bufc[msgbuf.msg_bufx++] = c; 377 if (msgbuf.msg_bufx < 0 || msgbuf.msg_bufx >= MSG_BSIZE) 378 msgbuf.msg_bufx = 0; 379 } 380 if ((flags & TOCONS) && constty == 0 && c != '\0') 381 (*v_putc)(c); 382 } 383