127 lines
2.9 KiB
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);
|
|
}
|