<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Florent Herisson</title>
    <description>The latest articles on DEV Community by Florent Herisson (@florent_herisson_691b0bac).</description>
    <link>https://dev.to/florent_herisson_691b0bac</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3702181%2F8e829aaf-15ed-4eb2-bfd1-812060d6d80b.jpg</url>
      <title>DEV Community: Florent Herisson</title>
      <link>https://dev.to/florent_herisson_691b0bac</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/florent_herisson_691b0bac"/>
    <language>en</language>
    <item>
      <title>The Care and Feeding of Interrupt Handlers</title>
      <dc:creator>Florent Herisson</dc:creator>
      <pubDate>Sun, 11 Jan 2026 01:00:57 +0000</pubDate>
      <link>https://dev.to/florent_herisson_691b0bac/the-care-and-feeding-of-interrupt-handlers-4gai</link>
      <guid>https://dev.to/florent_herisson_691b0bac/the-care-and-feeding-of-interrupt-handlers-4gai</guid>
      <description>&lt;h1&gt;
  
  
  The Care and Feeding of Interrupt Handlers
&lt;/h1&gt;

&lt;p&gt;Dear diary,&lt;/p&gt;

&lt;p&gt;Today I decided to give my embryonic operating system a voice. Not literally—that would be terrifying—but an interactive shell so it could at least complain about its existence in real time. What started as an innocent afternoon project turned into another reminder that hardware and I have what therapists might call "trust issues."&lt;/p&gt;

&lt;p&gt;The plan seemed reasonable enough: create a simple command prompt that could poke around the system hardware. You know, basic things like "what PCI devices do we have" and "where did all my memory go." The sort of diagnostic tools that separate a proper OS kernel from what is essentially a very expensive screensaver.&lt;/p&gt;

&lt;p&gt;I'd already conquered the Herculean task of drawing pixels to the screen—my proudest achievement to date—so surely adding keyboard input couldn't be that much harder. The UEFI specification even provides nice abstractions for this sort of thing. Just read from ConIn, echo characters back, handle a few special keys. How hard could it be?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Narrator: It was exactly as hard as he expected, which somehow made it worse.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The shell implementation started promisingly. I created a neat little input loop that waits for keyboard events, echoes printable characters, and handles backspace with the sort of careful buffer management that would make my CS professors weep with pride. The command parser splits input on spaces and dispatches to handler functions. Clean, simple, maintainable code.&lt;/p&gt;

&lt;p&gt;The first command I implemented was 'help', because I am fundamentally unoriginal. Then 'clear' to wipe the screen, because watching text scroll off into the void makes me existentially uncomfortable. Then 'reboot' and 'halt', because sometimes you need an escape hatch when your creation develops delusions of grandeur.&lt;/p&gt;

&lt;p&gt;But the real meat was going to be hardware inspection. I wanted my OS to survey its domain like a new homeowner checking what's actually in the basement. This meant implementing PCI bus scanning—the digital equivalent of opening every cabinet and drawer to see what's inside.&lt;/p&gt;

&lt;p&gt;PCI scanning is one of those things that sounds impressive but is really just systematic brute force. You iterate through every possible bus, device, and function combination, poking at I/O ports 0xCF8 and 0xCFC to see if anything responds. It's like knocking on doors in a very large, mostly empty apartment building, except some of the residents are graphics cards with anger management issues.&lt;/p&gt;

&lt;p&gt;The beautiful thing about PCI is that it's completely standardized. Every device announces itself with a vendor ID, device ID, and class code. I built a little database of known hardware—Intel chipsets, NVIDIA graphics, Realtek network controllers—so my OS could recognize the residents of its new digital neighborhood.&lt;/p&gt;

&lt;p&gt;Testing this on my Aorus X3 laptop was like introducing two socially awkward people at a party. My kernel politely requested a list of PCI devices, and the hardware responded with what I can only describe as a comprehensive résumé of every chip on the motherboard. Intel Haswell DRAM controller at 00:00.0, HD Graphics 4600 at 00:02.0, SATA controller at 00:1F.2—a complete census of silicon citizens.&lt;/p&gt;

&lt;p&gt;But wait, there's more. Because I apparently enjoy complications, I also implemented memory map inspection. UEFI kindly provides a GetMemoryMap function that tells you exactly how your system's RAM is carved up. Conventional memory here, boot services there, runtime services over there, and a suspiciously large chunk marked "Reserved" that's probably hiding something important.&lt;/p&gt;

&lt;p&gt;The memory display shows you the harsh reality of modern computing: out of your gigabytes of RAM, a shocking amount is already spoken for before your OS even gets to first base. Boot services code, ACPI tables, MMIO regions—it's like buying a house and discovering the previous owner left all their furniture with notes saying "DO NOT MOVE."&lt;/p&gt;

&lt;p&gt;When I finally built the whole thing, the output was satisfying in that uniquely developer way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[CC] src/lib/shell.c
[CC] src/lib/pci.c
[LD] deploy/BOOTX64.EFI
Build complete. Output: deploy/BOOTX64.EFI (27,648 bytes)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From 21KB to 27KB. My kernel was growing up, developing personality. Or at least the ability to introspect about its own existential crisis.&lt;/p&gt;

&lt;p&gt;The moment of truth came when I booted the USB drive on real hardware. The familiar ChronOS banner appeared, my console initialized properly, and then... a command prompt. Blinking cursor. Waiting for input.&lt;/p&gt;

&lt;p&gt;I typed 'help' and held my breath.&lt;/p&gt;

&lt;p&gt;The command list appeared instantly. No crashes, no triple faults, no mysterious reboots. Just a clean list of available commands like a proper operating system might display. I felt that peculiar mixture of relief and disbelief that accompanies any successful interaction with x86 hardware.&lt;/p&gt;

&lt;p&gt;The 'pci' command was the real test. When I pressed enter, I could practically hear the kernel methodically knocking on every door in the PCI address space. A moment later, a neat table appeared:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bus:Dev.Fn  Vendor:Device  Class     Description
00:00.0     8086:0C00      06:00     Intel Haswell DRAM
00:02.0     8086:0416      03:00     Intel HD Graphics 4600
00:1F.2     8086:8C03      01:06     Intel 8 Series SATA (AHCI)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My OS was actually talking to the hardware and getting sensible responses. It knew about the integrated graphics, the SATA controller, even the wireless adapter. Like finally having a proper conversation with someone you'd only exchanged awkward nods with in the hallway.&lt;/p&gt;

