264 lines
4.4 KiB
C
264 lines
4.4 KiB
C
// Console input and output.
|
|
// Input is from the keyboard or serial port.
|
|
// Output is written to the screen and serial port.
|
|
|
|
#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"
|
|
|
|
static void consputc(int);
|
|
|
|
static volatile int panicked = 0;
|
|
|
|
static struct {
|
|
struct spinlock lock;
|
|
int locking;
|
|
} cons;
|
|
|
|
static char digits[] = "0123456789abcdef";
|
|
|
|
static void
|
|
printint(int xx, int base, int sign)
|
|
{
|
|
char buf[16];
|
|
int i;
|
|
uint x;
|
|
|
|
if(sign && (sign = xx < 0))
|
|
x = -xx;
|
|
else
|
|
x = xx;
|
|
|
|
i = 0;
|
|
do{
|
|
buf[i++] = digits[x % base];
|
|
}while((x /= base) != 0);
|
|
|
|
if(sign)
|
|
buf[i++] = '-';
|
|
|
|
while(--i >= 0)
|
|
consputc(buf[i]);
|
|
}
|
|
|
|
static void
|
|
printptr(uint64 x) {
|
|
int i;
|
|
consputc('0');
|
|
consputc('x');
|
|
for (i = 0; i < (sizeof(uint64) * 2); i++, x <<= 4)
|
|
consputc(digits[x >> (sizeof(uint64) * 8 - 4)]);
|
|
}
|
|
|
|
// Print to the console. only understands %d, %x, %p, %s.
|
|
void
|
|
printf(char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
int i, c, locking;
|
|
char *s;
|
|
|
|
locking = cons.locking;
|
|
if(locking)
|
|
acquire(&cons.lock);
|
|
|
|
if (fmt == 0)
|
|
panic("null fmt");
|
|
|
|
va_start(ap, fmt);
|
|
for(i = 0; (c = fmt[i] & 0xff) != 0; i++){
|
|
if(c != '%'){
|
|
consputc(c);
|
|
continue;
|
|
}
|
|
c = fmt[++i] & 0xff;
|
|
if(c == 0)
|
|
break;
|
|
switch(c){
|
|
case 'd':
|
|
printint(va_arg(ap, int), 10, 1);
|
|
break;
|
|
case 'x':
|
|
printint(va_arg(ap, int), 16, 1);
|
|
break;
|
|
case 'p':
|
|
printptr(va_arg(ap, uint64));
|
|
break;
|
|
case 's':
|
|
if((s = va_arg(ap, char*)) == 0)
|
|
s = "(null)";
|
|
for(; *s; s++)
|
|
consputc(*s);
|
|
break;
|
|
case '%':
|
|
consputc('%');
|
|
break;
|
|
default:
|
|
// Print unknown % sequence to draw attention.
|
|
consputc('%');
|
|
consputc(c);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(locking)
|
|
release(&cons.lock);
|
|
}
|
|
|
|
void
|
|
panic(char *s)
|
|
{
|
|
cons.locking = 0;
|
|
printf("panic: ");
|
|
printf(s);
|
|
printf("\n");
|
|
panicked = 1; // freeze other CPU
|
|
for(;;)
|
|
;
|
|
}
|
|
|
|
#define BACKSPACE 0x100
|
|
|
|
void
|
|
consputc(int c)
|
|
{
|
|
if(panicked){
|
|
for(;;)
|
|
;
|
|
}
|
|
|
|
if(c == BACKSPACE){
|
|
uartputc('\b'); uartputc(' '); uartputc('\b');
|
|
} else
|
|
uartputc(c);
|
|
}
|
|
|
|
#define INPUT_BUF 128
|
|
struct {
|
|
char buf[INPUT_BUF];
|
|
uint r; // Read index
|
|
uint w; // Write index
|
|
uint e; // Edit index
|
|
} input;
|
|
|
|
#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(input.r == input.w){
|
|
if(myproc()->killed){
|
|
release(&cons.lock);
|
|
return -1;
|
|
}
|
|
sleep(&input.r, &cons.lock);
|
|
}
|
|
c = input.buf[input.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.
|
|
input.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(input.e != input.w &&
|
|
input.buf[(input.e-1) % INPUT_BUF] != '\n'){
|
|
input.e--;
|
|
consputc(BACKSPACE);
|
|
}
|
|
break;
|
|
case C('H'): case '\x7f': // Backspace
|
|
if(input.e != input.w){
|
|
input.e--;
|
|
consputc(BACKSPACE);
|
|
}
|
|
break;
|
|
default:
|
|
if(c != 0 && input.e-input.r < INPUT_BUF){
|
|
c = (c == '\r') ? '\n' : c;
|
|
input.buf[input.e++ % INPUT_BUF] = c;
|
|
consputc(c);
|
|
if(c == '\n' || c == C('D') || input.e == input.r+INPUT_BUF){
|
|
input.w = input.e;
|
|
wakeup(&input.r);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
release(&cons.lock);
|
|
|
|
if(doprocdump)
|
|
procdump();
|
|
}
|
|
|
|
void
|
|
consoleinit(void)
|
|
{
|
|
initlock(&cons.lock, "console");
|
|
|
|
devsw[CONSOLE].write = consolewrite;
|
|
devsw[CONSOLE].read = consoleread;
|
|
cons.locking = 1;
|
|
}
|