Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Release 1.0
[palacios.git] / geekos / src / geekos / screen.c
diff --git a/geekos/src/geekos/screen.c b/geekos/src/geekos/screen.c
new file mode 100644 (file)
index 0000000..c952b42
--- /dev/null
@@ -0,0 +1,571 @@
+/*
+ * GeekOS text screen output
+ * Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $Revision: 1.3 $
+ * 
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "COPYING".
+ */
+
+#include <stdarg.h>
+#include <geekos/kassert.h>
+#include <geekos/ktypes.h>
+#include <geekos/io.h>
+#include <geekos/int.h>
+#include <geekos/screen.h>
+#include <geekos/debug.h>
+
+/*
+ * Information sources for VT100 and ANSI escape sequences:
+ * - http://www.lns.cornell.edu/~pvhp/dcl/vt100.html
+ * - http://en.wikipedia.org/wiki/ANSI_escape_code
+ */
+
+/* ----------------------------------------------------------------------
+ * Private functions and data
+ * ---------------------------------------------------------------------- */
+
+#define ESC ((char) 0x1B)
+#define DEFAULT_ATTRIBUTE ATTRIB(BLACK, GRAY)
+
+enum State {
+    S_NORMAL,          /* Normal state - output is echoed verbatim */
+    S_ESC,             /* Saw ESC character - begin output escape sequence */
+    S_ESC2,            /* Saw '[' character - continue output escape sequence */
+    S_ARG,             /* Scanning a numeric argument */
+    S_CMD,             /* Command */
+};
+
+#define MAXARGS 8      /* Max args that can be passed to esc sequence */
+
+struct Console_State {
+    /* Current state information */
+    int row, col;
+    int saveRow, saveCol;
+    uchar_t currentAttr;
+
+    /* Working variables for processing escape sequences. */
+    enum State state;
+    int argList[MAXARGS];
+    int numArgs;
+};
+
+static struct Console_State s_cons;
+
+#define NUM_SCREEN_DWORDS ((NUMROWS * NUMCOLS * 2) / 4)
+#define NUM_SCROLL_DWORDS (((NUMROWS-1) * NUMCOLS * 2) / 4)
+#define NUM_DWORDS_PER_LINE ((NUMCOLS*2)/4)
+#define FILL_DWORD (0x00200020 | (s_cons.currentAttr<<24) | (s_cons.currentAttr<<8))
+
+/*
+ * Scroll the display one line.
+ * We speed things up by copying 4 bytes at a time.
+ */
+static void Scroll(void)
+{
+    uint_t* v;
+    int i, n = NUM_SCROLL_DWORDS;
+    uint_t fill = FILL_DWORD;
+
+    /* Move lines 1..NUMROWS-1 up one position. */
+    for (v = (uint_t*)VIDMEM, i = 0; i < n; ++i) {
+       *v = *(v + NUM_DWORDS_PER_LINE);
+       ++v;
+    }
+
+    /* Clear out last line. */
+    for (v = (uint_t*)VIDMEM + n, i = 0; i < NUM_DWORDS_PER_LINE; ++i)
+       *v++ = fill;
+}
+
+/*
+ * Clear current cursor position to end of line using
+ * current attribute.
+ */
+static void Clear_To_EOL(void)
+{
+    int n = (NUMCOLS - s_cons.col);
+    uchar_t* v = VIDMEM + s_cons.row*(NUMCOLS*2) + s_cons.col*2;
+    while (n-- > 0) {
+       *v++ = ' ';
+       *v++ = s_cons.currentAttr;
+    }
+}
+
+/*
+ * Move to the beginning of the next line, scrolling
+ * if necessary.
+ */
+static void Newline(void)
+{
+    ++s_cons.row;
+    s_cons.col = 0;
+    if (s_cons.row == NUMROWS) {
+       Scroll();
+       s_cons.row = NUMROWS - 1;
+    }
+}
+
+/*
+ * Write the graphic representation of given character to the screen
+ * at current position, with current attribute, scrolling if
+ * necessary.
+ */
+static void Put_Graphic_Char(int c)
+{
+    uchar_t* v = VIDMEM + s_cons.row*(NUMCOLS*2) + s_cons.col*2;
+
+    /* Put character at current position */
+    *v++ = (uchar_t) c;
+    *v = s_cons.currentAttr;
+
+    if (s_cons.col < NUMCOLS - 1)
+       ++s_cons.col;
+    else
+       Newline();
+}
+
+/*
+ * Put one character to the screen using the current cursor position
+ * and attribute, scrolling if needed.  The caller should update
+ * the cursor position once all characters have been written.
+ */
+static void Output_Literal_Character(int c)
+{
+    int numSpaces;
+
+    switch (c) {
+    case '\n':
+       Clear_To_EOL();
+       Newline();
+       break;
+
+    case '\t':
+       numSpaces = TABWIDTH - (s_cons.col % TABWIDTH);
+       while (numSpaces-- > 0)
+           Put_Graphic_Char(' ');
+       break;
+
+    default:
+       Put_Graphic_Char(c);
+       break;
+    }
+
+#ifndef NDEBUG
+    /*
+     * When compiled with --enable-port-e9-hack, Bochs will send writes
+     * to port E9 to the console.  This helps tremendously with debugging,
+     * because it allows debug Print() statements to be visible after
+     * Bochs has exited.
+     */
+    Out_Byte(0xE9, c);
+#endif
+}
+
+/*
+ * Move the cursor to a new position, stopping at the screen borders.
+ */
+static void Move_Cursor(int row, int col)
+{
+    if (row < 0)
+       row = 0;
+    else if (row >= NUMROWS)
+       row = NUMROWS - 1;
+
+    if (col < 0)
+       col = 0;
+    else if (col >= NUMCOLS)
+       col = NUMCOLS - 1;
+
+    s_cons.row = row;
+    s_cons.col = col;
+}
+
+/*
+ * Table mapping ANSI colors to VGA text mode colors.
+ */
+static const uchar_t s_ansiToVgaColor[] = {
+    BLACK,RED,GREEN,AMBER,BLUE,MAGENTA,CYAN,GRAY
+};
+
+/*
+ * Update the attributes specified by the arguments
+ * of the escape sequence.
+ */
+static void Update_Attributes(void)
+{
+    int i;
+    int attr = s_cons.currentAttr & ~(BRIGHT);
+
+    for (i = 0; i < s_cons.numArgs; ++i) {
+       int value = s_cons.argList[i];
+       if (value == 0)
+           attr = DEFAULT_ATTRIBUTE;
+       else if (value == 1)
+           attr |= BRIGHT;
+       else if (value >= 30 && value <= 37)
+           attr = (attr & ~0x7) | s_ansiToVgaColor[value - 30];
+       else if (value >= 40 && value <= 47)
+           attr = (attr & ~(0x7 << 4)) | (s_ansiToVgaColor[value - 40] << 4);
+    }
+    s_cons.currentAttr = attr;
+}
+
+/* Reset to cancel or finish processing an escape sequence. */
+static void Reset(void)
+{
+    s_cons.state = S_NORMAL;
+    s_cons.numArgs = 0;
+}
+
+/* Start an escape sequence. */
+static void Start_Escape(void)
+{
+    s_cons.state = S_ESC;
+    s_cons.numArgs = 0;
+}
+
+/* Start a numeric argument to an escape sequence. */
+static void Start_Arg(int argNum)
+{
+    KASSERT(s_cons.numArgs == argNum);
+    s_cons.numArgs++;
+    s_cons.state = S_ARG;
+    if (argNum < MAXARGS)
+       s_cons.argList[argNum] = 0;
+}
+
+/* Save current cursor position. */
+static void Save_Cursor(void)
+{
+    s_cons.saveRow = s_cons.row;
+    s_cons.saveCol = s_cons.col;
+}
+
+/* Restore saved cursor position. */
+static void Restore_Cursor(void)
+{
+    s_cons.row = s_cons.saveRow;
+    s_cons.col = s_cons.saveCol;
+}
+
+/* Add a digit to current numeric argument. */
+static void Add_Digit(int c)
+{
+    KASSERT(ISDIGIT(c));
+    if (s_cons.numArgs < MAXARGS) {
+       int argNum = s_cons.numArgs - 1;
+       s_cons.argList[argNum] *= 10;
+       s_cons.argList[argNum] += (c - '0');
+    }
+}
+
+/*
+ * Get a numeric argument.
+ * Returns zero if that argument was not actually specified.
+ */
+static int Get_Arg(int argNum)
+{
+    return argNum < s_cons.numArgs ? s_cons.argList[argNum] : 0;
+}
+
+/*
+ * The workhorse output function.
+ * Depending on the current console output state,
+ * does literal character output or processes part of
+ * an escape sequence.
+ */
+static void Put_Char_Imp(int c)
+{
+again:
+    switch (s_cons.state) {
+    case S_NORMAL:
+       if (c == ESC)
+           Start_Escape();
+       else
+           Output_Literal_Character(c);
+       break;
+
+    case S_ESC:
+       if (c == '[')
+           s_cons.state = S_ESC2;
+       else
+           Reset();
+       break;
+
+    case S_ESC2:
+       if (ISDIGIT(c)) {
+           Start_Arg(0);
+           goto again;
+       } else if (c == ';') {
+           /* Special case: for "n;m" commands, "n" is implicitly 1 if omitted */
+           Start_Arg(0);
+           Add_Digit('1');
+           Start_Arg(1);
+       } else {
+           s_cons.state = S_CMD;
+           goto again;
+       }
+       break;
+
+    case S_ARG:
+       if (ISDIGIT(c))
+           Add_Digit(c);
+       else if (c == ';')
+           Start_Arg(s_cons.numArgs);
+       else {
+           s_cons.state = S_CMD;
+           goto again;
+       }
+       break;
+
+    case S_CMD:
+       switch (c) {
+       case 'K': Clear_To_EOL(); break;
+       case 's': Save_Cursor(); break;
+       case 'u': Restore_Cursor(); break;
+       case 'A': Move_Cursor(s_cons.row - Get_Arg(0), s_cons.col); break;
+       case 'B': Move_Cursor(s_cons.row + Get_Arg(0), s_cons.col); break;
+       case 'C': Move_Cursor(s_cons.row, s_cons.col + Get_Arg(0)); break;
+       case 'D': Move_Cursor(s_cons.row, s_cons.col - Get_Arg(0)); break;
+       case 'm': Update_Attributes(); break;
+       case 'f': case 'H':
+           if (s_cons.numArgs == 2) Move_Cursor(Get_Arg(0)-1, Get_Arg(1)-1); break;
+       case 'J':
+           if (s_cons.numArgs == 1 && Get_Arg(0) == 2) {
+               Clear_Screen();
+               Put_Cursor(0, 0);
+           }
+           break;
+       default: break;
+       }
+       Reset();
+       break;
+
+    default:
+       KASSERT(false);
+    }
+}
+
+/*
+ * Update the location of the hardware cursor.
+ */
+static void Update_Cursor(void)
+{
+    /*
+     * The cursor location is a character offset from the beginning
+     * of page memory (I think).
+     */
+    uint_t characterPos = (s_cons.row * NUMCOLS) + s_cons.col;
+    uchar_t origAddr;
+
+    /*
+     * Save original contents of CRT address register.
+     * It is considered good programming practice to restore
+     * it to its original value after modifying it.
+     */
+    origAddr = In_Byte(CRT_ADDR_REG);
+    IO_Delay();
+
+    /* Set the high cursor location byte */
+    Out_Byte(CRT_ADDR_REG, CRT_CURSOR_LOC_HIGH_REG);
+    IO_Delay();
+    Out_Byte(CRT_DATA_REG, (characterPos>>8) & 0xff);
+    IO_Delay();
+
+    /* Set the low cursor location byte */
+    Out_Byte(CRT_ADDR_REG, CRT_CURSOR_LOC_LOW_REG);
+    IO_Delay();
+    Out_Byte(CRT_DATA_REG, characterPos & 0xff);
+    IO_Delay();
+
+    /* Restore contents of the CRT address register */
+    Out_Byte(CRT_ADDR_REG, origAddr);
+}
+
+/* ----------------------------------------------------------------------
+ * Public functions
+ * ---------------------------------------------------------------------- */
+
+/*
+ * Initialize the screen module.
+ */
+void Init_Screen(void)
+{
+    bool iflag = Begin_Int_Atomic();
+
+    s_cons.row = s_cons.col = 0;
+    s_cons.currentAttr = DEFAULT_ATTRIBUTE;
+    Clear_Screen();
+
+#if 0
+    {
+    unsigned int z = (unsigned int)&Print_Emit;
+    int i;
+    Put_Char(' ');
+    Put_Char('0');
+    Put_Char('x');
+    
+    for (i = 0; i < 8; i++) {
+      int j = z & 0xf0000000;
+      
+      j = j >> 28;
+      j &= 0x0000000f;
+
+      if (j > 9) {
+       j += 55;
+      } else {
+       j += 48;
+      }
+
+      Put_Char(j);    
+      
+      z = z << 4;
+    }
+  }
+
+#endif
+
+    End_Int_Atomic(iflag);
+    Print("Screen Inited\n");
+}
+
+/*
+ * Clear the screen using the current attribute.
+ */
+void Clear_Screen(void)
+{
+    uint_t* v = (uint_t*)VIDMEM;
+    int i;
+    uint_t fill = FILL_DWORD;
+
+    bool iflag = Begin_Int_Atomic();
+
+    for (i = 0; i < NUM_SCREEN_DWORDS; ++i)
+       *v++ = fill;
+
+    End_Int_Atomic(iflag);
+}
+
+/*
+ * Get current cursor position.
+ */
+void Get_Cursor(int* row, int* col)
+{
+    bool iflag = Begin_Int_Atomic();
+    *row = s_cons.row;
+    *col = s_cons.col;
+    End_Int_Atomic(iflag);
+}
+
+/*
+ * Set the current cursor position.
+ * Return true if successful, or false if the specified
+ * cursor position is invalid.
+ */
+bool Put_Cursor(int row, int col)
+{
+    bool iflag;
+
+    if (row < 0 || row >= NUMROWS || col < 0 || col >= NUMCOLS)
+       return false;
+
+    iflag = Begin_Int_Atomic();
+    s_cons.row = row;
+    s_cons.col = col;
+    Update_Cursor();
+    End_Int_Atomic(iflag);
+
+    return true;
+}
+
+/*
+ * Get the current character attribute.
+ */
+uchar_t Get_Current_Attr(void)
+{
+    return s_cons.currentAttr;
+}
+
+/*
+ * Set the current character attribute.
+ */
+void Set_Current_Attr(uchar_t attrib)
+{
+    bool iflag = Begin_Int_Atomic();
+    s_cons.currentAttr = attrib;
+    End_Int_Atomic(iflag);
+}
+
+/*
+ * Write a single character to the screen at current position
+ * using current attribute, handling scrolling, special characters, etc.
+ */
+void Put_Char(int c)
+{
+    bool iflag = Begin_Int_Atomic();
+    Put_Char_Imp(c);
+    Update_Cursor();
+    End_Int_Atomic(iflag);
+}
+
+/*
+ * Write a string of characters to the screen at current cursor
+ * position using current attribute.
+ */
+void Put_String(const char* s)
+{
+    bool iflag = Begin_Int_Atomic();
+    while (*s != '\0')
+       Put_Char_Imp(*s++);
+    Update_Cursor();
+    End_Int_Atomic(iflag);
+}
+
+/*
+ * Write a buffer of characters at current cursor position
+ * using current attribute.
+ */
+void Put_Buf(const char* buf, ulong_t length)
+{
+    bool iflag = Begin_Int_Atomic();
+    while (length > 0) {
+       Put_Char_Imp(*buf++);
+       --length;
+    }
+    Update_Cursor();
+    End_Int_Atomic(iflag);
+}
+
+/* Support for Print(). */
+static void Print_Emit(struct Output_Sink *o, int ch) { Put_Char_Imp(ch); }
+static void Print_Finish(struct Output_Sink *o) { Update_Cursor(); }
+static struct Output_Sink s_outputSink = { &Print_Emit, &Print_Finish };
+
+/*
+ * Print to console using printf()-style formatting.
+ * Calls into Format_Output in common library.
+ */
+
+static __inline__ void PrintInternal(const char * format, va_list ap) {
+    Format_Output(&s_outputSink, format, ap);
+}
+
+void Print(const char *fmt, ...)
+{
+    va_list args;
+    bool iflag = Begin_Int_Atomic();
+
+    va_start(args, fmt);
+    PrintInternal(fmt, args);
+    va_end(args);
+
+    End_Int_Atomic(iflag);
+}
+
+
+void PrintList(const char * fmt, va_list ap) {
+    bool iflag = Begin_Int_Atomic();
+    PrintInternal(fmt, ap);
+    End_Int_Atomic(iflag);
+}