Skip to content
Snippets Groups Projects
console.c 8.25 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"
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, state = 0, c, locking = 0;
rsc's avatar
rsc committed
  uint *ap = (uint*)(void*)&fmt + 1;
rtm's avatar
rtm committed

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

rtm's avatar
rtm committed
  for(i = 0; fmt[i]; i++){
    c = fmt[i] & 0xff;
    if(state == 0){
      if(c == '%'){
        state = '%';
      } else {
        cons_putc(c);
rtm's avatar
rtm committed
      }
    } else if(state == '%'){
      if(c == 'd'){
        printint(*ap, 10, 1);
        ap++;
      } else if(c == 'x' || c == 'p'){
rtm's avatar
rtm committed
        printint(*ap, 16, 0);
        ap++;
rsc's avatar
rsc committed
      } else if(c == 's'){
        char *s = (char*)*ap;
        ap++;
rsc's avatar
rsc committed
        if(s == 0){
          cons_putc('0');
        }else{
          while(*s != 0){
            cons_putc(*s);
            s++;
          }
rsc's avatar
rsc committed
        }
rtm's avatar
rtm committed
      } else if(c == '%'){
        cons_putc(c);
rsc's avatar
rsc committed
      } else {
        // Unknown % sequence.  Print it 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
    release(&console_lock);
rtm's avatar
rtm committed
}

void
panic(char *s)
{
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
  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);

rsc's avatar
rsc committed
  for(i = 0; i < n; i++) {
    cons_putc(buf[i] & 0xff);
kaashoek's avatar
kaashoek committed
  }

kaashoek's avatar
kaashoek committed
  release(&console_lock);

kaashoek's avatar
kaashoek committed
  return n;
}

rsc's avatar
rsc committed
// This is i8042reg.h + kbdreg.h from NetBSD.
#define KBSTATP         0x64    // kbd controller status port(I)
#define KBS_DIB         0x01    // kbd data in buffer
#define KBDATAP         0x60    // kbd data port(I)
#define SHIFT           (1<<0)
#define CTL             (1<<1)
#define ALT             (1<<2)
#define CAPSLOCK        (1<<3)
#define NUMLOCK         (1<<4)
#define SCROLLLOCK      (1<<5)
#define E0ESC           (1<<6)

// Special keycodes
#define KEY_HOME        0xE0
#define KEY_END         0xE1
#define KEY_UP          0xE2
#define KEY_DN          0xE3
#define KEY_LF          0xE4
#define KEY_RT          0xE5
#define KEY_PGUP        0xE6
#define KEY_PGDN        0xE7
#define KEY_INS         0xE8
#define KEY_DEL         0xE9
rsc's avatar
rsc committed
static uchar shiftcode[256] =
  [0x1D] CTL,
  [0x2A] SHIFT,
  [0x36] SHIFT,
  [0x38] ALT,
  [0x9D] CTL,
  [0xB8] ALT
rsc's avatar
rsc committed
static uchar togglecode[256] =
  [0x3A] CAPSLOCK,
  [0x45] NUMLOCK,
  [0x46] SCROLLLOCK
};

