diff --git a/Makefile b/Makefile index e5bb583..65b4b3d 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ debug: image.bin image.bin: mbr.bin kernel.bin cat $^ >$@ -kernel.bin: kernel.o +kernel.bin: kernel.o vga.o $(LD) -m elf_i386 -o $@ -Ttext 0x1000 $^ --oformat binary %.o: %.c diff --git a/kernel.c b/kernel.c index a1e5157..52fa679 100644 --- a/kernel.c +++ b/kernel.c @@ -1,7 +1,9 @@ asm("jmp main"); +#include "vga.h" + int main() { - char* video_memory = (char*) 0xb8000; - *video_memory = 'X'; + vga_clear_screen(); + vga_print_string("hello world"); return 0; } diff --git a/port.h b/port.h new file mode 100644 index 0000000..edfdf90 --- /dev/null +++ b/port.h @@ -0,0 +1,11 @@ +#pragma once + +static unsigned char port_byte_in(unsigned short port) { + unsigned char result; + __asm__("in %%dx, %%al" : "=a" (result) : "d" (port)); + return result; +} + +static void port_byte_out(unsigned short port, unsigned char data) { + __asm__("out %%al, %%dx" : : "a" (data), "d" (port)); +} diff --git a/vga.c b/vga.c new file mode 100644 index 0000000..c3d10bb --- /dev/null +++ b/vga.c @@ -0,0 +1,51 @@ +#include "port.h" + +char* const video_memory = (char*) 0xb8000; + +enum { + LINES = 25, + COLS = 80, + WHITE_ON_BLACK = 0x0f, + + VGA_CTRL_REGISTER = 0x3d4, + VGA_DATA_REGISTER = 0x3d5, + VGA_OFFSET_LOW = 0x0f, + VGA_OFFSET_HIGH = 0x0e, +}; + +void vga_set_cursor(unsigned offset) { + port_byte_out(VGA_CTRL_REGISTER, VGA_OFFSET_HIGH); + port_byte_out(VGA_DATA_REGISTER, (unsigned char) (offset >> 8)); + port_byte_out(VGA_CTRL_REGISTER, VGA_OFFSET_LOW); + port_byte_out(VGA_DATA_REGISTER, (unsigned char) (offset & 0xff)); +} + +unsigned vga_get_cursor() { + port_byte_out(VGA_CTRL_REGISTER, VGA_OFFSET_HIGH); + unsigned offset = port_byte_in(VGA_DATA_REGISTER) << 8; + port_byte_out(VGA_CTRL_REGISTER, VGA_OFFSET_LOW); + offset += port_byte_in(VGA_DATA_REGISTER); + return offset; +} + +void vga_set_char(unsigned offset, char c) { + video_memory[2 * offset] = c; + video_memory[2 * offset + 1] = WHITE_ON_BLACK; +} + +void vga_clear_screen() { + for (unsigned i = 0; i < LINES * COLS; ++i) { + vga_set_char(i, ' '); + } + vga_set_cursor(0); +} + +void vga_print_string(const char* s) { + int offset = vga_get_cursor(); + while (*s != 0) { + vga_set_char(offset, *s); + s++; + offset++; + } + vga_set_cursor(offset); +} diff --git a/vga.h b/vga.h new file mode 100644 index 0000000..4f09b11 --- /dev/null +++ b/vga.h @@ -0,0 +1,5 @@ +#pragma once + +void vga_clear_screen(); + +void vga_print_string(const char* s);