#include "types.h" #include "x86.h" #include "defs.h" #include "spinlock.h" #include "dev.h" #include "param.h" struct spinlock console_lock; int panicked = 0; int use_console_lock = 0; /* * 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) { int i; for (i = 0; !(inb(0x378+1) & 0x80) && i < 12800; i++) ; outb(0x378+0, c); outb(0x378+2, 0x08|0x04|0x01); outb(0x378+2, 0x08); } static void cons_putc(int c) { int crtport = 0x3d4; // io port of CGA ushort *crt = (ushort *) 0xB8000; // base of CGA memory int ind; if(panicked){ cli(); for(;;) ; } lpt_putc(c); // 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++; } if((ind / 80) >= 24){ // scroll up memmove(crt, crt + 80, sizeof(crt[0]) * (23 * 80)); 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); } void printint(int xx, int base, int sgn) { char buf[16]; char digits[] = "0123456789ABCDEF"; int i = 0, neg = 0; uint x; 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]); } /* * print to the console. only understands %d, %x, %p, %s. */ void cprintf(char *fmt, ...) { int i, state = 0, c, locking = 0; uint *ap = (uint *)(void*)&fmt + 1; if(use_console_lock){ locking = 1; acquire(&console_lock); } for(i = 0; fmt[i]; i++){ c = fmt[i] & 0xff; if(state == 0){ if(c == '%'){ state = '%'; } else { cons_putc(c); } } else if(state == '%'){ if(c == 'd'){ printint(*ap, 10, 1); ap++; } else if(c == 'x' || c == 'p'){ printint(*ap, 16, 0); ap++; } else if(c == 's'){ char *s = (char*)*ap; ap++; while(*s != 0){ cons_putc(*s); s++; } } else if(c == '%'){ cons_putc(c); } else { // Unknown % sequence. Print it to draw attention. cons_putc('%'); cons_putc(c); } state = 0; } } if(locking) release(&console_lock); } void panic(char *s) { __asm __volatile("cli"); use_console_lock = 0; cprintf("panic (%d): ", cpu()); cprintf(s, 0); cprintf("\n", 0); panicked = 1; // freeze other CPU for(;;) ; } int console_write (int minor, char *buf, int n) { int i; acquire(&console_lock); for (i = 0; i < n; i++) { cons_putc(buf[i] & 0xff); } release(&console_lock); return n; } /* 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 NO 0 #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 static uchar shiftcode[256] = { [0x1D] CTL, [0x2A] SHIFT, [0x36] SHIFT, [0x38] ALT, [0x9D] CTL, [0xB8] ALT }; 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 [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 }; 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 [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 }; #define C(x) (x - '@') static uchar ctlmap[256] = { 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'), 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, [0xB5] C('/'), [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; static uint shift; void kbd_intr() { uint st, data, c; acquire(&kbd_lock); st = inb(KBSTATP); if ((st & KBS_DIB) == 0){ release(&kbd_lock); return; } data = inb(KBDATAP); if (data == 0xE0) { shift |= E0ESC; release(&kbd_lock); return; } else if (data & 0x80) { // Key released data = (shift & E0ESC ? data : data & 0x7F); shift &= ~(shiftcode[data] | E0ESC); release(&kbd_lock); return; } 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]; if (shift & CAPSLOCK) { if ('a' <= c && c <= 'z') c += 'A' - 'a'; else if ('A' <= c && c <= 'Z') c += 'a' - 'A'; } // xxx hack if (c == 0x0) { 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); while(kbd_w == kbd_r) sleep(&kbd_r, &kbd_lock); while(n > 0 && kbd_w != kbd_r){ *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() { initlock(&console_lock, "console"); initlock(&kbd_lock, "kbd"); devsw[CONSOLE].d_write = console_write; devsw[CONSOLE].d_read = console_read; ioapic_enable (IRQ_KBD, 1); use_console_lock = 1; }