// Console input and output. // Input is from the keyboard or serial port. // Output is written to the screen and serial port. #include "types.h" #include "defs.h" #include "param.h" #include "spinlock.h" #include "fs.h" #include "file.h" #include "memlayout.h" #include "mmu.h" #include "proc.h" __code cbc_consoleread1 (); __code cbc_consoleread2 (); static void consputc (int); static int panicked = 0; static struct { struct spinlock lock; int locking; } cons; static void printint (int xx, int base, int sign) { static char digits[] = "0123456789abcdef"; char buf[16]; int i; uint x; if (sign && (sign = xx < 0)) { x = -xx; } else { x = xx; } i = 0; do { buf[i++] = digits[x % base]; } while ((x /= base) != 0); if (sign) { buf[i++] = '-'; } while (--i >= 0) { consputc(buf[i]); } } //PAGEBREAK: 50 // Print to the console. only understands %d, %x, %p, %s. void cprintf (char *fmt, ...) { int i, c, locking; uint *argp; char *s; locking = cons.locking; if (locking) { acquire(&cons.lock); } if (fmt == 0) { panic("null fmt"); } argp = (uint*) (void*) (&fmt + 1); 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(*argp++, 10, 1); break; case 'x': case 'p': printint(*argp++, 16, 0); break; case 's': if ((s = (char*) *argp++) == 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(&cons.lock); } } __code cbc_panic (char *s) { cli(); cons.locking = 0; cprintf("cpu%d: panic: ", cpu->id); show_callstk(s); panicked = 1; // freeze other CPU while (1) ; } void panic (char *s) { cli(); cons.locking = 0; cprintf("cpu%d: panic: ", cpu->id); show_callstk(s); panicked = 1; // freeze other CPU while (1) ; } //PAGEBREAK: 50 #define BACKSPACE 0x100 #define CRTPORT 0x3d4 void consputc (int c) { if (panicked) { cli(); while (1) ; } if (c == BACKSPACE) { uartputc('\b'); uartputc(' '); uartputc('\b'); } else { uartputc(c); } // cgaputc(c); } #define INPUT_BUF 512 struct { struct spinlock lock; char buf[INPUT_BUF]; uint r; // Read index uint w; // Write index uint e; // Edit index } input; #define C(x) ((x)-'@') // Control-x void consoleintr (int (*getc) (void)) { int c; acquire(&input.lock); while ((c = getc()) >= 0) { switch (c) { case C('P'): // Process listing. procdump(); break; case C('U'): // Kill line. while ((input.e != input.w) && (input.buf[(input.e - 1) % INPUT_BUF] != '\n')) { input.e--; consputc(BACKSPACE); } break; case C('H'): case '\x7f': // Backspace if (input.e != input.w) { input.e--; consputc(BACKSPACE); } break; default: if ((c != 0) && (input.e - input.r < INPUT_BUF)) { c = (c == '\r') ? '\n' : c; input.buf[input.e++ % INPUT_BUF] = c; consputc(c); if (c == '\n' || c == C('D') || input.e == input.r + INPUT_BUF) { input.w = input.e; wakeup(&input.r); } } break; } } release(&input.lock); } __code cbc_consoleread2 () { struct inode *ip = proc->cbc_arg.cbc_console_arg.ip; __code(*next)(int ret) = proc->cbc_arg.cbc_console_arg.next; if (input.r == input.w) { if (proc->killed) { release(&input.lock); ilock(ip); goto next(-1); } goto cbc_sleep(&input.r, &input.lock, cbc_consoleread2); } goto cbc_consoleread1(); } __code cbc_consoleread1 () { int cont = 1; int n = proc->cbc_arg.cbc_console_arg.n; int target = proc->cbc_arg.cbc_console_arg.target; char* dst = proc->cbc_arg.cbc_console_arg.dst; struct inode *ip = proc->cbc_arg.cbc_console_arg.ip; __code(*next)(int ret) = proc->cbc_arg.cbc_console_arg.next; int c = input.buf[input.r++ % INPUT_BUF]; if (c == C('D')) { // EOF if (n < target) { // Save ^D for next time, to make sure // caller gets a 0-byte result. input.r--; } cont = 0; } *dst++ = c; --n; if (c == '\n') { cont = 0; } if (cont == 1) { if (n > 0) { proc->cbc_arg.cbc_console_arg.n = n; proc->cbc_arg.cbc_console_arg.target = target; proc->cbc_arg.cbc_console_arg.dst = dst; proc->cbc_arg.cbc_console_arg.ip = ip; proc->cbc_arg.cbc_console_arg.next = next; goto cbc_sleep(&input.r, &input.lock, cbc_consoleread2); } } release(&input.lock); ilock(ip); goto next(target - n); } __code cbc_consoleread (struct inode *ip, char *dst, int n, __code(*next)(int ret)) { uint target; iunlock(ip); target = n; acquire(&input.lock); if (n > 0) { proc->cbc_arg.cbc_console_arg.n = n; proc->cbc_arg.cbc_console_arg.target = target; proc->cbc_arg.cbc_console_arg.dst = dst; proc->cbc_arg.cbc_console_arg.ip = ip; proc->cbc_arg.cbc_console_arg.next = next; goto cbc_consoleread2(); } goto cbc_consoleread1(); } int consoleread (struct inode *ip, char *dst, int n) { uint target; int c; iunlock(ip); target = n; acquire(&input.lock); while (n > 0) { while (input.r == input.w) { if (proc->killed) { release(&input.lock); ilock(ip); return -1; } sleep(&input.r, &input.lock); } c = input.buf[input.r++ % INPUT_BUF]; if (c == C('D')) { // EOF if (n < target) { // Save ^D for next time, to make sure // caller gets a 0-byte result. input.r--; } break; } *dst++ = c; --n; if (c == '\n') { break; } } release(&input.lock); ilock(ip); return target - n; } int consolewrite (struct inode *ip, char *buf, int n) { int i; iunlock(ip); acquire(&cons.lock); for (i = 0; i < n; i++) { consputc(buf[i] & 0xff); } release(&cons.lock); ilock(ip); return n; } void consoleinit (void) { initlock(&cons.lock, "console"); initlock(&input.lock, "input"); devsw[CONSOLE].write = consolewrite; devsw[CONSOLE].read = consoleread; //cbc_devsw[CONSOLE].write = cbc_consolewrite; cbc_devsw[CONSOLE].read = cbc_consoleread; cons.locking = 1; }