kexts: add generic vga/fb tty driver

This commit is contained in:
2023-06-10 21:41:46 +01:00
parent d09ad5838e
commit 4cd9ebcb4f
9 changed files with 395 additions and 7 deletions

View File

@@ -0,0 +1,10 @@
name: fbcon
description: |
VGA/Framebuffer kernel console.
id: net.doorstuck.socks.fbcon
license: BSD-3-Clause
copyright: Copyright © Max Wash 2023
sources:
- main.c
- fbcon.c
- vgacon.c

View File

@@ -0,0 +1,91 @@
#include <socks/tty.h>
#include "fbcon.h"
#define CELL_WIDTH 8
#define CELL_HEIGHT 16
static void fbcon_init(struct device *dev)
{
}
static void fbcon_deinit(struct device *dev)
{
}
static void fbcon_clear(struct device *dev, int x, int y, int width, int height)
{
}
static void fbcon_putc(struct device *dev, int c, int xpos, int ypos, tty_attrib_t attrib)
{
}
static void fbcon_set_cursor(struct device *dev, enum tty_cursor cur)
{
}
static void fbcon_move_cursor(struct device *dev, int x, int y)
{
}
static void fbcon_scroll(struct device *dev, enum tty_scroll_dir dir, int lines)
{
}
static struct tty_driver_ops fbcon_ops = {
.tty_init = fbcon_init,
.tty_deinit = fbcon_deinit,
.tty_clear = fbcon_clear,
.tty_putc = fbcon_putc,
.tty_set_cursor = fbcon_set_cursor,
.tty_move_cursor = fbcon_move_cursor,
.tty_scroll = fbcon_scroll,
};
kern_status_t init_fbcon_console(struct device *tty, struct device *fb)
{
struct char_device *cdev = CHAR_DEVICE(tty);
struct framebuffer_varinfo fb_mode;
struct framebuffer_fixedinfo fixedinfo;
struct tty_device *ttydev = cdev->c_tty;
struct fbcon_priv *priv = kmalloc(sizeof *priv, VM_NORMAL);
if (!priv) {
return KERN_NO_MEMORY;
}
kern_status_t status = framebuffer_get_varinfo(fb, &fb_mode);
if (status != KERN_OK) {
kfree(priv);
return status;
}
status = framebuffer_get_fixedinfo(fb, &fixedinfo);
if (status != KERN_OK) {
kfree(priv);
return status;
}
ttydev->tty_xcells = fb_mode.fb_xres / CELL_WIDTH;
ttydev->tty_ycells = fb_mode.fb_yres / CELL_HEIGHT;
ttydev->tty_xcur = 0;
ttydev->tty_ycur = 0;
priv->fbdev = fb;
priv->fb_pitch = fb_mode.fb_stride;
priv->fb_pixels = vm_phys_to_virt(fixedinfo.fb_baseptr);
priv->tty_ops = &fbcon_ops;
tty->dev_priv = priv;
return KERN_OK;
}

View File

@@ -0,0 +1,24 @@
#ifndef FBCON_H_
#define FBCON_H_
#include <socks/status.h>
#include <stdint.h>
struct fbcon_priv {
struct device *fbdev;
union {
uint32_t *fb_pixels;
uint16_t *fb_cells;
};
unsigned long fb_pitch;
struct tty_driver_ops *tty_ops;
};
struct device;
struct tty_driver_ops;
extern kern_status_t init_fbcon_console(struct device *tty, struct device *fb);
extern kern_status_t init_vgacon_console(struct device *tty, struct device *fb);
#endif

View File

@@ -0,0 +1,11 @@
#ifndef SOCKS_FBCON_H_
#define SOCKS_FBCON_H_
#include <socks/status.h>
struct device;
extern kern_status_t start_console_on_framebuffer(struct device *fb);
extern void early_vgacon_init(void);
#endif

View File

