2026-05-14 14:57:00 +02:00
2026-05-14 14:57:00 +02:00
2026-05-14 14:57:00 +02:00
2026-05-14 14:57:00 +02:00

NT-Lite -- an x86-64 kernel

Boots. Runs processes. Mimics Windows to some extent.

what is it?

NT-Lite is a 64-bit operating system kernel written from scratch. It includes a UEFI bootloader, physical and virtual memory managers, a preemptive scheduler, a HAL, a VFS, a PE loader, and partial Win32 and POSIX layers. It boots into a shell.

The codebase is roughly 20k lines of C and assembly.

features

  • UEFI bootloader
  • physical memory manager
  • virtual memory manager with kernel pool
  • HAL for screen, keyboard, mouse, timer, disk, PCI, and APIC
  • preemptive scheduler with priority levels
  • processes and threads
  • VFS with IRPs
  • drive-letter paths such as 0:\apps\shell.exe
  • INI-based boot and driver configuration
  • PE import resolution and dynamic driver loading
  • partial Win32 personality
  • partial POSIX personality

architecture notes

memory layout

NT-Lite uses a single virtual address space per booted system rather than a fully separate kernel address space and user address space. The distinction between kernel and user mode comes from page permissions and CPU privilege checks, not from having a different page table for the kernel.

The kernel is mapped into the higher half of virtual memory and user processes only receive the regions they are explicitly granted. Kernel pages are marked supervisor-only, so user-mode code cannot read or write them directly. User pages are mapped with user permissions and are isolated from one another by the kernel’s allocator, VMM, and process creation path.

boot chain

The bootloader reads configuration, loads the core images, maps the higher-half layout, and hands control to KernelMain. After that, the kernel takes over interrupt setup, paging, scheduler bring-up, runtime driver loading, and user process launch.

drivers

Drivers are PE32+ .sys files with a conventional DriverEntry export that accepts a pointer to HAL_API.

Drivers are split into two groups:

  • essential boot drivers, which are loaded before the kernel starts doing real work
  • runtime drivers, which are loaded later from disk once storage and the VFS are available

The driver model is intentionally small. Disk drivers expose a DISK_DRIVER vtable and register with IoRegisterDisk(index, &driver). Filesystem drivers expose an IO_FILESYSTEM vtable and register with IoRegisterFilesystem(index, &fs, &vol).

Currently shipping: AHCI (interrupts), IDE (PIO/DMA), and FAT32.

I/O and filesystems

All file access flows through the VFS layer. That keeps disk access, filesystem parsing, and path translation separate instead of spreading storage logic across the rest of the kernel.

Paths are not interpreted as Windows paths by default. A drive such as 0:\ is a mounted namespace, while the Win32 and POSIX personalities translate their own path styles into the same underlying VFS.

processes, threads, and syscalls

User processes are launched from PE images, imports are resolved before the first thread is queued, and the syscall layer provides the boundary between user code and kernel services. syscall.dll is the shared entry point for the supported personalities.

The scheduler is preemptive and priority-based, so threads do not depend on cooperative yielding to keep the system responsive. Process state is tracked separately from thread state, which allows a process to exit, be reaped, or be restarted by init without bringing down the rest of the system.

personalities

The Win32 personality supports programs that expect drive letters, familiar process APIs, and a Windows-style runtime. The POSIX personality maps the same kernel primitives into a tree-shaped namespace and a different userspace contract.

how it boots

  1. UEFI loads boot.ini and reads drivers.ini
  2. the bootloader maps the kernel, HAL, and boot drivers into the upper half
  3. a direct physical window is mapped at 0xFFFF880000000000
  4. control passes to KernelMain
  5. PMM, VMM, GDT, IDT, HAL, IRQs, and scheduler initialization run
  6. runtime drivers are loaded from disk
  7. shell.exe is launched

how to build

  • open the VS x64 build tools as administrator
  • change into this directory
  • run build.bat
  • use one of run.bat (IDE), rund.bat (IDE, debug), runa.bat (AHCI), or runad.bat (AHCI, debug)

paths

"apps\shell.exe"      -> current working directory
"0:\apps\shell.exe"   -> drive 0
"2:\data\config.ini"  -> drive 2

Drives 0-7 are available. A drive only works if a filesystem is registered on it. The Win32 personality translates drive letters to drive numbers, while the POSIX personality maps drives onto a tree.

screenshots

video.exe running bink video 2

