Do you remember the famous Windows NT Blue Screen Of Death? For years it was a source of jokes and bad reputation of Windows reliability. There even was a Blue Screen Saver!
Today we fortunately see much less of it, but it still is there, reminding us that Windows Kernel was developed in a text mode environment. The 1989 NT Design Workbook tells us that in the early days of development there was an ANSI terminal emulator and bunch of command line utilities running in the text mode. Sadly all were removed in the retail version. The only true text mode application left around was autochk. Since the day Aclock was conceived I always wanted to run it on the NT text mode boot screen. In it’s twisted logic it actually makes a perfect sense.
So how do you actually output to the BSOD screen? Initially there was a lot hope in Windows NT Native Application, which can use NtDisplayString() function to display text before GUI takes over. Mark Russinovitch has written a sample Native Application with source code. Unfortunately I soon realized that NtDisplayString() does not allow for any control characters that would let me position the cursor or clear the screen. It doesn’t let much more than to display “Hello World” during Windows boot. This unfortunately wasn’t what I was hoping for. Out of lack of further ideas the project was shelved for nearly 10 years until I recently got some help from a real windows insider.
The new hope came from a HalDisplayString() and it’s helper functions HalQueryDisplayParameters() and HalSetDisplayParameters() which return screen resolution in characters and allow to position the text cursor. Exactly what I needed! However these functions are part of the NT Kernel and there was absolutely no hope of calling them from user mode, even a Native application.
So a device driver version of Aclock was conceived. Err WHAT? Yes a Windows Kernel Mode Device Driver version of Aclock. It sounds like craziest idea and most ridiculous waste of time ever. Worse than that, it definitely is! Despite that, development of the driver was actually surprisingly straight forward and the most difficulties I had was to do with setting up the right environment. It required Windows NT 4.0 SP6, an old version of NTDDK, SDK and Visual Studio. Once I had the project set up correctly, the only thing left to do was to figure out the kernel mode equivalents of some of the things I was getting for granted, for instance sleep(). My last surprise was rather unexpectedly difficult access to floating point in the driver. I was advised to avoid, so I have generated a pre computed tables of sin and cos values for every minute on the clock dial.
I must say that VMware Workstation Snapshots came very handy for launching and testing of the driver. It spared me from constant rebooting and re-launching the whole environment. I could load aclock and literally click “back” like in a web browser.
Here is a link to the binary, source and project files.
Since running the driver on your own system will render it unbootable (you can always do a snapshot or use last known good configuration) I have build a minimal Windows NT Embedded (NTe) image that loads the driver on startup. It’s available as VMware machine, and a Qemu image.
The next steps may involve porting AA-Lib to NTHAL. From there the possibilities are unlimited aalib-quake?
I don’t think the advice against using floating-point actually applies in this particular case. In general yes, it is very troublesome, as the user has to save/restore the floating-point state in kernel context. However… in a BSOD state, that should not be an issue as there simply won’t be any other floating-point users.
As “running the driver on your own system will render it unbootable” I think that sooner or later it will be detected as malicious software by anti-virus products…
I do not think you can re-distribute the windows nt kernel without explicit written permission from MS. Distributing the driver should not be an issue.
>Reminding us that Windows internally is in fact a text mode operating system.
This makes zero sense. Programs are, internally just math. They output through whatever method the programmer chooses. Since all video cards support text mode, it only makes sense that a competent programmer would choose to use such a mode to display crash information, using the fewest resources on a system that has just proven unstable. If they so choose, however, they could just as easily display the information in VGA mode using graphics, at the risk of being illegible on extreme legacy systems which, while very rare, are not as rare as any of us would hope.
What I was referring to is a fact that NT kernel was first developed in text only environment with VT100 terminal and text console of a DEC Workstation. This was long before addition of “graphical” environments like OS/2 or Win32 GUI on top. The developers could not easily choose to display on VGA mode because not all of the machines they developed for (MIPS, PowerPC, Alpha and x86) had VGA cards.
The PowerPCs and Alphas I’ve seen running NT all had VGA graphics… but those came relatively late in the NT development cycle. The older targets were MIPS or initially even i860 and those did not have VGA. See eg. Jazz, Microsoft’s MIPS-based NT hardware design.
My Alpha had DEC ZLX framebuffer card. Later models indeed eventually all had VGA. But it took some time for VGA cards to get decent screen resolutions.
That depends on what’s a “decent resolution” and what’s a “VGA” 🙂 IBM’s VGA + 8514/A combo could do 1024×768 with 256 colors back in 1987. There were OEM graphics cards that could do at least 1280×1024 in the late 1980s, though it’s questionable whether they might be called “VGA”. By 1994 there were cards like the ATI Graphics Pro Turbo 1600 with 1600×1200 resolution–that was more than decent back then.
The canonical VGA register interface can set up an 800×600 resolution, but needs a custom clock source (the regular 28MHz pixel clock just isn’t enough). Higher resolutions additionally need bank-switching which was never standard. Neither were any SuperVGA extensions–a sad fact.
My experience with Alphas is limited to their circa 1996-1997 models, and back then they were all PCI based. The ones I used had Matrox Millennium (or was it the Millennium II?) PCI graphics cards in them. Very good boards.
The PowerPC systems I’ve seen (various IBMs) all had pretty standard S3/Weitek/Western Digital PCI chips (WDs on laptops). The NT ARC floppy included a little x86 emulator to run the BIOS POST and even used real text mode.
Around early ’90 I was working with a several *low end* Unix and VMS workstations such as DECstation 5000, HP9000, SGI Indy, SUN Sparc Station etc. I recall the machines having custom frame buffers with 21″ monitors and 1280 x 1024 resolution. Also my Atari TT at home had 1280 x 960. This is what I call decent and none of these were VGAs. PCs with VGA of that time were rocking 640×480 and sometimes 800×600 although I indeed saw drivers and modes for 1024×768 like the one in QNX2.
Some trial & error with linked VMware image (in VirtualBox, actually) brigs conclusion, that Windows NT 4.x Embedded needs at least 6 MB of RAM. With 4 megs it BSODs with ‘INSTALL_MORE_MEM’, with 5 MB it just reboots, with 6 megs aclock just works 🙂