@@ -0,0 +1,110 @@
#include <socks/printk.h>
#include <socks/device.h>
#include <socks/kext.h>
#include <socks/tty.h>
#include <socks/libc/stdio.h>
#include "fbcon.h"
static struct tty_driver *fbcon_driver = NULL;
static struct device *tty0 = NULL;
static void tty_console_write(struct console *con, const char *s, unsigned int len)
{
if (!tty0) {
return;
}
}
static int tty_console_read(struct console *con, char *s, unsigned int len)
{
return 0;
}
static struct console tty_console = {
.c_name = "tty0",
.c_write = tty_console_write,
.c_read = tty_console_read,
};
static void tty_clear(struct device *dev, int x, int y, int width, int height)
{
struct fbcon_priv *priv = dev->dev_priv;
priv->tty_ops->tty_clear(dev, x, y, width, height);
}
static void tty_putc(struct device *dev, int c, int xpos, int ypos, tty_attrib_t attrib)
{
struct fbcon_priv *priv = dev->dev_priv;
priv->tty_ops->tty_putc(dev, c, xpos, ypos, attrib);
}
static void tty_set_cursor(struct device *dev, enum tty_cursor cur)
{
struct fbcon_priv *priv = dev->dev_priv;
priv->tty_ops->tty_set_cursor(dev, cur);
}
static void tty_move_cursor(struct device *dev, int x, int y)
{
struct fbcon_priv *priv = dev->dev_priv;
priv->tty_ops->tty_move_cursor(dev, x, y);
}
static void tty_scroll(struct device *dev, enum tty_scroll_dir dir, int lines)
{
struct fbcon_priv *priv = dev->dev_priv;
priv->tty_ops->tty_scroll(dev, dir, lines);
}
static struct tty_driver_ops tty_ops = {
.tty_clear = tty_clear,
.tty_putc = tty_putc,
.tty_set_cursor = tty_set_cursor,
.tty_move_cursor = tty_move_cursor,
.tty_scroll = tty_scroll,
};
static kern_status_t online(struct kext *self)
{
fbcon_driver = tty_driver_create(self, "tty");
if (!fbcon_driver) {
return KERN_NO_MEMORY;
}
fbcon_driver->tty_ops = &tty_ops;
tty_driver_register(fbcon_driver);
console_register(&tty_console);
return KERN_OK;
}
kern_status_t start_console_on_framebuffer(struct device *fb)
{
struct framebuffer_varinfo fb_mode;
framebuffer_get_varinfo(fb, &fb_mode);
struct device *tty = tty_device_create();
kern_status_t status;
if (fb_mode.fb_flags & FB_MODE_VGATEXT) {
status = init_vgacon_console(tty, fb);
} else {
status = init_fbcon_console(tty, fb);
}
if (status != KERN_OK) {
/* TODO destroy tty device */
return status;
}
if (!tty0) {
tty0 = tty;
}
return status;
}
DEFINE_KEXT("net.doorstuck.socks.fbcon",
online, NULL,
KEXT_NO_DEPENDENCIES);

View File

