[eros-cvs] cvs commit: eros/src/base/sys/kerninc KernStream.hxx
shap@eros.cs.jhu.edu
shap@eros.cs.jhu.edu
Sun, 25 Nov 2001 20:31:11 -0500
shap 01/11/25 20:31:11
Added: src/base/sys/arch/i486/kernel ConsoleStream.cxx
SerialStream.cxx
src/base/sys/kernel kern_KernStream.cxx kern_LogStream.cxx
kern_printf.cxx
src/base/sys/kerninc KernStream.hxx
Log:
These should have been checked in with the last commit
Revision Changes Path
1.1 eros/src/base/sys/arch/i486/kernel/ConsoleStream.cxx
Index: ConsoleStream.cxx
===================================================================
/*
* Copyright (C) 2001, Jonathan S. Shapiro.
*
* This file is part of the EROS Operating System.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* This is a (poor) implementation of a text-mode kernel frame buffer
* for use in diagnostics and debugger output. It assumes that the
* display has been left in the standard VGA text mode by the
* bootstrap code. */
#include <kerninc/kernel.hxx>
#include <kerninc/KernStream.hxx>
#include <kerninc/Machine.hxx>
#include <kerninc/IRQ.hxx>
#include <kerninc/util.h>
#include <eros/i486/io.h>
#include <eros/i486/fixregs.h>
#include "IDT.hxx"
#define SCREEN_START PTOV(0xb8000u)
#define SCREEN_ROWS 25
#define SCREEN_COLS 80
#define SCREEN_END (SCREEN_START + 2*SCREEN_COLS*SCREEN_ROWS)
/* This class has a singleton instance! */
struct ConsoleStream: public KernStream {
void Init();
void Put(uint8_t c);
#ifdef OPTION_DDB
uint8_t Get();
void SetDebugging(bool onoff);
void EnableDebuggerInput();
#endif
};
struct ConsoleStream TheConsoleStream;
KernStream* KernStream::ConsoleStream = &TheConsoleStream;
static void ClearTextConsole();
static unsigned long offset;
static uint32_t StartAddressReg = 0; /* as seen by the display hardware */
static uint16_t *screen = (uint16_t *) SCREEN_START;
void
ConsoleStream::Init()
{
outb(0xc, 0x3d4); /* start address hi register addr */
uint8_t hi = inb(0x3d5);
outb(0xd, 0x3d4); /* start address lo register addr */
uint8_t lo = inb(0x3d5);
StartAddressReg = hi << 8 | lo;
offset = 0;
ClearTextConsole();
}
enum VGAColors {
Black = 0,
Blue = 1,
Green = 2,
Cyan = 3,
Red = 4,
Magenta = 5,
Brown = 6,
White = 7,
Gray = 8,
LightBlue = 9,
LightGreen = 10,
LightCyan = 11,
LightRed = 12,
LightMagenta = 13,
LightBrown = 14, /* yellow */
BrightWhite = 15,
/* Combinations used by the console driver: */
WhiteOnBlack = 0x7,
blank = 0,
};
static void
SetPosition(uint32_t pos, uint8_t c)
{
uint16_t vgaAttrs = WhiteOnBlack << 8;
screen[pos] = ((uint16_t) c) | vgaAttrs;
}
static void
ShowCursorAt(uint32_t pos)
{
uint32_t cursAddr = (uint32_t) pos;
cursAddr += StartAddressReg;
outb(0xE, 0x3D4);
outb((cursAddr >> 8) & 0xFFu, 0x3D5);
outb(0xF, 0x3D4);
outb((cursAddr & 0xFFu), 0x3D5);
}
static void
Scroll(uint32_t startPos, uint32_t endPos, int amount)
{
if (amount > 0) {
uint32_t gap = amount;
for (uint32_t p = startPos + gap; p < endPos; p++)
screen[p] = screen[p - gap];
for (uint32_t p = startPos; p < startPos + gap; p++)
screen[p] = (WhiteOnBlack << 8);
}
else {
uint32_t gap = -amount;
for (uint32_t p = startPos; p < endPos - gap; p++)
screen[p] = screen[p + gap];
for (uint32_t p = endPos - gap; p < endPos; p++)
screen[p] = (WhiteOnBlack << 8);
}
}
static void
ClearTextConsole()
{
for (uint32_t wpos = 0; wpos < SCREEN_ROWS * SCREEN_COLS; wpos++)
SetPosition(wpos, ' ');
}
static void Beep() {}
/* FIX: This is NOT RIGHT!! */
void
ConsoleStream::Put(uint8_t c)
{
const unsigned cols = SCREEN_COLS;
const unsigned rows = SCREEN_ROWS;
const int TABSTOP = 8;
uint32_t posCol = offset % cols;
/* On newline, clear to EOL: */
if (c == ASCII::CR)
if (offset % cols) Scroll (offset, offset + (cols - posCol), (cols - posCol));
if (IsPrint(c)) {
SetPosition(offset, c);
offset++;
}
else {
/* Handle the non-printing characters: */
switch(c) {
case ASCII::BEL:
Beep();
break;
case ASCII::BS: /* backspace is NONDESTRUCTIVE */
if ( offset % cols )
offset--;
break;
case ASCII::TAB: /* NONDESTRUCTIVE until we know how */
while (offset % TABSTOP) {
SetPosition(offset, ' ');
offset++;
}
break;
case ASCII::LF:
offset += cols;
break;
case ASCII::VT: /* reverse line feed */
if (offset > cols)
offset -= cols;
break;
#if 0
case ASCII::FF: /* reverse line feed */
offset = 0;
ClearScreen();
break;
#endif
case ASCII::CR:
offset -= (offset % cols);
break;
}
}
if (offset >= rows * cols) {
Scroll(0, rows * cols, - (int) cols);
offset -= cols;
}
assert (offset < rows * cols);
ShowCursorAt(offset);
return;
}
/*************************************************************************
*
* EVERYTHING FROM HERE DOWN IS KEYBOARD DRIVER!!!!
*
* The keyboard logic is enabled only if the debugger is running on
* the console.
*
*************************************************************************/
#if defined(OPTION_DDB_ON_CONSOLE)
const uint8_t KbdDataPort = 0x60u;
const uint8_t KbdCtrlPort = 0x64u;
const uint8_t KbdStatusPort = 0x64u;
struct KeyCmd {
enum {
SetLed = 0xedu,
} ;
};
struct KbdStatus {
enum {
BufFull = 0x1,
Ready = 0x2,
};
};
struct KeyMod {
enum {
/* Note that the first three values correspond to the bitmask for the
* keyboard LED's -- this is not an accident!
*/
ScrlLock = 0x01u,
NumLock = 0x02u,
AlphaLock = 0x04u,
Shift = 0x10u,
Ctrl = 0x20u,
Alt = 0x40u,
Extended = 0x100u, /* key is an "extended" key */
IsAlpha = 0x200u, /* key is modified by alpha lock key */
IsPad = 0x400u, /* key is modified by num lock key */
Meta = 0x800u, /* key can be meta'd */
} ;
};
static uint32_t ShiftState = 0;
/* kbd_wait -- wait for a character to be available from the keyboard. */
static void
KbdWait(void)
{
int i = 100;
while (i--) {
if ((inb(KbdStatusPort) & KbdStatus::Ready) == 0)
break;
Machine::SpinWaitUs(10);
}
#if 0
printf("KbdWait fails\n");
#endif
}
static void
KbdCmd(uint8_t command)
{
int retry = 5;
do {
int i = 100000;
KbdWait();
old_outb(KbdDataPort, command);
while (i--) {
if (inb(KbdStatusPort) & KbdStatus::BufFull) {
int val;
/* DELAY(10); */
val = inb(KbdDataPort);
if (val == 0xfa)
return;
if (val == 0xfe)
break;
}
}
} while (retry--);
printf("KbdCmd fails\n");
}
static bool
ReadKbd(uint8_t& c)
{
KbdWait();
while ( (inb(KbdStatusPort) & KbdStatus::BufFull) == 0 )
return false;
c = inb(KbdDataPort);
return true;
}
static void
UpdateKbdLeds()
{
KbdCmd(KeyCmd::SetLed);
KbdCmd(ShiftState & 0x7u);
}
/* Keyboard interpretation proceeds in two phases. First, the scan
* code is converted into a virtual key code, performing any necessary
* keyboard escape translation. Then the key code translation table
* is consulted to decide what character to return and whether to
* update the shift state (if at all).
*/
#define NOP 256
#define NOCHAR(name) {{ NOP, NOP, NOP, NOP }, 0 }
#define ALPHA(X) {{ X+32, X, X - 64, X - 64 }, KeyMod::Meta|KeyMod::IsAlpha }
#define KEY(X, Y) {{ X, Y, X, Y }, KeyMod::Meta }
#define PAD(X, Y) {{ X, Y, X, Y }, KeyMod::IsPad }
#define F(X) (X + 256)
const uint32_t num_scan = 0x59;
struct KeyInfo {
uint16_t value[4]; /* base, shift, ctrl, shift-ctrl */
uint16_t flags;
} key_table[num_scan] = {
NOCHAR(None), /* 0x00 */
KEY('\027', '\027'), /* 0x01 */
KEY('1', '!'), /* 0x02 */
{ { '2', '@', '\0', '\0'}, 0 }, /* 0x03 -- generate NUL */
KEY('3', '#'), /* 0x04 */
KEY('4', '$'), /* 0x05 */
KEY('5', '%'), /* 0x06 */
KEY('6', '^'), /* 0x07 */
KEY('7', '&'), /* 0x08 */
KEY('8', '*'), /* 0x09 */
KEY('9', '('), /* 0x0a */
KEY('0', ')'), /* 0x0b */
KEY('-', '_'), /* 0x0c */
KEY('=', '+'), /* 0x0d */
KEY(0x08, 0x08), /* 0x0e */
KEY(0x09, 0x08), /* 0x0f -- is back tab right? */
ALPHA('Q'), /* 0x10 */
ALPHA('W'), /* 0x11 */
ALPHA('E'), /* 0x12 */
ALPHA('R'), /* 0x13 */
ALPHA('T'), /* 0x14 */
ALPHA('Y'), /* 0x15 */
ALPHA('U'), /* 0x16 */
ALPHA('I'), /* 0x17 */
ALPHA('O'), /* 0x18 */
ALPHA('P'), /* 0x19 */
KEY('[', '{'), /* 0x1a */
KEY(']', '}'), /* 0x1b */
KEY('\r', '\r'), /* 0x1c -- enter */
{ { NOP, NOP, NOP, NOP }, KeyMod::Ctrl }, /* 0x1d -- lctrl */
ALPHA('A'), /* 0x1e */
ALPHA('S'), /* 0x1f */
ALPHA('D'), /* 0x20 */
ALPHA('F'), /* 0x21 */
ALPHA('G'), /* 0x22 */
ALPHA('H'), /* 0x23 */
ALPHA('J'), /* 0x24 */
ALPHA('K'), /* 0x25 */
ALPHA('L'), /* 0x26 */
KEY(';', ':'), /* 0x27 */
KEY('\'', '"'), /* 0x28 */
KEY('`', '~'), /* 0x29 */
{ { NOP, NOP, NOP, NOP }, KeyMod::Shift }, /* 0x2a -- lshift */
KEY('\\', '|'), /* 0x2b */
ALPHA('Z'), /* 0x2c */
ALPHA('X'), /* 0x2d */
ALPHA('C'), /* 0x2e */
ALPHA('V'), /* 0x2f */
ALPHA('B'), /* 0x30 */
ALPHA('N'), /* 0x31 */
ALPHA('M'), /* 0x32 */
KEY(',', '<'), /* 0x33 */
KEY('.', '>'), /* 0x34 */
KEY('/', '?'), /* 0x35 */
{ { NOP, NOP, NOP, NOP }, KeyMod::Shift }, /* 0x36 -- rshift */
KEY('*', '*'), /* 0x37 */
{ { NOP, NOP, NOP, NOP }, KeyMod::Alt }, /* 0x38 -- lalt */
KEY(' ', ' '), /* 0x39 -- space */
{ { NOP, NOP, NOP, NOP }, KeyMod::AlphaLock }, /* 0x3a -- alpha lock */
KEY( F(1), NOP ), /* 0x3b -- F1 */
KEY( F(2), NOP ), /* 0x3c -- F2 */
KEY( F(3), NOP ), /* 0x3d -- F3 */
KEY( F(4), NOP ), /* 0x3e -- F4 */
KEY( F(5), NOP ), /* 0x3f -- F5 */
KEY( F(6), NOP ), /* 0x40 -- F6 */
KEY( F(7), NOP ), /* 0x41 -- F7 */
KEY( F(8), NOP ), /* 0x42 -- F8 */
KEY( F(9), NOP ), /* 0x43 -- F9 */
KEY( F(10), NOP ), /* 0x44 -- F10 */
{ { NOP, NOP, NOP, NOP }, KeyMod::NumLock }, /* 0x45 -- num lock */
{ { NOP, NOP, NOP, NOP }, KeyMod::ScrlLock }, /* 0x46 -- scroll-lock */
/* Keypad character mappings -- these assume that num-lock is NOT set! */
PAD( F(15), '7' ), /* 0x47 -- keypad 7 */
PAD( F(16), '8' ), /* 0x48 -- keypad 8 */
PAD( F(17), '9' ), /* 0x49 -- keypad 9 */
KEY( '-', NOP ), /* 0x4a -- keypad - */
PAD( F(19), '4' ), /* 0x4b -- keypad 4 */
PAD( NOP, '5' ), /* 0x4c -- keypad 5 */
PAD( F(20), '6' ), /* 0x4d -- keypad 6 */
KEY( '+', '+' ), /* 0x4e -- keypad + */
PAD( F(22), '1' ), /* 0x4f -- keypad 1 */
PAD( F(23), '2' ), /* 0x50 -- keypad 2 */
PAD( F(24), '3' ), /* 0x51 -- keypad 3 */
PAD( F(25), '0' ), /* 0x52 -- keypad 0 */
PAD( 0x7f, '.' ), /* 0x53 -- keypad ./DEL */
KEY( NOP, NOP ), /* 0x54 -- unused! */
KEY( NOP, NOP ), /* 0x55 -- unused! */
KEY( NOP, NOP ), /* 0x56 -- unused! */
KEY( F(11), NOP ), /* 0x57 -- F11 */
KEY( F(12), NOP ), /* 0x58 -- F12 */
#if 0
/* CHARACTERS BELOW THIS POINT ARE RECODED!!! */
{ { NOP, NOP, NOP, NOP }, KeyMod::Ctrl }, /* 0x59 rctrl */
{ { NOP, NOP, NOP, NOP }, KeyMod::Alt }, /* 0x5a ralt */
e0,1c kpd-enter
e0,1d rctrl SUPPRESSED
e0,35 kpd-/
e0,37 print-screen
e0,38 ralt SUPPRESSED
e0,47 home
e0,48 uparrow
e0,49 PgUp
e0,4b left-arrow
e0,4d right-arrow
e0,4f end
e0,50 downarrow
e0,51 PgDn
e0,52 insert
e0,53 delete
e0,5b lwindow
e0,5c rwindow
e0,5d menu
e1,1d,68 pause
#endif
};
static uint32_t
FetchInputFromKeyboard()
{
static uint8_t esc_code = 0;
uint8_t scanCode = 0;
while ( ReadKbd(scanCode) ) {
/* printf("<kc = %x>", scanCode); */
bool shift = ShiftState & KeyMod::Shift;
#if 0
bool alt = ShiftState & KeyMod::Alt;
#endif
bool ctrl = ShiftState & KeyMod::Ctrl;
/* If this is a break character, we need to know: */
bool isBreak = scanCode & 0x80u;
uint32_t keyCode = scanCode & 0x7fu;
switch (esc_code) {
case 0x0:
{
/* printf("esc_code==0\n"); */
switch (scanCode) {
case 0xe0:
case 0xe1:
esc_code = scanCode;
continue;
default:
if (keyCode >= num_scan) {
printf("<? 0x0 \\x%x>", keyCode);
return NOP;
}
}
break;
}
case 0xe0:
{
switch (keyCode) {
case 0x2a: /* shift hack used by some keyboards */
/* for extra keys! */
shift = ! shift;
case 0x1c: /* kpd-enter */
case 0x1d: /* rctrl */
case 0x35: /* kpd-/ */
case 0x38: /* ralt */
case 0x47: /* home */
case 0x48: /* uparrow */
case 0x49: /* pgup */
case 0x4b: /* left-arrow */
case 0x4d: /* right-arrow */
case 0x4f: /* end */
case 0x50: /* down-arrow */
case 0x51: /* pgdn */
case 0x52: /* insert */
case 0x53: /* del */
esc_code = 0;
break;
case 0x5b: /* lwindow */
case 0x5c: /* rwindow */
case 0x5d: /* menu */
/* consume these transparently: */
esc_code = 0;
return NOP;
default:
printf("<? 0xe0 \\x%x>", scanCode);
esc_code = 0;
return NOP;
}
break;
}
case 0xe1:
{
if (keyCode == 0x1d) {
esc_code = scanCode;
continue;
}
else {
esc_code = 0;
printf("<? 0xe1 \\x%x>", scanCode);
return NOP;
}
break;
}
case 0x1d:
{
if (keyCode == 0x68) {
/* consume transparently */
esc_code = 0;
return NOP;
}
else {
printf("<? 0x1d \\x%x>", scanCode);
esc_code = 0;
return NOP;
}
break;
}
default:
printf("Unknown escape 0x%x\n", esc_code);
break;
}
/* printf("Key code is %d (0x%x)\n", keyCode, keyCode); */
KeyInfo& ki = key_table[keyCode];
/* printf("<kf=\\x%x,0x%x>", keyCode, ki.flags); */
if ( (ki.flags & KeyMod::IsAlpha) &&
(ShiftState & KeyMod::AlphaLock) )
shift = !shift;
if ( (ki.flags & KeyMod::IsPad) &&
(ShiftState & KeyMod::NumLock) )
shift = !shift;
uint32_t ndx = (shift ? 1 : 0) + (ctrl ? 2 : 0);
uint32_t ascii = ki.value[ndx];
/* keep track of shift, ctrl, alt */
if (isBreak)
ShiftState &= ~ (ki.flags & 0xf0u);
else {
ShiftState |= (ki.flags & 0xf0u);
}
/* keep track of the various lock keys on the break, not the
* keypress - the break doesn't repeat. These are toggles, thus
* the XOR:
*/
if (isBreak && (ki.flags & 0xfu)) {
ShiftState ^= (ki.flags & 0xfu);
UpdateKbdLeds();
}
if (isBreak || ascii >= NOP)
return NOP;
#if 0
/* Check for three-fingered salute: */
if ( keyCode == 0x53u && ctrl && alt)
Reboot();
#endif
#if 0
#ifdef OPTION_DDB
/* Check for kernel debugger: */
if ( keyCode == 0x20u && ctrl && alt)/* 20u == 'd' */
Debugger();
if ( keyCode == 0x2eu && ctrl ) /* 1fu == 'c' */
Debugger();
#endif
#endif
#ifdef CORNER_HACK
*((uint16_t *) 0x000b8000) = 0x8f00 | (ascii & 0xffu);
#endif
return ascii;
}
return NOP;
}
static void
KeyboardInterrupt(fixregs_t *sa)
{
uint32_t c;
uint32_t irq = IRQ_FROM_EXCEPTION(sa->ExceptNo);
assert(irq == 1);
if (KernStream::debuggerIsActive)
return;
#ifdef CORNER_HACK
*((uint16_t *) 0x000b8000) = 0x8f00 | 'I';
#endif
c = FetchInputFromKeyboard();
if (c == ASCII::ETX)
Debugger();
IRQ::Enable(irq);
}
uint8_t
ConsoleStream::Get()
{
uint32_t c;
#ifdef CORNER_HACK
*((uint16_t *) 0x000b8000) = 0x8f00 | 'P';
#endif
do {
c = FetchInputFromKeyboard();
} while (c == NOP);
#ifdef CORNER_HACK
*((uint16_t *) 0x000b8000) = 0x8f00 | 'G';
#endif
return c;
}
void
ConsoleStream::SetDebugging(bool onOff)
{
debuggerIsActive = onOff;
if (debuggerIsActive == false)
IRQ::Enable(IRQ386::Keyboard);
}
void
ConsoleStream::EnableDebuggerInput()
{
IRQ::SetHandler(IRQ386::Keyboard, KeyboardInterrupt);
printf("Set up keyboard (console) interrupt handler!\n");
#if 0
/* Establish initial keyboard state visibly: */
UpdateKbdLeds();
#endif
/* FIX: This may prove a problem, as I need to check exactly where
* the interrupt vectors are set up in the boot sequence... */
IRQ::Enable(IRQ386::Keyboard);
}
#elif defined(OPTION_DDB)
void
ConsoleStream::EnableDebuggerInput()
{
fatal("EnableDebuggerInput on console when not DDB_ON_CONSOLE\n");
}
void
ConsoleStream::SetDebugging(bool onOff)
{
fatal("SetDebugging() on console when not DDB_ON_CONSOLE\n");
}
uint8_t
ConsoleStream::Get()
{
fatal("Get() on console when not DDB_ON_CONSOLE\n");
return 0;
}
#endif /* OPTION_DDB_ON_CONSOLE */
1.1 eros/src/base/sys/arch/i486/kernel/SerialStream.cxx
Index: SerialStream.cxx
===================================================================
/*
* Copyright (C) 2001, Jonathan S. Shapiro.
*
* This file is part of the EROS Operating System.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* This is a serial debugging stream based closely on the earlier
* logic introduced by Mike Hilsdale. */
#include <kerninc/kernel.hxx>
#include <kerninc/KernStream.hxx>
#include <kerninc/IRQ.hxx>
#include <eros/i486/io.h>
#include <eros/i486/fixregs.h>
#include "IDT.hxx"
/* This class has a singleton instance! */
struct SerialStream: public KernStream {
void Init();
void Put(uint8_t c);
#ifdef OPTION_DDB
uint8_t Get();
void SetDebugging(bool onoff);
void EnableDebuggerInput();
#endif
};
#define COMIRQ IRQ386::Serial0
#define COMBASE 0x3f8
struct SerialStream TheSerialStream;
KernStream* KernStream::SerialStream = &TheSerialStream;
void
SerialStream::Init()
{
uint16_t dlab = COMBASE + 3;
/* Initialize COM port */
/* Currently: 9600, 8N1 */
/* (This seemes to not be needed when using VMware
* and psuedo terminal pipes, but it's here for
* completeness and for real hardware.)
*/
/* set DLAB bit */
/* b7=1 */
old_outb(dlab, inb(dlab) ^ 0x80);
/* set 16-bit divisor to 12 (0Ch = 9600 baud) */
old_outb(COMBASE, 0x0C);
old_outb(COMBASE + 1, 0);
/* set data bits to 8 */
/* b0=1 b1=1 */
old_outb(dlab, inb(dlab) ^ 0x03);
/* set parity to None */
/* b3=0 b4=4 b5=0 */
old_outb(dlab, inb(dlab) & 0xC7);
/* set stop bits to 1 */
/* b2=0 */
old_outb(dlab, inb(dlab) & 0xFB);
/* unset DLAB bit */
/* b7=0 */
old_outb(COMBASE + 3, inb(COMBASE + 3) & 0x70);
/* tell COM port to report INTs on received char */
old_outb(COMBASE + 1, 1);
}
uint8_t
SerialStream::Get()
{
uint8_t c;
/* This is incorrect: Should be spinning waiting for a valid
* character! */
c = inb(COMBASE);
return c;
}
void
SerialStream::Put(uint8_t c)
{
/* This *may* be incorrect. Should *probably* be spinning waiting
* for room in the output fifo! */
old_outb(COMBASE, c);
return;
}
void
SerialStream::SetDebugging(bool onOff)
{
debuggerIsActive = onOff;
if (debuggerIsActive == false)
IRQ::Enable(COMIRQ);
}
static void
SerialInterrupt(fixregs_t *sa)
{
char c;
uint32_t irq = IRQ_FROM_EXCEPTION(sa->ExceptNo);
/* look at interrupt id to quell UART */
/* may want to actually do something here sometime later */
inb(COMBASE + 2);
if (KernStream::debuggerIsActive)
return;
assert(irq == COMIRQ);
c = TheSerialStream.Get();
if (c == ASCII::ETX)
Debugger();
IRQ::Enable(irq);
}
void
SerialStream::EnableDebuggerInput()
{
IRQ::SetHandler(COMIRQ, SerialInterrupt);
printf("Set up keyboard (console) interrupt handler!\n");
#if 0
/* Establish initial keyboard state visibly: */
UpdateKbdLeds();
#endif
/* FIX: This may prove a problem, as I need to check exactly where
* the interrupt vectors are set up in the boot sequence... */
IRQ::Enable(COMIRQ);
}
1.1 eros/src/base/sys/kernel/kern_KernStream.cxx
Index: kern_KernStream.cxx
===================================================================
/*
* Copyright (C) 2001, Jonathan S. Shapiro.
*
* This file is part of the EROS Operating System.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <kerninc/kernel.hxx>
#include <kerninc/util.h>
#include <kerninc/KernStream.hxx>
#ifdef OPTION_DDB
bool KernStream::debuggerIsActive = false;
KernStream *KernStream::dbg_stream = 0;
#endif
KernStream *KernStream::syscon_stream = 0;
KernStream *KernStream::log_stream = 0;
void
KernStream::InitStreams()
{
LogStream->Init();
ConsoleStream->Init();
#ifdef OPTION_DDB_ON_TTY0
SerialStream->Init();
#endif
syscon_stream = ConsoleStream;
log_stream = LogStream;
#if defined(OPTION_DDB_ON_CONSOLE)
dbg_stream = ConsoleStream;
#elif defined(OPTION_DDB_ON_TTY0)
dbg_stream = SerialStream;
#endif
#ifdef OPTION_DDB
/* If the debugger stream is set to point to the console device,
* turn off the syscon_stream so that we do not see duplicated
* output. */
if (dbg_stream == ConsoleStream)
syscon_stream = 0;
#endif /* OPTION_DDB */
printf("Kernel streams initialized...\n");
}
bool
KernStream::IsPrint(uint8_t c)
{
if (c > 127)
return false;
static uint8_t isPrint[16] = { /* really a bitmask! */
0x00, /* BEL ACK ENQ EOT ETX STX SOH NUL */
0x00, /* SI SO CR FF VT LF TAB BS */
0x00, /* ETB SYN NAK DC4 DC3 DC2 DC1 DLE */
0x00, /* US RS GS FS ESC SUB EM CAN */
0xff, /* ' & % $ # " ! SPC */
0xff, /* / . - , + * ) ( */
0xff, /* 7 6 5 4 3 2 1 0 */
0xff, /* ? > = < ; : 9 8 */
0xff, /* G F E D C B A @ */
0xff, /* O N M L K J I H */
0xff, /* W V U T S R Q P */
0xff, /* _ ^ ] \ [ Z Y X */
0xff, /* g f e d c b a ` */
0xff, /* o n m l k j i h */
0xff, /* w v u t s r q p */
0x7f, /* DEL ~ } | { z y x */
} ;
uint8_t mask = isPrint[(c >> 3)];
c &= 0x7u;
if (c)
mask >>= c;
if (mask & 1)
return true;
return false;
}
void
KernStream::do_putc(char c)
{
#ifdef OPTION_DDB
if (dbg_stream) dbg_stream->Put(c);
#endif
if (syscon_stream) syscon_stream->Put(c);
#ifdef OPTION_DDB
if (log_stream && !debuggerIsActive) log_stream->Put(c);
#else
if (log_stream) log_stream->Put(c);
#endif
}
void
KernStream::PutBuf(uint8_t *s, uint32_t len)
{
for (uint32_t i = 0; i < len; i++)
nl_putc(s[i]);
}
void
KernStream::nl_putc(char c)
{
if (c == '\n')
do_putc('\r');
do_putc(c);
}
#ifdef OPTION_DDB
uint8_t
KernStream::Get()
{
fatal("Fatal call to KernStream::Get() made.\n");
return ASCII::SPC;
}
void
KernStream::SetDebugging(bool onOff)
{
fatal("Fatal call to KernStream::SetDebugging() made.\n");
}
#endif
extern "C" void __pure_virtual(void);
void
__pure_virtual(void)
{
fatal("pure virtual function called\n");
}
void
KernStream::BeginUserThreads()
{
printf("Starting first thread. Console output now disabled...\n");
syscon_stream = 0;
}
1.1 eros/src/base/sys/kernel/kern_LogStream.cxx
Index: kern_LogStream.cxx
===================================================================
/*
* Copyright (C) 2001, Jonathan S. Shapiro.
*
* This file is part of the EROS Operating System.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* The LogStream is a consolidation of the various previous logging
* mechanisms.
*/
#include <kerninc/kernel.hxx>
#include <kerninc/util.h>
#include <kerninc/KernStream.hxx>
#include <eros/i486/io.h>
/* This class has a singleton instance! */
struct LogStream: public KernStream {
void Init();
void Put(uint8_t c);
#ifdef OPTION_DDB
uint8_t Get();
void SetDebugging(bool onoff);
void EnableDebuggerInput();
#endif
};
struct LogStream TheLogStream;
KernStream* KernStream::LogStream = &TheLogStream;
#define DIAG_BUF_PAGES 1u
static char diagbuf[DIAG_BUF_PAGES * EROS_PAGE_SIZE];
static char *const logbuf = diagbuf;
static char *nextin = diagbuf;
#if 0
/* Eventually to be used for user-level extraction of log output. */
static char *nextout = diagbuf;
#endif
static char *const logtop = diagbuf + (DIAG_BUF_PAGES * EROS_PAGE_SIZE);
void
LogStream::Init()
{
}
void
LogStream::Put(uint8_t c)
{
if ((unsigned)(nextin - logbuf) > (DIAG_BUF_PAGES * EROS_PAGE_SIZE))
halt('p');
if (nextin == logtop)
nextin = logbuf;
*nextin++ = c;
}
#ifdef OPTION_DDB
uint8_t
LogStream::Get()
{
fatal("LogStream::Get() should never be called!\n");
return 0;
}
void
LogStream::SetDebugging(bool onOff)
{
fatal("LogStream::SetDebugging() should never be called!\n");
}
void
LogStream::EnableDebuggerInput()
{
fatal("LogStream::EnableDebuggerInput() should never be called!\n");
}
#endif
1.1 eros/src/base/sys/kernel/kern_printf.cxx
Index: kern_printf.cxx
===================================================================
/*
* Mach Operating System
* Copyright (c) 1991,1990 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
/* The bulk of this code originated as the Mach debugger printf()
* code. While I could replace it with the equivalent code from
* MsgLog::printf(), this version is well tested and mature.
*/
#include <kerninc/kernel.hxx>
#include <kerninc/util.h>
#include <kerninc/KernStream.hxx>
#include <eros/stdarg.h>
#ifdef OPTION_DDB
#include <arch-kerninc/db_machdep.hxx>
#include <ddb/db_command.hxx>
#endif
/* $NetBSD: db_output.c,v 1.8 1994/06/29 22:41:41 deraadt Exp $ */
#ifndef DB_MAX_LINE
#define DB_MAX_LINE 23 /* maximum line */
#define DB_MAX_WIDTH 80 /* maximum width */
#endif /* DB_MAX_LINE */
#define DB_MIN_MAX_WIDTH 20 /* minimum max width */
#define DB_MIN_MAX_LINE 3 /* minimum max line */
#define CTRL(c) ((c) & 0xff)
int db_output_position = 0; /* output column */
int db_output_line = 0; /* output line number */
int db_last_non_space = 0; /* last non-space character */
int db_tab_stop_width = 8; /* how wide are tab stops? */
#define NEXT_TAB(i) \
((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width)
int db_max_line = DB_MAX_LINE; /* output max lines */
int db_max_width = DB_MAX_WIDTH; /* output line width */
extern void db_check_interrupt();
#define cngetc() KernStream::dbg_stream->Get()
#define cnputc(c) KernStream::nl_putc(c)
/*
* Printf and character output for debugger.
*/
#define NBBY 8 /* for all modern machines */
/*
* Printing
*/
long db_radix = 10;
/*
* End line if too long.
*/
void
db_end_line()
{
if (db_output_position >= db_max_width)
printf("\n");
}
#ifdef OPTION_DDB
/*
* Return output position
*/
int
db_print_position()
{
return (db_output_position);
}
#endif
/*
* Put a number (base <= 16) in a buffer in reverse order; return an
* optional length and a pointer to the NULL terminated (preceded?)
* buffer.
*/
static char *
db_ksprintn(register u_long ul, register int base, register int *lenp)
{ /* A long in base 8, plus NULL. */
static char buf[sizeof(long) * NBBY / 3 + 2];
register char *p;
p = buf;
do {
*++p = "0123456789abcdef"[ul % base];
} while (ul /= base);
if (lenp)
*lenp = p - buf;
return (p);
}
static char *
db_ll_ksprintn(register unsigned long long ull, register int base,
register int *lenp)
{
static char buf[sizeof(long long) * NBBY / 3 + 2];
register char *p;
p = buf;
do {
*++p = "0123456789abcdef"[ull % base];
} while (ull /= base);
if (lenp)
*lenp = p - buf;
return (p);
}
/*
* Force pending whitespace.
*/
void
db_force_whitespace()
{
register int last_print, next_tab;
last_print = db_last_non_space;
while (last_print < db_output_position) {
next_tab = NEXT_TAB(last_print);
if (next_tab <= db_output_position) {
while (last_print < next_tab) { /* DON'T send a tab!!! */
cnputc(' ');
last_print++;
}
}
else {
cnputc(' ');
last_print++;
}
}
db_last_non_space = db_output_position;
}
#ifdef OPTION_DDB
static void
db_more()
{
register char *p;
int quit_output = 0;
if (KernStream::debuggerIsActive == false) {
db_output_line = 0;
return;
}
for (p = "--db_more--"; *p; p++)
cnputc(*p);
switch(cngetc()) {
case ' ':
db_output_line = 0;
break;
case 'q':
case CTRL('c'):
db_output_line = 0;
quit_output = 1;
break;
default:
db_output_line--;
break;
}
p = "\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b";
while (*p)
cnputc(*p++);
if (quit_output) {
db_error(0);
/* NOTREACHED */
}
}
#endif
/*
* Output character. Buffer whitespace.
*/
void
db_putchar(int c)
{
#ifdef OPTION_DDB
if (db_max_line >= DB_MIN_MAX_LINE && db_output_line >= db_max_line-1)
db_more();
#endif
if (c > ' ' && c <= '~') {
/*
* Printing character.
* If we have spaces to print, print them first.
* Use tabs if possible.
*/
db_force_whitespace();
cnputc(c);
db_output_position++;
if (db_max_width >= DB_MIN_MAX_WIDTH
&& db_output_position >= db_max_width-1) {
/* auto new line */
cnputc('\n');
db_output_position = 0;
db_last_non_space = 0;
db_output_line++;
}
db_last_non_space = db_output_position;
}
else if (c == '\n') {
/* Return */
cnputc(c);
db_output_position = 0;
db_last_non_space = 0;
db_output_line++;
#ifdef OPTION_DDB
db_check_interrupt();
#endif
}
else if (c == '\t') {
/* assume tabs every 8 positions */
db_output_position = NEXT_TAB(db_output_position);
}
else if (c == ' ') {
/* space */
db_output_position++;
}
else if (c == '\007') {
/* bell */
cnputc(c);
}
/* other characters are assumed non-printing */
}
void
db_printf_guts(register const char *fmt, va_list ap)
{
register char *p;
register int ch, n;
u_long ul;
unsigned long long ull;
int base, lflag, tmp, width;
char padc;
int ladjust;
int sharpflag;
int neg;
for (;;) {
padc = ' ';
width = 0;
while ((ch = *(u_char *)fmt++) != '%') {
if (ch == '\0')
return;
db_putchar(ch);
}
lflag = 0;
ladjust = 0;
sharpflag = 0;
neg = 0;
reswitch: switch (ch = *(u_char *)fmt++) {
case '0':
padc = '0';
goto reswitch;
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
for (width = 0;; ++fmt) {
width = width * 10 + ch - '0';
ch = *fmt;
if (ch < '0' || ch > '9')
break;
}
goto reswitch;
case 'l':
lflag = 1;
goto reswitch;
case '-':
ladjust = 1;
goto reswitch;
case '#':
sharpflag = 1;
goto reswitch;
case 'b':
ul = va_arg(ap, int);
p = va_arg(ap, char *);
for (p = db_ksprintn(ul, *p++, NULL); (ch = *p--);)
db_putchar(ch);
if (!ul)
break;
for (tmp = 0; (n = *p++);) {
if (ul & (1 << (n - 1))) {
db_putchar(tmp ? ',' : '<');
for (; (n = *p) > ' '; ++p)
db_putchar(n);
tmp = 1;
} else
for (; *p > ' '; ++p);
}
if (tmp)
db_putchar('>');
break;
case '*':
width = va_arg (ap, int);
if (width < 0) {
ladjust = !ladjust;
width = -width;
}
goto reswitch;
case 'c':
db_putchar(va_arg(ap, int));
break;
case 's':
p = va_arg(ap, char *);
width -= strlen (p);
if (!ladjust && width > 0)
while (width--)
db_putchar (padc);
while ((ch = *p++))
db_putchar(ch);
if (ladjust && width > 0)
while (width--)
db_putchar (padc);
break;
case 'r':
ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
if ((long)ul < 0) {
neg = 1;
ul = -(long)ul;
}
base = db_radix;
if (base < 8 || base > 16)
base = 10;
goto number;
case 'n':
ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
base = db_radix;
if (base < 8 || base > 16)
base = 10;
goto number;
case 'd':
ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
if ((long)ul < 0) {
neg = 1;
ul = -(long)ul;
}
base = 10;
goto number;
case 'o':
ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
base = 8;
goto number;
case 'u':
ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
base = 10;
goto number;
case 'U':
ull = va_arg(ap, unsigned long long);
base = 10;
goto ll_number;
case 'X':
ull = va_arg(ap, unsigned long long);
base = 16;
goto ll_number;
case 'z':
ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
if ((long)ul < 0) {
neg = 1;
ul = -(long)ul;
}
base = 16;
goto number;
case 'x':
ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
base = 16;
#if 0
number: p = (char *)db_ksprintn(ul, base, &tmp);
if (sharpflag && ul != 0) {
if (base == 8)
tmp++;
else if (base == 16)
tmp += 2;
}
if (neg)
tmp++;
if (!ladjust && width && (width -= tmp) > 0)
while (width--)
db_putchar(padc);
if (neg)
db_putchar ('-');
if (sharpflag && ul != 0) {
if (base == 8) {
db_putchar ('0');
} else if (base == 16) {
db_putchar ('0');
db_putchar ('x');
}
}
if (ladjust && width && (width -= tmp) > 0)
while (width--)
db_putchar(padc);
while ((ch = *p--))
db_putchar(ch);
break;
#endif
number: ull = ul;
ll_number: p = (char *)db_ll_ksprintn(ull, base, &tmp);
if (sharpflag && ull != 0) {
if (base == 8)
tmp++;
else if (base == 16)
tmp += 2;
}
if (neg)
tmp++;
if (!ladjust && width && (width -= tmp) > 0)
while (width--)
db_putchar(padc);
if (neg)
db_putchar ('-');
if (sharpflag && ull != 0) {
if (base == 8) {
db_putchar ('0');
} else if (base == 16) {
db_putchar ('0');
db_putchar ('x');
}
}
if (ladjust && width && (width -= tmp) > 0)
while (width--)
db_putchar(padc);
while ((ch = *p--))
db_putchar(ch);
break;
default:
db_putchar('%');
if (lflag)
db_putchar('l');
/* FALLTHROUGH */
case '%':
db_putchar(ch);
}
}
}
/*VARARGS1*/
void
printf(const char *fmt, ...)
{
va_list listp;
va_start(listp, fmt);
db_printf_guts (fmt, listp);
va_end(listp);
}
/*VARARGS1*/
void dprintf(unsigned shouldStop, const char* fmt, ...)
{
va_list listp;
va_start(listp, fmt);
db_printf_guts (fmt, listp);
va_end(listp);
if (shouldStop) Debugger();
}
/*VARARGS1*/
void
fatal(const char *fmt, ...)
{
va_list listp;
va_start(listp, fmt);
db_printf_guts (fmt, listp);
va_end(listp);
#ifdef OPTION_DDB
Debugger();
#else
#if 0
Debug::Backtrace(0, false);
/* This routine will never return. I personally guarantee it! */
Flush();
#endif
halt('F');
#endif
}
void printOid(OID oid)
{
printf("0x%04x%08x", (uint32_t) (oid >> 32), (uint32_t) oid);
}
void printCount(ObCount count)
{
printf("0x%08x", count);
}
1.1 eros/src/base/sys/kerninc/KernStream.hxx
Index: KernStream.hxx
===================================================================
#ifndef __KERNSTREAM_HXX__
#define __KERNSTREAM_HXX__
/*
* Copyright (C) 2001, Jonathan S. Shapiro.
*
* This file is part of the EROS Operating System.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <kerninc/kernel.hxx>
/** KernStream is really an interface specification. The kernel
* maintains three KernStreams: ConsoleStream, SerialStream,
* LogStream. LogStream is global, and present in all
* kernels. ConsoleStream is present if a console is
* configured. SerialStream is present if the kernel debugger has been
* configured for serial mode.
*
* Pointers to the ConsoleStream and SerialStream objects are in
* turn conditionally assigned to two variables syscon_stream and
* dbg_stream.
*/
struct ASCII {
enum {
NUL = 0x00,
SOH = 0x01,
STX = 0x02,
ETX = 0x03,
EOT = 0x04,
ENQ = 0x05,
ACK = 0x06,
BEL = 0x07,
BS = 0x08,
TAB = 0x09,
LF = 0x0a,
VT = 0x0b,
FF = 0x0c,
CR = 0x0d,
SO = 0x0e,
SI = 0x0f,
DLE = 0x10,
DC1 = 0x11,
DC2 = 0x12,
DC3 = 0x13,
DC4 = 0x14,
NAK = 0x15,
SYN = 0x16,
ETB = 0x17,
CAN = 0x18,
EM = 0x19,
SUB = 0x1a,
ESC = 0x1b,
FS = 0x1c,
GS = 0x1d,
RS = 0x1e,
US = 0x1f,
SPC = 0x20,
DEL = 0x7f,
};
};
struct KernStream {
virtual void Init() = 0;
virtual void Put(uint8_t c) = 0;
#ifdef OPTION_DDB
/* Following only called via dbg_stream */
virtual uint8_t Get() = 0;
virtual void SetDebugging(bool onoff) = 0;
virtual void EnableDebuggerInput() = 0;
#endif
/*** END OF MEMBERS -- REST IS JUST NAMESPACE TRICKERY ***/
#ifdef OPTION_DDB
static bool debuggerIsActive;
#endif
/* I would like to make these references, but the global constructor
* code generator is screwing up the pointer initialization. */
static KernStream* LogStream;
static KernStream* ConsoleStream;
#ifdef OPTION_DDB_ON_TTY0
static KernStream* SerialStream;
#endif
#ifdef OPTION_DDB
static KernStream *dbg_stream;
#endif
static KernStream *syscon_stream;
static KernStream *log_stream;
static bool IsPrint(uint8_t c);
static void KernStream::InitStreams();
static void PutBuf(uint8_t *s, uint32_t len);
static void nl_putc(char c);
static void do_putc(char c);
static void BeginUserThreads();
};
#endif /* __KERNSTREAM_HXX__ */