From 9a299f2fe91554a1b9d9db402391ae757c591ef8 Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Thu, 11 Feb 2021 16:17:53 +0200 Subject: Add comments to explain CGA ports better --- drivers/cga.cc | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/cga.h | 69 +++++++++++++++++++++++++++++++++ drivers/makefile | 1 + drivers/ports.h | 47 +++++++++++++++++++++++ makefile | 6 ++- src/kernel.cc | 4 +- src/makefile | 1 - src/ports.h | 43 --------------------- src/vga.cc | 92 -------------------------------------------- src/vga.h | 59 ---------------------------- toolchain.makefile | 2 +- 11 files changed, 235 insertions(+), 200 deletions(-) create mode 100644 drivers/cga.cc create mode 100644 drivers/cga.h create mode 100644 drivers/makefile create mode 100644 drivers/ports.h delete mode 100644 src/ports.h delete mode 100644 src/vga.cc delete mode 100644 src/vga.h diff --git a/drivers/cga.cc b/drivers/cga.cc new file mode 100644 index 0000000..79facee --- /dev/null +++ b/drivers/cga.cc @@ -0,0 +1,111 @@ +#include "cga.h" +#include + +static_assert(sizeof(CGA::Entry) == 2); + +/* cga registers, see https://www.lowlevel.eu/wiki/Color_Graphics_Adapter */ +constexpr uint8_t cursor_start = 10; // 0xa +constexpr uint8_t cursor_end = 11; // 0xb +constexpr uint8_t cursor_addr_h = 14; // 0xe +constexpr uint8_t cursor_addr_l = 15; // 0xf + +/* cursor format + * register | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * start | | e | t | scanline | + * end | | scanline | + * e = enable; t = timing + * e t | effect + * 0 0 | no blinking + * 0 1 | hide cursor + * 1 0 | blink normally + * 1 1 | blink fast + */ +constexpr uint8_t cursor_hide = 0b00100000; + +CGA::CGA(Colour fg, Colour bg, uint32_t address) : colour_fg(fg), colour_bg(bg) { + buffer = reinterpret_cast(address); + + // clear buffer + for (size_t y = 0; y < max_rows; y++) { + for (size_t x = 0; x < max_columns; x++) { + const size_t index = y * max_columns + x; + buffer[index].c = ' '; + buffer[index].fg = colour_fg; + buffer[index].bg = colour_bg; + } + } + + enable_cursor(14, 15); + update_cursor(); +} + +void CGA::set_colour(Colour fg, Colour bg) { + colour_fg = fg; + colour_bg = bg; + for (size_t y = 0; y < max_rows; y++) { + for (size_t x = 0; x < max_columns; x++) { + const size_t index = y * max_columns + x; + buffer[index].fg = colour_fg; + buffer[index].bg = colour_bg; + } + } +} + +void CGA::enable_cursor(uint8_t start, uint8_t end) { + p_idx.write(cursor_start); + p_dat.write((p_dat.read() & 0xc0) | start); + + p_idx.write(cursor_end); + p_dat.write((p_dat.read() & 0xe0) | end); +} +void CGA::disable_cursor() { + p_idx.write(cursor_start); + p_dat.write(cursor_hide); +} +void CGA::update_cursor() { + const uint16_t pos = row * max_columns + column; + + p_idx.write(cursor_addr_l); + p_dat.write(static_cast(pos & 0xff)); + + p_idx.write(cursor_addr_h); + p_dat.write(static_cast((pos >> 8) & 0xff)); +} + +void CGA::write(char c) { + switch (c) { + case '\n': + column = 0; + ++row; + break; + default: { + const size_t index = row * max_columns + column; + buffer[index].c = c; + ++column; + } + } + + if (column == max_columns) { + column = 0; + ++row; + } + + if (row == max_rows) { + // scroll up - move rows 1~25 up by one + for (size_t y = 1; y < max_rows; y++) { + const auto prev_y = y - 1; + for (size_t x = 0; x < max_columns; ++x) { + const auto prev = prev_y * max_columns + x; + const auto idx = y * max_columns + x; + buffer[prev] = buffer[idx]; + } + } + --row; + } +} + +void CGA::write(ViewIterator& iter) { + while (iter) { + write(iter.next()); + } +} diff --git a/drivers/cga.h b/drivers/cga.h new file mode 100644 index 0000000..f0ca412 --- /dev/null +++ b/drivers/cga.h @@ -0,0 +1,69 @@ +#pragma once +#include +#include "ports.h" + +/* + * CGA (Colour Graphics Adapter) + * + * useful links: + * https://www.seasip.info/VintagePC/cga.html + * https://www.lowlevel.eu/wiki/Color_Graphics_Adapter + * + * TODO: switching between modes + * TODO: cursor styling + */ + +class CGA : public Console { +public: + /* Hardware text mode colour constants. */ + enum Colour : uint8_t { + CGA_COLOR_BLACK = 0, + CGA_COLOR_BLUE = 1, + CGA_COLOR_GREEN = 2, + CGA_COLOR_CYAN = 3, + CGA_COLOR_RED = 4, + CGA_COLOR_MAGENTA = 5, + CGA_COLOR_BROWN = 6, + CGA_COLOR_LIGHT_GREY = 7, + CGA_COLOR_DARK_GREY = 8, + CGA_COLOR_LIGHT_BLUE = 9, + CGA_COLOR_LIGHT_GREEN = 10, + CGA_COLOR_LIGHT_CYAN = 11, + CGA_COLOR_LIGHT_RED = 12, + CGA_COLOR_LIGHT_MAGENTA = 13, + CGA_COLOR_LIGHT_BROWN = 14, + CGA_COLOR_WHITE = 15, + }; + + CGA(Colour fg = CGA_COLOR_BLACK, Colour bg = CGA_COLOR_LIGHT_GREY, uint32_t address = 0xB8000); + ~CGA() = default; + + void set_colour(Colour fg, Colour bg); + + void enable_cursor(uint8_t start, uint8_t end); + void disable_cursor(); + void update_cursor() override; + + void write(char c) override; + void write(ViewIterator& iter) override; + + + struct Entry { + char c; + Colour fg : 4; + Colour bg : 4; + } __attribute((packed)); + +private: + const size_t max_columns = 80, max_rows = 25; + size_t column = 0, row = 0; + + Colour colour_fg; + Colour colour_bg; + + Entry* buffer; + + // ports + cga_idx_port p_idx; + cga_dat_port p_dat; +}; diff --git a/drivers/makefile b/drivers/makefile new file mode 100644 index 0000000..b76f7c5 --- /dev/null +++ b/drivers/makefile @@ -0,0 +1 @@ +CXX_OBJ += drivers/cga.o diff --git a/drivers/ports.h b/drivers/ports.h new file mode 100644 index 0000000..338c3b8 --- /dev/null +++ b/drivers/ports.h @@ -0,0 +1,47 @@ +#pragma once + +template +concept port_data_t = (is_same::value || is_same::value || is_same::value); + +template +class Port { +public: + [[nodiscard]] T read() { + T result; + + switch (sizeof(T)) { + case 1: + asm volatile("inb %1, %0" : "=a"(result) : "Nd"(port_num)); + break; + case 2: + asm volatile("inw %1, %0" : "=a"(result) : "Nd"(port_num)); + break; + case 4: + asm volatile("inl %1, %0" : "=a"(result) : "Nd"(port_num)); + break; + } + + return result; + } + + void write(T data) { + switch (sizeof(T)) { + case 1: + asm volatile("outb %0, %1" : : "a"(data), "Nd"(port_num)); + break; + case 2: + asm volatile("outw %0, %1" : : "a"(data), "Nd"(port_num)); + break; + case 4: + asm volatile("outl %0, %1" : : "a"(data), "Nd"(port_num)); + break; + } + } +}; + +/* Ports 0x3d0 to 0x3df are reserved for CGA; each port is 1 byte wide */ +typedef Port<0x3d4, uint8_t> cga_idx_port; +typedef Port<0x3d5, uint8_t> cga_dat_port; +// 0x3d8 : mode select register +// 0x3d8 : color control register +// 0x3da : status register diff --git a/makefile b/makefile index f65e699..ccb2b1a 100644 --- a/makefile +++ b/makefile @@ -1,8 +1,10 @@ include toolchain.makefile OBJ_DIR := build -include src/makefile include libk/makefile +include src/makefile +include drivers/makefile + AS_OBJ := $(addprefix $(OBJ_DIR)/, $(AS_OBJ)) CXX_OBJ := $(addprefix $(OBJ_DIR)/, $(CXX_OBJ)) CXX_DEP = $(CXX_OBJ:%o=%.d) @@ -29,7 +31,7 @@ $(CXX_OBJ) $(CXX_TEST_OBJ): $(OBJ_DIR)/%.o : %.cc @$(CXX) -target $(TARGET) $(CXX_FLAGS) $(CXX_INCLUDE) $(CXX_SYSTEM_INCLUDE) -MMD -c $^ -o $@ clean: - rm -rf $(AS_OBJ) $(CXX_OBJ) $(CXX_DEP) $(CXX_TEST_OBJ) glitch.elf isodir + @rm -rf $(AS_OBJ) $(CXX_OBJ) $(CXX_DEP) $(CXX_TEST_OBJ) glitch.elf isodir # testing test: $(CXX_TEST_OBJ) check-grub diff --git a/src/kernel.cc b/src/kernel.cc index 4569107..4c17969 100644 --- a/src/kernel.cc +++ b/src/kernel.cc @@ -10,15 +10,15 @@ #include #include +#include "cga.h" #include "gdt.h" -#include "vga.h" extern "C" { void dump_multiboot(uint32_t mb_magic, uint32_t mb_addr); void dump_gdt(); void kernel_main([[maybe_unused]] uint32_t mb_magic, [[maybe_unused]] uint32_t mb_addr) { - VGA terminal; + CGA terminal; Console::set(&terminal); printk("Hello, kernel World!\n"); diff --git a/src/makefile b/src/makefile index 25c58be..8214d03 100644 --- a/src/makefile +++ b/src/makefile @@ -4,6 +4,5 @@ CXX_OBJ += src/kernel.o \ src/kernel/dump_gdt.o \ src/kernel/dump_multiboot.o \ src/memory.o \ - src/vga.o \ src/gdt.o \ src/gdt/segmentdescriptor.o diff --git a/src/ports.h b/src/ports.h deleted file mode 100644 index 0371bcc..0000000 --- a/src/ports.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -template -concept port_data_t = (is_same::value || is_same::value || is_same::value); - -template -class Port { -public: - [[nodiscard]] T read() { - T result; - - switch (sizeof(T)) { - case 1: - asm volatile("inb %1, %0" : "=a"(result) : "Nd"(port_num)); - break; - case 2: - asm volatile("inw %1, %0" : "=a"(result) : "Nd"(port_num)); - break; - case 4: - asm volatile("inl %1, %0" : "=a"(result) : "Nd"(port_num)); - break; - } - - return result; - } - - void write(T data) { - switch (sizeof(T)) { - case 1: - asm volatile("outb %0, %1" : : "a"(data), "Nd"(port_num)); - break; - case 2: - asm volatile("outw %0, %1" : : "a"(data), "Nd"(port_num)); - break; - case 4: - asm volatile("outl %0, %1" : : "a"(data), "Nd"(port_num)); - break; - } - } -}; - -typedef Port<0x3d4, uint8_t> vga_horizontal_total; -typedef Port<0x3d5, uint8_t> vga_horizontal_display_enable_end; diff --git a/src/vga.cc b/src/vga.cc deleted file mode 100644 index 66a6b3a..0000000 --- a/src/vga.cc +++ /dev/null @@ -1,92 +0,0 @@ -#include "vga.h" -#include - -static_assert(sizeof(VGA::Entry) == 2); - -VGA::VGA(vga_color fg, vga_color bg, uint32_t address) : color_fg(fg), color_bg(bg) { - buffer = reinterpret_cast(address); - - // clear buffer - for (size_t y = 0; y < max_rows; y++) { - for (size_t x = 0; x < max_columns; x++) { - const size_t index = y * max_columns + x; - buffer[index].c = ' '; - buffer[index].fg = color_fg; - buffer[index].bg = color_bg; - } - } - - enable_cursor(14, 15); - update_cursor(); -} - -void VGA::set_color(vga_color fg, vga_color bg) { - color_fg = fg; - color_bg = bg; - for (size_t y = 0; y < max_rows; y++) { - for (size_t x = 0; x < max_columns; x++) { - const size_t index = y * max_columns + x; - buffer[index].fg = color_fg; - buffer[index].bg = color_bg; - } - } -} - -void VGA::enable_cursor(uint8_t start, uint8_t end) { - p_3d4.write(0x0a); - p_3d5.write((p_3d5.read() & 0xc0) | start); - - p_3d4.write(0x0b); - p_3d5.write((p_3d5.read() & 0xe0) | end); -} -void VGA::disable_cursor() { - p_3d4.write(0x0a); - p_3d5.write(0x20); -} -void VGA::update_cursor() { - const uint16_t pos = row * max_columns + column; - - p_3d4.write(0x0f); - p_3d5.write(static_cast(pos & 0xff)); - - p_3d4.write(0x0e); - p_3d5.write(static_cast((pos >> 8) & 0xff)); -} - -void VGA::write(char c) { - switch (c) { - case '\n': - column = 0; - ++row; - break; - default: { - const size_t index = row * max_columns + column; - buffer[index].c = c; - ++column; - } - } - - if (column == max_columns) { - column = 0; - ++row; - } - - if (row == max_rows) { - // scroll up - move rows 1~25 up by one - for (size_t y = 1; y < max_rows; y++) { - const auto prev_y = y - 1; - for (size_t x = 0; x < max_columns; ++x) { - const auto prev = prev_y * max_columns + x; - const auto idx = y * max_columns + x; - buffer[prev] = buffer[idx]; - } - } - --row; - } -} - -void VGA::write(ViewIterator& iter) { - while (iter) { - write(iter.next()); - } -} diff --git a/src/vga.h b/src/vga.h deleted file mode 100644 index 7a8c755..0000000 --- a/src/vga.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once -#include -#include "ports.h" - -class VGA : public Console { -public: - /* Hardware text mode color constants. */ - enum vga_color : uint8_t { - VGA_COLOR_BLACK = 0, - VGA_COLOR_BLUE = 1, - VGA_COLOR_GREEN = 2, - VGA_COLOR_CYAN = 3, - VGA_COLOR_RED = 4, - VGA_COLOR_MAGENTA = 5, - VGA_COLOR_BROWN = 6, - VGA_COLOR_LIGHT_GREY = 7, - VGA_COLOR_DARK_GREY = 8, - VGA_COLOR_LIGHT_BLUE = 9, - VGA_COLOR_LIGHT_GREEN = 10, - VGA_COLOR_LIGHT_CYAN = 11, - VGA_COLOR_LIGHT_RED = 12, - VGA_COLOR_LIGHT_MAGENTA = 13, - VGA_COLOR_LIGHT_BROWN = 14, - VGA_COLOR_WHITE = 15, - }; - - VGA(vga_color fg = VGA_COLOR_BLACK, vga_color bg = VGA_COLOR_LIGHT_GREY, uint32_t address = 0xB8000); - ~VGA() = default; - - void set_color(vga_color fg, vga_color bg); - - void enable_cursor(uint8_t start, uint8_t end); - void disable_cursor(); - void update_cursor() override; - - void write(char c) override; - void write(ViewIterator& iter) override; - - - struct Entry { - char c; - vga_color fg : 4; - vga_color bg : 4; - } __attribute((packed)); - -private: - const size_t max_columns = 80, max_rows = 25; - size_t column = 0, row = 0; - - vga_color color_fg; - vga_color color_bg; - - Entry* buffer; - - // ports - vga_horizontal_total p_3d4; - vga_horizontal_display_enable_end p_3d5; -}; - diff --git a/toolchain.makefile b/toolchain.makefile index fe916e4..9dc5b17 100644 --- a/toolchain.makefile +++ b/toolchain.makefile @@ -15,7 +15,7 @@ CXX_FLAGS := -std=c++20 -ffreestanding -nostdlib -nostdinc -nostdinc++ \ -Wnon-virtual-dtor \ -Wold-style-cast -Wconversion \ -Wconsumed -CXX_INCLUDE := $(CURDIR)/libk +CXX_INCLUDE := $(CURDIR)/libk $(CURDIR)/drivers CXX_SYSTEM_INCLUDE := $(CURDIR)/grub # -- cgit v1.2.1