263 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			263 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // Console input and output.
 | |
| // Input is from the keyboard or serial port.
 | |
| // Output is written to the screen and serial port.
 | |
| 
 | |
| #include <stdarg.h>
 | |
| 
 | |
| #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"
 | |
| 
 | |
| static void consputc(int);
 | |
| 
 | |
| static volatile int panicked = 0;
 | |
| 
 | |
| static struct {
 | |
|   struct spinlock lock;
 | |
|   int locking;
 | |
| } cons;
 | |
| 
 | |
| static char digits[] = "0123456789abcdef";
 | |
| 
 | |
| 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[x % base];
 | |
|   }while((x /= base) != 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 < (sizeof(uint64) * 2); i++, x <<= 4)
 | |
|     consputc(digits[x >> (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 = cons.locking;
 | |
|   if(locking)
 | |
|     acquire(&cons.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(&cons.lock);
 | |
| }
 | |
| 
 | |
| void
 | |
| panic(char *s)
 | |
| {
 | |
|   cons.locking = 0;
 | |
|   printf("panic: ");
 | |
|   printf(s);
 | |
|   printf("\n");
 | |
|   panicked = 1; // freeze other CPU
 | |
|   for(;;)
 | |
|     ;
 | |
| }
 | |
| 
 | |
| #define BACKSPACE 0x100
 | |
| 
 | |
| void
 | |
| consputc(int c)
 | |
| {
 | |
|   if(panicked){
 | |
|     for(;;)
 | |
|       ;
 | |
|   }
 | |
| 
 | |
|   if(c == BACKSPACE){
 | |
|     uartputc('\b'); uartputc(' '); uartputc('\b');
 | |
|   } else
 | |
|     uartputc(c);
 | |
| }
 | |
| 
 | |
| #define INPUT_BUF 128
 | |
| struct {
 | |
|   char buf[INPUT_BUF];
 | |
|   uint r;  // Read index
 | |
|   uint w;  // Write index
 | |
|   uint e;  // Edit index
 | |
| } input;
 | |
| 
 | |
| #define C(x)  ((x)-'@')  // Contro
 | |
| 
 | |
| int
 | |
| consoleread(int user_dst, uint64 dst, int n)
 | |
| {
 | |
|   uint target;
 | |
|   int c;
 | |
|   char buf[1];
 | |
| 
 | |
|   target = n;
 | |
|   acquire(&cons.lock);
 | |
|   while(n > 0){
 | |
|     while(input.r == input.w){
 | |
|       if(myproc()->killed){
 | |
|         release(&cons.lock);
 | |
|         return -1;
 | |
|       }
 | |
|       sleep(&input.r, &cons.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;
 | |
|     }
 | |
|     buf[0] = c;
 | |
|     if(either_copyout(user_dst, dst, &buf[0], 1) == -1)
 | |
|       break;
 | |
|     dst++;
 | |
|     --n;
 | |
|     if(c == '\n')
 | |
|       break;
 | |
|   }
 | |
|   release(&cons.lock);
 | |
| 
 | |
|   return target - n;
 | |
| }
 | |
| 
 | |
| int
 | |
| consolewrite(int user_src, uint64 src, int n)
 | |
| {
 | |
|   int i;
 | |
| 
 | |
|   acquire(&cons.lock);
 | |
|   for(i = 0; i < n; i++){
 | |
|     char c;
 | |
|     if(either_copyin(&c, user_src, src+i, 1) == -1)
 | |
|       break;
 | |
|     consputc(c);
 | |
|   }
 | |
|   release(&cons.lock);
 | |
| 
 | |
|   return n;
 | |
| }
 | |
| 
 | |
| void
 | |
| consoleintr(int c)
 | |
| {
 | |
|   int doprocdump = 0;
 | |
|   
 | |
|   acquire(&cons.lock);
 | |
| 
 | |
|   switch(c){
 | |
|   case C('P'):  // Process list.
 | |
|     // procdump() locks cons.lock indirectly; invoke later
 | |
|     doprocdump = 1;
 | |
|     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(&cons.lock);
 | |
| 
 | |
|   if(doprocdump)
 | |
|     procdump();
 | |
| }
 | |
| 
 | |
| void
 | |
| consoleinit(void)
 | |
| {
 | |
|   initlock(&cons.lock, "console");
 | |
| 
 | |
|   devsw[CONSOLE].write = consolewrite;
 | |
|   devsw[CONSOLE].read = consoleread;
 | |
|   cons.locking = 1;
 | |
| }
 | 
