| Return to main |

Workaround for HP notebooks with bios minipci lock

written by Garlaschini Davide, 23/12/2005

This aims to be a short how-to providing guidelines to "hack" HP notebooks bios protection which prevents to boot the system when an uncertified wireless adapter is inserted into minipci slot. Here I'm explain how I did it with an Atheros card for use with linux. There are other pages (links below) explaining a similar procedure with Intel adapters.

This guide is not intended for people who wants to use modified adapter with Windows and I'll explain why later...

DISCLAIMER: Use this procedure on your own risk. Any modification will most likely void waranty for the modified products, and, besides, you may mess up your wireless adapter.

I bought an HP NX6125 notebook, really a nice peice of hardware except from that linux-unfriendly Broadcom 4318 wireless adapter. Before the purchase I was aware of that but I tought I could have replaced it with any wireless adapter on the market...so after some tests to see if everything was ok I decided to install my good "old" Atheros adapter (a Gigabyte WIAG01).

under the hood before

I removed Broadcom card and replaced with my Atheros one, reassembled all parts, screwed up everything (while thinking "I won't open it again..." :-D) and turned it on...

With my great surprise and a little bit of anger I read: "Error 104 - Unsupported network device..."

After some googling I discovered it's a sort of bios "protection" present on several HP and IBM laptops. Someone says it's a way to have FCC certification, other says it's the beginning of Palladium era... for me it's only a really annoying problem which prevents me to use my good wireless adapter which works really well with linux... and I use linux the 99% of my time...

So I had to look for a solution; I could use ndiswrapper with Windows drivers but I don't like that idea, I could buy a PCMCIA wireless adapter but it's stupid because I have integrated wireless... so I decided to look better on the web for a workaround, there's always a crack for everything out there...

While for IBM laptops there's a good article explaining how to modify bios to accomodate "unsupported" cards for HP I found only some guys on HP official forum and HP X1000 forum talking about a way to baypass the lock using Intel adapters...so I decided to trust them...

THE PROBLEM: Bios compares Vendor ID, Device ID and Subsystem ID of the minipci adapter with those in it's whitelist and if they are in that list system can bootup.

THE SOLUTION: Simply setting adapter's IDs equal to the ones in the whitelist but...there's no public whitelist so I tried setting the same ids like in the preinstalled adapter.

While in above links they only change Subsystem ID (so the adapter's manufacturer) but drivers won't stop working, here the only adapter known to work is the original Broadcom 4318 which has either Vendor and Devices IDs different from my Atheros adapter. So I'll need to edit drivers to recognize it.

The first step is to get Broadcom 4318 IDs, and an lspci -nv can do the work; here is the output:

root@electron:~# lspci -nv
02:02.0 Class 0200: 14e4:4318 (rev 01)
Subsystem: 103c:1356
Flags: bus master, medium devsel, latency 168, IRQ 11
Memory at c4010000 (32-bit, non-prefetchable) [size=64K]
Capabilities: [44] Power Management version 2

After writing down hex codes you can remove Broadcom card. Now it's time to work on your Atheros adapter; you have 3 ways to do it: using another laptop without bios lock, using a minipci to pci converter in your desktop or inserting the adapter in your HP notebook after POST, during lilo or grub boot menu to avoid bios check (you could think it's the most dangerous solution but it works and is the one I used...). Now you have to install madwifi drivers and get you unmodified adapter working. An lspci -nv will now return your adapter's current ids and the base address. This is my output:

root@electron:~# lspci -nv
02:04.0 Class 0200: 168c:0013 (rev 01)
Subsystem: e911:1458
Flags: bus master, medium devsel, latency 168, IRQ 11
Memory at c4020000 (32-bit, non-prefetchable) [size=64K]
Capabilities: [44] Power Management version 2

So I need to change 168c in 14e4, 0013 in 4318, e911 in 103c and 1458 in 1356. In the above links is explained a simple procedure using Ethtool but executing ethtool -e ath0 to read hex dump of EEPROM data returned this:

root@electron:~# ethtool -e ath0
Cannot get EEPROM data: Operation not supported

I asked why of this problem on Madwifi's mailing list (here's full discussion) and they said EEPROM access trought Ethtool is unsupported. However there's an unofficial code (it isn't part of Madwifi project so they won't support people using it and won't be responsible for any mistake) derived from ar5k posted some time ago to overwrite regional domain code set in Atheros adapters. I adapted that code to my needs changing eeprom addresses. Here is my version:

You can download source code or precompiled binary; however to build the code:

root@electron:~# gcc idchanger.c -o idchanger

