(Maybe) better console subsystem

This commit is contained in:
Mark
2020-06-18 16:32:01 +03:00
parent bc36220152
commit dd36f0decf
17 changed files with 475 additions and 102 deletions
+34
View File
@@ -0,0 +1,34 @@
#include "arch/amd64/multiboot2.h"
#include "arch/amd64/hw/vesa.h"
#include "sys/display.h"
#include "sys/debug.h"
#include "sys/mm.h"
static struct display display_vesa_fb;
void amd64_vesa_init(struct multiboot_tag_framebuffer *tag) {
if (tag->common.framebuffer_type == 1) {
//vesa_available = 1;
//vesa_addr = MM_VIRTUALIZE(tag->common.framebuffer_addr);
//vesa_pitch = tag->common.framebuffer_pitch;
//vesa_width = tag->common.framebuffer_width;
//vesa_height = tag->common.framebuffer_height;
//vesa_bpp = tag->common.framebuffer_bpp;
kdebug("Initializing VESA framebuffer\n");
display_vesa_fb.flags = DISP_GRAPHIC | DISP_LFB;
display_vesa_fb.width_pixels = tag->common.framebuffer_width;
display_vesa_fb.height_pixels = tag->common.framebuffer_height;
display_vesa_fb.bpp = tag->common.framebuffer_bpp;
display_vesa_fb.pitch = tag->common.framebuffer_pitch;
display_vesa_fb.framebuffer = MM_VIRTUALIZE(tag->common.framebuffer_addr);
list_head_init(&display_vesa_fb.list);
display_add(&display_vesa_fb);
//kdebug("Set up VESA video:\n");
//kdebug("BPP: %d, Width: %d, Height: %d\n", vesa_bpp, vesa_width, vesa_height);
//kdebug("Addr: %p\n", vesa_addr);
//dev_add(DEV_CLASS_BLOCK, DEV_BLOCK_OTHER, &_vesa_fb0, "fb0");
}
}
+5 -6
View File
@@ -107,12 +107,11 @@ void kernel_early_init(void) {
amd64_mm_init();
// Console can only be initialized after memory buffers can be allocated
//#if defined(VESA_ENABLE)
// if (multiboot_tag_framebuffer) {
// amd64_vesa_init(multiboot_tag_framebuffer);
// }
// amd64_con_init();
//#endif
#if defined(VESA_ENABLE)
if (multiboot_tag_framebuffer) {
amd64_vesa_init(multiboot_tag_framebuffer);
}
#endif
ps2_register_device();
+1 -1
View File
@@ -25,7 +25,7 @@ DEFINES+=-DVESA_ENABLE=1 \
-DVESA_HEIGHT=$(VESA_HEIGHT) \
-DVESA_DEPTH=$(VESA_DEPTH) \
-DVESA_MODE=0
#OBJS+=$(O)/arch/amd64/hw/vesa.o
OBJS+=$(O)/arch/amd64/hw/vesa.o
endif
### From config
+2
View File
@@ -64,6 +64,8 @@ OBJS+=$(O)/sys/ubsan.o \
$(O)/sys/mem/shmem.o \
$(O)/sys/mem/slab.o \
$(O)/sys/wait.o \
$(O)/sys/console.o \
$(O)/sys/display.o \
$(O)/sys/mod.o
DIRS+=$(O)/sys \
$(O)/sys/char \
+3 -3
View File
@@ -3,9 +3,9 @@
struct multiboot_tag_framebuffer;
extern int vesa_available, vesa_hold;
extern uint32_t vesa_width, vesa_height, vesa_pitch, vesa_bpp;
extern uint64_t vesa_addr;
//extern int vesa_available, vesa_hold;
//extern uint32_t vesa_width, vesa_height, vesa_pitch, vesa_bpp;
//extern uint64_t vesa_addr;
void amd64_vesa_init(struct multiboot_tag_framebuffer *info);
void vesa_put(uint32_t x, uint32_t y, uint32_t v);
+2 -2
View File
@@ -1,8 +1,8 @@
#pragma once
#include "sys/types.h"
struct chrdev;
extern struct chrdev *g_keyboard_tty;
struct console;
extern struct console *g_keyboard_console;
#define INPUT_MOD_CONTROL (1 << 0)
#define INPUT_MOD_SHIFT (1 << 1)
+10 -3
View File
@@ -1,14 +1,19 @@
#pragma once
#include "sys/types.h"
#include "sys/list.h"
struct chrdev;
struct console;
struct console_buffer;
struct tty_data {
// Process group ID of the foreground group (session leader)
pid_t fg_pgid;
// Output device info
void *out_dev;
int (*out_putc) (void *dev, char c);
// Console to which the TTY is attached
struct console *master;
struct console_buffer *buffer;
// List link of TTYs which share the same console
struct list_head list;
};
// From keyboard handlers and stuff
@@ -19,4 +24,6 @@ void tty_data_write(struct chrdev *n, char c);
void tty_puts(struct chrdev *n, const char *s);
void tty_putc(struct chrdev *n, char c);
int tty_create(struct console *con);
void tty_init(void);
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#include "sys/types.h"
#include "sys/list.h"
struct chrdev;
struct display;
struct console_buffer;
struct console {
struct display *display;
// Current display
struct chrdev *tty_active;
struct console_buffer *buf_active;
// This console's slaves
struct list_head slaves;
// All consoles
struct list_head list;
uint16_t width_chars, height_chars;
};
// Enslave a TTY to a physical console
void console_attach(struct console *con, struct chrdev *tty);
void console_resize(struct console *con, uint16_t new_width, uint16_t new_height);
void console_putc(struct console *con, struct chrdev *tty, int c);
void console_type(struct console *con, int c);
void console_default_putc(int c);
struct console *console_get_default(void);
void console_init_default(void);
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#include "sys/types.h"
#include "sys/list.h"
// Not a text mode
#define DISP_GRAPHIC (1 << 0)
// Has a linear framebuffer
#define DISP_LFB (1 << 1)
struct display {
// Text modes: set character at y, x
void (*setc) (uint16_t y, uint16_t x, uint16_t c);
// If DISP_GRAPHIC and not DISP_LFB
void (*setpixel) (uint32_t x, uint32_t y, uint32_t c);
uint32_t flags;
// If DISP_GRAPHIC
uint32_t width_pixels, height_pixels;
uint32_t bpp, pitch;
// If DISP_LFB
uintptr_t framebuffer;
uint16_t width_chars, height_chars;
// Private data
void *data;
struct list_head list;
};
void display_add(struct display *d);
struct display *display_create(void);
void display_setc(struct display *disp, uint16_t y, uint16_t x, uint16_t ch);
struct display *display_get_default(void);
+4 -2
View File
@@ -14,5 +14,7 @@ struct psf_font {
uint32_t width;
};
void psf_init(uintptr_t addr, uintptr_t pitch, uint16_t *charw, uint16_t *charh);
void psf_draw(uint16_t row, uint16_t col, uint8_t c, uint32_t fg, uint32_t bg);
extern struct psf_font *font;
struct display;
void psf_draw(struct display *disp, uint16_t row, uint16_t col, uint8_t c, uint32_t fg, uint32_t bg);
+52 -47
View File
@@ -1,51 +1,56 @@
#include "sys/char/input.h"
#include "sys/char/tty.h"
#include "sys/console.h"
#include "sys/debug.h"
#include "sys/ctype.h"
struct chrdev *g_keyboard_tty = 0;
struct console *g_keyboard_console = NULL;
void input_scan(uint8_t c) {
switch (c) {
case INPUT_KEY_UP:
tty_data_write(g_keyboard_tty, '\033');
tty_data_write(g_keyboard_tty, '[');
tty_data_write(g_keyboard_tty, 'A');
break;
case INPUT_KEY_DOWN:
tty_data_write(g_keyboard_tty, '\033');
tty_data_write(g_keyboard_tty, '[');
tty_data_write(g_keyboard_tty, 'B');
break;
case INPUT_KEY_RIGHT:
tty_data_write(g_keyboard_tty, '\033');
tty_data_write(g_keyboard_tty, '[');
tty_data_write(g_keyboard_tty, 'C');
break;
case INPUT_KEY_LEFT:
tty_data_write(g_keyboard_tty, '\033');
tty_data_write(g_keyboard_tty, '[');
tty_data_write(g_keyboard_tty, 'D');
break;
case INPUT_KEY_HOME:
tty_data_write(g_keyboard_tty, '\033');
tty_data_write(g_keyboard_tty, '[');
tty_data_write(g_keyboard_tty, '[');
tty_data_write(g_keyboard_tty, 'H');
break;
case INPUT_KEY_END:
tty_data_write(g_keyboard_tty, '\033');
tty_data_write(g_keyboard_tty, '[');
tty_data_write(g_keyboard_tty, '[');
tty_data_write(g_keyboard_tty, 'F');
break;
default:
kdebug("Ignoring unhandled key: %02x\n", c);
break;
}
//switch (c) {
//case INPUT_KEY_UP:
// tty_data_write(g_keyboard_tty, '\033');
// tty_data_write(g_keyboard_tty, '[');
// tty_data_write(g_keyboard_tty, 'A');
// break;
//case INPUT_KEY_DOWN:
// tty_data_write(g_keyboard_tty, '\033');
// tty_data_write(g_keyboard_tty, '[');
// tty_data_write(g_keyboard_tty, 'B');
// break;
//case INPUT_KEY_RIGHT:
// tty_data_write(g_keyboard_tty, '\033');
// tty_data_write(g_keyboard_tty, '[');
// tty_data_write(g_keyboard_tty, 'C');
// break;
//case INPUT_KEY_LEFT:
// tty_data_write(g_keyboard_tty, '\033');
// tty_data_write(g_keyboard_tty, '[');
// tty_data_write(g_keyboard_tty, 'D');
// break;
//case INPUT_KEY_HOME:
// tty_data_write(g_keyboard_tty, '\033');
// tty_data_write(g_keyboard_tty, '[');
// tty_data_write(g_keyboard_tty, '[');
// tty_data_write(g_keyboard_tty, 'H');
// break;
//case INPUT_KEY_END:
// tty_data_write(g_keyboard_tty, '\033');
// tty_data_write(g_keyboard_tty, '[');
// tty_data_write(g_keyboard_tty, '[');
// tty_data_write(g_keyboard_tty, 'F');
// break;
//default:
// kdebug("Ignoring unhandled key: %02x\n", c);
// break;
//}
}
void input_key(uint8_t key, uint8_t mods, const char *map0, const char *map1) {
if (!g_keyboard_console) {
return;
}
if (!(mods & INPUT_MOD_CONTROL)) {
const char *map = (mods & INPUT_MOD_SHIFT) ? map1 : map0;
uint8_t c = map[key];
@@ -60,20 +65,20 @@ void input_key(uint8_t key, uint8_t mods, const char *map0, const char *map1) {
}
// Normal key
tty_data_write(g_keyboard_tty, c);
console_type(g_keyboard_console, c);
} else {
// Special keys
input_scan(c);
}
} else {
char c = map0[key];
//char c = map0[key];
switch (c) {
case 'c':
case '.':
case 'd':
tty_control_write(g_keyboard_tty, c);
break;
}
//switch (c) {
//case 'c':
//case '.':
//case 'd':
// tty_control_write(g_keyboard_tty, c);
// break;
//}
}
}
+75 -21
View File
@@ -10,6 +10,7 @@
#include "arch/amd64/cpu.h"
#include "sys/char/tty.h"
#include "sys/char/chr.h"
#include "sys/console.h"
#include "sys/string.h"
#include "sys/thread.h"
#include "sys/assert.h"
@@ -17,28 +18,14 @@
#include "sys/debug.h"
#include "sys/sched.h"
#include "sys/panic.h"
#include "sys/heap.h"
#include "sys/dev.h"
#include "sys/mm.h"
static ssize_t tty_write(struct chrdev *tty, const void *buf, size_t pos, size_t lim);
static int tty_ioctl(struct chrdev *tty, unsigned int cmd, void *arg);
// Keyboard + display
static struct tty_data _dev_tty0_data = {
.fg_pgid = 1,
.out_dev = NULL,
.out_putc = NULL, //pc_con_putc
};
static struct chrdev _dev_tty0 = {
.type = CHRDEV_TTY,
.dev_data = &_dev_tty0_data,
.tc = TERMIOS_DEFAULT,
.write = tty_write,
// Line discipline
.read = line_read,
.ioctl = tty_ioctl
};
static const struct termios default_termios = TERMIOS_DEFAULT;
void tty_control_write(struct chrdev *tty, char c) {
struct tty_data *data = tty->dev_data;
@@ -98,18 +85,47 @@ void tty_puts(struct chrdev *tty, const char *s) {
}
}
int tty_create(struct console *master) {
struct chrdev *tty = kmalloc(sizeof(struct chrdev));
_assert(tty);
struct tty_data *data = kmalloc(sizeof(struct tty_data));
_assert(data);
data->fg_pgid = 1;
data->master = NULL;
data->buffer = NULL;
list_head_init(&data->list);
tty->type = CHRDEV_TTY;
memcpy(&tty->tc, &default_termios, sizeof(struct termios));
tty->write = tty_write;
tty->ioctl = tty_ioctl;
tty->read = line_read;
tty->dev_data = data;
ring_init(&tty->buffer, 16);
console_attach(master, tty);
dev_add(DEV_CLASS_CHAR, DEV_CHAR_TTY, tty, "tty0");
return 0;
}
void tty_putc(struct chrdev *tty, char c) {
struct tty_data *data = tty->dev_data;
_assert(data);
//_assert(data->out_putc);
//data->out_putc(data->out_dev, c);
_assert(data->master);
console_putc(data->master, tty, c);
}
void tty_init(void) {
// tty0
ring_init(&_dev_tty0.buffer, 16);
g_keyboard_tty = &_dev_tty0;
dev_add(DEV_CLASS_CHAR, DEV_CHAR_TTY, &_dev_tty0, "tty0");
// ring_init(&_dev_tty0.buffer, 16);
// g_keyboard_tty = &_dev_tty0;
// dev_add(DEV_CLASS_CHAR, DEV_CHAR_TTY, &_dev_tty0, "tty0");
// ttyS0
//ring_init(&_dev_ttyS0.buffer, 16);
@@ -118,9 +134,47 @@ void tty_init(void) {
}
static ssize_t tty_write(struct chrdev *tty, const void *buf, size_t pos, size_t lim) {
struct tty_data *data = tty->dev_data;
_assert(data);
for (size_t i = 0; i < lim; ++i) {
console_putc(data->master, tty, ((const char *) buf)[i]);
}
return lim;
}
static int tty_ioctl(struct chrdev *tty, unsigned int cmd, void *arg) {
struct tty_data *data = tty->dev_data;
_assert(data);
switch (cmd) {
case TIOCGWINSZ:
{
_assert(arg);
struct winsize *winsz = arg;
_assert(data->master);
winsz->ws_col = data->master->width_chars;
winsz->ws_row = data->master->height_chars;
}
return 0;
case TCGETS:
memcpy(arg, &tty->tc, sizeof(struct termios));
return 0;
case TCSETS:
memcpy(&tty->tc, arg, sizeof(struct termios));
if (tty->tc.c_iflag & ICANON) {
tty->buffer.flags &= ~RING_RAW;
} else {
tty->buffer.flags |= RING_RAW;
}
return 0;
case TIOCSPGRP:
// Clear interrupts and stuff
tty->buffer.flags = 0;
data->fg_pgid = *(pid_t *) arg;
return 0;
}
return -EINVAL;
}
+151
View File
@@ -0,0 +1,151 @@
#include "sys/char/input.h"
#include "sys/char/tty.h"
#include "sys/char/chr.h"
#include "sys/display.h"
#include "sys/console.h"
#include "sys/assert.h"
#include "sys/string.h"
#include "sys/debug.h"
#include "sys/heap.h"
#define ATTR_DEFAULT 0x1700
static void console_flush(struct console *con, struct console_buffer *buf);
static LIST_HEAD(g_consoles);
struct console_buffer {
uint16_t attr;
uint16_t y, x;
uint16_t data[0];
};
static struct console_buffer *console_buffer_create(uint16_t rows, uint16_t cols) {
struct console_buffer *buf = kmalloc(sizeof(struct console_buffer) + rows * cols * sizeof(uint16_t));
_assert(buf);
memsetw(buf->data, ATTR_DEFAULT, rows * cols);
buf->y = 0;
buf->x = 0;
buf->attr = ATTR_DEFAULT;
return buf;
}
void console_attach(struct console *con, struct chrdev *tty) {
struct console_buffer *tty_buffer = console_buffer_create(con->width_chars, con->height_chars);
_assert(tty_buffer);
struct tty_data *data = tty->dev_data;
_assert(data);
// Make sure the TTY hasn't already been enslaved to a console
_assert(!data->buffer);
_assert(!data->master);
data->master = con;
data->buffer = tty_buffer;
list_add(&data->list, &con->slaves);
// Make current active TTY if none yet selected
if (!con->tty_active) {
con->tty_active = tty;
con->buf_active = tty_buffer;
// Clear new default console
console_flush(con, tty_buffer);
}
}
static void console_flush(struct console *con, struct console_buffer *buf) {
for (uint16_t row = 0; row < con->height_chars; ++row) {
for (uint16_t col = 0; col < con->width_chars; ++col) {
uint16_t ch = buf->data[row * con->width_chars + col];
display_setc(con->display, row, col, ch);
}
}
}
static void console_scroll_check(struct console *con, struct console_buffer *buf) {
if (buf->y >= con->height_chars) {
buf->y = con->height_chars - 1;
memcpy(buf->data, &buf->data[con->width_chars], (con->height_chars - 1) * con->width_chars * 2);
memsetw(&buf->data[(con->height_chars - 1) * con->width_chars], ATTR_DEFAULT, con->width_chars);
console_flush(con, buf);
}
}
static void _console_putc(struct console *con, struct console_buffer *buf, int c) {
int act = buf == con->buf_active;
if (c == '\n') {
++buf->y;
buf->x = 0;
console_scroll_check(con, buf);
} else if (c >= ' ') {
buf->data[buf->y * con->width_chars + buf->x] = c | buf->attr;
if (act) {
display_setc(con->display, buf->y, buf->x, c | buf->attr);
}
++buf->x;
if (buf->x >= con->width_chars) {
++buf->y;
buf->x = 0;
console_scroll_check(con, buf);
}
}
}
void console_putc(struct console *con, struct chrdev *tty, int c) {
struct tty_data *data = tty->dev_data;
_assert(data);
struct console_buffer *buf = data->buffer;
_assert(buf);
_console_putc(con, buf, c);
}
void console_type(struct console *con, int c) {
if (con->tty_active) {
tty_data_write(con->tty_active, c);
}
}
void console_default_putc(int c) {
if (list_empty(&g_consoles)) {
return;
}
struct console *con = list_entry(g_consoles.next, struct console, list);
if (con->buf_active) {
_console_putc(con, con->buf_active, c);
}
}
void console_init_default(void) {
// Initialize default display+keyboard pair
struct console *con = kmalloc(sizeof(struct console));
_assert(con);
con->tty_active = NULL;
con->buf_active = NULL;
list_head_init(&con->slaves);
list_head_init(&con->list);
struct display *display = display_get_default();
_assert(display);
con->display = display;
// Extract initial display mode
con->width_chars = display->width_chars;
con->height_chars = display->height_chars;
kdebug("Initializing default console: %ux%u\n", con->width_chars, con->height_chars);
if (!g_keyboard_console) {
g_keyboard_console = con;
}
// Create a single TTY device
_assert(tty_create(con) == 0);
list_add(&con->list, &g_consoles);
}
+4 -3
View File
@@ -1,4 +1,5 @@
#include "arch/amd64/multiboot2.h"
#include "sys/console.h"
#include "sys/string.h"
#include "sys/debug.h"
#include "sys/ctype.h"
@@ -197,9 +198,9 @@ void debugc(int level, char c) {
if (DEBUG_SERIAL(level) & kernel_config[CFG_DEBUG]) {
rs232_send(RS232_COM1, c);
}
//if (DEBUG_DISP(level) & kernel_config[CFG_DEBUG]) {
// amd64_con_putc(c);
//}
if (DEBUG_DISP(level) & kernel_config[CFG_DEBUG]) {
console_default_putc(c);
}
#endif
}
+50
View File
@@ -0,0 +1,50 @@
#include "sys/font/psf.h"
#include "sys/display.h"
#include "sys/debug.h"
#include <stddef.h>
static LIST_HEAD(displays);
static uint8_t color_map[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
static uint32_t rgb_map[16] = {
0x000000,
0x0000AA,
0x00AA00,
0x00AAAA,
0xAA0000,
0xAA00AA,
0xAA5500,
0xAAAAAA,
0x555555,
0x5555FF,
0x55FF55,
0x55FFFF,
0xFF5555,
0xFF55FF,
0xFFFF55,
0xFFFFFF,
};
struct display *display_get_default(void) {
if (list_empty(&displays)) {
return NULL;
}
return list_entry(displays.next, struct display, list);
}
void display_add(struct display *disp) {
// Initialize text mode for framebuffers
if (disp->flags & DISP_GRAPHIC) {
disp->width_chars = disp->width_pixels / font->width;
disp->height_chars = disp->height_pixels / font->height;
}
list_add(&disp->list, &displays);
}
void display_setc(struct display *disp, uint16_t y, uint16_t x, uint16_t ch) {
if (disp->flags & DISP_GRAPHIC) {
// TODO: attr conversion
psf_draw(disp, y, x, ch & 0xFF, rgb_map[(ch >> 8) & 0xF], rgb_map[(ch >> 12) & 0xF]);
}
}
+8 -14
View File
@@ -1,26 +1,20 @@
#include "sys/font/psf.h"
#include "sys/display.h"
#include "sys/panic.h"
// XXX: Only supports non-indexed linear buffers
#include "sys/attr.h"
extern char _psf_start;
extern char _psf_end;
static struct psf_font *font;
static uintptr_t psf_fb_addr, psf_fb_pitch;
struct psf_font *font;
void psf_init(uintptr_t addr, uintptr_t pitch, uint16_t *charw, uint16_t *charh) {
static __init void psf_init(void) {
font = (struct psf_font *) &_psf_start;
if (font->magic != PSF_FONT_MAGIC) {
panic("Invalid PSF magic\n");
}
psf_fb_addr = addr;
psf_fb_pitch = pitch;
*charw = font->width;
*charh = font->height;
}
void psf_draw(uint16_t row, uint16_t col, uint8_t c, uint32_t fg, uint32_t bg) {
void psf_draw(struct display *disp, uint16_t row, uint16_t col, uint8_t c, uint32_t fg, uint32_t bg) {
if (c >= font->numglyph) {
c = 0;
}
@@ -31,7 +25,7 @@ void psf_draw(uint16_t row, uint16_t col, uint8_t c, uint32_t fg, uint32_t bg) {
// XXX: Assuming BPP is 32
/* calculate the upper left corner on screen where we want to display.
we only do this once, and adjust the offset later. This is faster. */
uintptr_t offs = (row * font->height * psf_fb_pitch) + (col * font->width * 4);
uintptr_t offs = (row * font->height * disp->pitch) + (col * font->width * 4);
/* finally display pixels according to the bitmap */
uint32_t x, y, line, mask;
for (y = 0; y < font->height; ++y) {
@@ -40,13 +34,13 @@ void psf_draw(uint16_t row, uint16_t col, uint8_t c, uint32_t fg, uint32_t bg) {
mask = 1 << (font->width - 1);
/* display a row */
for (x = 0; x < font->width; ++x) {
*((uint32_t *)(psf_fb_addr + line)) = ((int) *glyph) & (mask) ? fg : bg;
*((uint32_t *)(disp->framebuffer + line)) = ((int) *glyph) & (mask) ? fg : bg;
/* adjust to the next pixel */
mask >>= 1;
line += 4;
}
/* adjust to the next line */
glyph += bytesperline;
offs += psf_fb_pitch;
offs += disp->pitch;
}
}
+2
View File
@@ -2,6 +2,7 @@
#include "drivers/pci/pci.h"
#include "drivers/usb/usb.h"
#include "sys/char/tty.h"
#include "sys/console.h"
#include "sys/sched.h"
#include "sys/panic.h"
#include "fs/sysfs.h"
@@ -13,6 +14,7 @@ void main(void) {
pci_init();
vfs_init();
console_init_default();
tty_init();
sysfs_populate();