Skip to content

Cosmos Gen3: The NativeAOT Era and the End of IL2CPU? #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
valentinbreiz opened this issue Mar 5, 2025 · 0 comments
Open

Cosmos Gen3: The NativeAOT Era and the End of IL2CPU? #3

valentinbreiz opened this issue Mar 5, 2025 · 0 comments
Labels
dotnet os-dev Operating System Development
Milestone

Comments

@valentinbreiz
Copy link
Owner

valentinbreiz commented Mar 5, 2025

A Radical Shift for Cosmos

Cosmos has always been an ambitious project, enabling developers to write entire operating systems in C# without touching assembly or low-level components. For years, it relied on IL2CPU, a custom-built compiler that translated .NET bytecode into raw x86 machine instructions. This approach worked well enough to get Cosmos off the ground, but as time went on, its limitations became impossible to ignore, specially in areas that needs strong optimizations like graphical development.

We are now making a game-changing move: Cosmos Gen3 will no longer use IL2CPU. Instead, the compilation pipeline will be built on top of NativeAOT, a new born next-generation compiler that produces highly optimized and reliable native code.

💡 Work has already been started in this GitHub repository.

What makes this transition particularly exciting is that NativeAOT essentially accomplishes what Cosmos was doing with IL2CPU for nearly two decades—but in a more new, robust, modern, and optimized way. While IL2CPU required translating CIL into x86 assembly and only then compiling it to native code, NativeAOT automates this process by compiling directly CIL to native code, applying advanced optimizations that IL2CPU simply cannot match due to its open-source and experimental nature. This means that Cosmos Gen3 will not only be faster, more efficient, and more portable, but it will also benefit from continuous improvements and support from Microsoft’s own compiler stack—something that the Cosmos Core Team, due to limited manpower and time, cannot maintain at the same level.

This transition is not just a minor upgrade—it is a complete revolution in how Cosmos is built and how it will perform in the future. In this article, we will dive deep into why this transition is necessary, the benefits it brings, the challenges ahead, and the current state of the project.

Image


Why Are We Abandoning IL2CPU?

For years, IL2CPU was the core of the Cosmos project. Its job was to convert C# bytecode into raw x86 assembly, which was then compiled into machine code using yasm, making it possible to run .NET-based kernels on bare metal hardware. While this worked in theory, in practice, it became a major bottleneck.

The Core Problems with IL2CPU

The most significant issue is performance. IL2CPU does no real optimization on the code it generates. Every single instruction is compiled as literally as possible, meaning that even simple loops or method calls could become massively inefficient. The end result? Cosmos-based operating systems were unnecessarily slow.

Another crippling limitation was its strict dependence on x86 (32-bit). This made Cosmos completely incompatible with modern systems. Today, almost all hardware—whether it’s a PC, server, or embedded system like a Raspberry Pi—runs on x86-64 or ARM64. But IL2CPU simply wasn’t designed to support those architectures at its creation, making Cosmos outdated by default now.

Beyond these architectural constraints, IL2CPU also required continuous maintenance to stay compliant with .NET updates and is thus still on dotnet 6 (a dotnet 8 update was started but development is now discontinued since gen3). Since IL2CPU translates CIL (Common Intermediate Language) to raw x86 assembly, every new .NET release introduced potential breaking changes. To keep up, we had to manually track and support all CIL changes, ensuring that IL2CPU correctly translated new opcodes, calling conventions, and runtime behaviors—an increasingly unsustainable effort.

With NativeAOT, this entire process is now automated. Instead of manually converting CIL to assembly, NativeAOT compiles CIL directly into native code, leveraging Microsoft’s own compiler optimizations. This means that:

  • We no longer need to maintain an independent IL-to-assembly translation layer.
  • There is no need to manually implement new opcodes or update translation logic when .NET evolves.
  • Cosmos will automatically benefit from every improvement Microsoft makes to NativeAOT.

