// // formatted console output -- printf, panic. // // TODO Printf to not use mul/div/mod and all that and send stuff to hw-implemented UART #include #include "types.h" #include "param.h" #include "spinlock.h" #include "sleeplock.h" #include "fs.h" #include "file.h" #include "memlayout.h" #include "riscv.h" #include "defs.h" #include "proc.h" volatile int panicked = 0; // lock to avoid interleaving concurrent printf's. static struct { struct spinlock lock; int locking; } pr; static char digits[] = "0123456789abcdef"; int mul(int x, int y) { int ret = x; for (int tmp = y-1; tmp > 0; tmp--) { // Add higher and lower 16 bits seperately // apparently gcc uses muldi3 builtin while adding long long ints int rettmp = ret; ret = (((uint16)(x>>16))+((uint16)(rettmp>>16))); ret += (((uint16)(x&0xffff))+((uint16)(rettmp&0xffff))); } return ret; } int mod(int x, int y) { int idx = 0; for (idx = 0; mul(idx, y) <= x; idx++); idx = x-mul((idx-1), y); return idx; } int div(int x, int y) { if (y >= x) return 0; int ret = 1; for (; (x=x-y) >= y; ret++); return ret; } static void printint(int xx, int base, int sign) { char buf[16]; int i; uint x; if(sign && (sign = xx < 0)) x = -xx; else x = xx; i = 0; do { buf[i++] = digits[mod(x, base)]; x = div(x, base); } while(x != 0); if(sign) buf[i++] = '-'; while(--i >= 0) consputc(buf[i]); } static void printptr(uint64 x) { int i; consputc('0'); consputc('x'); for (i = 0; i < (mul(sizeof(uint64), 2)); i++, x <<= 4) consputc(digits[x >> (mul(sizeof(uint64), 8) - 4)]); } // Print to the console. only understands %d, %x, %p, %s. void printf(char *fmt, ...) { va_list ap; int i, c, locking; char *s; locking = pr.locking; if(locking) acquire(&pr.lock); if (fmt == 0) panic("null fmt"); va_start(ap, fmt); for(i = 0; (c = fmt[i] & 0xff) != 0; i++){ if(c != '%'){ consputc(c); continue; } c = fmt[++i] & 0xff; if(c == 0) break; switch(c){ case 'd': printint(va_arg(ap, int), 10, 1); break; case 'x': printint(va_arg(ap, int), 16, 1); break; case 'p': printptr(va_arg(ap, uint64)); break; case 's': if((s = va_arg(ap, char*)) == 0) s = "(null)"; for(; *s; s++) consputc(*s); break; case '%': consputc('%'); break; default: // Print unknown % sequence to draw attention. consputc('%'); consputc(c); break; } } if(locking) release(&pr.lock); } void panic(char *s) { pr.locking = 0; printf("panic: "); printf(s); printf("\n"); panicked = 1; // freeze uart output from other CPUs for(;;) ; } void printfinit(void) { initlock(&pr.lock, "pr"); pr.locking = 1; }