├── 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 |
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 |
42 |
43 |
44 |
45 |
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
--------------------------------------------------------------------------------