📄 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;voidConsoleStream::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 voidSetPosition(uint32_t pos, uint8_t c){ uint16_t vgaAttrs = WhiteOnBlack << 8; screen[pos] = ((uint16_t) c) | vgaAttrs;}static voidShowCursorAt(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 voidScroll(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 voidClearTextConsole(){ for (uint32_t wpos = 0; wpos < SCREEN_ROWS * SCREEN_COLS; wpos++) SetPosition(wpos, ' ');}static void Beep() {}/* FIX: This is NOT RIGHT!! */voidConsoleStream::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 boolReadKbd(uint8_t& c){ KbdWait(); while ( (inb(KbdStatusPort) & KbdStatus::BufFull) == 0 ) return false; c = inb(KbdDataPort); return true;}static voidUpdateKbdLeds(){ 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -