IBM make really good Laptops. Sometimes they just need hacking...
They're called ThinkPad's and IBM have got the sense that when they have a nearly-perfect design they shouldn't change it. These machines also tend to run GNU/Linux better than most laptops and have three mouse buttons. I have a ThinkPad R31 and Matthew Garrett decided to buy an IBM ThinkPad X40 which came with a built-in 2.4Ghz aeriel and empty Mini-PCI slot. It was just asking to have a wireless network card installed. Now there are many wifi cards out there, so there's no point buying an IBM ultra-expensive one for £150.00 when any old Mini-PCI card will do (PCI is a standard after all...).
Well, IBM—in their American FCC-paranoidian wisdom—check if
there is a network card inserted on bootup and see whether they have
them in their list. That list of secret PCI-ID's looks like what
follows—and what follows is taken from a `bios.img
'
dumped from the flash of an ThinkPad X40 laptop.
HP also restrict the IDs that are allowed; This guys did some similar funky stuff to modify the BIOS of an HP ZE2000 to accept his Atheros Mini-PCI card.
It's not so much which cards are supported, as which cards don't bring up an annoying message saying:
1802: Unauthorized network card is plugged in - Power off and remove the miniPCI network card.
Offset | PCI ID & Sub-system | Manufacturer | Card |
---|---|---|---|
0x6acc0 | 168c:1014/17ab:8331 | Atheros | IBM 11a/b/g Wireless LAN Mini PCI Adapter (P/N:31P9701) |
0x6acc9 | 8086:1043/8086:2551 | Intel | IBM 802.11b. Intel Pro/Wireless 2100B |
0x6acd2 | 168c:0013/1468:0408 | Atheros | 802.11a/b/g |
0x6acdb | 8086:4220/8086:2711 | Intel | IBM 802.11b/g. Intel Pro/Wireless 2200BG (Centrino?) |
0x6ace4 | 8086:4220/8086:2712 | Intel | IBM 802.11b/g. Intel Pro/Wireless 2200BG (Centrino?) |
0x6aced | 0000:0000/0000:0000 | (null) | End-of-array marker (or possibley a spare?) |
0x78011 | 1260:3873/8086:1380 | Harris Semiconductor | Prism 2.5 Wavelan chipset (Intel) |
0x7801b | 1260:3873/1668:0406 | Harris Semiconductor | Prism 2.5 Wavelan chipset (Actiontec) aka/ IBM High Rate Wireless LAN Card (Orinoco/Prism 2.5/HostAP Linux driver) |
Now say you had a card with PCI-ID 8086:1043/8086:2527
that was only one byte different from the second one in the list, you'd be annoyed wouldn't you...
Phoenix FirstBIOS(tm) Notebook Pro Version 2.0 for IBM ThinkPad (NoteBIOS Pro):
0006aca0 00 08 cd 10 59 5b 58 c3 14 10 57 05 42 43 50 55 |....Y[X...W.BCPU| 0006acb0 53 42 01 01 10 00 06 14 10 2e 05 58 c3 e9 77 1a |SB.........X..w.| 0006acc0 8c 16 14 10 ab 17 31 83 00 86 80 43 10 86 80 51 |......1....C...Q| ^^^^^^^^^^^-^^^^^^^^^^^ ^^^^^^^^^^^-^^^^^^^^ 0006acd0 25 00 8c 16 13 00 68 14 08 04 00 86 80 20 42 86 |%.....h...... B.| ^^ ^^^^^^^^^^^-^^^^^^^^^^^^ ^^^^^^^^^^^-^^ 0006ace0 80 11 27 00 86 80 20 42 86 80 12 27 00 00 00 00 |..'... B...'....| ^^^^^^^^ ^^^^^^^^^^^--^^^^^^^^^^^ ^^^^^^^^ 0006acf0 00 00 00 00 00 00 01 05 03 07 00 20 80 00 00 10 |........... ....| ^^-^^^^^^^^^^^
Grep for the unrelated string `BCPUSB
' to locate the
first set of PCI ID's. Later on, in a completely different place,
are the two Prism 2.5 cards:
00078010 c3 60 12 73 38 86 80 13 25 1a 05 60 12 73 38 68 |.`.s8...%..`.s8h| ^^^^^^^^^^^-^^^^^^^^^^^^ ^^^^^^^^^^^-^^ 00078020 16 06 04 27 02 bb f0 00 ba 19 00 9a 11 54 00 f0 |...'.........T..| ^^^^^^^^
This BIOS Image in question was approximately 1029kB bytes in
size. The image suppiled by IBM on their ``Flash Upgrade Disk'' is
about 650kB long and is a compressed version of the finally image. I
haven't worked out the compression system yet (it seems quite simple
and appears to drop markers with the top bit set,
eg. 0xdf
and 0xff
.
I've just learnt alot about BIOS's. A company producing a machine doesn't write their own code from scratch, they buy a VGA BIOS from one company, a PXE booter from another, a main BIOS from another, SCSI, RAID, TCPA and the like. There are then linked together in a BIOS image which is flashed as a whole onto the computer. Think of the modules as files and the image as a small read-only filesystem.
[generalisation] There are three types of x86 BIOS around, AMI, Award and Phoenix. Near the start of the new century when there were calls to ditch classical BIOS's and remove legacy fluff, Award and Phoenix (who in turn seems to own Award now) came out with two new streams of BIOS. The Award Medallion BIOS and the Phoenix FirstBIOS. Both of these have new flash layouts so think of it as there being five common variants.
All the types are very similar, yet slightly different. They all contain modules, some of which are compressed. If compression is used, it is a variant of LHA; such as LZINT (FirstBIOS), LZSS (Phoenix) or LZARI (Award?). All the flash images have a BCP ``BIOS Configuration Parameter'' section and support for Bootup Logos. Finally, the BIOS images are throughly undocumented formats unless you have licensed the source.
IBM has chosen the Phoenix FirstBIOS for it's recent ThinkPad laptops, more specifically the Notebook Pro variant. Now when you turn on the machine it all looks very IBM-ish, but in reality these are just LOGO files (.BMP Microsoft bitmaps) that were added as modules to the flash image. Lets look at some tools, which are annoyingly all DOS based and/or written in crazy languages like Pascal or Visual Basic.
phlash16.exe
winphlash.exe
phnxdeco
prepare.exe
.scr
) file along with
binary files and produces Module (.mod
catenate.exe
biosedit.exe/BEDemo.zip
uniflash
awardmod
Flash chips come in 128kB, 256kB, 512kB and 1MB sizes which are referred to as 1 Megabit, 2 Megabit... chips. The T40 BIOS is designed to fit on a 8Mb flash chip and so is just a little shorter than a megabyte (1029kB); this means that you should be careful when adding any additional modules. What? You can add modules? Yes, it's effectively a small filesystem with extra metadata about whether modules are compressed and where they should be loaded into memory.
Using ``./phnxdeco bios.img -ls'' it spews the following before crashing:
C I LEVEL START END LENGTH RATIO LINK TO FILEOFFSET ---- ----- --------- --------- ------ ----- --------- ---------- X 0 NONE FFFE 85DD FFFE FFFD 7A06 100% FFFE 7372 E85DDh D 0 NONE FFFE 7372 FFFE 85DC 1250 100% FFFE 5347 E7372h C 0 NONE FFFE 5347 FFFE 7371 2010 100% FFFE 4EFC E5347h G 0 NONE FFFE 4EFC FFFE 5346 430 100% FFFE 4DED E4EFCh A 0 NONE FFFE 4DED FFFE 4EFB F4 100% FFFE 4D9F E4DEDh A 1 NONE FFFE 4D9F FFFE 4DEC 33 100% FFFE 4D51 E4D9Fh A 2 NONE FFFE 4D51 FFFE 4D9E 33 100% FFFE 4CE4 E4D51h L 1 NONE FFFE 49F5 FFFE 4C21 212 100% FFFE 4708 E49F5h L 2 NONE FFFE 4708 FFFE 49F4 2D2 100% FFFE 46D3 E4708h R 0 LZINT FFFD 0720 FFFD 850A 7DD0 49% FFFC A705 D0720h R 1 NONE FFFC A705 FFFD 071F 6000 100% FFFC 2EEA CA705h R 2 NONE FFFC 2EEA FFFC A704 7800 100% FFFB E9F8 C2EEAh E 0 LZINT FFFB E9F8 FFFC 2EE9 44D7 40% FFFB B16D BE9F8h T 0 LZINT FFFB B16D FFFB E9F7 3870 48% FFFA BCF2 BB16Dh M 0 NONE FFFA BCF2 FFFB B16C F460 100% FFF9 8D77 ABCF2h Q 0 NONE FFF9 8D77 FFFA BCF1 12F60 100% FFF9 42B6 98D77h A 3 LZINT FFF9 42B6 FFF9 8D76 4AA6 37% FFF9 1A9B 942B6h
You'll notice that the files don't have names, but like a Zip
file they have start and end locations, lengths and some are
compressed. The left-hand two columns are Class and
Instance. The single letter can be thought of as the file
name and the second column makes sure there are classes. L1 and L2
are the first and second bitmaps Logos in the image. The names
translate as follows: (list from phnxdeco
source).
case 'A': return("ACPI"); // ACPI AML/Table case 'B': return("BIOSCODE"); // BIOSCode Group case 'C': return("UPDATE"); // CPU P6Update case 'D': return("DISPLAY"); // Display case 'E': return("SETUP"); // Editor case 'F': return("FONT"); // case 'G': return("DECOMPCODE"); // case 'I': return("BOOTBLOCK"); // case 'L': return("LOGO"); // Logo Bitmap case 'M': return("MISER"); // Power Management case 'N': return("ROMPILOTLOAD"); // case 'O': return("NETWORK"); // Networking case 'P': return("ROMPILOTINIT"); // case 'R': return("OPROM"); // PCI Option ROM case 'S': return("STRINGS"); // User Interface Strings case 'T': return("TEMPLATE"); // case 'U': return("USER"); // case 'X': return("ROMEXEC"); // Bootstraping? case 'W': return("WAV"); // Audio default: return("User-Defined");
This ThinkPad BIOS also contains additional type/files called '*'
'H' 'K' '<' and 'Q' which all seem to be related to the TCPA (Trust
Computing) components in the ThinkPad. The default:
statement above means that phnxdeco
screws up
extracting these weird files. Wish I had the source to the latest
version to fix it :-(.
This long excursion with trying to explode and then recombine the BIOS images was to investigate checksuming. What would happen if we just hex-edited the bytes in an individual module and recombined them? Well, it turns out not much happens, there are no module-specific checksums, but there is a global checksum for the whole BIOS.
000e86c0 45 58 54 44 15 c5 0a b6 00 00 00 00 43 4b 53 4d |EXTD........CKSM| ^^^^^^^^^^^ 32-bit additive checksum Extended Checksum
The checksum is such that when the entire file is added up, four bytes at a time, the result is zero. To make this happen, the value in-between the Extended Checksum brackets is changed. In short, if you change a value upwards (add), then you need to subtract the same difference from the correctly aligned byte of the checksum.
This information is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. When you fry your laptop and have to send it back to IBM, do not blame me!
Remember that wifi card with ID
8086:1043/8086:2527
? After hexediting the file,
the differences in the 1st, 2nd and 3rd columns are zero; but in the
4th column the difference is (0x51+0x27 = -0x2a) meaning that +0x2a
must be added onto the checksum in the correct
column—the net effect must be ``zero''. (0xb6+0x2a=0xe0):
1--2--3--4 1--2--3--4 1--2--3--4 1--2--3--4 0006acb0 53 42 01 01 10 00 06 14 10 2e 05 58 c3 e9 77 1a |SB.........X..w.| -0006acc0 8c 16 14 10 ab 17 31 83 00 86 80 43 10 86 80 51 |......1....C...Q| +0006acc0 8c 16 14 10 ab 17 31 83 00 86 80 43 10 86 80 27 |......1....C...Q| 0006acd0 25 00 8c 16 13 00 68 14 08 04 00 86 80 20 42 86 |%.....h...... B.| 000e86b0 44 2a 5c 2a 71 2a 79 2a 8c 2a 94 2a 8e 6c 63 00 |D*\*q*y*.*.*.lc.| -000e86c0 45 58 54 44 15 c5 0a b6 00 00 00 00 43 4b 53 4d |EXTD........CKSM| +000e86c0 45 58 54 44 15 c5 0a e0 00 00 00 00 43 4b 53 4d |EXTD........CKSM| 000e86d0 58 09 b4 1b 6a 24 23 27 55 00 e5 00 02 50 d8 80 |X...j$#'U....P..|
Hey Presto, save, burn, flash, insert, boot and congratulate yourself for having beaten Big Blue at their own game—and saved £100.00!
Nota Bene: Need to confirm the exact ordering of the bytes in
all cases (little-endian?). XOR produces a similar result but with
an inverted top-bit, proving that the checksum is additive and has
carry issues. Following diff was generated using
prepare
and catenate
programs and is known
to be correct. The phflash
also has a flag for
validating that the checksum is correct:
-0008ab60 51 25 00 8c 16 13 00 68 14 08 04 00 86 80 20 42 |Q%.....h...... B| +0008ab60 68 24 00 8c 16 13 00 68 14 08 04 00 86 80 20 42 |h$.....h...... B| -000a00e0 8c 2a 94 2a 8e 6c 63 00 45 58 54 44 f4 6e 3e 7b |.*.*.lc.EXTD.n>{| +000a00e0 8c 2a 94 2a 8e 6c 63 00 45 58 54 44 dd 6f 3e 7b |.*.*.lc.EXTD.o>{| >>> hex(0x5125-0x6824+0xf46e) + ' Correct' '0xdd6f Correct' >>> hex(0x5125^0x6824^0xf46e) + ' Wrong' '0xcd6f Wrong' >>> hex(0x2551+0x2468+0x6ef4) + ' Wrong' '0xb8ad Wrong'
In Addition, some of the following could be lines of investigate:
NOP
it out.0x0280
(network device) to an unused code
so that no card is flagged as something the BIOS should investigate further.Taking it further, Sravan Ravinutala reports that he had
modified his BIOS and accidently flashed it with an incorrect
checksum. Thankfully his machine booted fine again and so it would
appear that the checksum is only there for the benefit of the flash
utility to check integrity of the file and not for the BIOS itself
to check. If you flash the image using the `devbios
'
support under Linux then you should just be able to hex-edit the
BIOS image.
Nota Bene: Do not rely on this.
In 1998, Stefan Reinauer announced a `/dev/bios
'
device and then announced an update a couple of months later; then
again in 2000. It seems to have lived in OpenBIOS CVS since. I
got this driver to work on
my ThinkPad R31 (it intelligently knows about a whole series of
Flash types) and using it was as easily as typing:
# make # insmod ./bios.o # cat /proc/bios # dd if=/dev/bios bs=4k of=./my-bios.img
[no reboot required!] The reason for doing it as a kernel module rather than a userspace program seems to be to guarantee time-critical requirements when writing to a chip, if you were doing the equivalent in userspace, you'd have to do lots of ugly hacks to stop your program with being task-switched to another process in the middle:
In 2003 Jeremy Jackson ported the code to the Linux MTD (Memory Technology Device) framework which means means [in theory] you can use the flash socket on a network card to reflash your system BIOS. Think of MTD as covering all the types of Flash that aren't Compact Flash/SD Cards. Specifically, MTD devices have to be [silently] erased first and things—yes, I know the name sucks and as always confused me:
FreeBIOS (aka LinuxBIOS) also appear to have some tools. I have so-far failed to get these to work, even out of CVS:
flash_and_burn
and `flash_rom
')Paul Sladen and Matthew Garrett. 2004-04-27 → 2004-04-29 by the end of which, Matthew had a working laptop with MiniPCI wireless