LinuxBIOS supports the concept of a primary and a fallback boot image in order to allow updates to a system, all the while minimizing the risk that the system will become unbootable. In most cases, where flash chips are socketed, this is merely a strong convenience; in others where the flash chip is soldered to the board, it is nearly necessity.
This mechanism is implemented through two bits in CMOS (byte 0x30 bit 0 and 1) as will be explained below:
ffff0000 - ffffffff fallback block
fffe0000 - fffeffff primary image
(beginning of flash) - fffdffff payload space.
Normally, the payloads are (from bottom to top):
primary boot method (typically etherboot)
secondary boot method
Upon power up, the top 64K (at least) of the flash will be mapped into real mode address f000:0000 - f000:ffff. The CPU will begin execution at f000:fff0 (the reset vector). Thus, the fallback LinuxBIOS is stored at the top of the flash. On reset, the fallback image transitions to flat protected mode and jumps to protected mode code somewhere in ffff0000-ffffffef. That code tests the checksum on the CMOS, then the power failed bit in the real time clock. If the checksum fails or the power failed, the fallback image boots the machine.
If both of those tests pass, the boot bit (bit 0 of CMOS 0x30) is copied to bit 1, then zeroed. If the bit was a 1, The system jumps to the primary image's vector at fffefff8 and booting continues with the primary LinuxBIOS. Otherwise, the fallback image boots the system.
In either case, the controlling LinuxBIOS image initializes serial output, then system RAM. The second stage of LinuxBIOS is decompressed from flash to ram, and control is passed to it (The second stage consists of a small assembly language setup which initializes the stack followed by all of the C code in LinuxBIOS). Serial is initialized first in order to provide diagnostic messages for the rest of the setup.
The C code initializes the rest of the chipset (including any additional CPUs (virtual or physical), configures PCI resources, and then loads a target (payload).
The loader searches for a payload tag starting at address ZKERNEL_START. ZKERNEL_START will be ffff0000 for a fallback image or the start of the ROM for a primary image. If no tags are found, LinuxBIOS will attempt to load an image starting at ZKERNEL_START. Otherwise, the first tagged image will be loaded.
Typically, the fallback image will load etherboot. Primary images often load bootselect.
bootselect is a simple utility to manage multiple choice booting. It will first check the serial input buffer. If no characters are waiting, it will load the default target (the first tagged payload other than itself), otherwise, it will present a menu (over serial console) of all found targets such as:
4. fallback etherboot
The user will select an image by number.
Note that the fallback etherboot will be stored at ffff0000 (along with the fallback LinuxBIOS image) and should not be changed.
Once the final kernel is successfully loaded, it is responsible for setting bit 0 or CMOS 0x30 (using cmos_tool) in order to indicate success. If the boot fails, the system will use the fallback LinuxBIOS upon reset since the boot bit will be zero.
The contents of the flash are manipulated through flash_tool and it's associated utilities flash_on, and flash_invert.
flash_on must be run first. Its purpose is to set a number of GPIO lines and often a chipset register to enable write operations to the flash chip.
flash_tool is a multi-function tool for managing the contents of flash. When run with no arguments, it will display each individual erase block of the flash, its status (locked or unlocked), and associated payload tag if any.
Options: flash_tool [-t 'tag string'] [-s] [-b <num>] [-f] [-p <filename> | -d | -u | -l]
-t when programming, pre-pend a tag with 'tag string' as the text. No effect in other cases.
-b <num> operate on <num> flash block (starting with 0). If omitted, operate on the entire flash
-s small blocks. Some flash devices support reletivly small sectors as well as blocks for finer grained control of contents. Since this results in much more extensive output and can generally complicate things, flash_tool defaults to blocks. -s causes it to work with the smallest independantly erasable sectors available.
-f force. This will allow programming of blocks even if the start or end of the payload are not block aligned.
-p flash <filename> into ROM.
-d dump contents to stdout
-u unlock flash block(s)
-l lock flash blocks.
Some flash chips support soft locking and unlocking of blocks for safety. (In addition to hard locking controlled by hardware control lines). A locked block can not be programmed or erased. Options -l and -u have no effect on chips that do not support block locking.
So, to program a Tyan i7501 board, the following may be done:
flash_tool -b 7 -p linuxbios-fallback.bin
flash_tool -b 6 -p linuxbios-primary.bin
flash_tool -t 'bootselect' -b 0 -f -p bootselect.elf
flash_tool -t 'eepro100' -b 1 -f -p eepro100.elf
flash_tool -t 'pforth' -b 2 -f -p pforth.elf
The cmos_tool is a simple utility for initializing and updating LinuxBIOS parameters in CMOS:
cmos_tool [-z | -c] [<address> <data>] With no parameters, cmos_tool hexdumps the current values to stdout -z zero option area and set checksum -c set checksum to the data currently in CMOS //optionally: set byte <address> to <data>//
So, to prepare for booting the machine for the first time:
cmos_tool 0x30 0x03
Subsequently, the Linux system init should do:
cmos_tool 0x30 0x03
to indicate successful boot and continue using the primary LinuxBIOS.
For safer updating of flash, some chipsets (currently i7500 and i7501) support a register to swap the top and second to the top flash blocks logically (by inverting address bit 16)
flash_invert [n | i]
with no parameters, display current status of invert bit
n set to normal (un inverted) state
i invert (swap) the blocks
flash_invert should not be needed once a board has been initially set up with a fallback image.
It is important to note that the top two blocks MAY NOT be programmed while the top blocks are inverted. There will be data corruption (flash_tool will report a verification failure). The exact cause of this is not yet known, but is likely chipset related.
The LinuxBIOS fallback boot may be tested on a new board by:
flash_tool -b 6 -u
flash_tool -b 6 -p linuxbios-fallback.bin
cmos_tool 0x30 0x00
Then boot. Should the boot fail, set the clear CMOS jumper, then follow the manufacturor's instructions for recovering from a failed flash update.
cmos_tool 0x30 0xff
Note that this technique is primarily used on boards where the flash is soldered down.
Otherwise, a hot flash technique is used.
It is good practice to keep a flash chip handy with the OEM BIOS stored on it. With the board powered off, remove that chip, then re-insert it with fishing line (or similar non-conductive string) underneath it (corner to corner) making sure that the line doesn't interfere with electrical contact. On new boards, it will be desirable to remove and re-insert the chip several times to loosen it up a bit.
Boot the board with the OEM BIOS. Pull out the OEM BIOS by the fishing line (WITH THE POWER ON!) and carefully insert the flash to be programmed. Follow the usual programming procedure.
While the procedure may sound horrific, both board and chip are quite tolerant of the procedure as long as the new flash is inserted correctly. For best results, the chip should be pulled or replaced in a single firm action.
In practice, the hot flash procedure is less time consuming and more certain than the flash_invert method whenever feasable.
Netbooting and Linux kernels
Etherboot for LinuxBIOS uses a combination of DHCP and TFTP (like any netboot) to fetch a linux kernel image. However, it expects the kernel to be in the form of a fixed ELF executable. That is accomplished by processing a standard bzImage with mkelfImage.
mkelfImage –kernel=<bzImage file> –command-line='kernel command line' [–ramdisk=<initrd> –output=<filename>]