Implementing UEFI Boot to Zork
One of the earlier examples of students using MIT computer resources
to lay the groundwork for a later commercial endeavour, Zork was
originally written in a LISP derivative called MDL.
This was later tuned into the Zork Implementation Language, a domain
specific language that was compiled to target the Z-machine rather
than a specific piece of hardware. Combined with machine-specific
Z-machine interpreters, this allowed rapid porting of games to a wide
range of platforms - the only thing that needed to be rewritten was
the interpreter, and that could be reused for any future games running
on the same hardware.
Infocom were eventually acquired and killed off, but fan interest in
their games continued. New Z-machine interpreters were written in
order to allow their games (including Zork) to be run on platforms
that Infocom had never targetted. One of the best known is Frotz. This has the advantage
of being (a) portable and (b) including a "dumb" UI that makes no
assumptions about the availablity of any vaguely useful
functionality. Like, say, a Curses library.
So, Frotz seemed like the natural choice when this happened. But despite having a set of functionality that makes it look much
more like an OS than a boot environment, UEFI doesn't actually expose
a standard C library. The EFI
Application Development Kit solves this particular design
decision. Porting Frotz ended up involving far more fixing up of Frotz
bugs that tripped up -Werror than anything else. One note, though -
make sure you include DevShell in the list of required packages at
build time, otherwise file i/o will mysteriously fail.
The tying of file i/o to the shell protocol unfortunately means that
Frotz can't be directly launched by the firmware. The Boot to Zork images
therefore contain a UEFI shell in the standard boot location
(\EFI\BOOT\BOOTX64.EFI) which is executed when the firmware attempts
to boot the device. The shell then looks for a file called
"startup.nsh" in the root directory of the boot device and executes
it. Unfortunately this doesn't actually set the shell equivalent of
the current device, and so just launching Frotz from startup.nsh fails
when Frotz can't open the Zork data file. The solution for this is
simple, if ugly - the script walks through the list of devices,
looking for one that contains ZORK1.DAT in the root directory. It then
changes to that device and launches Frotz. If Frotz exits, it then
resets the system.
This could be avoided by doing some more work and turning Frotz into a
more UEFI-native application. Teaching Frotz to make native UEFI calls
would avoid the requirement for the shell protocols, and the firmware
provides a mechanism to obtain the path of the currently running
executable which would avoid the need to explicitly locate the
device. But I'm lazy and this was a "I'm spending the day on a plane"
project initially inspired by a Sazerac-fuelled conversation during
the UEFI plugfest, not a demonstration of UEFI best practices.
UEFI Boot To Zork and the source code to the modified Frotz can be downloaded here.
Syndicated 2013-09-22 18:17:46 from Matthew Garrett