You can run idchanger with -r or -w flags to read or write eeprom. You should first read eeprom to find which addresses to change. In my case are 0x00, 0x01, 0x07 and 0x08 and I found them by comparing idchanger's output with ids obtained previously from lspci -nv. Syntax is: idchanger -r BASE_ADDR. You can get BASE_ADDR value from the Memory at c4010000 (32-bit, non-prefetchable) [size=64K] row in lspci output and use it adding 0x prefix. Sometimes either reading or writing to eeprom idchanger hangs... you simply have to press CTRL-C and retry until you get no errors. This is my output:

root@electron:~# ./idchanger -r 0xc4010000
Reading 0 current value 0x0013
Reading 1 current value 0x168C
Reading 2 current value 0x0200
Reading 3 current value 0x0001
Reading 4 current value 0x0000
Reading 5 current value 0x5001
Reading 6 current value 0x0000
Reading 7 current value 0xE911
Reading 8 current value 0x1458
Reading 9 current value 0x1C0A
Reading a current value 0x0100
Reading b current value 0x0000
Reading c current value 0x01C2
Reading d current value 0x0002
Reading e current value 0xC606
Reading f current value 0x0001

Now it's time to write to eeprom. Syntax is: idchanger -w BASE_ADDR 0x00_value 0x01_value 0x07_value 0x08_value. This is the output:

root@electron:~# ./idchanger -w 0xc4010000 0x4318 0x14E4 0x1356 0x103C
Accessing adapter at 0xc4010000
Current value 0x0013 will change to 0x4318
Current value 0x168C will change to 0x14E4
Current value 0xE911 will change to 0x1356
Current value 0x1458 will change to 0x103C

If you got no errors id's done! You can verify everything is ok by reading again eeprom. The output should be the following:

root@electron:~# ./idchanger -r 0xc4010000
Reading 0 current value 0x4318
Reading 1 current value 0x14E4
Reading 2 current value 0x0200
Reading 3 current value 0x0001
Reading 4 current value 0x0000
Reading 5 current value 0x5001
Reading 6 current value 0x0000
Reading 7 current value 0x1356
Reading 8 current value 0x103C
Reading 9 current value 0x1C0A
Reading a current value 0x0100
Reading b current value 0x0000
Reading c current value 0x01C2
Reading d current value 0x0002
Reading e current value 0xC606
Reading f current value 0x0001

If your output is ok your laptop should boot correctly without error 104 message. Warning! before rebooting you have to be sure you set the correct values because madwifi drivers won't recognise your adapter any more and idchander won't run.

Now it's time to edit Madwifi drivers so they can recognise our fake Broadcom adapter...I tried either CVS and Madwifi-NG with no errors. Atheros cards are identified by 168C producer id (which means Atheros) and 00xx (0012, 0013 etc which represents the chipset) so we need to modify drivers in order to recognise 14E4 producer id (Broadcom) and 4318 device id.

Let's download the latest madwifi code (both madwifi-ng and madwifi-old should work) and change it... the first file to be modified is ath/if_ath_pci.c. It provides a list of recognised adapters so we only have to add a row representing our adapter (row 96):

