From c2ea7f1446b6f49b5ad1adfd3c1143284d02350d Mon Sep 17 00:00:00 2001 From: Ole Morud Date: Sun, 11 Aug 2024 13:03:13 +0200 Subject: [PATCH] Add keypress detection --- Makefile | 27 ++- src/drivers/ps2-keyboard.c | 178 +++++++++++++++++- src/include/ps2-keyboard.h | 146 ++++++++++++++- src/include/ring_buffer.h | 22 +++ src/kernel/interrupts.c | 347 ++++++++++++++++++++++++++++++++++-- src/kernel/interrupts.h | 313 +++++++++++++++++++++++++++++++- src/kernel/kernel.c | 149 +++++++--------- src/kernel/kernel_state.c | 29 ++- src/kernel/kernel_state.h | 64 ++++++- src/kernel/pic.c | 91 ++++++++++ src/kernel/pic.h | 171 ++++++++++++++++++ src/lib/printf.c | 31 +++- src/lib/ring_buffer.c | 35 ++++ src/test/test_ring_buffer.c | 176 ++++++++++++++++++ 14 files changed, 1652 insertions(+), 127 deletions(-) create mode 100644 src/include/ring_buffer.h create mode 100644 src/kernel/pic.c create mode 100644 src/kernel/pic.h create mode 100644 src/lib/ring_buffer.c create mode 100644 src/test/test_ring_buffer.c diff --git a/Makefile b/Makefile index 219b452..58259ef 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ all: myos.iso SOURCE_DIR := src BUILD_DIR := build + CONTAINER_CMD := podman run -v "$(shell pwd)":"/scratch" \ --workdir="/scratch" \ --network=none \ @@ -20,7 +21,7 @@ LD := $(CONTAINER_CMD) i686-elf-ld AS := $(CONTAINER_CMD) i686-elf-as AR := $(CONTAINER_CMD) i686-elf-ar -C_SOURCES := $(shell find $(SOURCE_DIR) -name '*.c') +C_SOURCES := $(shell find $(SOURCE_DIR) ! -name 'test_*' -name '*.c') ASM_SOURCES := $(shell find $(SOURCE_DIR) -name '*.S') OBJECTS := $(patsubst $(SOURCE_DIR)/%, $(BUILD_DIR)/%, $(C_SOURCES:.c=.o) $(ASM_SOURCES:.S=.o)) DEPENDS := $(patsubst $(SOURCE_DIR)/%, $(BUILD_DIR)/%, $(C_SOURCES:.c=.d)) @@ -60,7 +61,6 @@ $(BUILD_DIR)/kernel/interrupts.o: $(SOURCE_DIR)/kernel/interrupts.c Makefile @mkdir -p $(@D) $(CC) -c $(CFLAGS) -mgeneral-regs-only -mno-red-zone $< -o $@ - $(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c Makefile @mkdir -p $(@D) $(CC) -c $(CFLAGS) $< -o $@ @@ -69,3 +69,26 @@ $(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.S Makefile @mkdir -p $(@D) $(AS) $(ASFLAGS) $< -o $@ + +################### +# TESTS # +################### + +TEST_SOURCE_DIR := $(SOURCE_DIR)/test +TEST_BUILD_DIR := $(BUILD_DIR)/test + +TEST_SOURCES := $(shell find $(TEST_SOURCE_DIR) -name 'test_*.c') +TEST_DEPENDS := $(patsubst $(TEST_SOURCE_DIR)/%, $(TEST_BUILD_DIR)/%, $(TEST_SOURCES:.c=.d)) +TEST_OUTPUT := $(patsubst $(TEST_SOURCE_DIR)/%, $(TEST_BUILD_DIR)/%, $(TEST_SOURCES:.c=)) + +$(info TEST_SOURCES is $(TEST_SOURCES)) +$(info TEST_OUTPUT is $(TEST_OUTPUT)) + +tests: $(TEST_OUTPUT) + +-include $(TEST_DEPENDS) + +$(TEST_BUILD_DIR)/test_%: $(TEST_SOURCE_DIR)/test_%.c $(SOURCE_DIR)/lib/%.c | Makefile + @mkdir -p $(@D) + gcc -O1 -fsanitize=address,undefined -Wall -Wextra -Werror -g3 -std=c2x -D_FORTIFY_SOURCE=2 -I$(SOURCE_DIR)/include -o $@ $^ + diff --git a/src/drivers/ps2-keyboard.c b/src/drivers/ps2-keyboard.c index 287393e..dd8ba5e 100644 --- a/src/drivers/ps2-keyboard.c +++ b/src/drivers/ps2-keyboard.c @@ -1,7 +1,7 @@ #include "ps2-keyboard.h" -const struct str ps2_cmd_str[PS2CMD_COUNT] = { +const struct str ps2_cmd_str[] = { [PS2CMD_SET_LEDS ] = str_attach("PS2CMD_SET_LEDS"), [PS2CMD_ECHO ] = str_attach("PS2CMD_ECHO"), [PS2CMD_GET_SCAN ] = str_attach("PS2CMD_GET_SCAN"), @@ -21,7 +21,7 @@ const struct str ps2_cmd_str[PS2CMD_COUNT] = { [PS2CMD_RESEND_RESET_AND_SELF_TEST] = str_attach("PS2CMD_RESEND_RESET_AND_SELF_TEST"), }; -const struct str ps2_response_str[PS2RESPONSE_COUNT] = { +const struct str ps2_response_str[] = { [PS2RESPONSE_ERROR_1 ] = str_attach("PS2RESPONSE_ERROR_1"), [PS2RESPONSE_ERROR_2 ] = str_attach("PS2RESPONSE_ERROR_2"), [PS2RESPONSE_SELF_TEST_PASSED ] = str_attach("PS2RESPONSE_SELF_TEST_PASSED"), @@ -32,4 +32,178 @@ const struct str ps2_response_str[PS2RESPONSE_COUNT] = { [PS2RESPONSE_RESEND ] = str_attach("PS2RESPONSE_RESEND"), }; +const struct str ps2_key_str[] = { + [KEY_EXTENDED ] = str_attach("KEY_EXTENDED (PRESSED)"), + [KEY_ESCAPE ] = str_attach("KEY_ESCAPE (PRESSED)"), + [KEY_1 ] = str_attach("KEY_1 (PRESSED)"), + [KEY_2 ] = str_attach("KEY_2 (PRESSED)"), + [KEY_3 ] = str_attach("KEY_3 (PRESSED)"), + [KEY_4 ] = str_attach("KEY_4 (PRESSED)"), + [KEY_5 ] = str_attach("KEY_5 (PRESSED)"), + [KEY_6 ] = str_attach("KEY_6 (PRESSED)"), + [KEY_7 ] = str_attach("KEY_7 (PRESSED)"), + [KEY_8 ] = str_attach("KEY_8 (PRESSED)"), + [KEY_9 ] = str_attach("KEY_9 (PRESSED)"), + [KEY_0 ] = str_attach("KEY_0 (PRESSED)"), + [KEY_MINUS ] = str_attach("KEY_MINUS (PRESSED)"), + [KEY_EQUALS ] = str_attach("KEY_EQUALS (PRESSED)"), + [KEY_BACKSPACE ] = str_attach("KEY_BACKSPACE (PRESSED)"), + [KEY_TAB ] = str_attach("KEY_TAB (PRESSED)"), + [KEY_Q ] = str_attach("KEY_Q (PRESSED)"), + [KEY_W ] = str_attach("KEY_W (PRESSED)"), + [KEY_E ] = str_attach("KEY_E (PRESSED)"), + [KEY_R ] = str_attach("KEY_R (PRESSED)"), + [KEY_T ] = str_attach("KEY_T (PRESSED)"), + [KEY_Y ] = str_attach("KEY_Y (PRESSED)"), + [KEY_U ] = str_attach("KEY_U (PRESSED)"), + [KEY_I ] = str_attach("KEY_I (PRESSED)"), + [KEY_O ] = str_attach("KEY_O (PRESSED)"), + [KEY_P ] = str_attach("KEY_P (PRESSED)"), + [KEY_SQUARE_BRACKET_LEFT ] = str_attach("KEY_SQUARE_BRACKET_LEFT (PRESSED)"), + [KEY_SQUARE_BRACKET_RIGHT] = str_attach("KEY_SQUARE_BRACKET_RIGHT (PRESSED)"), + [KEY_ENTER ] = str_attach("KEY_ENTER (PRESSED)"), + [KEY_LEFT_CONTROL ] = str_attach("KEY_LEFT_CONTROL (PRESSED)"), + [KEY_A ] = str_attach("KEY_A (PRESSED)"), + [KEY_S ] = str_attach("KEY_S (PRESSED)"), + [KEY_D ] = str_attach("KEY_D (PRESSED)"), + [KEY_F ] = str_attach("KEY_F (PRESSED)"), + [KEY_G ] = str_attach("KEY_G (PRESSED)"), + [KEY_H ] = str_attach("KEY_H (PRESSED)"), + [KEY_J ] = str_attach("KEY_J (PRESSED)"), + [KEY_K ] = str_attach("KEY_K (PRESSED)"), + [KEY_L ] = str_attach("KEY_L (PRESSED)"), + [KEY_SEMICOLON ] = str_attach("KEY_SEMICOLON (PRESSED)"), + [KEY_SINGLE_QUOTE ] = str_attach("KEY_SINGLE_QUOTE (PRESSED)"), + [KEY_BACKTICK ] = str_attach("KEY_BACKTICK (PRESSED)"), + [KEY_LEFT_SHIFT ] = str_attach("KEY_LEFT_SHIFT (PRESSED)"), + [KEY_BACKSLASH ] = str_attach("KEY_BACKSLASH (PRESSED)"), + [KEY_Z ] = str_attach("KEY_Z (PRESSED)"), + [KEY_X ] = str_attach("KEY_X (PRESSED)"), + [KEY_C ] = str_attach("KEY_C (PRESSED)"), + [KEY_V ] = str_attach("KEY_V (PRESSED)"), + [KEY_B ] = str_attach("KEY_B (PRESSED)"), + [KEY_N ] = str_attach("KEY_N (PRESSED)"), + [KEY_M ] = str_attach("KEY_M (PRESSED)"), + [KEY_COMMA ] = str_attach("KEY_COMMA (PRESSED)"), + [KEY_DOT ] = str_attach("KEY_DOT (PRESSED)"), + [KEY_FORWARD_SLASH ] = str_attach("KEY_FORWARD_SLASH (PRESSED)"), + [KEY_RIGHT_SHIFT ] = str_attach("KEY_RIGHT_SHIFT (PRESSED)"), + [KEY_KEYPAD_ASTERISK ] = str_attach("KEY_KEYPAD_ASTERISK (PRESSED)"), + [KEY_LEFT_ALT ] = str_attach("KEY_LEFT_ALT (PRESSED)"), + [KEY_SPACE ] = str_attach("KEY_SPACE (PRESSED)"), + [KEY_CAPSLOCK ] = str_attach("KEY_CAPSLOCK (PRESSED)"), + [KEY_F1 ] = str_attach("KEY_F1 (PRESSED)"), + [KEY_F2 ] = str_attach("KEY_F2 (PRESSED)"), + [KEY_F3 ] = str_attach("KEY_F3 (PRESSED)"), + [KEY_F4 ] = str_attach("KEY_F4 (PRESSED)"), + [KEY_F5 ] = str_attach("KEY_F5 (PRESSED)"), + [KEY_F6 ] = str_attach("KEY_F6 (PRESSED)"), + [KEY_F7 ] = str_attach("KEY_F7 (PRESSED)"), + [KEY_F8 ] = str_attach("KEY_F8 (PRESSED)"), + [KEY_F9 ] = str_attach("KEY_F9 (PRESSED)"), + [KEY_F10 ] = str_attach("KEY_F10 (PRESSED)"), + [KEY_NUMBERLOCK ] = str_attach("KEY_NUMBERLOCK (PRESSED)"), + [KEY_SCROLLLOCK ] = str_attach("KEY_SCROLLLOCK (PRESSED)"), + [KEY_KEYPAD_7 ] = str_attach("KEY_KEYPAD_7 (PRESSED)"), + [KEY_KEYPAD_8 ] = str_attach("KEY_KEYPAD_8 (PRESSED)"), + [KEY_KEYPAD_9 ] = str_attach("KEY_KEYPAD_9 (PRESSED)"), + [KEY_KEYPAD_MINUS ] = str_attach("KEY_KEYPAD_MINUS (PRESSED)"), + [KEY_KEYPAD_4 ] = str_attach("KEY_KEYPAD_4 (PRESSED)"), + [KEY_KEYPAD_5 ] = str_attach("KEY_KEYPAD_5 (PRESSED)"), + [KEY_KEYPAD_6 ] = str_attach("KEY_KEYPAD_6 (PRESSED)"), + [KEY_KEYPAD_PLUS ] = str_attach("KEY_KEYPAD_PLUS (PRESSED)"), + [KEY_KEYPAD_1 ] = str_attach("KEY_KEYPAD_1 (PRESSED)"), + [KEY_KEYPAD_2 ] = str_attach("KEY_KEYPAD_2 (PRESSED)"), + [KEY_KEYPAD_3 ] = str_attach("KEY_KEYPAD_3 (PRESSED)"), + [KEY_KEYPAD_0 ] = str_attach("KEY_KEYPAD_0 (PRESSED)"), + [KEY_KEYPAD_DOT ] = str_attach("KEY_KEYPAD_DOT (PRESSED)"), + [KEY_F11 ] = str_attach("KEY_F11 (PRESSED)"), + [KEY_F12 ] = str_attach("KEY_F12 (PRESSED)"), + + [KEY_RELEASED | KEY_ESCAPE ] = str_attach("KEY_ESCAPE (RELEASED)"), + [KEY_RELEASED | KEY_1 ] = str_attach("KEY_1 (RELEASED)"), + [KEY_RELEASED | KEY_2 ] = str_attach("KEY_2 (RELEASED)"), + [KEY_RELEASED | KEY_3 ] = str_attach("KEY_3 (RELEASED)"), + [KEY_RELEASED | KEY_4 ] = str_attach("KEY_4 (RELEASED)"), + [KEY_RELEASED | KEY_5 ] = str_attach("KEY_5 (RELEASED)"), + [KEY_RELEASED | KEY_6 ] = str_attach("KEY_6 (RELEASED)"), + [KEY_RELEASED | KEY_7 ] = str_attach("KEY_7 (RELEASED)"), + [KEY_RELEASED | KEY_8 ] = str_attach("KEY_8 (RELEASED)"), + [KEY_RELEASED | KEY_9 ] = str_attach("KEY_9 (RELEASED)"), + [KEY_RELEASED | KEY_0 ] = str_attach("KEY_0 (RELEASED)"), + [KEY_RELEASED | KEY_MINUS ] = str_attach("KEY_MINUS (RELEASED)"), + [KEY_RELEASED | KEY_EQUALS ] = str_attach("KEY_EQUALS (RELEASED)"), + [KEY_RELEASED | KEY_BACKSPACE ] = str_attach("KEY_BACKSPACE (RELEASED)"), + [KEY_RELEASED | KEY_TAB ] = str_attach("KEY_TAB (RELEASED)"), + [KEY_RELEASED | KEY_Q ] = str_attach("KEY_Q (RELEASED)"), + [KEY_RELEASED | KEY_W ] = str_attach("KEY_W (RELEASED)"), + [KEY_RELEASED | KEY_E ] = str_attach("KEY_E (RELEASED)"), + [KEY_RELEASED | KEY_R ] = str_attach("KEY_R (RELEASED)"), + [KEY_RELEASED | KEY_T ] = str_attach("KEY_T (RELEASED)"), + [KEY_RELEASED | KEY_Y ] = str_attach("KEY_Y (RELEASED)"), + [KEY_RELEASED | KEY_U ] = str_attach("KEY_U (RELEASED)"), + [KEY_RELEASED | KEY_I ] = str_attach("KEY_I (RELEASED)"), + [KEY_RELEASED | KEY_O ] = str_attach("KEY_O (RELEASED)"), + [KEY_RELEASED | KEY_P ] = str_attach("KEY_P (RELEASED)"), + [KEY_RELEASED | KEY_SQUARE_BRACKET_LEFT ] = str_attach("KEY_SQUARE_BRACKET_LEFT (RELEASED)"), + [KEY_RELEASED | KEY_SQUARE_BRACKET_RIGHT] = str_attach("KEY_SQUARE_BRACKET_RIGHT (RELEASED)"), + [KEY_RELEASED | KEY_ENTER ] = str_attach("KEY_ENTER (RELEASED)"), + [KEY_RELEASED | KEY_LEFT_CONTROL ] = str_attach("KEY_LEFT_CONTROL (RELEASED)"), + [KEY_RELEASED | KEY_A ] = str_attach("KEY_A (RELEASED)"), + [KEY_RELEASED | KEY_S ] = str_attach("KEY_S (RELEASED)"), + [KEY_RELEASED | KEY_D ] = str_attach("KEY_D (RELEASED)"), + [KEY_RELEASED | KEY_F ] = str_attach("KEY_F (RELEASED)"), + [KEY_RELEASED | KEY_G ] = str_attach("KEY_G (RELEASED)"), + [KEY_RELEASED | KEY_H ] = str_attach("KEY_H (RELEASED)"), + [KEY_RELEASED | KEY_J ] = str_attach("KEY_J (RELEASED)"), + [KEY_RELEASED | KEY_K ] = str_attach("KEY_K (RELEASED)"), + [KEY_RELEASED | KEY_L ] = str_attach("KEY_L (RELEASED)"), + [KEY_RELEASED | KEY_SEMICOLON ] = str_attach("KEY_SEMICOLON (RELEASED)"), + [KEY_RELEASED | KEY_SINGLE_QUOTE ] = str_attach("KEY_SINGLE_QUOTE (RELEASED)"), + [KEY_RELEASED | KEY_BACKTICK ] = str_attach("KEY_BACKTICK (RELEASED)"), + [KEY_RELEASED | KEY_LEFT_SHIFT ] = str_attach("KEY_LEFT_SHIFT (RELEASED)"), + [KEY_RELEASED | KEY_BACKSLASH ] = str_attach("KEY_BACKSLASH (RELEASED)"), + [KEY_RELEASED | KEY_Z ] = str_attach("KEY_Z (RELEASED)"), + [KEY_RELEASED | KEY_X ] = str_attach("KEY_X (RELEASED)"), + [KEY_RELEASED | KEY_C ] = str_attach("KEY_C (RELEASED)"), + [KEY_RELEASED | KEY_V ] = str_attach("KEY_V (RELEASED)"), + [KEY_RELEASED | KEY_B ] = str_attach("KEY_B (RELEASED)"), + [KEY_RELEASED | KEY_N ] = str_attach("KEY_N (RELEASED)"), + [KEY_RELEASED | KEY_M ] = str_attach("KEY_M (RELEASED)"), + [KEY_RELEASED | KEY_COMMA ] = str_attach("KEY_COMMA (RELEASED)"), + [KEY_RELEASED | KEY_DOT ] = str_attach("KEY_DOT (RELEASED)"), + [KEY_RELEASED | KEY_FORWARD_SLASH ] = str_attach("KEY_FORWARD_SLASH (RELEASED)"), + [KEY_RELEASED | KEY_RIGHT_SHIFT ] = str_attach("KEY_RIGHT_SHIFT (RELEASED)"), + [KEY_RELEASED | KEY_KEYPAD_ASTERISK ] = str_attach("KEY_KEYPAD_ASTERISK (RELEASED)"), + [KEY_RELEASED | KEY_LEFT_ALT ] = str_attach("KEY_LEFT_ALT (RELEASED)"), + [KEY_RELEASED | KEY_SPACE ] = str_attach("KEY_SPACE (RELEASED)"), + [KEY_RELEASED | KEY_CAPSLOCK ] = str_attach("KEY_CAPSLOCK (RELEASED)"), + [KEY_RELEASED | KEY_F1 ] = str_attach("KEY_F1 (RELEASED)"), + [KEY_RELEASED | KEY_F2 ] = str_attach("KEY_F2 (RELEASED)"), + [KEY_RELEASED | KEY_F3 ] = str_attach("KEY_F3 (RELEASED)"), + [KEY_RELEASED | KEY_F4 ] = str_attach("KEY_F4 (RELEASED)"), + [KEY_RELEASED | KEY_F5 ] = str_attach("KEY_F5 (RELEASED)"), + [KEY_RELEASED | KEY_F6 ] = str_attach("KEY_F6 (RELEASED)"), + [KEY_RELEASED | KEY_F7 ] = str_attach("KEY_F7 (RELEASED)"), + [KEY_RELEASED | KEY_F8 ] = str_attach("KEY_F8 (RELEASED)"), + [KEY_RELEASED | KEY_F9 ] = str_attach("KEY_F9 (RELEASED)"), + [KEY_RELEASED | KEY_F10 ] = str_attach("KEY_F10 (RELEASED)"), + [KEY_RELEASED | KEY_NUMBERLOCK ] = str_attach("KEY_NUMBERLOCK (RELEASED)"), + [KEY_RELEASED | KEY_SCROLLLOCK ] = str_attach("KEY_SCROLLLOCK (RELEASED)"), + [KEY_RELEASED | KEY_KEYPAD_7 ] = str_attach("KEY_KEYPAD_7 (RELEASED)"), + [KEY_RELEASED | KEY_KEYPAD_8 ] = str_attach("KEY_KEYPAD_8 (RELEASED)"), + [KEY_RELEASED | KEY_KEYPAD_9 ] = str_attach("KEY_KEYPAD_9 (RELEASED)"), + [KEY_RELEASED | KEY_KEYPAD_MINUS ] = str_attach("KEY_KEYPAD_MINUS (RELEASED)"), + [KEY_RELEASED | KEY_KEYPAD_4 ] = str_attach("KEY_KEYPAD_4 (RELEASED)"), + [KEY_RELEASED | KEY_KEYPAD_5 ] = str_attach("KEY_KEYPAD_5 (RELEASED)"), + [KEY_RELEASED | KEY_KEYPAD_6 ] = str_attach("KEY_KEYPAD_6 (RELEASED)"), + [KEY_RELEASED | KEY_KEYPAD_PLUS ] = str_attach("KEY_KEYPAD_PLUS (RELEASED)"), + [KEY_RELEASED | KEY_KEYPAD_1 ] = str_attach("KEY_KEYPAD_1 (RELEASED)"), + [KEY_RELEASED | KEY_KEYPAD_2 ] = str_attach("KEY_KEYPAD_2 (RELEASED)"), + [KEY_RELEASED | KEY_KEYPAD_3 ] = str_attach("KEY_KEYPAD_3 (RELEASED)"), + [KEY_RELEASED | KEY_KEYPAD_0 ] = str_attach("KEY_KEYPAD_0 (RELEASED)"), + [KEY_RELEASED | KEY_KEYPAD_DOT ] = str_attach("KEY_KEYPAD_DOT (RELEASED)"), + [KEY_RELEASED | KEY_F11 ] = str_attach("KEY_F11 (RELEASED)"), + [KEY_RELEASED | KEY_F12 ] = str_attach("KEY_F12 (RELEASED)"), +}; diff --git a/src/include/ps2-keyboard.h b/src/include/ps2-keyboard.h index 966302e..15b0c40 100644 --- a/src/include/ps2-keyboard.h +++ b/src/include/ps2-keyboard.h @@ -1,9 +1,10 @@ #pragma once #include "str.h" +#include /* commands that the system sends to the keyboard */ -enum ps2_cmd { +enum ps2_cmd : uint8_t { /* Set LEDs */ PS2CMD_SET_LEDS = 0xED, @@ -55,12 +56,11 @@ enum ps2_cmd { /* Reset and start self-test */ PS2CMD_RESEND_RESET_AND_SELF_TEST = 0xFF, - - PS2CMD_COUNT, }; +extern const struct str ps2_cmd_str[]; /* commands that the keyboard sends to the system */ -enum ps2_response { +enum ps2_response : uint8_t { /* Self test passed (sent after "0xFF (reset)" command or keyboard power up) */ PS2RESPONSE_SELF_TEST_PASSED = 0xAA, @@ -81,11 +81,141 @@ enum ps2_response { /* Key detection error or internal buffer overrun */ PS2RESPONSE_ERROR_1 = 0x00, PS2RESPONSE_ERROR_2 = 0xFF, +}; +extern const struct str ps2_response_str[]; - PS2RESPONSE_COUNT, +enum ps2_keys { + KEY_RELEASED = 0x80, + KEY_EXTENDED = 0xE0, + + KEY_ESCAPE = 0x01, + KEY_1 = 0x02, + KEY_2 = 0x03, + KEY_3 = 0x04, + KEY_4 = 0x05, + KEY_5 = 0x06, + KEY_6 = 0x07, + KEY_7 = 0x08, + KEY_8 = 0x09, + KEY_9 = 0x0A, + KEY_0 = 0x0B, + KEY_MINUS = 0x0C, + KEY_EQUALS = 0x0D, + KEY_BACKSPACE = 0x0E, + KEY_TAB = 0x0F, + KEY_Q = 0x10, + KEY_W = 0x11, + KEY_E = 0x12, + KEY_R = 0x13, + KEY_T = 0x14, + KEY_Y = 0x15, + KEY_U = 0x16, + KEY_I = 0x17, + KEY_O = 0x18, + KEY_P = 0x19, + KEY_SQUARE_BRACKET_LEFT = 0x1A, + KEY_SQUARE_BRACKET_RIGHT = 0x1B, + KEY_ENTER = 0x1C, + KEY_LEFT_CONTROL = 0x1D, + KEY_A = 0x1E, + KEY_S = 0x1F, + KEY_D = 0x20, + KEY_F = 0x21, + KEY_G = 0x22, + KEY_H = 0x23, + KEY_J = 0x24, + KEY_K = 0x25, + KEY_L = 0x26, + KEY_SEMICOLON = 0x27, + KEY_SINGLE_QUOTE = 0x28, + KEY_BACKTICK = 0x29, + KEY_LEFT_SHIFT = 0x2A, + KEY_BACKSLASH = 0x2B, + KEY_Z = 0x2C, + KEY_X = 0x2D, + KEY_C = 0x2E, + KEY_V = 0x2F, + KEY_B = 0x30, + KEY_N = 0x31, + KEY_M = 0x32, + KEY_COMMA = 0x33, + KEY_DOT = 0x34, + KEY_FORWARD_SLASH = 0x35, + KEY_RIGHT_SHIFT = 0x36, + KEY_KEYPAD_ASTERISK = 0x37, + KEY_LEFT_ALT = 0x38, + KEY_SPACE = 0x39, + KEY_CAPSLOCK = 0x3A, + KEY_F1 = 0x3B, + KEY_F2 = 0x3C, + KEY_F3 = 0x3D, + KEY_F4 = 0x3E, + KEY_F5 = 0x3F, + KEY_F6 = 0x40, + KEY_F7 = 0x41, + KEY_F8 = 0x42, + KEY_F9 = 0x43, + KEY_F10 = 0x44, + KEY_NUMBERLOCK = 0x45, + KEY_SCROLLLOCK = 0x46, + KEY_KEYPAD_7 = 0x47, + KEY_KEYPAD_8 = 0x48, + KEY_KEYPAD_9 = 0x49, + KEY_KEYPAD_MINUS = 0x4A, + KEY_KEYPAD_4 = 0x4B, + KEY_KEYPAD_5 = 0x4C, + KEY_KEYPAD_6 = 0x4D, + KEY_KEYPAD_PLUS = 0x4E, + KEY_KEYPAD_1 = 0x4F, + KEY_KEYPAD_2 = 0x50, + KEY_KEYPAD_3 = 0x51, + KEY_KEYPAD_0 = 0x52, + KEY_KEYPAD_DOT = 0x53, + KEY_F11 = 0x57, + KEY_F12 = 0x58, +}; +extern const struct str ps2_key_str[]; + +enum ps2_extended_key : uint8_t { + KEY_E_MULTIMEDIA_PREV_TRACK = 0x10, + KEY_E_MULTIMEDIA_NEXT_TRACK = 0x19, + KEY_E_KEYPAD_ENTER = 0x1C, + KEY_E_RIGHT_CONTROL = 0x1D, + KEY_E_MULTIMEDIA_MUTE = 0x20, + KEY_E_MULTIMEDIA_CALCULATOR = 0x21, + KEY_E_MULTIMEDIA_PLAY = 0x22, + KEY_E_MULTIMEDIA_STOP = 0x24, + KEY_E_MULTIMEDIA_VOLUME_DOWN = 0x2E, + KEY_E_MULTIMEDIA_VOLUME_UP = 0x30, + KEY_E_MULTIMEDIA_WWW_HOME = 0x32, + KEY_E_KEYPAD_FORWARD_SLASH = 0x35, + KEY_E_RIGHT_ALT = 0x38, + KEY_E_HOME = 0x47, + KEY_E_CURSOR_UP = 0x48, + KEY_E_PAGE_UP = 0x49, + KEY_E_CURSOR_LEFT = 0x4B, + KEY_E_CURSOR_RIGHT = 0x4D, + KEY_E_END = 0x4F, + KEY_E_CURSOR_DOWN = 0x50, + KEY_E_PAGE_DOWN = 0x51, + KEY_E_DELETE = 0x53, + KEY_E_LEFT_GUI = 0x5B, + KEY_E_RIGHT_GUI = 0x5C, + KEY_E_APPS = 0x5D, + KEY_E_ACPI_SLEEP = 0x5F, + KEY_E_ACPI_WAKE = 0x63, + KEY_E_MULTIMEDIA_WWW_SEARCH = 0x65, + KEY_E_MULTIMEDIA_WWW_REFRESH = 0x67, + KEY_E_MULTIMEDIA_WWW_STOP = 0x68, + KEY_E_MULTIMEDIA_WWW_FORWARD = 0x69, + KEY_E_MULTIMEDIA_MY_COMPUTER = 0x6B, + KEY_E_MULTIMEDIA_EMAIL = 0x6C, + KEY_E_MULTIMEDIA_MEDIA_SELECT = 0x6D, + /* TODO: implement these: + 0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5 pause pressed + 0x2A, 0xE0, 0x37 print screen pressed + 0xB7, 0xE0, 0xAA print screen released + */ }; -extern const struct str ps2_cmd_str[PS2CMD_COUNT]; - -extern const struct str ps2_response_str[PS2RESPONSE_COUNT]; diff --git a/src/include/ring_buffer.h b/src/include/ring_buffer.h new file mode 100644 index 0000000..b29099b --- /dev/null +++ b/src/include/ring_buffer.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +constexpr size_t RING_BUFFER_MAX = 1024; + +struct ring_buffer { + size_t head; + size_t tail; + size_t len; + size_t entry_size; + uint8_t data[RING_BUFFER_MAX]; +}; + +#define make_ring_buffer(type) (struct ring_buffer){.entry_size = sizeof(type)} + +size_t ring_buffer_remaining(struct ring_buffer* q); + +bool ring_buffer_push(struct ring_buffer* q, const void* data); + +bool ring_buffer_get(struct ring_buffer* q, void* out); diff --git a/src/kernel/interrupts.c b/src/kernel/interrupts.c index 2f0126b..74a9ae8 100644 --- a/src/kernel/interrupts.c +++ b/src/kernel/interrupts.c @@ -4,7 +4,9 @@ #include "interrupts.h" #include "kernel_state.h" -#define EXCEPTION_DEPTH_MAX 5 +#include "pic.h" + +#define EXCEPTION_DEPTH_MAX 3 struct __attribute__((packed)) interrupt_frame { uword_t ip; @@ -31,6 +33,25 @@ static void print_interrupt_frame(struct interrupt_frame* f) f->ss); } +/* not an interrupt/exception, but called by exception stubs */ +__attribute__((noreturn)) +static void panic_exception_not_implemented(struct interrupt_frame* frame, int exception_no) +{ + terminal_set_color(VGA_COLOR_WHITE, VGA_COLOR_RED); + printf(str_attach("non-implemented exception {i32} occurred\n"), exception_no); + struct str name = idt_desc_index_str[exception_no]; + if (name.len != 0) { + printf(str_attach("exception name: {str})\n"), name); + } + if (frame != NULL) { + print_interrupt_frame(frame); + } else { + printf(str_attach("(no interrupt frame)n")); + } + __asm__ volatile("cli; hlt"); + __builtin_unreachable(); +} + /** * Exceptions * ========== @@ -89,18 +110,6 @@ void exception_handler_page_fault(struct interrupt_frame* frame, int err) __builtin_unreachable(); } -__attribute__((interrupt, noreturn)) -void exception_default(struct interrupt_frame* frame) -{ - (void)frame; - if (kernel.nested_exception_counter++ > EXCEPTION_DEPTH_MAX) { - panic(str_attach("fatal: too many nested exceptions\n")); - } - panic(str_attach("non-implemented exception occured")); - - kernel.nested_exception_counter = 0; -} - /** * Interrupts * ========== @@ -129,16 +138,320 @@ void interrupt_handler_1(struct interrupt_frame* frame) kernel.nested_exception_counter = 0; } -__attribute__((interrupt)) -void interrupt_handler_userspace_exit(struct interrupt_frame* frame) +/* + * IRQs + * ==== + * */ +static void irq_stub(struct interrupt_frame* frame, int line) { + (void)frame; + (void)line; if (kernel.nested_exception_counter++ > EXCEPTION_DEPTH_MAX) { panic(str_attach("fatal: too many nested exceptions\n")); } - (void)frame; - printf(str_attach("interrupt_handler_userspace_exit called!\n")); + //printf(str_attach("irq handler {i32} called!\n"), line); + outb(PIC1_COMMAND, OCW2_EOI); kernel.nested_exception_counter = 0; } +__attribute__((interrupt)) void irq_handler_0(struct interrupt_frame* frame) { irq_stub(frame, 0); } +/* IRQ1 - keyboard controller */ +#include "ps2-keyboard.h" +__attribute__((interrupt)) void irq_handler_1(struct interrupt_frame* frame) +{ + /* TODO: move keyboard logic to a separate compilation unit */ + (void)frame; + uint8_t key = inb(PIC_KEYBOARD); + + bool released = key & KEY_RELEASED; + + printf(str_attach("key {str}\n"), ps2_key_str[key]); + outb(PIC1_COMMAND, OCW2_EOI); +} + +__attribute__((interrupt)) void irq_handler_2(struct interrupt_frame* frame) { irq_stub(frame, 2); } +__attribute__((interrupt)) void irq_handler_3(struct interrupt_frame* frame) { irq_stub(frame, 3); } +__attribute__((interrupt)) void irq_handler_4(struct interrupt_frame* frame) { irq_stub(frame, 4); } +__attribute__((interrupt)) void irq_handler_5(struct interrupt_frame* frame) { irq_stub(frame, 5); } +__attribute__((interrupt)) void irq_handler_6(struct interrupt_frame* frame) { irq_stub(frame, 6); } +__attribute__((interrupt)) void irq_handler_7(struct interrupt_frame* frame) { irq_stub(frame, 7); } +__attribute__((interrupt)) void irq_handler_8(struct interrupt_frame* frame) { irq_stub(frame, 8); } +__attribute__((interrupt)) void irq_handler_9(struct interrupt_frame* frame) { irq_stub(frame, 9); } +__attribute__((interrupt)) void irq_handler_10(struct interrupt_frame* frame) { irq_stub(frame, 10); } +__attribute__((interrupt)) void irq_handler_11(struct interrupt_frame* frame) { irq_stub(frame, 11); } +__attribute__((interrupt)) void irq_handler_12(struct interrupt_frame* frame) { irq_stub(frame, 12); } +__attribute__((interrupt)) void irq_handler_13(struct interrupt_frame* frame) { irq_stub(frame, 13); } +__attribute__((interrupt)) void irq_handler_14(struct interrupt_frame* frame) { irq_stub(frame, 14); } +__attribute__((interrupt)) void irq_handler_15(struct interrupt_frame* frame) { irq_stub(frame, 15); } + + +/** + * Exception Stubs + * =============== + */ + +#define DEFINE_EXCEPTION_STUB(n) \ + __attribute__((interrupt, noreturn)) \ + void EXCEPTION_STUB(n)(struct interrupt_frame* frame) \ + { \ + panic_exception_not_implemented(frame, n); \ + } + +DEFINE_EXCEPTION_STUB(0) +DEFINE_EXCEPTION_STUB(1) +DEFINE_EXCEPTION_STUB(2) +DEFINE_EXCEPTION_STUB(3) +DEFINE_EXCEPTION_STUB(4) +DEFINE_EXCEPTION_STUB(5) +DEFINE_EXCEPTION_STUB(6) +DEFINE_EXCEPTION_STUB(7) +DEFINE_EXCEPTION_STUB(8) +DEFINE_EXCEPTION_STUB(9) +DEFINE_EXCEPTION_STUB(10) +DEFINE_EXCEPTION_STUB(11) +DEFINE_EXCEPTION_STUB(12) +DEFINE_EXCEPTION_STUB(13) +DEFINE_EXCEPTION_STUB(14) +DEFINE_EXCEPTION_STUB(15) +DEFINE_EXCEPTION_STUB(16) +DEFINE_EXCEPTION_STUB(17) +DEFINE_EXCEPTION_STUB(18) +DEFINE_EXCEPTION_STUB(19) +DEFINE_EXCEPTION_STUB(20) +DEFINE_EXCEPTION_STUB(21) +DEFINE_EXCEPTION_STUB(22) +DEFINE_EXCEPTION_STUB(23) +DEFINE_EXCEPTION_STUB(24) +DEFINE_EXCEPTION_STUB(25) +DEFINE_EXCEPTION_STUB(26) +DEFINE_EXCEPTION_STUB(27) +DEFINE_EXCEPTION_STUB(28) +DEFINE_EXCEPTION_STUB(29) +DEFINE_EXCEPTION_STUB(30) +DEFINE_EXCEPTION_STUB(31) +DEFINE_EXCEPTION_STUB(32) +DEFINE_EXCEPTION_STUB(33) +DEFINE_EXCEPTION_STUB(34) +DEFINE_EXCEPTION_STUB(35) +DEFINE_EXCEPTION_STUB(36) +DEFINE_EXCEPTION_STUB(37) +DEFINE_EXCEPTION_STUB(38) +DEFINE_EXCEPTION_STUB(39) +DEFINE_EXCEPTION_STUB(40) +DEFINE_EXCEPTION_STUB(41) +DEFINE_EXCEPTION_STUB(42) +DEFINE_EXCEPTION_STUB(43) +DEFINE_EXCEPTION_STUB(44) +DEFINE_EXCEPTION_STUB(45) +DEFINE_EXCEPTION_STUB(46) +DEFINE_EXCEPTION_STUB(47) +DEFINE_EXCEPTION_STUB(48) +DEFINE_EXCEPTION_STUB(49) +DEFINE_EXCEPTION_STUB(50) +DEFINE_EXCEPTION_STUB(51) +DEFINE_EXCEPTION_STUB(52) +DEFINE_EXCEPTION_STUB(53) +DEFINE_EXCEPTION_STUB(54) +DEFINE_EXCEPTION_STUB(55) +DEFINE_EXCEPTION_STUB(56) +DEFINE_EXCEPTION_STUB(57) +DEFINE_EXCEPTION_STUB(58) +DEFINE_EXCEPTION_STUB(59) +DEFINE_EXCEPTION_STUB(60) +DEFINE_EXCEPTION_STUB(61) +DEFINE_EXCEPTION_STUB(62) +DEFINE_EXCEPTION_STUB(63) +DEFINE_EXCEPTION_STUB(64) +DEFINE_EXCEPTION_STUB(65) +DEFINE_EXCEPTION_STUB(66) +DEFINE_EXCEPTION_STUB(67) +DEFINE_EXCEPTION_STUB(68) +DEFINE_EXCEPTION_STUB(69) +DEFINE_EXCEPTION_STUB(70) +DEFINE_EXCEPTION_STUB(71) +DEFINE_EXCEPTION_STUB(72) +DEFINE_EXCEPTION_STUB(73) +DEFINE_EXCEPTION_STUB(74) +DEFINE_EXCEPTION_STUB(75) +DEFINE_EXCEPTION_STUB(76) +DEFINE_EXCEPTION_STUB(77) +DEFINE_EXCEPTION_STUB(78) +DEFINE_EXCEPTION_STUB(79) +DEFINE_EXCEPTION_STUB(80) +DEFINE_EXCEPTION_STUB(81) +DEFINE_EXCEPTION_STUB(82) +DEFINE_EXCEPTION_STUB(83) +DEFINE_EXCEPTION_STUB(84) +DEFINE_EXCEPTION_STUB(85) +DEFINE_EXCEPTION_STUB(86) +DEFINE_EXCEPTION_STUB(87) +DEFINE_EXCEPTION_STUB(88) +DEFINE_EXCEPTION_STUB(89) +DEFINE_EXCEPTION_STUB(90) +DEFINE_EXCEPTION_STUB(91) +DEFINE_EXCEPTION_STUB(92) +DEFINE_EXCEPTION_STUB(93) +DEFINE_EXCEPTION_STUB(94) +DEFINE_EXCEPTION_STUB(95) +DEFINE_EXCEPTION_STUB(96) +DEFINE_EXCEPTION_STUB(97) +DEFINE_EXCEPTION_STUB(98) +DEFINE_EXCEPTION_STUB(99) +DEFINE_EXCEPTION_STUB(100) +DEFINE_EXCEPTION_STUB(101) +DEFINE_EXCEPTION_STUB(102) +DEFINE_EXCEPTION_STUB(103) +DEFINE_EXCEPTION_STUB(104) +DEFINE_EXCEPTION_STUB(105) +DEFINE_EXCEPTION_STUB(106) +DEFINE_EXCEPTION_STUB(107) +DEFINE_EXCEPTION_STUB(108) +DEFINE_EXCEPTION_STUB(109) +DEFINE_EXCEPTION_STUB(110) +DEFINE_EXCEPTION_STUB(111) +DEFINE_EXCEPTION_STUB(112) +DEFINE_EXCEPTION_STUB(113) +DEFINE_EXCEPTION_STUB(114) +DEFINE_EXCEPTION_STUB(115) +DEFINE_EXCEPTION_STUB(116) +DEFINE_EXCEPTION_STUB(117) +DEFINE_EXCEPTION_STUB(118) +DEFINE_EXCEPTION_STUB(119) +DEFINE_EXCEPTION_STUB(120) +DEFINE_EXCEPTION_STUB(121) +DEFINE_EXCEPTION_STUB(122) +DEFINE_EXCEPTION_STUB(123) +DEFINE_EXCEPTION_STUB(124) +DEFINE_EXCEPTION_STUB(125) +DEFINE_EXCEPTION_STUB(126) +DEFINE_EXCEPTION_STUB(127) +DEFINE_EXCEPTION_STUB(128) +DEFINE_EXCEPTION_STUB(129) +DEFINE_EXCEPTION_STUB(130) +DEFINE_EXCEPTION_STUB(131) +DEFINE_EXCEPTION_STUB(132) +DEFINE_EXCEPTION_STUB(133) +DEFINE_EXCEPTION_STUB(134) +DEFINE_EXCEPTION_STUB(135) +DEFINE_EXCEPTION_STUB(136) +DEFINE_EXCEPTION_STUB(137) +DEFINE_EXCEPTION_STUB(138) +DEFINE_EXCEPTION_STUB(139) +DEFINE_EXCEPTION_STUB(140) +DEFINE_EXCEPTION_STUB(141) +DEFINE_EXCEPTION_STUB(142) +DEFINE_EXCEPTION_STUB(143) +DEFINE_EXCEPTION_STUB(144) +DEFINE_EXCEPTION_STUB(145) +DEFINE_EXCEPTION_STUB(146) +DEFINE_EXCEPTION_STUB(147) +DEFINE_EXCEPTION_STUB(148) +DEFINE_EXCEPTION_STUB(149) +DEFINE_EXCEPTION_STUB(150) +DEFINE_EXCEPTION_STUB(151) +DEFINE_EXCEPTION_STUB(152) +DEFINE_EXCEPTION_STUB(153) +DEFINE_EXCEPTION_STUB(154) +DEFINE_EXCEPTION_STUB(155) +DEFINE_EXCEPTION_STUB(156) +DEFINE_EXCEPTION_STUB(157) +DEFINE_EXCEPTION_STUB(158) +DEFINE_EXCEPTION_STUB(159) +DEFINE_EXCEPTION_STUB(160) +DEFINE_EXCEPTION_STUB(161) +DEFINE_EXCEPTION_STUB(162) +DEFINE_EXCEPTION_STUB(163) +DEFINE_EXCEPTION_STUB(164) +DEFINE_EXCEPTION_STUB(165) +DEFINE_EXCEPTION_STUB(166) +DEFINE_EXCEPTION_STUB(167) +DEFINE_EXCEPTION_STUB(168) +DEFINE_EXCEPTION_STUB(169) +DEFINE_EXCEPTION_STUB(170) +DEFINE_EXCEPTION_STUB(171) +DEFINE_EXCEPTION_STUB(172) +DEFINE_EXCEPTION_STUB(173) +DEFINE_EXCEPTION_STUB(174) +DEFINE_EXCEPTION_STUB(175) +DEFINE_EXCEPTION_STUB(176) +DEFINE_EXCEPTION_STUB(177) +DEFINE_EXCEPTION_STUB(178) +DEFINE_EXCEPTION_STUB(179) +DEFINE_EXCEPTION_STUB(180) +DEFINE_EXCEPTION_STUB(181) +DEFINE_EXCEPTION_STUB(182) +DEFINE_EXCEPTION_STUB(183) +DEFINE_EXCEPTION_STUB(184) +DEFINE_EXCEPTION_STUB(185) +DEFINE_EXCEPTION_STUB(186) +DEFINE_EXCEPTION_STUB(187) +DEFINE_EXCEPTION_STUB(188) +DEFINE_EXCEPTION_STUB(189) +DEFINE_EXCEPTION_STUB(190) +DEFINE_EXCEPTION_STUB(191) +DEFINE_EXCEPTION_STUB(192) +DEFINE_EXCEPTION_STUB(193) +DEFINE_EXCEPTION_STUB(194) +DEFINE_EXCEPTION_STUB(195) +DEFINE_EXCEPTION_STUB(196) +DEFINE_EXCEPTION_STUB(197) +DEFINE_EXCEPTION_STUB(198) +DEFINE_EXCEPTION_STUB(199) +DEFINE_EXCEPTION_STUB(200) +DEFINE_EXCEPTION_STUB(201) +DEFINE_EXCEPTION_STUB(202) +DEFINE_EXCEPTION_STUB(203) +DEFINE_EXCEPTION_STUB(204) +DEFINE_EXCEPTION_STUB(205) +DEFINE_EXCEPTION_STUB(206) +DEFINE_EXCEPTION_STUB(207) +DEFINE_EXCEPTION_STUB(208) +DEFINE_EXCEPTION_STUB(209) +DEFINE_EXCEPTION_STUB(210) +DEFINE_EXCEPTION_STUB(211) +DEFINE_EXCEPTION_STUB(212) +DEFINE_EXCEPTION_STUB(213) +DEFINE_EXCEPTION_STUB(214) +DEFINE_EXCEPTION_STUB(215) +DEFINE_EXCEPTION_STUB(216) +DEFINE_EXCEPTION_STUB(217) +DEFINE_EXCEPTION_STUB(218) +DEFINE_EXCEPTION_STUB(219) +DEFINE_EXCEPTION_STUB(220) +DEFINE_EXCEPTION_STUB(221) +DEFINE_EXCEPTION_STUB(222) +DEFINE_EXCEPTION_STUB(223) +DEFINE_EXCEPTION_STUB(224) +DEFINE_EXCEPTION_STUB(225) +DEFINE_EXCEPTION_STUB(226) +DEFINE_EXCEPTION_STUB(227) +DEFINE_EXCEPTION_STUB(228) +DEFINE_EXCEPTION_STUB(229) +DEFINE_EXCEPTION_STUB(230) +DEFINE_EXCEPTION_STUB(231) +DEFINE_EXCEPTION_STUB(232) +DEFINE_EXCEPTION_STUB(233) +DEFINE_EXCEPTION_STUB(234) +DEFINE_EXCEPTION_STUB(235) +DEFINE_EXCEPTION_STUB(236) +DEFINE_EXCEPTION_STUB(237) +DEFINE_EXCEPTION_STUB(238) +DEFINE_EXCEPTION_STUB(239) +DEFINE_EXCEPTION_STUB(240) +DEFINE_EXCEPTION_STUB(241) +DEFINE_EXCEPTION_STUB(242) +DEFINE_EXCEPTION_STUB(243) +DEFINE_EXCEPTION_STUB(244) +DEFINE_EXCEPTION_STUB(245) +DEFINE_EXCEPTION_STUB(246) +DEFINE_EXCEPTION_STUB(247) +DEFINE_EXCEPTION_STUB(248) +DEFINE_EXCEPTION_STUB(249) +DEFINE_EXCEPTION_STUB(250) +DEFINE_EXCEPTION_STUB(251) +DEFINE_EXCEPTION_STUB(252) +DEFINE_EXCEPTION_STUB(253) +DEFINE_EXCEPTION_STUB(254) +DEFINE_EXCEPTION_STUB(255) diff --git a/src/kernel/interrupts.h b/src/kernel/interrupts.h index b788501..4d61873 100644 --- a/src/kernel/interrupts.h +++ b/src/kernel/interrupts.h @@ -10,6 +10,9 @@ struct __attribute__((packed)) interrupt_frame { uword_t ss; }; +/* + * Exceptions + * ==========*/ __attribute__((interrupt, noreturn)) void exception_handler_div_by_zero(struct interrupt_frame* frame); @@ -22,12 +25,318 @@ void exception_handler_double_fault(struct interrupt_frame* frame); __attribute__((interrupt, noreturn)) void exception_default(struct interrupt_frame* frame); +/** + * Interrupts + * ========== + */ __attribute__((interrupt, noreturn)) void interrupt_default(struct interrupt_frame* frame); __attribute__((interrupt)) void interrupt_handler_1(struct interrupt_frame* frame); -__attribute__((interrupt)) -void interrupt_handler_userspace_exit(struct interrupt_frame* frame); +/** + * IRQs + * ==== + */ +__attribute__((interrupt)) void irq_handler_0(struct interrupt_frame*); +__attribute__((interrupt)) void irq_handler_1(struct interrupt_frame*); +__attribute__((interrupt)) void irq_handler_2(struct interrupt_frame*); +__attribute__((interrupt)) void irq_handler_3(struct interrupt_frame*); +__attribute__((interrupt)) void irq_handler_4(struct interrupt_frame*); +__attribute__((interrupt)) void irq_handler_5(struct interrupt_frame*); +__attribute__((interrupt)) void irq_handler_6(struct interrupt_frame*); +__attribute__((interrupt)) void irq_handler_7(struct interrupt_frame*); +__attribute__((interrupt)) void irq_handler_8(struct interrupt_frame*); +__attribute__((interrupt)) void irq_handler_9(struct interrupt_frame*); +__attribute__((interrupt)) void irq_handler_10(struct interrupt_frame*); +__attribute__((interrupt)) void irq_handler_11(struct interrupt_frame*); +__attribute__((interrupt)) void irq_handler_12(struct interrupt_frame*); +__attribute__((interrupt)) void irq_handler_13(struct interrupt_frame*); +__attribute__((interrupt)) void irq_handler_14(struct interrupt_frame*); +__attribute__((interrupt)) void irq_handler_15(struct interrupt_frame*); + +/* + * Exception and interrupt stubs + * ============================= + * Everything below this line is a horrible compile time crime. + * */ + + +#include "idt.h" +#include "kernel_state.h" + +/* This function is a horrible crime */ +static void idt_init_stubs(struct idt_gate_descriptor idt[]) { + #define EXCEPTION_STUB(n) exception_stub_##n + + #define DESC(func) \ + idt_encode_descriptor( \ + func, \ + segment(SEGMENT_KERNEL_CODE, SEGMENT_GDT, 0), \ + IDT_DPL_3, \ + IDT_GATE_TYPE_TRAP32) + + #define DECLARE_EXCEPTION_STUB(n) \ + __attribute__((interrupt)) void EXCEPTION_STUB(n)(struct interrupt_frame*); \ + idt[n] = DESC(EXCEPTION_STUB(n)) + DECLARE_EXCEPTION_STUB(0); + DECLARE_EXCEPTION_STUB(1); + DECLARE_EXCEPTION_STUB(2); + DECLARE_EXCEPTION_STUB(3); + DECLARE_EXCEPTION_STUB(4); + DECLARE_EXCEPTION_STUB(5); + DECLARE_EXCEPTION_STUB(6); + DECLARE_EXCEPTION_STUB(7); + DECLARE_EXCEPTION_STUB(8); + DECLARE_EXCEPTION_STUB(9); + DECLARE_EXCEPTION_STUB(10); + DECLARE_EXCEPTION_STUB(11); + DECLARE_EXCEPTION_STUB(12); + DECLARE_EXCEPTION_STUB(13); + DECLARE_EXCEPTION_STUB(14); + DECLARE_EXCEPTION_STUB(15); + DECLARE_EXCEPTION_STUB(16); + DECLARE_EXCEPTION_STUB(17); + DECLARE_EXCEPTION_STUB(18); + DECLARE_EXCEPTION_STUB(19); + DECLARE_EXCEPTION_STUB(20); + DECLARE_EXCEPTION_STUB(21); + DECLARE_EXCEPTION_STUB(22); + DECLARE_EXCEPTION_STUB(23); + DECLARE_EXCEPTION_STUB(24); + DECLARE_EXCEPTION_STUB(25); + DECLARE_EXCEPTION_STUB(26); + DECLARE_EXCEPTION_STUB(27); + DECLARE_EXCEPTION_STUB(28); + DECLARE_EXCEPTION_STUB(29); + DECLARE_EXCEPTION_STUB(30); + DECLARE_EXCEPTION_STUB(31); + DECLARE_EXCEPTION_STUB(32); + DECLARE_EXCEPTION_STUB(33); + DECLARE_EXCEPTION_STUB(34); + DECLARE_EXCEPTION_STUB(35); + DECLARE_EXCEPTION_STUB(36); + DECLARE_EXCEPTION_STUB(37); + DECLARE_EXCEPTION_STUB(38); + DECLARE_EXCEPTION_STUB(39); + DECLARE_EXCEPTION_STUB(40); + DECLARE_EXCEPTION_STUB(41); + DECLARE_EXCEPTION_STUB(42); + DECLARE_EXCEPTION_STUB(43); + DECLARE_EXCEPTION_STUB(44); + DECLARE_EXCEPTION_STUB(45); + DECLARE_EXCEPTION_STUB(46); + DECLARE_EXCEPTION_STUB(47); + DECLARE_EXCEPTION_STUB(48); + DECLARE_EXCEPTION_STUB(49); + DECLARE_EXCEPTION_STUB(50); + DECLARE_EXCEPTION_STUB(51); + DECLARE_EXCEPTION_STUB(52); + DECLARE_EXCEPTION_STUB(53); + DECLARE_EXCEPTION_STUB(54); + DECLARE_EXCEPTION_STUB(55); + DECLARE_EXCEPTION_STUB(56); + DECLARE_EXCEPTION_STUB(57); + DECLARE_EXCEPTION_STUB(58); + DECLARE_EXCEPTION_STUB(59); + DECLARE_EXCEPTION_STUB(60); + DECLARE_EXCEPTION_STUB(61); + DECLARE_EXCEPTION_STUB(62); + DECLARE_EXCEPTION_STUB(63); + DECLARE_EXCEPTION_STUB(64); + DECLARE_EXCEPTION_STUB(65); + DECLARE_EXCEPTION_STUB(66); + DECLARE_EXCEPTION_STUB(67); + DECLARE_EXCEPTION_STUB(68); + DECLARE_EXCEPTION_STUB(69); + DECLARE_EXCEPTION_STUB(70); + DECLARE_EXCEPTION_STUB(71); + DECLARE_EXCEPTION_STUB(72); + DECLARE_EXCEPTION_STUB(73); + DECLARE_EXCEPTION_STUB(74); + DECLARE_EXCEPTION_STUB(75); + DECLARE_EXCEPTION_STUB(76); + DECLARE_EXCEPTION_STUB(77); + DECLARE_EXCEPTION_STUB(78); + DECLARE_EXCEPTION_STUB(79); + DECLARE_EXCEPTION_STUB(80); + DECLARE_EXCEPTION_STUB(81); + DECLARE_EXCEPTION_STUB(82); + DECLARE_EXCEPTION_STUB(83); + DECLARE_EXCEPTION_STUB(84); + DECLARE_EXCEPTION_STUB(85); + DECLARE_EXCEPTION_STUB(86); + DECLARE_EXCEPTION_STUB(87); + DECLARE_EXCEPTION_STUB(88); + DECLARE_EXCEPTION_STUB(89); + DECLARE_EXCEPTION_STUB(90); + DECLARE_EXCEPTION_STUB(91); + DECLARE_EXCEPTION_STUB(92); + DECLARE_EXCEPTION_STUB(93); + DECLARE_EXCEPTION_STUB(94); + DECLARE_EXCEPTION_STUB(95); + DECLARE_EXCEPTION_STUB(96); + DECLARE_EXCEPTION_STUB(97); + DECLARE_EXCEPTION_STUB(98); + DECLARE_EXCEPTION_STUB(99); + DECLARE_EXCEPTION_STUB(100); + DECLARE_EXCEPTION_STUB(101); + DECLARE_EXCEPTION_STUB(102); + DECLARE_EXCEPTION_STUB(103); + DECLARE_EXCEPTION_STUB(104); + DECLARE_EXCEPTION_STUB(105); + DECLARE_EXCEPTION_STUB(106); + DECLARE_EXCEPTION_STUB(107); + DECLARE_EXCEPTION_STUB(108); + DECLARE_EXCEPTION_STUB(109); + DECLARE_EXCEPTION_STUB(110); + DECLARE_EXCEPTION_STUB(111); + DECLARE_EXCEPTION_STUB(112); + DECLARE_EXCEPTION_STUB(113); + DECLARE_EXCEPTION_STUB(114); + DECLARE_EXCEPTION_STUB(115); + DECLARE_EXCEPTION_STUB(116); + DECLARE_EXCEPTION_STUB(117); + DECLARE_EXCEPTION_STUB(118); + DECLARE_EXCEPTION_STUB(119); + DECLARE_EXCEPTION_STUB(120); + DECLARE_EXCEPTION_STUB(121); + DECLARE_EXCEPTION_STUB(122); + DECLARE_EXCEPTION_STUB(123); + DECLARE_EXCEPTION_STUB(124); + DECLARE_EXCEPTION_STUB(125); + DECLARE_EXCEPTION_STUB(126); + DECLARE_EXCEPTION_STUB(127); + DECLARE_EXCEPTION_STUB(128); + DECLARE_EXCEPTION_STUB(129); + DECLARE_EXCEPTION_STUB(130); + DECLARE_EXCEPTION_STUB(131); + DECLARE_EXCEPTION_STUB(132); + DECLARE_EXCEPTION_STUB(133); + DECLARE_EXCEPTION_STUB(134); + DECLARE_EXCEPTION_STUB(135); + DECLARE_EXCEPTION_STUB(136); + DECLARE_EXCEPTION_STUB(137); + DECLARE_EXCEPTION_STUB(138); + DECLARE_EXCEPTION_STUB(139); + DECLARE_EXCEPTION_STUB(140); + DECLARE_EXCEPTION_STUB(141); + DECLARE_EXCEPTION_STUB(142); + DECLARE_EXCEPTION_STUB(143); + DECLARE_EXCEPTION_STUB(144); + DECLARE_EXCEPTION_STUB(145); + DECLARE_EXCEPTION_STUB(146); + DECLARE_EXCEPTION_STUB(147); + DECLARE_EXCEPTION_STUB(148); + DECLARE_EXCEPTION_STUB(149); + DECLARE_EXCEPTION_STUB(150); + DECLARE_EXCEPTION_STUB(151); + DECLARE_EXCEPTION_STUB(152); + DECLARE_EXCEPTION_STUB(153); + DECLARE_EXCEPTION_STUB(154); + DECLARE_EXCEPTION_STUB(155); + DECLARE_EXCEPTION_STUB(156); + DECLARE_EXCEPTION_STUB(157); + DECLARE_EXCEPTION_STUB(158); + DECLARE_EXCEPTION_STUB(159); + DECLARE_EXCEPTION_STUB(160); + DECLARE_EXCEPTION_STUB(161); + DECLARE_EXCEPTION_STUB(162); + DECLARE_EXCEPTION_STUB(163); + DECLARE_EXCEPTION_STUB(164); + DECLARE_EXCEPTION_STUB(165); + DECLARE_EXCEPTION_STUB(166); + DECLARE_EXCEPTION_STUB(167); + DECLARE_EXCEPTION_STUB(168); + DECLARE_EXCEPTION_STUB(169); + DECLARE_EXCEPTION_STUB(170); + DECLARE_EXCEPTION_STUB(171); + DECLARE_EXCEPTION_STUB(172); + DECLARE_EXCEPTION_STUB(173); + DECLARE_EXCEPTION_STUB(174); + DECLARE_EXCEPTION_STUB(175); + DECLARE_EXCEPTION_STUB(176); + DECLARE_EXCEPTION_STUB(177); + DECLARE_EXCEPTION_STUB(178); + DECLARE_EXCEPTION_STUB(179); + DECLARE_EXCEPTION_STUB(180); + DECLARE_EXCEPTION_STUB(181); + DECLARE_EXCEPTION_STUB(182); + DECLARE_EXCEPTION_STUB(183); + DECLARE_EXCEPTION_STUB(184); + DECLARE_EXCEPTION_STUB(185); + DECLARE_EXCEPTION_STUB(186); + DECLARE_EXCEPTION_STUB(187); + DECLARE_EXCEPTION_STUB(188); + DECLARE_EXCEPTION_STUB(189); + DECLARE_EXCEPTION_STUB(190); + DECLARE_EXCEPTION_STUB(191); + DECLARE_EXCEPTION_STUB(192); + DECLARE_EXCEPTION_STUB(193); + DECLARE_EXCEPTION_STUB(194); + DECLARE_EXCEPTION_STUB(195); + DECLARE_EXCEPTION_STUB(196); + DECLARE_EXCEPTION_STUB(197); + DECLARE_EXCEPTION_STUB(198); + DECLARE_EXCEPTION_STUB(199); + DECLARE_EXCEPTION_STUB(200); + DECLARE_EXCEPTION_STUB(201); + DECLARE_EXCEPTION_STUB(202); + DECLARE_EXCEPTION_STUB(203); + DECLARE_EXCEPTION_STUB(204); + DECLARE_EXCEPTION_STUB(205); + DECLARE_EXCEPTION_STUB(206); + DECLARE_EXCEPTION_STUB(207); + DECLARE_EXCEPTION_STUB(208); + DECLARE_EXCEPTION_STUB(209); + DECLARE_EXCEPTION_STUB(210); + DECLARE_EXCEPTION_STUB(211); + DECLARE_EXCEPTION_STUB(212); + DECLARE_EXCEPTION_STUB(213); + DECLARE_EXCEPTION_STUB(214); + DECLARE_EXCEPTION_STUB(215); + DECLARE_EXCEPTION_STUB(216); + DECLARE_EXCEPTION_STUB(217); + DECLARE_EXCEPTION_STUB(218); + DECLARE_EXCEPTION_STUB(219); + DECLARE_EXCEPTION_STUB(220); + DECLARE_EXCEPTION_STUB(221); + DECLARE_EXCEPTION_STUB(222); + DECLARE_EXCEPTION_STUB(223); + DECLARE_EXCEPTION_STUB(224); + DECLARE_EXCEPTION_STUB(225); + DECLARE_EXCEPTION_STUB(226); + DECLARE_EXCEPTION_STUB(227); + DECLARE_EXCEPTION_STUB(228); + DECLARE_EXCEPTION_STUB(229); + DECLARE_EXCEPTION_STUB(230); + DECLARE_EXCEPTION_STUB(231); + DECLARE_EXCEPTION_STUB(232); + DECLARE_EXCEPTION_STUB(233); + DECLARE_EXCEPTION_STUB(234); + DECLARE_EXCEPTION_STUB(235); + DECLARE_EXCEPTION_STUB(236); + DECLARE_EXCEPTION_STUB(237); + DECLARE_EXCEPTION_STUB(238); + DECLARE_EXCEPTION_STUB(239); + DECLARE_EXCEPTION_STUB(240); + DECLARE_EXCEPTION_STUB(241); + DECLARE_EXCEPTION_STUB(242); + DECLARE_EXCEPTION_STUB(243); + DECLARE_EXCEPTION_STUB(244); + DECLARE_EXCEPTION_STUB(245); + DECLARE_EXCEPTION_STUB(246); + DECLARE_EXCEPTION_STUB(247); + DECLARE_EXCEPTION_STUB(248); + DECLARE_EXCEPTION_STUB(249); + DECLARE_EXCEPTION_STUB(250); + DECLARE_EXCEPTION_STUB(251); + DECLARE_EXCEPTION_STUB(252); + DECLARE_EXCEPTION_STUB(253); + DECLARE_EXCEPTION_STUB(254); + DECLARE_EXCEPTION_STUB(255); + #undef DESC + #undef DECLARE_EXCEPTION_STUB +} diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 683b4d0..8cbbdd7 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -8,29 +8,17 @@ #include "interrupts.h" #include "types.h" #include "kernel_state.h" +#include "pic.h" // Future user-space #include "libc.h" #include "tty.h" #include "str.h" -static void pic_disable() -{ - __asm__ volatile ("outb %0, %1" - : - : "a"((uint8_t)0xff), "Nd"((uint16_t)0x21) - : "memory"); - __asm__ volatile ("outb %0, %1" - : - : "a"((uint8_t)0xff), "Nd"((uint16_t)0xA1) - : "memory"); -} - static void user_mode_code(void*) { printf(str_attach("hello from user-space before interrupt :)\n")); - __asm__ volatile ("int $0x80"); - __asm__ volatile ("int $0x81"); + //__asm__ volatile ("int $0x80"); //while (1) /* busy loop */; #if 0 @@ -82,8 +70,9 @@ void kernel_main(void) { __asm__ volatile("cli"); - _Static_assert(sizeof(kernel.gdt) == 0x30); + /* Set up the GDT + * ============== */ kernel.gdt[SEGMENT_NULL] = gdt_encode_entry((struct gdt_entry_content){0}); /* kernel */ @@ -140,86 +129,80 @@ void kernel_main(void) | GDT_ACCESS_PRESENT, .flags = 0}); - /* Setup the TSS */ - memset(&kernel.tss, 0, sizeof kernel.tss); - kernel.tss.ss0 = segment(SEGMENT_KERNEL_DATA, SEGMENT_GDT, 0); -#if 1 - static uint8_t kernel_stack[1024]; - kernel.tss.esp0 = (uint32_t)kernel_stack; -#else - kernel.tss.esp0 = 0; -#endif - -#if 1 - /* Setup the IDT */ - for (size_t i = 0; i < 32; i++) { - kernel.idt[i] = idt_encode_descriptor( - exception_default, - segment(SEGMENT_KERNEL_CODE, SEGMENT_GDT, 0), - IDT_DPL_3, - IDT_GATE_TYPE_TRAP32); - } - for (size_t i = 32; i < IDT_COUNT; i++) { - kernel.idt[i] = idt_encode_descriptor( - interrupt_default, - segment(SEGMENT_KERNEL_CODE, SEGMENT_GDT, 0), - IDT_DPL_3, - IDT_GATE_TYPE_INTERRUPT32); - } - - kernel.idt[0x0] = idt_encode_descriptor( - exception_handler_div_by_zero, - segment(SEGMENT_KERNEL_CODE, SEGMENT_GDT, 0), - IDT_DPL_3, - IDT_GATE_TYPE_TRAP32 - ); - - kernel.idt[0x8] = idt_encode_descriptor( - exception_handler_double_fault, - segment(SEGMENT_KERNEL_CODE, SEGMENT_GDT, 0), - IDT_DPL_3, - IDT_GATE_TYPE_TRAP32 - ); - - kernel.idt[0xD] = idt_encode_descriptor( - exception_handler_general_protection_fault, - segment(SEGMENT_KERNEL_CODE, SEGMENT_GDT, 0), - IDT_DPL_3, - IDT_GATE_TYPE_TRAP32 - ); - - // Interrupts - kernel.idt[0x80] = idt_encode_descriptor( - interrupt_handler_1, - segment(SEGMENT_KERNEL_CODE, SEGMENT_GDT, 0), - IDT_DPL_3, - IDT_GATE_TYPE_INTERRUPT32 - ); - - kernel.idt[0x81] = idt_encode_descriptor( - interrupt_handler_userspace_exit, - segment(SEGMENT_KERNEL_CODE, SEGMENT_GDT, 0), - IDT_DPL_3, - IDT_GATE_TYPE_INTERRUPT32 - ); -#endif - - /* Flush the gdt and tss */ gdt_load(kernel.gdt, sizeof kernel.gdt, segment(SEGMENT_KERNEL_DATA, SEGMENT_GDT, 0), segment(SEGMENT_KERNEL_CODE, SEGMENT_GDT, 0)); + + /* + * Setup the TSS + * ============= */ + static uint8_t kernel_stack[KERNEL_STACK_SIZE]; + kernel.tss.ss0 = segment(SEGMENT_KERNEL_DATA, SEGMENT_GDT, 0); + kernel.tss.esp0 = (uint32_t)kernel_stack; tss_load(segment(SEGMENT_TASK_STATE, SEGMENT_GDT, 0)); + + /** + * Setup the IDT + * ============= */ +#define m_idt_default(func, type) \ + idt_encode_descriptor( \ + func, \ + segment(SEGMENT_KERNEL_CODE, SEGMENT_GDT, 0), \ + IDT_DPL_3, \ + type) + +#define mtrap(func) m_idt_default(func, IDT_GATE_TYPE_TRAP32); +#define mint(func) m_idt_default(func, IDT_GATE_TYPE_INTERRUPT32); + + idt_init_stubs(kernel.idt); + + /* Exceptions */ + kernel.idt[IDT_DESC_EXCEPTION_DIVISION_ERROR] = mtrap(exception_handler_div_by_zero); + kernel.idt[IDT_DESC_EXCEPTION_DOUBLE_FAULT] = mtrap(exception_handler_double_fault); + kernel.idt[IDT_DESC_EXCEPTION_GENERAL_PROTECTION_FAULT] = mtrap(exception_handler_general_protection_fault); + + /* IRQs */ + kernel.idt[IDT_DESC_PIC1 + 0] = mint(irq_handler_0); + kernel.idt[IDT_DESC_PIC1 + 1] = mint(irq_handler_1); + kernel.idt[IDT_DESC_PIC1 + 2] = mint(irq_handler_2); + kernel.idt[IDT_DESC_PIC1 + 3] = mint(irq_handler_3); + kernel.idt[IDT_DESC_PIC1 + 4] = mint(irq_handler_4); + kernel.idt[IDT_DESC_PIC1 + 5] = mint(irq_handler_5); + kernel.idt[IDT_DESC_PIC1 + 6] = mint(irq_handler_6); + kernel.idt[IDT_DESC_PIC1 + 7] = mint(irq_handler_7); + + kernel.idt[IDT_DESC_PIC2 + 0] = mint(irq_handler_8); + kernel.idt[IDT_DESC_PIC2 + 1] = mint(irq_handler_9); + kernel.idt[IDT_DESC_PIC2 + 2] = mint(irq_handler_10); + kernel.idt[IDT_DESC_PIC2 + 3] = mint(irq_handler_11); + kernel.idt[IDT_DESC_PIC2 + 4] = mint(irq_handler_12); + kernel.idt[IDT_DESC_PIC2 + 5] = mint(irq_handler_13); + kernel.idt[IDT_DESC_PIC2 + 6] = mint(irq_handler_14); + kernel.idt[IDT_DESC_PIC2 + 7] = mint(irq_handler_15); + + /* Interrupts */ + kernel.idt[IDT_DESC_INTERRUPT_SYSCALL] = mint(interrupt_handler_1); +#undef mtrap +#undef mint +#undef m_idt_default + idt_load(kernel.idt, sizeof kernel.idt); + /** + * PIC setup + * ========= + */ + + //irq_set_mask(0xff); /* Disable all IRQs */ + pic8259_remap(IDT_DESC_PIC1, IDT_DESC_PIC2); + /* enable interrupts */ __asm__ volatile("sti"); - /* Finally go to ring 3 */ printf(str_attach("hello from kernel space!\n")); - pic_disable(); // temporary duct-tape - + /* Finally go to ring 3 */ ring3_mode(segment(SEGMENT_USER_DATA, SEGMENT_GDT, 3), segment(SEGMENT_USER_CODE, SEGMENT_GDT, 3), user_mode_code); diff --git a/src/kernel/kernel_state.c b/src/kernel/kernel_state.c index 4f7ecc7..0f58377 100644 --- a/src/kernel/kernel_state.c +++ b/src/kernel/kernel_state.c @@ -12,7 +12,34 @@ const struct str gdt_segment_index_str[SEGMENT_COUNT] = { [SEGMENT_TASK_STATE ] = str_attach("SEGMENT_TASK_STATE"), }; -const struct str idt_index_str[IDT_COUNT] = { +const struct str idt_desc_index_str[IDT_DESC_COUNT] = { + [IDT_DESC_EXCEPTION_DIVISION_ERROR ] = str_attach("IDT_DESC_EXCEPTION_DIVISION_ERROR"), + [IDT_DESC_EXCEPTION_DEBUG ] = str_attach("IDT_DESC_EXCEPTION_DEBUG"), + [IDT_DESC_EXCEPTION_NON_MASKABLE ] = str_attach("IDT_DESC_EXCEPTION_NON_MASKABLE"), + [IDT_DESC_EXCEPTION_BREAKPOINT ] = str_attach("IDT_DESC_EXCEPTION_BREAKPOINT"), + [IDT_DESC_EXCEPTION_OVERFLOW ] = str_attach("IDT_DESC_EXCEPTION_OVERFLOW"), + [IDT_DESC_EXCEPTION_BOUND_RANGE_EXCEEDED ] = str_attach("IDT_DESC_EXCEPTION_BOUND_RANGE_EXCEEDED"), + [IDT_DESC_EXCEPTION_INVALID_OPCODE ] = str_attach("IDT_DESC_EXCEPTION_INVALID_OPCODE"), + [IDT_DESC_EXCEPTION_DEVICE_NOT_AVAILABLE ] = str_attach("IDT_DESC_EXCEPTION_DEVICE_NOT_AVAILABLE"), + [IDT_DESC_EXCEPTION_DOUBLE_FAULT ] = str_attach("IDT_DESC_EXCEPTION_DOUBLE_FAULT"), + [IDT_DESC_EXCEPTION_COPROCESSOR_SEGMENT_OVERRUN] = str_attach("IDT_DESC_EXCEPTION_COPROCESSOR_SEGMENT_OVERRUN"), + [IDT_DESC_EXCEPTION_INVALID_TSS ] = str_attach("IDT_DESC_EXCEPTION_INVALID_TSS"), + [IDT_DESC_EXCEPTION_SEGMENT_NOT_PRESENT ] = str_attach("IDT_DESC_EXCEPTION_SEGMENT_NOT_PRESENT"), + [IDT_DESC_EXCEPTION_STACK_SEGMENTATION_FAULT ] = str_attach("IDT_DESC_EXCEPTION_STACK_SEGMENTATION_FAULT"), + [IDT_DESC_EXCEPTION_GENERAL_PROTECTION_FAULT ] = str_attach("IDT_DESC_EXCEPTION_GENERAL_PROTECTION_FAULT"), + [IDT_DESC_EXCEPTION_PAGE_FAULT ] = str_attach("IDT_DESC_EXCEPTION_PAGE_FAULT"), + [IDT_DESC_EXCEPTION_X87_FLOATING_POINT ] = str_attach("IDT_DESC_EXCEPTION_X87_FLOATING_POINT"), + [IDT_DESC_EXCEPTION_ALIGNMENT_CHECK ] = str_attach("IDT_DESC_EXCEPTION_ALIGNMENT_CHECK"), + [IDT_DESC_EXCEPTION_MACHINE_CHECK ] = str_attach("IDT_DESC_EXCEPTION_MACHINE_CHECK"), + [IDT_DESC_EXCEPTION_SIMD_FLOATING_POINT ] = str_attach("IDT_DESC_EXCEPTION_SIMD_FLOATING_POINT"), + [IDT_DESC_EXCEPTION_VIRTUALIZATION ] = str_attach("IDT_DESC_EXCEPTION_VIRTUALIZATION"), + [IDT_DESC_EXCEPTION_CONTROL_PROTECTION ] = str_attach("IDT_DESC_EXCEPTION_CONTROL_PROTECTION"), + [IDT_DESC_EXCEPTION_HYPERVISOR_INJECTION ] = str_attach("IDT_DESC_EXCEPTION_HYPERVISOR_INJECTION"), + [IDT_DESC_EXCEPTION_VMM_COMMUNICATION ] = str_attach("IDT_DESC_EXCEPTION_VMM_COMMUNICATION"), + [IDT_DESC_EXCEPTION_SECURITY ] = str_attach("IDT_DESC_EXCEPTION_SECURITY"), + [IDT_DESC_PIC1 ] = str_attach("IDT_DESC_IRQ_MASTER"), + [IDT_DESC_PIC2 ] = str_attach("IDT_DESC_IRQ_SLAVE"), + [IDT_DESC_INTERRUPT_SYSCALL ] = str_attach("IDT_DESC_INTERRUPT_SYSCALL"), }; struct kernel_state kernel = { 0 }; diff --git a/src/kernel/kernel_state.h b/src/kernel/kernel_state.h index c5013ae..57dae53 100644 --- a/src/kernel/kernel_state.h +++ b/src/kernel/kernel_state.h @@ -6,6 +6,9 @@ #include "idt.h" #include "gdt.h" +/* + * Constants for the GDT + * */ enum gdt_segment_index : size_t { SEGMENT_NULL, SEGMENT_KERNEL_CODE, @@ -17,18 +20,65 @@ enum gdt_segment_index : size_t { }; extern const struct str gdt_segment_index_str[SEGMENT_COUNT]; // reverse lookup enum -> str -enum idt_index : size_t { - IDT_COUNT = 256 +/** + * Constants for the TSS + */ +constexpr size_t KERNEL_STACK_SIZE = 1024; + +/* + * Constants for IDT descriptors + * */ +static constexpr size_t IDT_EXCEPTION_COUNT = 32; +static constexpr size_t IDT_IRQ_MASTER_COUNT = 8; +static constexpr size_t IDT_IRQ_SLAVE_COUNT = 8; + +enum idt_desc_index : size_t { + /* Exceptions */ + IDT_DESC_EXCEPTION_DIVISION_ERROR = 0, + IDT_DESC_EXCEPTION_DEBUG = 1, + IDT_DESC_EXCEPTION_NON_MASKABLE = 2, + IDT_DESC_EXCEPTION_BREAKPOINT = 3, + IDT_DESC_EXCEPTION_OVERFLOW = 4, + IDT_DESC_EXCEPTION_BOUND_RANGE_EXCEEDED = 5, + IDT_DESC_EXCEPTION_INVALID_OPCODE = 6, + IDT_DESC_EXCEPTION_DEVICE_NOT_AVAILABLE = 7, + IDT_DESC_EXCEPTION_DOUBLE_FAULT = 8, + IDT_DESC_EXCEPTION_COPROCESSOR_SEGMENT_OVERRUN = 9, + IDT_DESC_EXCEPTION_INVALID_TSS = 10, + IDT_DESC_EXCEPTION_SEGMENT_NOT_PRESENT = 11, + IDT_DESC_EXCEPTION_STACK_SEGMENTATION_FAULT = 12, + IDT_DESC_EXCEPTION_GENERAL_PROTECTION_FAULT = 13, + IDT_DESC_EXCEPTION_PAGE_FAULT = 14, + /* 15 is reserved */ + IDT_DESC_EXCEPTION_X87_FLOATING_POINT = 16, + IDT_DESC_EXCEPTION_ALIGNMENT_CHECK = 17, + IDT_DESC_EXCEPTION_MACHINE_CHECK = 18, + IDT_DESC_EXCEPTION_SIMD_FLOATING_POINT = 19, + IDT_DESC_EXCEPTION_VIRTUALIZATION = 20, + IDT_DESC_EXCEPTION_CONTROL_PROTECTION = 21, + /* 21 to 27 are reserved */ + IDT_DESC_EXCEPTION_HYPERVISOR_INJECTION = 28, + IDT_DESC_EXCEPTION_VMM_COMMUNICATION = 29, + IDT_DESC_EXCEPTION_SECURITY = 30, + /* 31 is reserved */ + + /* IRQ offsets */ + IDT_DESC_PIC1 = 32, + IDT_DESC_PIC2 = IDT_DESC_PIC1 + 8, + + IDT_DESC_INTERRUPT_SYSCALL = 128, + + IDT_DESC_COUNT = 256, }; -extern const struct str idt_index_str[IDT_COUNT]; // reverse lookup enum -> str - -constexpr size_t BACKTRACE_MAX = 256; +extern const struct str idt_desc_index_str[IDT_DESC_COUNT]; // reverse lookup enum -> str +/** + * The global kernel state object + */ struct kernel_state { struct tss tss; struct gdt_table_entry gdt[SEGMENT_COUNT]; - struct idt_gate_descriptor idt[IDT_COUNT]; + struct idt_gate_descriptor idt[IDT_DESC_COUNT]; int nested_exception_counter; }; - extern struct kernel_state kernel; diff --git a/src/kernel/pic.c b/src/kernel/pic.c new file mode 100644 index 0000000..7729370 --- /dev/null +++ b/src/kernel/pic.c @@ -0,0 +1,91 @@ + +#include "pic.h" + +void pic8259_remap(int offset1, int offset2) +{ + /* ICW1: restart PIC1 and PIC2 with + - icw4 + - cascade + - 8 bit interval + - edge triggered mode + */ + outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); + outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4); + + /* ICW2: Send new offsets */ + outb(PIC1_DATA, offset1); + outb(PIC2_DATA, offset2); + + /* ICW2 and ICW3: Setup cascading */ + outb(PIC1_DATA, 1<<2); /* tell master PIC that IR input 2 has a slave */ + outb(PIC2_DATA, 2); /* set ID of slave PIC */ + + /* ICW4: 8086/88 mode */ + outb(PIC1_DATA, ICW4_8086); + outb(PIC2_DATA, ICW4_8086); +} + +static inline void irq_set(enum pic8259_port port, uint8_t mask) +{ + outb(port, inb(port) | mask); +} + +static inline void irq_clear(enum pic8259_port port, uint8_t mask) +{ + outb(port, inb(port) & ~(mask)); +} + +void pic8259_set_irq_mask(uint16_t mask) +{ + const uint8_t pic1_mask = mask & 0xF; + mask >>= 8; + const uint8_t pic2_mask = mask & 0xF; + + if (pic1_mask) { + irq_set(PIC1_DATA, pic1_mask); + } + if (pic2_mask) { + irq_set(PIC2_DATA, pic2_mask); + } +} + +void pic8259_clear_irq_mask(uint16_t mask) +{ + const uint8_t pic1_mask = mask & 0xF; + mask >>= 8; + const uint8_t pic2_mask = mask & 0xF; + + if (pic1_mask) { + irq_clear(PIC1_DATA, pic1_mask); + } + if (pic2_mask) { + irq_clear(PIC2_DATA, pic2_mask); + } +} + +/** + * https://wiki.osdev.org/8259_PIC#ISR_and_IRR + * =========================================== + * */ +static uint16_t get_irq_reg(int ocw3) +{ + /* OCW3 to PIC CMD to get the register values. PIC2 is chained, and + represents IRQs 8-15. PIC1 is IRQs 0-7, with 2 being the chain */ + outb(PIC1_COMMAND, ocw3); + outb(PIC2_COMMAND, ocw3); + return (inb(PIC2_COMMAND) << 8) | inb(PIC1_COMMAND); +} + +/* Returns the combined value of the cascaded PICs irq request register */ +uint16_t pic8259_get_irr(void) +{ + return get_irq_reg(OCW3_READ_IRR); +} + +/* Returns the combined value of the cascaded PICs in-service register */ +uint16_t pic8259_get_isr(void) +{ + return get_irq_reg(OCW3_READ_ISR); +} + +/* =========================================== */ diff --git a/src/kernel/pic.h b/src/kernel/pic.h new file mode 100644 index 0000000..0f4ab7d --- /dev/null +++ b/src/kernel/pic.h @@ -0,0 +1,171 @@ +#pragma once + +#include +#include "str.h" + +enum pic8259_port : uint16_t { + PIC1_COMMAND = 0x20, + PIC1_DATA = 0x21, + + PIC2_COMMAND = 0xA0, + PIC2_DATA = 0xA1, + + PIC_KEYBOARD = 0x60, +}; + +static const struct str pic8259_port_str[] = { + [PIC1_COMMAND ] = str_attach("PIC1_COMMAND"), + [PIC1_DATA ] = str_attach("PIC1_DATA"), + [PIC2_COMMAND ] = str_attach("PIC2_COMMAND"), + [PIC2_DATA ] = str_attach("PIC2_DATA"), +}; + + +enum irq : uint16_t { + IRQ_SYSTEM_TIMER = 0, + IRQ_KEYBOARD_CONTROLLER = 1, + IRQ_SERIAL_COM2 = 3, + IRQ_SERIAL_COM1 = 4, + IRQ_LINE_PRINT_TERMINAL_2 = 5, + IRQ_FLOPPY_CONTROLLER = 6, + IRQ_LINE_PRINT_TERMINAL_1 = 7, + IRQ_RTC_TIMER = 8, + IRQ_ACPI = 9, + IRQ_MOUSE_CONTROLLER = 12, + IRQ_MATH_COPROCESSOR = 13, + IRQ_ATA_CHANNEL_1 = 14, + IRQ_ATA_CHANNEL_2 = 15, +}; + +static const struct str irq_str[] = { + [IRQ_SYSTEM_TIMER ] = str_attach("IRQ_SYSTEM_TIMER"), + [IRQ_KEYBOARD_CONTROLLER ] = str_attach("IRQ_KEYBOARD_CONTROLLER"), + [IRQ_SERIAL_COM2 ] = str_attach("IRQ_SERIAL_COM2"), + [IRQ_SERIAL_COM1 ] = str_attach("IRQ_SERIAL_COM1"), + [IRQ_LINE_PRINT_TERMINAL_2] = str_attach("IRQ_LINE_PRINT_TERMINAL_2"), + [IRQ_FLOPPY_CONTROLLER ] = str_attach("IRQ_FLOPPY_CONTROLLER"), + [IRQ_LINE_PRINT_TERMINAL_1] = str_attach("IRQ_LINE_PRINT_TERMINAL_1"), + [IRQ_RTC_TIMER ] = str_attach("IRQ_RTC_TIMER"), + [IRQ_ACPI ] = str_attach("IRQ_ACPI"), + [IRQ_MOUSE_CONTROLLER ] = str_attach("IRQ_MOUSE_CONTROLLER"), + [IRQ_MATH_COPROCESSOR ] = str_attach("IRQ_MATH_COPROCESSOR"), + [IRQ_ATA_CHANNEL_1 ] = str_attach("IRQ_ATA_CHANNEL_1"), + [IRQ_ATA_CHANNEL_2 ] = str_attach("IRQ_ATA_CHANNEL_2"), +}; + +/** + Initialization Command Words + ======================= + From the Intel manuals: + https://pdos.csail.mit.edu/6.828/2010/readings/hardware/8259A.pdf + https://web.archive.org/web/20240606163819/https://pdos.csail.mit.edu/6.828/2010/readings/hardware/8259A.pdf + + > Whenever a command is issued with A0 = 0 and D4 = 1, this is interpreted + > as Initialization Command Word 1 (ICW1) CW1 starts the intiitalization + > sequence during which the following automatically occur: + > a. The edge sense circuit is reset, which means that following + > initialization, an interrupt request (IR) input must make a + > low-to-high transistion to generate an interrupt. + > b. The Interrupt Mask Register is cleared. + > c. IR7 input is assigned priority 7. + > d. The slave mode address is set to 7. + > e. Special Mask Mode is cleared and Status Read is set to IRR + > f. If IC4 = 0, then all functions selected in ICW4 are set to zero. + > (Non-Buffered mode*, no Auto-EOI, MCS-80, 85 system). + > [*]: Master/Slave in ICW4 is only used in the buffered mode + */ +enum icw1 : uint8_t { + ICW1_ICW4 = 1<<0, /* 1: ICW4 Needed + 0: ICW4 Not needed */ + + ICW1_SINGLE = 1<<1, /* 1: Single + 0: Cascade mode */ + + ICW1_INTERVAL4 = 1<<2, /* Call Address Interval: + 1: interval of 4 + 0: interval of 8 */ + + ICW1_LEVEL = 1<<3, /* 1: Level triggered mode + 0: Edge triggered mode */ + + ICW1_INIT = 1<<4, /* Must be present */ +}; + +enum icw4 : uint8_t { + ICW4_8086 = 1<<0, /* 1: 8086/88 mode + 0: MCS-80/85 mode */ + + ICW4_AUTO = 1<<1, /* 1: Auto EOI + 0: Normal EOI */ + + ICW4_BUF1 = 0b11<<2, /* Buffered mode master */ + + ICW4_BUF2 = 0b10<<2, /* Buffered mode slave */ + + ICW4_SFNM = 1<<4, /* 1: Special fully nested mode + 0: Not special fully nested mode */ +}; + +/* OCW2 */ +enum ocw2_command : uint8_t { + OCW2_EOI = 1<<5, + OCW2_SPECIFIC = 1<<6, + OCW2_ROTATE = 1<<7, + + /* Determines the interrupt level acted upon when the specific flag is set */ + OCW2_IR_LEVEL_0 = 0, + OCW2_IR_LEVEL_1 = 1, + OCW2_IR_LEVEL_2 = 2, + OCW2_IR_LEVEL_3 = 3, + OCW2_IR_LEVEL_4 = 4, + OCW2_IR_LEVEL_5 = 5, + OCW2_IR_LEVEL_6 = 6, + OCW2_IR_LEVEL_7 = 7, +}; + +/* OCW3 */ +enum ocw3_bits : uint8_t { + OCW3_BIT_RIS = (1<<0), + OCW3_BIT_RR = (1<<1), + OCW3_BIT_P = (1<<2), + /* bit 3 and 4 must be 0b01 for OCW3 to be selected */ + OCW3_BIT_SMM = (1<<5), + OCW3_BIT_ESMM = (1<<6), +}; + +enum ocw3_command : uint8_t { + OCW3_READ_ISR = (1<<3) | OCW3_BIT_RR | OCW3_BIT_RIS, + OCW3_READ_IRR = (1<<3) | OCW3_BIT_RR, + OCW3_POLL = (1<<3) | OCW3_BIT_P, + OCW3_RESET_SPECIAL_MASK = (1<<3) | OCW3_BIT_SMM, + OCW3_SET_SPECIAL_MASK = (1<<3) | OCW3_BIT_ESMM | OCW3_BIT_SMM, +}; + +static inline void outb(uint16_t port, uint8_t signal) +{ + __asm__ volatile ("outb %[signal], %[port]" + : + : [signal] "a" (signal), + [port] "Nd" (port) + : "memory"); +#ifdef ADD_IO_WAIT + /* do an I/O operation on an unused port to wait 1-4 microseconds */ + outb(0x80, 0); +#endif +} + +static inline uint8_t inb(uint16_t port) +{ + uint8_t ret; + __asm__ volatile ( "inb %w1, %b0" + : "=a"(ret) + : "Nd"(port) + : "memory"); + return ret; +} + +void pic8259_remap(int offset1, int offset2); + +void pic8259_set_irq_mask(uint16_t mask); + +void pic8259_clear_irq_mask(uint16_t mask); diff --git a/src/lib/printf.c b/src/lib/printf.c index 2a54101..eddc791 100644 --- a/src/lib/printf.c +++ b/src/lib/printf.c @@ -77,7 +77,7 @@ static int print_i32(struct printf_state* s, int padding, char pad_char) { padding = padding ? padding : 0; pad_char = pad_char ? pad_char : ' '; - long n = va_arg(s->ap, int32_t); + uint32_t n = va_arg(s->ap, int32_t); return print_long(n, str_attach("0123456789"), true, padding, pad_char); } @@ -85,7 +85,7 @@ static int print_u32(struct printf_state* s, int padding, char pad_char) { padding = padding ? padding : 0; pad_char = pad_char ? pad_char : ' '; - unsigned long n = va_arg(s->ap, uint32_t); + uint32_t n = va_arg(s->ap, uint32_t); return print_long(n, str_attach("0123456789"), false, padding, pad_char); } @@ -93,7 +93,7 @@ static int print_x32(struct printf_state* s, int padding, char pad_char) { padding = padding ? padding : 0; pad_char = pad_char ? pad_char : '0'; - unsigned long n = va_arg(s->ap, uint32_t); + uint32_t n = va_arg(s->ap, uint32_t); struct str alphabet = str_attach("0123456789abcdef"); return print_long(n, alphabet, false, padding, pad_char); } @@ -102,7 +102,7 @@ static int print_b32(struct printf_state* s, int padding, char pad_char) { padding = padding ? padding : 32; pad_char = pad_char ? pad_char : '0'; - unsigned long n = va_arg(s->ap, uint32_t); + uint32_t n = va_arg(s->ap, uint32_t); struct str alphabet = str_attach("01"); return print_long(n, alphabet, false, padding, pad_char); } @@ -119,7 +119,19 @@ static int print_str(struct printf_state* s, int padding, char pad_char) return str.len; } -#pragma GCC diagnostic ignored "-Wmultichar" +static int print_char(struct printf_state* s) +{ + // char is promoted to int when passed through va_arg + const int ch = va_arg(s->ap, int); + + if (ch >= 32 && ch < 127) { + terminal_putchar(ch); + return 1; + } else { + return print_long(ch, str_attach("0123456789abcdef"), false, 0, 0); + } +} + static int parse_format_cmd(struct printf_state* s) { int c; @@ -137,16 +149,21 @@ static int parse_format_cmd(struct printf_state* s) if (c == EOF) return -1; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmultichar" switch (cmd) { // 16 bit types are promoted to 32 bit by va_arg(...) anyways + case 'int': case 'i16': case 'i32': return print_i32(s, pad, pad_char); + case 'uint': case 'u16': case 'u32': return print_u32(s, pad, pad_char); + case 'hex': case 'x16': case 'x32': return print_x32(s, pad, pad_char); @@ -154,9 +171,13 @@ static int parse_format_cmd(struct printf_state* s) case 'str': return print_str(s, pad, pad_char); + case 'char': + return print_char(s); + default: return -1; } +#pragma GCC diagnostic pop } int printf(struct str format, ...) diff --git a/src/lib/ring_buffer.c b/src/lib/ring_buffer.c new file mode 100644 index 0000000..82dbd60 --- /dev/null +++ b/src/lib/ring_buffer.c @@ -0,0 +1,35 @@ + +#include "ring_buffer.h" + +size_t ring_buffer_remaining(struct ring_buffer* q) +{ + return (RING_BUFFER_MAX - q->len) / q->entry_size; +} + +bool ring_buffer_push(struct ring_buffer* q, const void* data) +{ + if (q->len + q->entry_size > RING_BUFFER_MAX) { + return false; + } + q->len += q->entry_size; + for (size_t i = 0; i < q->entry_size; i++) { + q->data[q->tail] = ((uint8_t*)data)[i]; + q->tail += 1; + q->tail %= RING_BUFFER_MAX; + } + return true; +} + +bool ring_buffer_get(struct ring_buffer* q, void* out) +{ + if (q->len == 0) { + return false; + } + q->len -= q->entry_size; + for (size_t i = 0; i < q->entry_size; i++) { + ((uint8_t*)out)[i] = q->data[q->head]; + q->head += 1; + q->head %= RING_BUFFER_MAX; + } + return true; +} diff --git a/src/test/test_ring_buffer.c b/src/test/test_ring_buffer.c new file mode 100644 index 0000000..2468061 --- /dev/null +++ b/src/test/test_ring_buffer.c @@ -0,0 +1,176 @@ + +#include "ring_buffer.h" +#include +#include +#include +#include +#include + +struct myObj { + int32_t a; + int32_t b; +}; + +static int g_status = EXIT_SUCCESS; +static int test_no = 0; +static bool test_ongoing = false; + +#define test_begin(name) _test_begin(name, __LINE__) +static void _test_begin(const char* name, int line) +{ + (void)line; // unused for now + assert(!test_ongoing); + test_ongoing = true; + printf("\n#%i - %s:\n", test_no, name); + test_no += 1; +} + +static void test_ok(const char* format, ...) +{ + va_list ap; + va_start(ap, format); + printf("OK: "); + vprintf(format, ap); + printf("\n"); + va_end(ap); + test_ongoing = false; +} + +static void test_fail(const char* format, ...) +{ + va_list ap; + va_start(ap, format); + printf("FAIL: "); + vprintf(format, ap); + printf("\n"); + va_end(ap); + g_status = EXIT_FAILURE; + test_ongoing = false; +} + +int main() +{ + struct ring_buffer q = make_ring_buffer(struct myObj); + + test_begin("entry_size"); + { + if (q.entry_size != sizeof (struct myObj)) { + test_fail("wrong entry_size"); + } else { + test_ok("entry_size is %zu", q.entry_size); + } + } + + test_begin("ring_buffer_remaining"); + size_t max_items = ring_buffer_remaining(&q); // used later + { + if (max_items != RING_BUFFER_MAX / sizeof(struct myObj)) { + test_fail("unexpected ring_buffer_remaining()"); + } else { + test_ok("ring_buffer_remaining() is %zu", max_items); + } + } + + test_begin("ring_buffer_push"); + { + bool ok = true; + size_t remaining = ring_buffer_remaining(&q); + for (size_t i = 0; i < remaining; i++) { + if (ring_buffer_push(&q, &(struct myObj){i, i}) == false) { + ok = false; + break; + } + } + if (!ok) { + test_fail("expected ring_buffer push to work"); + } else { + test_ok("successfully pushed %zu times", remaining); + } + } + + test_begin("ring_buffer_push on full ring buffer"); + { + if (ring_buffer_push(&q, &(struct myObj){}) == true) { + test_fail("ring buffer should be full by now, ring_buffer_remaining is %zu", ring_buffer_remaining(&q)); + } else { + test_ok("correctly failed to push when ring buffer is full"); + } + } + + test_begin("ring_buffer_get"); + { + for (size_t i = 0; i < max_items; i++) { + struct myObj o; + bool ok = ring_buffer_get(&q, &o); + + if (!ok) { + test_fail("ring_buffer_get() didn't fetch when buffer had data"); + goto end_test; + } + + if (o.a != (int32_t)i + || o.b != (int32_t)i + ){ + test_fail("ring_buffer_get() retrived faulty data {%i, %i}", o.a, o.b); + goto end_test; + } + } + test_ok("ring_buffer_get() works"); + +end_test: + } + + test_begin("ring_buffer_get on empty ring buffer"); + { + struct myObj o; + bool ok = ring_buffer_get(&q, &o); + if (ok) { + test_fail("ring_buffer_get() on empty ring buffer succeeded, got {%i, %i}", o.a, o.b); + } else { + test_ok("ring_buffer_get() on empty ring buffer didn't succeed"); + } + } + + test_begin("stress test"); + { + struct ring_buffer rb = make_ring_buffer(struct myObj); + bool fail = false; + + for (volatile size_t i = 0; i < RING_BUFFER_MAX * 10; i++) { + bool ok; + struct myObj before = {i, i}; + struct myObj after = {-1, -1}; + + ok = ring_buffer_push(&rb, &before); + if (!ok) { + test_fail("failed to push during stress-test"); + fail = true; + break; + } + + ok = ring_buffer_get(&rb, &after); + if (!ok) { + test_fail("failed to get during stress-test"); + fail = true; + break; + } + + if (before.a != after.a || before.b != after.b) { + test_fail("data got damaged in queue"); + fail = true; + break; + } + } + if (!fail) { + test_ok("stress test succeeded"); + } + } + + if (g_status == EXIT_SUCCESS) { + printf("\nAll tests succeeded\n"); + } else { + printf("\nOne or more tests failed\n"); + } + + return g_status; +}