|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26: /*-
27: * Copyright (c) 1986, 1988, 1991, 1993
28: * The Regents of the University of California. All rights reserved.
29: * (c) UNIX System Laboratories, Inc.
30: * All or some portions of this file are derived from material licensed
31: * to the University of California by American Telephone and Telegraph
32: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
33: * the permission of UNIX System Laboratories, Inc.
34: *
35: * Redistribution and use in source and binary forms, with or without
36: * modification, are permitted provided that the following conditions
37: * are met:
38: * 1. Redistributions of source code must retain the above copyright
39: * notice, this list of conditions and the following disclaimer.
40: * 2. Redistributions in binary form must reproduce the above copyright
41: * notice, this list of conditions and the following disclaimer in the
42: * documentation and/or other materials provided with the distribution.
43: * 3. All advertising materials mentioning features or use of this software
44: * must display the following acknowledgement:
45: * This product includes software developed by the University of
46: * California, Berkeley and its contributors.
47: * 4. Neither the name of the University nor the names of its contributors
48: * may be used to endorse or promote products derived from this software
49: * without specific prior written permission.
50: *
51: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61: * SUCH DAMAGE.
62: *
63: * @(#)subr_prf.c 8.4 (Berkeley) 5/4/95
64: */
65: /* HISTORY
66: * 22-Sep-1997 Umesh Vaishampayan ([email protected])
67: * Cleaned up m68k crud. Fixed vlog() to do logpri() for ppc, too.
68: *
69: * 17-July-97 Umesh Vaishampayan ([email protected])
70: * Eliminated multiple definition of constty which is defined
71: * in bsd/dev/XXX/cons.c
72: *
73: * 26-MAR-1997 Umesh Vaishampayan ([email protected]
74: * Fixed tharshing format in many functions. Cleanup.
75: *
76: * 17-Jun-1995 Mac Gillon (mgillon) at NeXT
77: * Purged old history
78: * New version based on 4.4 and NS3.3
79: */
80:
81: #include <cpus.h>
82: #include <cputypes.h>
83:
84: #include <sys/param.h>
85: #include <sys/systm.h>
86: #include <sys/buf.h>
87: #include <sys/conf.h>
88: #include <sys/reboot.h>
89: #include <sys/msgbuf.h>
90: #include <sys/proc.h>
91: #include <sys/ioctl.h>
92: #include <sys/tty.h>
93: #include <sys/file.h>
94: #include <sys/tprintf.h>
95: #include <sys/syslog.h>
96: #include <stdarg.h>
97: #include <sys/malloc.h>
98: #include <kern/lock.h>
99: #include <kern/parallel.h>
100: #import <sys/subr_prf.h>
101:
102: #include <machine/cpu.h> /* for cpu_number() */
103: #include <machine/spl.h>
104:
105: /*
106: * In case console is off,
107: * panicstr contains argument to last
108: * call to panic.
109: */
110: const char *panicstr;
111:
112: extern cnputc(); /* standard console putc */
113: int (*v_putc)() = cnputc; /* routine to putc on virtual console */
114:
115: extern struct tty cons; /* standard console tty */
116: extern struct tty *constty; /* pointer to console "window" tty */
117:
118: /*
119: * Record cpu that panic'd and lock around panic data
120: */
121: decl_simple_lock_data(,panic_lock)
122: int paniccpu;
123:
124: static void puts(const char *s, int flags, struct tty *ttyp);
125: static void printn(u_long n, int b, int flags, struct tty *ttyp, int zf, int fld_size);
126:
127: /* MP printf stuff */
128: decl_simple_lock_data(,printf_lock)
129: #if NCPUS > 1
130: boolean_t new_printf_cpu_number; /* do we need to output who we are */
131: #endif
132:
133: extern void logwakeup();
134: extern void halt_cpu();
135: #if NeXT
136: extern void mini_mon();
137: #endif /* NeXT */
138: extern boot();
139: int putchar();
140:
141:
142: /*
143: * Scaled down version of C Library printf.
144: * Used to print diagnostic information directly on console tty.
145: * Since it is not interrupt driven, all system activities are
146: * suspended. Printf should not be used for chit-chat.
147: *
148: * One additional format: %b is supported to decode error registers.
149: * Usage is:
150: * printf("reg=%b\n", regval, "<base><arg>*");
151: * Where <base> is the output base expressed as a control character,
152: * e.g. \10 gives octal; \20 gives hex. Each arg is a sequence of
153: * characters, the first of which gives the bit number to be inspected
154: * (origin 1), and the next characters (up to a control character, i.e.
155: * a character <= 32), give the name of the register. Thus
156: * printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
157: * would produce output:
158: * reg=3<BITTWO,BITONE>
159: *
160: */
161:
162: void printf(const char *format, ...)
163: {
164: va_list ap;
165:
166: va_start(ap, format);
167: prf(format, ap, TOCONS | TOLOG, (struct tty *)0);
168: va_end(ap);
169:
170: if (!panicstr)
171: logwakeup();
172: }
173:
174: int sprintf(char *s, const char *format, ...)
175: {
176: char *sptr = s;
177: char *s0 = s;
178: va_list ap;
179:
180: va_start(ap, format);
181: prf(format, ap, TOSTR, (struct tty *)&sptr);
182: va_end(ap);
183: *sptr = 0;
184: return sptr - s0;
185: }
186:
187: /*
188: * Uprintf prints to the controlling terminal for the current process.
189: * It may block if the tty queue is overfull. No message is printed if
190: * the queue does not clear in a reasonable time.
191: */
192: void
193: uprintf(const char *fmt, ...)
194: {
195: register struct proc *p = current_proc();
196: va_list ap;
197:
198: unix_master(); /* sessions, sigh */
199: if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
200: va_start(ap, fmt);
201: prf(fmt, ap, TOTTY, (struct tty *)p->p_session->s_ttyvp);
202: va_end(ap);
203: }
204: unix_release();
205: }
206:
207: tpr_t
208: tprintf_open(p)
209: register struct proc *p;
210: {
211: unix_master(); /* sessions, sigh */
212: if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
213: SESSHOLD(p->p_session);
214: unix_release();
215: return ((tpr_t) p->p_session);
216: }
217: unix_release();
218: return ((tpr_t) NULL);
219: }
220:
221: void
222: tprintf_close(sess)
223: tpr_t sess;
224: {
225: unix_master(); /* sessions, sigh */
226: if (sess)
227: SESSRELE((struct session *) sess);
228: unix_release();
229: }
230:
231: /*
232: * tprintf prints on the controlling terminal associated
233: * with the given session.
234: */
235: void
236: tprintf(tpr_t tpr, const char *fmt, ...)
237: {
238: register struct session *sess = (struct session *)tpr;
239: struct tty *tp = NULL;
240: int flags = TOLOG;
241: va_list ap;
242:
243: logpri(LOG_INFO);
244: unix_master(); /* sessions, sigh */
245: if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
246: flags |= TOTTY;
247: tp = sess->s_ttyp;
248: }
249: if (tp != NULL) {
250: va_start(ap, fmt);
251: prf(fmt, ap, TOTTY, tp);
252: va_end(ap);
253: }
254: unix_release();
255: logwakeup();
256: }
257:
258: /*
259: * Ttyprintf displays a message on a tty; it should be used only by
260: * the tty driver, or anything that knows the underlying tty will not
261: * be revoke(2)'d away. Other callers should use tprintf.
262: */
263: void
264: ttyprintf(struct tty *tp, const char *fmt, ...)
265: {
266: va_list ap;
267:
268: if (tp != NULL) {
269: va_start(ap, fmt);
270: prf(fmt, ap, TOTTY, tp);
271: va_end(ap);
272: }
273: }
274:
275: extern int log_open;
276:
277: /*
278: * Log writes to the log buffer,
279: * and guarantees not to sleep (so can be called by interrupt routines).
280: * If there is no process reading the log yet, it writes to the console also.
281: */
282: void
283: log(int level, const char *fmt, ...)
284: {
285: extern void vlog();
286: va_list ap;
287:
288: va_start(ap, fmt);
289: vlog(level, fmt, ap);
290: va_end(ap);
291: }
292:
293: /*
294: * driverkit needs vlog to be called from IOLog
295: */
296: void
297: vlog(int level, const char *fmt, va_list ap)
298: {
299: register s = splhigh();
300:
301: #if !NeXT
302: logpri(level);
303: #endif
304: prf(fmt, ap, TOLOG, (struct tty *)0);
305: splx(s);
306: if (!log_open)
307: prf(fmt, ap, TOCONS, (struct tty *)0);
308: logwakeup();
309: }
310:
311: void
312: logpri(level)
313: int level;
314: {
315:
316: putchar('<', TOLOG, (struct tty *)0);
317: printn((u_long)level, 10, TOLOG, (struct tty *)0, 0, 0);
318: putchar('>', TOLOG, (struct tty *)0);
319: }
320:
321: void
322: addlog(const char *fmt, ...)
323: {
324: register s = splhigh();
325: va_list ap;
326:
327: va_start(ap, fmt);
328: prf(fmt, ap, TOLOG, (struct tty *)0);
329: splx(s);
330: if (!log_open)
331: prf(fmt, ap, TOCONS, (struct tty *)0);
332: va_end(ap);
333: logwakeup();
334: }
335: #warning pulled in from mksparc check encumbered or not
336: void _printf(int flags, struct tty *ttyp, const char *format, ...)
337: {
338: va_list ap;
339:
340: va_start(ap, format);
341: prf(format, ap, flags, ttyp);
342: va_end(ap);
343: }
344:
345: int prf(const char *fmt, va_list ap, int flags, struct tty *ttyp)
346: {
347: register int b, c, i;
348: char *s;
349: int any;
350: int zf = 0, fld_size;
351:
352: #if NCPUS > 1
353: int cpun = cpu_number();
354:
355: if(ttyp == 0) {
356: simple_lock(&printf_lock);
357: } else
358: TTY_LOCK(ttyp);
359:
360: if (cpun != master_cpu)
361: new_printf_cpu_number = TRUE;
362:
363: if (new_printf_cpu_number) {
364: putchar('{', flags, ttyp);
365: printn((u_long)cpun, 10, flags, ttyp, 0, 0);
366: putchar('}', flags, ttyp);
367: }
368: #endif /* NCPUS > 1 */
369: loop:
370: while ((c = *fmt++) != '%') {
371: if (c == '\0') {
372: #if NCPUS > 1
373: if(ttyp == 0) {
374: simple_unlock(&printf_lock);
375: } else
376: TTY_UNLOCK(ttyp);
377: #endif
378: return 0;
379: }
380: putchar(c, flags, ttyp);
381: }
382: again:
383: zf = 0;
384: fld_size = 0;
385: c = *fmt++;
386: if (c == '0')
387: zf = '0';
388: fld_size = 0;
389: for (;c <= '9' && c >= '0'; c = *fmt++)
390: fld_size = fld_size * 10 + c - '0';
391:
392: /* THIS CODE IS VAX DEPENDENT IN HANDLING %l? AND %c */
393: switch (c) {
394:
395: case 'l':
396: goto again;
397: case 'x': case 'X':
398: b = 16;
399: goto number;
400: case 'd': case 'D':
401: case 'u': /* what a joke */
402: b = 10;
403: goto number;
404: case 'o': case 'O':
405: b = 8;
406: number:
407: printn(va_arg(ap, unsigned), b, flags, ttyp, zf, fld_size);
408: break;
409: case 'c':
410: b = va_arg(ap, unsigned);
411: #if BYTE_ORDER == LITTLE_ENDIAN
412: for (i = 24; i >= 0; i -= 8)
413: if (c = (b >> i) & 0x7f)
414: putchar(c, flags, ttyp);
415: #endif
416: #if BYTE_ORDER == BIG_ENDIAN
417: if ((c = (b & 0x7f)))
418: putchar(c, flags, ttyp);
419: #endif
420: break;
421: case 'b':
422: b = va_arg(ap, unsigned);
423: s = va_arg(ap, char *);
424: printn((u_long)b, *s++, flags, ttyp, 0, 0);
425: any = 0;
426: if (b) {
427: while ((i = *s++)) {
428: if (*s <= 32) {
429: register int j;
430:
431: if (any++)
432: putchar(',', flags, ttyp);
433: j = *s++ ;
434: for (; (c = *s) > 32 ; s++)
435: putchar(c, flags, ttyp);
436: printn( (u_long)( (b >> (j-1)) &
437: ( (2 << (i-j)) -1)),
438: 8, flags, ttyp, 0, 0);
439: } else if (b & (1 << (i-1))) {
440: putchar(any? ',' : '<', flags, ttyp);
441: any = 1;
442: for (; (c = *s) > 32; s++)
443: putchar(c, flags, ttyp);
444: } else
445: for (; *s > 32; s++)
446: ;
447: }
448: putchar('>', flags, ttyp);
449: }
450: break;
451:
452: case 's':
453: s = va_arg(ap, char *);
454: #ifdef DEBUG
455: if (fld_size) {
456: while (fld_size-- > 0)
457: putchar((c = *s++)? c : '_', flags, ttyp);
458: } else {
459: while ((c = *s++))
460: putchar(c, flags, ttyp);
461: }
462: #else
463: while (c = *s++)
464: putchar(c, flags, ttyp);
465: #endif
466: break;
467:
468: case '%':
469: putchar('%', flags, ttyp);
470: goto loop;
471: case 'C':
472: b = va_arg(ap, unsigned);
473: #if BYTE_ORDER == LITTLE_ENDIAN
474: for (i = 24; i >= 0; i -= 8)
475: if (c = (b >> i) & 0x7f)
476: putchar(c, flags, ttyp);
477: #endif
478: #if BYTE_ORDER == BIG_ENDIAN
479: if ((c = (b & 0x7f)))
480: putchar(c, flags, ttyp);
481: #endif
482:
483: case 'r':
484: case 'R':
485: b = va_arg(ap, unsigned);
486: s = va_arg(ap, char *);
487: if (c == 'R') {
488: puts("0x", flags, ttyp);
489: printn((u_long)b, 16, flags, ttyp, 0, 0);
490: }
491: any = 0;
492: if (c == 'r' || b) {
493: register struct reg_desc *rd;
494: register struct reg_values *rv;
495: unsigned field;
496:
497: putchar('<', flags, ttyp);
498: for (rd = (struct reg_desc *)s; rd->rd_mask; rd++) {
499: field = b & rd->rd_mask;
500: field = (rd->rd_shift > 0)
501: ? field << rd->rd_shift
502: : field >> -rd->rd_shift;
503: if (any &&
504: (rd->rd_format || rd->rd_values
505: || (rd->rd_name && field)
506: )
507: )
508: putchar(',', flags, ttyp);
509: if (rd->rd_name) {
510: if (rd->rd_format || rd->rd_values
511: || field) {
512: puts(rd->rd_name, flags, ttyp);
513: any = 1;
514: }
515: if (rd->rd_format || rd->rd_values) {
516: putchar('=', flags, ttyp);
517: any = 1;
518: }
519: }
520: if (rd->rd_format) {
521: _printf(flags, ttyp, rd->rd_format,
522: field);
523: any = 1;
524: if (rd->rd_values)
525: putchar(':', flags, ttyp);
526: }
527: if (rd->rd_values) {
528: any = 1;
529: for (rv = rd->rd_values;
530: rv->rv_name;
531: rv++) {
532: if (field == rv->rv_value) {
533: puts(rv->rv_name, flags,
534: ttyp);
535: break;
536: }
537: }
538: if (rv->rv_name == NULL)
539: puts("???", flags, ttyp);
540: }
541: }
542: putchar('>', flags, ttyp);
543: }
544: break;
545:
546: case 'n':
547: case 'N':
548: {
549: register struct reg_values *rv;
550:
551: b = va_arg(ap, unsigned);
552: s = va_arg(ap,char *);
553: for (rv = (struct reg_values *)s; rv->rv_name; rv++) {
554: if (b == rv->rv_value) {
555: puts(rv->rv_name, flags, ttyp);
556: break;
557: }
558: }
559: if (rv->rv_name == NULL)
560: puts("???", flags, ttyp);
561: if (c == 'N' || rv->rv_name == NULL) {
562: putchar(':', flags, ttyp);
563: printn((u_long)b, 10, flags, ttyp, 0, 0);
564: }
565: }
566: break;
567: }
568: goto loop;
569: }
570:
571: static void puts(const char *s, int flags, struct tty *ttyp)
572: {
573: register char c;
574:
575: while ((c = *s++))
576: putchar(c, flags, ttyp);
577: }
578:
579: /*
580: * Printn prints a number n in base b.
581: * We don't use recursion to avoid deep kernel stacks.
582: */
583: static void printn(u_long n, int b, int flags, struct tty *ttyp, int zf, int fld_size)
584: {
585: char prbuf[11];
586: register char *cp;
587:
588: if (b == 10 && (int)n < 0) {
589: putchar('-', flags, ttyp);
590: n = (unsigned)(-(int)n);
591: }
592: cp = prbuf;
593: do {
594: *cp++ = "0123456789abcdef"[n%b];
595: n /= b;
596: } while (n);
597: if (fld_size) {
598: for (fld_size -= cp - prbuf; fld_size > 0; fld_size--)
599: if (zf)
600: putchar('0', flags, ttyp);
601: else
602: putchar(' ', flags, ttyp);
603: }
604: do
605: putchar(*--cp, flags, ttyp);
606: while (cp > prbuf);
607: }
608:
609: void panic_init()
610: {
611: simple_lock_init(&panic_lock);
612: }
613:
614: /*
615: * Panic is called on unresolvable fatal errors. It prints "panic: mesg",
616: * and then reboots. If we are called twice, then we avoid trying to sync
617: * the disks as this often leads to recursive panics.
618: */
619: #ifdef __GNUC__
620: volatile
621: #endif
622: void
623: panic(const char *fmt, ...)
624: {
625: #if MACH_LDEBUG
626: extern int mach_ldebug;
627: #endif /* MACH_LDEBUG */
628: int bootopt;
629: va_list ap;
630: char buffer[256];
631:
632: simple_lock(&panic_lock);
633: bootopt = RB_AUTOBOOT;
634: if (panicstr) {
635: if (cpu_number() == paniccpu) {
636: bootopt |= RB_NOSYNC;
637: } else {
638: simple_unlock(&panic_lock);
639: halt_cpu();
640: /* NOTREACHED */
641: }
642: } else {
643: panicstr = fmt;
644: paniccpu = cpu_number();
645: }
646:
647: simple_unlock(&panic_lock);
648:
649: #if MACH_LDEBUG
650: mach_ldebug = 0; // turn off simple lock debugging.
651: #endif /* MACH_LDEBUG */
652:
653: va_start(ap, fmt);
654: sprintf(buffer, "panic: %s", fmt);
655: prf(buffer, ap, TOCONS, (struct tty *)0);
656: va_end(ap);
657:
658: #if NeXT
659: if( panicstr == fmt) {
660: // make panicstr for minimon
661: char * strOut = buffer;
662: va_start(ap, fmt);
663: prf(fmt, ap, TOSTR, (struct tty *)&strOut );
664: va_end(ap);
665: *strOut = 0;
666: panicstr = buffer;
667: }
668: mini_mon ("panic", "System Panic", current_thread()->pcb);
669: #endif /* NeXT */
670: boot(RB_PANIC, bootopt, "");
671: }
672:
673: /*
674: * Warn that a system table is full.
675: */
676: void tablefull(const char *tab)
677: {
678: log(LOG_ERR, "%s: table is full\n", tab);
679: }
680:
681: /*
682: * Hard error is the preface to plaintive error messages
683: * about failing disk transfers.
684: */
685: void harderr(struct buf *bp, const char *cp)
686: {
687:
688: printf("%s%d%c: hard error sn%d ", cp,
689: minor(bp->b_dev) >> 3, 'a'+(minor(bp->b_dev)&07), bp->b_blkno);
690: }
691:
692: /*
693: * Print a character on console or users terminal.
694: * If destination is console then the last MSGBUFS characters
695: * are saved in msgbuf for inspection later.
696: */
697: /*ARGSUSED*/
698: int
699: putchar(c, flags, tp)
700: register int c;
701: struct tty *tp;
702: {
703: register struct msgbuf *mbp;
704: char **sp = (char**) tp;
705:
706: if (panicstr)
707: constty = 0;
708: if ((flags & TOCONS) && tp == NULL && constty) {
709: tp = constty;
710: flags |= TOTTY;
711: }
712: if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
713: (flags & TOCONS) && tp == constty)
714: constty = 0;
715: if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177) {
716: mbp = msgbufp;
717: if (mbp-> msg_magic != MSG_MAGIC) {
718: register int i;
719:
720: mbp->msg_magic = MSG_MAGIC;
721: mbp->msg_bufx = mbp->msg_bufr = 0;
722: for (i=0; i < MSG_BSIZE; i++)
723: mbp->msg_bufc[i] = 0;
724: }
725: mbp->msg_bufc[mbp->msg_bufx++] = c;
726: if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
727: mbp->msg_bufx = 0;
728: }
729: if ((flags & TOCONS) && constty == 0 && c != '\0')
730: (*v_putc)(c);
731: if (flags & TOSTR) {
732: **sp = c;
733: (*sp)++;
734: }
735: return 0;
736: }
737:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.