xv6, line by line
kernel/printk.c

kernel/printk.c

C · 152 lines · annotated 100% · kernel · upstream

About this file

The kernel’s own printf. The kernel cannot use the C library’s printf (there is no C library in a freestanding (vs. hosted) C kernel), so this file provides printk, a small formatted-output function, and panic, which prints a message and stops.

printk is a variadic function: it walks its format string and prints ordinary characters as they are, while each % directive takes the next argument and prints it as a decimal or hexadecimal number, a pointer, a character or a string. The helpers printint and printptr do the number conversions. Every character goes out through consputc in kernel/console.c, which writes it to the UART by busy-waiting, so printk never sleeps and is safe to call from anywhere in the kernel, including interrupt handlers and code holding spinlocks.

A lock, pr.lock, keeps messages from different CPUs from being mixed character by character. During a panic that lock is bypassed, and two flags, panicking and panicked, change how printing behaves across all CPUs.

(In older versions of xv6 this function was called printf, like the user-space one in user/printf.c. In this version the kernel’s is printk, the name Linux uses.)

Read before: kernel/console.c and kernel/uart.c.

1//
2// formatted console output -- printk, panic.
3//
5#include <stdarg.h>
7#include "types.h"
8#include "param.h"
9#include "spinlock.h"
11#include "fs.h"
12#include "file.h"
14#include "riscv.h"
15#include "defs.h"
16#include "proc.h"
18volatile int panicking = 0; // printing a panic message
19volatile int panicked = 0; // spinning forever at end of a panic
21// lock to avoid interleaving concurrent printk's.
22static struct {
23 struct spinlock lock;
24} pr;
26static char digits[] = "0123456789abcdef";
28static void
29printint(long long xx, int base, int sign)
31 char buf[20];
32 int i;
33 unsigned long long x;
35 if (sign && (sign = (xx < 0)))
36 x = -xx;
37 else
38 x = xx;
40 i = 0;
41 do {
42 buf[i++] = digits[x % base];
43 } while ((x /= base) != 0);
45 if (sign)
46 buf[i++] = '-';
48 while (--i >= 0)
52static void
55 int i;
56 consputc('0');
57 consputc('x');
58 for (i = 0; i < (sizeof(uint64) * 2); i++, x <<= 4)
59 consputc(digits[x >> (sizeof(uint64) * 8 - 4)]);
62// Print to the console.
63int
64printk(char *fmt, ...)
66 va_list ap;
67 int i, cx, c0, c1, c2;
68 char *s;
70 if (panicking == 0)
73 va_start(ap, fmt);
74 for (i = 0; (cx = fmt[i] & 0xff) != 0; i++) {
75 if (cx != '%') {
77 continue;
78 }
79 i++;
80 c0 = fmt[i + 0] & 0xff;
81 c1 = c2 = 0;
82 if (c0)
83 c1 = fmt[i + 1] & 0xff;
84 if (c1)
85 c2 = fmt[i + 2] & 0xff;
86 if (c0 == 'd') {
87 printint(va_arg(ap, int), 10, 1);
88 } else if (c0 == 'l' && c1 == 'd') {
89 printint(va_arg(ap, uint64), 10, 1);
90 i += 1;
91 } else if (c0 == 'l' && c1 == 'l' && c2 == 'd') {
92 printint(va_arg(ap, uint64), 10, 1);
93 i += 2;
94 } else if (c0 == 'u') {
95 printint(va_arg(ap, uint32), 10, 0);
96 } else if (c0 == 'l' && c1 == 'u') {
97 printint(va_arg(ap, uint64), 10, 0);
98 i += 1;
99 } else if (c0 == 'l' && c1 == 'l' && c2 == 'u') {
100 printint(va_arg(ap, uint64), 10, 0);
101 i += 2;
102 } else if (c0 == 'x') {
103 printint(va_arg(ap, uint32), 16, 0);
104 } else if (c0 == 'l' && c1 == 'x') {
105 printint(va_arg(ap, uint64), 16, 0);
106 i += 1;
107 } else if (c0 == 'l' && c1 == 'l' && c2 == 'x') {
108 printint(va_arg(ap, uint64), 16, 0);
109 i += 2;
110 } else if (c0 == 'p') {
111 printptr(va_arg(ap, uint64));
112 } else if (c0 == 'c') {
113 consputc(va_arg(ap, uint));
114 } else if (c0 == 's') {
115 if ((s = va_arg(ap, char *)) == 0)
116 s = "(null)";
117 for (; *s; s++)
119 } else if (c0 == '%') {
121 } else if (c0 == 0) {
122 break;
123 } else {
124 // Print unknown % sequence to draw attention.
127 }
128 }
129 va_end(ap);
131 if (panicking == 0)
134 return 0;
137void
138panic(char *s)
141 printk("panic: ");
142 printk("%s\n", s);
143 panicked = 1; // freeze uart output from other CPUs
144 for (;;)
145 ;
148void
151 initlock(&pr.lock, "pr");