Skip to content

About

Small OS kernel (i386, x86_64 for now) written in C++20

Topics

Resources

Code of conduct

Contributing

Stars

4 stars

Watchers

1 watching

Forks

Latest commit

 

History

522 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

IgrOS-Kernel

Badge-CPP Badge-License

IgrOS-Kernel is a hobby operating system kernel written in modern C++20 with a thin layer of assembly. It boots via Multiboot (GRUB) on i386 and x86_64, sets up the CPU (GDT, IDT, exceptions, interrupts, paging), manages physical memory and drives basic PC hardware: VGA text mode, serial port, PIT timer, keyboard and CMOS clock.

Badge-Arch-i386 Badge-Arch-x86_64 Badge-Arch-arm Badge-Arch-arm64 Badge-Arch-avr


Status

CI/CD Badge-GitHub Badge-GitLab Badge-Azure-DevOps
Codacy Badge-Codacy-Quality Badge-Codacy-Coverage
SonarCloud Badge-Sonar-Quality-Gate Badge-Sonar-Coverage Badge-Sonar-Bugs Badge-Sonar-Vulnerabilities Badge-Sonar-Code-Smells

Features

Area Implemented Planned
Boot Multiboot (GRUB), protected mode (i386), long mode switch (x86_64) Multiboot 2, custom bootloader
CPU GDT, IDT, exceptions, hardware interrupts (8259 PIC) APIC
Memory Physical page allocator, paging Virtual memory allocator
Drivers VGA text mode, serial port (UART), keyboard (read), CMOS RTC (read), PIT timer (off by default) Loadable kernel drivers
User space User mode, user programs, GUI

Quick start

Requirements

Linux host with:

  • CMake 3.21+ and Ninja
  • Clang + LLD, or GCC with multilib
  • GRUB tools: grub-mkrescue (grub-common, grub-pc-bin), xorriso, mtools
  • QEMU (qemu-system-x86) to run; BOCHS optionally

On Ubuntu:

sudo apt install ccache clang cmake g++-multilib gcc-multilib grub-common grub-pc-bin lld mtools ninja-build qemu-system-x86 xorriso

Build, run and test

Build, run and test scripts take <i386|x86_64> [clang++|g++] [debug|release] (defaults: clang++ debug).

# Build bootable ISO
config/script/build.sh x86_64
# Run in QEMU (serial output in terminal)
config/script/run-qemu.sh x86_64
# Run in BOCHS
config/script/run-bochs.sh x86_64
# Host unit tests + QEMU boot test
config/script/test.sh x86_64
# Remove build artifacts
config/script/clean.sh

The ISO is placed at install/<Debug|Release>/config-linux-<compiler>-<arch>-<type>/kernel.iso.

You can also build with CMake presets directly:

cmake --preset config-linux-clang++-x86_64-debug
cmake --build --preset build-linux-clang++-x86_64-debug --target install

Docker

The image contains only the toolchain; sources are mounted from the host, so code changes don't require rebuilding it:

docker compose up kernel_x86_64_clang_build   # also: kernel_i386_clang_build, kernel_{i386,x86_64}_gcc_build

The analysis image adds analyzers, gcovr, QEMU and CodeQL to the toolchain and runs all analysis at once:

docker compose run --rm kernel_analysis                  # all four configs
docker compose run --rm kernel_analysis g++:x86_64       # or some of them

Testing

  • Unit tests – host-compiled tests of kernel library, memory, interrupts, paging, drivers and multiboot code for both architectures' code paths, in tests/. Assembly functions (port I/O, control registers, CPU halt) are replaced with fake hardware (tests/hw.hpp):
    cmake -S tests -B build/tests -G Ninja -DIGROS_TEST_ARCH=x86_64 [-DIGROS_TESTS_COVERAGE=ON]
    cmake --build build/tests
    ctest --test-dir build/tests --output-on-failure
  • Boot test – tests/boot/qemu-boot.sh boots the ISO in QEMU and checks that the kernel reaches the end of kmain and handles a keyboard IRQ.

