293 lines
		
	
	
	
		
			5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			293 lines
		
	
	
	
		
			5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // 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 "traps.h"
 | |
| #include "spinlock.h"
 | |
| #include "fs.h"
 | |
| #include "file.h"
 | |
| #include "memlayout.h"
 | |
| #include "mmu.h"
 | |
| #include "proc.h"
 | |
| #include "x86.h"
 | |
| 
 | |
| 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);
 | |
| }
 | |
| 
 | |
| void
 | |
| panic(char *s)
 | |
| {
 | |
|   int i;
 | |
|   uint pcs[10];
 | |
|   
 | |
|   cli();
 | |
|   cons.locking = 0;
 | |
|   cprintf("cpu%d: panic: ", cpu->id);
 | |
|   cprintf(s);
 | |
|   cprintf("\n");
 | |
|   getcallerpcs(&s, pcs);
 | |
|   for(i=0; i<10; i++)
 | |
|     cprintf(" %p", pcs[i]);
 | |
|   panicked = 1; // freeze other CPU
 | |
|   for(;;)
 | |
|     ;
 | |
| }
 | |
| 
 | |
| //PAGEBREAK: 50
 | |
| #define BACKSPACE 0x100
 | |
| #define CRTPORT 0x3d4
 | |
| static ushort *crt = (ushort*)P2V(0xb8000);  // CGA memory
 | |
| 
 | |
| static void
 | |
| cgaputc(int c)
 | |
| {
 | |
|   int pos;
 | |
|   
 | |
|   // Cursor position: col + 80*row.
 | |
|   outb(CRTPORT, 14);
 | |
|   pos = inb(CRTPORT+1) << 8;
 | |
|   outb(CRTPORT, 15);
 | |
|   pos |= inb(CRTPORT+1);
 | |
| 
 | |
|   if(c == '\n')
 | |
|     pos += 80 - pos%80;
 | |
|   else if(c == BACKSPACE){
 | |
|     if(pos > 0) --pos;
 | |
|   } else
 | |
|     crt[pos++] = (c&0xff) | 0x0700;  // black on white
 | |
|   
 | |
|   if((pos/80) >= 24){  // Scroll up.
 | |
|     memmove(crt, crt+80, sizeof(crt[0])*23*80);
 | |
|     pos -= 80;
 | |
|     memset(crt+pos, 0, sizeof(crt[0])*(24*80 - pos));
 | |
|   }
 | |
|   
 | |
|   outb(CRTPORT, 14);
 | |
|   outb(CRTPORT+1, pos>>8);
 | |
|   outb(CRTPORT, 15);
 | |
|   outb(CRTPORT+1, pos);
 | |
|   crt[pos] = ' ' | 0x0700;
 | |
| }
 | |
| 
 | |
| void
 | |
| consputc(int c)
 | |
| {
 | |
|   if(panicked){
 | |
|     cli();
 | |
|     for(;;)
 | |
|       ;
 | |
|   }
 | |
| 
 | |
|   if(c == BACKSPACE){
 | |
|     uartputc('\b'); uartputc(' '); uartputc('\b');
 | |
|   } else
 | |
|     uartputc(c);
 | |
|   cgaputc(c);
 | |
| }
 | |
| 
 | |
| #define INPUT_BUF 128
 | |
| 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);
 | |
| }
 | |
| 
 | |
| 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;
 | |
|   cons.locking = 1;
 | |
| 
 | |
|   picenable(IRQ_KBD);
 | |
|   ioapicenable(IRQ_KBD, 0);
 | |
| }
 | |
| 
 | 