The only responsibility remaining for Cosmos is to fill holes where .NET relies on a runtime environment (native code)—this is done via plugs, our existing mechanism for replacing .NET methods with platform-specific implementations. But now, instead of rebuilding a full compiler from scratch, we can focus purely on kernel and hardware-specific integrations.

At this point, IL2CPU had become more of a burden than a tool, making it clear that Cosmos needed to evolve.


Why NativeAOT is the Future of Cosmos

NativeAOT (formerly known as CoreRT) is a groundbreaking .NET compilation technology. Instead of relying on a custom-built compiler (like IL2CPU), it allows us to compile C# directly into highly optimized native machine code.

This is a game-changer.

The Major Advantages of Gen3

  • Drastic Performance Improvements
    NativeAOT applies aggressive optimizations, generating code that is as fast as modern C/C++ compilers.

  • Multi-Architecture Support
    Cosmos will finally support x86-64 and ARM64, meaning it can run on modern CPUs, embedded devices, and even Raspberry Pi boards.

  • A More Modular Cosmos
    Instead of bundling everything together, Cosmos Gen3 will allow developers to pick only the components they need, making OS builds lighter and more efficient.

In short, NativeAOT finally makes Cosmos a serious tool for real-world OS development, rather than just an experimental / educational project.


The Technical Challenges of Transitioning to NativeAOT

The move from IL2CPU to NativeAOT isn’t just a simple migration—it’s a complete rework of Cosmos’ fundamental architecture. While this shift unlocks huge performance gains and better compatibility, it also introduces significant technical challenges that require deep modifications to how Cosmos and its compilation operates. Below are some of the major hurdles we are tackling as we transition to this new compilation model.

1. Reinventing the Compilation Pipeline

With IL2CPU, the entire compilation and linking process followed a monolithic approach:

  1. C# code is compiled to Common Intermediate Language (CIL) using the Roslyn Compiler, producing Dynamic-link Library (DLL) files.
  2. IL2CPU reads the compiled .dll files, extracts CIL instructions, and translates them into x86 assembly.
  3. If a method has a plug, IL2CPU does not translate its CIL into assembly. Instead, it directly injects the corresponding plug implementation into the .asm file.
  4. The entire kernel is written as a single, large .asm file, containing all method translations and plugs.
  5. At the very end, this massive .asm file is assembled using yasm, producing the final machine code.

With NativeAOT, this entire approach is replaced by a modern, multi-stage compilation process:

  1. CIL is compiled directly to native machine code using ilc—eliminating the need for IL2CPU’s translation layer.
  2. Plugs are preprocessed before compilation and compiled separately as native objects instead of being injected into a monolithic assembler file.
  3. Instead of a single massive .asm file, NativeAOT produces linked native object files, which are combined at the end using a standard linker.

This new approach significantly reduces complexity, allowing Cosmos to focus on OS development rather than maintaining a custom compiler infrastructure. In IL2CPU, Cosmos developers had full control over every CPU instruction since we manually defined how CIL opcodes were mapped to assembly. With NativeAOT, we now rely on Microsoft’s compiler backend for this translation.

2. Rethinking the Plug System

One of the most unique and powerful features of Cosmos has always been plugs—custom implementations that replace .NET standard library methods to allow Cosmos kernels to run without relying on a managed runtime.

With IL2CPU, plugs were integrated directly at the assembly generation stage. When IL2CPU detected a method that required a replacement (e.g., System.Console.WriteLine), it skipped its CIL translation and injected a plug’s assembly implementation directly into the .asm file using X#. X# plays a crucial role in IL2CPU’s pipeline. Since Cosmos does not use a traditional runtime like .NET, many system calls (such as memory allocation, console output, or file operations) had to be replaced with low-level implementations. The resulting single, large .asm file contained both translated CIL code and plug implementations, ensuring that calls to plugged methods were already resolved before linking.

However, NativeAOT completely changes this workflow. Since CIL is compiled directly to native code, we no longer have control over method translation during assembly generation. Instead, we must prepare plugs before compilation, generating them as pre-compiled native stubs that integrate into the final binary before linking.

