| // Simple implementation of cprintf console output for the kernel, |
| // based on printfmt() and the kernel console's cputchar(). |
| |
| #ifdef __SHARC__ |
| #pragma nosharc |
| #endif |
| |
| #include <arch/arch.h> |
| #include <ros/common.h> |
| |
| #include <atomic.h> |
| #include <stdio.h> |
| #include <stdarg.h> |
| #include <smp.h> |
| |
| spinlock_t output_lock = SPINLOCK_INITIALIZER_IRQSAVE; |
| |
| void putch(int ch, int **cnt) |
| { |
| cputchar(ch); |
| **cnt = **cnt + 1; |
| } |
| |
| // buffered putch to (potentially) speed up printing. |
| // static buffer is safe because output_lock must be held. |
| // ch == -1 flushes the buffer. |
| void buffered_putch(int ch, int **cnt) |
| { |
| #define buffered_putch_bufsize 64 |
| static char LCKD(&output_lock) (RO buf)[buffered_putch_bufsize]; |
| static int LCKD(&output_lock) buflen = 0; |
| |
| if(ch != -1) |
| { |
| buf[buflen++] = ch; |
| **cnt = **cnt + 1; |
| } |
| |
| if(ch == -1 || buflen == buffered_putch_bufsize) |
| { |
| cputbuf(buf,buflen); |
| buflen = 0; |
| } |
| } |
| |
| int vcprintf(const char *fmt, va_list ap) |
| { |
| struct per_cpu_info *pcpui; |
| extern int booting; |
| int cnt = 0; |
| int *cntp = &cnt; |
| volatile int i; |
| int8_t irq_state = 0; |
| |
| /* this ktrap depth stuff is in case the kernel faults in a printfmt call. |
| * we disable the locking if we're in a fault handler so that we don't |
| * deadlock. */ |
| if (booting) |
| pcpui = &per_cpu_info[0]; |
| else |
| pcpui = &per_cpu_info[core_id()]; |
| /* lock all output. this will catch any printfs at line granularity. when |
| * tracing, we short-circuit the main lock call, so as not to clobber the |
| * results as we print. */ |
| if (!ktrap_depth(pcpui)) { |
| #ifdef CONFIG_TRACE_LOCKS |
| disable_irqsave(&irq_state); |
| __spin_lock(&output_lock); |
| #else |
| spin_lock_irqsave(&output_lock); |
| #endif |
| } |
| |
| // do the buffered printf |
| #ifdef __DEPUTY__ |
| vprintfmt(buffered_putch, &cntp, fmt, ap); |
| #else |
| vprintfmt((void*)buffered_putch, (void*)&cntp, fmt, ap); |
| #endif |
| |
| // write out remaining chars in the buffer |
| buffered_putch(-1,&cntp); |
| |
| if (!ktrap_depth(pcpui)) { |
| #ifdef CONFIG_TRACE_LOCKS |
| __spin_unlock(&output_lock); |
| enable_irqsave(&irq_state); |
| #else |
| spin_unlock_irqsave(&output_lock); |
| #endif |
| } |
| |
| return cnt; |
| } |
| |
| int cprintf(const char *fmt, ...) |
| { |
| va_list ap; |
| int cnt; |
| |
| if (!fmt) |
| return 0; |
| |
| va_start(ap, fmt); |
| cnt = vcprintf(fmt, ap); |
| va_end(ap); |
| |
| return cnt; |
| } |