main kernel startup, libc, console tty, asmops, build flags fixes
[bootcensus] / src / contty.c
diff --git a/src/contty.c b/src/contty.c
new file mode 100644 (file)
index 0000000..9a78ca2
--- /dev/null
@@ -0,0 +1,202 @@
+#include <stdio.h>
+#include <string.h>
+#include "contty.h"
+#include "serial.h"
+#include "asmops.h"
+#include "config.h"
+
+#define VIRT_ROWS      200
+
+#define NCOLS          80
+#define NROWS          25
+#define TEXT_ADDR      ((char*)0xb8000)
+
+#define CRTC_ADDR      0x3d4
+#define CRTC_DATA      0x3d5
+
+#define CRTC_REG_CURSTART      0x0a
+#define CRTC_REG_CUREND                0x0b
+#define CRTC_REG_START_H       0x0c
+#define CRTC_REG_START_L       0x0d
+#define CRTC_REG_CURLOC_H      0x0e
+#define CRTC_REG_CURLOC_L      0x0f
+
+#define VMEM_CHAR(c, attr) \
+       ((uint16_t)(c) | ((uint16_t)(attr) << 8))
+
+static void scroll(void);
+static void crtc_cursor(int x, int y);
+static void crtc_setstart(int y);
+static inline unsigned char crtc_read(int reg);
+static inline void crtc_write(int reg, unsigned char val);
+static inline void crtc_write_bits(int reg, unsigned char val, unsigned char mask);
+
+extern int cursor_x, cursor_y;
+static unsigned char txattr = 0x07;
+static int start_line;
+
+int con_init(void)
+{
+#ifdef CON_SERIAL
+       ser_open(0, 9600, SER_8N1);
+#endif
+
+#ifdef CON_TEXTMODE
+       con_show_cursor(1);
+       crtc_setstart(0);
+       crtc_cursor(cursor_x, cursor_y);
+       /*
+       printf("curloc: %x %x\n", (unsigned int)crtc_read(CRTC_REG_CURLOC_H),
+                       (unsigned int)crtc_read(CRTC_REG_CURLOC_L));
+       printf("curstart: %x\n", (unsigned int)crtc_read(CRTC_REG_CURSTART));
+       printf("curend: %x\n", (unsigned int)crtc_read(CRTC_REG_CUREND));
+       */
+#endif
+
+       return 0;
+}
+
+void con_show_cursor(int show)
+{
+#ifdef CON_TEXTMODE
+       unsigned char val = show ? 0 : 0x20;
+
+       crtc_write_bits(CRTC_REG_CURSTART, val, 0x20);
+#endif
+}
+
+void con_cursor(int x, int y)
+{
+#ifdef CON_TEXTMODE
+       cursor_x = x;
+       cursor_y = y;
+       crtc_cursor(x, y);
+#endif
+}
+
+void con_fgcolor(int c)
+{
+       txattr = (txattr & 0xf0) | c;
+}
+
+void con_bgcolor(int c)
+{
+       txattr = (txattr & 0x0f) | (c << 4);
+}
+
+void con_clear(void)
+{
+#ifdef CON_TEXTMODE
+       memset(TEXT_ADDR, 0, NCOLS * NROWS * 2);
+
+       start_line = 0;
+       crtc_setstart(0);
+
+       cursor_x = cursor_y = 0;
+       crtc_cursor(0, 0);
+#endif
+}
+
+static inline void linefeed(void)
+{
+       if(++cursor_y >= NROWS) {
+               scroll();
+               --cursor_y;
+       }
+}
+
+void con_putchar(int c)
+{
+#ifdef CON_TEXTMODE
+       uint16_t *ptr;
+
+       switch(c) {
+       case '\n':
+               linefeed();
+       case '\r':
+               cursor_x = 0;
+               crtc_cursor(cursor_x, cursor_y);
+               break;
+
+       case '\t':
+               cursor_x = (cursor_x & 0x7) + 8;
+               if(cursor_x >= NCOLS) {
+                       linefeed();
+                       cursor_x = 0;
+               }
+               crtc_cursor(cursor_x, cursor_y);
+               break;
+
+       default:
+               ptr = (uint16_t*)TEXT_ADDR;
+               ptr[(cursor_y + start_line) * NCOLS + cursor_x] = VMEM_CHAR(c, txattr);
+
+               if(++cursor_x >= NCOLS) {
+                       linefeed();
+                       cursor_x = 0;
+               }
+               crtc_cursor(cursor_x, cursor_y);
+       }
+#endif
+
+#ifdef CON_SERIAL
+       ser_putchar(c);
+#endif
+}
+
+static void scroll(void)
+{
+       int new_line;
+
+       if(++start_line > VIRT_ROWS - NROWS) {
+               /* The bottom of the visible range reached the end of our text buffer.
+                * Copy the rest of the lines to the top and reset start_line.
+                */
+               memcpy(TEXT_ADDR, TEXT_ADDR + start_line * NCOLS, (NROWS - 1) * NCOLS * 2);
+               start_line = 0;
+       }
+
+       /* clear the next line that will be revealed by scrolling */
+       new_line = start_line + NROWS - 1;
+       memset16(TEXT_ADDR + new_line * NCOLS, VMEM_CHAR(' ', txattr), NCOLS);
+       crtc_setstart(start_line);
+}
+
+static void crtc_cursor(int x, int y)
+{
+       unsigned int addr;
+
+       addr = (y + start_line) * NCOLS + x;
+
+       crtc_write(CRTC_REG_CURLOC_L, addr);
+       crtc_write(CRTC_REG_CURLOC_H, addr >> 8);
+}
+
+static void crtc_setstart(int y)
+{
+       unsigned int addr = y * NCOLS;
+
+       crtc_write(CRTC_REG_START_L, addr);
+       crtc_write(CRTC_REG_START_H, addr >> 8);
+}
+
+static inline unsigned char crtc_read(int reg)
+{
+       outb(reg, CRTC_ADDR);
+       return inb(CRTC_DATA);
+}
+
+static inline void crtc_write(int reg, unsigned char val)
+{
+       outb(reg, CRTC_ADDR);
+       outb(val, CRTC_DATA);
+}
+
+static inline void crtc_write_bits(int reg, unsigned char val, unsigned char mask)
+{
+       unsigned char prev;
+       outb(reg, CRTC_ADDR);
+       prev = inb(CRTC_DATA);
+       val = (prev & ~mask) | (val & mask);
+       outb(val, CRTC_DATA);
+}