From 8f9b9cd8aac30572b7e275bbeb1b32d2cbb8950a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 16 Sep 2024 14:07:41 +0000 Subject: build: migrate away from conan --- .clang-format | 77 +++++ .devcontainer/x86-64/devcontainer.json | 11 + .vscode/settings.json | 2 +- CMakeLists.txt | 121 +++++++ CMakePresets.json | 26 ++ README.rst | 50 +-- arch/x86_64/CMakeLists.txt | 64 ++++ arch/x86_64/include/arch/boot/pointers.hpp | 11 + arch/x86_64/include/arch/io/port_io.hpp | 134 ++++++++ arch/x86_64/include/arch/kernel/main.hpp | 11 + arch/x86_64/include/arch/video/vga/io.hpp | 41 +++ arch/x86_64/include/arch/video/vga/text.hpp | 113 +++++++ arch/x86_64/scripts/kernel.ld | 139 ++++++++ arch/x86_64/src/boot/boot.s | 370 +++++++++++++++++++++ arch/x86_64/src/boot/crti.s | 13 + arch/x86_64/src/boot/crtn.s | 9 + arch/x86_64/src/boot/multiboot.s | 26 ++ arch/x86_64/src/kernel/main.cpp | 15 + arch/x86_64/src/video/vga/text.cpp | 47 +++ arch/x86_64/support/grub.cfg.in | 7 + cmake/Modules/FindSphinx.cmake | 10 + cmake/Modules/Findgrub-mkrescue.cmake | 10 + cmake/Platforms/x86_64.cmake | 35 ++ conanfile.py | 62 ---- include/memory/asm_pointer.hpp | 72 ++++ requirements.txt | 6 - source/.clang-format | 77 ----- source/CMakeLists.txt | 115 ------- source/arch/x86_64/CMakeLists.txt | 64 ---- source/arch/x86_64/include/arch/boot/pointers.hpp | 11 - source/arch/x86_64/include/arch/io/port_io.hpp | 134 -------- source/arch/x86_64/include/arch/kernel/main.hpp | 11 - source/arch/x86_64/include/arch/video/vga/io.hpp | 41 --- source/arch/x86_64/include/arch/video/vga/text.hpp | 113 ------- source/arch/x86_64/scripts/kernel.ld | 139 -------- source/arch/x86_64/src/boot/boot.s | 370 --------------------- source/arch/x86_64/src/boot/crti.s | 13 - source/arch/x86_64/src/boot/crtn.s | 9 - source/arch/x86_64/src/boot/multiboot.s | 26 -- source/arch/x86_64/src/kernel/main.cpp | 15 - source/arch/x86_64/src/video/vga/text.cpp | 47 --- source/arch/x86_64/support/grub.cfg.in | 7 - source/cmake/Modules/FindSphinx.cmake | 10 - source/cmake/Modules/Findgrub-mkrescue.cmake | 10 - source/cmake/Platforms/x86_64.cmake | 27 -- source/include/memory/asm_pointer.hpp | 72 ---- source/src/kernel/main.cpp | 3 - src/kernel/main.cpp | 3 + 48 files changed, 1370 insertions(+), 1429 deletions(-) create mode 100644 .clang-format create mode 100644 .devcontainer/x86-64/devcontainer.json create mode 100644 CMakeLists.txt create mode 100644 CMakePresets.json create mode 100644 arch/x86_64/CMakeLists.txt create mode 100644 arch/x86_64/include/arch/boot/pointers.hpp create mode 100644 arch/x86_64/include/arch/io/port_io.hpp create mode 100644 arch/x86_64/include/arch/kernel/main.hpp create mode 100644 arch/x86_64/include/arch/video/vga/io.hpp create mode 100644 arch/x86_64/include/arch/video/vga/text.hpp create mode 100644 arch/x86_64/scripts/kernel.ld create mode 100644 arch/x86_64/src/boot/boot.s create mode 100644 arch/x86_64/src/boot/crti.s create mode 100644 arch/x86_64/src/boot/crtn.s create mode 100644 arch/x86_64/src/boot/multiboot.s create mode 100644 arch/x86_64/src/kernel/main.cpp create mode 100644 arch/x86_64/src/video/vga/text.cpp create mode 100644 arch/x86_64/support/grub.cfg.in create mode 100644 cmake/Modules/FindSphinx.cmake create mode 100644 cmake/Modules/Findgrub-mkrescue.cmake create mode 100644 cmake/Platforms/x86_64.cmake delete mode 100644 conanfile.py create mode 100644 include/memory/asm_pointer.hpp delete mode 100644 requirements.txt delete mode 100644 source/.clang-format delete mode 100644 source/CMakeLists.txt delete mode 100644 source/arch/x86_64/CMakeLists.txt delete mode 100644 source/arch/x86_64/include/arch/boot/pointers.hpp delete mode 100644 source/arch/x86_64/include/arch/io/port_io.hpp delete mode 100644 source/arch/x86_64/include/arch/kernel/main.hpp delete mode 100644 source/arch/x86_64/include/arch/video/vga/io.hpp delete mode 100644 source/arch/x86_64/include/arch/video/vga/text.hpp delete mode 100644 source/arch/x86_64/scripts/kernel.ld delete mode 100644 source/arch/x86_64/src/boot/boot.s delete mode 100644 source/arch/x86_64/src/boot/crti.s delete mode 100644 source/arch/x86_64/src/boot/crtn.s delete mode 100644 source/arch/x86_64/src/boot/multiboot.s delete mode 100644 source/arch/x86_64/src/kernel/main.cpp delete mode 100644 source/arch/x86_64/src/video/vga/text.cpp delete mode 100644 source/arch/x86_64/support/grub.cfg.in delete mode 100644 source/cmake/Modules/FindSphinx.cmake delete mode 100644 source/cmake/Modules/Findgrub-mkrescue.cmake delete mode 100644 source/cmake/Platforms/x86_64.cmake delete mode 100644 source/include/memory/asm_pointer.hpp delete mode 100644 source/src/kernel/main.cpp create mode 100644 src/kernel/main.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..d4da962 --- /dev/null +++ b/.clang-format @@ -0,0 +1,77 @@ +--- +AccessModifierOffset: '-2' +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: 'false' +AlignConsecutiveDeclarations: 'false' +AlignEscapedNewlines: Left +AlignOperands: 'true' +AlignTrailingComments: 'true' +AllowAllParametersOfDeclarationOnNextLine: 'true' +AllowShortBlocksOnASingleLine: 'false' +AllowShortCaseLabelsOnASingleLine: 'false' +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: 'false' +AllowShortLoopsOnASingleLine: 'false' +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: 'true' +BinPackArguments: 'true' +BinPackParameters: 'true' +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: 'true' + AfterControlStatement: 'true' + AfterEnum: 'true' + AfterFunction: 'true' + AfterNamespace: 'true' + AfterStruct: 'true' + AfterUnion: 'true' + AfterExternBlock: 'true' + BeforeCatch: 'true' + BeforeElse: 'true' + IndentBraces: 'false' +BreakBeforeInheritanceComma: 'false' +BreakConstructorInitializers: BeforeComma +BreakStringLiterals: 'true' +ColumnLimit: '120' +CompactNamespaces: 'false' +Cpp11BracedListStyle: 'true' +DerivePointerAlignment: 'false' +FixNamespaceComments: 'true' +IncludeBlocks: Regroup +IncludeCategories: + # Local Headers + - Regex: '"(.*/?)+/.+\.hpp"' + Priority: 100 + # STL Headers + - Regex: '<[[:alnum:]._]+(?!\.(h|hpp))>' + Priority: 400 + # C Library Headers + - Regex: '<([[:alnum:]._]/*)+\.h>' + Priority: 300 +IndentCaseLabels: 'true' +IndentPPDirectives: None +IndentWidth: '2' +KeepEmptyLinesAtTheStartOfBlocks: 'false' +Language: Cpp +MaxEmptyLinesToKeep: '1' +NamespaceIndentation: All +PointerAlignment: Middle +ReflowComments: 'true' +SortIncludes: 'true' +SortUsingDeclarations: 'true' +SpaceAfterCStyleCast: 'false' +SpaceAfterTemplateKeyword: 'false' +SpaceBeforeAssignmentOperators: 'true' +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: 'false' +SpacesBeforeTrailingComments: '2' +SpacesInAngles: 'false' +SpacesInContainerLiterals: 'false' +SpacesInCStyleCastParentheses: 'false' +SpacesInParentheses: 'false' +SpacesInSquareBrackets: 'false' +Standard: Cpp11 +TabWidth: '2' +UseTab: Never +... diff --git a/.devcontainer/x86-64/devcontainer.json b/.devcontainer/x86-64/devcontainer.json new file mode 100644 index 0000000..3c88eae --- /dev/null +++ b/.devcontainer/x86-64/devcontainer.json @@ -0,0 +1,11 @@ +{ + "image": "registry.gitlab.ost.ch:45023/teachos/devcontainers/x86-64:14.2.0", + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cmake-tools", + "ms-vscode.cpptools" + ] + } + } +} diff --git a/.vscode/settings.json b/.vscode/settings.json index f7a4d59..21d4f5f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { - "cmake.sourceDirectory": "/home/sophia/Projects/os/teachos/kernel/source", "cmake.useCMakePresets": "always", + "cmake.options.statusBarVisibility": "visible", "C_Cpp.autoAddFileAssociations": false, "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..c51ffb9 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,121 @@ +cmake_minimum_required(VERSION "3.27") + +project("kernel" + DESCRIPTION "${TEACHOS_DESCRIPTION}" + HOMEPAGE_URL "${TEACHOS_HOMEPAGE_URL}" + VERSION "${TEACHOS_VERSION}" + LANGUAGES ASM C CXX +) + +#[============================================================================[ +# Global Build System Configuration +#]============================================================================] + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") +set(CMAKE_INTERPROCEDURAL_OPTIMIZATION YES) + +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/Modules") + +set(CMAKE_CXX_STANDARD "20") +set(CMAKE_CXX_STANDARD_REQUIRED YES) +set(CMAKE_CXX_EXTENSIONS NO) + +#[============================================================================[ +# Documentation +#]============================================================================] + +find_package("Doxygen") + +set(DOXYGEN_GENERATE_HTML NO) +set(DOXYGEN_GENERATE_XML YES) +set(DOXYGEN_EXCLUDE_PATTERNS "*.cpp") +set(DOXYGEN_OUTPUT_DIRECTORY "doxygen") +set(DOXYGEN_QUIET YES) + +file(GLOB_RECURSE DOXYGEN_SOURCES CONFIGURE_DEPENDS "*.hpp") + +message(STATUS "${SPHINX_SOURCES}") + +doxygen_add_docs("docs_xml" + ${DOXYGEN_SOURCES} + ALL + USE_STAMP_FILE + COMMENT "Generating developer documentation sources" +) + +set_target_properties("docs_xml" PROPERTIES + ADDITIONAL_CLEAN_FILES + "${PROJECT_BINARY_DIR}/doxygen" +) + +file(GLOB_RECURSE SPHINX_SOURCES CONFIGURE_DEPENDS "../docs/**.rst") + +add_custom_target("docs" ALL + COMMAND "${SPHINX_BUILD_EXE}" + "../docs" + "docs" + "-q" + DEPENDS "docs_xml" + SOURCES ${SPHINX_SOURCES} + COMMENT "Generating developer documentation html" +) + +set_target_properties("docs" PROPERTIES + ADDITIONAL_CLEAN_FILES + "${PROJECT_BINARY_DIR}/docs" +) + +#[============================================================================[ +# Global Compiler Configuration +#]============================================================================] + +add_compile_options( + "$<$:-Wall>" + "$<$:-Wextra>" + "$<$:-Werror>" + "$<$:-pedantic-errors>" +) + +#[============================================================================[ +# Global Directories +#]============================================================================] + +include_directories( + "include" + "arch/${CMAKE_SYSTEM_PROCESSOR}/include" +) + +#[============================================================================[ +# The Bootstrap Library +#]============================================================================] + +add_library("_boot" OBJECT) +add_library("teachos::boot" ALIAS "_boot") + +#[============================================================================[ +# The Video Library +#]============================================================================] + +add_library("_video" OBJECT) +add_library("teachos::video" ALIAS "_video") + +#[============================================================================[ +# The Kernel +#]============================================================================] + +add_executable("_kernel" + "src/kernel/main.cpp" +) +add_executable("teachos::kernel" ALIAS "_kernel") + +target_link_libraries("_kernel" PRIVATE + "teachos::boot" + "teachos::video" +) + +#[============================================================================[ +# Platform Specific Components +#]============================================================================] + +add_subdirectory("arch/${CMAKE_SYSTEM_PROCESSOR}") diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..ecac6fb --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,26 @@ +{ + "version": 6, + "configurePresets": [ + { + "name": "default", + "binaryDir": "${sourceDir}/build", + "generator": "Ninja Multi-Config", + "cacheVariables": { + "CMAKE_CONFIGURATION_TYPES": "Debug;MinSizeRel", + "CMAKE_TOOLCHAIN_FILE": "cmake/Platforms/x86_64.cmake" + } + } + ], + "buildPresets": [ + { + "name": "debug", + "configurePreset": "default", + "configuration": "Debug" + }, + { + "name": "release", + "configurePreset": "default", + "configuration": "MinSizeRel" + } + ] +} diff --git a/README.rst b/README.rst index c418cd8..fb994bd 100644 --- a/README.rst +++ b/README.rst @@ -11,59 +11,17 @@ Development Development happens primarily on Linux. Other platforms (e.g. Windows, macOS) may allow building of the kernel as well, however at the time of this writing they are not officially supported. -To manage the toolchain and dependencies of the kernel, conan is used as a package manager. Required Tools ~~~~~~~~~~~~~~ -In orer to build the kernel, the following tools are required: +In order to build the kernel, the following tools are required: -- Python 3 to run conan -- A C and C++ toolchain to build the kernel toolchain -- GRUB2 to build the bootable ISO image +- Docker to run the development container +- Visual Studio Code for development Setup ~~~~~ -Create an activate a Python virtual environment, for example by using the ``venv`` module: +Open this directory in Visual Studio Code and then reopen the project in the development container -.. code-block:: bash - - $ python -m venv .venv - $ source .venv/bin/activate - -With the virtual environment activated, install the required Python package from the ``requirements.txt`` file: - -.. code-block:: bash - - $ pip install -r requirements.txt - -Next, prepare the default conan profile and install the required packages (note: the example below assumes x86_64 is being targeted as the kernel's platform): - -.. code-block:: bash - - $ conan profile new --detect default - $ conan install -if .conan/install -pr:b default -pr:h .conan/profiles/x86_64-gcc -b missing - -The second command may need to be rerun in case the conan dependencies change. - -Building -~~~~~~~~ - -With the setup performed, the kernel can now be built: - -.. code-block:: bash - - $ conan build -if .conan/install . - -Developing in an IDE -~~~~~~~~~~~~~~~~~~~~ - -This repository includes a configuration for Visual Studio Code. -In order to work on the kernel from within Visual Studio Code, activation of the conan build environment is required: - -.. code-block:: bash - - $ source build/generators/conanbuild.sh - -Afterward the IDE can be started from the same shell and will automatically pick up the required environment variables. diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt new file mode 100644 index 0000000..6ff1332 --- /dev/null +++ b/arch/x86_64/CMakeLists.txt @@ -0,0 +1,64 @@ +#[============================================================================[ +# The Kernel Library +#]============================================================================] + +set(TEACHOS_KERNEL_LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/kernel.ld") +mark_as_advanced(TEACHOS_KERNEL_LINKER_SCRIPT) + +target_sources("_kernel" PRIVATE + "src/kernel/main.cpp" +) + +target_link_options("_kernel" PRIVATE + "-T${TEACHOS_KERNEL_LINKER_SCRIPT}" +) + +set_target_properties("_kernel" PROPERTIES + LINK_DEPENDS "${TEACHOS_KERNEL_LINKER_SCRIPT}" +) + +#[============================================================================[ +# The Bootstrap Library +#]============================================================================] + +target_sources("_boot" PRIVATE + "src/boot/boot.s" + "src/boot/crti.s" + "src/boot/crtn.s" + "src/boot/multiboot.s" +) + +#[============================================================================[ +# The Video Library +#]============================================================================] + +target_sources("_video" PRIVATE + "src/video/vga/text.cpp" +) + +#[============================================================================[ +# The Bootable ISO Image +#]============================================================================] + +find_package("grub-mkrescue") + +if(grub-mkrescue_FOUND) + file(GENERATE + OUTPUT "isofs/boot/grub/grub.cfg" + INPUT "support/grub.cfg.in" + ) + + add_custom_target("bootable-iso" + COMMAND "${GRUB_MKRESCUE_EXE}" + "-o" + "${PROJECT_BINARY_DIR}/teachos-$.iso" + "${CMAKE_CURRENT_BINARY_DIR}/isofs" + "$" + "2>/dev/null" + DEPENDS + "$" + "isofs/boot/grub/grub.cfg" + BYPRODUCTS "${PROJECT_BINARY_DIR}/teachos-$.iso" + COMMENT "Creating bootable ISO image" + ) +endif() diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp new file mode 100644 index 0000000..dcd14fe --- /dev/null +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -0,0 +1,11 @@ +#ifndef TEACHOS_ARCH_X86_64_BOOT_POINTERS_HPP +#define TEACHOS_ARCH_X86_64_BOOT_POINTERS_HPP + +#include + +namespace teachos::arch::boot +{ + extern "C" std::byte const multiboot_information_pointer; +} // namespace teachos::arch::boot + +#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/io/port_io.hpp b/arch/x86_64/include/arch/io/port_io.hpp new file mode 100644 index 0000000..5b61f90 --- /dev/null +++ b/arch/x86_64/include/arch/io/port_io.hpp @@ -0,0 +1,134 @@ +#ifndef TEACHOS_ARCH_X86_64_IO_PORT_IO_HPP +#define TEACHOS_ARCH_X86_64_IO_PORT_IO_HPP + +#include +#include +#include +#include + +namespace teachos::arch::io +{ + + /** + * @brief An I/O port of a given size at a given address. + * + * @tparam Address The address (port number) of the I/O port. + * @tparam Size The size (in bytes) of the I/O port. + */ + template + struct port + { + static_assert(Size == 1 || Size == 2 || Size == 4, "A port must be either 1, 2, or 4 bytes in size"); + + /** + * @brief The type of data available for reading and writing through this port. + */ + using io_type = + std::conditional_t>; + + /** + * @brief Write a byte to the I/O port. + * + * @param data The data to write to the I/O port. + */ + auto static write(io_type data) -> void + requires(Size == 1) + { + asm volatile("mov %[port], %%dx\n" + "mov %[data], %%al\n" + "out %%al, %%dx\n" + : + : [port] "i"(Address), [data] "im"(data) + : "dx", "al"); + } + + /** + * @brief Write a word to the I/O port. + * + * @param data The data to write to the I/O port. + */ + auto static write(io_type data) -> void + requires(Size == 2) + { + asm volatile("mov %[port], %%dx\n" + "mov %[data], %%ax\n" + "out %%ax, %%dx\n" + : + : [port] "i"(Address), [data] "im"(data) + : "dx", "ax"); + } + + /** + * @brief Write a double-word to the I/O port. + * + * @param data The data to write to the I/O port. + */ + auto static write(io_type data) -> void + requires(Size == 4) + { + asm volatile("mov %[port], %%dx\n" + "mov %[data], %%eax\n" + "out %%eax, %%dx\n" + : + : [port] "i"(Address), [data] "im"(data) + : "dx", "eax"); + } + + /** + * @brief Read a byte from the I/O port. + * + * @return The data read from the I/O port. + */ + auto static read() -> io_type + requires(Size == 1) + { + auto data = io_type{}; + asm volatile("mov %[port], %%dx\n" + "in %%dx, %%al\n" + "mov %%al, %[data]\n" + : [data] "=m"(data) + : [port] "i"(Address) + : "dx", "al"); + return data; + } + + /** + * @brief Read a word from the I/O port. + * + * @return The data read from the I/O port. + */ + auto static read() -> io_type + requires(Size == 2) + { + auto data = io_type{}; + asm volatile("mov %[port], %%dx\n" + "in %%dx, %%ax\n" + "mov %%ax, %[data]\n" + : [data] "=m"(data) + : [port] "i"(Address) + : "dx", "ax"); + return data; + } + + /** + * @brief Read a double-word from the I/O port. + * + * @return The data read from the I/O port. + */ + auto static read() -> io_type + requires(Size == 4) + { + auto data = io_type{}; + asm volatile("mov %[port], %%dx\n" + "in %%dx, %%eax\n" + "mov %%eax, %[data]\n" + : [data] "=m"(data) + : [port] "i"(Address) + : "dx", "eax"); + return data; + } + }; + +} // namespace teachos::arch::io + +#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/kernel/main.hpp b/arch/x86_64/include/arch/kernel/main.hpp new file mode 100644 index 0000000..6961594 --- /dev/null +++ b/arch/x86_64/include/arch/kernel/main.hpp @@ -0,0 +1,11 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_MAIN_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_MAIN_HPP + +#include + +namespace teachos::arch::kernel +{ + auto main() -> void; +} + +#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/video/vga/io.hpp b/arch/x86_64/include/arch/video/vga/io.hpp new file mode 100644 index 0000000..9226c5c --- /dev/null +++ b/arch/x86_64/include/arch/video/vga/io.hpp @@ -0,0 +1,41 @@ +#ifndef TEACHOS_ARCH_X86_64_VIDEO_VGA_IO_HPP +#define TEACHOS_ARCH_X86_64_VIDEO_VGA_IO_HPP + +#include "arch/io/port_io.hpp" + +#include + +namespace teachos::arch::video::vga +{ + + namespace crtc + { + + /** + * @brief The address port of the CRT Controller + */ + using address_port = arch::io::port<0x3d4, 1>; + + /** + * @brief The data port of the CRT Controller + */ + using data_port = arch::io::port<0x3d5, 1>; + + namespace registers + { + /** + * @brief The address of the Cursor Start register of the CRTC + */ + [[maybe_unused]] auto constexpr cursor_start = std::byte{0x0a}; + + /** + * @brief The address of the Cursor End register of the CRTC + */ + [[maybe_unused]] auto constexpr curser_end = std::byte{0x0b}; + } // namespace registers + + }; // namespace crtc + +} // namespace teachos::arch::video::vga + +#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/video/vga/text.hpp b/arch/x86_64/include/arch/video/vga/text.hpp new file mode 100644 index 0000000..1e584d6 --- /dev/null +++ b/arch/x86_64/include/arch/video/vga/text.hpp @@ -0,0 +1,113 @@ +#ifndef TEACHOS_ARCH_X86_64_VIDEO_VGA_TEXT_HPP +#define TEACHOS_ARCH_X86_64_VIDEO_VGA_TEXT_HPP + +#include +#include + +namespace teachos::arch::video::vga::text +{ + /** + * @brief The colors available in the standard VGA text mode. + */ + enum struct color : std::uint8_t + { + black, /**< Equivalent to HTML color \#000000 */ + blue, /**< Equivalent to HTML color \#0000AA */ + green, /**< Equivalent to HTML color \#00AA00 */ + cyan, /**< Equivalent to HTML color \#00AAAA */ + red, /**< Equivalent to HTML color \#AA0000 */ + purple, /**< Equivalent to HTML color \#AA00AA */ + brown, /**< Equivalent to HTML color \#AA5500 */ + gray, /**< Equivalent to HTML color \#AAAAAA */ + }; + + /** + * @brief The foreground color modification flag. + */ + enum struct foreground_flag : bool + { + none, /**< Apply no flag e.g., keep color as is. */ + intense, /**< Make the color more intense (usually brighter). */ + }; + + /** + * @brief The background color modification flag. + */ + enum struct background_flag : bool + { + none, /**< Apply no flag e.g., keep color as is. */ + blink_or_bright, /**< Make the cell blink or more intense, dependent on the VGA configuration */ + }; + + /** + * @brief The VGA text mode attribute. + * + * In the text mode of VGA, every code point being presented is followed by an attribute description. This allows for + * the modification of how the relevant "cell" is presented. + * + * @see vga::text::foreground_flag + * @see vga::text::background_flag + */ + struct attribute + { + color foreground_color : 3; /**< The foreground color of the cell, e.g. the color of the code point.*/ + enum foreground_flag foreground_flag : 1; /**< The foreground color modification flag of the cell.*/ + color bacground_color : 3; /**< The background color of the cell.*/ + enum background_flag background_flag : 1; /**< The background color modification flag of the cell.*/ + }; + + static_assert(sizeof(attribute) == 1, "The VGA text mode attribute must fit inside a single byte."); + + /** + * @brief Commonly used VGA text mode attributes + */ + namespace common_attributes + { + /** + * @brief Make the affected cell display with a gray foreground and black background. + */ + [[maybe_unused]] auto constexpr gray_on_black = + attribute{color::gray, foreground_flag::none, color::black, background_flag::none}; + + /** + * @brief Make the affected cell display with a green foreground and black background. + */ + [[maybe_unused]] auto constexpr green_on_black = + attribute{color::green, foreground_flag::none, color::black, background_flag::none}; + + /** + * @brief Make the affected cell display with a white (gray + intense) foreground and red background. + */ + [[maybe_unused]] auto constexpr white_on_red = + attribute{color::gray, foreground_flag::intense, color::red, background_flag::none}; + } // namespace common_attributes + + /** + * @brief Clear the VGA text mode buffer. + * + * @note This function also resets the text mode buffer pointer. + * + * @param attribute The attribute to "clear" the screen with. + */ + auto clear(attribute attribute = common_attributes::gray_on_black) -> void; + + /** + * @brief Enable or disable the VGA text mode cursor. + * + * @param enabled Whether or not to enable the cursors. + */ + auto cursor(bool enabled) -> void; + + /** + * @brief Write a string of code points to the VGA text buffer. + * + * @note This function also updates the text mode buffer pointer. + * + * @param code_points A string of (8-bit) code points to write to the VGA text mode buffer. + * @param attribute The attribute to apply to the written sequence of code points. + * @see vga::text::attribute + */ + auto write(std::string_view code_points, attribute attribute) -> void; +} // namespace teachos::arch::video::vga::text + +#endif \ No newline at end of file diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld new file mode 100644 index 0000000..765a432 --- /dev/null +++ b/arch/x86_64/scripts/kernel.ld @@ -0,0 +1,139 @@ +ENTRY(_start) + +/***************************************************************************** + * Virtual and linear start addresses of the TeachOS kernel + *****************************************************************************/ +TEACHOS_HIGH = -2048M; +TEACHOS_LOW = 1M; + +PHDRS { + boot_rodata PT_LOAD FLAGS(4); + boot_text PT_LOAD FLAGS(5); + boot_data PT_LOAD FLAGS(6); + + text PT_LOAD FLAGS(5); + data PT_LOAD FLAGS(6); + rodata PT_LOAD FLAGS(4); +} + +SECTIONS +{ + /*************************************************************************** + * Load the bootstrap code into low memory. We need to be accessible in + * 32-Bit mode, so we want to live down low, but we need to leave the 1MiB + * hole open since some BIOS functionality resides below it. + ***************************************************************************/ + . = TEACHOS_LOW; + + /*************************************************************************** + * We want to be able to be able to access all memory (linear and virtual) + * during bootstrapping and operation. To achieve this, we define some + * symbols at the beginning. + ***************************************************************************/ + _start_linear = .; + _start_virtual = . + TEACHOS_HIGH; + + /*************************************************************************** + * The bootstrapping infratructure goes first. We first place the read-only + * data, followed by our code, initialized mutable data, and finally our + * uninitialized mutable data. + ***************************************************************************/ + .boot_rodata : + { + KEEP(*(.boot_mbh)) + *(.boot_rodata) + } :boot_rodata + + .boot_text : + { + *(.boot_text) + } :boot_text + + .boot_data : + { + *(.boot_data) + } :boot_data + + .boot_bss : + { + *(.boot_bss) + *(.boot_stack) + } + + /*************************************************************************** + * Now it is time to load the 64-bit kernel code. We virtually load it into + * the upper 2GiB, while adjusting the linear load address appropriately. We + * also make sure to align the loaded data onto a page boundary. + ***************************************************************************/ + . = ALIGN(4K); + . += TEACHOS_HIGH; + + .init ALIGN(4K) : AT(ADDR (.init) - TEACHOS_HIGH) + { + /* + * Make sure that the crt code is wrapped around the compiler generated + * initialization code. + */ + KEEP(*crti.s.obj(.init)) + KEEP(*(EXCLUDE_FILE (*crti.s.obj *crtn.s.obj) .init)) + KEEP(*crtn.s.obj(.init)) + } :text + + .fini ALIGN(4K) : AT(ADDR (.fini) - TEACHOS_HIGH) + { + /* + * Make sure that the crt code is wrapped around the compiler generated + * finalizer code. + */ + KEEP(*crti.s.obj(.fini)) + KEEP(*(EXCLUDE_FILE (*crti.s.obj *crtn.s.obj) .fini)) + KEEP(*crtn.s.obj(.fini)) + } + + .text ALIGN(4K) : AT(ADDR (.text) - TEACHOS_HIGH) + { + *(.text*) + } + + .rodata ALIGN(4K) : AT (ADDR (.rodata) - TEACHOS_HIGH) + { + *(.rodata) + *(.rodata.*) + } :rodata + + .ctors ALIGN(4K) : AT (ADDR (.ctors) - TEACHOS_HIGH) + { + KEEP(*crtbegin.o(.ctors)) + KEEP(*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP(*(SORT(.ctors.*))) + KEEP(*crtend.o(.ctors)) + } :data + + .dtors ALIGN(4K) : AT (ADDR (.dtors) - TEACHOS_HIGH) + { + KEEP(*crtbegin.o(.dtors)) + KEEP(*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP(*(SORT(.dtors.*))) + KEEP(*crtend.o(.dtors)) + } + + .data ALIGN(4K) : AT (ADDR (.data) - TEACHOS_HIGH) + { + *(.data*) + } + + .bss ALIGN(4K) : AT (ADDR (.bss) - TEACHOS_HIGH) + { + *(COMMON) + *(.bss*) + } + + /*************************************************************************** + * In accordance with the symbol definitions at the start, we generate some + * symbols to mark the end of our loaded image. + ***************************************************************************/ + _end_virtual = ADDR(.bss) + SIZEOF(.bss); + _end_linear = _end_virtual - TEACHOS_HIGH; + + /DISCARD/ : { *(.comment) } +} diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s new file mode 100644 index 0000000..7b4e193 --- /dev/null +++ b/arch/x86_64/src/boot/boot.s @@ -0,0 +1,370 @@ +.extern _end_physical +.extern _init +.extern kernel_main + + +/** + * Uninitialized data for the bootstrapping process. + */ +.section .boot_bss, "aw", @nobits +.align 4096 + +/** + * Reserve space for the page maps we are going to used during startup. + * + * Note: We are going to use large pages to make the initial mapping code + * simpler. + * + * We need: + * - A single PML 4 (since we will only use 4-level paging) + * - 2 PML 3s (since we need to map high (-2GiB) and low (1+MiB) memory) + * - 2 PML 2s (since we need to map high (-2GiB) and low (1+MiB) memory) + */ + +.global page_map_level_4 +page_map_level_4: .skip 512 * 8 + +.global page_map_level_3_low +page_map_level_3_low: .skip 512 * 8 +.global page_map_level_3_high +page_map_level_3_high: .skip 512 * 8 + +.global page_map_level_2_low +page_map_level_2_low: .skip 512 * 8 +.global page_map_level_2_high +page_map_level_2_high: .skip 512 * 8 + +/** + * Reserve some space for the Multiboot 2 information pointer. + */ +.global multiboot_information_pointer +multiboot_information_pointer: .skip 4 + +/** + * Stack space for the bootstrapping process. + * + * Note: We are going to reserve 1 MiB for now. If/when the kernel requires + * more space to run, it will have to relocate the stack. + */ +.section .boot_stack, "aw", @nobits +.align 16 + +stack_bottom: .skip 1 << 20 +stack_top: + +/** + * Constants for the bootstrapping process. + */ +.section .boot_rodata, "a", @progbits + +/** + * A valid Global Descriptor Table is still required in long mode. However, we + * only need a single entry for the "code segment", so we will setup a single + * segment table below. + * + * Bit 43: "E" in the access byte => mark the segment as executable. + * Bit 44: "S" in the access byte => mark the segment as code or data. + * Bit 47: "P" in the access byte => mark the segment as being present. + * Bit 53: "L" in the flags byte => mark the segment as being for long mode + */ + +global_descriptor_table: .quad 0 +global_descriptor_table_code = . - global_descriptor_table +.quad (1<<43) | (1<<44) | (1<<47) | (1<<53) + +/** + * We also need a pointer that we can load into the GDTR. + * + * The pointer consists of a word describing the size of the table minus 1 and + * the pointer to the actual table. + */ +global_descriptor_table_pointer: +.word . - global_descriptor_table - 1 +.quad global_descriptor_table + +/** + * We are going to print some messages in case we panic during boot, so we are + * going to store them here as well + */ +message_prefix_panic: +.string "TeachOS Panic: " +message_not_loaded_by_multiboot2: +.string "The operating system was not loaded by a Multiboot 2 loader." +message_cpuid_instruction_no_supported: +.string "The 'cpuid' instruction is not supported on this platform." +mesage_long_mode_not_supported: +.string "Long mode is not supported by this platform." + +/** + * Mutable data for the bootstrapping process. + */ +.section .boot_data, "aw", @progbits + +/** + * We need a pointer to our current position in the VGA text buffer. + */ +.global vga_buffer_pointer +vga_buffer_pointer: .long 0xb8000 + +/** + * Code for the bootstrapping process. + */ +.section .boot_text, "ax", @progbits +.align 16 +.code32 + +/** + * Print a given panic message and then halt the machine. + * + * Parameters: + * - [stack - 0] message: the message to print + */ +_panic: + push %ebp + mov %esp, %ebp + + push message_prefix_panic + push $0x4f + call _print + add $8, %esp + + push 8(%ebp) + push 0x4f + call _print + add $8, %esp + + hlt + +/** + * Print a message via the VGA buffer. + * + * Parameters: + * - [stack - 4] message: the message to print + * - [stack - 0] color: the color of the message + */ +_print: + push %ebp + mov %esp, %ebp + + push %ebx + push %esi + mov 8(%ebp), %eax + mov 12(%ebp), %ebx + mov $0, %ecx + mov (vga_buffer_pointer), %esi + +.Lprint_loop: + mov (%ebx, %ecx), %dl + test %dl, %dl + je .Lupdate_vga_buffer_address + mov %dl, (%esi, %ecx, 2) + mov %al, 1(%esi, %ecx, 2) + inc %ecx + jmp .Lprint_loop + +.Lupdate_vga_buffer_address: + shl $1, %ecx + add %ecx, (vga_buffer_pointer) + +.Lprint_end: + pop %esi + pop %ebx + mov %ebp, %esp + pop %ebp + ret + +/** + * This is our entry point after being loaded by the bootloader. + * + * Having this in assembly makes it easier for us to keep things together. + */ +.global _start +_start: + mov $stack_top, %esp + mov %esp, %ebp + + call assert_loaded_by_multiboot2_loader + call assert_cpuid_instruction_is_supported + call assert_cpu_supports_long_mode + call prepare_page_maps + call enable_paging + call enable_sse + + lgdt (global_descriptor_table_pointer) + jmp $global_descriptor_table_code,$_transition_to_long_mode + + hlt + +/** + * Assert that the CPU supports going into long mode. + */ +assert_cpu_supports_long_mode: + mov $0x80000000, %eax + cpuid + cmp $0x80000001, %eax + jb .Llong_mode_assertion_failed + + mov $0x80000001, %eax + cpuid + test $(1 << 29), %edx + jz .Llong_mode_assertion_failed + ret +.Llong_mode_assertion_failed: + push $mesage_long_mode_not_supported + call _panic + +/** + * Assert that the CPU supports the CPUID instruction. + * + * The primary way to check for support of the instruction is to flip the ID + * bin in EFLAGS and then check if this changed was accepted. If so, the CPU + * supports the CPUID instruction, otherwise it most-likely doesn't. + */ +assert_cpuid_instruction_is_supported: + pushfl + pop %eax + mov %eax, %ecx + + xor $(1 << 21), %eax /* Flip the ID bit */ + push %eax /* Move the new bitset on the stack for loading */ + popfl /* Load the flags with ID set back into EFLAGS */ + pushfl /* Copy the flags back onto the stack */ + pop %eax /* Load the flags for further checking */ + + push %ecx + popfl + + cmp %ecx, %eax + je .Lcpuid_assertion_fail + ret +.Lcpuid_assertion_fail: + push $message_cpuid_instruction_no_supported + call _panic + +/** + * Assert that we were loaded by a Multiboot 2 compliant bootloader. + * + * This assertion will panic the system if the magic signature was not found. + * If we were loaded my an appropriate bootloader, this function also saves + * the provided MBI pointer to `multiboot_information_pointer`. + */ +assert_loaded_by_multiboot2_loader: + cmp $0x36d76289, %eax /* Check if we received the + expected magic */ + jne .Lmultiboot2_assertion_fail /* Panic otherwise */ + mov %ebx, multiboot_information_pointer /* Store the MBI pointer */ + ret +.Lmultiboot2_assertion_fail: + push $message_not_loaded_by_multiboot2 + call _panic + +/** + * Enable paging. + * + * Note: This routine expects for there to be a valid set of page maps already + * set up for use. + */ +enable_paging: + mov $page_map_level_4, %eax + mov %eax, %cr3 + + /* Enable Physical Address Extension */ + mov %cr4, %eax + or $(1 << 5), %eax + mov %eax, %cr4 + + /* Enable long mode support */ + mov $0xC0000080, %ecx + rdmsr + or $(1 << 8), %eax + wrmsr + + /* Enable paging */ + mov %cr0, %eax + or $(1 << 31), %eax + mov %eax, %cr0 + + ret + +/** + * Enable use of SSE instructions. + */ +enable_sse: + mov %cr0, %eax + and $0xfffffffb, %eax + or $0x00000002, %eax + mov %eax, %cr0 + + mov %cr4, %eax + or $(3 << 9), %eax + mov %eax, %cr4 + + ret + +/** + * Prepare the page maps. + * + * We map all physical memory we were loaded in plus one additional page. The + * mapping is done in terms of huge pages (2 MiB per page) to save on required + * page map entries. Note that we also map memory both in the low and high + * virtual address ranges, giving us two ways of accessing it. We need to do + * this, because the bootstrapping code lives in low memory, while the rest of + * the kernel will reside on the high end. + */ +prepare_page_maps: + /* Add an entry to the PML4, pointing to the low PML3 */ + mov $page_map_level_3_low, %eax + or $0x3, %eax + mov %eax, (page_map_level_4 + ((0x0000000000100000 >> 39) & 0x1ff) * 8) + + /* Add an entry to the PML4, pointing to the high PML3 */ + mov $page_map_level_3_high, %eax + or $0x3, %eax + mov %eax, (page_map_level_4 + ((0xffffffff80100000 >> 39) & 0x1ff) * 8) + + /* Add an entry to the low PML3, pointing to the low PML2 */ + mov $page_map_level_2_low, %eax + or $0x3, %eax + mov %eax, (page_map_level_3_low + ((0x0000000000100000 >> 30) & 0x1ff) * 8) + + /* Add an entry to the high PML3, pointing to the high PML2 */ + mov $page_map_level_2_high, %eax + or $0x3, %eax + mov %eax, (page_map_level_3_high + ((0xffffffff80100000 >> 30) & 0x1ff) * 8) + + xor %ecx, %ecx + + mov $_end_linear, %esi + shr $21, %esi + add $2, %esi + +.Lmap_pages: + mov $(1 << 21), %eax + mul %ecx + or $((1 << 0) | (1 << 1) | (1 << 7)), %eax + mov %eax, page_map_level_2_low(,%ecx,8) + mov %eax, page_map_level_2_high(,%ecx,8) + + inc %ecx + cmp %esi, %ecx + jne .Lmap_pages + + ret + +.section .boot_text, "ax", @progbits +.code64 + +_transition_to_long_mode: + xor %rax, %rax + mov %rax, %ss + mov %rax, %ds + mov %rax, %es + mov %rax, %fs + mov %rax, %gs + + movl $0xb8000, (vga_buffer_pointer) + + call _init + + call kernel_main + hlt diff --git a/arch/x86_64/src/boot/crti.s b/arch/x86_64/src/boot/crti.s new file mode 100644 index 0000000..26878fe --- /dev/null +++ b/arch/x86_64/src/boot/crti.s @@ -0,0 +1,13 @@ +.code64 + +.section .init +.global _init +_init: + push %rbp + movq %rsp, %rbp + +.section .fini +.global _fini +_fini: + push %rbp + movq %rsp, %rbp diff --git a/arch/x86_64/src/boot/crtn.s b/arch/x86_64/src/boot/crtn.s new file mode 100644 index 0000000..06fb7ce --- /dev/null +++ b/arch/x86_64/src/boot/crtn.s @@ -0,0 +1,9 @@ +.code64 + +.section .init + popq %rbp + ret + +.section .fini + popq %rbp + ret diff --git a/arch/x86_64/src/boot/multiboot.s b/arch/x86_64/src/boot/multiboot.s new file mode 100644 index 0000000..7ccca56 --- /dev/null +++ b/arch/x86_64/src/boot/multiboot.s @@ -0,0 +1,26 @@ +.section .boot_mbh, "a" +.align 8 + +multiboot_header_start: +.Lmagic: + .long 0xe85250d6 +.Larch: + .long 0 +.Llength: + .long multiboot_header_end - multiboot_header_start +.Lchecksum: + .long 0x100000000 - (0xe85250d6 + 0 + (multiboot_header_end - multiboot_header_start)) +.align 8 +.Lflags_start: + .word 4 + .word 1 + .long .Lflags_end - .Lflags_start + .long 3 +.Lflags_end: +.align 8 +.Lend_start: + .word 0 + .word 0 + .long .Lend_end - .Lend_start +.Lend_end: +multiboot_header_end: diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp new file mode 100644 index 0000000..0e90264 --- /dev/null +++ b/arch/x86_64/src/kernel/main.cpp @@ -0,0 +1,15 @@ +#include "arch/kernel/main.hpp" + +#include "arch/video/vga/text.hpp" + +namespace teachos::arch::kernel +{ + auto main() -> void + { + using namespace video::vga; + + text::clear(); + text::cursor(false); + text::write("TeachOS is starting up...", text::common_attributes::green_on_black); + } +} // namespace teachos::arch::kernel diff --git a/arch/x86_64/src/video/vga/text.cpp b/arch/x86_64/src/video/vga/text.cpp new file mode 100644 index 0000000..f1e7412 --- /dev/null +++ b/arch/x86_64/src/video/vga/text.cpp @@ -0,0 +1,47 @@ +#include "arch/video/vga/text.hpp" + +#include "arch/boot/pointers.hpp" +#include "arch/video/vga/io.hpp" +#include "memory/asm_pointer.hpp" + +#include +#include +#include + +namespace teachos::arch::video::vga::text +{ + + namespace + { + auto constexpr default_text_buffer_address = 0xb8000; + + extern "C" std::pair * vga_buffer_pointer; + auto constinit text_buffer = teachos::memory::asm_pointer{vga_buffer_pointer}; + + auto write(char code_point, attribute attribute) -> void + { + auto & p = *text_buffer; + (*p++) = std::pair{code_point, attribute}; + }; + } // namespace + + auto clear(attribute attribute) -> void + { + *text_buffer = reinterpret_cast(default_text_buffer_address); + std::ranges::fill_n(*text_buffer, 2000, std::pair{' ', attribute}); + } + + auto cursor(bool enabled) -> void + { + auto cursor_disable_byte = std::byte{!enabled} << 5; + + crtc::address_port::write(crtc::registers::cursor_start); + crtc::data_port::write(vga::crtc::data_port::read() | cursor_disable_byte); + } + + auto write(std::string_view code_points, attribute attribute) -> void + { + std::ranges::for_each(code_points, [&](auto code_point) { write(code_point, attribute); }); + } + +} // namespace teachos::arch::video::vga::text diff --git a/arch/x86_64/support/grub.cfg.in b/arch/x86_64/support/grub.cfg.in new file mode 100644 index 0000000..86674dd --- /dev/null +++ b/arch/x86_64/support/grub.cfg.in @@ -0,0 +1,7 @@ +timeout=2 +default=0 + +menuentry "TeachOS" { + multiboot2 /$ + boot +} \ No newline at end of file diff --git a/cmake/Modules/FindSphinx.cmake b/cmake/Modules/FindSphinx.cmake new file mode 100644 index 0000000..a0a1c31 --- /dev/null +++ b/cmake/Modules/FindSphinx.cmake @@ -0,0 +1,10 @@ +include("FindPackageHandleStandardArgs") + +find_program(SPHINX_BUILD_EXE "sphinx-build" + HINTS "${PROJECT_SOURCE_DIR}/../.venv/bin" +) + +find_package_handle_standard_args("Sphinx" + DEFAULT_MSG + SPHINX_BUILD_EXE +) diff --git a/cmake/Modules/Findgrub-mkrescue.cmake b/cmake/Modules/Findgrub-mkrescue.cmake new file mode 100644 index 0000000..036b4fa --- /dev/null +++ b/cmake/Modules/Findgrub-mkrescue.cmake @@ -0,0 +1,10 @@ +include("FindPackageHandleStandardArgs") + +find_program(GRUB_MKRESCUE_EXE "grub-mkrescue") +find_program(MTOOLS_MFORMAT_EXE "mformat") + +find_package_handle_standard_args("grub-mkrescue" + DEFAULT_MSG + GRUB_MKRESCUE_EXE + MTOOLS_MFORMAT_EXE +) diff --git a/cmake/Platforms/x86_64.cmake b/cmake/Platforms/x86_64.cmake new file mode 100644 index 0000000..291cbaa --- /dev/null +++ b/cmake/Platforms/x86_64.cmake @@ -0,0 +1,35 @@ +execute_process(COMMAND "x86_64-elf-g++" "-print-file-name=crtbegin.o" + OUTPUT_VARIABLE CRT_BEGIN + ERROR_QUIET +) +string(STRIP "${CRT_BEGIN}" CRT_BEGIN) +mark_as_advanced(CRT_BEGIN) + +string(REGEX REPLACE "/crtbegin.o" "" CMAKE_SYSROOT "${CRT_BEGIN}") +mark_as_advanced(CMAKE_SYSROOT) + +set(SYSTEM_NAME "Generic") + +set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") + +set(CMAKE_C_COMPILER "x86_64-elf-gcc") +set(CMAKE_CXX_COMPILER "x86_64-elf-g++") + +set(CMAKE_CXX_FLAGS_INIT "-m64 -mno-red-zone -mcmodel=large -fno-exceptions -ffunction-sections -fdata-sections") +set(CMAKE_CXX_FLAGS_DEBUG "-ggdb3") +set(CMAKE_ASM_FLAGS_DEBUG "-ggdb3") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-ggdb3") +set(CMAKE_ASM_FLAGS_RELWITHDEBINFO "-ggdb3") +set(CMAKE_EXE_LINKER_FLAGS_INIT "-nostartfiles -Wl,--gc-sections") +set(CMAKE_CXX_LINK_EXECUTABLE + " \ + \ + \ + \ + ${CMAKE_SYSROOT}/crtbegin.o \ + \ + -o \ + \ + -lgcc \ + ${CMAKE_SYSROOT}/crtend.o" +) \ No newline at end of file diff --git a/conanfile.py b/conanfile.py deleted file mode 100644 index 9b1d4d3..0000000 --- a/conanfile.py +++ /dev/null @@ -1,62 +0,0 @@ -from conan import ConanFile -from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout -from conan.tools.env import VirtualBuildEnv - - -class KernelConan(ConanFile): - name = "kernel" - description = "The kernel of TeachOS" - version = "0.0.1" - package_type = "application" - homepage = "https://gitlab.ost.ch/teachos/kernel" - - settings = [ - "arch", - "build_type", - "compiler", - ] - - tool_requires = [ - "cmake/[~3.27]", - "doxygen/[~1.9]", - "gcc/13.2.0@teachos/stable", - "ninja/[~1.11]", - ] - - def build(self): - cmake = CMake(self) - cmake.configure() - if self.settings.arch == "x86_64": - cmake.build(target="bootable-iso") - else: - cmake.build() - - def generate(self): - build_environment = VirtualBuildEnv(self) - build_environment.generate() - - dependencies = CMakeDeps(self) - dependencies.generate() - - toolchain = CMakeToolchain(self, generator="Ninja Multi-Config") - toolchain.cache_variables["CMAKE_TRY_COMPILE_TARGET_TYPE"] = "STATIC_LIBRARY" - toolchain.variables["TEACHOS_DESCRIPTION"] = self.description - toolchain.variables["TEACHOS_HOMEPAGE_URL"] = self.homepage - toolchain.variables["TEACHOS_VERSION"] = self.version - toolchain.blocks["teachos_cmake_modules"] = CMakeModulesPathBlock - toolchain.blocks["teachos_cmake_modules"].values["root"] = self.source_folder - toolchain.blocks["teachos_platform"] = PlatformIncludeBlock - toolchain.blocks["teachos_platform"].values["platform"] = self.settings.arch - toolchain.blocks.remove("cmake_flags_init") - toolchain.blocks.remove("arch_flags") - toolchain.generate() - - def layout(self): - cmake_layout(self, src_folder="source", generator="Ninja Multi-Config") - - -class PlatformIncludeBlock: - template = 'include("{{platform}}")' - -class CMakeModulesPathBlock: - template = 'list(APPEND CMAKE_MODULE_PATH "{{root}}/cmake/Modules" "{{root}}/cmake/Platforms")' diff --git a/include/memory/asm_pointer.hpp b/include/memory/asm_pointer.hpp new file mode 100644 index 0000000..9ec2218 --- /dev/null +++ b/include/memory/asm_pointer.hpp @@ -0,0 +1,72 @@ +#ifndef TEACHOS_MEMORY_ASM_POINTER_HPP +#define TEACHOS_MEMORY_ASM_POINTER_HPP + +namespace teachos::memory +{ + + /** + * @brief A pointer that is defined in some assembly source file. + * + * @tparam Type The type of the pointer + * @since 0.0.1 + */ + template + struct asm_pointer + { + /** + * @brief The type of the underlying pointer. + */ + using pointer = Type *; + + /** + * @brief Construct a new asm_pointer for a given assembly-defined pointer. + * @param pointer A pointer defined in assembly. + */ + constexpr asm_pointer(Type *& pointer) + : m_pointer{&pointer} + { + } + + /** + * @brief Access the underlying pointer. + * @return The pointer wrapped by this asm_pointer. + */ + auto constexpr operator*() -> pointer & { return *m_pointer; } + + /** + * @brief Access the underlying pointer. + * @return The pointer wrapped by this asm_pointer. + */ + auto constexpr operator*() const -> pointer const & { return *m_pointer; } + + private: + pointer * m_pointer; + }; + + /** + * @copydoc asm_pointer + * + * @note This specialization allows the use of this type for pointers to constant data. + * @since 0.0.1 + */ + template + struct asm_pointer + { + /** @copydoc asm_pointer::asm_pointer */ + constexpr asm_pointer(Type const & pointer) + : m_pointer{&pointer} + { + } + + /** @copydoc asm_pointer::operator*() */ + auto constexpr operator*() -> Type const & { return *m_pointer; } + /** @copydoc asm_pointer::operator*() const */ + auto constexpr operator*() const -> Type const & { return *m_pointer; } + + private: + Type const * m_pointer; + }; + +} // namespace teachos::memory + +#endif \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 5468185..0000000 --- a/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -black>=23 -conan~=1.61 -mypy~=1.5 -sphinx>=6,<7 -breathe~=4.35 -sphinx-book-theme~=1.0 \ No newline at end of file diff --git a/source/.clang-format b/source/.clang-format deleted file mode 100644 index d4da962..0000000 --- a/source/.clang-format +++ /dev/null @@ -1,77 +0,0 @@ ---- -AccessModifierOffset: '-2' -AlignAfterOpenBracket: Align -AlignConsecutiveAssignments: 'false' -AlignConsecutiveDeclarations: 'false' -AlignEscapedNewlines: Left -AlignOperands: 'true' -AlignTrailingComments: 'true' -AllowAllParametersOfDeclarationOnNextLine: 'true' -AllowShortBlocksOnASingleLine: 'false' -AllowShortCaseLabelsOnASingleLine: 'false' -AllowShortFunctionsOnASingleLine: All -AllowShortIfStatementsOnASingleLine: 'false' -AllowShortLoopsOnASingleLine: 'false' -AlwaysBreakAfterDefinitionReturnType: None -AlwaysBreakAfterReturnType: None -AlwaysBreakTemplateDeclarations: 'true' -BinPackArguments: 'true' -BinPackParameters: 'true' -BreakBeforeBraces: Custom -BraceWrapping: - AfterClass: 'true' - AfterControlStatement: 'true' - AfterEnum: 'true' - AfterFunction: 'true' - AfterNamespace: 'true' - AfterStruct: 'true' - AfterUnion: 'true' - AfterExternBlock: 'true' - BeforeCatch: 'true' - BeforeElse: 'true' - IndentBraces: 'false' -BreakBeforeInheritanceComma: 'false' -BreakConstructorInitializers: BeforeComma -BreakStringLiterals: 'true' -ColumnLimit: '120' -CompactNamespaces: 'false' -Cpp11BracedListStyle: 'true' -DerivePointerAlignment: 'false' -FixNamespaceComments: 'true' -IncludeBlocks: Regroup -IncludeCategories: - # Local Headers - - Regex: '"(.*/?)+/.+\.hpp"' - Priority: 100 - # STL Headers - - Regex: '<[[:alnum:]._]+(?!\.(h|hpp))>' - Priority: 400 - # C Library Headers - - Regex: '<([[:alnum:]._]/*)+\.h>' - Priority: 300 -IndentCaseLabels: 'true' -IndentPPDirectives: None -IndentWidth: '2' -KeepEmptyLinesAtTheStartOfBlocks: 'false' -Language: Cpp -MaxEmptyLinesToKeep: '1' -NamespaceIndentation: All -PointerAlignment: Middle -ReflowComments: 'true' -SortIncludes: 'true' -SortUsingDeclarations: 'true' -SpaceAfterCStyleCast: 'false' -SpaceAfterTemplateKeyword: 'false' -SpaceBeforeAssignmentOperators: 'true' -SpaceBeforeParens: ControlStatements -SpaceInEmptyParentheses: 'false' -SpacesBeforeTrailingComments: '2' -SpacesInAngles: 'false' -SpacesInContainerLiterals: 'false' -SpacesInCStyleCastParentheses: 'false' -SpacesInParentheses: 'false' -SpacesInSquareBrackets: 'false' -Standard: Cpp11 -TabWidth: '2' -UseTab: Never -... diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt deleted file mode 100644 index beb0c07..0000000 --- a/source/CMakeLists.txt +++ /dev/null @@ -1,115 +0,0 @@ -cmake_minimum_required(VERSION "3.27") - -project("kernel" - DESCRIPTION "${TEACHOS_DESCRIPTION}" - HOMEPAGE_URL "${TEACHOS_HOMEPAGE_URL}" - VERSION "${TEACHOS_VERSION}" - LANGUAGES ASM C CXX -) - -#[============================================================================[ -# Global Build System Configuration -#]============================================================================] - -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") -set(CMAKE_INTERPROCEDURAL_OPTIMIZATION YES) - -#[============================================================================[ -# Documentation -#]============================================================================] - -find_package("Doxygen") - -set(DOXYGEN_GENERATE_HTML NO) -set(DOXYGEN_GENERATE_XML YES) -set(DOXYGEN_EXCLUDE_PATTERNS "*.cpp") -set(DOXYGEN_OUTPUT_DIRECTORY "doxygen") -set(DOXYGEN_QUIET YES) - -file(GLOB_RECURSE DOXYGEN_SOURCES CONFIGURE_DEPENDS "*.hpp") - -message(STATUS "${SPHINX_SOURCES}") - -doxygen_add_docs("docs_xml" - ${DOXYGEN_SOURCES} - ALL - USE_STAMP_FILE - COMMENT "Generating developer documentation sources" -) - -set_target_properties("docs_xml" PROPERTIES - ADDITIONAL_CLEAN_FILES - "${PROJECT_BINARY_DIR}/doxygen" -) - -file(GLOB_RECURSE SPHINX_SOURCES CONFIGURE_DEPENDS "../docs/**.rst") - -add_custom_target("docs" ALL - COMMAND "${SPHINX_BUILD_EXE}" - "../docs" - "docs" - "-q" - DEPENDS "docs_xml" - SOURCES ${SPHINX_SOURCES} - COMMENT "Generating developer documentation html" -) - -set_target_properties("docs" PROPERTIES - ADDITIONAL_CLEAN_FILES - "${PROJECT_BINARY_DIR}/docs" -) - -#[============================================================================[ -# Global Compiler Configuration -#]============================================================================] - -add_compile_options( - "$<$:-Wall>" - "$<$:-Wextra>" - "$<$:-Werror>" - "$<$:-pedantic-errors>" -) - -#[============================================================================[ -# Global Directories -#]============================================================================] - -include_directories( - "include" - "arch/${CMAKE_SYSTEM_PROCESSOR}/include" -) - -#[============================================================================[ -# The Bootstrap Library -#]============================================================================] - -add_library("_boot" OBJECT) -add_library("teachos::boot" ALIAS "_boot") - -#[============================================================================[ -# The Video Library -#]============================================================================] - -add_library("_video" OBJECT) -add_library("teachos::video" ALIAS "_video") - -#[============================================================================[ -# The Kernel -#]============================================================================] - -add_executable("_kernel" - "src/kernel/main.cpp" -) -add_executable("teachos::kernel" ALIAS "_kernel") - -target_link_libraries("_kernel" PRIVATE - "teachos::boot" - "teachos::video" -) - -#[============================================================================[ -# Platform Specific Components -#]============================================================================] - -add_subdirectory("arch/${CMAKE_SYSTEM_PROCESSOR}") diff --git a/source/arch/x86_64/CMakeLists.txt b/source/arch/x86_64/CMakeLists.txt deleted file mode 100644 index 6ff1332..0000000 --- a/source/arch/x86_64/CMakeLists.txt +++ /dev/null @@ -1,64 +0,0 @@ -#[============================================================================[ -# The Kernel Library -#]============================================================================] - -set(TEACHOS_KERNEL_LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/kernel.ld") -mark_as_advanced(TEACHOS_KERNEL_LINKER_SCRIPT) - -target_sources("_kernel" PRIVATE - "src/kernel/main.cpp" -) - -target_link_options("_kernel" PRIVATE - "-T${TEACHOS_KERNEL_LINKER_SCRIPT}" -) - -set_target_properties("_kernel" PROPERTIES - LINK_DEPENDS "${TEACHOS_KERNEL_LINKER_SCRIPT}" -) - -#[============================================================================[ -# The Bootstrap Library -#]============================================================================] - -target_sources("_boot" PRIVATE - "src/boot/boot.s" - "src/boot/crti.s" - "src/boot/crtn.s" - "src/boot/multiboot.s" -) - -#[============================================================================[ -# The Video Library -#]============================================================================] - -target_sources("_video" PRIVATE - "src/video/vga/text.cpp" -) - -#[============================================================================[ -# The Bootable ISO Image -#]============================================================================] - -find_package("grub-mkrescue") - -if(grub-mkrescue_FOUND) - file(GENERATE - OUTPUT "isofs/boot/grub/grub.cfg" - INPUT "support/grub.cfg.in" - ) - - add_custom_target("bootable-iso" - COMMAND "${GRUB_MKRESCUE_EXE}" - "-o" - "${PROJECT_BINARY_DIR}/teachos-$.iso" - "${CMAKE_CURRENT_BINARY_DIR}/isofs" - "$" - "2>/dev/null" - DEPENDS - "$" - "isofs/boot/grub/grub.cfg" - BYPRODUCTS "${PROJECT_BINARY_DIR}/teachos-$.iso" - COMMENT "Creating bootable ISO image" - ) -endif() diff --git a/source/arch/x86_64/include/arch/boot/pointers.hpp b/source/arch/x86_64/include/arch/boot/pointers.hpp deleted file mode 100644 index dcd14fe..0000000 --- a/source/arch/x86_64/include/arch/boot/pointers.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_BOOT_POINTERS_HPP -#define TEACHOS_ARCH_X86_64_BOOT_POINTERS_HPP - -#include - -namespace teachos::arch::boot -{ - extern "C" std::byte const multiboot_information_pointer; -} // namespace teachos::arch::boot - -#endif \ No newline at end of file diff --git a/source/arch/x86_64/include/arch/io/port_io.hpp b/source/arch/x86_64/include/arch/io/port_io.hpp deleted file mode 100644 index 5b61f90..0000000 --- a/source/arch/x86_64/include/arch/io/port_io.hpp +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_IO_PORT_IO_HPP -#define TEACHOS_ARCH_X86_64_IO_PORT_IO_HPP - -#include -#include -#include -#include - -namespace teachos::arch::io -{ - - /** - * @brief An I/O port of a given size at a given address. - * - * @tparam Address The address (port number) of the I/O port. - * @tparam Size The size (in bytes) of the I/O port. - */ - template - struct port - { - static_assert(Size == 1 || Size == 2 || Size == 4, "A port must be either 1, 2, or 4 bytes in size"); - - /** - * @brief The type of data available for reading and writing through this port. - */ - using io_type = - std::conditional_t>; - - /** - * @brief Write a byte to the I/O port. - * - * @param data The data to write to the I/O port. - */ - auto static write(io_type data) -> void - requires(Size == 1) - { - asm volatile("mov %[port], %%dx\n" - "mov %[data], %%al\n" - "out %%al, %%dx\n" - : - : [port] "i"(Address), [data] "im"(data) - : "dx", "al"); - } - - /** - * @brief Write a word to the I/O port. - * - * @param data The data to write to the I/O port. - */ - auto static write(io_type data) -> void - requires(Size == 2) - { - asm volatile("mov %[port], %%dx\n" - "mov %[data], %%ax\n" - "out %%ax, %%dx\n" - : - : [port] "i"(Address), [data] "im"(data) - : "dx", "ax"); - } - - /** - * @brief Write a double-word to the I/O port. - * - * @param data The data to write to the I/O port. - */ - auto static write(io_type data) -> void - requires(Size == 4) - { - asm volatile("mov %[port], %%dx\n" - "mov %[data], %%eax\n" - "out %%eax, %%dx\n" - : - : [port] "i"(Address), [data] "im"(data) - : "dx", "eax"); - } - - /** - * @brief Read a byte from the I/O port. - * - * @return The data read from the I/O port. - */ - auto static read() -> io_type - requires(Size == 1) - { - auto data = io_type{}; - asm volatile("mov %[port], %%dx\n" - "in %%dx, %%al\n" - "mov %%al, %[data]\n" - : [data] "=m"(data) - : [port] "i"(Address) - : "dx", "al"); - return data; - } - - /** - * @brief Read a word from the I/O port. - * - * @return The data read from the I/O port. - */ - auto static read() -> io_type - requires(Size == 2) - { - auto data = io_type{}; - asm volatile("mov %[port], %%dx\n" - "in %%dx, %%ax\n" - "mov %%ax, %[data]\n" - : [data] "=m"(data) - : [port] "i"(Address) - : "dx", "ax"); - return data; - } - - /** - * @brief Read a double-word from the I/O port. - * -