root/kernel/console.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. consputc
  2. consolewrite
  3. consoleread
  4. consoleintr
  5. consoleinit

   1 //
   2 // Console input and output, to the uart.
   3 // Reads are line at a time.
   4 // Implements special input characters:
   5 //   newline -- end of line
   6 //   control-h -- backspace
   7 //   control-u -- kill line
   8 //   control-d -- end of file
   9 //   control-p -- print process list
  10 //
  11 
  12 #include <stdarg.h>
  13 
  14 #include "types.h"
  15 #include "param.h"
  16 #include "spinlock.h"
  17 #include "sleeplock.h"
  18 #include "fs.h"
  19 #include "file.h"
  20 #include "memlayout.h"
  21 #include "riscv.h"
  22 #include "defs.h"
  23 #include "proc.h"
  24 
  25 #define BACKSPACE 0x100       // erase the last output character
  26 #define C(x)      ((x) - '@') // Control-x
  27 
  28 //
  29 // send one character to the uart, but don't use
  30 // interrupts or sleep(). safe to be called from
  31 // interrupts, e.g. by printk and to echo input
  32 // characters.
  33 //
  34 void
  35 consputc(int c)
  36 {
  37   if (c == BACKSPACE) {
  38     // if the user typed backspace, overwrite with a space.
  39     uartputc_sync('\b');
  40     uartputc_sync(' ');
  41     uartputc_sync('\b');
  42   } else {
  43     uartputc_sync(c);
  44   }
  45 }
  46 
  47 struct {
  48   struct spinlock lock;
  49 
  50   // input circular buffer
  51 #define INPUT_BUF_SIZE 128
  52   char buf[INPUT_BUF_SIZE];
  53   uint r; // Read index
  54   uint w; // Write index
  55   uint e; // Edit index
  56 } cons;
  57 
  58 //
  59 // user write() system calls to the console go here.
  60 // uses sleep() and UART interrupts.
  61 //
  62 int
  63 consolewrite(int user_src, uint64 src, int n)
  64 {
  65   char buf[32]; // move batches from user space to uart.
  66   int i = 0;
  67 
  68   while (i < n) {
  69     int nn = sizeof(buf);
  70     if (nn > n - i)
  71       nn = n - i;
  72     if (either_copyin(buf, user_src, src + i, nn) == -1)
  73       break;
  74     uartwrite(buf, nn);
  75     i += nn;
  76   }
  77 
  78   return i;
  79 }
  80 
  81 //
  82 // user read()s from the console go here.
  83 // copy (up to) a whole input line to dst.
  84 // user_dst indicates whether dst is a user
  85 // or kernel address.
  86 //
  87 int
  88 consoleread(int user_dst, uint64 dst, int n)
  89 {
  90   uint target;
  91   int c;
  92   char cbuf;
  93 
  94   target = n;
  95   acquire(&cons.lock);
  96   while (n > 0) {
  97     // wait until interrupt handler has put some
  98     // input into cons.buffer.
  99     while (cons.r == cons.w) {
 100       if (killed(myproc())) {
 101         release(&cons.lock);
 102         return -1;
 103       }
 104       sleep_prepare(&cons.r);
 105       release(&cons.lock);
 106       sleep();
 107       acquire(&cons.lock);
 108     }
 109 
 110     c = cons.buf[cons.r++ % INPUT_BUF_SIZE];
 111 
 112     if (c == C('D')) { // end-of-file
 113       if (n < target) {
 114         // Save ^D for next time, to make sure
 115         // caller gets a 0-byte result.
 116         cons.r--;
 117       }
 118       break;
 119     }
 120 
 121     // copy the input byte to the user-space buffer.
 122     cbuf = c;
 123     if (either_copyout(user_dst, dst, &cbuf, 1) == -1)
 124       break;
 125 
 126     dst++;
 127     --n;
 128 
 129     if (c == '\n') {
 130       // a whole line has arrived, return to
 131       // the user-level read().
 132       break;
 133     }
 134   }
 135   release(&cons.lock);
 136 
 137   return target - n;
 138 }
 139 
 140 //
 141 // the console input interrupt handler.
 142 // uartintr() calls this for each input character.
 143 // do erase/kill processing, append to cons.buf,
 144 // wake up consoleread() if a whole line has arrived.
 145 //
 146 void
 147 consoleintr(int c)
 148 {
 149   acquire(&cons.lock);
 150 
 151   switch (c) {
 152   case C('P'): // Print process list.
 153     procdump();
 154     break;
 155   case C('U'): // Kill line.
 156     while (cons.e != cons.w &&
 157            cons.buf[(cons.e - 1) % INPUT_BUF_SIZE] != '\n') {
 158       cons.e--;
 159       consputc(BACKSPACE);
 160     }
 161     break;
 162   case C('H'): // Backspace
 163   case '\x7f': // Delete key
 164     if (cons.e != cons.w) {
 165       cons.e--;
 166       consputc(BACKSPACE);
 167     }
 168     break;
 169   default:
 170     if (c != 0 && cons.e - cons.r < INPUT_BUF_SIZE) {
 171       c = (c == '\r') ? '\n' : c;
 172 
 173       // echo back to the user.
 174       consputc(c);
 175 
 176       // store for consumption by consoleread().
 177       cons.buf[cons.e++ % INPUT_BUF_SIZE] = c;
 178 
 179       if (c == '\n' || c == C('D') || cons.e - cons.r == INPUT_BUF_SIZE) {
 180         // wake up consoleread() if a whole line (or end-of-file)
 181         // has arrived.
 182         cons.w = cons.e;
 183         wakeup(&cons.r);
 184       }
 185     }
 186     break;
 187   }
 188 
 189   release(&cons.lock);
 190 }
 191 
 192 void
 193 consoleinit(void)
 194 {
 195   initlock(&cons.lock, "cons");
 196 
 197   uartinit();
 198 
 199   // connect read and write system calls
 200   // to consoleread and consolewrite.
 201   devsw[CONSOLE].read = consoleread;
 202   devsw[CONSOLE].write = consolewrite;
 203 }

/* [<][>][^][v][top][bottom][index][help] */