├── Kernel.cbp ├── Kernel.layout ├── README.md ├── addresses.cpp ├── addresses.h ├── boot.asm ├── color_table.h ├── grub.cfg ├── iso.sh ├── kernel.cpp ├── kernel.h ├── keyboard.cpp ├── keyboard.h ├── linker.ld ├── main.cpp ├── main.h └── makefile /Kernel.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 46 | 47 | -------------------------------------------------------------------------------- /Kernel.layout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cpp-kernel 2 | A simple kernel in C++ 3 | 4 | TO-DO: Fix keyboard input and provide proper information here. 5 | -------------------------------------------------------------------------------- /addresses.cpp: -------------------------------------------------------------------------------- 1 | #include "addresses.h" 2 | 3 | unsigned long Addresses::video_memory_color = 0xB8000; 4 | unsigned long Addresses::video_memory_monochrome = 0xB0000; 5 | unsigned short Addresses::keyboard_port = 0x60; 6 | -------------------------------------------------------------------------------- /addresses.h: -------------------------------------------------------------------------------- 1 | #ifndef _ADDRESSES_H_ 2 | #define _ADDRESSES_H_ 3 | 4 | class Addresses 5 | { 6 | private: 7 | Addresses() {} 8 | 9 | public: 10 | static unsigned long video_memory_color; 11 | static unsigned long video_memory_monochrome; 12 | static unsigned short keyboard_port; 13 | }; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /boot.asm: -------------------------------------------------------------------------------- 1 | # So our entry-point can be called from asm code. 2 | .extern entry_point 3 | .global entry 4 | 5 | .set FLAGS, 0 6 | .set MAGIC, 0x1BADB002 7 | .set CHECKSUM, -(MAGIC + FLAGS) 8 | 9 | .section .multiboot 10 | 11 | .long MAGIC 12 | .long FLAGS 13 | .long CHECKSUM 14 | 15 | stack_bottom: 16 | .skip 4096 17 | 18 | stack_top: 19 | .section .text 20 | .type entry, @function 21 | 22 | entry: 23 | mov $stack_top, %esp 24 | call entry_point 25 | cli 26 | 27 | .size entry, . - entry 28 | 29 | .section .end -------------------------------------------------------------------------------- /color_table.h: -------------------------------------------------------------------------------- 1 | #ifndef _COLOR_TABLE_H_ 2 | #define _COLOR_TABLE_H_ 3 | 4 | // Ref: https://wiki.osdev.org/Printing_To_Screen#Color_Table 5 | enum VIDEO_COLOR_TABLE 6 | { 7 | BLACK, 8 | BLUE, 9 | GREEN, 10 | CYAN, 11 | RED, 12 | PURPLE, 13 | BROWN, 14 | GRAY, 15 | DARK_GRAY, 16 | LIGHT_BLUE, 17 | LIGHT_GREEN, 18 | LIGHT_CYAN, 19 | LIGHT_RED, 20 | LIGHT_PURPLE, 21 | YELLOW, 22 | WHITE 23 | }; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /grub.cfg: -------------------------------------------------------------------------------- 1 | menuentry "Kernel" 2 | { 3 | multiboot /boot/Kernel.bin 4 | } 5 | -------------------------------------------------------------------------------- /iso.sh: -------------------------------------------------------------------------------- 1 | grub2-file --is-x86-multiboot Kernel.bin 2 | mkdir -p iso/boot/grub 3 | cp Kernel.bin iso/boot/Kernel.bin 4 | cp grub.cfg iso/boot/grub/grub.cfg 5 | grub2-mkrescue -o Kernel.iso iso -------------------------------------------------------------------------------- /kernel.cpp: -------------------------------------------------------------------------------- 1 | #include "kernel.h" 2 | 3 | Kernel::Kernel() 4 | { 5 | this->video_buffer = reinterpret_cast(Addresses::video_memory_color); 6 | this->ClearVideoBuffer(VIDEO_COLOR_TABLE::WHITE); 7 | } 8 | 9 | unsigned short Kernel::VideoEntry(const unsigned char character, const unsigned char color) 10 | { 11 | return static_cast(character) | color << 8; 12 | } 13 | 14 | void Kernel::ClearVideoBuffer(const unsigned char color) 15 | { 16 | for(unsigned char i = 0; i < VIDEO_HEIGHT; ++i) 17 | { 18 | for(unsigned char j = 0; j < VIDEO_WIDTH; ++j) 19 | { 20 | this->video_buffer[i * VIDEO_WIDTH + j] = this->VideoEntry(' ', color); 21 | } 22 | } 23 | this->current_line = 0; 24 | this->current_pos = 0; 25 | } 26 | 27 | void Kernel::PrintString(const char* str, const unsigned char color) 28 | { 29 | unsigned long length = 0; 30 | 31 | while(str[length]) 32 | { 33 | if(str[length] == '\n') 34 | { 35 | this->current_line++; 36 | this->current_pos = VIDEO_WIDTH * this->current_line - 1; 37 | } 38 | else 39 | { 40 | this->video_buffer[(this->current_line * VIDEO_WIDTH + this->current_pos)] = this->VideoEntry(str[length], color); 41 | } 42 | 43 | if(++this->current_pos == VIDEO_WIDTH) 44 | { 45 | this->current_pos = 0; 46 | 47 | if(++this->current_line == VIDEO_HEIGHT) 48 | { 49 | this->current_line = 0; 50 | } 51 | } 52 | length++; 53 | } 54 | } 55 | 56 | void Kernel::PrintCharacter(const char character, const unsigned char color) 57 | { 58 | if(character == '\n') 59 | { 60 | this->current_line++; 61 | this->current_pos = VIDEO_WIDTH * this->current_line - 1; 62 | } 63 | else 64 | { 65 | this->video_buffer[(this->current_line * VIDEO_WIDTH + this->current_pos)] = this->VideoEntry(character, color); 66 | } 67 | 68 | if(++this->current_pos == VIDEO_WIDTH) 69 | { 70 | this->current_pos = 0; 71 | 72 | if(++this->current_line == VIDEO_HEIGHT) 73 | { 74 | this->current_line = 0; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /kernel.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_H_ 2 | #define _KERNEL_H_ 3 | 4 | #include "main.h" 5 | 6 | #define VIDEO_WIDTH 80 7 | #define VIDEO_HEIGHT 25 8 | 9 | class Kernel 10 | { 11 | private: 12 | unsigned short* video_buffer; 13 | unsigned int current_pos; 14 | unsigned int current_line; 15 | 16 | public: 17 | Kernel(); 18 | 19 | unsigned short VideoEntry(const unsigned char character, const unsigned char color); 20 | void ClearVideoBuffer(const unsigned char color); 21 | void PrintString(const char* str, const unsigned char color); 22 | void PrintCharacter(const char character, const unsigned char color); 23 | }; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /keyboard.cpp: -------------------------------------------------------------------------------- 1 | #include "keyboard.h" 2 | 3 | Keyboard::Keyboard() 4 | { 5 | 6 | } 7 | 8 | char Keyboard::GetKeyCharacter(const unsigned char code) 9 | { 10 | switch(code) 11 | { 12 | case KEYS::A: return 'A'; 13 | case KEYS::B: return 'B'; 14 | case KEYS::C: return 'C'; 15 | case KEYS::D: return 'D'; 16 | case KEYS::E: return 'E'; 17 | case KEYS::F: return 'F'; 18 | case KEYS::G: return 'G'; 19 | case KEYS::H: return 'H'; 20 | case KEYS::I: return 'I'; 21 | case KEYS::J: return 'J'; 22 | case KEYS::K: return 'K'; 23 | case KEYS::L: return 'L'; 24 | case KEYS::M: return 'M'; 25 | case KEYS::N: return 'N'; 26 | case KEYS::O: return 'O'; 27 | case KEYS::P: return 'P'; 28 | case KEYS::Q: return 'Q'; 29 | case KEYS::R: return 'R'; 30 | case KEYS::S: return 'S'; 31 | case KEYS::T: return 'T'; 32 | case KEYS::U: return 'U'; 33 | case KEYS::V: return 'V'; 34 | case KEYS::W: return 'W'; 35 | case KEYS::X: return 'X'; 36 | case KEYS::Y: return 'Y'; 37 | case KEYS::Z: return 'Z'; 38 | case KEYS::_1: return '1'; 39 | case KEYS::_2: return '2'; 40 | case KEYS::_3: return '3'; 41 | case KEYS::_4: return '4'; 42 | case KEYS::_5: return '5'; 43 | case KEYS::_6: return '6'; 44 | case KEYS::_7: return '7'; 45 | case KEYS::_8: return '8'; 46 | case KEYS::_9: return '9'; 47 | case KEYS::_0: return '0'; 48 | case KEYS::SPACE: return ' '; 49 | case KEYS::OPEN_BRACKET: return '['; 50 | case KEYS::CLOSE_BRACKET: return ']'; 51 | case KEYS::COMMA: return ','; 52 | case KEYS::DOT: return '.'; 53 | case KEYS::SEMICOLON: return ';'; 54 | case KEYS::FORWARD_SLASH: return '/'; 55 | case KEYS::SLASH: return '\\'; 56 | default: return 0; 57 | } 58 | } 59 | 60 | char Keyboard::GetInput() 61 | { 62 | char key = 0; 63 | 64 | asm volatile("inb %1, %0" : "=a" (key) : "d" (Addresses::keyboard_port)); 65 | 66 | if(key == KEYS::ENTER) 67 | { 68 | return '\n'; 69 | } 70 | else 71 | { 72 | return this->GetKeyCharacter(key); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /keyboard.h: -------------------------------------------------------------------------------- 1 | #ifndef _KEYBOARD_H_ 2 | #define _KEYBOARD_H_ 3 | 4 | #include "main.h" 5 | 6 | class Keyboard 7 | { 8 | private: 9 | enum KEYS 10 | { 11 | A = 0x1E, 12 | B = 0x30, 13 | C = 0x2E, 14 | D = 0x20, 15 | E = 0x12, 16 | F = 0x21, 17 | G = 0x22, 18 | H = 0x23, 19 | I = 0x17, 20 | J = 0x24, 21 | K = 0x25, 22 | L = 0x26, 23 | M = 0x32, 24 | N = 0x31, 25 | O = 0x18, 26 | P = 0x19, 27 | Q = 0x10, 28 | R = 0x13, 29 | S = 0x1F, 30 | T = 0x14, 31 | U = 0x16, 32 | V = 0x2F, 33 | W = 0x11, 34 | X = 0x2D, 35 | Y = 0x15, 36 | Z = 0x2C, 37 | _1 = 0x02, 38 | _2 = 0x03, 39 | _3 = 0x04, 40 | _4 = 0x05, 41 | _5 = 0x06, 42 | _6 = 0x07, 43 | _7 = 0x08, 44 | _8 = 0x09, 45 | _9 = 0x0A, 46 | _0 = 0x0B, 47 | SPACE = 0x39, 48 | OPEN_BRACKET = 0x1A, 49 | CLOSE_BRACKET = 0x1B, 50 | COMMA = 0x33, 51 | DOT = 0x34, 52 | BACKSPACE = 0x0E, 53 | SEMICOLON = 0x27, 54 | FORWARD_SLASH = 0x35, 55 | SLASH = 0x2B, 56 | ESC = 0x01, 57 | ENTER = 0x1C 58 | }; 59 | 60 | char GetKeyCharacter(const unsigned char code); 61 | 62 | public: 63 | Keyboard(); 64 | 65 | char GetInput(); 66 | }; 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /linker.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT(elf32-i386) 2 | ENTRY(entry) 3 | 4 | SECTIONS 5 | { 6 | /* 1M needed at least for the Kernel */ 7 | . = 1M; 8 | 9 | /* text section */ 10 | .text BLOCK(4K) : ALIGN(4K) 11 | { 12 | *(.multiboot) 13 | *(.text) 14 | } 15 | 16 | /* read only data section */ 17 | .rodata BLOCK(4K) : ALIGN(4K) 18 | { 19 | *(.rodata) 20 | } 21 | 22 | /* data section */ 23 | .data BLOCK(4K) : ALIGN(4K) 24 | { 25 | *(.data) 26 | } 27 | 28 | /* bss section */ 29 | .bss BLOCK(4K) : ALIGN(4K) 30 | { 31 | *(COMMON) 32 | *(.bss) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | extern "C" void entry_point() 4 | { 5 | Kernel kernel; 6 | kernel.PrintString("This is a test\n", VIDEO_COLOR_TABLE::WHITE); 7 | kernel.PrintString("Type anything below:\n", VIDEO_COLOR_TABLE::CYAN); 8 | 9 | Keyboard keyboard; 10 | bool keyPressed = false; // State to track if a key has been pressed 11 | 12 | while (1) 13 | { 14 | const char key = keyboard.GetInput(); 15 | 16 | if (key) 17 | { 18 | if (!keyPressed) // Check if the key hasn't been pressed before 19 | { 20 | keyPressed = true; // Mark that the key has been pressed 21 | kernel.PrintCharacter(key, VIDEO_COLOR_TABLE::WHITE); 22 | } 23 | } 24 | else 25 | { 26 | keyPressed = false; // Mark that the key has been released 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /main.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAIN_H_ 2 | #define _MAIN_H_ 3 | 4 | #include "color_table.h" 5 | #include "addresses.h" 6 | #include "kernel.h" 7 | #include "keyboard.h" 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | 3 | CC_FLAGS = -m32 -c -nostdlib -std=c++11 -ffreestanding -O2 -Wall -Wextra 4 | 5 | CPP_FILES := $(wildcard *.cpp) 6 | ASM_FILES := $(wildcard *.asm) 7 | BOOT_FILE := boot.asm 8 | O_FILES := $(CPP_FILES:.cpp=.o) $(ASM_FILES:.asm=.o) 9 | KERNEL_BIN := Kernel.bin 10 | 11 | all: $(KERNEL_BIN) 12 | 13 | clean: 14 | rm -f $(KERNEL_BIN) $(O_FILES) 15 | 16 | %.o: %.cpp 17 | $(CC) $(CC_FLAGS) -o $@ $< 18 | 19 | $(BOOT_FILE): $(O_FILES) 20 | as --32 -o $@ $< 21 | 22 | $(KERNEL_BIN): $(O_FILES) 23 | ld -m elf_i386 -nostdlib -T linker.ld -o $@ $^ 24 | ./iso.sh --------------------------------------------------------------------------------