This is a brief note on a new Windows bug that was discovered recently. Windows 10 RS1 (aka Anniversary Update) and Windows Server 2016 RTM added a new BSOD graphical element, namely a QR code which points to http://windows.com/stopcode. This has even received media coverage.
Unfortunately the QR code rendering code has a bug. If Windows decides to use a 24 bits-per-pixel VGA mode for displaying the blue screen, it crashes at a callstack similar to this:
nt!BgpGxConvertRectangle nt!BgpGxDrawRectangle nt!BgpFwDisplayBugCheckScreen nt!KiDisplayBlueScreen nt!KeBugCheck2
The code in BgpGxConvertRectangle appears to be performing a pixel format conversion of some sort and overruns its buffer. Note that this is a traditional BIOS VGA mode and has nothing to do with how the Windows display driver is set up. After all, it may be the display driver crashing here so Windows needs a robust way to present the user with graphical output.
Crashing an already crashed machine doesn’t sound like a big deal, but it prevents the crash dump generation code from running which makes diagnosing the initial crash much harder.
As for the impact of the bug, it is uncommon for a modern VGA BIOS to support 24 bpp modes – they have been obsoleted by 32 bpp ones long time ago. Fun exercise, run the following commands at the grub command line:
grub> insmod all_video grub> videoinfo
But there is one important exception: SeaBIOS. This popular BIOS/VGA BIOS implementation used by emulators like QEMU/KVM provides two kinds of virtual VGA adapters: one Cirrus and a handful of Bochs-based ones. All of them have a 24 bpp VGA mode which Windows happens to use – VBE mode 0x118 1024 x 768 24 bpp. So in summary, due to this Windows bug it is not possible to get a Windows crash dump out of a QEMU/KVM virtual machine.
Fixes and workarounds
The Cirrus virtual adapter does not support any 32 bpp modes and should simply not be used at all. In the QEMU/KVM context, avoid the following:
and instead use one of
-vga std -vga qxl -vga virtio -vga vmware
to get an adapter that supports both 24 bpp and 32 bpp modes. That’s not enough though, because at boot time Windows sees the 24 bpp mode first and will use it even though a better one is available. The only known workaround at the moment is to change the order in which video modes are enumerated to make sure that Windows sees 32 bpp first:
The issue can also be completely side-stepped by switching from SeaBIOS to OVMF as the virtual machine firmware. This is definitely a less commonly used configuration, but it should work fine with modern guest operating systems.