I've been doing OS development in NASM on and off for years.
Recently, I restarted an x86-64 hobby OS project from scratch, with one deliberate difference: I'm using an LLM as a development partner.
This is not an "AI generated an OS in five minutes" project.
The project uses architecture and platform specifications to define expected behaviour, and physical hardware to validate the implementation.
My basic rules are:
- Check hardware-facing structures, offsets and bitfields against specifications or reliable technical references.
- Validate each development step before moving on.
- Generated code is not accepted simply because it compiles.
- Investigate and correct failures before continuing.
- Avoid giant generated code dumps containing several unfinished subsystems.
Development environment and hardware
The entire build process currently runs on Windows 11, using NASM and LLVM's lld-link to produce PE32+ x86-64 UEFI executables.
No Linux host is involved.
The physical development machine is:
Code: Select all
CPU: AMD Ryzen 5 9600X
Zen 5 / Granite Ridge
Motherboard: ASUS TUF GAMING B850-PLUS WIFI
RAM: 32 GiB
Graphics: AMD integrated graphics
NVIDIA GeForce RTX 5050
Boot: Native UEFI
Language choices
The current system is still written primarily in NASM.
I originally wanted to write the entire OS in assembly. Over time, however, I found myself building increasingly elaborate NASM macros to express structures that were no longer especially assembly-specific.
That changed how I think about language choice.
Assembly is particularly useful when the exact machine operations are part of the problem being understood. For other subsystems, the structure of the problem may eventually matter more than the exact instruction sequence.
So my current rule is:
For more structurally complex subsystems, the language will be chosen module by module rather than imposing an "assembly at all costs" rule.Use assembly when the exact machine operations are part of the problem being understood.
Use a higher-level language only when assembly can no longer express the problem clearly without adding unnecessary machinery.
Milestone 1 — UEFI GOP framebuffer
Status: PASS on physical hardware
Validated path:
Code: Select all
ASUS UEFI
|
v
\EFI\BOOT\BOOTX64.EFI (PE32+ x86-64)
|
v
NASM entry point
|
v
EFI_BOOT_SERVICES
|
v
LocateProtocol()
|
v
Graphics Output Protocol (GOP)
|
v
Framebuffer information
|
v
Direct pixel writes
The firmware display is replaced by a full-screen dark gray background with a small fixed white triangular software cursor near the upper-left corner:
Code: Select all
┌──────────────────────────────┐
│ dark gray background │
│ │
│ ◢ small white cursor │
│ │
│ │
└──────────────────────────────┘
It is intentionally primitive and serves as a rendering test. There is no keyboard or mouse input yet.
Booting on physical hardware
There is no installer.
The OS boots as a standard UEFI removable-media application from a dedicated USB flash drive and does not access the internal SSD containing Windows.
Until the boot path is stable, I prefer keeping it separate from the Windows EFI System Partition.
Breaking a disposable USB flash drive is considerably funnier than breaking Windows Boot Manager.
1. Prepare the USB drive
Format a spare USB flash drive as FAT32, create the standard x86-64 UEFI removable-media directory, and copy the generated executable as:
Code: Select all
\EFI\BOOT\BOOTX64.EFI
Code: Select all
mkdir X:\EFI\BOOT
copy /Y build\BOOTX64.EFI X:\EFI\BOOT\BOOTX64.EFI
2. Configure the firmware
My development configuration is:
Code: Select all
UEFI ON
CSM OFF
Secure Boot OFF
TPM ON, but unused by the OS
TPM remains enabled but is currently ignored by the OS.
ASUS configuration example
On my ASUS TUF GAMING B850-PLUS WIFI, the relevant setting is:
Code: Select all
UEFI Setup
-> Boot
-> Secure Boot
-> OS Type
Code: Select all
Windows UEFI mode -> Secure Boot enabled
Other OS -> Secure Boot disabled
Windows System Information (msinfo32) reports:
Code: Select all
BIOS Mode: UEFI
Secure Boot State: Off
ASUS — How to Enable/Disable Secure Boot
Source code
I've attached the complete source code for this stage, including:
- NASM source and UEFI definitions
- Windows build script and PE32+ EFI generation
- GOP framebuffer access
- Fixed software cursor rendering
Next milestone — Leaving Boot Services
The next target is:
Code: Select all
GetMemoryMap()
|
v
Prepare boot information
|
v
ExitBootServices()
|
v
Continue executing independently
|
v
Keep rendering to the existing framebuffer
Roadmap
The current direction is approximately:
Code: Select all
UEFI
|
+-- GOP / framebuffer [PASS]
|
+-- GetMemoryMap / ExitBootServices [NEXT]
|
+-- CPU / memory / interrupts
|
+-- ACPI
| |
| +-- RSDP
| +-- XSDT
| +-- MCFG
|
+-- PCI Express
| |
| +-- ECAM
| +-- bus/device/function enumeration
| +-- Vendor ID / Device ID
| +-- Class / Subclass / ProgIF
| +-- BAR / MMIO discovery
|
+-- Review PCIe / BAR foundation
|
+-- xHCI
| |
| +-- USB
| +-- HID
| +-- keyboard
| +-- mouse
|
+-- Movable software cursor
|
+-- Eventually, a graphical environment

