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