kernel/console.c

198 lines
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 line6//   control-h -- backspace7//   control-u -- kill line8//   control-d -- end of file9//   control-p -- print process list10//1112#include <stdarg.h>1314#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"2425#define BACKSPACE 0x100  // erase the last output character26#define C(x)  ((x)-'@')  // Control-x2728//29// send one character to the uart, but don't use30// interrupts or sleep(). safe to be called from31// interrupts, e.g. by printf and to echo input32// characters.33//34void35consputc(int c)36{37  if(c == BACKSPACE){38    // if the user typed backspace, overwrite with a space.39    uartputc_sync('\b'); uartputc_sync(' '); uartputc_sync('\b');40  } else {41    uartputc_sync(c);42  }43}4445struct {46  struct spinlock lock;47  48  // input circular buffer49#define INPUT_BUF_SIZE 12850  char buf[INPUT_BUF_SIZE];51  uint r;  // Read index52  uint w;  // Write index53  uint e;  // Edit index54} cons;5556//57// user write() system calls to the console go here.58// uses sleep() and UART interrupts.59//60int61consolewrite(int user_src, uint64 src, int n)62{63  char buf[32]; // move batches from user space to uart.64  int i = 0;6566  while(i < n){67    int nn = sizeof(buf);68    if(nn > n - i)69      nn = n - i;70    if(either_copyin(buf, user_src, src+i, nn) == -1)71      break;72    uartwrite(buf, nn);73    i += nn;74  }7576  return i;77}7879//80// user read()s from the console go here.81// copy (up to) a whole input line to dst.82// user_dst indicates whether dst is a user83// or kernel address.84//85int86consoleread(int user_dst, uint64 dst, int n)87{88  uint target;89  int c;90  char cbuf;9192  target = n;93  acquire(&cons.lock);94  while(n > 0){95    // wait until interrupt handler has put some96    // input into cons.buffer.97    while(cons.r == cons.w){98      if(killed(myproc())){99        release(&cons.lock);100        return -1;101      }102      sleep(&cons.r, &cons.lock);103    }104105    c = cons.buf[cons.r++ % INPUT_BUF_SIZE];106107    if(c == C('D')){  // end-of-file108      if(n < target){109        // Save ^D for next time, to make sure110        // caller gets a 0-byte result.111        cons.r--;112      }113      break;114    }115116    // copy the input byte to the user-space buffer.117    cbuf = c;118    if(either_copyout(user_dst, dst, &cbuf, 1) == -1)119      break;120121    dst++;122    --n;123124    if(c == '\n'){125      // a whole line has arrived, return to126      // the user-level read().127      break;128    }129  }130  release(&cons.lock);131132  return target - n;133}134135//136// the console input interrupt handler.137// uartintr() calls this for each input character.138// do erase/kill processing, append to cons.buf,139// wake up consoleread() if a whole line has arrived.140//141void142consoleintr(int c)143{144  acquire(&cons.lock);145146  switch(c){147  case C('P'):  // Print process list.148    procdump();149    break;150  case C('U'):  // Kill line.151    while(cons.e != cons.w &&152          cons.buf[(cons.e-1) % INPUT_BUF_SIZE] != '\n'){153      cons.e--;154      consputc(BACKSPACE);155    }156    break;157  case C('H'): // Backspace158  case '\x7f': // Delete key159    if(cons.e != cons.w){160      cons.e--;161      consputc(BACKSPACE);162    }163    break;164  default:165    if(c != 0 && cons.e-cons.r < INPUT_BUF_SIZE){166      c = (c == '\r') ? '\n' : c;167168      // echo back to the user.169      consputc(c);170171      // store for consumption by consoleread().172      cons.buf[cons.e++ % INPUT_BUF_SIZE] = c;173174      if(c == '\n' || c == C('D') || cons.e-cons.r == INPUT_BUF_SIZE){175        // wake up consoleread() if a whole line (or end-of-file)176        // has arrived.177        cons.w = cons.e;178        wakeup(&cons.r);179      }180    }181    break;182  }183  184  release(&cons.lock);185}186187void188consoleinit(void)189{190  initlock(&cons.lock, "cons");191192  uartinit();193194  // connect read and write system calls195  // to consoleread and consolewrite.196  devsw[CONSOLE].read = consoleread;197  devsw[CONSOLE].write = consolewrite;198}199