xv6

port of xv6 to x86-64
git clone http://frotz.net/git/xv6.git
Log | Files | Refs | README | LICENSE

console.c (5439B)


      1 // Console input and output.
      2 // Input is from the keyboard or serial port.
      3 // Output is written to the screen and serial port.
      4 
      5 #include <stdarg.h>
      6 
      7 #include "types.h"
      8 #include "defs.h"
      9 #include "param.h"
     10 #include "traps.h"
     11 #include "spinlock.h"
     12 #include "fs.h"
     13 #include "file.h"
     14 #include "memlayout.h"
     15 #include "mmu.h"
     16 #include "proc.h"
     17 #include "x86.h"
     18 
     19 static void consputc(int);
     20 
     21 static int panicked = 0;
     22 
     23 static struct {
     24   struct spinlock lock;
     25   int locking;
     26 } cons;
     27 
     28 static char digits[] = "0123456789abcdef";
     29 
     30 static void
     31 printptr(uintp x) {
     32   int i;
     33   for (i = 0; i < (sizeof(uintp) * 2); i++, x <<= 4)
     34     consputc(digits[x >> (sizeof(uintp) * 8 - 4)]);
     35 }
     36 
     37 static void
     38 printint(int xx, int base, int sign)
     39 {
     40   char buf[16];
     41   int i;
     42   uint x;
     43 
     44   if(sign && (sign = xx < 0))
     45     x = -xx;
     46   else
     47     x = xx;
     48 
     49   i = 0;
     50   do{
     51     buf[i++] = digits[x % base];
     52   }while((x /= base) != 0);
     53 
     54   if(sign)
     55     buf[i++] = '-';
     56 
     57   while(--i >= 0)
     58     consputc(buf[i]);
     59 }
     60 //PAGEBREAK: 50
     61 
     62 // Print to the console. only understands %d, %x, %p, %s.
     63 void
     64 cprintf(char *fmt, ...)
     65 {
     66   va_list ap;
     67   int i, c, locking;
     68   char *s;
     69 
     70   va_start(ap, fmt);
     71 
     72   locking = cons.locking;
     73   if(locking)
     74     acquire(&cons.lock);
     75 
     76   if (fmt == 0)
     77     panic("null fmt");
     78 
     79   for(i = 0; (c = fmt[i] & 0xff) != 0; i++){
     80     if(c != '%'){
     81       consputc(c);
     82       continue;
     83     }
     84     c = fmt[++i] & 0xff;
     85     if(c == 0)
     86       break;
     87     switch(c){
     88     case 'd':
     89       printint(va_arg(ap, int), 10, 1);
     90       break;
     91     case 'x':
     92       printint(va_arg(ap, int), 16, 0);
     93       break;
     94     case 'p':
     95       printptr(va_arg(ap, uintp));
     96       break;
     97     case 's':
     98       if((s = va_arg(ap, char*)) == 0)
     99         s = "(null)";
    100       for(; *s; s++)
    101         consputc(*s);
    102       break;
    103     case '%':
    104       consputc('%');
    105       break;
    106     default:
    107       // Print unknown % sequence to draw attention.
    108       consputc('%');
    109       consputc(c);
    110       break;
    111     }
    112   }
    113 
    114   if(locking)
    115     release(&cons.lock);
    116 }
    117 
    118 void
    119 panic(char *s)
    120 {
    121   int i;
    122   uintp pcs[10];
    123   
    124   cli();
    125   cons.locking = 0;
    126   cprintf("cpu%d: panic: ", cpu->id);
    127   cprintf(s);
    128   cprintf("\n");
    129   getcallerpcs(&s, pcs);
    130   for(i=0; i<10; i++)
    131     cprintf(" %p", pcs[i]);
    132   panicked = 1; // freeze other CPU
    133   for(;;)
    134     ;
    135 }
    136 
    137 //PAGEBREAK: 50
    138 #define BACKSPACE 0x100
    139 #define CRTPORT 0x3d4
    140 static ushort *crt = (ushort*)P2V(0xb8000);  // CGA memory
    141 
    142 static void
    143 cgaputc(int c)
    144 {
    145   int pos;
    146   
    147   // Cursor position: col + 80*row.
    148   outb(CRTPORT, 14);
    149   pos = inb(CRTPORT+1) << 8;
    150   outb(CRTPORT, 15);
    151   pos |= inb(CRTPORT+1);
    152 
    153   if(c == '\n')
    154     pos += 80 - pos%80;
    155   else if(c == BACKSPACE){
    156     if(pos > 0) --pos;
    157   } else
    158     crt[pos++] = (c&0xff) | 0x0700;  // black on white
    159   
    160   if((pos/80) >= 24){  // Scroll up.
    161     memmove(crt, crt+80, sizeof(crt[0])*23*80);
    162     pos -= 80;
    163     memset(crt+pos, 0, sizeof(crt[0])*(24*80 - pos));
    164   }
    165   
    166   outb(CRTPORT, 14);
    167   outb(CRTPORT+1, pos>>8);
    168   outb(CRTPORT, 15);
    169   outb(CRTPORT+1, pos);
    170   crt[pos] = ' ' | 0x0700;
    171 }
    172 
    173 void
    174 consputc(int c)
    175 {
    176   if(panicked){
    177     cli();
    178     for(;;)
    179       ;
    180   }
    181 
    182   if(c == BACKSPACE){
    183     uartputc('\b'); uartputc(' '); uartputc('\b');
    184   } else
    185     uartputc(c);
    186   cgaputc(c);
    187 }
    188 
    189 #define INPUT_BUF 128
    190 struct {
    191   struct spinlock lock;
    192   char buf[INPUT_BUF];
    193   uint r;  // Read index
    194   uint w;  // Write index
    195   uint e;  // Edit index
    196 } input;
    197 
    198 #define C(x)  ((x)-'@')  // Control-x
    199 
    200 void
    201 consoleintr(int (*getc)(void))
    202 {
    203   int c;
    204 
    205   acquire(&input.lock);
    206   while((c = getc()) >= 0){
    207     switch(c){
    208     case C('Z'): // reboot
    209       lidt(0,0);
    210       break;
    211     case C('P'):  // Process listing.
    212       procdump();
    213       break;
    214     case C('U'):  // Kill line.
    215       while(input.e != input.w &&
    216             input.buf[(input.e-1) % INPUT_BUF] != '\n'){
    217         input.e--;
    218         consputc(BACKSPACE);
    219       }
    220       break;
    221     case C('H'): case '\x7f':  // Backspace
    222       if(input.e != input.w){
    223         input.e--;
    224         consputc(BACKSPACE);
    225       }
    226       break;
    227     default:
    228       if(c != 0 && input.e-input.r < INPUT_BUF){
    229         c = (c == '\r') ? '\n' : c;
    230         input.buf[input.e++ % INPUT_BUF] = c;
    231         consputc(c);
    232         if(c == '\n' || c == C('D') || input.e == input.r+INPUT_BUF){
    233           input.w = input.e;
    234           wakeup(&input.r);
    235         }
    236       }
    237       break;
    238     }
    239   }
    240   release(&input.lock);
    241 }
    242 
    243 int
    244 consoleread(struct inode *ip, char *dst, int n)
    245 {
    246   uint target;
    247   int c;
    248 
    249   iunlock(ip);
    250   target = n;
    251   acquire(&input.lock);
    252   while(n > 0){
    253     while(input.r == input.w){
    254       if(proc->killed){
    255         release(&input.lock);
    256         ilock(ip);
    257         return -1;
    258       }
    259       sleep(&input.r, &input.lock);
    260     }
    261     c = input.buf[input.r++ % INPUT_BUF];
    262     if(c == C('D')){  // EOF
    263       if(n < target){
    264         // Save ^D for next time, to make sure
    265         // caller gets a 0-byte result.
    266         input.r--;
    267       }
    268       break;
    269     }
    270     *dst++ = c;
    271     --n;
    272     if(c == '\n')
    273       break;
    274   }
    275   release(&input.lock);
    276   ilock(ip);
    277 
    278   return target - n;
    279 }
    280 
    281 int
    282 consolewrite(struct inode *ip, char *buf, int n)
    283 {
    284   int i;
    285 
    286   iunlock(ip);
    287   acquire(&cons.lock);
    288   for(i = 0; i < n; i++)
    289     consputc(buf[i] & 0xff);
    290   release(&cons.lock);
    291   ilock(ip);
    292 
    293   return n;
    294 }
    295 
    296 void
    297 consoleinit(void)
    298 {
    299   initlock(&cons.lock, "console");
    300   initlock(&input.lock, "input");
    301 
    302   devsw[CONSOLE].write = consolewrite;
    303   devsw[CONSOLE].read = consoleread;
    304   cons.locking = 1;
    305 
    306   picenable(IRQ_KBD);
    307   ioapicenable(IRQ_KBD, 0);
    308 }
    309