Programming Space Game For X86 In Assembly Without An Operating System

Some assembly code

In this video our hacker [Inkbox] shows us how to create a computer game that runs directly on computer hardware, without an operating system!

[Inkbox] briefly explains what BIOS is, then covers how UEFI replaces it. He talks about the genesis of UEFI from Intel in the late 90s. After Intel’s implementation of UEFI was made open source it got picked up by the TianoCore community who make tools such as the TianoCore EDK II.

[Inkbox] explains that the UEFI implementation provides boot services and runtime services. Boot services include things such as loading memory management facilities or running other UEFI applications, and runtime services include things like system clock access and system reset. In addition to these services there are many more UEFI protocols that are available.

[Inkbox] tells us that when an x64 CPU boots it jumps to memory address 0xfffffff0 that contains the initialization instructions which will enter protected mode, verify the firmware, initialize the memory, load the storage and graphics drivers, then run the UEFI Boot Manager. The UEFI Boot Manager will in turn load the appropriate EFI application, such as the firmware settings manager application (the “BIOS settings”), Windows Boot Manager, or GRUB. In this video we make our very own EFI application that the UEFI Boot Manager can be configured to load and run.

The system used for development and testing has a AMD Ryzen AI 9 HX 370 CPU and 32GB DDR5 RAM.

Having explained how everything gets started [Inkbox] goes on to explain how to write and deploy the assembly language program which will load and play the game. [Inkbox] shows how to read and write to the console and mentions that he did his testing on QEMU with an image on an external USB thumbdrive. He goes on to show how to use the system time and date facilities to get the current month. When trying to read nanoseconds from the system clock he ended up needing to refer to the UEFI Specification Release 2.10 (2.11 is latest as of this writing).

In the rest of the video [Inkbox] does some arithmetic for timing, uses LocateProtocol to load the graphics output provider, configures an appropriate video mode, writes to the screen using BLT operations, and makes the program run on multiple CPU cores (the CPU used has 24). At last, with some simple graphics programming and mouse input, [Inkbox] manages to get Space Game for x86 to run.

If you’re interested in knowing more about UEFI a good place to start is What’s The Deal With UEFI?