@@ -0,0 +1,220 @@
#include <socks/tty.h>
#include <arch/serial.h>
#include <socks/libc/string.h>
#include <socks/libc/ctype.h>
#include <arch/ports.h>
#include <socks/console.h>
#include <socks/vm.h>
#include <socks/printk.h>
#include <stdint.h>
#include "fbcon.h"
#define VGA_PORT_CMD 0x3D4
#define VGA_PORT_DATA 0x3D5
#define VGA_CHAR(ch, attrib) ((uint16_t)(ch) | ((uint16_t)(attrib) << 8))
#define DEFAULT_ATTRIB 0x07
static uint16_t *g_console_fb = (uint16_t *)(VM_KERNEL_VOFFSET + 0xb8000);
static const unsigned int k_console_width = 80;
static const unsigned int k_console_height = 25;
static unsigned int g_console_cursor_xpos = 0;
static unsigned int g_console_cursor_ypos = 0;
static void init_vga_cursor(void)
{
unsigned int start = 0, end = 15;
outportb(VGA_PORT_CMD, 0x0A);
outportb(VGA_PORT_DATA, (inportb(VGA_PORT_DATA) & 0xC0) | start);
outportb(VGA_PORT_CMD, 0x0B);
outportb(VGA_PORT_DATA, (inportb(VGA_PORT_DATA) & 0xE0) | end);
}
static void move_vga_cursor(unsigned int x, unsigned int y)
{
unsigned int offset = y * k_console_width + x;
outportb(VGA_PORT_CMD, 0x0F);
outportb(VGA_PORT_DATA, (uint8_t)(offset & 0xFF));
outportb(VGA_PORT_CMD, 0x0E);
outportb(VGA_PORT_DATA, (uint8_t)((offset >> 8) & 0xFF));
}
static void scroll_display()
{
uint16_t *src = g_console_fb + k_console_width;
uint16_t *dst = g_console_fb;
size_t n = k_console_width * (k_console_height - 1) * 2;
memmove(dst, src, n);
dst = g_console_fb + ((k_console_height - 1) * k_console_width);
for (int i = 0; i < k_console_width; i++) {
dst[i] = VGA_CHAR(0, DEFAULT_ATTRIB);
}
}
static void handle_ctrl(int c)
{
switch (c) {
case '\n':
g_console_cursor_xpos = 0;
g_console_cursor_ypos++;
if (g_console_cursor_ypos >= k_console_height) {
scroll_display();
g_console_cursor_ypos = k_console_height - 1;
}
break;
default:
break;
}
move_vga_cursor(g_console_cursor_xpos, g_console_cursor_ypos);
}
static void vgacon_putchar(int c)
{
//serial_putchar(SERIAL_PORT_A, c);
if (iscntrl(c)) {
handle_ctrl(c);
return;
}
g_console_fb[(g_console_cursor_ypos * k_console_width) + g_console_cursor_xpos] = VGA_CHAR(c, DEFAULT_ATTRIB);
g_console_cursor_xpos++;
if (g_console_cursor_xpos >= k_console_width) {
g_console_cursor_xpos = 0;
g_console_cursor_ypos++;
}
if (g_console_cursor_ypos >= k_console_height) {
scroll_display();
g_console_cursor_ypos = k_console_height - 1;
g_console_cursor_xpos = 0;
}
move_vga_cursor(g_console_cursor_xpos, g_console_cursor_ypos);
}
static void vgacon_write(struct console *con, const char *s, unsigned int len)
{
for (unsigned int i = 0; i < len; i++) {
vgacon_putchar(s[i]);
}
}
static struct console early_vgacon = {
.c_name = "vgacon",
.c_flags = CON_BOOT,
.c_write = vgacon_write,
.c_lock = SPIN_LOCK_INIT,
};
void early_vgacon_init(void)
{
g_console_cursor_xpos = 0;
g_console_cursor_ypos = 0;
for (int i = 0; i < k_console_width * k_console_height; i++) {
g_console_fb[i] = DEFAULT_ATTRIB << 8;
}
init_vga_cursor();
move_vga_cursor(g_console_cursor_xpos, g_console_cursor_ypos);
console_register(&early_vgacon);
early_printk_init(&early_vgacon);
}
static void vgacon_init(struct device *dev)
{
}
static void vgacon_deinit(struct device *dev)
{
}
static void vgacon_clear(struct device *dev, int x, int y, int width, int height)
{
}
static void vgacon_putc(struct device *dev, int c, int xpos, int ypos, tty_attrib_t attrib)
{
}
static void vgacon_set_cursor(struct device *dev, enum tty_cursor cur)
{
}
static void vgacon_move_cursor(struct device *dev, int x, int y)
{
}
static void vgacon_scroll(struct device *dev, enum tty_scroll_dir dir, int lines)
{
}
static struct tty_driver_ops vgacon_ops = {
.tty_init = vgacon_init,
.tty_deinit = vgacon_deinit,
.tty_clear = vgacon_clear,
.tty_putc = vgacon_putc,
.tty_set_cursor = vgacon_set_cursor,
.tty_move_cursor = vgacon_move_cursor,
.tty_scroll = vgacon_scroll,
};
kern_status_t init_vgacon_console(struct device *tty, struct device *fb)
{
struct char_device *cdev = CHAR_DEVICE(tty);
struct framebuffer_varinfo fb_mode;
struct framebuffer_fixedinfo fixedinfo;
struct tty_device *ttydev = cdev->c_tty;
struct fbcon_priv *priv = kmalloc(sizeof *priv, VM_NORMAL);
if (!priv) {
return KERN_NO_MEMORY;
}
kern_status_t status = framebuffer_get_varinfo(fb, &fb_mode);
if (status != KERN_OK) {
kfree(priv);
return status;
}
status = framebuffer_get_fixedinfo(fb, &fixedinfo);
if (status != KERN_OK) {
kfree(priv);
return status;
}
ttydev->tty_xcells = fb_mode.fb_xcells;
ttydev->tty_ycells = fb_mode.fb_ycells;
ttydev->tty_xcur = 0;
ttydev->tty_ycur = 0;
priv->fbdev = fb;
priv->fb_pitch = fb_mode.fb_stride;
priv->fb_pixels = vm_phys_to_virt(fixedinfo.fb_baseptr);
priv->tty_ops = &vgacon_ops;
tty->dev_priv = priv;
return KERN_OK;
}

View File

@@ -0,0 +1,8 @@
name: serialcon
description: |
Serial port console.
id: net.doorstuck.socks.serialcon
license: BSD-3-Clause
copyright: Copyright © Max Wash 2023
sources:
- main.c

View File

@@ -0,0 +1,38 @@
#include <socks/printk.h>
#include <socks/device.h>
#include <socks/kext.h>
#include <socks/tty.h>
#include <socks/libc/stdio.h>
static struct tty_driver *serialcon_driver = NULL;
static kern_status_t online(struct kext *self)
{
serialcon_driver = tty_driver_create(self, "ttyS");
if (!serialcon_driver) {
return KERN_NO_MEMORY;
}
tty_driver_register(serialcon_driver);
struct device *ttyS0 = tty_device_create();
struct device *ttyS1 = tty_device_create();
struct device *ttyS2 = tty_device_create();
struct device *ttyS3 = tty_device_create();
snprintf(ttyS0->dev_name, sizeof ttyS0->dev_name, "ttyS0");
snprintf(ttyS1->dev_name, sizeof ttyS1->dev_name, "ttyS1");
snprintf(ttyS2->dev_name, sizeof ttyS2->dev_name, "ttyS2");
snprintf(ttyS3->dev_name, sizeof ttyS3->dev_name, "ttyS3");
tty_device_register(ttyS0, serialcon_driver, misc_device());
tty_device_register(ttyS1, serialcon_driver, misc_device());
tty_device_register(ttyS2, serialcon_driver, misc_device());
tty_device_register(ttyS3, serialcon_driver, misc_device());
return KERN_OK;
}
DEFINE_KEXT("net.doorstuck.socks.serialcon",
online, NULL,
KEXT_NO_DEPENDENCIES);