static struct pci_device_id ath_pci_id_table[] __devinitdata = {
        { 0x168c, 0x0007, PCI_ANY_ID, PCI_ANY_ID },
        { 0x168c, 0x0012, PCI_ANY_ID, PCI_ANY_ID },
        { 0x168c, 0x0013, PCI_ANY_ID, PCI_ANY_ID },
        { 0xa727, 0x0013, PCI_ANY_ID, PCI_ANY_ID },     /* 3com */
        { 0x10b7, 0x0013, PCI_ANY_ID, PCI_ANY_ID },     /* 3com 3CRDAG675 */
        { 0x168c, 0x1014, PCI_ANY_ID, PCI_ANY_ID },     /* IBM minipci 5212 */
        { 0x168c, 0x0015, PCI_ANY_ID, PCI_ANY_ID },
        { 0x168c, 0x0016, PCI_ANY_ID, PCI_ANY_ID },
        { 0x168c, 0x0017, PCI_ANY_ID, PCI_ANY_ID },
        { 0x168c, 0x0018, PCI_ANY_ID, PCI_ANY_ID },
        { 0x168c, 0x0019, PCI_ANY_ID, PCI_ANY_ID },
        { 0x168c, 0x001a, PCI_ANY_ID, PCI_ANY_ID },
        { 0x14e4, 0x4318, PCI_ANY_ID, PCI_ANY_ID }, /* Fake Broadcom (HP Bios Lock workaround) */
        { 0 }

The next file to be changed is hal/ah_devid.h which contains a list of known ids like the one before:

#define ATHEROS_3COM_VENDOR_ID  0xa727          /* 3Com 3CRPAG175 vendor ID */
#define ATHEROS_3COM2_VENDOR_ID 0x10b7          /* 3Com 3CRDAG675 vendor ID */
#define ATHEROS_BROADCOM_VENDOR_ID 0x14e4       /* Fake Broadcom (HP Bios Lock workaround) */

/* AR5210 (for reference) */
#define AR5210_DEFAULT          0x1107          /* No eeprom HW default */
#define AR5210_PROD             0x0007          /* Final device ID */
#define AR5210_AP               0x0207          /* Early AP11s */

/* AR5211 */
#define AR5211_DEFAULT          0x1112          /* No eeprom HW default */
#define AR5311_DEVID            0x0011          /* Final ar5311 devid */
#define AR5211_DEVID            0x0012          /* Final ar5211 devid */
#define AR5211_LEGACY           0xff12          /* Original emulation board */
#define AR5211_FPGA11B          0xf11b          /* 11b emulation board */

/* AR5212 */
#define AR5212_DEFAULT          0x1113          /* No eeprom HW default */
#define AR5212_DEVID            0x0013          /* Final ar5212 devid */
#define AR5212_FPGA             0xf013          /* Emulation board */
#define AR5212_DEVID_IBM        0x1014          /* IBM minipci ID */
#define AR5212_AR5312_REV2      0x0052          /* AR5312 WMAC (AP31) */
#define AR5212_AR5312_REV7      0x0057          /* AR5312 WMAC (AP30-040) */
#define AR5212_AR2313_REV8      0x0058          /* AR2313 WMAC (AP43-030) */
#define AR5212_FAKE_BROADCOM    0x4318          /* Fake Broadcom (HP Bios Lock workaround) */

The binary HAL provided with madwifi drivers has hardcoded ids so it won't work with a 4318 device... You have to force it to use the original id of your adapter. Mine was 0013 instead of 4318 and to do this edit hal/linux/ah_osdep.c in order to pass the right device id to ath_hal_attach method:

_ath_hal_attach(u_int16_t devid, HAL_SOFTC sc,
                HAL_BUS_TAG t, HAL_BUS_HANDLE h, void* s)
        HAL_STATUS status;
        struct ath_hal *ah = ath_hal_attach(0x0013 /*devid*/, sc, t, h, &status);

        *(HAL_STATUS *)s = status;
        if (ah)
        return ah;

All done! Now make && make install and reboot. Madwifi should now detect your adapter and dmesg should return something like this:

ath_hal: module license 'Proprietary' taints kernel.
ath_hal: (AR5210, AR5211, AR5212, RF5111, RF5112, RF2413, RF5413, DFS)
wlan: (Atheros/multi-bss)
ath_rate_sample: 1.2
ath_pci: (Atheros/multi-bss)
wifi0: 11b rates: 1Mbps 2Mbps 5.5Mbps 11Mbps
wifi0: 11g rates: 1Mbps 2Mbps 5.5Mbps 11Mbps 6Mbps 9Mbps 12Mbps 18Mbps 24Mbps 36Mbps 48Mbps 54Mbps
wifi0: turboG rates: 6Mbps 12Mbps 18Mbps 24Mbps 36Mbps 48Mbps 54Mbps
wifi0: H/W encryption support: WEP AES AES_CCM TKIP
wifi0: mac 5.9 phy 4.3 radio 4.6
wifi0: Use hw queue 1 for WME_AC_BE traffic
wifi0: Use hw queue 0 for WME_AC_BK traffic
wifi0: Use hw queue 2 for WME_AC_VI traffic
wifi0: Use hw queue 3 for WME_AC_VO traffic
wifi0: Use hw queue 8 for CAB traffic
wifi0: Use hw queue 9 for beacons
wifi0: Atheros ???: mem=0xc4010000, irq=11

Now your fake Broadcom is perfectly working, have fun!

Using this approach to avoid bios lock makes impossible to drivers to work with modified adapter. While in linux, bsd, solaris etc. you have access to driver sources and can add new ids to operate with, in windows it's impossible and this is the new problem to solve. I've no Windows driver programming skills but I think there could be 2 ways to get them working:

1) The ar2511.sys file should have hardcoded ids, so I think changing them using an hex editor would be possible. I tried to look for 8c16 (168c) and 1300 (0013) but I found a lot of them so I actually don't know which to change... I should dissassmble the driver to see where ids are compared but I'd need help with assembler.

2) Create a stub driver from scratch, something acting like a proxy which simply exports original driver's functions but masquerates real device ids and forces Atheros driver to work with user specidied ones...

If someone intrested feels like to help me and knows how to develop win drivers please contact.

As a workaround to drivers problem I also tried setting the same device ids as in HP W400 and HP W500 wireless Atheros adapters (hoping they were accepted by bios) but it didn't work. At least I saved a lot of $$ not buying them... so DON"T BUY HP W400 or HP W500 because they aren't accepted.

I'm sorry for this bad english; feel free to contact me for corrections, comments or questions...