From: Duje Mihanović <duje.mihanovic@skole.hr>
Date: Sat, 2 Jul 2022 12:54:37 +0000 (+0200)
Subject: kernel: Huge refactoring of tty driver
X-Git-Url: http://git.dujemihanovic.xyz/html/static/gitweb.css?a=commitdiff_plain;h=119dc631e1b417eec4f0eb2d8373d034b53d0f2e;p=nameless-os.git

kernel: Huge refactoring of tty driver

The VGA-specific parts now reside solely at arch/x86/tty.c and the
non-arch-specific functions (kprint*) are in kernel/kprint.c.

TODO: Make kernel/kprint.c more device agnostic
---

diff --git a/kernel/arch/x86/Makefile b/kernel/arch/x86/Makefile
index b164c9d..c15bef9 100644
--- a/kernel/arch/x86/Makefile
+++ b/kernel/arch/x86/Makefile
@@ -1,4 +1,3 @@
 include arch/x86/irq/Makefile
-include arch/x86/tty/Makefile
 
-KERNEL_OBJ += $(addprefix arch/x86/, entry.o halt.o)
+KERNEL_OBJ += $(addprefix arch/x86/, entry.o halt.o tty.o)
diff --git a/kernel/arch/x86/irq/interrupt.c b/kernel/arch/x86/irq/interrupt.c
index 5c448fe..b3c3173 100644
--- a/kernel/arch/x86/irq/interrupt.c
+++ b/kernel/arch/x86/irq/interrupt.c
@@ -1,6 +1,6 @@
 #include <irq/idt.h>
 #include <irq/interrupt.h>
-#include <tty.h>
+#include <kprint.h>
 #include <stddef.h>
 #include <irq/i8259a.h>
 
