Hey all!
For the past week, I’ve been exploring the embedded controller on our awesome laptops, and I’d like to share some of my findings.
This is going to be somewhat structured and somewhat stream-of-consciousness, so bear with me. Most of the same findings are written up on my website at The Framework Laptop's Embedded Controller (EC) :: HowettNET.
Rationale
@nrp mentioned here that the EC firmware is based on chromium-ec, and it seemed like it would be a fun challenge to reverse engineer how the battery charge limit feature in 3.07 worked. Given that the EC may eventually be open source, this could serve as a living document for its capabilities.
Disclaimer
- This information is current as of firmware version 3.07 with EC version
hx20_v0.0.1-369d3c3
. - This information comes with no warranty. If you break your computer, I’m sorry, but that might be a really interesting finding.
- It’s my dearest hope to not tie the Framework team’s hands – if any of the information presented here limits what they can do in future versions for fear of breaking compatibility with a few community hacks, this project will have been a failure.
Tools
The EC uses a customized version of the CrOS EC v3 LPC protocol, which Chromium’s ectool
does not support out of the box. I’m hosting a fork at https://github.com/DHowett/fw-ectool that does. It only works on Linux.
Instructions
- If you’re using a kernel that supports lockdown and secure boot is enabled, make sure you turn it off. This application uses raw port I/O and requires a higher I/O privilege level, which is locked down when secure boot is enabled
- Clone the repository.
-
make utils
. This will produce anectool
binary at$/build/bds/util/ectool
. .../ectool --interface=fwk version
- Fun!
This tool offers an extended raw
command, allowing you to send anything to the EC. It will handle encoding the packet as a v3 exchange.
Syntax: raw 0xCOMMAND payload
payload
takes the form of a long string of type codes (b
, w
, d
, q
) and values in hex.
Examples:
-
b1
will write one byte,0x01
. -
w3
will write one word in little-endian,0x03 0x00
. -
b1w3
orb1,w3
will write0x01 0x03 0x00
.
Findings
This thing is really cool! It supports a lot of the normal CrOS EC commands for reporting status and reconfiguring the system at runtime. Of particular note is led
– you can configure the two side LEDs and the power button.
Most of the features in the Advanced page of UEFI setup are synced to the EC on startup using a number of OEM commands, with values and structures documented here. The settings are applied on every boot, so if you change something like the charge limit it will be reset on restart. This is both good and bad.
Charge Limit
The charge limit is pushed to the EC using command 3E03
. You can set a new charge limit at runtime with…
ectool fwchargelimit 80
Older versions of the tool did not support the
fwchargelimit
command, and you had to send the charge limit host command manually:ectool --interface=fwk raw 0x3E03 b2,wXXXX
where
XXXX
is the charge limit from 0-100 in hex (00 .. 64
).
EDIT 2022-01-10: I’ve added a more ergonomic command for this!
Key Mapping
The “Swap Ctrl/Fn” setting relies on command 3E0C
(dubbed “Keyboard Mapping”). It looks like it takes a set of matrix positions and scancodes. As such, it’s possible to remap any key to emit any¹ scancode. To help with remapping, I’ve reversed the key matrix layout².
I thought it would be very cool to write an EFI driver that remapped Caps Lock to Escape on every boot. However, because the firmware doesn’t support ESP driver loading, it doesn’t work unless you have a compatible bootloader. The source lives here (edk2 required to build.)
Feel free to pile on with questions, info, or findings of your own!
¹ Almost any. I haven’t been able to set any extended scancodes that require escapes in the PC/AT scancode set.
² The EC can simulate a key press at a matrix position, so I just ran kbpress
128 times and asked it to press every matrix position and observed what it emitted using xev
and evtest
. This was before I determined that the key mapping host command can report the matrix mapping! I went back and double-checked afterwards.