static uchar normalmap[256] =
{
  NO,   0x1B, '1',  '2',  '3',  '4',  '5',  '6',  // 0x00
  '7',  '8',  '9',  '0',  '-',  '=',  '\b', '\t',
  'q',  'w',  'e',  'r',  't',  'y',  'u',  'i',  // 0x10
  'o',  'p',  '[',  ']',  '\n', NO,   'a',  's',
  'd',  'f',  'g',  'h',  'j',  'k',  'l',  ';',  // 0x20
  '\'', '`',  NO,   '\\', 'z',  'x',  'c',  'v',
  'b',  'n',  'm',  ',',  '.',  '/',  NO,   '*',  // 0x30
  NO,   ' ',  NO,   NO,   NO,   NO,   NO,   NO,
  NO,   NO,   NO,   NO,   NO,   NO,   NO,   '7',  // 0x40
  '8',  '9',  '-',  '4',  '5',  '6',  '+',  '1',
  '2',  '3',  '0',  '.',  NO,   NO,   NO,   NO,   // 0x50
rsc's avatar
rsc committed
  [0x97] KEY_HOME,
  [0x9C] '\n',      // KP_Enter
  [0xB5] '/',       // KP_Div
  [0xC8] KEY_UP,
  [0xC9] KEY_PGUP,
  [0xCB] KEY_LF,
  [0xCD] KEY_RT,
  [0xCF] KEY_END,
  [0xD0] KEY_DN,
  [0xD1] KEY_PGDN,
  [0xD2] KEY_INS,
  [0xD3] KEY_DEL
rsc's avatar
rsc committed
static uchar shiftmap[256] =
  NO,   033,  '!',  '@',  '#',  '$',  '%',  '^',  // 0x00
  '&',  '*',  '(',  ')',  '_',  '+',  '\b', '\t',
  'Q',  'W',  'E',  'R',  'T',  'Y',  'U',  'I',  // 0x10
  'O',  'P',  '{',  '}',  '\n', NO,   'A',  'S',
  'D',  'F',  'G',  'H',  'J',  'K',  'L',  ':',  // 0x20
  '"',  '~',  NO,   '|',  'Z',  'X',  'C',  'V',
  'B',  'N',  'M',  '<',  '>',  '?',  NO,   '*',  // 0x30
  NO,   ' ',  NO,   NO,   NO,   NO,   NO,   NO,
  NO,   NO,   NO,   NO,   NO,   NO,   NO,   '7',  // 0x40
  '8',  '9',  '-',  '4',  '5',  '6',  '+',  '1',
  '2',  '3',  '0',  '.',  NO,   NO,   NO,   NO,   // 0x50
rsc's avatar
rsc committed
  [0x97] KEY_HOME,
  [0x9C] '\n',      // KP_Enter
  [0xB5] '/',       // KP_Div
  [0xC8] KEY_UP,
  [0xC9] KEY_PGUP,
  [0xCB] KEY_LF,
  [0xCD] KEY_RT,
  [0xCF] KEY_END,
  [0xD0] KEY_DN,
  [0xD1] KEY_PGDN,
  [0xD2] KEY_INS,
  [0xD3] KEY_DEL
rsc's avatar
rsc committed
static uchar ctlmap[256] =
rsc's avatar
rsc committed
  NO,      NO,      NO,      NO,      NO,      NO,      NO,      NO,
  NO,      NO,      NO,      NO,      NO,      NO,      NO,      NO,
  C('Q'),  C('W'),  C('E'),  C('R'),  C('T'),  C('Y'),  C('U'),  C('I'),
  C('O'),  C('P'),  NO,      NO,      '\r',    NO,      C('A'),  C('S'),
rsc's avatar
rsc committed
  C('D'),  C('F'),  C('G'),  C('H'),  C('J'),  C('K'),  C('L'),  NO,
  NO,      NO,      NO,      C('\\'), C('Z'),  C('X'),  C('C'),  C('V'),
  C('B'),  C('N'),  C('M'),  NO,      NO,      C('/'),  NO,      NO,
  [0x97] KEY_HOME,
rsc's avatar
rsc committed
  [0xB5] C('/'),    // KP_Div
  [0xC8] KEY_UP,
  [0xC9] KEY_PGUP,
  [0xCB] KEY_LF,
  [0xCD] KEY_RT,
  [0xCF] KEY_END,
  [0xD0] KEY_DN,
  [0xD1] KEY_PGDN,
  [0xD2] KEY_INS,
  [0xD3] KEY_DEL
};

static uchar *charcode[4] = {
  normalmap,
  shiftmap,
  ctlmap,
  ctlmap
};

#define KBD_BUF 64
char kbd_buf[KBD_BUF];
int kbd_r;
int kbd_w;
struct spinlock kbd_lock;
kaashoek's avatar
kaashoek committed
static uint shift;
kaashoek's avatar
kaashoek committed
void
kbd_intr()
{
  uint st, data, c;
kaashoek's avatar
kaashoek committed

  acquire(&kbd_lock);
rsc's avatar
rsc committed
  if((st & KBS_DIB) == 0){
kaashoek's avatar
kaashoek committed
    release(&kbd_lock);
    return;
  }
  data = inb(KBDATAP);

rsc's avatar
rsc committed
  if(data == 0xE0) {
    shift |= E0ESC;
kaashoek's avatar
kaashoek committed
    release(&kbd_lock);
rsc's avatar
rsc committed
  } else if(data & 0x80) {
    // Key released
    data = (shift & E0ESC ? data : data & 0x7F);
    shift &= ~(shiftcode[data] | E0ESC);
kaashoek's avatar
kaashoek committed
    release(&kbd_lock);
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

  // xxx hack
rsc's avatar
rsc committed
  if(c == 0x0) {
kaashoek's avatar
kaashoek committed
    release(&kbd_lock);
    return;
  }

  if(((kbd_w + 1) % KBD_BUF) != kbd_r){
    kbd_buf[kbd_w++] = c;
    if(kbd_w >= KBD_BUF)
      kbd_w = 0;
    wakeup(&kbd_r);
  } else {
    cprintf("kbd overflow\n");
  }

  release(&kbd_lock);
}

int
console_read(int minor, char *dst, int n)
{
  uint target = n;

  acquire(&kbd_lock);

    sleep(&kbd_r, &kbd_lock);

  while(n > 0 && kbd_w != kbd_r){
kaashoek's avatar
kaashoek committed
    *dst = (kbd_buf[kbd_r]) & 0xff;
    cons_putc(*dst & 0xff);
    dst++;
    --n;
    kbd_r++;
    if(kbd_r >= KBD_BUF)
      kbd_r = 0;
  }

  release(&kbd_lock);

  return target - n;
}

void
console_init()
kaashoek's avatar
kaashoek committed
{
  initlock(&console_lock, "console");
  initlock(&kbd_lock, "kbd");

kaashoek's avatar
kaashoek committed
  devsw[CONSOLE].d_write = console_write;
  devsw[CONSOLE].d_read = console_read;
rsc's avatar
rsc committed
  ioapic_enable(IRQ_KBD, 0);
kaashoek's avatar
kaashoek committed
}