123381Smckusick /* 234420Skarels * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 323381Smckusick * All rights reserved. The Berkeley software License Agreement 423381Smckusick * specifies the terms and conditions for redistribution. 523381Smckusick * 6*39560Smarc * @(#)subr_prf.c 7.15 (Berkeley) 11/20/89 723381Smckusick */ 831Sbill 917094Sbloom #include "param.h" 1017094Sbloom #include "systm.h" 1117094Sbloom #include "seg.h" 1217094Sbloom #include "buf.h" 1317094Sbloom #include "conf.h" 1417094Sbloom #include "reboot.h" 1517094Sbloom #include "vm.h" 1617094Sbloom #include "msgbuf.h" 1717094Sbloom #include "user.h" 1817094Sbloom #include "proc.h" 1917577Sbloom #include "ioctl.h" 20*39560Smarc #include "vnode.h" 21*39560Smarc #include "file.h" 2217094Sbloom #include "tty.h" 2318364Skarels #include "syslog.h" 2431Sbill 2537496Smckusick #include "machine/mtpr.h" 2635282Skarels #ifdef KADB 2737496Smckusick #include "machine/kdbparam.h" 2830625Skarels #endif 2930625Skarels 3016724Sralph #define TOCONS 0x1 3116724Sralph #define TOTTY 0x2 3216724Sralph #define TOLOG 0x4 3316724Sralph 3431Sbill /* 3531Sbill * In case console is off, 3631Sbill * panicstr contains argument to last 3731Sbill * call to panic. 3831Sbill */ 3931Sbill char *panicstr; 4031Sbill 4130549Skarels extern cnputc(); /* standard console putc */ 4230549Skarels extern struct tty cons; /* standard console tty */ 4330549Skarels struct tty *constty; /* pointer to console "window" tty */ 4430549Skarels int (*v_putc)() = cnputc; /* routine to putc on virtual console */ 4530549Skarels 4631Sbill /* 4731Sbill * Scaled down version of C Library printf. 482781Swnj * Used to print diagnostic information directly on console tty. 492781Swnj * Since it is not interrupt driven, all system activities are 502781Swnj * suspended. Printf should not be used for chit-chat. 512781Swnj * 522781Swnj * One additional format: %b is supported to decode error registers. 532781Swnj * Usage is: 542781Swnj * printf("reg=%b\n", regval, "<base><arg>*"); 552781Swnj * Where <base> is the output base expressed as a control character, 562781Swnj * e.g. \10 gives octal; \20 gives hex. Each arg is a sequence of 572781Swnj * characters, the first of which gives the bit number to be inspected 582781Swnj * (origin 1), and the next characters (up to a control character, i.e. 592781Swnj * a character <= 32), give the name of the register. Thus 602781Swnj * printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 612781Swnj * would produce output: 6217594Skarels * reg=3<BITTWO,BITONE> 6334478Skarels * 6434478Skarels * Another additional format: %r is used to pass an additional format string 6534478Skarels * and argument list recursively. Usage is typically: 6634478Skarels * 6734478Skarels * fn(otherstuff, fmt [, arg1, ... ] ) 6834478Skarels * char *fmt; 6934478Skarels * u_int arg1, ...; 7034478Skarels * 7134478Skarels * printf("prefix: %r, other stuff\n", fmt, &arg1); 7231Sbill */ 7329946Skarels #if defined(tahoe) 7429946Skarels int consintr; 7529946Skarels #endif 7629946Skarels 7731Sbill /*VARARGS1*/ 7831Sbill printf(fmt, x1) 792781Swnj char *fmt; 802781Swnj unsigned x1; 8131Sbill { 8229946Skarels #if defined(tahoe) 8329946Skarels register int savintr; 84285Sbill 8529946Skarels savintr = consintr, consintr = 0; /* disable interrupts */ 8629946Skarels #endif 87*39560Smarc prf(fmt, &x1, TOCONS | TOLOG, (caddr_t)0); 8816724Sralph logwakeup(); 8929946Skarels #if defined(tahoe) 9029946Skarels consintr = savintr; /* reenable interrupts */ 9129946Skarels #endif 92285Sbill } 93285Sbill 942377Swnj /* 95*39560Smarc * Uprintf prints to the controlling terminal for the current process. 9625389Skarels * It may block if the tty queue is overfull. 9730695Skarels * No message is printed if the queue does not clear 9830695Skarels * in a reasonable time. 992377Swnj */ 1002377Swnj /*VARARGS1*/ 1012377Swnj uprintf(fmt, x1) 1022781Swnj char *fmt; 1032377Swnj unsigned x1; 104285Sbill { 105*39560Smarc register struct tty *tp = u.u_procp->p_session->s_ttyp; 106285Sbill 107*39560Smarc if (tp != NULL && tp->t_session == u.u_procp->p_session) 10830695Skarels prf(fmt, &x1, TOTTY, tp); 109285Sbill } 110285Sbill 11118364Skarels /* 11218364Skarels * tprintf prints on the specified terminal (console if none) 11318364Skarels * and logs the message. It is designed for error messages from 11425389Skarels * single-open devices, and may be called from interrupt level 11525389Skarels * (does not sleep). 11618364Skarels */ 11716724Sralph /*VARARGS2*/ 118*39560Smarc tprintf(vp, fmt, x1) 119*39560Smarc register caddr_t vp; 12016724Sralph char *fmt; 12116724Sralph unsigned x1; 12216724Sralph { 12325389Skarels int flags = TOTTY | TOLOG; 12416724Sralph 125*39560Smarc #ifdef notyet 12625389Skarels logpri(LOG_INFO); 127*39560Smarc 128*39560Smarc if (vp == NULL || 129*39560Smarc VOP_IOCTL(vp, TIOCCHECKOUTQ, &val, FWRITE, NOCRED) != 0 || 130*39560Smarc val == 0) 13125389Skarels flags = TOLOG; 132*39560Smarc prf(fmt, &x1, flags, vp); 13325389Skarels logwakeup(); 134*39560Smarc #else 135*39560Smarc printf("tprintf called\n"); 136*39560Smarc #endif 13716724Sralph } 13816724Sralph 13916724Sralph /* 14016724Sralph * Log writes to the log buffer, 14117594Skarels * and guarantees not to sleep (so can be called by interrupt routines). 14218364Skarels * If there is no process reading the log yet, it writes to the console also. 14316724Sralph */ 14416724Sralph /*VARARGS2*/ 14516724Sralph log(level, fmt, x1) 14616724Sralph char *fmt; 14716724Sralph unsigned x1; 14816724Sralph { 14916724Sralph register s = splhigh(); 15018364Skarels extern int log_open; 15116724Sralph 15225389Skarels logpri(level); 153*39560Smarc prf(fmt, &x1, TOLOG, (caddr_t)0); 15416724Sralph splx(s); 15518364Skarels if (!log_open) 156*39560Smarc prf(fmt, &x1, TOCONS, (caddr_t)0); 15716724Sralph logwakeup(); 15816724Sralph } 15916724Sralph 16025389Skarels logpri(level) 16125389Skarels int level; 16225389Skarels { 16325389Skarels 16425389Skarels putchar('<', TOLOG, (struct tty *)0); 16526356Skarels printn((u_long)level, 10, TOLOG, (struct tty *)0); 16625389Skarels putchar('>', TOLOG, (struct tty *)0); 16725389Skarels } 16825389Skarels 16933479Skarels /*VARARGS1*/ 17033479Skarels addlog(fmt, x1) 17133479Skarels char *fmt; 17233479Skarels unsigned x1; 17333479Skarels { 17433479Skarels register s = splhigh(); 17533479Skarels 176*39560Smarc prf(fmt, &x1, TOLOG, (caddr_t)0); 17733479Skarels splx(s); 17833479Skarels if (!log_open) 179*39560Smarc prf(fmt, &x1, TOCONS, (caddr_t)0); 18033479Skarels logwakeup(); 18133479Skarels } 18233479Skarels 183*39560Smarc prf(fmt, adx, flags, where) 1842781Swnj register char *fmt; 1852781Swnj register u_int *adx; 186*39560Smarc caddr_t where; 187285Sbill { 1882434Swnj register int b, c, i; 18931Sbill char *s; 1902678Swnj int any; 19131Sbill 19231Sbill loop: 1932377Swnj while ((c = *fmt++) != '%') { 19416724Sralph if (c == '\0') 19531Sbill return; 196*39560Smarc putchar(c, flags, where); 19731Sbill } 1982377Swnj again: 19931Sbill c = *fmt++; 20029946Skarels /* THIS CODE IS MACHINE DEPENDENT IN HANDLING %l? AND %c */ 2012377Swnj switch (c) { 2022377Swnj 2032377Swnj case 'l': 2042377Swnj goto again; 2052377Swnj case 'x': case 'X': 2062377Swnj b = 16; 2072377Swnj goto number; 2082377Swnj case 'd': case 'D': 20929946Skarels b = -10; 21029946Skarels goto number; 21129946Skarels case 'u': 2122377Swnj b = 10; 2132377Swnj goto number; 2142377Swnj case 'o': case 'O': 2152377Swnj b = 8; 2162377Swnj number: 217*39560Smarc printn((u_long)*adx, b, flags, where); 2182377Swnj break; 2192377Swnj case 'c': 2202434Swnj b = *adx; 22133479Skarels #if BYTE_ORDER == LITTLE_ENDIAN 2222434Swnj for (i = 24; i >= 0; i -= 8) 2232434Swnj if (c = (b >> i) & 0x7f) 224*39560Smarc putchar(c, flags, where); 22529946Skarels #endif 22633479Skarels #if BYTE_ORDER == BIG_ENDIAN 22729946Skarels if (c = (b & 0x7f)) 228*39560Smarc putchar(c, flags, where); 22929946Skarels #endif 2302377Swnj break; 2312678Swnj case 'b': 2322678Swnj b = *adx++; 2332678Swnj s = (char *)*adx; 234*39560Smarc printn((u_long)b, *s++, flags, where); 2352678Swnj any = 0; 2362678Swnj if (b) { 2372678Swnj while (i = *s++) { 2382678Swnj if (b & (1 << (i-1))) { 239*39560Smarc putchar(any ? ',' : '<', flags, where); 2402678Swnj any = 1; 2412678Swnj for (; (c = *s) > 32; s++) 242*39560Smarc putchar(c, flags, where); 2432678Swnj } else 2442678Swnj for (; *s > 32; s++) 2452678Swnj ; 2462678Swnj } 2473878Swnj if (any) 248*39560Smarc putchar('>', flags, where); 2492678Swnj } 2502678Swnj break; 2512678Swnj 2522377Swnj case 's': 25331Sbill s = (char *)*adx; 254285Sbill while (c = *s++) 255*39560Smarc putchar(c, flags, where); 2562377Swnj break; 2573736Sroot 25833479Skarels case 'r': 25933479Skarels s = (char *)*adx++; 260*39560Smarc prf(s, (u_int *)*adx, flags, where); 26133479Skarels break; 26233479Skarels 2633736Sroot case '%': 264*39560Smarc putchar('%', flags, where); 2653736Sroot break; 26631Sbill } 26731Sbill adx++; 26831Sbill goto loop; 26931Sbill } 27031Sbill 2712781Swnj /* 2722781Swnj * Printn prints a number n in base b. 2732781Swnj * We don't use recursion to avoid deep kernel stacks. 2742781Swnj */ 275*39560Smarc printn(n, b, flags, where) 2763101Swnj u_long n; 277*39560Smarc caddr_t where; 27831Sbill { 2792434Swnj char prbuf[11]; 2802377Swnj register char *cp; 28131Sbill 28229946Skarels if (b == -10) { 28329946Skarels if ((int)n < 0) { 284*39560Smarc putchar('-', flags, where); 28529946Skarels n = (unsigned)(-(int)n); 28629946Skarels } 28729946Skarels b = -b; 28831Sbill } 2892434Swnj cp = prbuf; 2902377Swnj do { 2912377Swnj *cp++ = "0123456789abcdef"[n%b]; 2922377Swnj n /= b; 2932377Swnj } while (n); 2942377Swnj do 295*39560Smarc putchar(*--cp, flags, where); 2962434Swnj while (cp > prbuf); 29731Sbill } 29831Sbill 29931Sbill /* 3001184Sbill * Panic is called on unresolvable fatal errors. 3012781Swnj * It prints "panic: mesg", and then reboots. 3022781Swnj * If we are called twice, then we avoid trying to 3032781Swnj * sync the disks as this often leads to recursive panics. 30431Sbill */ 30531Sbill panic(s) 3062781Swnj char *s; 30731Sbill { 30830566Skarels int bootopt = RB_AUTOBOOT | RB_DUMP; 3092377Swnj 3105416Swnj if (panicstr) 3115416Swnj bootopt |= RB_NOSYNC; 3129758Ssam else { 3139758Ssam panicstr = s; 3148950Sroot } 3153285Swnj printf("panic: %s\n", s); 31635282Skarels #ifdef KADB 31730625Skarels if (boothowto & RB_KDB) { 31834420Skarels int x = splnet(); /* below kdb pri */ 31930625Skarels 32030625Skarels setsoftkdb(); 32134420Skarels splx(x); 32230625Skarels } 32330625Skarels #endif 32430566Skarels boot(bootopt); 32531Sbill } 32631Sbill 32731Sbill /* 3282941Swnj * Warn that a system table is full. 3292941Swnj */ 3302941Swnj tablefull(tab) 3312941Swnj char *tab; 3322941Swnj { 3332941Swnj 33424839Seric log(LOG_ERR, "%s: table is full\n", tab); 3352941Swnj } 3362941Swnj 3372941Swnj /* 3382377Swnj * Print a character on console or users terminal. 339285Sbill * If destination is console then the last MSGBUFS characters 340285Sbill * are saved in msgbuf for inspection later. 341285Sbill */ 3421785Sbill /*ARGSUSED*/ 343*39560Smarc putchar(c, flags, where) 3442377Swnj register int c; 345*39560Smarc caddr_t where; 346285Sbill { 34733479Skarels extern int msgbufmapped; 348285Sbill 34930549Skarels if (panicstr) 35030549Skarels constty = 0; 351*39560Smarc if ((flags & TOCONS) && where == 0 && constty) { 352*39560Smarc where = (caddr_t)constty; 35330549Skarels flags |= TOTTY; 35430549Skarels } 355*39560Smarc if ((flags & TOTTY) && where && tputchar(c, (struct tty *)where) < 0 && 356*39560Smarc (flags & TOCONS) && (struct tty *)where == constty) 357*39560Smarc constty = 0; 35833479Skarels if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177 && 35933479Skarels msgbufmapped) { 3602172Swnj if (msgbuf.msg_magic != MSG_MAGIC) { 36112494Ssam register int i; 36212494Ssam 3632172Swnj msgbuf.msg_magic = MSG_MAGIC; 36416724Sralph msgbuf.msg_bufx = msgbuf.msg_bufr = 0; 36512494Ssam for (i=0; i < MSG_BSIZE; i++) 36612494Ssam msgbuf.msg_bufc[i] = 0; 3672172Swnj } 36826427Sbloom msgbuf.msg_bufc[msgbuf.msg_bufx++] = c; 3692172Swnj if (msgbuf.msg_bufx < 0 || msgbuf.msg_bufx >= MSG_BSIZE) 3702172Swnj msgbuf.msg_bufx = 0; 371285Sbill } 37230549Skarels if ((flags & TOCONS) && constty == 0 && c != '\0') 37330549Skarels (*v_putc)(c); 374285Sbill } 375