&lt;p&gt;The 'mem' command revealed the brutal economics of system memory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Type                Start        Pages     Size
Conventional        00100000     156238    629 MB
BootServicesData    26F64000     8         32 KB
Reserved            FED00000     1024      4 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Out of several gigabytes, only about 629MB was marked as "conventional"—free for my OS to use however it pleased. The rest was a complicated web of reservations, runtime services, and hardware mappings. Like discovering your new apartment comes with seventeen different HOA fees.&lt;/p&gt;

&lt;p&gt;The logging system faithfully captured everything in UTF-16 format on the USB drive. When I decoded BOOTLOG_002.txt later, I could see the complete conversation between my shell and the hardware, preserved for posterity like a transcript of humanity's first contact with an alien civilization. Except the aliens were PCI devices and they mostly wanted to talk about their vendor IDs.&lt;/p&gt;

&lt;p&gt;What struck me most was how routine it all felt once it worked. The shell accepted commands, parsed them correctly, executed the appropriate functions, and displayed results. The very definition of "working as intended." No drama, no last-minute debugging sessions, no mysterious crashes at 2am.&lt;/p&gt;

&lt;p&gt;This is perhaps the strangest part of OS development: the profound satisfaction when something mundane actually works. I'd built an interactive shell that could inspect its own hardware environment. Not exactly revolutionary—every operating system since the 1970s has had this capability—but mine did it too, and that felt like joining a very exclusive club.&lt;/p&gt;

&lt;p&gt;The PCI scanner found every device on the motherboard. The memory mapper correctly interpreted UEFI's memory layout. The command parser handled edge cases gracefully. All the careful buffer management and input validation paid off in boring, reliable functionality.&lt;/p&gt;

&lt;p&gt;As I typed 'halt' to end the session, watching my OS politely save its log file and shut down the CPU, I realized I'd crossed another small threshold in this quixotic project. My kernel could now have conversations, even if they were mostly about hardware specifications and memory addresses.&lt;/p&gt;

&lt;p&gt;Next comes the real challenge: storage. The SATA controller is sitting right there at 00:1F.2, advertising its AHCI capabilities like a résumé. Time to teach my OS to read and write actual data, to persist information beyond the fragile boundary of system reboot.&lt;/p&gt;

&lt;p&gt;But that's tomorrow's problem. Tonight, I have a working shell and a sense of cautious optimism that I haven't completely lost my mind building an operating system in 2026.&lt;/p&gt;

&lt;p&gt;The blinking cursor awaits.&lt;/p&gt;




&lt;h1&gt;
  
  
  osdev #programming #interrupts #lowlevel #bootloader #uefi #memorymanagement #assembly #x86_64 #debugging
&lt;/h1&gt;

