Linux and the Open Firmware PC Demo

This document tells you how to run Linux from the PC demo version of FirmWorks Open Firmware. A lot of the information herein also applies to using Linux with any Open Firmware version from FirmWorks.

Getting the Demo

Use of the demo is subject to the terms of a no-charge Evaluation License. Do not download demo unless you agree to abide by the terms of that license.

Download demo.zip (approximate size 2.5 Mbytes) to get the demo.

Making the Demo Floppies

Two of the files in the demo archive file, floppyof.img and floppylx.img, are verbatim floppy disk images. Each of those files must be copied verbatim onto a blank floppy. The image files contain the floppy filesystem format within them, so the copy must be done in a block-for-block fashion. If you are doing it on a Linux system, the appropriate command for the copy is dd.
  1. Get two blank floppy disks
  2. Insert the first one into the floppy drive
  3. dd if=floppyof.img of=/dev/fd0 bs=36b
  4. After the operation has finished and the drive light has gone out, remove and label the first floppy "Open Firmware"
  5. Insert the second floppy
  6. dd if=floppylx.img of=/dev/fd0 bs=36b
  7. After the operation has finished and the drive light has gone out, remove and label the second floppy "Linux"
The Open Firmware floppy (floppyof.img) contains You can put the Open Firmware floppy into a stock PC that is configured (from the BIOS setup screen) to boot from floppy, and the PC will run Open Firmware instead of the regular operating system.

The Linux floppy (floppylx.img) contains
This Linux floppy cannot be booted directly from the BIOS, because it lacks the special helper programs (boot loader, etc) that are normally present on a Linux boot floppy. Instead, it contains just the Linux kernel, which Open Firmware can load directly, without all the helper programs.  For more information, see Which Linux File? .

The initfd.imz RAMdisk image is from the Linux Router Project. The kernel is built from the 2.2.16 sources with a patch to preserve the Open Firmware debugger function (see Using the Debugger ) and another patch that is similar in spirit to the initrd-always patch from the Linux Router Project.

Running the Programs

  1. Use your PC's BIOS setup facility to configure it to boot from floppy disk.
  2. Insert the Open Firmware floppy
  3. Turn on the PC
  4. After the BIOS reads the floppy, you should see a series of startup messages on the screen*, then an "ok" prompt
  5. Insert the Linux floppy
  6. Type linux
  7. You should see some loading messages, then a splash screen, then an "ok" prompt
  8. Type go to run Linux, or use the debugger
* Normally, production versions of Open Firmware are configured to boot quietly, often in two seconds or less, but the demo version has all the startup reports enabled for ease of debugging. See Open Firmware Startup Messages .

The linux command is a variant of the standard Open Firmware load command; it loads a ramdisk image in addition to the operating system kernel. If you wanted to load just the kernel, you could use load or boot , which is equivalent to load then go .

Setting Configuration Variables

