Friday, November 26, 2010

How to flash your XPS M1730 BIOS with a dead battery

As you may know, you can't flash the BIOS of your Dell XPS M1730 laptop once the battery is dead. When you run the BIOS flash program, it displays an error like "The battery must be charged above 10% before the system BIOS can be flashed. Press OK when the battery is charged or CANCEL to quit."

This is obviously a pain in the ass if you have a dead battery and are happily using the laptop plugged into AC power. I wanted to flash my laptop to version A11 of the BIOS, which adds new thermal tables for the video cards in an effort to stop them from frying, since I had already had my 8700M GTs replaced.

What I did was to patch the Dell BIOS update program MXG7A11.exe to remove this check that the battery charge is at least 10%. I have run my patched BIOS update and successfully upgraded my M1730 to BIOS A11, while plugged into AC power (obviously, since my battery is dead).

You can download a zip file for Windows XP which contains both the original and patched MXG7A11.exe here. All you have to do is run 'Patched MXG7A11.exe' and follow the usual BIOS update process.


What I changed
Here's a listing of the assembler code of the function in MXG7A11.exe that checks the battery charge. My comments are in red and apply to the line below the comment.
004213C0 /$ 55 PUSH EBP
004213C1 |. 8BEC MOV EBP,ESP
004213C3 |. 83EC 0C SUB ESP,0C
004213C6 |. 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C]
004213C9 |. 50 PUSH EAX

Call the Windows API function GetSystemPowerStatus to determine the battery charge. You can read about what this function returns here.
004213CA |. E8 FD0E0000 CALL <JMP.&KERNEL32.GetSystemPowerStatus>
Check the returned ACLineStatus ("The AC power status").
004213CF |. 807D F4 00 CMP BYTE PTR SS:[EBP-C],0
004213D3 |. 75 04 JNZ SHORT MXG7A11.004213D9
ACLineStatus = 0, return 1 to indicate that the AC power status is 'offline'.
004213D5 |. 6A 01 PUSH 1
004213D7 |. EB 22 JMP SHORT MXG7A11.004213FB
Check the returned BatteryFlag ("The battery charge status").
004213D9 |> 807D F5 80 CMP BYTE PTR SS:[EBP-B],80
BatteryFlag = 128, return 2 to indicate that there is no system battery.
004213DD |. 74 1A JE SHORT MXG7A11.004213F9
004213DF |. 807D F5 FF CMP BYTE PTR SS:[EBP-B],0FF
BatteryFlag = 255, return 2 to indicate that Windows was unable to read the battery flag information.
004213E3 |. 74 14 JE SHORT MXG7A11.004213F9
Check if the returned BatteryLifePercent is <= 10%.
004213E5 |. 807D F6 0A CMP BYTE PTR SS:[EBP-A],0A
If it is, return 3.
004213E9 |. 76 0A JBE SHORT MXG7A11.004213F5
Check if the returned BatteryLifePercent = 255 (battery life percent unknown).
004213EB |. 807D F6 FF CMP BYTE PTR SS:[EBP-A],0FF
If it is, return 3.
004213EF |. 74 04 JE SHORT MXG7A11.004213F5
All is good, return 0.
004213F1 |. 33C0 XOR EAX,EAX
004213F3 |. C9 LEAVE
004213F4 |. C3 RETN
004213F5 |> 6A 03 PUSH 3
004213F7 |. EB 02 JMP SHORT MXG7A11.004213FB
004213F9 |> 6A 02 PUSH 2
004213FB |> 58 POP EAX
004213FC |. C9 LEAVE
004213FD \. C3 RETN

The bit I was interested in was where the function returns 3 if the battery charge <= 10%. I simply patched the file to return 0 (success) instead of 3, so no matter what the battery charge, the BIOS flash will go ahead. In other words, I changed this:
004213F5 |> 6A 03 PUSH 3
to this:
004213F5 |> 6A 00 PUSH 0

Update May 9, 2011
I updated the patch to ignore all battery conditions - i.e. it will now update the BIOS whether you have a battery in your laptop or not, and not just check the charge remaining in the battery. I changed the routine above to always return 0, to indicate success.