Plugs must be portable across architectures, since Cosmos Gen3 targets both x86-64 and ARM64, unlike IL2CPU, which was strictly x86. To address these challenges, we are redesigning the plug system into a modular, NuGet-based package system.

3. Adapting to 64-bit & Multi-Architecture Support

Cosmos has been tied to x86 (32-bit) since its inception, mainly because IL2CPU was designed around that architecture (since it was the time the main architecture). The reality, however, is that 32-bit x86 is becoming obsolete—modern hardware is almost entirely x86-64 or ARM64.

With NativeAOT, Cosmos is finally moving to a 64-bit architecture, but that shift comes with major design changes:

  • Memory Management Must Be Reworked

    • In x86, Cosmos used its own memory manager, which provided dynamic memory allocation on a heap along with a garbage collector to free unused objects.
    • On x86-64, we now have larger virtual address spaces, meaning we must properly implement paging to ensure efficient memory handling.
    • ARM64 has an entirely different memory model, requiring custom page table implementations to handle address translation efficiently.
  • Boot Process Overhaul

    • IL2CPU relied on legacy BIOS booting, but modern systems use UEFI, requiring a complete redesign of the boot sequence.
    • With x86-64 and ARM64, we must implement UEFI bootloaders instead of relying on outdated BIOS-based boot methods.
    • Support for Multiboot2 is needed to ensure compatibility with GRUB and other boot managers.
  • Reimplementing All Plugs for Multi-Architecture Support

    • All existing plugs must be rewritten to support 64-bit execution and ARM64 compatibility.
    • Many low-level implementations, such as interrupt handling, hardware interaction, and I/O functions, are currently hardcoded for x86 and must be adapted to work across multiple architectures.
    • The Cosmos framework itself depends on these plugs, meaning that core functionalities like console output, file I/O, networking... must be rewritten to work with the new NativeAOT-based approach.

To address these challenges, we are designing a new memory abstraction layer that will work across both x86-64 and ARM64, ensuring that paging, heap allocation, and stack management remain efficient regardless of the target architecture. Additionally, we are working on a systematic plug migration process, where each plug will be reviewed, refactored, and rebuilt to support 64-bit execution while maintaining full functionality within Cosmos.

4. Debugging & Tooling: Adapting the Existing System

With IL2CPU, Cosmos relied on Visual Studio Debugging, providing a smooth, integrated debugging experience. Since IL2CPU generated custom x86 assembly, the debugging system was specifically designed to track Cosmos-specific method calls and stack frames.

Now that NativeAOT is handling compilation, debugging still requires adjustments, but instead of a complete overhaul, we will adapt our existing X#-based debugging system to work with the new architecture:

  • X#'s debugging infrastructure will be updated to support NativeAOT's execution model, allowing us to track kernel execution just as before.
  • The existing Cosmos Debugger will be extended to handle 64-bit architectures and ARM64 support.
  • Exception handling must be updated to align with NativeAOT’s compiled output, ensuring stack traces remain readable and Cosmos-specific errors are correctly handled.

Previously, if a Cosmos kernel crashed, IL2CPU provided structured stack traces because we controlled how function calls and registers were handled. With NativeAOT, stack unwinding must be synchronized with Microsoft's compiled output, meaning we need to adjust X# debugging hooks to ensure proper call tracing and symbol resolution. Rather than switching entirely to external debugging tools like GDB or LLDB, Cosmos will preserve its existing debugging ecosystem while extending it to support NativeAOT, x86-64, and ARM64. This ensures that developers working on Cosmos Gen3 retain the familiar debugging workflow while benefiting from improved compatibility and architecture flexibility.


Final Thoughts on the Challenges Ahead

