TeachOS Kernel
TeachOS is a modern kernel with a focus on clean design and simplicity. It is not highly optimized like production grade kernels, but instead aims to be understandable. It is implemented in assembly and C++, where the amount of assembly is kept to a minimum. The primary design goal of the kernel is to be teachable and useful as part of the operating systems lecture track at OST.
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 writing they are not officially supported.
Required Tools
A precompiled toolchain, targeting only x86-64 as of the time of writing, is available in the Devconainers repository. The toolchain is provided both as a downloadable, self-contained archive and an Ubuntu Linux based Docker image. When using the downloadable archive, care must be taken to make the contained executables available in the user's or system path. Also, when using the downloadable archive, further required tools, like CMake, QEMU, Ninja, xorisso, grub, etc. must be installed separately.
The primary IDE used for development is VSCodium. A configuration of runnable tasks, debugging settings, etc. as well as suggested extensions is provided. Other IDEs might work, especially Visual Studio Code related ones, but no support is provided.
Repository Structure
The code is grouped into separate "sub-packages", according to the following rules:
- arch: The root of all platform-dependent code.
- kapi: The Kernel API, implemented by either the kernel itself, or the platform, used by both.
- kernel: The root of all platform-independent code
- libs: Support libraries, like the TeachOS Standard Library, or Multiboot2 support.
When implementing new features, drivers, or infrastructure, care must be taken as to where to place the new code. In general, platform-dependent code, like CPU access, MMU configuration, privilege handling etc., should be placed in the relevant folder under the arch root. Platform independent-code, like generic memory allocation or scheduling algorithms, or generic drivers for hardware like PCIe devices, should be placed under the kernel root.
Launching
The default build target generates a bootable image. On x86-64 for example, this image takes the form of a bootable, grub2 based ISO image. These images are designed to be booted in QEMU, and should theoretically also be bootable on real hardware. However, note that not warranty is provided, and the kernel code may irreparably destroy any physical hardware if booted on a real system. The VSCodium IDE configuration provides a launch task using QEMU, available for debugging (via F5) and direct launch as a task.
Notes for Development under Windows
While this repository and the devcontainer can be used from Windows, significant performance issues may occur. To reduce these issues, you can either set up a Linux VM for development, or, if that is not preferred, clone the repository inside WSL and open it from there with Visual Studio Code.
If you use tools such as Git Extensions or GitHub Desktop, access the repository via the WSL network path, for example \\wsl.localhost\<distro>\<path-to-repo>.
Kernel Architecture
The kernel is structured into four primary directories, ensuring a clear division of concerns:
- arch/: Contains all platform-dependent implementations (currently targeting x86_64).
- kapi/: The Kernel API, which defines the boundaries between platform-dependent and platform-independent components.
- kernel/: Core platform-independent kernel logic.
- libs/: Standalone support libraries (e.g., custom standard library kstd, ACPI, and Multiboot2 parsers).
Architecture specific logic (arch) and platform-independent (kernel) logic must not depend directly on each other. Instead, all interaction must be facilitated via interfaces declared in kapi/.
Kernel API (KAPI) Decoupling Design
The decoupling of interfaces and implementations is structured via two categories of declarations within kapi/:
Kernel-defined: Platform-independent implementations located in kernel/kapi/. For example: - memory.cpp: Wraps physical frame allocation and page mapping. - filesystem.cpp: Wraps Virtual File System (VFS) operations. - interrupts.cpp: Registers and routes interrupts to handlers.
-
Platform-defined: Low-level hooks declared in kapi/ and implemented by the target platform under arch/x86_64/kapi/. For example: - cpu.cpp: Performs early CPU setup via init(). - memory.cpp: Initializes page tables and platform allocator. - interrupts.cpp: Exposes methods to toggle external interrupts.
This decoupling is intended to ease the porting of TeachOS to new architectures (e.g. RISC-V or ARM64) by implementing a new subdirectory under arch that implements the platform-defined KAPI interfaces.
Subsystems
Bootstrapping & CPU Initialization
Execution begins in platform-dependent code. Once a basic execution environment has been established, the C++ runtime is initialized via before calling the core main() function.
Memory Management
TeachOS separates memory allocation into three specialized systems:
- Physical Memory Manager: The current implementation manages physical memory using a bitmap.
- Virtual Memory Page Mapper: The architecture-specific page table management implementation.
- Kernel Heap Allocator: Memory allocations via new/delete are currently routed through a block_list_allocator using a linked list first-fit allocator.
- Memory-Mapped I/O (MMIO): The mmio_allocator reserves and maps memory regions for MMIO.
Virtual File System (VFS)
A POSIX-like directory and file abstraction layer is located in kernel/filesystem/:
- Abstractions: Managed via directory entries, filesystem nodes, mount hierarchies, and the open file table.
- Concrete Filesystems:
- RootFS: An in-memory filesystem mounted at / during early boot.
- Device FS: Exposes devices as files under /dev.
- Second Extended Filesystem: An Ext2 driver.
Standalone Support Libraries
Standalone support libraries under libs/ compile independently of the kernel logic:
- kstd: A custom standard library containing containers, support infrastructure, and printing/formatting implementations in lieu of a hosted standard library.
- multiboot2: A Multiboot2 structure parser.
- acpi: An ACPI parsing utility.
- elf: An ELF file format parser.
Semester & Bachelor's Thesis Opportunities
Due to its simple and educational design, TeachOS lacks several advanced OS features. This makes the kernel an excellent playground for semester projects and Bachelor's theses. The following list outlines potential areas of development, highlighting the architectural dependencies between key systems:
Multitasking, User Space, and System Calls
There is a direct dependency between process/thread abstractions and the implementation of user mode execution. To run separate user applications, the kernel must manage task states, perform context switches, and handle system calls. Conversely, user space isolation requires page table management and hardware privilege levels. These projects should be approached sequentially or as a joint effort:
- Kernel Multitasking (Cooperative and Preemptive):
- Scope: Design a Thread Control Block (TCB) and Process Control Block (PCB) structure. Implement low-level stack setup and context switching in assembly for the active CPU.
- Extension: Develop a task scheduler (e.g., Round-Robin, Priority-based, or Multi-Level Feedback Queue) utilizing the local APIC timer for preemptive multitasking.
- User Mode Isolation and System Call Interface:
- Prerequisite: A basic multitasking or thread control subsystem.
- Scope: Implement user-kernel privilege transitions (Ring 3 to Ring 0) utilizing platform-specific instructions. Configure page tables to separate user space virtual memory from the higher-half kernel mapping.
- Extension: Establish a system call dispatcher routing file and memory operations from user space to the corresponding kapi/ implementations.
Platform Ports (64-bit Architectures)
TeachOS currently targets only 64-bit x86 (x86_64). To validate the platform-independence of the kapi/ interface, ports to other 64-bit targets are highly encouraged:
- ARM64 (AArch64) Port:
- Scope: Implement the platform-defined KAPI interfaces for a 64-bit ARM target (e.g., QEMU virt board or Raspberry Pi 4). This includes writing the boot startup assembly, configuring the translation table (MMU paging), handling the Generic Interrupt Controller (GIC), and implementing timer ticks.
- RISC-V 64-bit (RV64G) Port:
- Scope: Port TeachOS to the RISC-V 64-bit architecture. This involves implementing boot assembly, configuring page table mappings (Sv39/Sv48), setting up the Core Local Interruptor (CLINT) and Platform-Level Interrupt Controller (PLIC), and managing supervisor/user mode transitions.
Memory Management Subsystem Extensions
The current memory management uses a basic bitmap page frame allocator and a first-fit heap allocator. There are significant opportunities to implement standard production-grade memory management schemes:
- Buddy Page Allocator:
- Scope: Replace the current bitmap_frame_allocator with a Buddy Allocator system. This manages memory allocations in power-of-two page sizes, significantly reducing external fragmentation and improving allocation speed.
- Slab/Slub/Slob Object Allocator:
- Scope: Implement a slab allocator on top of the physical page allocator. This caches kernel objects of identical size (such as inodes, file descriptors, and thread control blocks) to avoid constant heap fragmentation and overhead from the general-purpose block_list_allocator.
- Advanced Virtual Memory (Copy-on-Write, Demand Paging):
- Prerequisite: A basic thread multitasking subsystem.
- Scope: Implement a page fault handler that dynamically loads executable segments only when touched (demand paging), or implement copy-on-write page table sharing (crucial for implementing Unix-like fork semantics).
Filesystem Support and VFS Extensions
The Virtual File System (VFS) is designed to host multiple concurrent filesystem types, but support is currently limited. Project opportunities here include implementing new drivers or core VFS caching features:
- Ext2 Write Support and Dynamic Allocation (already available in experimental stage):
- Scope: Extend the read-oriented ext2 driver to support full write operations. This requires managing free inode and block bitmaps, updating directories, allocating data blocks dynamically, and maintaining superblock consistency.
- New Filesystem Drivers (e.g., FAT32, ISO 9660):
- Scope: Implement new filesystem drivers from scratch (such as FAT32 or ISO 9660 for CD-ROMs), allowing TeachOS to interoperate with standard virtual media and flash drives.
- Unified Page Cache and Directory Entry Cache:
- Scope: Develop a page caching subsystem that intercepts read/write VFS calls, caching recently accessed filesystem blocks in physical memory frames, and optimize pathname lookup times using a dynamic directory entry (dentry) cache.
- Virtual Filesystems (e.g., procfs, sysfs):
- Scope: Create virtual filesystems that dynamically generate contents from current kernel data structures, providing userspace with debugging and configuration access interfaces.
Hardware Buses and Device Drivers
Currently, block storage is simulated via RAM disks loaded as boot modules. Real hardware interaction requires expanding driver support:
- PCI/PCIe Bus Discovery:
- Scope: Develop a PCI/PCIe bus driver that scans configuration spaces, detects connected devices, and registers them to the virtual root bus using the kapi::devices interface.
- Storage Controller Drivers (AHCI/SATA or NVMe):
- Prerequisite: PCI bus discovery.
- Scope: Write a driver for SATA controllers (AHCI) or modern NVMe drives, routing block read/write operations from the VFS to actual physical disks.
- Network Stack and Driver Integration:
- Scope: Interface with a network adapter (e.g., Intel e1000 or VirtIO-net), and develop a lightweight network stack (ARP, IPv4, UDP) to allow TeachOS to send and receive raw network frames.
