Skip to content
Snippets Groups Projects
console.c 5.32 KiB
Newer Older
#include "types.h"
#include "x86.h"
kaashoek's avatar
kaashoek committed
#include "traps.h"
rtm's avatar
rtm committed
#include "defs.h"
rtm's avatar
rtm committed
#include "spinlock.h"
kaashoek's avatar
kaashoek committed
#include "dev.h"
rsc's avatar
rsc committed
#include "mmu.h"
#include "proc.h"
#include "kbd.h"
rtm's avatar
rtm committed

struct spinlock console_lock;
rsc's avatar
rsc committed
int panicked = 0;
rtm's avatar
rtm committed
int use_console_lock = 0;
rtm's avatar
rtm committed

rsc's avatar
rsc committed
// Copy console output to parallel port, which you can tell
// .bochsrc to copy to the stdout:
//   parport1: enabled=1, file="/dev/stdout"
static void
lpt_putc(int c)
{
rsc's avatar
rsc committed
  for(i = 0; !(inb(0x378+1) & 0x80) && i < 12800; i++)
    ;
  outb(0x378+0, c);
  outb(0x378+2, 0x08|0x04|0x01);
  outb(0x378+2, 0x08);
rtm's avatar
rtm committed
static void
cons_putc(int c)
rtm's avatar
rtm committed
{
  int crtport = 0x3d4; // io port of CGA
rsc's avatar
rsc committed
  ushort *crt = (ushort*) 0xB8000; // base of CGA memory
rtm's avatar
rtm committed
  int ind;

rsc's avatar
rsc committed
  if(panicked){
rtm's avatar
rtm committed
    cli();
rsc's avatar
rsc committed
    for(;;)
rtm's avatar
rtm committed
      ;
  }
rtm's avatar
rtm committed

  lpt_putc(c);

rtm's avatar
rtm committed
  // cursor position, 16 bits, col + 80*row
  outb(crtport, 14);
  ind = inb(crtport + 1) << 8;
  outb(crtport, 15);
  ind |= inb(crtport + 1);

  c &= 0xff;
  if(c == '\n'){
    ind -= (ind % 80);
    ind += 80;
  } else {
    c |= 0x0700; // black on white
    crt[ind] = c;
    ind++;
rtm's avatar
rtm committed
  }

  if((ind / 80) >= 24){
    // scroll up
rsc's avatar
 
rsc committed
    memmove(crt, crt + 80, sizeof(crt[0]) * (23 * 80));
rtm's avatar
rtm committed
    ind -= 80;
    memset(crt + ind, 0, sizeof(crt[0]) * ((24 * 80) - ind));
  }

  outb(crtport, 14);
  outb(crtport + 1, ind >> 8);
  outb(crtport, 15);
  outb(crtport + 1, ind);
rtm's avatar
rtm committed
}
rtm's avatar
rtm committed

rtm's avatar
rtm committed
void
printint(int xx, int base, int sgn)
{
  char buf[16];
  char digits[] = "0123456789ABCDEF";
  int i = 0, neg = 0;
rtm's avatar
rtm committed
  if(sgn && xx < 0){
    neg = 1;
    x = 0 - xx;
  } else {
    x = xx;
  }

  do {
    buf[i++] = digits[x % base];
  } while((x /= base) != 0);
  if(neg)
    buf[i++] = '-';

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

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

  locking = use_console_lock;
  if(locking)
rtm's avatar
rtm committed
    acquire(&console_lock);

  argp = (uint*)(void*)&fmt + 1;
  state = 0;
rtm's avatar
rtm committed
  for(i = 0; fmt[i]; i++){
    c = fmt[i] & 0xff;
    switch(state){
    case 0:
      if(c == '%')
rtm's avatar
rtm committed
        state = '%';
        cons_putc(c);
      break;
    
    case '%':
      switch(c){
      case 'd':
        printint(*argp++, 10, 1);
        break;
      case 'x':
      case 'p':
        printint(*argp++, 16, 0);
        break;
      case 's':
        s = (char*)*argp++;
        if(s == 0)
          s = "(null)";
        for(; *s; s++)
          cons_putc(*s);
        break;
      case '%':
        cons_putc('%');
        break;
      default:
        // Print unknown % sequence to draw attention.
        cons_putc('%');
        cons_putc(c);
rtm's avatar
rtm committed
      }
      state = 0;
rtm's avatar
rtm committed
    }
  }
rtm's avatar
rtm committed

rtm's avatar
rtm committed
    release(&console_lock);
rtm's avatar
rtm committed
}

void
panic(char *s)
{
rsc's avatar
rsc committed
  int i;
  uint pcs[10];
  
rtm's avatar
rtm committed
  __asm __volatile("cli");
  use_console_lock = 0;
kaashoek's avatar
kaashoek committed
  cprintf("panic (%d): ", cpu());
rtm's avatar
rtm committed
  cprintf(s, 0);
  cprintf("\n", 0);
rsc's avatar
rsc committed
  getcallerpcs(&s, pcs);
  for(i=0; i<10; i++)
    cprintf(" %p", pcs[i]);
rsc's avatar
rsc committed
  panicked = 1; // freeze other CPU
  for(;;)
rtm's avatar
rtm committed
    ;
}
kaashoek's avatar
kaashoek committed

int
rsc's avatar
rsc committed
console_write(int minor, char *buf, int n)
kaashoek's avatar
kaashoek committed
{
  int i;

kaashoek's avatar
kaashoek committed
  acquire(&console_lock);
  for(i = 0; i < n; i++)
    cons_putc(buf[i] & 0xff);
kaashoek's avatar
kaashoek committed
  release(&console_lock);

kaashoek's avatar
kaashoek committed
  return n;
}

#define KBD_BUF 64
struct {
  uchar buf[KBD_BUF];
  int r;
  int w;
  struct spinlock lock;
} kbd;
kaashoek's avatar
kaashoek committed
void
rsc's avatar
rsc committed
kbd_intr(void)
  static uint shift;
  static uchar *charcode[4] = {
    normalmap,
    shiftmap,
    ctlmap,
    ctlmap
  };
  uint st, data, c;
kaashoek's avatar
kaashoek committed

rsc's avatar
rsc committed
  acquire(&kbd.lock);
rsc's avatar
rsc committed
  if((st & KBS_DIB) == 0)
    goto out;
  data = inb(KBDATAP);

rsc's avatar
rsc committed
  if(data == 0xE0) {
    shift |= E0ESC;
rsc's avatar
rsc committed
    goto out;
rsc's avatar
rsc committed
  } else if(data & 0x80) {
    // Key released
    data = (shift & E0ESC ? data : data & 0x7F);
    shift &= ~(shiftcode[data] | E0ESC);
rsc's avatar
rsc committed
    goto out;
rsc's avatar
rsc committed
  } else if(shift & E0ESC) {
    // Last character was an E0 escape; or with 0x80
    data |= 0x80;
    shift &= ~E0ESC;
  }
  shift |= shiftcode[data];
  shift ^= togglecode[data];
  c = charcode[shift & (CTL | SHIFT)][data];
rsc's avatar
rsc committed
  if(shift & CAPSLOCK) {
    if('a' <= c && c <= 'z')
      c += 'A' - 'a';
rsc's avatar
rsc committed
    else if('A' <= c && c <= 'Z')
kaashoek's avatar
kaashoek committed

rsc's avatar
rsc committed
  switch(c){
  case 0:
    // Ignore unknown keystrokes.
    break;
  
  case C('T'):
    cprintf("#");  // Let user know we're still alive.
    break;
  
  case C('P'):
    procdump();
    break;

  default:
rsc's avatar
rsc committed
    if(((kbd.w + 1) % KBD_BUF) != kbd.r){
      kbd.buf[kbd.w++] = c;
      if(kbd.w >= KBD_BUF)
        kbd.w = 0;
      wakeup(&kbd.r);
rsc's avatar
rsc committed
    }
    break;
rsc's avatar
rsc committed
out:
rsc's avatar
rsc committed
  release(&kbd.lock);
//PAGEBREAK: 25
int
console_read(int minor, char *dst, int n)
{
  uint target;
  int c;
  acquire(&kbd.lock);
  while(n > 0){
    while(kbd.r == kbd.w){
rsc's avatar
rsc committed
      if(cp->killed){
        release(&kbd.lock);
        return -1;
      }
      sleep(&kbd.r, &kbd.lock);
    c = kbd.buf[kbd.r++];
    if(c == C('D')){  // EOF
      if(n < target){
        // Save ^D for next time, to make sure
        // caller gets a 0-byte result.
        kbd.r--;
      }
      break;
    }
    *dst++ = c;
    cons_putc(c);
    if(kbd.r >= KBD_BUF)
      kbd.r = 0;
  release(&kbd.lock);
rsc's avatar
rsc committed
console_init(void)
kaashoek's avatar
kaashoek committed
{
  initlock(&console_lock, "console");
  initlock(&kbd.lock, "kbd");
rsc's avatar
rsc committed
  devsw[CONSOLE].write = console_write;
  devsw[CONSOLE].read = console_read;
  use_console_lock = 1;
rsc's avatar
rsc committed
  irq_enable(IRQ_KBD);
rsc's avatar
rsc committed
  ioapic_enable(IRQ_KBD, 0);
kaashoek's avatar
kaashoek committed
}