The BIOS logic is stored in a flash ROM chip and its settings in a small area of battery backed RAM called NVRAM, or more commonly referred to as the "CMOS". In this article I'll show how to update both from the linux operating system.
Updating the flash ROMIt's a very common requirement to be able to update the BIOS logic to fix bugs or add new functionality, and I've needed to do this on all the systems I've worked on.
Traditionally manufacturers have provided a DOS tool to update their flash ROM chips, and unfortunately this is still quite common. The obvious problem with this is obtaining DOS bootable media for the system, especially since floppy drives are thankfully a thing of the past. Dell used to support this method with the biosdisk project, and here is a more generic solution for creating DOS boot media. However this method also precludes the very useful functionality of being able to update the BIOS remotely, and is much more awkward than using the host operating system itself to do the update.
Now some manufacturers are starting to provide linux tools to update their firmware, especially on servers which may have many flash ROM chips. For example IBM provide various tools to update their xseries servers, and I've used these successfully since 2003. Also Dell are starting to provide desktop and server tools, and also a live CD for flashing the BIOS.
The flashrom utilityThere is however a generic utility to both read and write the various flash chips found on systems, called flashrom. I used this to great effect in 2004 (when it was called flash_and_burn) to remotely update Intel 82802AC flash chips. More recently I've used it to update other systems, and have had no problems at all. This small utility is easy to compile, or install from the "flashrom" package on your distro. It automatically detects the type of flash ROM on your system, so usage is also simple as demonstrated below:
./flashrom -r firmware.old #save current flash ROM just in case ./flashrom -wv firmware.new #write and verify new flash ROM image
Another open source program you may find useful as a reference is uniflash.Also considering the privileged position of the BIOS in the system, it's worth noting this NIST guideline on BIOS protection guidelines for servers.
Updating the NVRAMBeing able to change the CMOS settings remotely, can be very useful indeed. For example one could enable the BIOS to start the watchdog on boot on a number of remote machines. One could also use a little space for your own stateful settings on systems that don't have any, like netboot systems for example. This assumes of course, the BIOS leaves some space unused.
As you can see in the diagram above, the NVRAM is 128 bytes on most systems. The first 14 bytes are dedicated to the RTC and the rest are usable by the firmware and made accessible to linux through the /dev/nvram device. Note you may need to sudo modprobe nvram to make this device available on your linux system, and you can confirm the driver is loaded by the presence of the /proc/driver/nvram file which represents some legacy CMOS parameters.
Now the content of the 114 bytes after the RTC is specific to the system's firmware, so the general method to change it is, on one machine enter the BIOS settings menu on boot, and set parameters as required. Then when the machine is fully booted, one can copy the settings with the dd if=/dev/nvram of=nvram.saved command. If your other machines have exactly the same BIOS settings then it's trivial to copy them to the other machines with the dd of=/dev/nvram if=nvram.saved command.
Things get a bit more involved if you want to set particular parameters independently from each other. In this case you must update the CRC which the firmware uses to check for corrupted settings (due to the battery losing charge for example). For my current system at least, the CRC is in the position shown above, and covers the white bytes in the diagram. However I have another system, where the CRC is 2 bytes further into the NVRAM. This is easy to determine by comparing hexdumps of the NVRAM before and after you change a setting. For example here are hexdumps (using od -Ax -tx1z -v /dev/nvram) before and after I set the thermal reboot limit in my BIOS settings:
000000 00 00 ff fe 00 03 4f 80 02 c0 ff 2f 2f bf ff ff >......O....//...< 000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................< 000020 07 ab c0 ff 20 ff ff ff ff ff fd bb ff 0f bf d1 >.... ...........< 000030 b9 11 00 07 00 50 00 00 00 01 0f 44 76 41 f8 00 >.....P.....DvA..< 000040 00 00 41 00 00 00 18 02 00 40 28 00 00 00 00 40 >..A......@(....@< 000050 f8 31 00 00 00 00 00 ee 0e 00 d0 4a 10 00 00 cf >.1.........J....< 000060 4a ff 2f 00 00 00 00 00 00 00 00 ff ff 0a f1 00 >J./.............< 000070 00 20
000000 00 00 ff fe 00 03 4f 80 02 c0 ff 2f 2f bf ff ff >......O....//...< 000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................< 000020 07 ab c0 ff 20 ff ff ff ff ff fd bb ff 0f bf d1 >.... ...........< 000030 b9 11 00 07 00 50 00 00 00 01 0f 44 76 41 f8 00 >.....P.....DvA..< 000040 00 00 41 06 00 00 18 02 00 40 28 00 00 00 00 40 >..A......@(....@< 000050 f8 31 00 00 00 00 00 ee 0e 00 d0 4a 10 00 00 cf >.1.........J....< 000060 4a ff 2f 00 00 00 00 00 00 00 00 ff ff 0a fe 00 >J./.............< 000070 00 20
Using that information I was able to write a simple utility to update the thermal reboot limit BIOS setting, and run it remotely on thousands of systems. Again I must stress that while you can use this utility as a template for your own, it's not generic and you will have to determine the CRC offset etc. as described above.
[Update Apr 2011: I noticed an AMI BIOS that had another checksum in addition to the above, that was outside the NVRAM area. There seemed to be some progress for updating this, but nothing definite I think.]
[Update Jun 2011: I noticed that with the overcomplicated beast that is EFI, one has more than 256 bytes available.][Update Mar 2015: I noticed Richard Jones' tool for offline EFI editing, Matthew Garret's tool for server firmware configuration, and Christop Hellwig's Linux kernel pmem driver for NVDIMMs.]