Initial import of virtio rings structures.
[akaros.git] / kern / src / printf.c
1 // Simple implementation of cprintf console output for the kernel,
2 // based on printfmt() and the kernel console's cputchar().
3
4 #include <arch/arch.h>
5 #include <ros/common.h>
6
7 #include <atomic.h>
8 #include <stdio.h>
9 #include <stdarg.h>
10 #include <smp.h>
11
12 spinlock_t output_lock = SPINLOCK_INITIALIZER_IRQSAVE;
13
14 void putch(int ch, int **cnt)
15 {
16         cputchar(ch);
17         **cnt = **cnt + 1;
18 }
19
20 // buffered putch to (potentially) speed up printing.
21 // static buffer is safe because output_lock must be held.
22 // ch == -1 flushes the buffer.
23 void buffered_putch(int ch, int **cnt)
24 {
25         #define buffered_putch_bufsize 64
26         static char buf[buffered_putch_bufsize];
27         static int buflen = 0;
28
29         if(ch != -1)
30         {
31                 buf[buflen++] = ch;
32                 **cnt = **cnt + 1;
33         }
34
35         if(ch == -1 || buflen == buffered_putch_bufsize)
36         {
37                 cputbuf(buf,buflen);
38                 buflen = 0;
39         }
40 }
41
42 int vcprintf(const char *fmt, va_list ap)
43 {
44         struct per_cpu_info *pcpui;
45         extern int booting;
46         int cnt = 0;
47         int *cntp = &cnt;
48         volatile int i;
49         int8_t irq_state = 0;
50
51         /* this ktrap depth stuff is in case the kernel faults in a printfmt call.
52          * we disable the locking if we're in a fault handler so that we don't
53          * deadlock. */
54         if (booting)
55                 pcpui = &per_cpu_info[0];
56         else
57                 pcpui = &per_cpu_info[core_id()];
58         /* lock all output.  this will catch any printfs at line granularity.  when
59          * tracing, we short-circuit the main lock call, so as not to clobber the
60          * results as we print. */
61         if (!ktrap_depth(pcpui)) {
62                 #ifdef CONFIG_TRACE_LOCKS
63                 disable_irqsave(&irq_state);
64                 __spin_lock(&output_lock);
65                 #else
66                 spin_lock_irqsave(&output_lock);
67                 #endif
68         }
69
70         // do the buffered printf
71         vprintfmt((void*)buffered_putch, (void*)&cntp, fmt, ap);
72
73         // write out remaining chars in the buffer
74         buffered_putch(-1,&cntp);
75
76         if (!ktrap_depth(pcpui)) {
77                 #ifdef CONFIG_TRACE_LOCKS
78                 __spin_unlock(&output_lock);
79                 enable_irqsave(&irq_state);
80                 #else
81                 spin_unlock_irqsave(&output_lock);
82                 #endif
83         }
84
85         return cnt;
86 }
87
88 int cprintf(const char *fmt, ...)
89 {
90         va_list ap;
91         int cnt;
92
93         if (!fmt)
94                 return 0;
95
96         va_start(ap, fmt);
97         cnt = vcprintf(fmt, ap);
98         va_end(ap);
99
100         return cnt;
101 }