27 thoughts on “Programming Space Game For X86 In Assembly Without An Operating System

  1. I understand it can be an interesting challenge, but is there any advantage to bare metal programming over relying on an OS for handling all the annoying and device specific nitty gritty?

    1. I can’t think of any advantage at all. Trying to program a computer without an operating system is not a good idea, except if your goal is to understand more about how the machine works…

        1. Yeah maybe some small theoretical performance boost but none that would be worth the insane development costs you’d be taking on. Ordinarily when you write a normal program that runs in an operating system the program runs in user space and you need to syscall into the operating system to do things the OS facilitates (reading and writing files, for instance). Those syscalls have some overhead. I guess the other thing you could do if you wanted to largely avoid OS overhead is to implement your program as a kernel module or device driver. But operating systems do a lot of good things that you don’t want to throw away or live without.

          1. There are a couple of synthesizers that run bare-metal (so without the Linux OS) on a raspberry pi, that way they can get realtime performance, even on older pi’s.

        2. You may be able to optimize a tiny portion of your code to be blazingly fast, but more than likely that will make the rest of your code suffer. Compilers today generally do a much better job than any individual person.

          1. That’s not true… Parts of the ffmpeg code has been written in assembly by hand… Compilers are okay, but nothing beats a human actually writing the code, in terms of performance… It’s not even close… Even windows and Linux have assembly binaries for low level functions…

          2. I’ve written code in assembly which needed to run faster than the compiled version would allow. And the rest of the code didn’t suffer one bit.

            The disadvantage would be code readability for future devs. Also, computers are so fast today that most developers would rather just throw more cores or memory at the problem than write parts in assembly or even try to optimize.

            Compilers these days are quite amazing and efficient. Cores and ram is easy to add with a single click. The art of writing in assembly or optimizing is mostly lost with today’s programmers.

            I’ll end with this: 0x5F3759DF

          3. @Pacman:
            Nothing beats hand optimizing for a singular target cpu, for the best hands. Optimizing across several targets for the best average? Not so much.

            @Tim Eckel:
            Funny you should end with a magic number for the fast inverse square algo, because that one is outdated and slow on modern hardware compared to the instructions available (and also written in C). As you say, you end up with hard-to-read code that may become a drag with the next version of a compiler or hardware.

            Optimizing code using assembly is still a thing though, but mostly for embedded (singular) targets. If you want something thats portable, it’s just not a go anymore, because while you may make it run faster on your computer, it may actually run slower on other targets.

      1. Unikernel microvms are a real thing and have significant advantages over containers and full vms. Certainly it’s all abstracted away and the app/program/server developed in higher level language becomes the actual os.

      2. BS. When your goal is reliability and performance, there are occasions you don’t want an OS in the way. There are many – mostly industrial – places where this is the case. Just because you can´t think of an advantage does not mean there aren’t any.

    2. If you need to create a system where security is vital, and you have visibility over all the code involved, then this is a big step closer than relying on a massive OS code base.

      Of course, there’s still a massive amount of code to get through bootup, not to mention microcode as well as various supporting microcontrollers (and indeed the very silicon itself) that is all very opaque.

    3. My first programming language was Hex code which is one step above machine code/binary. The speed and efficiency is unmatched. An assembler is short hand for Hex code. Thus only two steps away from binary and again, unmatched speed and efficiency.

      1. Nope. I watched the video through twice and summarized it by hand, letting our readers know what is in the video so they can make a decision about whether to watch it or not. I also looked up some of the things referenced in the video and linked to them.

  2. I enjoyed the video. It was all putting theory into practice and that, to me, seemed to be the whole point. Not whether you should do something but whether you can do something.

    It actually inspired me to think about projects that I could create for the bios. Maybe something as simple as a splash screen or maybe something more protective like a low level formatting operation keyed to not knowing my password…

  3. It is ridiculous how slow the implementation ends up being. 3 GHz on modern CPU with all the branching prediction and cashes and it’s literally slower than Arduino Uno with 16 MHz 8 bit CPU.

    Could as well write it in Python.

  4. I started to program games in the early 90s and remember we barely used DOS functions – eventually for loading/saving game-states to file and loading assets which could probably be replaced with BIOS level functions if there wouldn’t be a need to use a FAT filesystem. 99% of all code was talking to hardware.

    1. And let’s don’t forget using infamous VGA (MCGA) mode 13h in pixelated glory of 320×200 256c.
      With exception of shareware/freeware games or a few high-quality commercial titles,
      most DOS games stuck to it throughout the 90s, even if it wasn’t necessary.

      Instead of using VESA VBE mode 100h in 640×400 256c or mode 6Ah/102h in 800×600 16c..
      Which all had worked fine with basic 256 KB of VGA memory (and a VBE TSR in DOS memory).

      Even Deluxe Paint on PC did support Super VGA back then.
      But no, mode 13h remained the industry standard on DOS for many years to come.
      I was there in mid-90s and it made me sad, it seemed so backwards to me even by 1995 standards.
      PC versions of Doom and Wolf3D didn’t look any sophisticated to me, either.
      I could not understand all the fuss about it, StarFox or Donkey Kong Country on Super NES looked way cooler to me.

      Man, this is so frustating, I think, considering that Windows 3.x
      or Macintosh desktop games all ran on a 640×480 desktop resolution at same time.
      Sigh! If only 640×480 256c would have been popular on DOS, at least..
      Or normal VGA (planar) in 640×480 16c, at the very least. Maybe using good dithering to simulate more colors.
      Both modes could be displayed just fine on any standard VGA monitor or an notebook screen!

      Not a few budget VGA cards such as ET-4000AX, OAK OTI-77 or Trident 8900D etc had 512 KB of VGA memory, also.
      So hardware wise, it was no issue loading UniVESA or UniVBE here (they may had refused to load on 256 KB cards).
      An average 486DX2-66 to Pentium 90 PC was good enough to handle it, too.

Leave a Reply to tr324Cancel reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.