Porting Wine to Astral

A few months ago, I posted about Astral, a hobby OS I have been working on over the years, running Minecraft. Since then, others have gotten modern versions of Minecraft to run as well as Factorio (using a glibc compatible libc). However, while these games are made or packaged in a way that makes it easier to get them to run under a new OS, most games are not. A lot of games are closed source and compiled for Windows, which makes something like Wine a necessity for playing them.
One of my favorite games, Cogmind, falls under that umbrella. It is a 32-bit Windows only roguelike, and it became my goal to run it under Astral. While there was already an existing Wine port, it was extremely incomplete, as not even
notepad.exe worked properly. To run Cogmind, the Wine port had to be finished, which also meant adding the ability to run 32-bit code on an otherwise 64-bit-only OS.Basic Wine Functionality
The first step of getting Wine up and running was downloading MinGW and enabling it in the Wine build, as it is needed to compile the PE DLLs. With it enabled,notepad.exe works and selecting "Save as" does not crash it anymore!
Compiling libEGL.so
There is still one big problem: Wine is being compiled without OpenGL support. While Astral did have OpenGL, Wine explicitly needs EGL to work, which Astral's Mesa port did not provide. EGL connects rendering APIs like OpenGL to the windowing system, which Wine needs to properly initialize graphics. At first, it seemed like a simple fix, just enable it in Mesa. However, Mesa does not support EGL on the xlib backend, forcing me to switch over to the DRI backend instead.DRI (Direct Rendering Infrastructure) allows applications to communicate more directly with the GPU rather than going through the X server. This led me into a rabbit hole of having to patch Mesa to allow the X.org server to start without
/dev/dri. In the end, I was successful and got a real game, Deltarune, to start:
WoW64 and 32-bit Windows programs
As Cogmind is 32-bit and Astral is 64-bit, more infrastructure is needed. This was accomplished using Wine's WoW64 mode, which does not need any 32-bit Unix libraries. It works by running 32-bit Windows binaries in a 64-bit process, translating between 32-bit and 64-bit system calls and data structures as needed, avoiding the need for a full 32-bit userspace.Getting it to work mostly involved implementing LDT (Local Descriptor Table) support in the kernel, as x86-64 allows you to run 32-bit code in long mode using 32-bit segment descriptors. These describe how memory should be accessed and, in the case of code segments, how the processor runs those instructions. The LDT is one of the mechanisms used to define these segment descriptors and allows them to be configured on a per-process basis. It also needed some finicky glue in Wine's signal and syscall handling code.
Cogmind!
After implementing WoW64 support in the Astral port and fixing a few other bugs in the kernel, Cogmind works! The game was playable and did not have any noticeable issues other than game news and scoresheet upload not working.
Broken scoresheet upload
This bug manifested by a TCP connection to the Cogmind servers being opened and instantly closed without any data being transferred. At first, I thought this was a network stack issue, but this was not the case.What made me suspicious it was something else was that the Wine debugging log function,
__wine_dbg_write, was not working at all in WoW64. After digging deep into Wine's code, I eventually noticed I was forgetting to save a register in the __wine_unix_call_dispatcher function. This broke the PE to Unix transition and led to UB. With this fixed, scoresheet upload works!More games and other programs
I have also tried to run some other applications under Wine:| Program | Status | Notes |
|---|---|---|
| FTL | Works | Fully playable. |
| Steam | Partial | Installs and updates; crashes on Chromium startup due to a broken GetInterfaceAddresses(). |
| iexplore.exe | Partial | Simple sites render; complex pages crash with the same root cause as Steam. |
| Factorio | Partial | Window opens but does not progress past loading. |
| Spooky's Jumpscare Mansion | Partial | Starts but runs too slowly to be playable. |
| Noita | Partial | Starts but runs too slowly to be playable. |
| Plants vs. Zombies | Broken | Blocked by Steam DRM before reaching the main menu. |
| Half-Life | Broken | Assert failure in Wine's C++ runtime. Likely a missing implementation in the port. |
| Firefox / Chromium | Broken | Installer fails; does not reach a runnable state. |
| SCP: Containment Breach | Broken | Does not start; cause not yet diagnosed. |
| Unity games in general | Broken | There seem to be issues with wine-mono on Astral, as Unity games get stuck on MonoManager ReloadAssembly |



Final thoughts
Porting Wine was a fun challenge and a way of proving that hobby OSes can be used to play a lot more games than originally thought, which is a step in the direction of hobby OSes becoming viable daily drivers. There are still some rough edges, performance issues and weird crashes, but the core of it works. This has also taught me a lot about the internal workings of Wine, especially while having to dig around to fix the PE-to-Unix transition.One of my big goals related to the Wine port now is to get Steam to work, which would also mean Chromium works. As for Astral, I plan on focusing more on optimizations, new drivers and bug fixes in the near future. There is a lot of room for improvements on the kernel side.
Thanks for reading!