More Power To Firmware© Amit Singh. All Rights Reserved. Written in June 2004
Part I: The Firmware Scene
The PC BIOS is as old as the PC itself, while the acronym BIOS is even older, dating back to the CP/M operating system. BIOS (Basic Input/Output System) was one of the three primary components of CP/M, the other two being BDOS (Basic Disk Operating System) and CCP (Console Command Processor).
One reason for the longevity of the BIOS, and for its sustained primitivity, is the insanely successful DOS (for the PC), which was built on top of the BIOS. DOS programs call BIOS routines via software interrupts (for example, the BIOS disk routine corresponds to
INT 0x13). Note that this is similar to many erstwhile Apple systems where the Macintosh ROM contained both low-level code (such as for hardware initialization, diagnostics, drivers, etc.) and the higher level "Toolbox" -- a collection of reusable software routines.
In a "modern" setting, the old-fashioned BIOS has severe limitations, even though it has seen numerous tweaks, improvements, extensions, and additions over the years. Consider some examples:
- x86 computers always come up in the IA-32 "real mode" -- an emulation of the ancient 8086/8088 Intel processors. The BIOS executes in this mode, which is severely limited (particularly for an ambitious BIOS, say, one that wants to provide a powerful pre-boot environment). Effective memory addresses in real mode are calculated by multiplying the segment (a 16-bit number) by 16, and adding the offset (another 16-bit number) to it. Thus, a segment is 16-bits wide -- restricted to 65,536 bytes (64 KB), and a memory address is 20-bits wide -- restricted to 1,048,576 bytes (1 MB). In particular, the IP (instruction) register is also 16-bits wide -- placing a 64 KB size limit on the code segment. Memory is a very limited resource in real mode.
- A BIOS usually has hardcoded knowledge of supported boot devices. Support for booting off "newer" devices gets added to most BIOSs very slowly, if at all.
- An "option ROM" is firmware usually residing on a plug-in card (but may also live on the system board). It is executed by the BIOS during platform initialization. The legacy option ROM space is limited to 128 KB: shared by all option ROMs. An option ROM typically compacts itself by getting rid of some initialization code (leaving behind a smaller runtime code). Nevertheless, this is a severe limitation.
- Legacy BIOS depends on VGA, which is a legacy standard, and is unnecessarily complicated to program for.
- The PC partitioning scheme is tied to the BIOS, and is rather inadequate, particularly when it comes to multibooting, or having a large number of partitions. PC partitions may be primary, extended, or logical, with at most 4 primary partitions allowed on a disk. The first (512-byte) sector of a PC disk, the Master Boot Record (MBR), has its 512 bytes divided as follows: 446 bytes for bootstrap code, 64 bytes for four partition table entries of 16 bytes each, and 2 bytes for a signature. Thus, the size of a PC partition table is rather limited, hence the limit on the number of primary partitions. However, one of the primary partitions may be an extended partition, and an arbitrary number of logical partitions could be defined within it. Note that Apple's partitioning scheme is much better in this regard.
- Even with standards like PXE and related security enhancements such as Boot Integrity Services (BIS), it is rather difficult, and often impossible, to deploy and manage computers in a "zero-touch" fashion, particularly when it comes to remote management at the system firmware level, or of the system firmware itself.
A representative legacy BIOS could be visualized as containing three sets of procedures: those that are the same on all BIOSs (the core procedures), those that are specific to chips on the platform (the silicon support procedures), and those that are specific to the system board. There is a great deal of "secret-sauce" element in the BIOS. The BIOS APIs are very limited, and it is very hard to extend the BIOS -- it is a black box not just to end users, but also to those who wish to develop pre-boot or pre-OS applications (as value-add, say). Even if such developers license the BIOS source, the environment is expensive to develop for in all respects (including deployment).
A Bit of a Problem
64-bit computing came relatively late to the PC world. With the advent of 64-bit PCs (those based on the Itanium Processor Family, for example), a better solution to the "BIOS problem" was sought, although the x86 real mode can be emulated in IA-64.
64-bit PCs do not use legacy BIOS. The IA-64 firmware is divided into three primary components: the Processor Abstraction Layer (PAL), the System Abstraction Layer (SAL), and the Extensible Firmware Interface (EFI).
PAL abstracts the processor hardware implementation from the point of view of SAL and the operating system. Different processor models with potential implementation differences appear uniformly via PAL. Examples of the PAL layer's functionality include:
- Interruption entry points such as those invoked by hardware events (processor reset, processor initialization, machine checks, etc.)
- Procedures that can be invoked by the operating system or higher level firmware, such as procedures for obtaining processor identification, configuration, capability information, cache initialization, enabling and disabling processor features.
PAL has no knowledge of platform implementation details. Note however that PAL is part of the IA-64 architecture. The firmware implementation of PAL is supplied by the processor vendor, and it resides in OEM flash memory.
SAL provides an abstraction for the platform implementation, without any knowledge of processor implementation details. SAL is not part of the IA-64 architecture -- it is part of the Developer's Interface Guide for 64-bit Intel Architecture (DIG64). The firmware implementation of PAL is provided by the OEM.
The remaining component, EFI, could be thought of as the grand solution to the BIOS problem -- for PCs.
Extensible Firmware Interface
The Extensible Firmware Interface (EFI) can be traced back to the "Intel Boot Initiative" (IBI) program (1998, but see Innovate later in this document)). The EFI specification, developed and maintained by a consortium of companies (including Intel and Microsoft), defines a set of APIs and data structures to be exported by a system's firmware, and to be used by a variety of clients, such as:
- EFI device drivers
- EFI diagnostics and system utilities
- EFI shell
- Operating system loaders
- Operating systems
In a representative EFI system, a thin Pre-EFI Initialization Layer (PEI) might do most of the POST-related work that is traditionally done by the BIOS POST. This includes things like chipset initialization, memory initialization, bus enumeration, etc. EFI prepares a Driver Execution Environment (DXE) to provide generic platform functions that EFI drivers may use. The drivers themselves provide specific platform capabilities and customizations.
There are two types of services available in the EFI environment: Boot Services and Runtime Services. Applications that run only within the pre-boot environment make use of boot services, which include services for events, timer, and task priority, for memory allocation, for handling EFI protocols, for loading various types of images (EFI applications, EFI boot services drivers, EFI runtime drivers), and for miscellaneous purposes.
An operating system loader also uses boot services to determine and access the boot device, allocate memory, and create a functional environment for the operating system to start loading. At this point, an OS loader could call the
ExitBootServices() function, after which boot services will not be available. Alternatively, an operating system kernel could call this function.
Runtime services are available both before and after
ExitBootServices(). This category includes services for:
- Managing variables (key-value pairs)
- Managing hardware time devices
- Virtual memory (for example, to allow an operating system loader, or an operating system, to invoke runtime services with virtual memory addressing instead of physical addressing)
- Retrieving the platform's monotonic counter
- Resetting the system
EFI drivers can come from non-volatile memory, from the option ROM of a card, or from a device that EFI supports natively.
Most EFI drivers would conform to the EFI Driver Model. Such drivers are written in C and operate in a flat memory model. Driver images may be converted to EFI Byte Code (EBC), and are typically compressed (using Deflate, a combination of LZ77 compression and Huffman coding). Examples include:
- Bus Drivers (manage and enumerate bus controllers, such as a PCI Network Interface Controller -- installed onto the bus's controller handle)
- Hybrid Drivers (manage and enumerate bus controllers, such as a SCSI Host Controller -- installed onto the bus's controller handle and the bus's child handles)
- Device Drivers (manage controllers or peripheral devices, such as a PS/2 or USB keyboard)
Drivers that may not conform to the EFI Driver Model include:
- Initializing Drivers (perform one-time initialization functions)
- Root Bridge Drivers (manage part of the core chipset)
- Service Drivers (provides services to other EFI drivers, such as the decompression protocol and the EFI Byte Code Virtual Machine)
- Older EFI drivers
EFI drivers consume various protocols (PCI I/O, Device Path, USB I/O, USB Path, etc.) and produce several other protocols (Simple Input, Simple Pointer, Block I/O, UGA Draw, UGA I/O, Simple Text Output, SCSI Block I/O, SCSI Passthrough, Network Interface Identification, Serial I/O, Debug Port, Load File, etc.)
EFI aims to be a powerful and modular firmware that is readily extensible, even by (power) users. Some noteworthy aspects of EFI include:
- EFI is implementation agnostic.
- EFI does not require real mode.
- EFI runs in a flat memory model, with the entire address space being addressable.
- EFI is written in C. Therefore, it is both easy to write and portable.
- EFI does not place a restriction on the total size of option ROMs. EFI drivers can be loaded anywhere in the EFI address space.
- EFI aims to replace VGA over time with simple graphics primitives courtesy the Universal Graphics Adapter (UGA).
- EFI includes an optional shell that gives the user a lot of freedom and flexibility.
- The pre-boot environment provided by EFI has a BSD socket compatible network interface, with a port of the FreeBSD TCP/IPv4 protocol stack.
Example EFI Environment
Following is a "site map" of a hypothetical user-visible EFI environment you may be presented with on an EFI-based machine:
(o) Power On
+-+ Boot Manager
+-+ Device Path(s) To OS Loader(s)
| +-- Windows XP-64
| +-- Linux IA-64
+_+ Boot Maintenance
| +-- Change Boot Order
| +-- Boot From Specified File
| +-- Add Boot Options
| +-- Select Console I/O
+-+ Launch EFI Shell
+-- Various shell functions
The EFI environment (optionally) includes an interactive shell that allows a user to do a wide variety of tasks:
- Launch other EFI programs.
- Load, test, and debug drivers manually (you can also load a ROM image).
- View or manipulate memory and hardware state.
- Manage system variables.
- Manage files.
- Do text editing.
- Run shell scripts.
- Access the network, say, via Ethernet or a dial-up connection.
The EFI shell has flavors of both the DOS command prompt and a rudimentary Unix shell. It is implemented in C, and is developer extensible.
Following are some examples of using the EFI shell, most of which are self-explanatory:
EFI Specification Revision : 1.10
EFI Vendor : INTEL
EFI Revision : 14.62
Directory of: fs0:\
06/12/04 02:30a <DIR> 4,096 diskutils
11/24/03 07:50p 401,773 Efildr
06/12/04 02:32a <DIR> 4,096 apps
1 File(s) 401,773 bytes
fs0:\> devices -b
C T D
T Y C I
R P F A
L E G G #P #D #C Device Name
== = = = == == == ===============================
06 R - - - 2 - FAT File System [FAT12] 1440 KB
07 R - - - 2 2 VenHw(Unknown Device:80)
0C R - - - 1 11 Acpi(PNP0A03,0)
1B D - - 1 - - Primary Standard Error Device
1C D - - 1 - - Primary Console Input Device
1D D - - 1 - - Primary Console Output Device
fs0:\> dh -b
2: Image(EFI Core)
3: DevIO DevPath ()
6: Fs DiskIo BlkIo DevPath (Acpi(PNP0604,0))
fs0:\> cd apps
Directory of: fs0:\apps
06/11/04 01:32a <DIR> 4,096 .
06/11/04 01:32a <DIR> 0 ..
06/11/04 02:18a 15,360 DrawBox.efi
06/11/04 02:18a 163,840 dhclient.efi
06/11/04 02:18a 114,688 ed.efi
06/11/04 02:18a 33,280 edit.efi
06/11/04 02:18a 14,848 extboot.efi
06/11/04 02:18a 192,512 ftp.efi
06/11/04 02:18a 73,728 hexdump.efi
06/11/04 02:18a 65,536 hostname.efi
06/11/04 02:18a 126,976 ifconfig.efi
06/11/04 02:18a 90,112 loadarg.efi
06/11/04 02:18a 73,728 mkramdisk.efi
06/11/04 02:18a 65,536 nunload.efi
06/11/04 02:18a 21,504 osloader.efi
06/11/04 02:18a 126,976 ping.efi
06/11/04 02:17a 19,968 pktsnoop.efi
06/11/04 02:17a 16,896 pktxmit.efi
06/11/04 02:17a 172,032 pppd.efi
06/11/04 02:17a 16,384 ramdisk.efi
06/11/04 02:17a 15,360 rtdriver.efi
06/11/04 02:17a 14,336 rtunload.efi
06/11/04 02:17a 16,896 test.efi
06/11/04 02:17a 4,608 test3.efi
06/11/04 02:24a 339,968 python.efi
06/11/04 02:24a 73,728 which.efi
06/11/04 02:24a 21,504 testvrt.efi
06/11/04 02:24a 15,360 testva.efi
06/11/04 02:24a 15,872 test4.efi
06/11/04 02:24a 14,848 test2.efi
06/11/04 02:24a 172,032 tcpipv4.efi
06/11/04 02:23a 126,976 route.efi
06/11/04 02:23a 335,872 zh_tw.efi
31 File(s) 2,571,264 bytes
fs0:\apps> load tcpipv4.efi
Interface attached to lo0
Interface attached to ppp0
Timecounter "TcpIpv4" frequency 18 Hz
Network protocol loaded and initialized
load: Image fs0:\apps\tcpipv4.efi loaded at 0xBDBA000 - Success
fs0:\apps> ifconfig -a
lo0: flags=8008<LOOPBACK,MULTICAST> mtu 16384
ppp0: flags=8010lgt;POINTTOPOINT,MULTICAST> mtu 1500
fs0:\apps> ifconfig lo0 inet 127.0.0.1 up
fs0:\apps> ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time<1 ms
Use 'help -b' to display commands one screen at a time.
GUID Based Partitioning Scheme
EFI defines GUID Partition Table (GPT), a new partitioning scheme that must be supported by EFI firmware. GPT uses globally unique identifiers to tag partitions. It is used by the 64-bit version of Windows, and offers several advantages over the legacy MBR-based partitioning scheme:
- 64-bit LBA (thus, disk offsets are 64-bit).
- Supports many partitions (without resorting to nesting schemes like "extended" partitions).
- Uses version number/size fields for future expansion.
- Uses CRC32 fields for improving data integrity.
- Each partition contains a 36 Unicode character human readable name.
- Uses a GUID and attributes to define partition content type (note that tagging each partition with a GUID makes relocation easier).
- Uses a primary and backup table for redundancy.
The primary header structure of a GUID partition table is stored on block 1 of the logical device, while the backup is stored on the last block. A GUID partition table header may never span more than one block on the device. Moreover, although GPT does not support nesting of partitions, it is legal to have a legacy MBR nested inside a GPT partition. Note however that the boot code on a legacy MBR is not executed by EFI firmware.
A sample implementation of GPT disk utilities is available from Intel. The package includes
diskpart (disk partitioning tool),
efifmt (formatting tool), and
efichk (disk checking tool).
DiskPart> select 0
Selected Disk = 0
Selected Disk = 0
### BlkSize BlkCount
--- ------- ----------------
* 0 200 167CA00
C13A7328-F81F-11D2 = EFISYS
34D22C00-1DD2-1000 @ 0
22 - C8021
EBD0A0A2-B9E5-4432 = MSDATA
1845F401-1DD2-1000 @ 0
C8022 - 167C9DE
Universal Graphics Adapter (UGA)
As mentioned earlier, legacy BIOS depends on VGA, a legacy standard. Thus, given the growing needs of pre-boot applications, graphics support in a firmware environment is both very limited and hard to program with (consider factors like 640x480 maximum resolution, small framebuffer, use of palette modes, and so on). EFI defines the UGA specification as a replacement for VGA and VESA. Microsoft is behind UGA, with support from major graphics device manufacturers like ATI.
Any graphics device with UGA firmware can be considered a UGA device. It may also contain VGA firmware for compatibility. The firmware execution environment interprets UGA firmware, which again is implemented in a high level language. Similarly, programming a UGA device does not require you to deal with hardware registers, etc.
The UGA model would work as follows: the UGA firmware may reside on the graphics device, may be a part of the system firmware in case of an onboard graphics device, or may even come from a regular storage device. The firmware contains an EFI driver, which is still a "lowest common denominator" driver, and is not meant to replace a "high-performance" device specific driver that would normally be part of the operating system. That said, the UGA driver may be used in the post-boot environment in various scenarios:
- As a fallback when the regular driver is corrupt or missing from the operating system.
- As the primary driver in machines where graphics performance is irrelevant, such as a server.
- In certain operating system modes such as "safe" and "panic".
- For displaying graphical elements when the primary driver may not be available temporarily, such as during operating system installation, early startup, hibernation, etc.
EFI Byte Code
Option ROMs require different executable images for different processors and platforms. EFI defines an EFI Byte Code (EBC) Virtual Machine to abstract such differences. The interpreter for this virtual machine is part of the firmware. C source can be compiled into EBC, then linked to yield drivers that "run" on the interpreter.
The EBC virtual machine uses two sets of 64-bit registers: 8 general purpose, and 2 dedicated registers. Further, it uses natural indexing for data offsets (relative to a base address) -- instead of a fixed number of bytes as an "offset unit", it uses a "natural unit", which is defined as the operation (as opposed to a constant)
sizeof(void *). This allows EFI byte code to execute seamlessly on 64-bit and 32-bit systems.
There exists a C to EBC compiler. Note that you have several restrictions for the kind of C you can use: floating point and inline assembly are not supported, for example. You cannot use C++ either.
Experimenting with EFI
It is possible to develop and test your own EFI applications, even on an IA-32 computer. You need an EFI runtime environment to explore EFI and run EFI programs, while you need an EFI development environment to create your own EFI programs. You have choices for each environment:
Runtime Environment: You can explore EFI on an IA-64 system, which would have a real implementation of the EFI firmware. It may also be possible to acquire an "artificial" EFI environment, such as within an EFI emulator or an IA-64 simulator. An EFI BIOS32 boot floppy is also available from Intel, using which you can simply "boot into" a real EFI environment on an x86 machine with a legacy BIOS.
Development Environment: You can develop EFI programs on Windows and Linux (perhaps on some others even).
An example Windows development environment for EFI could consist of (but not limited to) the following:
- Microsoft Windows XP (or 2000)
- Microsoft Visual Studio .NET (2003 or 2002)
- Intel EFI Application Toolkit (downloadable from Intel)
EFI emulation under Windows should allow for convenient application development and debugging.
Following is source for an example EFI program,
hanoi.efi, that solves Towers of Hanoi. You can build the program in an environment similar to the one described above. You can run it from the EFI shell. Refer to instructions in the README file within the source archive for details.
Source for Towers of Hanoi in the EFI environment.
Directory of: fs1:\
06/12/04 05:11a 15,872 hanoi.efi
1 File(s) 15,872 bytes
usage: hanoi N
Exit status code: Invalid Parameter
fs1:\> hanoi 3
move 1 --> 3
move 1 --> 2
move 3 --> 2
move 1 --> 3
move 2 --> 1
move 2 --> 3
move 1 --> 3
You can also develop EFI applications for IA-64 and x86 using the GNU toolchain on Linux. You need:
- GNU CC 3.x
- A recent version of
objcopy, specifically, one that supports
efi-app-ia32(for x86) or
efi-app-ia64(for IA-64) as targets.
gnu-efi, the GNU EFI package.
The ELF32 (or ELF64 on IA-64) binaries normally produced on Linux must be converted to EFI binaries, which are supposed to be in the PE32+ format. ELF sections are copied (via
objcopy) into PE32+. The EFI specific
_start function calls a relocator function, followed by a call to
efi_main. Compiling an EFI application on Linux looks like the following:
# Compile position independent, force wide characters to shorts
% gcc -I/usr/include/efi/ia32 -fpic -fshort-wchar -c hanoi.c
# Use EFI specific linker script
% ld -Bsymbolic --no-check-sections -nostdlib -L/usr/lib \
-T elf_ia32_efi.lds -shared /usr/lib/crt0-efi-ia32.o \
-o hanoi.so hanoi.o -lefi -lgnuefi \
# Copy specified sections to target
% objcopy --target=efi-app-ia32 -j .text -j .sdata -j .data \
-j .dynamic -j .dynsym -j .rel -j .rela -j .reloc \
More details of this process can be found in the file README.gnuefi within the GNU EFI package.
Elilo, the EFI Linux boot loader, allows booting of Linux on EFI systems (both IA-64 and IA-32). The Linux kernel also supports EFI, that is, the Linux kernel provides an interface to the EFI runtime services (you need a recent 2.6 kernel for such support on IA-32).
We discuss Open Firmware briefly in the following section. More details on interacting with Open Firmware may be found in Booting Mac OS X
Open Firmware originated at Sun Microsystems in 1988, and was later adopted by Apple and some other vendors. Sun's implementation is trade-marked as OpenBoot, while Apple simply calls it Open Firmware.
Open Firmware is a non-proprietary, platform- (CPU and system) independent, programmable, and extensible environment for use in boot ROMs. Consider:
- The Open Firmware software architecture is defined by IEEE Standard for Boot (Initialization Configuration) Firmware, also known as IEEE-1275. Thus, the standard is open to all and anybody may create an implementation.
- The architecture is independent of the underlying instruction set, bus, operating system, and so on. However, the core requirements and practices specified by the standard are augmented by platform-specific requirements. For example, processors such as PowerPC and SPARC, or buses such as PCI and Sun's SBus, have their own requirements and bindings. The union of the core and platform-specific requirements provides a complete firmware specification for that platform.
- Open Firmware exposes various interfaces, such as one for interaction with an end user, another for use by an operating system, and yet another for use by developers of plug-in devices. Open Firmware presents a machine's various hardware components and their interconnections as a hierarchical data structure: the Device Tree.
- An Open Firmware implementation is based on the Forth programming language, in particular, the FCode dialect. FCode is an American National Standards (ANS) compliant dialect that supports compilation of source to machine-independent bytecode. This allows for FCode drivers to be used on different platforms. Moreover, FCode bytecodes need less storage space (than text strings), and are evaluated faster (as compared to Forth text). An FCode evaluator is a part of the PROM resident firmware implementation.
- Open Firmware is modular in the sense that many features of the architecture are optional for an implementation. Moreover, if certain plug-in devices are required at boot-time, the expansion ROMs on the cards for such devices usually contain FCode-based drivers. As an Open Firmware equipped machine is powered-on, the main ROM begins execution; it probes both on-board and plug-in devices, as part of which the FCode programs on the plug-in ROMs are also executed. Consequently, such plug-in device drivers become part of the Open Firmware environment. A plug-in FCode driver's references to procedures in the main firmware are resolved in a linking process similar to one involving shared libraries in a traditional environment. Note that FCode is position-independent.
- Open Firmware provides access to the filesystem and limited access to the network.
- Open Firmware provides useful facilities for diagnosing hardware, and for debugging its own programs as well as the operating system.
You can enter Open Firmware by pressing the key combination
cmd-opt-O-F just as you power on a Macintosh. The
cmd key is the one with the Apple logo, and the
opt (option) key is the same as the
alt key. You should see a welcome message and some other verbiage, and should be dropped into a prompt like the following:
You can continue booting the machine by typing
mac-boot, or shut it down by typing
For more details on Open Firmware, refer to Booting Mac OS X.
Let us take a quick look at some other firmware related efforts.
There is some "firmware activity" in the open source world, aimed both at developing open source alternatives to the BIOS, or to even replace the BIOS with Linux.
LinuxBIOS is an open source project that uses the Linux kernel as the firmware.
LinuxBIOS uses a system call,
LOBOS (Linux OS Boots OS), to boot a new Linux kernel from a running Linux kernel -- without going into real-mode, and without using the BIOS. Thus, LinuxBIOS can be used as a network bootstrapper, and even as a BIOS replacement.
FreeBIOS aims to provide an open source replacement for any computer's firmware, with initial support for Intel-based processors and chipsets.
OpenBIOS is work-in-progress towards an open source firmware implementation that aims to be 100% compliant with Open Firmware.
Phoenix Core System Software (CSS)
As mentioned earlier, Phoenix currently seems to be taking a more incremental approach to EFI adoption.
Phoenix has been extending the functionality of their BIOS products through features such as:
- Device-level protection of Flash ROM integrity
- Embedded cryptography engine
- Secure authentication and launching of pre-OS anti-virus and system recovery applications
- Trusted Computing support
- Network based management
- A firmware development environment based on Microsoft Visual Studio .NET
Phoenix plans to support both EFI and legacy boot methods in Longhorn timeframe, with a gradual transition to EFI, leading to an eventual removal of legacy. Phoenix says this is a low-risk, low-cost, and non-disruptive approach.
In the next sections, we look at examples of using graphics and mouse within Open Firmware.
Part II: GUI Widgets In Open Firmware
(Having Fun On A Mac Without An Operating System)
The implementation of Open Firmware used in Apple computers includes the device support extensions for several devices, and in particular, for the graphics and the mouse devices. Thus, it is possible for you to write Open Firmware programs that use the mouse and draw to the framebuffer.
We look at two examples: creating a "window" that you can move around using the mouse, and animating Towers of Hanoi.
Open Firmware Windows
The sample Forth code in this section (see link below) creates a small, fixed size window that you can move around. Specifically, the code does the following:
- Creates a mouse pointer using the standard AND-XOR mask technique.
- Creates a window with a rudimentary title bar. The window contains text representing the screen's resolution in pixels.
- Creates a backing store for repairing damage to the portion of the screen under our window.
- Creates a clickable button for shutting down the computer.
The following example demonstrates how to "boot" into a window-drawing demo from the Open Firmware prompt, assuming the program file (called
ofwindows, say) resides in user
amit's home directory on the default hard disk:
0 > boot hd:\Users\amit\ofwindows
0 > ofwindows
Press control-z to quit the Open Firmware Windows demo.
Source for ofwindows.
Animating Towers of Hanoi
I have been interested in implementing (the solution of) Towers of Hanoi in several different ways, as evidenced by the "Hanoimania!" page [external page on www.kernelthread.com]. I recently added an implementation of animated Towers of Hanoi in Open Firmware, which serves as another (somewhat simpler than "ofwindows") example of using the framebuffer.
Towers of Hanoi
The following example demonstrates how to "boot" into Towers of Hanoi from within Open Firmware, assuming the program file (called
ofhanoi, say) resides in user
amit's home directory on the default hard disk:
0 > boot hd:\Users\amit\ofhanoi
0 > hanoi
usage: n hanoi, where 1 <= n < = 8
0 > 5 hanoi
Press control-z to quit the animation.
/* animation begins */
0 > shut-down
/* system powers off */
Source for ofhanoi.
While creating windows and moving disks might be fun, it might be important for those depending on Open Firmware (such as Apple) to think about its future, and what could be done to get to a new-generation firmware. This is particularly critical in the context of managed systems, whether they be servers or "desktops".
That said, it doesn't hurt to have some fun, even if it is arguably pointless.
A limited widget library could be developed to simplify creation of (small) GUI applications that run in the Open Firmware environment. Here are some fabricated reasons why somebody might want to do it:
- You want to learn programming in Forth.
- You like programming under constraints, such as in a limited environment (as compared to a regular operating system).
- You want to understand and appreciate what it takes to create a graphical environment from scratch.
- You want to have fun on an Apple computer, but without an operating system.
- You have a Macintosh, and free time you don't know what to do with.
Some conceivable projects could be:
Open Firmware Information Browser
A substantial amount of platform information is accessible from Open Firmware. It is also possible to set values of various parameters and device properties. Moreover, you can also access the filesystem from Open Firmware. A graphical interface could be created that displays such information, and allows GUI-based editing of parameters.
Simulation of Macintosh System 1
Open Firmware provides more resources in its execution environment than were available to Macintosh System 1. It should be possible to create a simulated System 1 within Open Firmware.
Simulation of Microsoft Windows 3.x
A subset of Microsoft Windows 3.x could be simulated, similar to System 1. Note that you can do color (8-bit) graphics in Open Firmware, as can be seen from the "Hanoi" example.