Migrating Cosmos to NativeAOT is a monumental task, but it is absolutely necessary to keep the project relevant in the modern computing landscape. The benefits—better performance, multi-architecture support, and a more streamlined development process—far outweigh the difficulties. Each of the challenges above requires a fundamental shift in how Cosmos operates, from rebuilding the plug system to supporting new architectures and modernizing the boot process. However, these changes will set Cosmos up for long-term thinking. This isn’t just an upgrade—it’s a full architecture redesign of Cosmos. 🚀


Current Progress & Roadmap

We are already deep into the development of Cosmos Gen3 and its NativeAOT integration. Here’s what has been accomplished so far:

Prototype of the NativeAOT Plug System (Check out the Patcher Repo)
Initial ILC Compilation Tests Successful
🔄 Rewriting the Build Pipeline for NativeAOT
🔄 Developing the New Plug Management System
🔄 Paging implementation
🔄 Writing full documentation
🔜 Full Support for x86-64 & ARM64
🔜 Integration of X# for Debugging
🔜 Integration of platform dependant plugs for Dotnet integration
🔜 Integration of the Cosmos Testrunner

The goal is to have a fully working Cosmos kernel with NativeAOT within the next few months.


Conclusion: The Future of Bare Metal .NET Starts Now

The transition to NativeAOT is not just an upgrade—it’s a complete rewrite of Cosmos, redefining what’s possible for .NET-based operating systems. By moving away from IL2CPU, Cosmos Gen3 will provide true performance, portability, and scalability, making it a serious contender for bare-metal .NET development on modern architectures.

While Cosmos is not the only project exploring NativeAOT for kernel development, one notable alternative is MOOS. MOOS is an impressive example of what can be achieved with C# on bare metal, offering direct NativeAOT compilation and a minimalist approach to OS design. However, MOOS and Cosmos take fundamentally different approaches to how .NET is utilized in low-level development:

  • MOOS avoids full .NET integration by rebuilding a lightweight subset of the framework, sacrificing CLR features to keep the system minimal.
  • Cosmos, on the other hand, aims for full compatibility with the .NET ecosystem, making it easier to port existing .NET applications and libraries to bare-metal environments.
  • MOOS heavily relies on C libraries to handle many low-level features, whereas Cosmos keeps a strong focus on managed code, reducing exposure to unsafe memory operations and maintaining a more secure execution model.
  • Cosmos' plug system allows direct replacement of standard .NET methods, making it fully adaptable without requiring complete rewrites of core framework components like MOOS.

With Cosmos Gen3 embracing NativeAOT while preserving full .NET compatibility, it becomes a powerful tool for ambitious projects that require both bare-metal performance and the productivity of C#. By leveraging .NET’s modern ecosystem, Cosmos can become an entry point for bringing C# into fields where it was traditionally impractical, such as:

Embedded Systems – With ARM64 support, Cosmos Gen3 can power IoT devices, drones, industrial automation, or other custom embedded solutions, all while allowing developers to write the project entirely in C#.

Cloud & Edge Computing – The ability to run .NET workloads directly on hardware, without needing an OS, opens the door to high-performance cloud appliances and custom hardware-accelerated services.

Game Consoles & Custom Hardware – Cosmos' integration with NativeAOT enables low-latency applications, making it a viable option for game engines, high-performance graphics processing, and real-time systems.

By maintaining .NET’s flexibility while unlocking the potential of bare-metal execution, Cosmos Gen3 bridges the gap between high-level application development and low-level systems programming. This is more than just an OS—it’s a new way to think about .NET beyond Windows and Linux. 🚀


💬 Want to contribute? Join us and be part of this groundbreaking transformation!

🔗 Useful Links:

@valentinbreiz valentinbreiz added os-dev Operating System Development dotnet labels Mar 6, 2025
@valentinbreiz valentinbreiz added this to the Posts milestone Mar 6, 2025
@valentinbreiz valentinbreiz changed the title 🚀 Cosmos Gen3: The NativeAOT Era and the End of IL2CPU? Cosmos Gen3: The NativeAOT Era and the End of IL2CPU? Mar 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dotnet os-dev Operating System Development
Projects
None yet
Development

No branches or pull requests

1 participant