Boot logs
BdsDxe: loading Boot0001 "UEFI QEMU HARDDISK QM00005 " from PciRoot(0x0)/Pci(0x4,0x0)/Sata(0x0,0xFFFF,0x0)
BdsDxe: starting Boot0001 "UEFI QEMU HARDDISK QM00005 " from PciRoot(0x0)/Pci(0x4,0x0)/Sata(0x0,0xFFFF,0x0)
1
2
3
4
Loading colonel.exe...
Loading hal.dll...
5
6
7
8
Found RSDP at: 0xF77E014
9
HAL: screen 1280x800
HAL: FADT PM1a_CNT=0xb004 PM1b_CNT=0x0000 DSDT=0x0f77a000
HAL: _S5_ SLP_TYP_A=0x00 SLP_TYP_B=0x00
HAL: LAPIC=00000000fee00000 IOAPIC=00000000fec00000 HPET=00000000fed00000
HAL: lapicPhys=0xFEE00000, lapicVirt=0xFFFF8800FEE00000, hpetPhys=0xFED00000
HAL: Attempting to calibrate APIC timer via HPET...
HAL: APIC timer: 62981 ticks/ms
HAL: initialisation complete.
KernelMain: Handing over to scheduler...
SystemInitThread: Thread started. Igniting the system...
InitializeDrivers: Initializing drivers...
InitializeDrivers: Executing DriverEntry for ide.sys
IDE: Init
IDE: No drive on primary channel
InitializeDrivers: Driver ide.sys failed to init!
InitializeDrivers: Executing DriverEntry for ahci.sys
AHCI: driver loading...
AHCI: controller at PCI 00:04.0
AHCI: PCI IRQ line = 11
AHCI: ABAR phys=0x81060000 version=0x00010000
AHCI: cap=0xc0141f05  ports=6  slots=32  64bit=1
AHCI: port 0: link up, initializing...
AHCI: port COMRESET done: sig=0x00000101 ssts=0x00000113
AHCI: drive 0: 524288 sectors (256 MB)
AHCI: drive 0 registered
AHCI: port 1: no link (ssts=0x00000000)
AHCI: port 2: no link (ssts=0x00000000)
AHCI: port 3: no link (ssts=0x00000000)
AHCI: port 4: no link (ssts=0x00000000)
AHCI: port 5: no link (ssts=0x00000000)
AHCI: ISR registered on IRQ 11; initialised 1 drive(s)
InitializeDrivers: Executing DriverEntry for fat32.sys
FAT32: Init
FAT32: Init complete (status=0, clusters=128480).
Found runtime driver: usb.sys
Test runtime driver
SystemInitThread: Loading system DLLs...
Memory Status:
  -> Free (PMM):   151.71 MB
  -> Kernel Pool:  4.00 MB
  -> User Heap:    0.55 MB
LaunchUserProcess: IoOpenFile: 0
LaunchUserProcess: IoGetFileSize: 5120
LaunchUserProcess: MmAllocateUserMemory: 0x8E020
LaunchUserProcess: IoReadFile: 0
LaunchUserProcess: IoCloseFile
Created process (PID 2) with command line: init.exe
LaunchUserProcess: PE Image mapped! Base 0x90020, Entry 0x91600
LaunchUserProcess: Thread created and queued!
[init] starting
[init] waiting
shell: ready
> help
Available commands:
  help              - Show this list
  dir               - List files
  cd <path>         - Change directory
  type <file>       - Display file contents
  del <file>        - Delete a file
  write <file> <tx> - Create a file with text
  exit              - Close the shell
> dir
System Volume Information
drivers
efi
colonel.exe
hal.dll
syscall.dll
win32.dll
posix.dll
init.exe
shell_win32.exe
shell_posix.exe
shell_native.exe
doom.exe
video.exe
boot.ini
bink2w64.dll
video.bk2
doom1.wad
> shell_win32.exe
shell: ready
shell_win32.exe
> doom.exe
doom: starting
getenv: Unknown variable DOOMWADDIR
                            DOOM Shareware Startup v1.10
V_Init: allocate screens.
M_LoadDefaults: Load system defaults.
Z_Init: Init zone memory allocation daemon.
W_Init: Init WADfiles.
 adding ./doom1.wad
===========================================================================
                                Shareware!
===========================================================================
M_Init: Init miscellaneous info.
R_Init: Init Doom refresh daemon - [..                 ]
InitTextures
InitFlats........
InitSprites
InitColormaps
R_InitData
R_InitPointToAngle
R_InitTables
R_InitPlanes
R_InitLightTables
R_InitSkyMap
R_InitTranslationsTables
P_Init: Init Playloop state.
I_Init: Setting up machine state.
I_InitSound: I_InitSound:  pre-cached all sound data
I_InitSound: sound module ready
D_CheckNetGame: Checking network game status.
startskill 2  deathmatch: 0  startmap: 1  startepisode: 1
player 1 of 1 (1 nodes)
S_Init: Setting up sound.
S_Init: default sfx volume 8
HU_Init: Setting up heads up display.
ST_Init: Init status bar.
doom: entering game loop
I_ShutdownSound: NOT finishing pending sounds
> shell_posix.exe
shell: ready
> help
Available commands:
  help               - Show this list
  dir [path]         - List directory contents
  cd <path>          - Change directory
  type <file>        - Display file contents
  del <file>         - Delete a file
  write <file> <txt> - Create a file with text
  exit              - Close the shell
> dir
      System Volume Information
      drivers
      efi
      colonel.exe
      hal.dll
      syscall.dll
      win32.dll
      posix.dll
      init.exe
      shell_win32.exe
      shell_posix.exe
      shell_native.exe
      doom.exe
      video.exe
      boot.ini
      bink2w64.dll
      video.bk2
      doom1.wad
      .doo
> video.exe
video: starting
video.exe
video: video.bk2 loaded
shell: goodbye
> exit
shell: goodbye
> exit
shell: goodbye
> exit
shell: goodbye
[init] done
ProcessWatcherThread: Process "init.exe" (PID 2) exited with code 0.
ProcessWatcherThread: Shutting down.

faq

Q: Why?
A: Learning. Fun.

Q: Does it run Doom?
A: doom.exe

Q: Is the Win32 layer real?
A: Real enough to load binaries that expect it. Not real enough to run Notepad.

Q: Are processes isolated?
A: No. But IPC is free.

Q: Is this finished?
A: No.

Will it corrupt my data? A: It shouldn't.

Q: Why is the path syntax so weird?
A: It makes sense to me.

Q: Why are the logs so verbose?
A: How else do I debug it?

Q: What should I read first?
A: This document.

Q: Can I use this in production?
A: Don't.

S
Description
No description provided
Readme
37 MiB
0 Stars 1 Watchers 0 Forks
Languages
C 98.9%
Assembly 0.9%
C++ 0.1%