GitHub Actions and GitLab CI run both for every compiler/architecture combination; Azure Pipelines runs the boot test. Coverage is reported to Codacy and SonarCloud. Locally, a coverage build of the tests has a coverage target (needs gcovr), HTML report in build/tests/reports/coverage/.

Analysis

cmake/modules/EnableAnalysis.cmake adds options and on-demand report targets to the kernel build (reports go to <build dir>/reports/):

Option / target What it does
IGROS_CXX_CLANG_TIDY=ON ClangTidy pass during the build
IGROS_CXX_STRICT_WARNINGS=ON Extra warnings (-Wconversion, -Wshadow, -Wold-style-cast, -Wframe-larger-than=1024...), reported but not fatal
IGROS_KERNEL_UBSAN=ON UndefinedBehaviorSanitizer in trap mode: UB raises #UD (vector 6), no runtime library needed
--target clang-tidy ClangTidy over all C++ sources with .clang-tidy checks → clang-tidy-report.txt (needs run-clang-tidy)
--target cppcheck Cppcheck over the compile database (inconclusive, exhaustive) → cppcheck-report.txt
--target codeql CodeQL database from a separate clean build → codeql-results.sarif (needs codeql CLI)
--target compiler-warnings Compiler diagnostics of all C++ sources, recompiled to a temporary directory → compiler-warnings.txt
--target analysis-report HTML page with findings of the reports above → index.html (needs Python 3)
cmake --preset config-linux-clang++-x86_64-debug -DIGROS_KERNEL_UBSAN=ON
cmake --build --preset build-linux-clang++-x86_64-debug --target cppcheck

config/script/analysis.sh runs everything for all (or given) configs: a debug build with strict warnings and UBSan, QEMU boot test, all report targets (CodeQL for the first config only, IGROS_ANALYSIS_CODEQL=all|none to change), host tests coverage. The report in build/analysis/index.html merges findings of every tool and config (the same issue reported by several tools or configs is one entry), shows them per file with source lines, build and boot status per config and coverage.

An open report page updates itself whenever the report is regenerated (it reloads index.data.js), also while analysis.sh is still running.

In CI the Analysis workflow runs analysis.sh (CodeQL goes to code scanning instead) and publishes the page on GitHub Pages: master at igr2014.github.io/IgrOS-Kernel, each pull request under pr/<number>/ with a summary comment in the PR (removed when it is closed). The code is kept free of findings, so any finding fails the workflow (after the report is published), as do a config that doesn't build or boot and failing host tests. A finding that doesn't apply is suppressed where it is, with a reason (// NOLINT(<check>): <reason>, // cppcheck-suppress <id>); a check that doesn't fit the kernel at all is disabled in .clang-tidy with the reason next to it.

A UBSan trap before the IDT is loaded ends in a triple fault without a message. analysis.sh resolves it into the report; by hand, boot with qemu-system-x86_64 ... -no-reboot -d int, take IP= of the v=06 line and resolve it with addr2line -f -C -i -e kernel.bin <IP>.

ASan and gcov coverage need a hosted runtime the kernel doesn't have: coverage comes from the host unit tests, SonarCloud and Codacy run in CI.


Project layout

Directory Contents
arch/ CPU support: common x86 code and i386 / x86_64 boot code, GDT, IDT
drivers/ VGA, serial (UART), PIT, CMOS RTC, keyboard
klib/ Freestanding kernel library: memory, strings, printing, math
mem/ Physical memory allocator
multiboot/ Multiboot information parsing
platform/ Platform initialization
dev/, sys/ Device abstraction, ELF definitions
config/ Build/run scripts, linker scripts, CMake toolchain configs
tests/ Unit and boot tests
kmain.cpp Kernel entry point

Contributing

See CONTRIBUTING.md and the Code of Conduct.

The repository is mirrored on GitHub, GitLab and Azure DevOps.

License

MIT © 2017 - 2026 Igor Baklykov

About

Small OS kernel (i386, x86_64 for now) written in C++20

Topics

Resources

Code of conduct

Contributing

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages