Introduction
Two months ago, I bought a new battery for my Lenovo laptop (a ThinkPad X230T). I was about to go away on holidays and wanted a battery that could last me through a plane flight; the original battery was by then barely lasting ten minutes. Little did I know that I was about to be in for an adventure.
I installed the new battery, and everything went fine for a few hours… that is, until I had to plug the laptop in to charge. The battery was not charging. Odd. I rebooted, only to find this message displayed on the screen by the BIOS:
The system does not support batteries that are not genuine Lenovo-made or authorized. The system will continue to boot, but may not charge unauthorized batteries.
ATTENTION: Lenovo has no responsibility for the performance or safety of unauthorized batteries, and provides no warranties for failures or damage arising out of their use.
Press the ESC key to continue.
“May not charge”? That was quite a non-definite message, but this battery was definitely not charging, even with the laptop off. Oh dear.
Now certainly at this point it was possible that the battery was faulty in addition to being non-genuine, but I did not like this idea of Lenovo locking me down to using only ‘genuine’ batteries. Firstly, I had a battery in my hands that might have been working perfectly fine otherwise. Secondly, it meant that Lenovo could charge artificially high prices for their ‘genuine’ batteries. Thirdly, should Lenovo discontinue replacement batteries for my laptop, I would indeed be left with a useless laptop.
First steps: investigating the battery
My first avenue of investigation would be to ‘sniff’ the communication between the laptop and the two batteries, to compare the replacement battery to the original battery. I easily found the pin-out for Lenovo batteries on the Internet, which for easy reference is:
Pin | Name | Description |
---|---|---|
1,2 | VBATT (+) | Battery voltage (or charging voltage) |
3 | SCL | SMBus clock |
4 | SDA | SMBus data |
5 | T | Thermistor |
6,7 | GND (-) | Ground |
In this case I was interested in the communication that happens via the SMBus pins, SCL and SDA. To sniff this communication, I used a basic logic analyser that I had at hand (a USBee SX). Conveniently, there is enough spare length in the battery contacts that it is possible to tap out signals while the battery is connected to the system as you can see in this photo:
(Trick 1: I soldered two 2-pin headers end-to-end () such that the end pins could be wedged around the SDA/SCL contacts, the middle could pass through the narrow gap to the outside of the laptop, and the logic analyser could be connected to the end header.)
(Trick 2: Ground can be attached to the VGA connector, this is a generally useful trick when probing laptops.)
The USBee SX software has the advantage of having built-in I2C/SMBus decoding at a single click. I don’t find the output particularly readable though, so I put it through a quick one-liner to clean it up a bit (perl -pe ‘s/\n/ /gs’ |sed ‘s/[[:space:]]\+/ /g;s/START/\nSTART/g;s/ACK \([0-9A-F]\) /ACK 0\1 /g;s/ ACK / /g’). I’ve uploaded the SMBus captures from the original and replacement batteries here and here for those interested.
Now, for those not in the know, most modern smart batteries implement a standard called Smart Battery Specification (SBS). The communication that we’ve just captured is, indeed, based around the Smart Battery Specification, albeit using a few vendor-specific commands.
I’ve decoded the communication according to the SBS protocol below. I’ve interleaved the two batteries, with green being the original battery and black being the replacement battery. I’ve called out interesting lines with bold red annotation that I’ll refer to below.
Read SpecificationInfo -> 0x0031 (SBS 1.1 with PEC support)
Read SpecificationInfo -> 0x0031 (SBS 1.1 with PEC support)
Read BatteryMode -> 0xe004 (No internal charge controller, etc.)
Read BatteryMode -> 0xe005**bad PEC checksum** (1)
Read BatteryMode -> 0xe005 (Internal charge controller present, etc.) (2)
Write BatteryMode 0xe004
Write BatteryMode 0xe005
Read BatteryMode -> 0xe004
Read BatteryMode -> 0xe005
Read DesignCapacity -> 0x1848 (62.16Wh)
Read DesignCapacity -> 0x1314 (48.84Wh)
Read DesignVoltage -> 0x2b5c (11.1V)
Read DesignVoltage -> 0x2b5c (11.1V)
Read ManufactureDate -> 0x4308 (2013-08-08)
Read ManufactureDate -> 0x46f2 (2015-07-18)
Read SerialNumber -> 0x036d (877)
Read SerialNumber -> 0x18c7 (6343)
Read ManufacturerName -> “LGC 11”
Read ManufacturerName -> “SANYO” (3)
Read DeviceName -> “LNV-45N1079”
Read DeviceName -> “LNV-45N1079”
Read DeviceChemistry -> “LION”
Read DeviceChemistry -> “LION”
(authentication sequence 1)
Write OptionalMfgFunction4 0x39 0x55 0x48 0x28
Read OptionalMfgFunction4 -> “Lenovo Japan” 0x3b 0x7b 0x8c 0x44
Write OptionalMfgFunction4 0x0f 0x35 0x48 0x28
Read OptionalMfgFunction4 -> “”
Write OptionalMfgFunction4 0x10 0x68 0x48 0x28**fail (NACK)**
Write OptionalMfgFunction4 0x10 0x6f 0x48 0x28
Read OptionalMfgFunction4 -> “”
Write OptionalMfgFunction4 0x11 0xa3 0x48 0x28**fail (NACK)**
Write OptionalMfgFunction4 0x11 0xb1 0x48 0x28
Read OptionalMfgFunction4 -> “”
Write OptionalMfgFunction4 0x12 0xe5 0x48 0x28**fail (NACK)**
Write OptionalMfgFunction4 0x12 0xec 0x48 0x28
Read OptionalMfgFunction4 -> “”
Write OptionalMfgFunction4 0x14 0x20 0x48 0x28**fail (NACK)**
Read unknown 0x35 -> 0x00c0
Read unknown 0x37 -> 0x01 0x00 0x3A 0x00 0x00 0x01 0xFB 0x01
Read OptionalMfgFunction5 -> “1ZL1J38L1W3”
Read OptionalMfgFunction5 -> “” (4)
Read OptionalMfgFunction2 -> 0x0021 (33)
Read OptionalMfgFunction2 -> 0x0021 (33)
Read OptionalMfgFunction1 -> 0x4325 (17189)
Read OptionalMfgFunction1 -> 0x42a3 (17059)
Read ManufacturerAccess -> 0x0010
Read ManufacturerAccess -> 0x0018
Read BatteryStatus -> 0x02a0 (FULLY_CHARGED, etc.)
Read BatteryStatus -> 0x02c0 (DISCHARGING, etc.)
Read ChargingCurrent -> 0x0000 (0)
Read ChargingCurrent -> 0x0dac (3500mA)
Read ChargingVoltage -> 0x0000 (0)
Read ChargingVoltage -> 0x3138 (12.6V)
Read Temperature -> 0x0bcf (302.3°K)
Read Temperature -> 0x0bd5 (302.9°K)
Read unknown 0x3b -> 0x0bd6 (303.0°K)
Read unknown 0x3b -> 0x0bc5 (301.3°K)
Read Voltage -> 0x30fd (12.541V)
Read Voltage -> 0x2870 (10.352V)
Read RemainingCapacity -> 0x00c1 (1.93Wh)
Read RemainingCapacity -> 0x0146 (3.26Wh)
Read FullChargeCapacity -> 0x00c1 (1.93Wh) (5)
Read FullChargeCapacity -> 0x1215 (46.29Wh)
Read Current -> 0x0000 (0)
Read Current -> 0x0000 (0)
Read RunTimeToEmpty -> 0xffff (N/A)
Read RunTimeToEmpty -> 0xffff (N/A)
Read AverageCurrent -> 0x0000 (0)
Read AverageCurrent -> 0x0000 (0)
Read AverageTimeToFull -> 0xffff (N/A)
Read AverageTimeToFull -> 0xffff (N/A)
Read AverageTimeToEmpty -> 0xffff (N/A)
Read AverageTimeToEmpty -> 0xffff (N/A)
Read CycleCount -> 0x05d5 (1493)
Read CycleCount -> 0x0001 (1)
Read MaxError -> 0x0000 (0%)
Read MaxError -> 0x0001 (1%)
Read RelativeStateOfCharge -> 0x0064 (100%)
Read RelativeStateOfCharge -> 0x0007 (7%)
Read ManufacturerData -> 0x03 0x32 0x01 0x32 0x00 0x00 0x16 0x10 0x59 0x10 0x8D 0x10 0x08 0x10
Read unknown 0x30 -> 0x0A 0x7F 0xAE 0x59 0x50 0x5E 0x27 0x00 0x00 0x00 0x00
(authentication sequence 2)
Write unknown 0x27: 0x44 0x91 0x11 0x45 0xB2 0x77 0xFC 0x5C 0x5D 0x00 0xCF 0xE9 0x7B 0x72 0xE1 0x2E 0x03
Read unknown 0x28 -> 0xA6 0xCB 0x36 0x12 0xEF 0x36 0xF6 0x41 0x9B 0xB7 0xB7 0xDC 0xD5 0x9F 0xD1 0x36 0x5C 0xA0 0x07 0x3F 0xDF 0x4A 0xC6 0x2E 0x00
First, some minor differences:
- The replacement battery has a bug / feature where it generates the wrong packet checksum (PEC) on the first access (1). However, the laptop is happy enough trying again.
- The replacement battery reports that it has an integrated charge controller whereas the original battery doesn’t (2).
- The replacement battery reports a manufacturer of SANYO whereas the original battery reports a manufacturer of LGC (3). In fact, Lenovo batteries are made by both Sanyo and LG Chem; I suspect that whoever made my replacement battery just happened to be cloning a Sanyo-made battery.
- The original battery responds to the manufacturer-specific function OptionalMfgFunction5 with something that looks like a serial number (4).
It turns out that all of these minor differences can be ignored. The interesting parts are the authentication sequences:
- Authentication sequence 1: The laptop writes 4 bytes using the manufacturer-specific command OptionalMfgFunction4 (0x3c) and then reads 12+4 bytes using the same command. In this case, the outgoing message sends a four byte challenge and the response is the string “Lenovo Japan” followed by a four byte response that depends on the challenge (this is a form of challenge-response authentication).
- Authentication sequence 2: The laptop writes 17 bytes with command 0x27 and reads 8+17 bytes with command 0x28. These commands are not defined in the Smart Battery Specification. Again, it will turn out that this is a sort of challenge-response authentication.
It is not clear why there are two different authentication steps, but perhaps the first one has previously been broken: this is, after all, a cat-and-mouse game between Lenovo and those who have an interest in circumventing their scheme. Neither authentication scheme is implemented in my replacement battery.
(The line marked (5) is just to draw attention to the embarrassing situation where my 62Wh original battery, after two years, now has a full capacity of just under 2Wh.)
Attacking the problem
Now that we understand approximately how the battery is authenticated, the next question is how we might circumvent this authentication. There are a number of possible options.
Option 1: Replace just the used Li-Ion cells in the original battery, preserving the original controller
This is a common approach to battery reconditioning. However, there are a number of pitfalls. Getting the Lenovo batteries apart necessarily involves damaging the plastic to some extent, as the seams have both latches and glue. Also, replacing cells needs to be done carefully as some controllers can brick themselves if the battery voltage is disconnected (I do not know whether this is the case for the Lenovo batteries). The problematic corollary is that the controller will remember data about the old cells, and I’m not sure what effect this might have.
I decided not to go down this path except as a last resort. I did – after getting my replacement battery working – pull apart the original battery for my own edification, and I might comment more on this in a later post.
Option 2: Modify the firmware on the non-genuine battery to emulate the genuine battery
“Modify the firmware on a battery?”, you say incredulously. Yes, in fact smart batteries run firmware, and usually this firmware is updateable. For example, the TI BQ20Z80 battery fuel gauge chip is known to have an embedded ARC microprocessor and flash memory, and has been reverse engineered sufficiently that it is in fact practical to download/upload/modify the firmware (see Charlie Millers’s Blackhat talk on Battery Firmware Hacking).
There are two angles to this. Firstly, if we could download the firmware from the genuine battery, we would perhaps be able to work out the authentication algorithm. Secondly, if we could upload new firmware to a non-genuine battery, we could implement the authentication algorithm on the new battery.
At this point I hooked up the SMBus lines of both batteries to a microcontroller so I could send commands to them independent of the laptop. I used an Arduino just because it’s what I had readily at hand, although any microcontroller (preferably 3.3V) would work fine.
Unfortunately, I got nowhere with this: while all the standard SBS commands worked, neither battery responded to any TI vendor-specific commands that I tried. This makes me think that neither uses a TI chip or they are well locked down. The non-genuine battery responded to ManufacturerAccess command 0x0001 with 0x2168 (some sort of device ID perhaps?), while the genuine battery did not appear to respond to ManufacturerAccess in any useful way.
Given that I had no idea what chip was inside either battery – and even if I knew that, I might not have been able to get enough information to hack the firmware – I decided to shelve this option temporarily.
Option 3: Interpose between the laptop and the battery
Another option would be to add a small embedded microcontroller in between the laptop and battery which would answer the authentication commands if the battery cannot. (In fact it may not be necessary to interpose in the strict sense, it is probably sufficient just to sit on that bus.)
There is some spare space in the Thinkpad’s mini-PCIe slot so it would be possible to run wires from the SMBus lines down to that bay. However, adding extra electronics to the laptop is non-ideal, and at this point we still don’t know how to actually calculate the responses to the authentication challenges.
Option 4: Modify the ThinkPad embedded controller firmware
Clearly if we could modify the laptop to skip the battery authentication, that would solve all of our problems. Since the battery authentication happens even when the laptop is switched off, it cannot be BIOS that is doing the authentication (BIOS runs on the main system processors, and does not run when the system is switched off). Therefore the authentication must be being performed by another part of the system: the embedded controller.
We turn to the embedded controller in part 2 of this series…
Wow, thanks a bunch for pointing out that problem. I am also running a x230t (luckily the battery still lasts), but am getting more and more pissed of by lenovo’s shenanigans.
Keep it up and good luck!
f
the problem thet the battary is for x 220…
x230 need battary of x230…
i have the same problem and i know that the battari is only x230
I’m on this page:
http://www.zmatt.net/unlocking-my-lenovo-laptop-part-1/
Clicking ‘Unlocking my Lenovo laptop, part 2’ links to http://www.zmatt.net/unlocking-my-lenovo-laptop-part-2/ and is returning a 503 error.
Looks like your ‘next’ and ‘previous’ links are both returning 503’s – I see
rel=”next” in the <a href and I guess it's to blame.
Now to reading part two!
Best regards,
– Jesse
Fixed, I got Hacker News-ed and my webhost wasn’t prepared for the traffic.
You might try to use a HP-laptop without genuine ac/dc adaptor. Here i tried, does not work.
I can report that my HP dv7 runs perfectly fine on a Dell 90W power supply as well as an cheap universal laptop power supply bought on the internet.
But it’s ~4yr old by now.
Your model would help to narrow it down.
Wow, was considering of getting a new battery for my 5 year old T410, but I think i’ll pass now.
BTW, have you considered taking the old battery apart and just replace the degraded battery cells, while keeping the original battery controller? Would that work?
As far as I know, the Sandy Bridge generation is the first, where the embedded controller has been changed to a different model (at least that’s what I deduct by the fact that from these models on, you’ll need to load the tpacpi-bat module, instead of the old tp_smapi module in order for the battery related stuff to work in Linux (and some still doesn’t work, hasn’t been figured out yet). So since the T410 is still one model generation pre Sandy Bridge, it should run aftermarket batteries no problem (warning: use aftermarket batteries at your own risk, if you get one that’s too cheap to be true, it’s probably just that, and it may grill your motherboard).
Also, replacing the individual cells is always possible, even with the new embedded controler, however in order to do this, you’ll have to open the battery casing, which is normally clipped and glue-welded shut, so you’ll need a fine saw or a dremel or something like that, and hope never to cut too deep so you don’t hurt one of the cells, which in that case would start releasing pretty toxic smoke, become hot and possibly catch the whole pack on fire. Certainly not the best option (as mentioned in the blog post).
I tried replacing battery cells in HP 6910p laptop, after original battery lost 90% of its capacity, and I can confirm that the controller inside battery remembers old cell data and battery reported last remembered capacity although cells were new. So laptop would show 5% battery remaining and stay that way until battery eventually runs out of charge. It was a bit annoying as I had to set Ubuntu to not hibernate/shut down when battery is critically low. The only indication that battery is about to run out of charge was screen flicker that occurs when battery lives its last few minutes, enough time to save work and plug charger in.
AFAIK there is a battery calibration procedure somewhere in BIOS. At least it was there about 5 years 🙂 ago.
Pingback: Unlocking Thinkpad Batteries | Hackaday
Pingback: Weekendowa Lektura 2016-02-12 – bierzcie i czytajcie | Zaufana Trzecia Strona
Pingback: Links #1 – eKiwi-Blog.de
Pingback: Matthew Chapman on Lenovo laptop internals | Firmware Security
Pingback: Chapman: Unlocking my Lenovo laptop | Linux Press
Pingback: Обход искусственной привязки аккумуляторов в ноутбуках Lenovo | AllUNIX.ru — Всероссийский портал о UNIX-системах
Hi
Thanks for your posts, awesome hack!
I did BIOS unlock with Hamish tools based on your development and my new battery started to charge. But on the next day when I turn on my X230, the battery was 0% and acpi telling me “battery will never charge” and no charge occur. So I leave it as is for the night and when I turned on next day the battery was 90% charged! But when the AC adaptor is plugged-in it will not charge but stay the same. Any ideas what is going on? (I’m on Ubuntu 14.04)
Pingback: A Personal Fight Against The Modern Laptop | Hackaday
Hey there, Great hack! It’s amazing that Lenovo would go this far against third party battery packs…
I actually have a project about resetting the controllers in the original ThinkPad packs after replacing the cells. It builds on Charlie Miller’s work and may work on the newer ones as well (not sure since the latest ThinkPad battery I’ve used it with was for an X100e). The related blog posts section here: http://www.karosium.com/p/smbusb.html details my journey into the subject 🙂
I have a W520 i7
Bat says dead. So I opened it up.
All the cells measured at 4.2 volts. I charged them and subjected them to a load. They seem to be all fine. Which makes me suspect that think pad just disabled. The bat after it saw that it was 4 years old.
Not sure what I am going to do next. I could put in new cells. But would hate to put in that much effort only to figure out the controller still wont let me charge. Also not sure what happens if I disconnect the controller. Somebody said it detets this and wont work even with new cells.
so this is the way to dump the embedded controller EC firmware?
Thanks for your posts, awesome hack!
thanks a bunch for pointing out that problem. I am running a e335. I have not fix this problem
Super frustrated with something similar. I have a Lenovo Thinkpad Edge E520 and have been running it happily for 11 years now. The original battery needed to be replaced after about 2 years, and I’ve purchased 2 new batteries for it since then. Neither of them were genuine Lenovo batteries, and I’ve never had any issues before. The battery I’m currently using was bought in 2016. I really don’t use the battery much, I typically run my laptop plugged in all the time, using the battery mostly just to transport the laptop from one room to another. I have it set to only start charging when it drops below 90%, which means it really only charges about once every week to 10 days.
A few days ago, I was moving the laptop downstairs, as I do every morning, and when I went to plug it in again, I realized it had shut off. It wouldn’t turn back on until I took the battery out. Even the AC power indicator on the side of the machine wouldn’t come on until I had removed the battery. Once it booted up, I put the battery back in and figured I must have just jostled it out of place when I set it down. But then two days later, I was again moving the laptop from one room to another, and this time I was being extra careful with how I was holding it, and I watched it just shut itself off. This time, I unplugged the battery, but then put it back in BEFORE I turned on the machine. And this time, I got the following message before it would boot up: “The system does not support batteries that are not genuine Lenovo-made or authorized. The system will continue to boot, but may not charge unauthorized batteries.
Lenovo has no responsibility for the performance or safety of unauthorized batteries, and provides no warranties for failures or damage arising out of their use.
Press the ESC key to continue.”
It booted up fine, and when I checked the battery health, etc, it said that everything was fine, and the battery’s condition was good. Since then I’ve basically been running the laptop from room to room as quickly as I can to get it plugged in before it goes off. And if I leave the battery in when I fire it up, it gives me the above warning about unauthorized batteries. Tonight, I didn’t make it upstairs, it was less than 60 seconds after I unplugged it when it shut itself off, even though the battery is at 98%.
Why would it start giving me this trouble now? As I said, I’ve been using a “non-Lenovo, unauthorized” battery since 2014, and THIS battery in particular since 2016. Why is the laptop suddenly rejecting it? I’m still running Windows 7, so I didn’t think I was getting any updates to potentially monkey around with things in the background, but in trying to research the problem, I did see some people many years ago complaining about Lenovo rolling out something that caused this unauthorized battery rejection, so I’m wondering is this a software issue? Or is the battery just finally too old and needs to be replaced? I’ve just not experienced a dying battery do this before.
I’m desperate for help as I’m not computer literate at all, and I need my laptop. But the battery price has gone up considerably since 2016, and I’d be devastated if I bought a new one only to have it do the same thing and be unusable. Can anyone help, please? 🙁