xv6/console.c

306 lines
5.4 KiB
C
Raw Normal View History

2007-08-28 19:04:36 +00:00
// Console input and output.
// Input is from the keyboard only.
// Output is written to the screen and the printer port.
#include "types.h"
2006-06-12 15:22:12 +00:00
#include "defs.h"
2007-08-27 23:26:33 +00:00
#include "param.h"
#include "traps.h"
#include "spinlock.h"
#include "dev.h"
2006-09-07 16:52:13 +00:00
#include "mmu.h"
2007-08-08 10:29:42 +00:00
#include "proc.h"
2007-08-27 23:26:33 +00:00
#include "x86.h"
2007-08-24 20:28:08 +00:00
#define CRTPORT 0x3d4
#define LPTPORT 0x378
#define BACKSPACE 0x100
2007-08-24 20:28:08 +00:00
static ushort *crt = (ushort*)0xb8000; // CGA memory
static struct spinlock console_lock;
2006-07-17 01:25:22 +00:00
int panicked = 0;
int use_console_lock = 0;
2006-06-12 15:22:12 +00:00
2006-09-06 17:50:20 +00:00
// Copy console output to parallel port, which you can tell
// .bochsrc to copy to the stdout:
// parport1: enabled=1, file="/dev/stdout"
2006-06-22 15:51:57 +00:00
static void
lpt_putc(int c)
{
int i;
2006-06-22 15:51:57 +00:00
2007-08-24 20:28:08 +00:00
for(i = 0; !(inb(LPTPORT+1) & 0x80) && i < 12800; i++)
;
if(c == BACKSPACE)
c = '\b';
2007-08-24 20:28:08 +00:00
outb(LPTPORT+0, c);
outb(LPTPORT+2, 0x08|0x04|0x01);
outb(LPTPORT+2, 0x08);
2006-06-22 15:51:57 +00:00
}
static void
cga_putc(int c)
2006-06-12 15:22:12 +00:00
{
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){
if(pos > 0)
crt[--pos] = ' ' | 0x0700;
2007-08-28 18:37:41 +00:00
} 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;
}
2006-06-12 15:22:12 +00:00
2007-08-30 18:21:35 +00:00
void
cons_putc(int c)
{
2006-07-17 01:25:22 +00:00
if(panicked){
cli();
2006-07-17 01:25:22 +00:00
for(;;)
;
}
2006-06-22 15:51:57 +00:00
lpt_putc(c);
cga_putc(c);
}
2006-06-12 15:22:12 +00:00
void
printint(int xx, int base, int sgn)
{
2007-08-24 20:28:08 +00:00
static char digits[] = "0123456789ABCDEF";
2006-06-12 15:22:12 +00:00
char buf[16];
int i = 0, neg = 0;
uint x;
2006-09-06 17:27:19 +00:00
2006-06-12 15:22:12 +00:00
if(sgn && xx < 0){
neg = 1;
x = 0 - xx;
2007-08-28 18:37:41 +00:00
} else {
2006-06-12 15:22:12 +00:00
x = xx;
}
2007-08-28 18:32:08 +00:00
do{
2006-06-12 15:22:12 +00:00
buf[i++] = digits[x % base];
2007-08-28 18:32:08 +00:00
}while((x /= base) != 0);
2006-06-12 15:22:12 +00:00
if(neg)
buf[i++] = '-';
while(--i >= 0)
cons_putc(buf[i]);
2006-06-12 15:22:12 +00:00
}
2007-08-28 18:23:48 +00:00
// Print to the console. only understands %d, %x, %p, %s.
2006-06-12 15:22:12 +00:00
void
cprintf(char *fmt, ...)
{
int i, c, state, locking;
uint *argp;
char *s;
2006-06-12 15:22:12 +00:00
locking = use_console_lock;
if(locking)
acquire(&console_lock);
argp = (uint*)(void*)&fmt + 1;
state = 0;
2006-06-12 15:22:12 +00:00
for(i = 0; fmt[i]; i++){
c = fmt[i] & 0xff;
switch(state){
case 0:
if(c == '%')
2006-06-12 15:22:12 +00:00
state = '%';
else
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);
break;
2006-06-12 15:22:12 +00:00
}
state = 0;
break;
2006-06-12 15:22:12 +00:00
}
}
if(locking)
release(&console_lock);
2006-06-12 15:22:12 +00:00
}
int
console_write(struct inode *ip, char *buf, int n)
{
int i;
iunlock(ip);
acquire(&console_lock);
for(i = 0; i < n; i++)
cons_putc(buf[i] & 0xff);
release(&console_lock);
ilock(ip);
return n;
}
#define INPUT_BUF 128
struct {
struct spinlock lock;
char buf[INPUT_BUF];
int r; // Read index
int w; // Write index
int e; // Edit index
} input;
2007-08-28 04:13:40 +00:00
#define C(x) ((x)-'@') // Control-x
void
console_intr(int (*getc)(void))
{
int c;
acquire(&input.lock);
while((c = getc()) >= 0){
switch(c){
case C('P'): // Process listing.
procdump();
break;
case C('U'): // Kill line.
while(input.e > input.w &&
input.buf[(input.e-1) % INPUT_BUF] != '\n'){
input.e--;
cons_putc(BACKSPACE);
}
break;
case C('H'): // Backspace
if(input.e > input.w){
input.e--;
cons_putc(BACKSPACE);
}
break;
default:
if(c != 0 && input.e < input.r+INPUT_BUF){
2007-08-30 18:20:53 +00:00
input.buf[input.e++ % INPUT_BUF] = c;
cons_putc(c);
if(c == '\n' || c == C('D') || input.e == input.r+INPUT_BUF){
input.w = input.e;
wakeup(&input.r);
}
}
break;
2006-09-07 15:45:38 +00:00
}
}
release(&input.lock);
}
int
console_read(struct inode *ip, char *dst, int n)
{
uint target;
int c;
iunlock(ip);
target = n;
acquire(&input.lock);
while(n > 0){
while(input.r == input.w){
2007-08-10 16:37:27 +00:00
if(cp->killed){
release(&input.lock);
ilock(ip);
2007-08-08 10:29:42 +00:00
return -1;
}
sleep(&input.r, &input.lock);
2007-08-08 10:29:42 +00:00
}
2007-08-30 18:20:53 +00:00
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;
}
*dst++ = c;
--n;
if(c == '\n')
break;
}
release(&input.lock);
ilock(ip);
return target - n;
}
void
2007-08-08 09:32:39 +00:00
console_init(void)
{
initlock(&console_lock, "console");
initlock(&input.lock, "console input");
2006-09-07 13:08:23 +00:00
devsw[CONSOLE].write = console_write;
devsw[CONSOLE].read = console_read;
2007-09-27 12:29:25 +00:00
use_console_lock = 1;
2007-08-28 19:04:36 +00:00
pic_enable(IRQ_KBD);
2006-09-06 17:27:19 +00:00
ioapic_enable(IRQ_KBD, 0);
}
void
panic(char *s)
{
int i;
uint pcs[10];
__asm __volatile("cli");
use_console_lock = 0;
cprintf("panic (%d): ", cpu());
cprintf(s, 0);
cprintf("\n", 0);
getcallerpcs(&s, pcs);
for(i=0; i<10; i++)
cprintf(" %p", pcs[i]);
panicked = 1; // freeze other CPU
for(;;)
;
}