Skip to content
Snippets Groups Projects
console.c 5.06 KiB
Newer Older
rsc's avatar
rsc committed
// Console input and output.
rsc's avatar
rsc committed
// Input is from the keyboard or serial port.
// Output is written to the screen and serial port.
rsc's avatar
rsc committed

#include "types.h"
rtm's avatar
rtm committed
#include "defs.h"
rsc's avatar
rsc committed
#include "param.h"
#include "traps.h"
rtm's avatar
rtm committed
#include "spinlock.h"
#include "fs.h"
#include "file.h"
Frans Kaashoek's avatar
Frans Kaashoek committed
#include "memlayout.h"
rsc's avatar
rsc committed
#include "mmu.h"
#include "proc.h"
rsc's avatar
rsc committed
#include "x86.h"
rtm's avatar
rtm committed

static void consputc(int);
static int panicked = 0;
rsc's avatar
rsc committed

rsc's avatar
 
rsc committed
static struct {
Austin Clements's avatar
Austin Clements committed
  struct spinlock lock;
  int locking;
rsc's avatar
 
rsc committed
} cons;

rtm's avatar
rtm committed
static void
Russ Cox's avatar
Russ Cox committed
printint(int xx, int base, int sign)
rtm's avatar
rtm committed
{
rsc's avatar
rsc committed
  static char digits[] = "0123456789abcdef";
rtm's avatar
rtm committed
  char buf[16];
Russ Cox's avatar
Russ Cox committed
  int i;
Russ Cox's avatar
Russ Cox committed
  if(sign && (sign = xx < 0))
    x = -xx;
Russ Cox's avatar
Russ Cox committed
  else
rtm's avatar
rtm committed
    x = xx;

Russ Cox's avatar
Russ Cox committed
  i = 0;
rsc's avatar
rsc committed
  do{
rtm's avatar
rtm committed
    buf[i++] = digits[x % base];
rsc's avatar
rsc committed
  }while((x /= base) != 0);
Russ Cox's avatar
Russ Cox committed

  if(sign)
rtm's avatar
rtm committed
    buf[i++] = '-';

  while(--i >= 0)
    consputc(buf[i]);
rtm's avatar
rtm committed
}

//PAGEBREAK: 50
rsc's avatar
rsc committed
// Print to the console. only understands %d, %x, %p, %s.
rtm's avatar
rtm committed
void
cprintf(char *fmt, ...)
{
  int i, c, state, locking;
  uint *argp;
  char *s;
rtm's avatar
rtm committed

rsc's avatar
 
rsc committed
  locking = cons.locking;
  if(locking)
rsc's avatar
 
rsc committed
    acquire(&cons.lock);
rtm's avatar
rtm committed

Frans Kaashoek's avatar
Frans Kaashoek committed
  if (fmt == 0)
    panic("null fmt");

Russ Cox's avatar
Russ Cox committed
  argp = (uint*)(void*)(&fmt + 1);
  state = 0;
  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(*argp++, 10, 1);
      break;
    case 'x':
    case 'p':
      printint(*argp++, 16, 0);
      break;
    case 's':
      if((s = (char*)*argp++) == 0)
        s = "(null)";
      for(; *s; s++)
        consputc(*s);
      break;
    case '%':
      consputc('%');
      break;
    default:
      // Print unknown % sequence to draw attention.
      consputc('%');
      consputc(c);
rtm's avatar
rtm committed
    }
  }
rtm's avatar
rtm committed

rsc's avatar
 
rsc committed
    release(&cons.lock);
rtm's avatar
rtm committed
}

void
panic(char *s)
kaashoek's avatar
kaashoek committed
{
  int i;
  uint pcs[10];
  
  cli();
  cons.locking = 0;
Russ Cox's avatar
Russ Cox committed
  cprintf("cpu%d: panic: ", cpu->id);
  cprintf(s);
  cprintf("\n");
  getcallerpcs(&s, pcs);
  for(i=0; i<10; i++)
    cprintf(" %p", pcs[i]);
  panicked = 1; // freeze other CPU
  for(;;)
    ;
}
kaashoek's avatar
kaashoek committed

