Memtest86+ Graphical Console

The memtest86+ is an opensource memory tester. It can be directly booted and runs without an operating system. It can also relocate itself in memory while running and therefore allows to test if all memory is working correctly.

The original version was written in 1994 by Chris Brady and it has evolved since then so that it runs on recent enough hardware. In 2013 the development was taken over by a company called PassMark which continued to develop version 4 as open source project. Then the version 5 was released with a proprietary license and open source developers forked version 4.

The open source version is released under the GPL license, but there seems to be very little development.

The application itself can be booted as MS-DOS boot sector or with Linux compatible bootloaders as a bzImage kernel. The Debian upstream package also provides a patch that allows booting the memtest86+ as multiboot payload (e.g. with GRUB2 bootloader).

The biggest limitation of the memtest86+ seems to be the support of only text-mode displays. Text mode frame-buffers are no longer used in desktop computers (actually if you are about the same age as I am, than you can’t even remember this mode). It was not such a big problem for BIOS enabled machines, but the UEFI standard only provides kernels with a graphical mode console and this means that memtest86+ is useless on machines with the latter standard.

Text vs graphical framebuffers

Printing content on a screen is an essential feature of personal computers. Modern displays are always a dot matrix. To show anything on the screen, some dots must be turned on and some turned off in the simple case of two state dots.

Let’s imagine that we want to print a character on the screen. First we must know how the character looks like. A character in a program is represented as a single byte value (let’s assume ASCII encoding for simplicity). The value has no relation to the visual representation of the character as we imagine it. This might be a bit confusing at first, because when people think of characters, they strongly associate them with their visual representation. Therefore, decoupling the character value and its representation can be a bit non-intuitive.

On the other hand a computer has no clue how the character should look like and someone (us) has to tell it. That is when fonts come in. Fonts are sets of visual representations of different characters for computers. In its simplest form a font is just a fixed array of bits with zeroes where the background colour should be and ones where the foreground colour should be.

To render a character, we must find the proper place on the screen (usually the left upper corner of the glyph) and then iterate through the pixels and set them to proper values. Note that this is a very simplified approach that only works for fixed-dimension font. Modern computer fonts are much more complex, but this is out of the scope of this article.

Even such simple rendering requires code that might be trivial, but when done wrong it might have a non-trivial performance overhead. Furthermore, the font’s bitmap must be compiled in the binary executable which increases its size. This is probably not a problem of today, but there was a time when computer RAMs were a scarce resource.

Because of these issues with rendering, computers contained a hardware implementation called the Text Mode. In this mode the display was presented to the software as an array of characters instead of an array of pixels. To print a character, the OS had to simply write its ASCII code to the proper location in memory. Memory which belongs to the display is called framebuffer for both graphical and text mode.

On IBM PC compatible computers, this memory is located at physical address 0xB8000. Each character on the screen is represented as two bytes in memory. One byte is for the character value itself, while the other is for background/foreground color.

Sadly (or not?) the text mode support is part of the VGA/VESA protocol, which was superseded by the UEFI GOP protocol. The UEFI GOP protocol does not provide text mode and so the (opensource one) memtest86+ was not able to run on newer, UEFI-only computers.

The limitation of memtest to BIOS only computers condemns it to be practically useless on modern computers. There is the option to send output to the serial console, but nowadays this requires special hardware as most PCs are not equipped with a proper serial port. I therefore decided to extend the memtest with support for graphical framebuffers, which means adding support for rendering characters based on a font.

Detecting the framebuffer location

Before we can start drawing anything on a screen, we must know where the framebuffer is located. On the old BIOS PCs, it was always the 0xB8000, but this no longer applies for new machines. The fixed location reduces flexibility in hardware development and modern devices are trying not to stick to it.

When the framebuffer location is variable, we need it to be revealed to us on start. The boot process itself is extremely complicated and it forms a separate universe of complex hacks within the universe of runtime problems. I cannot describe much of the boot process here because I am definitely not aware of all of its details, since I ran away screaming when I learned about some of the drawbacks of RAM initialization (such as the nice Cache as RAM)

Luckily for us, these issues are solved by the firmware/bios/uefi/bootloader (choose the combination that suits your hardware best) and we can rely on it to initialize the hardware for us. In this article, we will assume that the boot process ends by running GRUB2 bootloader.

The bootloader sets a machine to some well defined state and then passes control to our code. The machine state is defined by something called boot protocol. GRUBs native boot protocol is called multiboot.

The multiboot protocol is very nice. It assumes that our “kernel” is a standard ELF file, and yes, this is the nice part, because we can produce the kernel with a relatively standard toolchain (GCC + some tweaks to the linker script). The GRUB2 even knows about the ELF sections, therefore the .bss is properly zeroed out etc. We can even compile our binary with debug symbols and the bootloader tells us where the symbol table is, so that we can print nice backtraces right from the kernel.

With all the kind treatment we get from the bootloader, getting the kernel up and running is much simpler than it would be if we did not use the bootloader, and we do not even need much assembler code.

What is important for us now is that when control is passed to our code, we get a pointer to the multiboot structure containing information about the machine collected by the bootloader. And some entries in that structure describe the framebuffer. The memtest86+ upstream does not contain support for booting from multiboot, but patches are available in the Debian repository adding this feature.

Framebuffer description

The following fields are provided in the multiboot structure. They are commonly called “framebuffer geometry”.

  • 64bit wide framebuffer address - The location of the framebuffer in the address space. Although the field is 64bit, recommendation is to put the framebuffer in the low 4GiB of memory to make it available to 32bit software
  • 8bit framebuffer type - This field tells us whether the framebuffer is set to graphical or text mode.
  • 8bit bpp - a.k.a. bits per pixel. This represents the color depth of the monitor. It is sad that this value does not have to be power of two, therefore the framebuffer cannot be represented as an array of proper sized integers. On my laptop for example, this value is 20.
  • 32bit framebuffer width and height - These are relatively straightforward items. They describe the dimensions of the framebuffer in its units (pixels or chars, depending on the mode)
  • 32bit framebuffer pitch - This value tells us how many (what? Some resources say bytes, but this seems odd to me, because for some combinations of bpp and framebuffer width one would not get multiples of 8bit) we have to skip to write a character on the same X offset, but on the line below. One could assume that pitch == bpp * framebuffer width, but this is not guaranteed. It should (I hope…) apply that pitch >= bpp * width because otherwise there will be overlapping pixels (anyway, everything is possible in the legacy hardware :P). Anyway, there can be holes in the framebuffer when the equality does not apply.
  • A union with two members, describing the “colour profile” of the monitor.

Next

In the next post we’ll take a closer look at the code and some drawbacks of the current memtest86+ implementation.