xv6-riscv/kernel/console.c

158 lines
2.7 KiB
C

//
// Console input and output, to the uart.
// Implements erase/kill processing.
//
#include <stdarg.h>
#include "types.h"
#include "param.h"
#include "spinlock.h"
#include "sleeplock.h"
#include "fs.h"
#include "file.h"
#include "memlayout.h"
#include "riscv.h"
#include "defs.h"
#include "proc.h"
#define BACKSPACE 0x100
void
consputc(int c)
{
extern volatile int panicked; // from printf.c
if(panicked){
for(;;)
;
}
if(c == BACKSPACE){
uartputc('\b'); uartputc(' '); uartputc('\b');
} else
uartputc(c);
}
struct {
struct spinlock lock;
// input
#define INPUT_BUF 128
char buf[INPUT_BUF];
uint r; // Read index
uint w; // Write index
uint e; // Edit index
} cons;
#define C(x) ((x)-'@') // Contro
int
consoleread(int user_dst, uint64 dst, int n)
{
uint target;
int c;
char buf[1];
target = n;
acquire(&cons.lock);
while(n > 0){
while(cons.r == cons.w){
if(myproc()->killed){
release(&cons.lock);
return -1;
}
sleep(&cons.r, &cons.lock);
}
c = cons.buf[cons.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.
cons.r--;
}
break;
}
buf[0] = c;
if(either_copyout(user_dst, dst, &buf[0], 1) == -1)
break;
dst++;
--n;
if(c == '\n')
break;
}
release(&cons.lock);
return target - n;
}
int
consolewrite(int user_src, uint64 src, int n)
{
int i;
acquire(&cons.lock);
for(i = 0; i < n; i++){
char c;
if(either_copyin(&c, user_src, src+i, 1) == -1)
break;
consputc(c);
}
release(&cons.lock);
return n;
}
void
consoleintr(int c)
{
int doprocdump = 0;
acquire(&cons.lock);
switch(c){
case C('P'): // Process list.
// procdump() locks cons.lock indirectly; invoke later
doprocdump = 1;
break;
case C('U'): // Kill line.
while(cons.e != cons.w &&
cons.buf[(cons.e-1) % INPUT_BUF] != '\n'){
cons.e--;
consputc(BACKSPACE);
}
break;
case C('H'): case '\x7f': // Backspace
if(cons.e != cons.w){
cons.e--;
consputc(BACKSPACE);
}
break;
default:
if(c != 0 && cons.e-cons.r < INPUT_BUF){
c = (c == '\r') ? '\n' : c;
cons.buf[cons.e++ % INPUT_BUF] = c;
consputc(c);
if(c == '\n' || c == C('D') || cons.e == cons.r+INPUT_BUF){
cons.w = cons.e;
wakeup(&cons.r);
}
}
break;
}
release(&cons.lock);
if(doprocdump)
procdump();
}
void
consoleinit(void)
{
initlock(&cons.lock, "cons");
devsw[CONSOLE].write = consolewrite;
devsw[CONSOLE].read = consoleread;
}