diff --git a/Makefile b/Makefile index 65b4b3d..36e2470 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ debug: image.bin image.bin: mbr.bin kernel.bin cat $^ >$@ -kernel.bin: kernel.o vga.o +kernel.bin: kernel.o vga.o string.o $(LD) -m elf_i386 -o $@ -Ttext 0x1000 $^ --oformat binary %.o: %.c diff --git a/kernel.c b/kernel.c index 52fa679..181cc7f 100644 --- a/kernel.c +++ b/kernel.c @@ -4,6 +4,8 @@ asm("jmp main"); int main() { vga_clear_screen(); - vga_print_string("hello world"); + for (int i = 0; i < 24; i++) { + vga_print_string("hello world\n"); + } return 0; } diff --git a/string.c b/string.c new file mode 100644 index 0000000..bb71bff --- /dev/null +++ b/string.c @@ -0,0 +1,16 @@ +#include "string.h" + +void kmemmove(char* dst, char* src, size_t size) { + if (dst == src) return; + if (dst > src && dst < src + size) { // s d + // copy right-to-left + for (; size != 0; size--) { + dst[size - 1] = src[size - 1]; + } + } else { + // copy left-to-right + for (size_t i = 0; i < size; ++i) { + dst[i] = src[i]; + } + } +} diff --git a/string.h b/string.h new file mode 100644 index 0000000..9d8b0de --- /dev/null +++ b/string.h @@ -0,0 +1,5 @@ +#pragma once + +typedef unsigned size_t; + +void kmemmove(char* dst, char* src, size_t size); diff --git a/vga.c b/vga.c index c3d10bb..18e9619 100644 --- a/vga.c +++ b/vga.c @@ -1,11 +1,34 @@ #include "port.h" +#include "string.h" char* const video_memory = (char*) 0xb8000; +enum colors16 { + black = 0, + blue, + green, + cyan, + red, + magenta, + brown, + light_gray, + dark_gray, + light_blue, + light_green, + light_cyan, + light_red, + light_magenta, + yellow, + white, +}; + +static unsigned char get_color(unsigned char fg, unsigned char bg) { + return (bg << 4) + fg; +} + enum { - LINES = 25, + ROWS = 25, COLS = 80, - WHITE_ON_BLACK = 0x0f, VGA_CTRL_REGISTER = 0x3d4, VGA_DATA_REGISTER = 0x3d5, @@ -13,6 +36,14 @@ enum { VGA_OFFSET_HIGH = 0x0e, }; +static unsigned get_offset(unsigned col, unsigned row) { + return row * COLS + col; +} + +static unsigned get_row_from_offset(unsigned offset) { + return offset / COLS; +} + 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)); @@ -30,22 +61,37 @@ unsigned vga_get_cursor() { void vga_set_char(unsigned offset, char c) { video_memory[2 * offset] = c; - video_memory[2 * offset + 1] = WHITE_ON_BLACK; + video_memory[2 * offset + 1] = get_color(light_gray, black); } void vga_clear_screen() { - for (unsigned i = 0; i < LINES * COLS; ++i) { + for (unsigned i = 0; i < ROWS * COLS; ++i) { vga_set_char(i, ' '); } vga_set_cursor(0); } +static unsigned scroll() { + kmemmove(video_memory, video_memory + COLS, 2 * COLS * (ROWS-1)); + for (int col = 0; col < COLS; col++) { + vga_set_char(get_offset(col, ROWS - 1), ' '); + } + return get_offset(0, ROWS - 1); +} + void vga_print_string(const char* s) { - int offset = vga_get_cursor(); + unsigned offset = vga_get_cursor(); while (*s != 0) { - vga_set_char(offset, *s); + if (*s == '\n') { + offset = get_offset(0, get_row_from_offset(offset) + 1); + } else { + vga_set_char(offset, *s); + offset++; + } s++; - offset++; + if (offset > COLS * ROWS) { + offset = scroll(); + } } vga_set_cursor(offset); }