Open Firmware has several configuration variables that control the Linux booting process. (Normally OFW configuration variables are stored in non-volatile RAM or in a writeable sector of FLASH memory, but on systems where OFW doesn't have access to such memory they can be stored in a disk file. On the floppy demo version, they are stored in NVRAM.DAT on the floppy.)

The OFW boot command (and its variants load and linux ) can specify the device and file from which to load the Linux kernel, as well as the arguments to pass to the kernel as its "cmdline" string. The complete form of the boot command is:
boot device-specifier arguments...
device-specifier indicates the device and file from which to load the kernel - for example disk:\boot\vmlinuz or nfs:\\myserver\kernels\vmlinuz .  The remainder of the line ( arguments... ) is passed to the kernel as the cmdline - for example console=ttyS0,9600 root=/dev/ram0  .

If either device-specifier or arguments... (or both) is missing, the boot command substitutes configuration variable values for the missing information.  The value of the boot-device configuration value supplies the default for device-specifier and the value of boot-file for arguments... . (It is possible to omit device-specifier but still supply arguments... on the command line. If the first word on the command line after boot or load does not have the form of a device pathname and is not a known alias, it is treated as part of arguments... ) (The name boot-file is an historical artifact from before the time Open Firmware supported filesystems, when it had to depend on intermediate programs for that function. The first command line argument to such intermediate filesystem reader programs was typically a file name.)

boot-device and boot-file are generic Open Firmware features whose usage is not specific to Linux. There is an additional Linux-specific configuration variable named ramdisk . If its value is set to a nonempty string, the linux command, whose arguments are the same as for boot and load , will first load, and uncompress if necessary, an initial RAMdisk image from the device and file specified by the value of ramdisk .

You can inspect the value of a configuration variable with, for example:
printenv varname
You can change its value with:
setenv varname value
or
editenv varname
editenv is usually the most convenient - it puts you into an interactive editor so you can modify the existing value.  editenv will also let you set the value to the empty string, which setenv can't do.

For the floppy-loaded PC demo version, the default value of boot-device is "a:\vmlinuz" and the default value of ramdisk is "a:\initrd.imz".  "a" is a device alias that expands to the first floppy device.  To load Linux from a different place, you could set boot-device as in these examples.:
setenv boot-device c:\boot\vmlinuz
setenv boot-device cdrom:\vmlinuz
setenv boot-device /pci/scsi/disk@4:3,\boot\vmlinux

setenv boot-device net

setenv boot-device nfs:\\myserver\mypath\vmlinux.gz
setenv boot-device http:\\168.192.0.5\binaries\vmlinux

Similarly, you could change ramdisk to load the initrd image from a different place. If you don't want to load the initrd image at all, just use the load command instead of the linux command.

The various pathnames are shown to illustrate the range of booting choices that Open Firmware can provide. Some of these devices aren't available in the demo version. In particular, the network booting options (nfs, http) require a network card driver, which the PC demo version does not include by default.

Using the Debugger

OFW's assembly-language debugger can step through and breakpoint the Linux startup sequence. However, if you are building your own kernel, you must apply a small patch so that it does not disable the debugger (the kernel on the demo floppy already has the patch). The patch files are in the demo archive file. The patch for 2.2.x kernels (patch-2.2.txt) is almost identical to the patch for 2.4.x kernels (patch-2.4.txt); they differ from one another only in small details of the surrounding context. The patch avoids zeroing the %eflags register (which would disable the debugger) and leaves the Open Firmware handlers for the debug and breakpoint interrupts installed in the interrupt table. Open Firmware can boot Linux without the patches; the patches are only necessary if you wish to use the OFW debugger on the Linux kernel.

If the Linux kernel file contains symbols (i.e. it has not been stripped) and OFW's client-symbols? configuration variable is set to true (its default value), then OFW will load the symbols into its memory area when it loads the kernel. The disassembler will then use symbolic names when displaying addresses and you can use symbolic names for addresses that you enter via the command interpreter.

Here is an example of debugging Linux with Open Firmware.
ok linux
Loading ramdisk image from disk:\initrd.imz ...
Boot device: /isa/fdc/disk@1:\vmlinuz
Arguments: root=/dev/ram0 mount_ramdisk=1
Linux start address at c0100000
Type 'go' to start or 'help-debug' to see debugger commands.
ok %eip dis
c0100000 _text        cld
c0100001 _text+1      mov     eax,18
c0100006 _text+6     mov     es,eax
c0100008 _text+8      mov     es,eax
(etc.)
ok step
c0100001 _text+1      mov     eax,18
ok .registers
EIP: c0100001   Flags: 6 vrn0oditszaPc

EAX ECX EDX EBX ESP EBP ESI EDI
ffc345d8 0 0 0 ffcca770 0 90000 0

ES: 18 CS: 10 SS: 18 DS: 18 FS: 18 GS: 18

ok start_kernel dis
c01ecb50 start_kernel push edi
c01ecb51 start_kernel+1 push ebx
c01ecb52 start_kernel+2 sub esp,10
(etc.)
ok start_kernel till
c01ecb50 start_kernel push edi
ok kbd_init till
<Various console messages from Linux>
c01f3ad4 kbd_init and eax,-7d000000
ok %eip dis
c01f3ad4 kbd_init and eax,-7d000000
c01f3ad9 kbd_init+5 or eax,50000000
...
c01f3b39 kbd_init+65 add esp,c
c01f3b3c kbd_init+68 ret near
ok kbd_init 68 + to %eip
ok step
c01f3da5 tty_init+1bd call c01f4704 rs_init
ok hop
c01f3daa tty_init+1c2 call c01f426c pty_init
ok ^R
^R
^R
go
Use the command that loads the ramdisk too






Disassemble starting at %eip





Single step

Display registers
In the Flags display,
lower case means the bit
is clear, upper case means
the bit is set



Disassemble from start_kernel
Typing a symbol name
pushes its value on the
Forth stack.


Execute until start_kernel

Execute until kbd_init


Examine the kbd_init routine,
look for its end,



and set %eip to that address,
thus skipping the routine,
otherwise Linux takes over the keyboard



Hop goes over instead of into subroutines

Control-R toggles the screen buffer so you
can see both Linux output and Open Firmware
output after Linux has scrolled the screen


In this example, after you continue with go, Linux will continue with its startup sequence. If everything is okay, it will come up to the login prompt, but you won't be able to login because in this example we forced Linux to skip its keyboard initialization step so the firmware debugger could continue to use the keyboard. An alternative would be to use a serial line for either the firmware console or the Linux console. If you were using a serial line for the firmware console and you needed to debug past the point where Linux normally takes over the serial port hardware, you would need to make Linux skip that step, thus preserving the state of that port for the firmware debugger.

Which Linux File?

The Linux build process creates several different images. At the top level of the Linux source/build tree (e.g. /usr/src/linux/., not the root of the overall filesystem) there is a file named vmlinux that is in ELF format. That file is the Linux kernel itself. Deeper down the tree, in arch/i386/boot/zImage (or bzImage) and arch/i386/boot/compressed/vmlinux , there are other files that files contain a stripped, compressed copy of the Linux kernel code prefixed by other little programs that do things like getting the CPU into protected mode and uncompressing the kernel. Normally, when you boot Linux from a floppy, the floppy must have the zImage or bzImage file on it.

However, that is not the case for Open Firmware. All of those extra little programs are unnecessary because:
Open Firmware cannot execute a zImage or bzImage file, because the little "helper" programs at the beginning of those files assume that they have been loaded directly by BIOS and that they begin execution in a real-mode environment.

Instead, Open Firmware directly boots the ELF-format vmlinux file, whether gzip'ed or not, whether or not symbols have been stripped. When Open Firmware loads a gzip'ed file, it automatically uncompresses it before preparing it for execution as specified by the ELF header.

Therefore, when you build a new Linux kernel, the file you need for Open Firmware is the vmlinux file at the top directory of your build tree. The final make command can be just "make vmlinux"; you don't need "make zImage" or "make bzImage" (it's okay to make zImage, because that makes vmlinux too, but the additional steps involved in the creation of zImage are unnecessary). Once you have the vmlinux file, you just copy it to some medium that Open Firmware can read. If you wish, you can gzip it first. It doesn't matter to OFW what you name the file, because OFW determines the file format from its contents, not by its name.  Nevertheless, it's probably a good idea to name a gzip'ed version of the kernel something like vmlinux.gz or vmlinuz, as a clue to humans.

