1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include <linux/kernel.h>
20#include <linux/mm.h>
21#include <linux/tty.h>
22#include <linux/tty_driver.h>
23#include <linux/smp_lock.h>
24#include <linux/console.h>
25#include <linux/init.h>
26#include <linux/module.h>
27#include <linux/interrupt.h>
28#include <linux/config.h>
29#include <linux/delay.h>
30#include <linux/smp.h>
31#include <linux/security.h>
32#include <linux/bootmem.h>
33
34#include <asm/uaccess.h>
35
36#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
37
38
39#define DEFAULT_MESSAGE_LOGLEVEL 4
40
41
42#define MINIMUM_CONSOLE_LOGLEVEL 1
43#define DEFAULT_CONSOLE_LOGLEVEL 7
44
45DECLARE_WAIT_QUEUE_HEAD(log_wait);
46
47int console_printk[4] = {
48 DEFAULT_CONSOLE_LOGLEVEL,
49 DEFAULT_MESSAGE_LOGLEVEL,
50 MINIMUM_CONSOLE_LOGLEVEL,
51 DEFAULT_CONSOLE_LOGLEVEL,
52};
53
54EXPORT_SYMBOL(console_printk);
55
56int oops_in_progress;
57
58
59
60
61
62
63static DECLARE_MUTEX(console_sem);
64struct console *console_drivers;
65
66
67
68
69
70
71
72
73static int console_locked;
74
75
76
77
78
79
80static spinlock_t logbuf_lock = SPIN_LOCK_UNLOCKED;
81
82static char __log_buf[__LOG_BUF_LEN];
83static char *log_buf = __log_buf;
84static int log_buf_len = __LOG_BUF_LEN;
85
86#define LOG_BUF_MASK (log_buf_len-1)
87#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
88
89
90
91
92
93static unsigned long log_start;
94static unsigned long con_start;
95static unsigned long log_end;
96static unsigned long logged_chars;
97
98
99
100
101struct console_cmdline
102{
103 char name[8];
104 int index;
105 char *options;
106};
107
108#define MAX_CMDLINECONSOLES 8
109
110static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
111static int preferred_console = -1;
112
113
114static int console_may_schedule;
115
116
117
118
119static int __init console_setup(char *str)
120{
121 char name[sizeof(console_cmdline[0].name)];
122 char *s, *options;
123 int idx;
124
125
126
127
128 if (str[0] >= '0' && str[0] <= '9') {
129 strcpy(name, "ttyS");
130 strncpy(name + 4, str, sizeof(name) - 5);
131 } else
132 strncpy(name, str, sizeof(name) - 1);
133 name[sizeof(name) - 1] = 0;
134 if ((options = strchr(str, ',')) != NULL)
135 *(options++) = 0;
136#ifdef __sparc__
137 if (!strcmp(str, "ttya"))
138 strcpy(name, "ttyS0");
139 if (!strcmp(str, "ttyb"))
140 strcpy(name, "ttyS1");
141#endif
142 for(s = name; *s; s++)
143 if (*s >= '0' && *s <= '9')
144 break;
145 idx = simple_strtoul(s, NULL, 10);
146 *s = 0;
147
148 add_preferred_console(name, idx, options);
149 return 1;
150}
151
152__setup("console=", console_setup);
153
154
155
156
157
158
159
160
161
162
163
164int __init add_preferred_console(char *name, int idx, char *options)
165{
166 struct console_cmdline *c;
167 int i;
168
169
170
171
172
173 for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
174 if (strcmp(console_cmdline[i].name, name) == 0 &&
175 console_cmdline[i].index == idx) {
176 preferred_console = i;
177 return 0;
178 }
179 if (i == MAX_CMDLINECONSOLES)
180 return -E2BIG;
181 preferred_console = i;
182 c = &console_cmdline[i];
183 memcpy(c->name, name, sizeof(c->name));
184 c->name[sizeof(c->name) - 1] = 0;
185 c->options = options;
186 c->index = idx;
187 return 0;
188}
189
190static int __init log_buf_len_setup(char *str)
191{
192 unsigned long size = memparse(str, &str);
193 unsigned long flags;
194
195 if (size)
196 size = roundup_pow_of_two(size);
197 if (size > log_buf_len) {
198 unsigned long start, dest_idx, offset;
199 char * new_log_buf;
200
201 new_log_buf = alloc_bootmem(size);
202 if (!new_log_buf) {
203 printk("log_buf_len: allocation failed\n");
204 goto out;
205 }
206
207 spin_lock_irqsave(&logbuf_lock, flags);
208 log_buf_len = size;
209 log_buf = new_log_buf;
210
211 offset = start = min(con_start, log_start);
212 dest_idx = 0;
213 while (start != log_end) {
214 log_buf[dest_idx] = __log_buf[start & (__LOG_BUF_LEN - 1)];
215 start++;
216 dest_idx++;
217 }
218 log_start -= offset;
219 con_start -= offset;
220 log_end -= offset;
221 spin_unlock_irqrestore(&logbuf_lock, flags);
222
223 printk("log_buf_len: %d\n", log_buf_len);
224 }
225out:
226
227 return 1;
228}
229
230__setup("log_buf_len=", log_buf_len_setup);
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247int do_syslog(int type, char __user * buf, int len)
248{
249 unsigned long i, j, limit, count;
250 int do_clear = 0;
251 char c;
252 int error = 0;
253
254 error = security_syslog(type);
255 if (error)
256 return error;
257
258 switch (type) {
259 case 0:
260 break;
261 case 1:
262 break;
263 case 2:
264 error = -EINVAL;
265 if (!buf || len < 0)
266 goto out;
267 error = 0;
268 if (!len)
269 goto out;
270 error = verify_area(VERIFY_WRITE,buf,len);
271 if (error)
272 goto out;
273 error = wait_event_interruptible(log_wait, (log_start - log_end));
274 if (error)
275 goto out;
276 i = 0;
277 spin_lock_irq(&logbuf_lock);
278 while (!error && (log_start != log_end) && i < len) {
279 c = LOG_BUF(log_start);
280 log_start++;
281 spin_unlock_irq(&logbuf_lock);
282 error = __put_user(c,buf);
283 buf++;
284 i++;
285 cond_resched();
286 spin_lock_irq(&logbuf_lock);
287 }
288 spin_unlock_irq(&logbuf_lock);
289 if (!error)
290 error = i;
291 break;
292 case 4:
293 do_clear = 1;
294
295 case 3:
296 error = -EINVAL;
297 if (!buf || len < 0)
298 goto out;
299 error = 0;
300 if (!len)
301 goto out;
302 error = verify_area(VERIFY_WRITE,buf,len);
303 if (error)
304 goto out;
305 count = len;
306 if (count > log_buf_len)
307 count = log_buf_len;
308 spin_lock_irq(&logbuf_lock);
309 if (count > logged_chars)
310 count = logged_chars;
311 if (do_clear)
312 logged_chars = 0;
313 limit = log_end;
314
315
316
317
318
319
320 for(i = 0; i < count && !error; i++) {
321 j = limit-1-i;
322 if (j + log_buf_len < log_end)
323 break;
324 c = LOG_BUF(j);
325 spin_unlock_irq(&logbuf_lock);
326 error = __put_user(c,&buf[count-1-i]);
327 cond_resched();
328 spin_lock_irq(&logbuf_lock);
329 }
330 spin_unlock_irq(&logbuf_lock);
331 if (error)
332 break;
333 error = i;
334 if(i != count) {
335 int offset = count-error;
336
337 for(i=0;i<error;i++) {
338 if (__get_user(c,&buf[i+offset]) ||
339 __put_user(c,&buf[i])) {
340 error = -EFAULT;
341 break;
342 }
343 cond_resched();
344 }
345 }
346 break;
347 case 5:
348 logged_chars = 0;
349 break;
350 case 6:
351 console_loglevel = minimum_console_loglevel;
352 break;
353 case 7:
354 console_loglevel = default_console_loglevel;
355 break;
356 case 8:
357 error = -EINVAL;
358 if (len < 1 || len > 8)
359 goto out;
360 if (len < minimum_console_loglevel)
361 len = minimum_console_loglevel;
362 console_loglevel = len;
363 error = 0;
364 break;
365 case 9:
366 error = log_end - log_start;
367 break;
368 case 10:
369 error = log_buf_len;
370 break;
371 default:
372 error = -EINVAL;
373 break;
374 }
375out:
376 return error;
377}
378
379asmlinkage long sys_syslog(int type, char __user * buf, int len)
380{
381 return do_syslog(type, buf, len);
382}
383
384
385
386
387
388static void crashdump_call_console_drivers(const char *buf, unsigned long len)
389{
390 struct console *con;
391
392 for (con = console_drivers; con; con = con->next) {
393 if ((con->flags & CON_ENABLED) && con->write)
394 con->write(con, buf, len);
395 }
396}
397
398
399
400
401static void __call_console_drivers(unsigned long start, unsigned long end)
402{
403 struct console *con;
404
405 for (con = console_drivers; con; con = con->next) {
406 if ((con->flags & CON_ENABLED) && con->write)
407 con->write(con, &LOG_BUF(start), end - start);
408 }
409}
410
411
412
413
414static void _call_console_drivers(unsigned long start,
415 unsigned long end, int msg_log_level)
416{
417 if (msg_log_level < console_loglevel &&
418 console_drivers && start != end) {
419 if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {
420
421 __call_console_drivers(start & LOG_BUF_MASK,
422 log_buf_len);
423 __call_console_drivers(0, end & LOG_BUF_MASK);
424 } else {
425 __call_console_drivers(start, end);
426 }
427 }
428}
429
430
431
432
433
434
435static void call_console_drivers(unsigned long start, unsigned long end)
436{
437 unsigned long cur_index, start_print;
438 static int msg_level = -1;
439
440 if (((long)(start - end)) > 0)
441 BUG();
442
443 cur_index = start;
444 start_print = start;
445 while (cur_index != end) {
446 if ( msg_level < 0 &&
447 ((end - cur_index) > 2) &&
448 LOG_BUF(cur_index + 0) == '<' &&
449 LOG_BUF(cur_index + 1) >= '0' &&
450 LOG_BUF(cur_index + 1) <= '7' &&
451 LOG_BUF(cur_index + 2) == '>')
452 {
453 msg_level = LOG_BUF(cur_index + 1) - '0';
454 cur_index += 3;
455 start_print = cur_index;
456 }
457 while (cur_index != end) {
458 char c = LOG_BUF(cur_index);
459 cur_index++;
460
461 if (c == '\n') {
462 if (msg_level < 0) {
463
464
465
466
467
468
469 msg_level = default_message_loglevel;
470 }
471 _call_console_drivers(start_print, cur_index, msg_level);
472 msg_level = -1;
473 start_print = cur_index;
474 break;
475 }
476 }
477 }
478 _call_console_drivers(start_print, end, msg_level);
479}
480
481static void emit_log_char(char c)
482{
483 LOG_BUF(log_end) = c;
484 log_end++;
485 if (log_end - log_start > log_buf_len)
486 log_start = log_end - log_buf_len;
487 if (log_end - con_start > log_buf_len)
488 con_start = log_end - log_buf_len;
489 if (logged_chars < log_buf_len)
490 logged_chars++;
491}
492
493
494
495
496
497
498static void zap_locks(void)
499{
500 static unsigned long oops_timestamp;
501
502 if (time_after_eq(jiffies, oops_timestamp) &&
503 !time_after(jiffies, oops_timestamp + 30*HZ))
504 return;
505
506 oops_timestamp = jiffies;
507
508
509 spin_lock_init(&logbuf_lock);
510
511 init_MUTEX(&console_sem);
512}
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527asmlinkage int printk(const char *fmt, ...)
528{
529 va_list args;
530 int r;
531
532 va_start(args, fmt);
533 r = vprintk(fmt, args);
534 va_end(args);
535
536 return r;
537}
538
539asmlinkage int vprintk(const char *fmt, va_list args)
540{
541 unsigned long flags;
542 int printed_len;
543 char *p;
544 static char printk_buf[1024];
545 static int log_level_unknown = 1;
546
547 if (unlikely(oops_in_progress))
548 zap_locks();
549
550
551 spin_lock_irqsave(&logbuf_lock, flags);
552
553
554 printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
555
556 if (unlikely(crashdump_mode())) {
557 crashdump_call_console_drivers(printk_buf, printed_len);
558 spin_unlock_irqrestore(&logbuf_lock, flags);
559 goto out;
560 }
561
562
563
564
565
566 for (p = printk_buf; *p; p++) {
567 if (log_level_unknown) {
568 if (p[0] != '<' || p[1] < '0' || p[1] > '7' || p[2] != '>') {
569 emit_log_char('<');
570 emit_log_char(default_message_loglevel + '0');
571 emit_log_char('>');
572 }
573 log_level_unknown = 0;
574 }
575 emit_log_char(*p);
576 if (*p == '\n')
577 log_level_unknown = 1;
578 }
579
580 if (!cpu_online(smp_processor_id()) &&
581 system_state != SYSTEM_RUNNING) {
582
583
584
585
586
587
588 spin_unlock_irqrestore(&logbuf_lock, flags);
589 goto out;
590 }
591 if (!down_trylock(&console_sem)) {
592 console_locked = 1;
593
594
595
596
597 spin_unlock_irqrestore(&logbuf_lock, flags);
598 console_may_schedule = 0;
599 release_console_sem();
600 } else {
601
602
603
604
605
606 spin_unlock_irqrestore(&logbuf_lock, flags);
607 }
608out:
609 return printed_len;
610}
611EXPORT_SYMBOL(printk);
612EXPORT_SYMBOL(vprintk);
613
614
615
616
617
618
619
620
621
622void acquire_console_sem(void)
623{
624 if (in_interrupt())
625 BUG();
626 down(&console_sem);
627 console_locked = 1;
628 console_may_schedule = 1;
629}
630EXPORT_SYMBOL(acquire_console_sem);
631
632int is_console_locked(void)
633{
634 return console_locked;
635}
636EXPORT_SYMBOL(is_console_locked);
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652void release_console_sem(void)
653{
654 unsigned long flags;
655 unsigned long _con_start, _log_end;
656 unsigned long wake_klogd = 0;
657
658 for ( ; ; ) {
659 spin_lock_irqsave(&logbuf_lock, flags);
660 wake_klogd |= log_start - log_end;
661 if (con_start == log_end)
662 break;
663 _con_start = con_start;
664 _log_end = log_end;
665 con_start = log_end;
666 spin_unlock_irqrestore(&logbuf_lock, flags);
667 call_console_drivers(_con_start, _log_end);
668 }
669 console_locked = 0;
670 console_may_schedule = 0;
671 up(&console_sem);
672 spin_unlock_irqrestore(&logbuf_lock, flags);
673 if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait))
674 wake_up_interruptible(&log_wait);
675}
676EXPORT_SYMBOL(release_console_sem);
677
678
679
680
681
682
683
684
685
686void console_conditional_schedule(void)
687{
688 if (console_may_schedule && need_resched()) {
689 set_current_state(TASK_RUNNING);
690 schedule();
691 }
692}
693EXPORT_SYMBOL(console_conditional_schedule);
694
695void console_print(const char *s)
696{
697 printk(KERN_EMERG "%s", s);
698}
699EXPORT_SYMBOL(console_print);
700
701void console_unblank(void)
702{
703 struct console *c;
704
705
706
707
708
709
710 if (down_trylock(&console_sem) != 0)
711 return;
712 console_locked = 1;
713 console_may_schedule = 0;
714 for (c = console_drivers; c != NULL; c = c->next)
715 if ((c->flags & CON_ENABLED) && c->unblank)
716 c->unblank();
717 release_console_sem();
718}
719EXPORT_SYMBOL(console_unblank);
720
721
722
723
724struct tty_driver *console_device(int *index)
725{
726 struct console *c;
727 struct tty_driver *driver = NULL;
728
729 acquire_console_sem();
730 for (c = console_drivers; c != NULL; c = c->next) {
731 if (!c->device)
732 continue;
733 driver = c->device(c, index);
734 if (driver)
735 break;
736 }
737 release_console_sem();
738 return driver;
739}
740
741
742
743
744
745
746void console_stop(struct console *console)
747{
748 acquire_console_sem();
749 console->flags &= ~CON_ENABLED;
750 release_console_sem();
751}
752EXPORT_SYMBOL(console_stop);
753
754void console_start(struct console *console)
755{
756 acquire_console_sem();
757 console->flags |= CON_ENABLED;
758 release_console_sem();
759}
760EXPORT_SYMBOL(console_start);
761
762
763
764
765
766
767
768void register_console(struct console * console)
769{
770 int i;
771 unsigned long flags;
772
773
774
775
776
777
778 if (preferred_console < 0) {
779 if (console->index < 0)
780 console->index = 0;
781 if (console->setup == NULL ||
782 console->setup(console, NULL) == 0) {
783 console->flags |= CON_ENABLED | CON_CONSDEV;
784 preferred_console = 0;
785 }
786 }
787
788
789
790
791
792 for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) {
793 if (strcmp(console_cmdline[i].name, console->name) != 0)
794 continue;
795 if (console->index >= 0 &&
796 console->index != console_cmdline[i].index)
797 continue;
798 if (console->index < 0)
799 console->index = console_cmdline[i].index;
800 if (console->setup &&
801 console->setup(console, console_cmdline[i].options) != 0)
802 break;
803 console->flags |= CON_ENABLED;
804 console->index = console_cmdline[i].index;
805 if (i == preferred_console)
806 console->flags |= CON_CONSDEV;
807 break;
808 }
809
810 if (!(console->flags & CON_ENABLED))
811 return;
812
813
814
815
816
817 acquire_console_sem();
818 if ((console->flags & CON_CONSDEV) || console_drivers == NULL) {
819 console->next = console_drivers;
820 console_drivers = console;
821 } else {
822 console->next = console_drivers->next;
823 console_drivers->next = console;
824 }
825 if (console->flags & CON_PRINTBUFFER) {
826
827
828
829
830 spin_lock_irqsave(&logbuf_lock, flags);
831 con_start = log_start;
832 spin_unlock_irqrestore(&logbuf_lock, flags);
833 }
834 release_console_sem();
835}
836EXPORT_SYMBOL(register_console);
837
838int unregister_console(struct console * console)
839{
840 struct console *a,*b;
841 int res = 1;
842
843 acquire_console_sem();
844 if (console_drivers == console) {
845 console_drivers=console->next;
846 res = 0;
847 } else {
848 for (a=console_drivers->next, b=console_drivers ;
849 a; b=a, a=b->next) {
850 if (a == console) {
851 b->next = a->next;
852 res = 0;
853 break;
854 }
855 }
856 }
857
858
859
860
861
862 if (console_drivers == NULL)
863 preferred_console = -1;
864
865
866 release_console_sem();
867 return res;
868}
869EXPORT_SYMBOL(unregister_console);
870
871
872
873
874
875
876
877
878void tty_write_message(struct tty_struct *tty, char *msg)
879{
880 if (tty && tty->driver->write)
881 tty->driver->write(tty, 0, msg, strlen(msg));
882 return;
883}
884
885
886
887
888
889
890
891
892int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst)
893{
894 static spinlock_t ratelimit_lock = SPIN_LOCK_UNLOCKED;
895 static unsigned long toks = 10*5*HZ;
896 static unsigned long last_msg;
897 static int missed;
898 unsigned long flags;
899 unsigned long now = jiffies;
900
901 spin_lock_irqsave(&ratelimit_lock, flags);
902 toks += now - last_msg;
903 last_msg = now;
904 if (toks > (ratelimit_burst * ratelimit_jiffies))
905 toks = ratelimit_burst * ratelimit_jiffies;
906 if (toks >= ratelimit_jiffies) {
907 int lost = missed;
908 missed = 0;
909 toks -= ratelimit_jiffies;
910 spin_unlock_irqrestore(&ratelimit_lock, flags);
911 if (lost)
912 printk(KERN_WARNING "printk: %d messages suppressed.\n", lost);
913 return 1;
914 }
915 missed++;
916 spin_unlock_irqrestore(&ratelimit_lock, flags);
917 return 0;
918}
919EXPORT_SYMBOL(__printk_ratelimit);
920
921
922int printk_ratelimit_jiffies = 5*HZ;
923
924
925int printk_ratelimit_burst = 10;
926
927int printk_ratelimit(void)
928{
929 return __printk_ratelimit(printk_ratelimit_jiffies,
930 printk_ratelimit_burst);
931}
932EXPORT_SYMBOL(printk_ratelimit);
933