//PAGEBREAK: 50
#define BACKSPACE 0x100
#define CRTPORT 0x3d4
Frans Kaashoek's avatar
Frans Kaashoek committed
static ushort *crt = (ushort*)P2V(0xb8000);  // CGA memory
kaashoek's avatar
kaashoek committed

static void
cgaputc(int c)
{
  int pos;
  
  // Cursor position: col + 80*row.
  outb(CRTPORT, 14);
  pos = inb(CRTPORT+1) << 8;
  outb(CRTPORT, 15);
  pos |= inb(CRTPORT+1);

  if(c == '\n')
    pos += 80 - pos%80;
  else if(c == BACKSPACE){
  } else
    crt[pos++] = (c&0xff) | 0x0700;  // black on white
  
  if((pos/80) >= 24){  // Scroll up.
    memmove(crt, crt+80, sizeof(crt[0])*23*80);
    pos -= 80;
    memset(crt+pos, 0, sizeof(crt[0])*(24*80 - pos));
  }
  
  outb(CRTPORT, 14);
  outb(CRTPORT+1, pos>>8);
  outb(CRTPORT, 15);
  outb(CRTPORT+1, pos);
  crt[pos] = ' ' | 0x0700;
}

void
consputc(int c)
{
  if(panicked){
    cli();
    for(;;)
      ;
  }

Austin Clements's avatar
Austin Clements committed
  if(c == BACKSPACE){
    uartputc('\b'); uartputc(' '); uartputc('\b');
  cgaputc(c);
kaashoek's avatar
kaashoek committed
}

#define INPUT_BUF 128
struct {
  struct spinlock lock;
  char buf[INPUT_BUF];
  uint r;  // Read index
  uint w;  // Write index
  uint e;  // Edit index
rsc's avatar
rsc committed
#define C(x)  ((x)-'@')  // Control-x

kaashoek's avatar
kaashoek committed
void
consoleintr(int (*getc)(void))
kaashoek's avatar
kaashoek committed

  acquire(&input.lock);
  while((c = getc()) >= 0){
    switch(c){
    case C('P'):  // Process listing.
      procdump();
      break;
    case C('U'):  // Kill line.
            input.buf[(input.e-1) % INPUT_BUF] != '\n'){
        input.e--;
        consputc(BACKSPACE);
    case C('H'): case '\x7f':  // Backspace
        consputc(BACKSPACE);
      if(c != 0 && input.e-input.r < INPUT_BUF){
        c = (c == '\r') ? '\n' : c;
rsc's avatar
rsc committed
        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;
rsc's avatar
rsc committed
    }
  release(&input.lock);
consoleread(struct inode *ip, char *dst, int n)
  uint target;
  int c;
rsc's avatar
 
rsc committed
  iunlock(ip);
  acquire(&input.lock);
  while(n > 0){
    while(input.r == input.w){
Russ Cox's avatar
Russ Cox committed
      if(proc->killed){
        release(&input.lock);
rsc's avatar
 
rsc committed
        ilock(ip);
        return -1;
      }
      sleep(&input.r, &input.lock);
rsc's avatar
rsc committed
    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.
    if(c == '\n')
      break;
  release(&input.lock);
rsc's avatar
 
rsc committed
  ilock(ip);
int
consolewrite(struct inode *ip, char *buf, int n)
{
  int i;

  iunlock(ip);
  acquire(&cons.lock);
  for(i = 0; i < n; i++)
    consputc(buf[i] & 0xff);
  release(&cons.lock);
  ilock(ip);

  return n;
}

consoleinit(void)
kaashoek's avatar
kaashoek committed
{
rsc's avatar
 
rsc committed
  initlock(&cons.lock, "console");
  initlock(&input.lock, "input");
  devsw[CONSOLE].write = consolewrite;
  devsw[CONSOLE].read = consoleread;
rsc's avatar
 
rsc committed
  cons.locking = 1;
  picenable(IRQ_KBD);
  ioapicenable(IRQ_KBD, 0);
kaashoek's avatar
kaashoek committed
}