@@ -11,15 +11,15 @@ void int_handler(struct interrupt_frame *frame)
 {
 	int interrupt = frame->interrupt;
 	if (int_handler_table[interrupt] == NULL) {
-		kprint("WARNING: Unhandled interrupt ", 0);
+		kprint("WARNING: Unhandled interrupt ", VGA_YELLOW, VGA_BLACK);
 		kprintb(interrupt, 1);
-		kprint(" occurred!\n", 0);
+		kprint(" occurred!\n", VGA_YELLOW, VGA_BLACK);
 	} else {
 		int ret = (*int_handler_table[interrupt])(frame);
 		if (ret) {
-			kprint("WARNING: Error while handling interrupt ", 0);
+			kprint("WARNING: Error while handling interrupt ", VGA_YELLOW, VGA_BLACK);
 			kprintb(interrupt, 1);
-			kprint("!\n", 0);
+			kprint("!\n", VGA_YELLOW, VGA_BLACK);
 		}
 	}
 	if (interrupt >= 0x20) {
diff --git a/kernel/arch/x86/tty.c b/kernel/arch/x86/tty.c
new file mode 100644
index 0000000..6796594
--- /dev/null
+++ b/kernel/arch/x86/tty.c
@@ -0,0 +1,94 @@
+#include <io.h>
+#include <tty.h>
+#include <stdint.h>
+
+#define VGA_WIDTH 80
+#define VGA_HEIGHT 25
+
+static int cursor_x = 0; /* keep track of where cursor is */
+static int cursor_y = 0;
+static uint16_t crtc_port;
+
+static inline uint8_t vga_get_color(const enum vga_color fg, const enum vga_color bg)
+{
+	return fg&0xf | bg<<4;
+}
+
+static inline uint16_t vga_get_char(const enum vga_color fg, const enum vga_color bg, char character)
+{
+	return character | vga_get_color(fg, bg)<<8;
+}
+
+static inline char *vga_get_memory_address(int x, int y)
+{
+	return (char *) 0xb8000 + (y*VGA_WIDTH + x)*2;
+}
+
+static void vga_scroll_up(void)
+{
+	for (int y=1; y<VGA_HEIGHT; y++) {
+		for (int x = 0; x<VGA_WIDTH; x++) {
+			*vga_get_memory_address(x, y-1) = *vga_get_memory_address(x, y);
+		}
+	}
+
+	for (int x = 0; x<VGA_WIDTH; x++) {
+		*vga_get_memory_address(x, VGA_HEIGHT-1) = vga_get_char(VGA_LIGHT_GRAY, VGA_BLACK, ' ');
+	}
+	cursor_y = VGA_HEIGHT - 1;
+}
+
+static void vga_set_cursor(int x, int y)
+{
+	uint16_t cursor_address = y*VGA_WIDTH + x;
+
+	outb(crtc_port, 0xe);
+	outb(crtc_port+1, cursor_address>>8);
+	outb(crtc_port, 0xf);
+	outb(crtc_port+1, cursor_address);
+}
+
+static void vga_screen_clear(void)
+{
+	for (int y=0; y<VGA_HEIGHT; y++) {
+		for (int x=0; x<VGA_WIDTH; x++) {
+			*vga_get_memory_address(x, y) = vga_get_char(VGA_LIGHT_GRAY, VGA_BLACK, ' ');
+		}
+	}
+
+	cursor_x = 0;
+	cursor_y = 0;
+	vga_set_cursor(0, 0);
+}
+
+void vga_print_char(const char character, const enum vga_color fg, const enum vga_color bg)
+{
+	if (character == '\n') {
+		cursor_x = 0;
+		cursor_y++;
+	} else {
+		*vga_get_memory_address(cursor_x, cursor_y) = vga_get_char(fg, bg, character);
+		cursor_x++;
+	}
+
+	if (cursor_x >= VGA_WIDTH) {
+		cursor_x = 0;
+		cursor_y++;
+	}
+
+	if (cursor_y >= VGA_HEIGHT)
+		vga_scroll_up();
+
+	vga_set_cursor(cursor_x, cursor_y);
+}
+
+void vga_initialize()
+{
+	uint8_t vga_misc = inb(0x3cc);
+	if (vga_misc&1)
+		crtc_port = 0x3d4;
+	else
+		crtc_port = 0x3b4;
+
+	vga_screen_clear();
+}
diff --git a/kernel/arch/x86/tty/Makefile b/kernel/arch/x86/tty/Makefile
deleted file mode 100644
index 0498223..0000000
--- a/kernel/arch/x86/tty/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-KERNEL_OBJ += arch/x86/tty/tty.o
diff --git a/kernel/arch/x86/tty/tty.c b/kernel/arch/x86/tty/tty.c
deleted file mode 100644
index ca3212a..0000000
--- a/kernel/arch/x86/tty/tty.c
+++ /dev/null
@@ -1,172 +0,0 @@
-#include <io.h>
-#include <tty.h>
-#include <stdint.h>
-
-#define VGA_WIDTH 80
-#define VGA_HEIGHT 25
-
-volatile char *video_memory = (char *) 0xB8000; /* VGA VRAM starts at 0xB8000 */
-
-static int cursor_x = 0; /* keep track of where cursor is */
-static int cursor_y = 0;
-
-char *hex_chars = "0123456789ABCDEF";
-
-void screen_clear(void)
-{
-	int x, y;
-	for ( y = 0; y < VGA_HEIGHT; y++ ) {
-		for ( x = 0; x < VGA_WIDTH; x++ ) {
-			video_memory[(y * VGA_WIDTH + x) * 2 + 1] = VGA_COLOR_LIGHT_GRAY;
-			video_memory[(y * VGA_WIDTH + x) * 2] = ' ';
-		}
-	}
-
-	cursor_x = 0;
-	cursor_y = 0;
-}
-
-void scroll_up(void)
-{
-	int x, y;
-	for ( y = 1; y < VGA_HEIGHT; y++ ) {
-		for ( x = 0; x < VGA_WIDTH; x++ ) {
-			video_memory[((y - 1) * VGA_WIDTH + x) * 2] = video_memory[(y * VGA_WIDTH + x) * 2];
-		}
-	}
-	for ( x = 0; x < VGA_WIDTH; x++ ) {
-		video_memory[((VGA_HEIGHT - 1) * VGA_WIDTH + x) * 2] = ' ';
-	}
-	cursor_y = VGA_HEIGHT - 1;
-}
-
-void kprint(const char *string, uint8_t color)
-{
-	char next_char;
-	uint8_t vga_misc_output;
-	uint16_t crtc_port;
-	next_char = *string;
-
-	while ( next_char != 0 ) {
-		if ( next_char == '\n') { cursor_x = 0; cursor_y++; }
-		else { video_memory[(cursor_y * VGA_WIDTH + cursor_x) * 2] = next_char; video_memory[((cursor_y * VGA_WIDTH + cursor_x++) * 2)+ 1] = color != 0 ? color : VGA_COLOR_LIGHT_GRAY; }
-		if ( cursor_x >= VGA_WIDTH ) { cursor_x = 0; cursor_y++; }
-		if ( cursor_y >= VGA_HEIGHT ) { scroll_up(); }
-		next_char = *++string;
-	}
-
-	vga_misc_output = inb(0x3CC);
-	if (vga_misc_output & 0x1 == 0) {
-		crtc_port = 0x3B4;
-	} else {
-		crtc_port = 0x3D4;
-	}
-
-	outb(crtc_port, 0xE);
-	outb(crtc_port + 1, (cursor_y * VGA_WIDTH + cursor_x) >> 8);
-	outb(crtc_port, 0xF);
-	outb(crtc_port + 1, (cursor_y * VGA_WIDTH + cursor_x) & 0xFF);
-}
-
-void kprintc(const char character, uint8_t color)
-{
-	uint8_t vga_misc_output;
-	uint16_t crtc_port;
-
-	if ( character == '\n') { cursor_x = 0; cursor_y++; }
-	else { video_memory[(cursor_y * VGA_WIDTH + cursor_x) * 2] = character; video_memory[((cursor_y * VGA_WIDTH + cursor_x++) * 2)+ 1] = color != 0 ? color : VGA_COLOR_LIGHT_GRAY; }
-	if ( cursor_x >= VGA_WIDTH ) { cursor_x = 0; cursor_y++; }
-	if ( cursor_y >= VGA_HEIGHT ) { scroll_up(); }
-
-	vga_misc_output = inb(0x3CC);
-	if (vga_misc_output & 0x1 == 0) {
-		crtc_port = 0x3B4;
-	} else {
-		crtc_port = 0x3D4;
-	}
-
-	outb(crtc_port, 0xE);
-	outb(crtc_port + 1, (cursor_y * VGA_WIDTH + cursor_x) >> 8);
-	outb(crtc_port, 0xF);
-	outb(crtc_port + 1, (cursor_y * VGA_WIDTH + cursor_x) & 0xFF);
-
-}
-
-void kprintnibble(uint8_t nibble)
-{
-	nibble &= 0xf;
-	if (nibble < 0xa)
-		kprintc('0' + nibble, 0);
-	else kprintc('a' - 0xa + nibble, 0);
-}
-
-void kprintb(uint8_t byte, int print_delm)
-{
-	if (print_delm)
-		kprint("0x", 0);
-
-	kprintnibble(byte >> 4);
-	kprintnibble(byte);
-}
-
-void kprintw(uint16_t word, int print_delm)
-{
-	if (print_delm)
-		kprint("0x", 0);
-
-	kprintb(word >> 8, 0);
-	kprintb(word, 0);
-}
-
-void kprintd(uint32_t dword, int print_delm)
-{
-	if (print_delm)
-		kprint("0x", 0);
-
-	kprintw(dword >> 16, 0);
-	kprintw(dword, 0);
-}
-
-void kprintq(uint64_t qword, int print_delm)
-{
-	if (print_delm)
-		kprint("0x", 0);
-
-	kprintd(qword >> 32, 0);
-	kprintd(qword, 0);
-}
-
-int kprintdec(uint32_t num, uint8_t color)
-{
-	char buffer[11];
-	int digits = 10;
-	/* TODO: make an actual memset function to use instead of this */
-	for (int i=0; i<11; i++) {
-		buffer[i] = 0;
-	}
-
-	/* put the numbers in the buffer */
-	for (int i=9; i>0 && num>0; i--) {
-		uint8_t currdigit = num%10;
-		buffer[i] = currdigit+'0';
-		num /= 10;
-	}
-
-	/* shift the array as much as needed */
-	while (*buffer == '\0') {
-		digits--;
-		for (int i=0; i<9; i++) {
-			buffer[i] = buffer[i+1];
-		}
-	}
-
-	/* zero out any leftovers */
-	if (digits < 10) {
-		for (int i=digits; i<10; i++) {
-			buffer[i] = '\0';
-		}
-	}
-
-	kprint(buffer, color);
-	return digits;
-}
diff --git a/kernel/include/arch/x86/tty.h b/kernel/include/arch/x86/tty.h
new file mode 100644
index 0000000..a7cb8cf
--- /dev/null
+++ b/kernel/include/arch/x86/tty.h
@@ -0,0 +1,25 @@
+#ifndef X86_TTY_H
+#define X86_TTY_H
+
+enum vga_color {
+	VGA_BLACK,
+	VGA_BLUE,
+	VGA_GREEN,
+	VGA_TEAL,
+	VGA_DARK_RED,
+	VGA_MAGENTA,
+	VGA_BROWN,
+	VGA_LIGHT_GRAY,
+	VGA_DARK_GRAY,
+	VGA_PURPLE,
+	VGA_LIME,
+	VGA_CYAN,
+	VGA_BRIGHT_RED,
+	VGA_PINK,
+	VGA_YELLOW,
+	VGA_WHITE
+};
+
+extern void vga_initialize(void);
+extern void vga_print_char(const char character, enum vga_color fg, enum vga_color bg);
+#endif
diff --git a/kernel/include/kprint.h b/kernel/include/kprint.h
new file mode 100644
index 0000000..b883c14
--- /dev/null
+++ b/kernel/include/kprint.h
@@ -0,0 +1,17 @@
+#ifndef KPRINT_H
+#define KPRINT_H
+
+#include <stdint.h>
+#include <tty.h>
+
+extern void tty_initialize();
+extern void kprint(const char *string, const enum vga_color fg, const enum vga_color bg);
+extern void kprintc(const char character, const enum vga_color fg, const enum vga_color bg);
+extern void kprintnibble(uint8_t nibble);
+extern void kprintb(const uint8_t byte, const int print_delm);
+extern void kprintw(const uint16_t word, const int print_delm);
+extern void kprintd(const uint32_t dword, const int print_delm);
+extern void kprintq(const uint64_t qword, const int print_delm);
+extern int kprintdec(uint32_t num, const enum vga_color fg, const enum vga_color bg);
+
+#endif
diff --git a/kernel/include/panic.h b/kernel/include/panic.h
index f481e0c..5c4d662 100644
--- a/kernel/include/panic.h
+++ b/kernel/include/panic.h
@@ -4,15 +4,15 @@
 extern void halt();
 
 #define PANIC(msg) \
-	kprint("PANIC (", VGA_COLOR_BRIGHT_RED);\
-	kprint(msg, VGA_COLOR_BRIGHT_RED);\
-	kprint(") in ", VGA_COLOR_BRIGHT_RED);\
-	kprint(__FILE__, VGA_COLOR_BRIGHT_RED);\
-	kprintc(':', VGA_COLOR_BRIGHT_RED);\
-	kprintdec(__LINE__, VGA_COLOR_BRIGHT_RED);\
-	kprintc(':', VGA_COLOR_BRIGHT_RED);\
-	kprint(__func__, VGA_COLOR_BRIGHT_RED);\
-	kprint("()", VGA_COLOR_BRIGHT_RED);\
+	kprint("PANIC (", VGA_BRIGHT_RED, VGA_BLACK);\
+	kprint(msg, VGA_BRIGHT_RED, VGA_BLACK);\
+	kprint(") in ", VGA_BRIGHT_RED, VGA_BLACK);\
+	kprint(__FILE__, VGA_BRIGHT_RED, VGA_BLACK);\
+	kprintc(':', VGA_BRIGHT_RED, VGA_BLACK);\
+	kprintdec(__LINE__, VGA_BRIGHT_RED, VGA_BLACK);\
+	kprintc(':', VGA_BRIGHT_RED, VGA_BLACK);\
+	kprint(__func__, VGA_BRIGHT_RED, VGA_BLACK);\
+	kprint("()", VGA_BRIGHT_RED, VGA_BLACK);\
 	halt();
 
 #endif
diff --git a/kernel/include/tty.h b/kernel/include/tty.h
deleted file mode 100644
index 87aad81..0000000
--- a/kernel/include/tty.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef TTY_H
-#define TTY_H
-
-#include <stdint.h>
-
-#define VGA_COLOR_BLACK 0x0
-#define VGA_COLOR_BLUE 0x1
-#define VGA_COLOR_GREEN 0x2
-#define VGA_COLOR_TEAL 0x3
-#define VGA_COLOR_DARK_RED 0x4
-#define VGA_COLOR_MAGENTA 0x5
-#define VGA_COLOR_BROWN 0x6
-#define VGA_COLOR_LIGHT_GRAY 0x7
-#define VGA_COLOR_DARK_GRAY 0x8
-#define VGA_COLOR_PURPLE 0x9
-#define VGA_COLOR_LIME 0xA
-#define VGA_COLOR_CYAN 0xB
-#define VGA_COLOR_BRIGHT_RED 0xC
-#define VGA_COLOR_PINK 0xD
-#define VGA_COLOR_YELLOW 0xE
-#define VGA_COLOR_WHITE 0xF
-
-extern void screen_clear(void);
-extern void kprint(const char *string, uint8_t color);
-extern void kprintc(const char character, uint8_t color);
-extern void kprintb(uint8_t byte, int print_delm);
-extern void kprintw(uint16_t word, int print_delm);
-extern void kprintd(uint32_t dword, int print_delm);
-extern void kprintq(uint64_t qword, int print_delm);
-extern int kprintdec(uint32_t num, uint8_t color);
-#endif
diff --git a/kernel/kernel/Makefile b/kernel/kernel/Makefile
index 8716875..1827b72 100644
--- a/kernel/kernel/Makefile
+++ b/kernel/kernel/Makefile
@@ -1 +1 @@
-KERNEL_OBJ += kernel/kernel.o
+KERNEL_OBJ += $(addprefix kernel/, kernel.o kprint.o)
diff --git a/kernel/kernel/kernel.c b/kernel/kernel/kernel.c
index cd3e228..64e64ae 100644
--- a/kernel/kernel/kernel.c
+++ b/kernel/kernel/kernel.c
@@ -1,4 +1,4 @@
-#include <tty.h>
+#include <kprint.h>
 #include <io.h>
 #include <irq/idt.h>
 #include <irq/interrupt.h>
@@ -20,78 +20,78 @@ struct e820_map {
 
 void print_e820(struct e820_map *mmap, int mmap_size)
 {
-	kprint("       Base       |      Length      |   Type   |  Attrib  |\n", 0);
-	kprint("------------------------------------------------------------\n", 0);
+	kprint("       Base       |      Length      |   Type   |  Attrib  |\n", VGA_LIGHT_GRAY, VGA_BLACK);
+	kprint("------------------------------------------------------------\n", VGA_LIGHT_GRAY, VGA_BLACK);
 	for (int i=0; i<mmap_size; i++) {
 		kprintq(mmap[i].base, 1);
-		kprintc('|', 0);
+		kprintc('|', VGA_LIGHT_GRAY, VGA_BLACK);
 		kprintq(mmap[i].length, 1);
-		kprintc('|', 0);
+		kprintc('|', VGA_LIGHT_GRAY, VGA_BLACK);
 		kprintd(mmap[i].type, 1);
-		kprintc('|', 0);
+		kprintc('|', VGA_LIGHT_GRAY, VGA_BLACK);
 		kprintd(mmap[i].attrib, 1);
-		kprintc('|', 0);
-		kprintc('\n', 0);
+		kprintc('|', VGA_LIGHT_GRAY, VGA_BLACK);
+		kprintc('\n', VGA_LIGHT_GRAY, VGA_BLACK);
 	}
 }
 
 /* Small handler for double faults. Will be put elsewhere eventually. */
 int double_fault_handler(struct interrupt_frame *frame)
 {
-	kprint("Double fault occurred!\n", VGA_COLOR_BRIGHT_RED);
-	kprint("EAX: ", 0);
+	kprint("Double fault occurred!\n", VGA_BRIGHT_RED, VGA_BLACK);
+	kprint("EAX: ", VGA_LIGHT_GRAY, VGA_BLACK);
 	kprintd(frame->eax, 1);
-	kprintc(' ', 0);
-	kprint("EBX: ", 0);
+	kprintc(' ', VGA_LIGHT_GRAY, VGA_BLACK);
+	kprint("EBX: ", VGA_LIGHT_GRAY, VGA_BLACK);
 	kprintd(frame->ebx, 1);
-	kprintc(' ', 0);
-	kprint("ECX: ", 0);
+	kprintc(' ', VGA_LIGHT_GRAY, VGA_BLACK);
+	kprint("ECX: ", VGA_LIGHT_GRAY, VGA_BLACK);
 	kprintd(frame->ecx, 1);
-	kprintc(' ', 0);
-	kprint("EDX: ", 0);
+	kprintc(' ', VGA_LIGHT_GRAY, VGA_BLACK);
+	kprint("EDX: ", VGA_LIGHT_GRAY, VGA_BLACK);
 	kprintd(frame->edx, 1);
-	kprintc('\n', 0);
-	kprint("EBP: ", 0);
+	kprintc('\n', VGA_LIGHT_GRAY, VGA_BLACK);
+	kprint("EBP: ", VGA_LIGHT_GRAY, VGA_BLACK);
 	kprintd(frame->ebp, 1);
-	kprintc(' ', 0);
-	kprint("ESP: ", 0);
+	kprintc(' ', VGA_LIGHT_GRAY, VGA_BLACK);
+	kprint("ESP: ", VGA_LIGHT_GRAY, VGA_BLACK);
 	kprintd(frame->esp, 1);
-	kprintc('\n', 0);
-	kprint("ESI: ", 0);
+	kprintc('\n', VGA_LIGHT_GRAY, VGA_BLACK);
+	kprint("ESI: ", VGA_LIGHT_GRAY, VGA_BLACK);
 	kprintd(frame->esi, 1);
-	kprintc(' ', 0);
-	kprint("EDI: ", 0);
+	kprintc(' ', VGA_LIGHT_GRAY, VGA_BLACK);
+	kprint("EDI: ", VGA_LIGHT_GRAY, VGA_BLACK);
 	kprintd(frame->edi, 1);
-	kprintc('\n', 0);
-	kprint("EIP: ", 0);
+	kprintc('\n', VGA_LIGHT_GRAY, VGA_BLACK);
+	kprint("EIP: ", VGA_LIGHT_GRAY, VGA_BLACK);
 	kprintd(frame->eip, 1);
-	kprintc(' ', 0);
-	kprint("EFLAGS: ", 0);
+	kprintc(' ', VGA_LIGHT_GRAY, VGA_BLACK);
+	kprint("EFLAGS: ", VGA_LIGHT_GRAY, VGA_BLACK);
 	kprintd(frame->eflags, 1);
-	kprintc('\n', 0);
+	kprintc('\n', VGA_LIGHT_GRAY, VGA_BLACK);
 	PANIC("double fault");
 }
 
 void kmain(struct e820_map *mmap, int mmap_size)
 {
-	screen_clear();
-	kprint("Welcome to Nameless OS!\nRunning revision: ", 0);
-	kprint(GIT_COMMIT, 0);
-	kprint("\n", 0);
-	kprint("BIOS memory map:\n", 0);
+	vga_initialize();
+	kprint("Welcome to Nameless OS!\nRunning revision: ", VGA_LIGHT_GRAY, VGA_BLACK);
+	kprint(GIT_COMMIT, VGA_LIGHT_GRAY, VGA_BLACK);
+	kprint("\n", VGA_LIGHT_GRAY, VGA_BLACK);
+	kprint("BIOS memory map:\n", VGA_LIGHT_GRAY, VGA_BLACK);
 	print_e820(mmap, mmap_size);
-	kprint("Preparing IDT...\n", 0);
+	kprint("Preparing IDT...\n", VGA_LIGHT_GRAY, VGA_BLACK);
 	for (int i=0; i<48; i++) {
 		idt_set_descriptor(idt, i, 0x8, _int_handler_table[i], IDT_INTERRUPT_GATE, 0);
 	}
-	kprint("IDT prepared, loading...\n", 0);
+	kprint("IDT prepared, loading...\n", VGA_LIGHT_GRAY, VGA_BLACK);
 	populate_idtr(&idtr, idt);
 	load_idt(idtr);
-	kprint("Setting up interrupts...\n", 0);
+	kprint("Setting up interrupts...\n", VGA_LIGHT_GRAY, VGA_BLACK);
 	register_interrupt(8, &double_fault_handler);
 	pic_init(0x20, 0x28);
 	pic_mask_all();
 	asm volatile ("sti");
-	kprint("All done\n", 0);
+	kprint("All done\n", VGA_LIGHT_GRAY, VGA_BLACK);
 	while(1);
 }
diff --git a/kernel/kernel/kprint.c b/kernel/kernel/kprint.c
new file mode 100644
index 0000000..654a0a0
--- /dev/null
+++ b/kernel/kernel/kprint.c
@@ -0,0 +1,100 @@
+#include <stdint.h>
+#include <kprint.h>
+
+void tty_initialize()
+{
+	vga_initialize();
+}
+
+void kprint(const char *string, const enum vga_color fg, const enum vga_color bg)
+{
+	char character = *string;
+	for (int i=1; character; i++) {
+		vga_print_char(character, fg, bg);
+		character = string[i];
+	}
+}
+
+void kprintc(const char character, const enum vga_color fg, const enum vga_color bg)
+{
+	vga_print_char(character, fg, bg);
+}
+
+void kprintnibble(uint8_t nibble)
+{
+	nibble &= 0xf;
+	if (nibble < 0xa)
+		kprintc('0' + nibble, VGA_LIGHT_GRAY, VGA_BLACK);
+	else kprintc('a' - 0xa + nibble, VGA_LIGHT_GRAY, VGA_BLACK);
+}
+
+void kprintb(const uint8_t byte, const int print_delm)
+{
+	if (print_delm)
+		kprint("0x", VGA_LIGHT_GRAY, VGA_BLACK);
+
+	kprintnibble(byte >> 4);
+	kprintnibble(byte);
+}
+
+void kprintw(const uint16_t word, const int print_delm)
+{
+	if (print_delm)
+		kprint("0x", VGA_LIGHT_GRAY, VGA_BLACK);
+
+	kprintb(word >> 8, 0);
+	kprintb(word, 0);
+}
+
+void kprintd(const uint32_t dword, const int print_delm)
+{
+	if (print_delm)
+		kprint("0x", VGA_LIGHT_GRAY, VGA_BLACK);
+
+	kprintw(dword >> 16, 0);
+	kprintw(dword, 0);
+}
+
+void kprintq(const uint64_t qword, const int print_delm)
+{
+	if (print_delm)
+		kprint("0x", VGA_LIGHT_GRAY, VGA_BLACK);
+
+	kprintd(qword >> 32, 0);
+	kprintd(qword, 0);
+}
+
+int kprintdec(uint32_t num, const enum vga_color fg, const enum vga_color bg)
+{
+	char buffer[11];
+	int digits = 10;
+	/* TODO: make an actual memset function to use instead of this */
+	for (int i=0; i<11; i++) {
+		buffer[i] = 0;
+	}
+
+	/* put the numbers in the buffer */
+	for (int i=9; i>0 && num>0; i--) {
+		const uint8_t currdigit = num%10;
+		buffer[i] = currdigit+'0';
+		num /= 10;
+	}
+
+	/* shift the array as much as needed */
+	while (*buffer == '\0') {
+		digits--;
+		for (int i=0; i<9; i++) {
+			buffer[i] = buffer[i+1];
+		}
+	}
+
+	/* zero out any leftovers */
+	if (digits < 10) {
+		for (int i=digits; i<10; i++) {
+			buffer[i] = '\0';
+		}
+	}
+
+	kprint(buffer, fg, bg);
+	return digits;
+}