</description>
      <category>osdev</category>
      <category>programming</category>
      <category>interrupts</category>
      <category>lowlevel</category>
    </item>
    <item>
      <title>Page Tables: A Love Story (It's Not)</title>
      <dc:creator>Florent Herisson</dc:creator>
      <pubDate>Sat, 10 Jan 2026 04:42:08 +0000</pubDate>
      <link>https://dev.to/florent_herisson_691b0bac/page-tables-a-love-story-its-not-4286</link>
      <guid>https://dev.to/florent_herisson_691b0bac/page-tables-a-love-story-its-not-4286</guid>
      <description>&lt;p&gt;Dear diary, today I discovered that leaving the comfortable embrace of UEFI is like moving out of your parents' house at 40. Everything that used to work magically now requires you to actually understand how the world functions.&lt;/p&gt;

&lt;p&gt;It was 9am when I sat down with my coffee, confident that transitioning from UEFI to bare metal would be straightforward. After all, I had successfully implemented AHCI storage and a key-value store. How hard could it be to set up a Global Descriptor Table and start running my own kernel? The hubris was palpable.&lt;/p&gt;

&lt;p&gt;The plan seemed reasonable: call ExitBootServices, set up a proper GDT for 64-bit long mode, get polling keyboard input working, and run a kernel shell. I'd even built a logging system that writes directly to the SSD so I could debug across reboots. What could possibly go wrong?&lt;/p&gt;

&lt;p&gt;Everything. Everything could go wrong.&lt;/p&gt;

&lt;p&gt;The first attempt was promising. ExitBootServices succeeded, the GDT loaded without complaint, and I was running in kernel mode. I could even see my kernel shell prompt. Victory seemed assured until I tried to enable interrupts with a confident &lt;code&gt;sti&lt;/code&gt; instruction.&lt;/p&gt;

&lt;p&gt;The machine triple-faulted immediately.&lt;/p&gt;

&lt;p&gt;Now, a triple fault is the x86 processor's way of saying "I give up, you're on your own" before performing the digital equivalent of flipping the table and storming out. It's simultaneously the most and least helpful error condition - you know something is catastrophically wrong, but the CPU has decided that telling you what would be too much effort.&lt;/p&gt;

&lt;p&gt;I spent the next two hours in what I like to call the "interrupt denial phase." Surely it wasn't the interrupts themselves. Maybe the GDT was wrong. I rewrote it three times, each iteration more baroque than the last. Maybe the stack was corrupted. I added stack canaries and verification code. Maybe UEFI had left some state that was interfering. I tried clearing every register I could think of.&lt;/p&gt;

&lt;p&gt;The machine continued to triple fault with the same mechanical precision that I continued to make coffee.&lt;/p&gt;

&lt;p&gt;By noon, I had accepted that interrupts were indeed the problem and decided to punt. Polling keyboard input wasn't elegant, but it would work. I implemented a simple PS/2 controller polling loop and got basic keyboard input working. The kernel shell was functional, and I could even save logs to the SSD. Milestone 5 was technically complete, but it felt like winning a race by getting out and pushing the car across the finish line.&lt;/p&gt;

&lt;p&gt;But you know what they say about kernel development - if you're not moving forward, you're moving backward into a triple fault. So naturally, I decided to tackle interrupts properly for Milestone 6.&lt;/p&gt;

&lt;p&gt;The afternoon was spent in the IDT mines, crafting interrupt service routines with the careful precision of a medieval scribe copying manuscripts. I wrote elegant macro systems that generated perfect stack frames. I created sophisticated handlers that could gracefully manage any interrupt condition. The code was beautiful, abstracted, and completely broken.&lt;/p&gt;

&lt;p&gt;The first test with interrupts enabled produced a Debug Exception (Vector 1) immediately after &lt;code&gt;sti&lt;/code&gt;. This was actually progress - instead of a triple fault, I was getting a specific exception. The CPU was at least trying to tell me what was wrong, even if what it was telling me made no sense.&lt;/p&gt;

&lt;p&gt;Debug exceptions fire when you hit a debug register breakpoint or when the trap flag is set for single-stepping. I wasn't using any debugger, and I certainly hadn't set the trap flag intentionally. But x86 processors are like that relative who remembers every slight from thirty years ago - they hold onto state in the most inconvenient places.&lt;/p&gt;

&lt;p&gt;It took me another hour to realize that UEFI might have left debugging state enabled. I added code to clear all the debug registers (DR0 through DR7) and the trap flag in RFLAGS. The debug exception disappeared, but now I had a new problem: the timer interrupt wasn't firing.&lt;/p&gt;

&lt;p&gt;This began what I now refer to as "the silent treatment phase" of debugging. The PIC was configured, the IDT was set up, interrupts were enabled, but my timer tick counter remained stubbornly at zero. The system wasn't crashing, which was somehow more frustrating than when it was exploding spectacularly.&lt;/p&gt;

&lt;p&gt;I verified the PIC configuration seventeen times. I read Intel manuals until my eyes bled. I checked and rechecked the IDT entries. Everything looked correct on paper, but the hardware seemed to be politely ignoring my carefully crafted interrupt handlers.&lt;/p&gt;

&lt;p&gt;The breakthrough came at 6pm when I was explaining the problem to my rubber duck (a literal rubber duck I keep on my desk for debugging purposes - don't judge). As I described my elegant ISR macro system, I realized the problem: I was being too clever.&lt;/p&gt;

&lt;p&gt;My macros were generating complex stack frame management code that was somehow corrupting the interrupt return address. When I looked at the actual assembly output, it was a nightmare of stack manipulation that would make a spaghetti factory jealous.&lt;/p&gt;

&lt;p&gt;So I threw it all away and wrote the simplest possible interrupt handlers using naked functions with inline assembly. No fancy macros, no elegant abstractions, just the bare minimum code to handle an interrupt and return cleanly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;__attribute__((naked)) void isr_timer(void) {
    asm volatile (
        "push %rax\n"
        "incq g_timer_ticks\n"
        "movb $0x20, %al\n"
        "outb %al, $0x20\n"  // Send EOI
        "pop %rax\n"
        "iretq"
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It was inelegant. It was primitive. It worked perfectly.&lt;/p&gt;

&lt;p&gt;The moment I enabled interrupts with the new handlers, the timer immediately started ticking at exactly 100 Hz. The keyboard interrupt began capturing input flawlessly. After eight hours of fighting with sophisticated abstractions, the solution was to write interrupt handlers like it was 1985.&lt;/p&gt;

&lt;p&gt;There's something profoundly humbling about spending an entire day implementing "modern" kernel architecture only to discover that the most primitive approach is the most reliable. It's like spending hours crafting a gourmet meal and then realizing that a peanut butter sandwich would have been both more satisfying and less likely to poison you.&lt;/p&gt;

&lt;p&gt;By evening, I had a fully functional interrupt-driven kernel. The timer was ticking, the keyboard was responsive, and the kernel shell worked flawlessly. I could watch the timer ticks increment in real-time, each one a small victory over the chaos of bare metal programming.&lt;/p&gt;

&lt;p&gt;The final test was letting the system run while I went to make dinner. When I returned, the timer showed 3,432 ticks - exactly 34 seconds of stable operation. No crashes, no mysterious hangs, no triple faults. Just a kernel quietly doing its job, handling dozens of interrupts per second with the reliability of a Swiss timepiece.&lt;/p&gt;

&lt;p&gt;I saved the kernel log to review later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[KERNEL] Enabling interrupts (STI)...
[KERNEL] Interrupts ENABLED.
[KERNEL] Timer ticks after delay: 199
[KERNEL] Kernel mode active (interrupt mode)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those simple log messages represent eight hours of debugging, three complete rewrites of the interrupt system, and more coffee than any human should consume in a single day. But they also represent something more: a functioning kernel that has successfully transitioned from UEFI's protective embrace to the harsh reality of bare metal operation.&lt;/p&gt;

&lt;p&gt;Looking back, the lessons are clear. First, x86 processors remember everything and forgive nothing - always clear the debug registers when transitioning from UEFI. Second, the PIC hasn't changed significantly since the 1980s, and trying to abstract away its quirks usually makes things worse. Third, when sophisticated solutions fail, sometimes the answer is to write code like it's three decades ago.&lt;/p&gt;

&lt;p&gt;Most importantly, I learned that there's a particular satisfaction in building something from first principles, even when those principles seem designed to maximize human suffering. Every successful interrupt is a small victory over the entropy of the universe. Every timer tick is proof that somewhere in the chaos of transistors and electrons, my code is executing exactly as intended.&lt;/p&gt;

&lt;p&gt;Tomorrow I'll tackle content-addressed storage and time travel debugging. Because apparently, I haven't suffered enough yet, and the beauty of hobby OS development is that there's always another layer of complexity waiting to humble you.&lt;/p&gt;

&lt;p&gt;But tonight, I'm going to sit here and watch my timer tick counter increment, one interrupt at a time, and pretend that building an operating system is a reasonable way to spend one's free time.&lt;/p&gt;




&lt;h1&gt;
  
  
  osdev #programming #virtualmemory #x86 #interrupts #lowlevel #bootloader #uefi #assembly #x86_64
&lt;/h1&gt;

</description>
      <category>osdev</category>
      <category>programming</category>
      <category>virtualmemory</category>
      <category>x86</category>
    </item>
    <item>
      <title>From Power-On to 'Oh No'</title>
      <dc:creator>Florent Herisson</dc:creator>
      <pubDate>Fri, 09 Jan 2026 21:18:36 +0000</pubDate>
      <link>https://dev.to/florent_herisson_691b0bac/from-power-on-to-oh-no-3hpg</link>
      <guid>https://dev.to/florent_herisson_691b0bac/from-power-on-to-oh-no-3hpg</guid>
      <description>&lt;h1&gt;
  
  
  From Power-On to 'Oh No'
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Dear Diary: MinGW, M1, and the Sweet Taste of Actually Working Code
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;January 2, 2026 - ChronOS Development Log&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Dear diary, today I discovered that building an operating system kernel is like trying to assemble IKEA furniture while blindfolded, using instructions written in ancient Sumerian, and the Allen wrench is actually a spoon.&lt;/p&gt;

&lt;p&gt;It's 3:20 PM on a gray Tuesday, and I'm sitting in my home office staring at a WSL terminal that's mocking me with a permission denied error. The coffee has gone cold – the third cup today – and somewhere in the back of my mind, a small voice is suggesting that perhaps normal people spend their afternoons watching Netflix instead of wrestling with GNU toolchains.&lt;/p&gt;

&lt;p&gt;But here we are.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Permission Paradox
&lt;/h2&gt;

&lt;p&gt;The day started innocently enough. I had ChronOS building perfectly in my WSL environment yesterday, producing a lovely little UEFI bootloader that should, in theory, transform my ancient Aorus laptop into a portal to kernel development glory. All I needed was to install a couple of build dependencies and push forward to the M1 milestone.&lt;/p&gt;

&lt;p&gt;"Just run &lt;code&gt;apt install&lt;/code&gt;," I told myself. "What could go wrong?"&lt;/p&gt;

&lt;p&gt;The terminal responded with the digital equivalent of a patronizing cough: permission denied. No sudo access on this machine. Of course. Because the universe has a sense of humor, and that sense of humor involves making sure that every simple task in OS development becomes a three-act tragedy.&lt;/p&gt;

&lt;p&gt;I spent twenty minutes googling "WSL sudo without admin rights" before accepting the uncomfortable truth: I was fighting the wrong battle. This is the moment in every debugging story where you realize you've been trying to push a door that clearly says "pull."&lt;/p&gt;

&lt;h2&gt;
  
  
  The MinGW Revelation
&lt;/h2&gt;

&lt;p&gt;Here's the thing about building UEFI applications that I somehow forgot in my quest for Linux purity: UEFI executables are PE32+ files. Windows executables, essentially. And what do you know, MinGW-w64 produces Windows executables natively. No conversion needed. No elaborate toolchain gymnastics. Just... build the thing with the tools designed to build Windows things.&lt;/p&gt;

&lt;p&gt;Sometimes the solution is so obvious you feel personally insulted by your own oversight.&lt;/p&gt;

&lt;p&gt;I fired up MSYS2 and watched pacman cheerfully install gcc without asking for a single password. No drama. No permissions. Just tools, installing themselves like civilized software should. It was almost suspicious how smooth it went.&lt;/p&gt;

&lt;p&gt;"This is going too well," I muttered, and the universe heard me.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Makefile Archaeology
&lt;/h2&gt;

&lt;p&gt;Creating a MinGW-compatible build system turned out to be an exercise in cross-platform archaeology. My existing Makefile was a beautiful work of Linux-centric art, complete with objcopy incantations to convert ELF files to PE format. Elegant, sophisticated, and completely useless for a toolchain that already speaks PE natively.&lt;/p&gt;

&lt;p&gt;So I created &lt;code&gt;Makefile.mingw&lt;/code&gt; – a parallel universe version where things just work without the ceremonial file format conversion dance. The key insight, which took me longer to grasp than I care to admit, is that MinGW produces PE executables because it's designed to target Windows. UEFI uses PE format because it's essentially Windows Boot Manager's cousin. The math was always there; I just needed to stop trying to make it more complicated than necessary.&lt;/p&gt;

&lt;p&gt;The missing piece was a replacement for the GNU-EFI library functions that my code was cheerfully calling. So I wrote &lt;code&gt;efi_support.c&lt;/code&gt; – a minimal shim that implements just enough EFI library functionality to keep my kernel from having an existential crisis at link time. It's not pretty, but it's honest work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Build That Actually Worked
&lt;/h2&gt;

&lt;p&gt;At 3:30 PM, I typed &lt;code&gt;make -f Makefile.mingw&lt;/code&gt; with the kind of cautious hope you reserve for situations that have failed spectacularly multiple times before. The compiler churned through six source files, the linker did its mysterious linking dance, and then...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[STRIP] deploy/BOOTX64.EFI

==========================================
  Build complete.
==========================================
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I stared at the screen for a moment, waiting for the other shoe to drop. When you've been fighting toolchains all day, success feels like a trap. But there it was: a 21KB UEFI executable, properly formatted, sitting in my deploy directory like it had every right to exist.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;file deploy/BOOTX64.EFI&lt;/code&gt; confirmed what I hardly dared believe: "PE32+ executable for EFI (application), x86-64." The computer had finally agreed with my vision of reality.&lt;/p&gt;

&lt;h2&gt;
  
  
  The USB Image Ritual
&lt;/h2&gt;

&lt;p&gt;Creating a bootable USB image involves a series of incantations that feel like digital witchcraft. You create an empty file, format it as FAT32, create the sacred directory structure (&lt;code&gt;EFI/BOOT/&lt;/code&gt;), and copy your executable to the precise location where UEFI expects to find it. Get any step wrong, and your laptop will stare at you with the blank indifference of a machine that has no idea what you wanted it to do.&lt;/p&gt;

&lt;p&gt;But mtools played along nicely, and soon I had a 64MB image file containing my bootloader, properly nested in its directory hierarchy like a Russian doll of boot-time hopes and dreams.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Moment of Truth
&lt;/h2&gt;

&lt;p&gt;Here's where the story takes a turn toward the genuinely terrifying. Up until now, everything had been theoretical. Text on screens, files being shuffled around, compilers producing output that looked plausible. But now came the moment where I had to find out if any of this actually worked on real hardware.&lt;/p&gt;

&lt;p&gt;I copied the image to a USB drive, walked over to my 2013 Aorus laptop – a machine old enough to have actual character – and held down F12 like I was making a wish on a digital birthday cake.&lt;/p&gt;

&lt;p&gt;The boot menu appeared. My USB drive was listed there, looking innocent and harmless. I selected it, pressed Enter, and watched the screen go black.&lt;/p&gt;

&lt;p&gt;This is the moment in every OS development story where time stops. The black screen could mean anything. Success, failure, or the kind of spectacular hardware confusion that requires a hard power cycle. You wait, holding your breath, hoping that somewhere in the depths of UEFI firmware, your code is doing what you told it to do instead of what you accidentally told it to do.&lt;/p&gt;

&lt;p&gt;Then the text appeared.&lt;/p&gt;

&lt;h2&gt;
  
  
  The M1 Miracle
&lt;/h2&gt;

&lt;p&gt;White text on black background, crisp and clear on the laptop's 3200x1800 display. My bootloader was not only running – it was chattering away happily, logging every detail of its interaction with the hardware:&lt;/p&gt;

&lt;p&gt;"Framebuffer base: 0x00000000D0000000"&lt;br&gt;
"Width: 3200, Height: 1800"&lt;br&gt;
"Display initialized"&lt;/p&gt;

&lt;p&gt;I pressed Enter, and it responded. I was having a conversation with code I had written, running on bare metal, without an operating system anywhere in sight. It's a feeling that's hard to describe – like hearing your own voice echoed back from the void, but the void is a graphics card and it's being remarkably cooperative about the whole thing.&lt;/p&gt;

&lt;p&gt;The bootloader created a log file on the USB drive, documenting its brief existence with the bureaucratic thoroughness of a kernel that takes its paperwork seriously. When I plugged the drive back into my development machine, there was &lt;code&gt;BOOTLOG.TXT&lt;/code&gt;, a UTF-16 testament to the fact that this insane project actually worked.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Aftermath
&lt;/h2&gt;

&lt;p&gt;It's now 4:15 PM, and I'm looking at a successful M1 milestone. The bootloader builds cleanly on MinGW, boots on real hardware, initializes the display, accepts keyboard input, and writes logs to persistent storage. All the basic building blocks of an operating system, working together in harmony.&lt;/p&gt;

&lt;p&gt;There's something deeply satisfying about solving a problem by stepping back and choosing the right tool instead of fighting with the wrong one. WSL wanted sudo permissions I didn't have, but MinGW just wanted to build Windows executables. UEFI wanted PE32+ files, and MinGW produces PE32+ files. Sometimes the universe aligns, and you remember why you started this project in the first place.&lt;/p&gt;

&lt;p&gt;Of course, this is just M1. The bootloader is currently about as sophisticated as a digital "Hello, World" with delusions of grandeur. Real operating systems have memory management, task scheduling, device drivers, filesystems, and a thousand other complexities that I haven't even begun to contemplate yet.&lt;/p&gt;

&lt;p&gt;But today, for the first time in weeks, I have a kernel that actually boots and responds to input. It's a small victory in the grand scheme of things, but in the world of hobby OS development, small victories are worth celebrating.&lt;/p&gt;

&lt;p&gt;Tomorrow I'll start working on M2, which will undoubtedly introduce new and creative ways for everything to break. But tonight, I'm going to enjoy the fact that I have 21KB of code that successfully convinced a modern laptop to do exactly what I asked it to do.&lt;/p&gt;

&lt;p&gt;That's not nothing. That's actually pretty remarkable.&lt;/p&gt;

&lt;p&gt;Now, where did I put that fourth cup of coffee?&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next up: M2 milestone, where we'll discover exciting new ways for hardware to ignore our carefully crafted instructions. The adventure continues.&lt;/em&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  osdev #programming #interrupts #lowlevel #userspace #kerneldev #bootloader #uefi #memorymanagement #assembly
&lt;/h1&gt;

</description>
      <category>osdev</category>
      <category>programming</category>
      <category>interrupts</category>
      <category>lowlevel</category>
    </item>
    <item>
      <title>IRQs and the Art of Not Crashing</title>
      <dc:creator>Florent Herisson</dc:creator>
      <pubDate>Fri, 09 Jan 2026 11:11:29 +0000</pubDate>
      <link>https://dev.to/florent_herisson_691b0bac/irqs-and-the-art-of-not-crashing-non</link>
      <guid>https://dev.to/florent_herisson_691b0bac/irqs-and-the-art-of-not-crashing-non</guid>
      <description>&lt;h1&gt;
  
  
  IRQs and the Art of Not Crashing
&lt;/h1&gt;

&lt;p&gt;Dear diary, today I committed to building an operating system again. No, I'm not okay.&lt;/p&gt;

&lt;p&gt;It's January 2nd, 2026, and while normal people are nursing hangovers and pretending they'll actually go to the gym this year, I'm sitting in my home office staring at a GitHub repository called "ChronOS." The afternoon light streams through my window, illuminating the graveyard of failed hobby projects scattered across my desk. An Arduino that was going to revolutionize my home automation. A Raspberry Pi that was definitely going to become a retro gaming console. A copy of "The Dragon Book" that I swore I'd read cover to cover.&lt;/p&gt;

&lt;p&gt;But today feels different. Today, I have 4,974 lines of recovered code fragments and what can only be described as dangerous levels of optimism.&lt;/p&gt;

&lt;p&gt;The plan is deceptively simple: boot on my Aorus X3 laptop, display some text on the 3200x1800 screen, and call it Milestone 1. How hard could it be? I've done this before. I mean, I've tried to do this before. Multiple times. The distinction is important.&lt;/p&gt;

&lt;p&gt;I spend the first hour setting up the project structure, creating folders with names like "drivers" and "kernel" as if I'm going to actually fill them with something meaningful. There's something deeply satisfying about creating empty directories. It's like buying workout clothes – you feel productive without actually doing the hard part yet.&lt;/p&gt;

&lt;p&gt;The recovered code gives me hope. Someone – presumably past me, though I have no memory of being this organized – actually implemented a bitmap font renderer. There's a complete 8x16 font, carefully crafted pixel by pixel. Looking at it now, I can almost remember the evening I spent squinting at character tables, painstakingly defining the letter 'Q' for what felt like the fortieth time.&lt;/p&gt;

&lt;p&gt;I create types.h first, because you have to start somewhere and fixed-width integers feel like progress. u8, u16, u32, u64 – the building blocks of civilization, or at least the building blocks of something that will triple-fault spectacularly in about three hours.&lt;/p&gt;

&lt;p&gt;The UEFI entry point comes next. This is where things get interesting, in the ancient Chinese curse sort of way. UEFI is supposed to be simpler than the old BIOS boot process. No more real mode, no more segments, no more 16-bit assembly that looks like it was written by someone having a stroke. Just good, clean C code that talks to a modern firmware interface.&lt;/p&gt;

&lt;p&gt;The irony is that UEFI is somehow more confusing than BIOS ever was. At least with BIOS, you knew you were in hell. UEFI pretends to be civilized while hiding a labyrinth of protocols and handles that would make Kafka weep.&lt;/p&gt;

&lt;p&gt;I write the framebuffer initialization code, and for a moment, I feel like I know what I'm doing. Graphics Output Protocol, acquire the framebuffer, store the base address in a global variable. Easy. The recovered code even has comments explaining the pixel format. Past me was clearly having a good day.&lt;/p&gt;

&lt;p&gt;The console code is where I start to remember why I abandoned this project the last time. Rendering text to a framebuffer sounds straightforward until you actually try to do it. Each character is 16 bytes representing an 8x16 bitmap. At 2x scaling for the HiDPI display, that becomes 16x32 pixels per character. Simple multiplication, right?&lt;/p&gt;

&lt;p&gt;Wrong. Because nothing is ever simple when you're working at the metal.&lt;/p&gt;

&lt;p&gt;First, I get the byte order backwards. The framebuffer expects BGRA, but I'm thinking RGB like a rational human being. My carefully crafted white text appears as a suspicious yellow-green color that reminds me of something I'd rather not think about.&lt;/p&gt;

&lt;p&gt;Then I discover that my font rendering has an off-by-one error that makes every character look like it's having an existential crisis. The letter 'A' develops a lean to the left. The letter 'O' becomes more of a philosophical concept than an actual circle.&lt;/p&gt;

&lt;p&gt;It's 4 PM now, and I've been debugging font rendering for two hours. This is not how I planned to spend my day. I was supposed to have a working bootloader by now, ready to impress myself with a clean boot banner. Instead, I'm staring at a screen that looks like someone spilled alphabet soup on it.&lt;/p&gt;

&lt;p&gt;The serial port code saves my sanity. At least, it saves what's left of it. COM1 at 115200 baud, 8N1, no flow control. The kind of simple, honest communication that doesn't pretend to be anything other than what it is. When the screen output looks like abstract art, I can still get debug messages through the serial port. It's like having a lifeline to the outside world.&lt;/p&gt;

&lt;p&gt;I implement a proper logging system because I've learned from past mistakes. Screen output should be clean and user-friendly. Serial output can be verbose and technical. And – this is the clever part – USB file logging writes everything to BOOTLOG.TXT on the boot USB itself. No more trying to remember cryptic error messages or squinting at serial output while balancing a laptop on my knee.&lt;/p&gt;

&lt;p&gt;The logging system grows more complex than I intended. Log levels, multiple outputs, formatted strings, hex value printing. Before I know it, I've written 200 lines of code just to say "hello world" in a slightly more sophisticated way. This is why hobby OS development takes forever. You start with a simple goal and end up implementing half of printf because you got carried away.&lt;/p&gt;

&lt;p&gt;The Makefile is its own special form of torture. GNU-EFI has opinions about compiler flags. The linker has opinions about section layouts. UEFI has opinions about executable formats. Everyone has opinions, and none of them agree with each other.&lt;/p&gt;

&lt;p&gt;I spend forty minutes figuring out why my bootloader won't... well, boot. The error message is spectacularly unhelpful: "Selected boot image did not authenticate." This could mean anything from "your code is garbage" to "you forgot to sacrifice a goat to the UEFI gods."&lt;/p&gt;

&lt;p&gt;The answer, it turns out, is that I'm creating a partition table when I should be using the superfloppy format. The Aorus X3, in its infinite wisdom, refuses to boot from anything that looks like a hard drive. It wants a floppy disk image, even though no one has seen an actual floppy disk since the Clinton administration.&lt;/p&gt;

&lt;p&gt;One line change in the Makefile. One line. I've been staring at this for forty minutes, and the fix is changing "mkfs.fat -F32" to "mkfs.fat -F32 -v". The -v flag creates a volume label, which apparently makes UEFI happy enough to actually run my code.&lt;/p&gt;

&lt;p&gt;By 6 PM, I have something that compiles. Whether it runs is a different question entirely.&lt;/p&gt;

&lt;p&gt;I write the bootable image to a USB drive and walk over to the Aorus X3. It's been sitting patiently on the shelf, accumulating dust and probably judging my life choices. I plug in the USB, power on, press F12 for the boot menu, and select the USB drive.&lt;/p&gt;

&lt;p&gt;The screen goes black. This is either very good or very bad. In OS development, there's rarely a middle ground.&lt;/p&gt;

&lt;p&gt;Then, slowly, like dawn breaking over a mountain range, text appears:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  CHRONO OS v4
  Time-Native Operating System

  Display: 3200x1800

  [OK] Boot successful
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works. It actually works. The framebuffer is initialized, the font is rendering correctly, and my carefully crafted boot banner is displayed in crisp, 2x-scaled glory. For a moment, I feel like I could conquer the world.&lt;/p&gt;

&lt;p&gt;The moment lasts exactly until I press a key and remember that I haven't implemented keyboard input yet. The system dutifully waits for a keypress, receives some sort of input event, logs it to the file, and then halts. Mission accomplished, in the most technical sense.&lt;/p&gt;

&lt;p&gt;I retrieve the USB drive and copy BOOTLOG.TXT to my desktop. The file is perfect – every debug message, every hardware detail, every moment of the boot process captured in excruciating detail. Past me would be proud. Present me is mostly relieved that I don't have to debug this with printk statements and a serial cable.&lt;/p&gt;

&lt;p&gt;The log shows exactly what happened: framebuffer acquired at address 0xD0000000, 3200x1800 resolution, 4 bytes per pixel, 23MB of VRAM. The GOP initialization succeeded, the console started correctly, and even the keypress was captured (scancode 0x0000, unicode 0x0020, which means I probably hit the space bar).&lt;/p&gt;

&lt;p&gt;Milestone 1 is officially complete. I have a bootloader that can display text on a HiDPI screen. It's not much, but it's honest work.&lt;/p&gt;

&lt;p&gt;Looking back at the recovered code, I realize this is further than I've ever gotten before. Previous attempts usually ended with triple faults or mysterious hangs during UEFI initialization. This time, everything just... worked. The font rendering is clean, the logging system is comprehensive, and the build process is repeatable.&lt;/p&gt;

&lt;p&gt;Of course, this is just the beginning. Milestone 2 involves keyboard input, which means learning about UEFI input protocols. Milestone 3 is memory management, which means page tables and virtual memory. Milestone 4 is multitasking, which means I'll need to understand CPU state switching and scheduler algorithms.&lt;/p&gt;

&lt;p&gt;But that's tomorrow's problem. Tonight, I have a bootloader that displays a boot banner and doesn't crash. In the world of hobby OS development, that's practically a Nobel Prize.&lt;/p&gt;

&lt;p&gt;Dear diary, I may actually finish this project. The thought terrifies me more than failure ever could.&lt;/p&gt;




&lt;h1&gt;
  
  
  osdev #programming #interrupts #lowlevel #bootloader #uefi #memorymanagement #assembly #x86_64 #debugging
&lt;/h1&gt;

</description>
      <category>osdev</category>
      <category>programming</category>
      <category>interrupts</category>
      <category>lowlevel</category>
    </item>
    <item>
      <title>IRQs and the Art of Not Crashing</title>
      <dc:creator>Florent Herisson</dc:creator>
      <pubDate>Fri, 09 Jan 2026 11:04:37 +0000</pubDate>
      <link>https://dev.to/florent_herisson_691b0bac/irqs-and-the-art-of-not-crashing-49jo</link>
      <guid>https://dev.to/florent_herisson_691b0bac/irqs-and-the-art-of-not-crashing-49jo</guid>
      <description>&lt;h1&gt;
  
  
  IRQs and the Art of Not Crashing
&lt;/h1&gt;

&lt;p&gt;Dear diary, today I committed to building an operating system again. No, I'm not okay.&lt;/p&gt;

&lt;p&gt;It's January 2nd, 2026, and while normal people are nursing hangovers and pretending they'll actually go to the gym this year, I'm sitting in my home office staring at a GitHub repository called "ChronOS." The afternoon light streams through my window, illuminating the graveyard of failed hobby projects scattered across my desk. An Arduino that was going to revolutionize my home automation. A Raspberry Pi that was definitely going to become a retro gaming console. A copy of "The Dragon Book" that I swore I'd read cover to cover.&lt;/p&gt;

&lt;p&gt;But today feels different. Today, I have 4,974 lines of recovered code fragments and what can only be described as dangerous levels of optimism.&lt;/p&gt;

&lt;p&gt;The plan is deceptively simple: boot on my Aorus X3 laptop, display some text on the 3200x1800 screen, and call it Milestone 1. How hard could it be? I've done this before. I mean, I've tried to do this before. Multiple times. The distinction is important.&lt;/p&gt;

&lt;p&gt;I spend the first hour setting up the project structure, creating folders with names like "drivers" and "kernel" as if I'm going to actually fill them with something meaningful. There's something deeply satisfying about creating empty directories. It's like buying workout clothes – you feel productive without actually doing the hard part yet.&lt;/p&gt;

&lt;p&gt;The recovered code gives me hope. Someone – presumably past me, though I have no memory of being this organized – actually implemented a bitmap font renderer. There's a complete 8x16 font, carefully crafted pixel by pixel. Looking at it now, I can almost remember the evening I spent squinting at character tables, painstakingly defining the letter 'Q' for what felt like the fortieth time.&lt;/p&gt;

&lt;p&gt;I create types.h first, because you have to start somewhere and fixed-width integers feel like progress. u8, u16, u32, u64 – the building blocks of civilization, or at least the building blocks of something that will triple-fault spectacularly in about three hours.&lt;/p&gt;

&lt;p&gt;The UEFI entry point comes next. This is where things get interesting, in the ancient Chinese curse sort of way. UEFI is supposed to be simpler than the old BIOS boot process. No more real mode, no more segments, no more 16-bit assembly that looks like it was written by someone having a stroke. Just good, clean C code that talks to a modern firmware interface.&lt;/p&gt;

&lt;p&gt;The irony is that UEFI is somehow more confusing than BIOS ever was. At least with BIOS, you knew you were in hell. UEFI pretends to be civilized while hiding a labyrinth of protocols and handles that would make Kafka weep.&lt;/p&gt;

&lt;p&gt;I write the framebuffer initialization code, and for a moment, I feel like I know what I'm doing. Graphics Output Protocol, acquire the framebuffer, store the base address in a global variable. Easy. The recovered code even has comments explaining the pixel format. Past me was clearly having a good day.&lt;/p&gt;

&lt;p&gt;The console code is where I start to remember why I abandoned this project the last time. Rendering text to a framebuffer sounds straightforward until you actually try to do it. Each character is 16 bytes representing an 8x16 bitmap. At 2x scaling for the HiDPI display, that becomes 16x32 pixels per character. Simple multiplication, right?&lt;/p&gt;

&lt;p&gt;Wrong. Because nothing is ever simple when you're working at the metal.&lt;/p&gt;

&lt;p&gt;First, I get the byte order backwards. The framebuffer expects BGRA, but I'm thinking RGB like a rational human being. My carefully crafted white text appears as a suspicious yellow-green color that reminds me of something I'd rather not think about.&lt;/p&gt;

&lt;p&gt;Then I discover that my font rendering has an off-by-one error that makes every character look like it's having an existential crisis. The letter 'A' develops a lean to the left. The letter 'O' becomes more of a philosophical concept than an actual circle.&lt;/p&gt;

&lt;p&gt;It's 4 PM now, and I've been debugging font rendering for two hours. This is not how I planned to spend my day. I was supposed to have a working bootloader by now, ready to impress myself with a clean boot banner. Instead, I'm staring at a screen that looks like someone spilled alphabet soup on it.&lt;/p&gt;

&lt;p&gt;The serial port code saves my sanity. At least, it saves what's left of it. COM1 at 115200 baud, 8N1, no flow control. The kind of simple, honest communication that doesn't pretend to be anything other than what it is. When the screen output looks like abstract art, I can still get debug messages through the serial port. It's like having a lifeline to the outside world.&lt;/p&gt;

&lt;p&gt;I implement a proper logging system because I've learned from past mistakes. Screen output should be clean and user-friendly. Serial output can be verbose and technical. And – this is the clever part – USB file logging writes everything to BOOTLOG.TXT on the boot USB itself. No more trying to remember cryptic error messages or squinting at serial output while balancing a laptop on my knee.&lt;/p&gt;

&lt;p&gt;The logging system grows more complex than I intended. Log levels, multiple outputs, formatted strings, hex value printing. Before I know it, I've written 200 lines of code just to say "hello world" in a slightly more sophisticated way. This is why hobby OS development takes forever. You start with a simple goal and end up implementing half of printf because you got carried away.&lt;/p&gt;

&lt;p&gt;The Makefile is its own special form of torture. GNU-EFI has opinions about compiler flags. The linker has opinions about section layouts. UEFI has opinions about executable formats. Everyone has opinions, and none of them agree with each other.&lt;/p&gt;

&lt;p&gt;I spend forty minutes figuring out why my bootloader won't... well, boot. The error message is spectacularly unhelpful: "Selected boot image did not authenticate." This could mean anything from "your code is garbage" to "you forgot to sacrifice a goat to the UEFI gods."&lt;/p&gt;

&lt;p&gt;The answer, it turns out, is that I'm creating a partition table when I should be using the superfloppy format. The Aorus X3, in its infinite wisdom, refuses to boot from anything that looks like a hard drive. It wants a floppy disk image, even though no one has seen an actual floppy disk since the Clinton administration.&lt;/p&gt;

&lt;p&gt;One line change in the Makefile. One line. I've been staring at this for forty minutes, and the fix is changing "mkfs.fat -F32" to "mkfs.fat -F32 -v". The -v flag creates a volume label, which apparently makes UEFI happy enough to actually run my code.&lt;/p&gt;

&lt;p&gt;By 6 PM, I have something that compiles. Whether it runs is a different question entirely.&lt;/p&gt;

&lt;p&gt;I write the bootable image to a USB drive and walk over to the Aorus X3. It's been sitting patiently on the shelf, accumulating dust and probably judging my life choices. I plug in the USB, power on, press F12 for the boot menu, and select the USB drive.&lt;/p&gt;

&lt;p&gt;The screen goes black. This is either very good or very bad. In OS development, there's rarely a middle ground.&lt;/p&gt;

&lt;p&gt;Then, slowly, like dawn breaking over a mountain range, text appears:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  CHRONO OS v4
  Time-Native Operating System

  Display: 3200x1800

  [OK] Boot successful
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works. It actually works. The framebuffer is initialized, the font is rendering correctly, and my carefully crafted boot banner is displayed in crisp, 2x-scaled glory. For a moment, I feel like I could conquer the world.&lt;/p&gt;

&lt;p&gt;The moment lasts exactly until I press a key and remember that I haven't implemented keyboard input yet. The system dutifully waits for a keypress, receives some sort of input event, logs it to the file, and then halts. Mission accomplished, in the most technical sense.&lt;/p&gt;

&lt;p&gt;I retrieve the USB drive and copy BOOTLOG.TXT to my desktop. The file is perfect – every debug message, every hardware detail, every moment of the boot process captured in excruciating detail. Past me would be proud. Present me is mostly relieved that I don't have to debug this with printk statements and a serial cable.&lt;/p&gt;

&lt;p&gt;The log shows exactly what happened: framebuffer acquired at address 0xD0000000, 3200x1800 resolution, 4 bytes per pixel, 23MB of VRAM. The GOP initialization succeeded, the console started correctly, and even the keypress was captured (scancode 0x0000, unicode 0x0020, which means I probably hit the space bar).&lt;/p&gt;

&lt;p&gt;Milestone 1 is officially complete. I have a bootloader that can display text on a HiDPI screen. It's not much, but it's honest work.&lt;/p&gt;

&lt;p&gt;Looking back at the recovered code, I realize this is further than I've ever gotten before. Previous attempts usually ended with triple faults or mysterious hangs during UEFI initialization. This time, everything just... worked. The font rendering is clean, the logging system is comprehensive, and the build process is repeatable.&lt;/p&gt;

&lt;p&gt;Of course, this is just the beginning. Milestone 2 involves keyboard input, which means learning about UEFI input protocols. Milestone 3 is memory management, which means page tables and virtual memory. Milestone 4 is multitasking, which means I'll need to understand CPU state switching and scheduler algorithms.&lt;/p&gt;

&lt;p&gt;But that's tomorrow's problem. Tonight, I have a bootloader that displays a boot banner and doesn't crash. In the world of hobby OS development, that's practically a Nobel Prize.&lt;/p&gt;

&lt;p&gt;Dear diary, I may actually finish this project. The thought terrifies me more than failure ever could.&lt;/p&gt;




&lt;h1&gt;
  
  
  osdev #programming #interrupts #lowlevel #bootloader #uefi #memorymanagement #assembly #x86_64 #debugging
&lt;/h1&gt;

</description>
      <category>osdev</category>
      <category>programming</category>
      <category>interrupts</category>
      <category>lowlevel</category>
    </item>
  </channel>
</rss>
