From 9b2a78fa52249ab481493550490aa5f37872dcf6 Mon Sep 17 00:00:00 2001 From: aqua Date: Sat, 10 Dec 2022 20:56:57 +0200 Subject: Rewrite drivers/uart and drivers/vga in cpp --- .config | 1 + Kconfig | 2 + Makefile | 2 + Makefile.config | 32 ++++++----- devices/Makefile | 2 +- devices/pckbd.c | 3 +- devices/uart.h | 17 ------ devices/uart.hpp | 7 +++ devices/uart_16550.c | 117 ------------------------------------- devices/uart_16550.cpp | 110 +++++++++++++++++++++++++++++++++++ devices/vga.c | 152 ------------------------------------------------- devices/vga.cpp | 138 ++++++++++++++++++++++++++++++++++++++++++++ devices/vga.h | 33 ----------- devices/vga.hpp | 51 +++++++++++++++++ i686/sys/cpuid.h | 2 +- i686/sys/io.h | 23 ++++++++ i686/sys/io.hpp | 15 +++++ i686/toolchain.mk | 31 +++++----- lib/Makefile | 2 +- lib/stdio.h | 26 ++++++--- lib/stdio/vfprintf.c | 54 ------------------ lib/stdio/vfprintf.cpp | 54 ++++++++++++++++++ lib/string.h | 6 ++ rules.mk | 15 ++++- src/Makefile | 2 +- src/kernel.c | 54 ------------------ src/kernel.cpp | 59 +++++++++++++++++++ 27 files changed, 536 insertions(+), 474 deletions(-) delete mode 100644 devices/uart.h create mode 100644 devices/uart.hpp delete mode 100644 devices/uart_16550.c create mode 100644 devices/uart_16550.cpp delete mode 100644 devices/vga.c create mode 100644 devices/vga.cpp delete mode 100644 devices/vga.h create mode 100644 devices/vga.hpp create mode 100644 i686/sys/io.hpp delete mode 100644 lib/stdio/vfprintf.c create mode 100644 lib/stdio/vfprintf.cpp delete mode 100644 src/kernel.c create mode 100644 src/kernel.cpp diff --git a/.config b/.config index b406c20..d2c8cb9 100644 --- a/.config +++ b/.config @@ -3,6 +3,7 @@ # Toolchain # CONFIG_CFLAGS="-g -Og" +CONFIG_CXXFLAGS="-g -Og" CONFIG_LDFLAGS="" # end of Toolchain diff --git a/Kconfig b/Kconfig index c8ce103..d50a25e 100644 --- a/Kconfig +++ b/Kconfig @@ -1,6 +1,8 @@ menu "Toolchain" config CFLAGS string "Additional C compiler flags" + config CXXFLAGS + string "Additional CXX compiler flags" config LDFLAGS string "Additional linker flags" endmenu diff --git a/Makefile b/Makefile index 262cd97..e5afd94 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,8 @@ info: @echo " MAKE $(shell ${MAKE} --version | head -n1)" @echo " CC $(shell ${CC} --version | head -n1)" @echo " ${CFLAGS}" + @echo " CXX $(shell ${CXX} --version | head -n1)" + @echo " ${CXXFLAGS}" @echo " LD $(shell ${LD} --version | head -n1)" @echo " ${LDFLAGS}" diff --git a/Makefile.config b/Makefile.config index 1ea871c..42aa510 100644 --- a/Makefile.config +++ b/Makefile.config @@ -3,6 +3,7 @@ # Toolchain # CONFIG_CFLAGS="-g -Og" +CONFIG_CXXFLAGS="-g -Og" CONFIG_LDFLAGS="" # end of Toolchain @@ -25,19 +26,20 @@ CONFIG_KB_PS2=y ARCH=i686 # define compiler, linker, archiver and strip and their flags -# -AS := i686-elf-as -CC := i686-elf-gcc -CFLAGS := -Wall -Wextra -Wpedantic -Wshadow -Wconversion -fanalyzer -ffreestanding -std=gnu11 -mgeneral-regs-only -CFLAGS += $(shell echo ${CONFIG_CFLAGS}) -LD := i686-elf-ld -LDFLAGS := -static -nostdlib -LDFLAGS += $(shell echo ${CONFIG_LDFLAGS}) -AR := i686-elf-ar -ARFLAGS := -crus -STRIP := i686-elf-strip - -# test framework -GTEST := $(shell pkg-config --cflags --libs gtest gtest_main) -GMOCK := $(shell pkg-config --cflags --libs gmock) +# FIXME: cpp threadsafe statics +AS := i686-elf-as +CC := i686-elf-gcc +CXX := i686-elf-g++ +CFLAGS := -Wall -Wextra -Wpedantic -Wshadow -Wconversion -fanalyzer -ffreestanding -std=gnu11 \ + -mgeneral-regs-only +CFLAGS += $(shell echo ${CONFIG_CFLAGS}) +CXXFLAGS := -Wall -Wextra -Wpedantic -Wshadow -Wconversion -ffreestanding -std=c++17 \ + -mgeneral-regs-only -fno-use-cxa-atexit -fno-threadsafe-statics -fno-exceptions -fno-rtti +CXXFLAGS += $(shell echo ${CONFIG_CXXFLAGS}) +LD := i686-elf-ld +LDFLAGS := -static -nostdlib +LDFLAGS += $(shell echo ${CONFIG_LDFLAGS}) +AR := i686-elf-ar +ARFLAGS := -crus +STRIP := i686-elf-strip diff --git a/devices/Makefile b/devices/Makefile index 0c3a0b1..3acf31c 100644 --- a/devices/Makefile +++ b/devices/Makefile @@ -1,6 +1,6 @@ include ../Makefile.config -devs.SRCS = pic_8259.c uart_16550.c vga.c i8042.c pckbd.c mouse.c +devs.SRCS = pic_8259.c uart_16550.cpp vga.cpp i8042.c pckbd.c mouse.c include ../rules.mk diff --git a/devices/pckbd.c b/devices/pckbd.c index c4fce5b..d550f91 100644 --- a/devices/pckbd.c +++ b/devices/pckbd.c @@ -1,6 +1,5 @@ #include "keyboard.h" #include "ps2_controller.h" -#include "vga.h" #include #include #include @@ -42,7 +41,7 @@ ps2_keyboard_irq_handler() return; case 0x58: // F12 - vga_clear(VGA_COLOR_LIGHT_BLUE, VGA_COLOR_LIGHT_GREY); + // vga_clear(VGA_COLOR_LIGHT_BLUE, VGA_COLOR_LIGHT_GREY); return; } diff --git a/devices/uart.h b/devices/uart.h deleted file mode 100644 index ee74e98..0000000 --- a/devices/uart.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -// TODO #include -#include - -enum UART { - COM1 = 0x3f8, - COM2 = 0x2f8, - COM3 = 0x3E8, - COM4 = 0x2E8, - COM5 = 0x5F8, - COM6 = 0x4F8, - COM7 = 0x5E8, - COM8 = 0x4E8, -}; - -FILE *uart_init(enum UART port); diff --git a/devices/uart.hpp b/devices/uart.hpp new file mode 100644 index 0000000..c86557c --- /dev/null +++ b/devices/uart.hpp @@ -0,0 +1,7 @@ +#pragma once + +#include +#include + +template FILE *uart_init(); +template <> FILE *uart_init(); diff --git a/devices/uart_16550.c b/devices/uart_16550.c deleted file mode 100644 index 1adcf38..0000000 --- a/devices/uart_16550.c +++ /dev/null @@ -1,117 +0,0 @@ -#include "uart.h" -#include -#include - -enum uart_16550_offset { - Data = 0, // read from receive buffer / write to transmit buffer | BaudDiv_l - InterruptControl = 1, // interrupt enable | BaudDiv_h - FifoControl = 2, // interrupt ID and FIFO control - LineControl = 3, // most significant bit is the DLAB - ModemControl = 4, - LineStatus = 5, - ModemStatus = 6, - Scratch = 7, -}; -// Line Control -// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | -// |dla| | parity | s | data | - -enum LineControl { - d5bit = 0x00, // 0000 0000 data bits - d6bit = 0x01, // 0000 0001 - d7bit = 0x02, // 0000 0010 - d8bit = 0x03, // 0000 0011 - // none = 0b00000000, // parity bits - odd = 0x08, // 0000 1000 - even = 0x18, // 0001 1000 - mark = 0x28, // 0010 1000 - space = 0x38, // 0011 1000 - // s1bit = 0b00000000, // stop bits - s2bit = 0x04, // 0000 0100 1.5 for 5bit data; 2 otherwise - dlab = 0x80 // 1000 0000 divisor latch access bit -}; - -// Line Status Register -enum LineStatus { - DR = (1 << 0), // data ready: see if there is data to read - OE = (1 << 1), // overrun error: see if there has been data lost - PE = (1 << 2), // parity error: see if there was error in transmission - FE = (1 << 3), // framing error: see if a stop bit was missing - BI = (1 << 4), // break indicator: see if there is a break in data input - THRE = (1 << 5), // transmitter holding register empty: see if transmission buffer is empty - TEMT = (1 << 6), // transmitter empty: see if transmitter is not doing anything - ERRO = (1 << 7), // impending error: see if there is an error with a word in the input buffer -}; - -int -uart_thre(enum UART port) -{ - return inb(port + LineStatus) & THRE; -} - -void -uart_write(const FILE *self, char a) -{ - while (uart_thre(self->id) == 0) {} - outb(a, self->id); - - if (a == '\n') { - while (uart_thre(self->id) == 0) {} - outb('\r', self->id); - } -} - -int -uart_puts(const FILE *self, const char *string, int length) -{ - int written = 0; - - if (length == -1) - while (*string != '\0') { - uart_write(self, *string); - ++string; - ++written; - } - - else - for (int i = 0; i < length; ++i) { - uart_write(self, string[i]); - ++written; - } - - return written; -} - -void -uart_flush(__attribute__((unused)) const FILE *self) -{ -} - -FILE uart_stream; - -FILE * -uart_init(enum UART port) -{ - outb(0x00, port + 1); // Disable all interrupts - outb(0x80, port + 3); // Enable DLAB (set baud rate divisor) - outb(0x03, port + 0); // Set divisor to 3 (lo byte) 38400 baud - outb(0x00, port + 1); // (hi byte) - outb(0x03, port + 3); // 8 bits, no parity, one stop bit - outb(0xc7, port + 2); // Enable FIFO, clear them, with 14-byte threshold - outb(0x0b, port + 4); // IRQs enabled, RTS/DSR set - outb(0x1e, port + 4); // Set in loopback mode, test the serial chip - outb(0xae, port + 0); // Test serial chip (send byte 0xAE and check if serial - // returns same byte) - - // Check if serial is faulty (i.e: not same byte as sent) - if (inb(port + 0) != 0xae) { return NULL; } - - // If serial is not faulty set it in normal operation mode - // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) - outb(0x0f, port + 4); - uart_stream.id = port; - uart_stream.putc = &uart_write; - uart_stream.puts = &uart_puts; - uart_stream.flush = &uart_flush; - return &uart_stream; -} diff --git a/devices/uart_16550.cpp b/devices/uart_16550.cpp new file mode 100644 index 0000000..9620981 --- /dev/null +++ b/devices/uart_16550.cpp @@ -0,0 +1,110 @@ +#include "uart.hpp" +#include + +template struct Uart16550 : public kIoDevice, private Port { + using Base = Port; + using Ports = UART; + using PortOffset = UARTPortOffset; + + // Line Control + // | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + // |dla| | parity | s | data | + enum LineControl : unsigned char { + d5bit = 0x00, // 0000 0000 data bits + d6bit = 0x01, // 0000 0001 + d7bit = 0x02, // 0000 0010 + d8bit = 0x03, // 0000 0011 + none = 0x00, // 0000 0000 parity bits + odd = 0x08, // 0000 1000 + even = 0x18, // 0001 1000 + mark = 0x28, // 0010 1000 + space = 0x38, // 0011 1000 + s1bit = 0x00, // 0000 0000 stop bits + s2bit = 0x04, // 0000 0100 1.5 for 5bit data; 2 otherwise + dlab = 0x80 // 1000 0000 divisor latch access bit + }; + + // Line Status Register + enum LineStatus : unsigned char { + DR = (1 << 0), // data ready: see if there is data to read + OE = (1 << 1), // overrun error: see if there has been data lost + PE = (1 << 2), // parity error: see if there was error in transmission + FE = (1 << 3), // framing error: see if a stop bit was missing + BI = (1 << 4), // break indicator: see if there is a break in data input + THRE = (1 << 5), // transmitter holding register empty: see if transmission buffer is empty + TEMT = (1 << 6), // transmitter empty: see if transmitter is not doing anything + ERRO = (1 << 7), // impending error: see if there is an error with a word in the input buffer + }; + + [[nodiscard]] static bool + test() + { + Base::out(0x00, 1); // Disable all interrupts + Base::out(0x80, 3); // Enable DLAB (set baud rate divisor) + Base::out(0x03, 0); // Set divisor to 3 (lo byte) 38400 baud + Base::out(0x00, 1); // (hi byte) + Base::out(0x03, 3); // 8 bits, no parity, one stop bit + Base::out(0xc7, 2); // Enable FIFO, clear them, with 14-byte threshold + Base::out(0x0b, 4); // IRQs enabled, RTS/DSR set + Base::out(0x1e, 4); // Set in loopback mode, test the serial chip + Base::out(0xae, 0); // Test serial chip (send byte 0xAE and check if serial + // returns same byte) + + // Check if serial is faulty (i.e: not same byte as sent) + if (Base::in() != 0xae) { return false; } + + // If serial is not faulty set it in normal operation mode + // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) + Base::out(0x0f, 4); + return true; + } + + [[nodiscard]] static bool + thre() + { + return Base::in(PortOffset::LineStatus)&THRE; + } + + void + putc(char a) override + { + while (!thre()) {} + Base::out(a); + if (a == '\n') putc('\r'); + } + + int + puts(const char *string, int length) override + { + int written = 0; + + if (length == -1) + while (*string != '\0') { + putc(*string); + ++string; + ++written; + } + + else { + for (int i = 0; i < length; ++i) putc(string[i]); + written += length; + } + + return written; + } + + void + flush() override + { + } +}; + +static_assert(sizeof(Uart16550) == sizeof(void *)); + +template <> +FILE * +uart_init() +{ + static Uart16550 device; + return &device; +} diff --git a/devices/vga.c b/devices/vga.c deleted file mode 100644 index 6d64c0a..0000000 --- a/devices/vga.c +++ /dev/null @@ -1,152 +0,0 @@ -#include "vga.h" -#include -#include - -#define cga_idx_port 0x3d4 -#define cga_dat_port 0x3d5 - -#define cursor_start 0x0a -#define cursor_end 0x0b -#define cursor_addr_h 0x0e -#define cursor_addr_l 0x0f -#define cursor_hide 0x20 - -struct __attribute__((packed)) VGAEntry { - unsigned char text; - uint8_t foreground : 4; - uint8_t background : 4; -}; -_Static_assert(sizeof(struct VGAEntry) == 2, "sizeof VGAEntry"); - -const int width = 80; -const int height = 25; - -struct VGAEntry *buffer; -int col = 0; -int row = 0; - -// *** Cursor *** -void -vga_enable_cursor(unsigned char start, unsigned char end) -{ - outb(cursor_start, cga_idx_port); - outb((inb(cga_dat_port) & 0xc0) | start, cga_dat_port); - - outb(cursor_end, cga_idx_port); - outb((inb(cga_dat_port) & 0xe0) | end, cga_dat_port); -} - -void -vga_disable_cursor() -{ - outb(cursor_start, cga_idx_port); - outb(cursor_hide, cga_dat_port); -} - -void -vga_update_cursor() -{ - const uint16_t pos = row * width + col; - - outb(cursor_addr_l, cga_idx_port); - outb(pos & 0xff, cga_dat_port); - - outb(cursor_addr_h, cga_idx_port); - outb((pos >> 8) & 0xff, cga_dat_port); -} - -// *** Text Mode Output *** -void -vga_putc(__attribute__((unused)) const FILE *self, char a) -{ - switch (a) { - case '\n': - col = 0; - ++row; - break; - case '\r': - col = 0; - break; - case '\b': - --col; - if (col < 0) col = 0; - break; - default: - buffer[row * width + col].text = a; - ++col; - } - - if (col == width) { - col = 0; - ++row; - } - - if (row == height) { - // scroll up - for (int y = 1; y < height; ++y) - for (int x = 0; x < width; ++x) { - const int prev = (y - 1) * width + x; - const int curr = y * width + x; - buffer[prev] = buffer[curr]; - } - // blank out last row - for (int i = (height - 1) * width; i < height * width; ++i) buffer[i].text = ' '; - --row; - } -} - -int -vga_puts(const FILE *self, const char *string, int len) -{ - int written = 0; - if (len == -1) - while (*string != '\0') { - vga_putc(self, *string); - ++string; - ++written; - } - - else - for (int i = 0; i < len; ++i) { - vga_putc(self, string[i]); - ++written; - } - return written; -} - -void -vga_flush(__attribute__((unused)) const FILE *self) -{ - vga_update_cursor(); -} - -// *** Text Mode *** -FILE vga_stream; - -FILE * -vga_init() -{ - buffer = (struct VGAEntry *)0xc03ff000; - vga_enable_cursor(14, 15); - vga_clear(VGA_COLOR_LIGHT_BLUE, VGA_COLOR_LIGHT_GREY); - - vga_stream.id = 0; - vga_stream.putc = &vga_putc; - vga_stream.puts = &vga_puts; - vga_stream.flush = &vga_flush; - return &vga_stream; -} - -void -vga_clear(enum vga_color foreground, enum vga_color background) -{ - for (int y = 0; y < height; ++y) - for (int x = 0; x < width; ++x) { - const int index = y * width + x; - buffer[index].text = ' '; - buffer[index].foreground = foreground; - buffer[index].background = background; - } - col = row = 0; - vga_update_cursor(); -} diff --git a/devices/vga.cpp b/devices/vga.cpp new file mode 100644 index 0000000..3f83a5f --- /dev/null +++ b/devices/vga.cpp @@ -0,0 +1,138 @@ +#include "vga.hpp" +#include +#include + +// FIXME user a Port +#define cga_idx_port 0x3d4 +#define cga_dat_port 0x3d5 + +// FIXME make constexpr +#define cursor_start 0x0a +#define cursor_end 0x0b +#define cursor_addr_h 0x0e +#define cursor_addr_l 0x0f +#define cursor_hide 0x20 + +static_assert(sizeof(struct VGA::VGAEntry) == 2, "sizeof VGAEntry"); + +// FIXME make constexpr +const int width = 80; +const int height = 25; + +// *** Cursor *** +// FIXME make VGA members +void +vga_enable_cursor(unsigned char start, unsigned char end) +{ + outb(cursor_start, cga_idx_port); + outb((inb(cga_dat_port) & 0xc0) | start, cga_dat_port); + + outb(cursor_end, cga_idx_port); + outb((inb(cga_dat_port) & 0xe0) | end, cga_dat_port); +} + +void +vga_disable_cursor() +{ + outb(cursor_start, cga_idx_port); + outb(cursor_hide, cga_dat_port); +} + +void +VGA::update_cursor() +{ + const uint16_t pos = row * width + col; + + outb(cursor_addr_l, cga_idx_port); + outb(pos & 0xff, cga_dat_port); + + outb(cursor_addr_h, cga_idx_port); + outb((pos >> 8) & 0xff, cga_dat_port); +} + +// *** Text Mode Output *** +void +VGA::putc(char a) +{ + switch (a) { + case '\n': + col = 0; + ++row; + break; + case '\r': + col = 0; + break; + case '\b': + --col; + if (col < 0) col = 0; + break; + default: + buffer[row * width + col].text = a; + ++col; + } + + if (col == width) { + col = 0; + ++row; + } + + if (row == height) { + // scroll up + for (int y = 1; y < height; ++y) + for (int x = 0; x < width; ++x) { + const int prev = (y - 1) * width + x; + const int curr = y * width + x; + buffer[prev] = buffer[curr]; + } + // blank out last row + for (int i = (height - 1) * width; i < height * width; ++i) buffer[i].text = ' '; + --row; + } +} + +int +VGA::puts(const char *string, int len) +{ + int written = 0; + if (len == -1) + while (*string != '\0') { + putc(*string); + ++string; + ++written; + } + + else + for (int i = 0; i < len; ++i) { + putc(string[i]); + ++written; + } + return written; +} + +// *** Text Mode *** +VGA::VGA(void *addr) +{ + buffer = (struct VGAEntry *)addr; + vga_enable_cursor(14, 15); + clear(VGA_COLOR_LIGHT_BLUE, VGA_COLOR_LIGHT_GREY); +} +FILE * +vga_init(void *buffer) +{ + static VGA device(buffer); + return &device; +} + +void +VGA::clear(enum vga_color foreground, enum vga_color background) +{ + for (int y = 0; y < height; ++y) + for (int x = 0; x < width; ++x) { + const int index = y * width + x; + buffer[index].text = ' '; + buffer[index].foreground = foreground; + buffer[index].background = background; + } + col = row = 0; + update_cursor(); +} diff --git a/devices/vga.h b/devices/vga.h deleted file mode 100644 index d9dfd44..0000000 --- a/devices/vga.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include - -/** Hardware text mode color constants. */ -enum vga_color { - 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, -}; - -FILE *vga_init(); -void vga_clear(enum vga_color foreground, enum vga_color background); - -// void vga_putc(char a); -// void vga_puts(const char *string, int len); - -// void vga_enable_cursor(unsigned char start, unsigned char end); -// void vga_disable_cursor(); -void vga_update_cursor(); diff --git a/devices/vga.hpp b/devices/vga.hpp new file mode 100644 index 0000000..5287d73 --- /dev/null +++ b/devices/vga.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include + +/** Hardware text mode color constants. */ +enum vga_color { + 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, +}; + +FILE *vga_init(void *buffer); + +struct VGA : public kIoDevice { + VGA(void *addr); + + void putc(char a) override; + int puts(const char *string, int length) override; + void + flush() override + { + update_cursor(); + } + + struct __attribute__((packed)) VGAEntry { + unsigned char text; + unsigned char foreground : 4; + unsigned char background : 4; + }; + +private: + void clear(enum vga_color foreground, enum vga_color background); + void update_cursor(); + + struct VGAEntry *buffer; + int col = 0; + int row = 0; +}; diff --git a/i686/sys/cpuid.h b/i686/sys/cpuid.h index 862601f..65b43c6 100644 --- a/i686/sys/cpuid.h +++ b/i686/sys/cpuid.h @@ -12,7 +12,7 @@ struct CPUVersion { unsigned int family_ex : 8; unsigned int __unused_2 : 4; } __attribute__((packed, aligned(__alignof__(unsigned int)))); -_Static_assert(sizeof(struct CPUVersion) == sizeof(unsigned int), "cpuid version struct size"); +// FIXME _Static_assert(sizeof(struct CPUVersion) == sizeof(unsigned int), "cpuid version struct size"); unsigned int family(const struct CPUVersion v) diff --git a/i686/sys/io.h b/i686/sys/io.h index 74d4950..b6c24c5 100644 --- a/i686/sys/io.h +++ b/i686/sys/io.h @@ -1,5 +1,27 @@ #pragma once +// port listings +enum UART { + COM1 = 0x3f8, + COM2 = 0x2f8, + COM3 = 0x3e8, + COM4 = 0x2e8, + COM5 = 0x5f8, + COM6 = 0x4f8, + COM7 = 0x5e8, + COM8 = 0x4e8, +}; +enum UARTPortOffset { + Data = 0, // read from receive buffer / write to transmit buffer | BaudDiv_l + InterruptControl = 1, // interrupt enable | BaudDiv_h + FifoControl = 2, // interrupt ID and FIFO control + LineControl = 3, // most significant bit is the DLAB + ModemControl = 4, + LineStatus = 5, + ModemStatus = 6, + Scratch = 7, +}; + static inline void outb(unsigned char val, unsigned short port) { @@ -77,3 +99,4 @@ insl(unsigned short port, void *__buf, unsigned long __n) { asm volatile("cld; rep; insl" : "+D"(__buf), "+c"(__n) : "d"(port)); } + diff --git a/i686/sys/io.hpp b/i686/sys/io.hpp new file mode 100644 index 0000000..bea9323 --- /dev/null +++ b/i686/sys/io.hpp @@ -0,0 +1,15 @@ +#pragma once + +template struct Port { + static void + out(T val, unsigned short offset = 0) + { + outb(val, port + offset); + } + + static auto + in(unsigned short offset = 0) + { + return inb(port + offset); + } +}; diff --git a/i686/toolchain.mk b/i686/toolchain.mk index 43c758c..ae2fb35 100644 --- a/i686/toolchain.mk +++ b/i686/toolchain.mk @@ -1,19 +1,20 @@ ARCH=i686 # define compiler, linker, archiver and strip and their flags -# -AS := i686-elf-as -CC := i686-elf-gcc -CFLAGS := -Wall -Wextra -Wpedantic -Wshadow -Wconversion -fanalyzer -ffreestanding -std=gnu11 -mgeneral-regs-only -CFLAGS += $(shell echo ${CONFIG_CFLAGS}) -LD := i686-elf-ld -LDFLAGS := -static -nostdlib -LDFLAGS += $(shell echo ${CONFIG_LDFLAGS}) -AR := i686-elf-ar -ARFLAGS := -crus -STRIP := i686-elf-strip - -# test framework -GTEST := $(shell pkg-config --cflags --libs gtest gtest_main) -GMOCK := $(shell pkg-config --cflags --libs gmock) +# FIXME: cpp threadsafe statics +AS := i686-elf-as +CC := i686-elf-gcc +CXX := i686-elf-g++ +CFLAGS := -Wall -Wextra -Wpedantic -Wshadow -Wconversion -fanalyzer -ffreestanding -std=gnu11 \ + -mgeneral-regs-only +CFLAGS += $(shell echo ${CONFIG_CFLAGS}) +CXXFLAGS := -Wall -Wextra -Wpedantic -Wshadow -Wconversion -ffreestanding -std=c++17 \ + -mgeneral-regs-only -fno-use-cxa-atexit -fno-threadsafe-statics -fno-exceptions -fno-rtti +CXXFLAGS += $(shell echo ${CONFIG_CXXFLAGS}) +LD := i686-elf-ld +LDFLAGS := -static -nostdlib +LDFLAGS += $(shell echo ${CONFIG_LDFLAGS}) +AR := i686-elf-ar +ARFLAGS := -crus +STRIP := i686-elf-strip diff --git a/lib/Makefile b/lib/Makefile index 68d1e74..b3e1f66 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,6 +1,6 @@ include ../Makefile.config -libk.SRCS = stdio/printf.c stdio/fprintf.c stdio/vfprintf.c \ +libk.SRCS = stdio/printf.c stdio/fprintf.c stdio/vfprintf.cpp \ stdlib/memcpy.c stdlib/memset.c \ string/itoa.c diff --git a/lib/stdio.h b/lib/stdio.h index f7c1846..9a0c41e 100644 --- a/lib/stdio.h +++ b/lib/stdio.h @@ -2,16 +2,20 @@ #include +#ifdef __cplusplus /** An object type used for streams */ -typedef struct kIoDevice { - int id; - /** Functions that prints a character to the stream */ - void (*putc)(const struct kIoDevice *, char); +struct kIoDevice { + /** Function that prints a character to the stream */ + virtual void putc(char) = 0; /** Function that prints a string to the stream */ - int (*puts)(const struct kIoDevice *, const char *, int); - /** Flush all buffers */ - void (*flush)(const struct kIoDevice *); -} FILE; + virtual int puts(const char *, int) = 0; + /** Flush write buffers */ + virtual void flush() = 0; +}; +typedef kIoDevice FILE; +#else +typedef void FILE; +#endif /** A FILE value corresponding to stdin, the keyboard buffer */ extern FILE *stdin; @@ -20,6 +24,9 @@ extern FILE *stdout; /** A FILE value corresponding to stderr, the uart */ extern FILE *stderr; +#ifdef __cplusplus +extern "C" { +#endif /** * Write the formatted string to stdout * @@ -36,3 +43,6 @@ int fprintf(FILE *restrict stream, const char *restrict format, ...); * Write the formatted string to stream; see printf */ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap); +#ifdef __cplusplus +} +#endif diff --git a/lib/stdio/vfprintf.c b/lib/stdio/vfprintf.c deleted file mode 100644 index d24e43e..0000000 --- a/lib/stdio/vfprintf.c +++ /dev/null @@ -1,54 +0,0 @@ -#include -#include - -static char buffer[3 * sizeof(int) + 2]; - -int -vfprintf(FILE *restrict stream, const char *restrict format, va_list params) -{ - int written = 0; - - int s = 0; - int l = 0; - for (int i = 0; format[i] != '\0'; ++i) { - if (format[i] == '%') { - written += stream->puts(stream, &format[s], l); - s = i + 2; - ++i; - - switch (format[i]) { - case 's': { - const char *arg = va_arg(params, const char *); - written += stream->puts(stream, arg, -1); - } break; - case 'c': { - const int arg = va_arg(params, int); - stream->putc(stream, arg); - ++written; - } break; - case 'd': { - const char *arg = itoa(buffer, va_arg(params, int), 10); - written += stream->puts(stream, arg, -1); - } break; - case 'u': { - const char *arg = utoa(buffer, va_arg(params, unsigned int), 10); - written += stream->puts(stream, arg, -1); - } break; - case 'x': { - const char *arg = utoa(buffer, va_arg(params, unsigned int), 16); - written += stream->puts(stream, arg, -1); - } break; - } - - l = 0; - } - - else - ++l; - } - - if (l > 0) { written += stream->puts(stream, &format[s], l); } - - stream->flush(stream); - return written; -} diff --git a/lib/stdio/vfprintf.cpp b/lib/stdio/vfprintf.cpp new file mode 100644 index 0000000..aa9256d --- /dev/null +++ b/lib/stdio/vfprintf.cpp @@ -0,0 +1,54 @@ +#include +#include + +static char buffer[3 * sizeof(int) + 2]; + +extern "C" int +vfprintf(FILE *restrict stream, const char *restrict format, va_list params) +{ + int written = 0; + + int s = 0; + int l = 0; + for (int i = 0; format[i] != '\0'; ++i) { + if (format[i] == '%') { + written += stream->puts(&format[s], l); + s = i + 2; + ++i; + + switch (format[i]) { + case 's': { + const char *arg = va_arg(params, const char *); + written += stream->puts(arg, -1); + } break; + case 'c': { + const int arg = va_arg(params, int); + stream->putc(arg); + ++written; + } break; + case 'd': { + const char *arg = itoa(buffer, va_arg(params, int), 10); + written += stream->puts(arg, -1); + } break; + case 'u': { + const char *arg = utoa(buffer, va_arg(params, unsigned int), 10); + written += stream->puts(arg, -1); + } break; + case 'x': { + const char *arg = utoa(buffer, va_arg(params, unsigned int), 16); + written += stream->puts(arg, -1); + } break; + } + + l = 0; + } + + else + ++l; + } + + if (l > 0) { written += stream->puts(&format[s], l); } + + stream->flush(); + return written; +} diff --git a/lib/string.h b/lib/string.h index 1eb3da2..460057c 100644 --- a/lib/string.h +++ b/lib/string.h @@ -4,6 +4,9 @@ #define DECIMAL 10 #define HEX 16 +#ifdef __cplusplus +extern "C" { +#endif /** * Convert int into a string */ @@ -12,3 +15,6 @@ char *itoa(char *p, int x, int base); * Convert unsigned int into a string */ char *utoa(char *p, unsigned x, int base); +#ifdef __cplusplus +} +#endif diff --git a/rules.mk b/rules.mk index ada9789..14023da 100644 --- a/rules.mk +++ b/rules.mk @@ -6,7 +6,8 @@ $(foreach V,$(filter %.SRCS, ${.VARIABLES}),\ ) # extra flags -CFLAGS += -isysteminclude -I../lib +CFLAGS += -isysteminclude -I../lib +CXXFLAGS += -isysteminclude -I../lib -Drestrict=__restrict__ # Suffix rules %.a: @@ -26,10 +27,18 @@ CFLAGS += -isysteminclude -I../lib @echo ' CC $^' @$(CC) $(CFLAGS) -c -o $@ $^ +.cpp.o: + @echo ' CXX $^' + @$(CXX) $(CXXFLAGS) -c -o $@ $^ + # Test rules +TEST_CXX := c++ +GTEST := $(shell pkg-config --cflags --libs gtest gtest_main) +GMOCK := $(shell pkg-config --cflags --libs gmock) + tst/test_%: tst/%.cc - @echo ' CXX $@' - @${CXX} $< -o $@ $(GTEST) $(GMOCK) + @echo ' CXX TEST $@' + @$(TEST_CXX) $< -o $@ $(GTEST) $(GMOCK) # clean target .PHONY: clean FORCE diff --git a/src/Makefile b/src/Makefile index de59cfb..637f9a1 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,6 +1,6 @@ include ../Makefile.config -kernel.SRCS := multiboot2.c mmap.c kernel.c mem/vmm.c +kernel.SRCS := multiboot2.c mmap.c kernel.cpp mem/vmm.c kernel.OBJS := conf.h include ../rules.mk diff --git a/src/kernel.c b/src/kernel.c deleted file mode 100644 index b8432a8..0000000 --- a/src/kernel.c +++ /dev/null @@ -1,54 +0,0 @@ -//===================================================================== -// glitch kernel -// spdx-license-identifier: ISC -// description: kernel entry point -//===================================================================== - -#include "conf.h" -#include "devices/keyboard.h" -#include "devices/mouse.h" -#include "devices/pic.h" -#include "devices/ps2_controller.h" -#include "devices/uart.h" -#include "devices/vga.h" -#include "mem.h" -#include -#include - -FILE *stdin; -FILE *stdout; -FILE *stderr; - -void kmain() { - stderr = uart_init(COM1); - stdout = vga_init(vmm_map(0xb8000, 0xc03ff000)); - - printf("glitch [version " VERSION "] [" CC "]\n"); - fprintf(stderr, "glitch [version " VERSION "] [" CC "]\n"); - { - char vendor[13] = {'\0'}; - unsigned int eax; - __get_cpuid(0, &eax, (unsigned int *)vendor, (unsigned int *)(vendor + 8), (unsigned int *)(vendor + 4)); - struct CPUVersion v; - __get_cpuid(1, (unsigned int *)&v, &eax, &eax, &eax); - printf("CPU: %s family %u model %u stepping %u\n", vendor, family(v), model(v), v.stepping); - fprintf(stderr, "CPU: %s family %u model %u stepping %u\n", vendor, family(v), model(v), v.stepping); - } - - pic_init(); - - ps2_ctrl_init(); - ps2_keyboard_init(); - mouse_init(); - - pic_enable(); - printf("interrupts enabled\n"); - - /* - alloc4M(); - char *c = (char *)0xc0700000; - if (*c == 0) printf("c is 0\r\n"); - */ - - while (1) {} -} diff --git a/src/kernel.cpp b/src/kernel.cpp new file mode 100644 index 0000000..751bcb0 --- /dev/null +++ b/src/kernel.cpp @@ -0,0 +1,59 @@ +//===================================================================== +// glitch kernel +// spdx-license-identifier: ISC +// description: kernel entry point +//===================================================================== + +extern "C" { +#include "conf.h" +#include "mem.h" +#include +#include +#include +#include +#include +#include +} +#include +#include + +FILE *stdin; +FILE *stdout; +FILE *stderr; + +extern "C" void +kmain() +{ + stderr = uart_init(); + vmm_map(0xb8000, 0xc03ff000); + stdout = vga_init((void *)0xc03ff000); + + printf("glitch [version " VERSION "] [" CC "]\n"); + fprintf(stderr, "glitch [version " VERSION "] [" CC "]\n"); + { + char vendor[13] = {'\0'}; + unsigned int eax; + __get_cpuid(0, &eax, (unsigned int *)vendor, (unsigned int *)(vendor + 8), (unsigned int *)(vendor + 4)); + struct CPUVersion v; + __get_cpuid(1, (unsigned int *)&v, &eax, &eax, &eax); + printf("CPU: %s family %u model %u stepping %u\n", vendor, family(v), model(v), v.stepping); + fprintf(stderr, "CPU: %s family %u model %u stepping %u\n", vendor, family(v), model(v), v.stepping); + } + + pic_init(); + + ps2_ctrl_init(); + ps2_keyboard_init(); + mouse_init(); + + pic_enable(); + fprintf(stderr, "interrupts enabled\n"); + + /* + alloc4M(); + char *c = (char *)0xc0700000; + if (*c == 0) printf("c is 0\r\n"); + */ + + while (1) {} +} -- cgit v1.2.1