Files
mango/arch/x86_64/vga.c

127 lines
2.9 KiB
C

#include <arch/irq.h>
#include <arch/ports.h>
#include <arch/serial.h>
#include <mango/libc/stdio.h>
#include <mango/machine/vm.h>
#include <mango/printk.h>
struct vga_console {
uint16_t *vga_framebuffer;
unsigned int vga_cursor_x, vga_cursor_y;
unsigned int vga_screen_width, vga_screen_height;
uint8_t vga_attrib;
};
static struct vga_console vga_con = {
.vga_attrib = 0x0F,
.vga_screen_width = 80,
.vga_screen_height = 25,
.vga_framebuffer = (uint16_t *)0xffffffff800b8000,
};
static void vga_console_clear(struct vga_console *con)
{
size_t len = con->vga_screen_width * con->vga_screen_height;
for (size_t i = 0; i < len; i++) {
con->vga_framebuffer[i] = (uint16_t)con->vga_attrib << 8;
}
con->vga_cursor_x = 0;
con->vga_cursor_y = 0;
}
static void vga_console_show_cursor(struct vga_console *con)
{
size_t start = 0, end = 15;
outportb(0x3D4, 0x0A);
outportb(0x3D5, (inportb(0x3D5) & 0xC0) | start);
outportb(0x3D4, 0x0B);
outportb(0x3D5, (inportb(0x3D5) & 0xE0) | end);
}
static void vga_console_update_cursor(struct vga_console *con)
{
uint16_t pos
= con->vga_cursor_y * con->vga_screen_width + con->vga_cursor_x;
outportb(0x3D4, 0x0F);
outportb(0x3D5, (uint8_t)(pos & 0xFF));
outportb(0x3D4, 0x0E);
outportb(0x3D5, (uint8_t)((pos >> 8) & 0xFF));
}
static void vga_console_scroll(struct vga_console *con)
{
uint16_t *src = &con->vga_framebuffer[con->vga_screen_width];
uint16_t *dest = &con->vga_framebuffer[0];
size_t len = (con->vga_screen_height - 1) * con->vga_screen_width
* sizeof *con->vga_framebuffer;
memcpy(dest, src, len);
dest = &con->vga_framebuffer
[(con->vga_screen_height - 1) * con->vga_screen_width];
len = con->vga_screen_width;
for (size_t i = 0; i < len; i++) {
dest[i] = (uint16_t)con->vga_attrib << 8;
}
con->vga_cursor_x = 0;
con->vga_cursor_y = con->vga_screen_height - 1;
}
static void vga_console_putc(struct vga_console *con, char c)
{
switch (c) {
case '\n':
con->vga_cursor_x = 0;
con->vga_cursor_y++;
break;
case '\r':
con->vga_cursor_x = 0;
break;
default:
con->vga_framebuffer
[con->vga_cursor_y * con->vga_screen_width
+ con->vga_cursor_x]
= ((uint16_t)con->vga_attrib << 8) | c;
con->vga_cursor_x++;
break;
}
if (con->vga_cursor_x >= con->vga_screen_width) {
con->vga_cursor_x = 0;
con->vga_cursor_y++;
}
if (con->vga_cursor_y >= con->vga_screen_height) {
vga_console_scroll(con);
}
}
static void vgacon_write(struct console *con, const char *s, unsigned int len)
{
for (unsigned int i = 0; i < len; i++) {
vga_console_putc(&vga_con, s[i]);
}
vga_console_update_cursor(&vga_con);
}
static struct console vgacon = {
.c_name = "vgacon",
.c_flags = CON_BOOT,
.c_write = vgacon_write,
.c_lock = SPIN_LOCK_INIT,
};
void vgacon_init(void)
{
vga_console_clear(&vga_con);
vga_console_show_cursor(&vga_con);
console_register(&vgacon);
}