Here is a recipe for putting a Linux image on a floppy disk for Open Firmware:
make vmlinux
gzip -c vmlinux >vmlinuz
mcopy -o vmlinuz a:

You can put an initial ramdisk image (initrd) on the same floppy disk if you have room. It will probably be necessary to compress it because uncompressed ramdisk images are usually too large for a floppy. Assuming that you have already created the initrd.img file,
gzip -c initrd.img >initrd.imz
mcopy -o initrd.imz a:

Open Firmware Startup Messages

Summary

These messages that are displayed during the startup of this BIOS-loaded demo version of Open Firmware are as follows:

Details

Here is a blow-by-blow of the startup reports on the screen:

     a...........................................

The above comes from the boot sector code that the BIOS loads from the first two sectors of the floppy. That code is a tiny little program that knows how to read OFW.IMG from the DOS file system on the floppy. (It is also supposed to know how to read OFW.IMG from the hard driver if there is a file named C:\OFW.IMG, but that doesn't work with the new-style FAT32 filesystem that is uses on modern large disks. It might work if your C: partition is in FAT16 format.)

The 'a' comes out right when the boot sector starts, then a dot is displayed every time the code reads a sector from the OFW.IMG file. Since the OFW.IMG file is about 300K, there will be several lines of dots. On some PCs, the dots just fly across the screen and the floppy loading process is over in a few seconds. On others, the dots come out a few per second, and the process is painful. I think that some BIOS floppy drivers tend to blow revs.

After several lines of dots, the OFW.IMG file is in memory (at address 0x7c00) and the boot sector code jumps to it. The CPU is still in real mode at this point, executing 16-bit code.

The next section of code, which is located at the beginning of the OFW.IMG file, is responsible for determining how much memory there is (via the use of real-mode BIOS calls) and then getting the processor into 32-bit protected mode.

The progress reports from this section of code are displayed in the upper left-hand corner of the video screen. They consist of the numbers 1-7, displayed in a funny color. The are all displayed at the same position, and if all goes well it won't take long for it to get all the way up to 7, so all you are likely to see is the number 7 up there in a funny color. Here is what happens as the numbers are being displayed:

Display Actions

Turn off floppy motor

Determine memory size with BIOS calls
1

Turn off interrupts
2

Disable NMI
3

Init COM1 at 9600,8,n,1

Enable A20 using port 92
4

Enable A20 using the keyboard controller
5

Output CR, LF, 'F' on COM1

Switch to protected mode, which is a bit complicated
6

Output 'o' 'r' on COM1

Copy the rest of OFW.IMG from low memory to 0x20.0000 (2 MB)
7

Jump to the copy

After this, everything is 32-bit code that is in the Forth dictionary. The first code to execute is a little machine language sequence ( prom-cold-code ) that sets up the Forth stack pointers and user area and then starts running Forth code. The top-level Forth entry point is the word "cold", which in turn runs the usual set of initialization chains, the same as for all of our implementations.

Defer Word Implementation chain
init-io stand-init-io
do-init init
init-environment stand-init
cold-hook startup

As usual, stand-init-io initializes the memory allocator and turns on the diagnostic output device. The diag output device used to be COM1, but today I modified it so that early startup messages go both to COM1 and also to the video screen, using a funny color.

The first diagnostic output is

    Type 'i' to interrupt stand-init sequence
which happens as the very last thing in the "init" chain. Said 'i' has to come from COM1, because the PC keyboard driver can't be installed this early, and we can't call the BIOS to get keyboard input because we are running in 32-bit protected mode.

Most of the rest of the startup messages come from the stand-init chain, until you get the "probe-pci" message, which is the first message from the "startup" word. Shortly after probe-pci , startup does "install-console", at which point the screen changes color to black-on-white.

Then you get the banner and an "ok" prompt.


Copyright 2002 FirmWorks  All Rights Reserved